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

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 (56) hide show
  1. package/README.md +30 -6
  2. package/dist/{chunk-2P7SUCQ3.js → chunk-EY3HXBJ4.js} +0 -26
  3. package/dist/chunk-RKHJN6KY.js +53 -0
  4. package/dist/{chunk-5R33PUJP.js → chunk-U7KAIPZC.js} +981 -796
  5. package/dist/chunk-WOMR3ZLM.js +17 -0
  6. package/dist/esbuild.cjs +1077 -864
  7. package/dist/esbuild.js +4 -2
  8. package/dist/index.cjs +1077 -864
  9. package/dist/index.js +4 -2
  10. package/dist/nuxt.cjs +1049 -850
  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 +824 -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 +797 -0
  20. package/dist/rollup.cjs +1077 -864
  21. package/dist/rollup.js +4 -2
  22. package/dist/rspack.cjs +1077 -864
  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 +1077 -864
  29. package/dist/vite.js +4 -2
  30. package/dist/webpack.cjs +1077 -864
  31. package/dist/webpack.js +4 -2
  32. package/package.json +1 -4
  33. package/src/caddy/caddyfile.ts +3 -0
  34. package/src/caddy/config.ts +195 -53
  35. package/src/caddy/constants.ts +30 -1
  36. package/src/caddy/index.ts +239 -206
  37. package/src/caddy/privileged.ts +124 -0
  38. package/src/caddy/utils.ts +0 -43
  39. package/src/index.ts +49 -22
  40. package/src/nuxt.ts +1 -6
  41. package/src/privilege-state.ts +23 -0
  42. package/src/privileged/bootstrap.ts +289 -0
  43. package/src/privileged/client.ts +288 -0
  44. package/src/privileged/entry.ts +73 -0
  45. package/src/privileged/hosts-file.ts +142 -0
  46. package/src/privileged/launch.ts +332 -0
  47. package/src/privileged/path-guard.ts +74 -0
  48. package/src/privileged/ports.ts +45 -0
  49. package/src/privileged/protocol.ts +111 -0
  50. package/src/privileged/server.ts +578 -0
  51. package/src/privileged/session.ts +169 -0
  52. package/src/privileged/validation.ts +38 -0
  53. package/src/privileged/windows-elevation.ts +80 -0
  54. package/src/privileged-helper.ts +123 -0
  55. package/src/utils.ts +0 -28
  56. package/src/host/index.ts +0 -52
@@ -1,512 +1,39 @@
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 process9 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";
27
-
28
- // node_modules/.pnpm/alien-signals@2.0.7/node_modules/alien-signals/esm/system.mjs
29
- var ReactiveFlags;
30
- (function(ReactiveFlags2) {
31
- ReactiveFlags2[ReactiveFlags2["None"] = 0] = "None";
32
- ReactiveFlags2[ReactiveFlags2["Mutable"] = 1] = "Mutable";
33
- ReactiveFlags2[ReactiveFlags2["Watching"] = 2] = "Watching";
34
- ReactiveFlags2[ReactiveFlags2["RecursedCheck"] = 4] = "RecursedCheck";
35
- ReactiveFlags2[ReactiveFlags2["Recursed"] = 8] = "Recursed";
36
- ReactiveFlags2[ReactiveFlags2["Dirty"] = 16] = "Dirty";
37
- ReactiveFlags2[ReactiveFlags2["Pending"] = 32] = "Pending";
38
- })(ReactiveFlags || (ReactiveFlags = {}));
39
- function createReactiveSystem({ update, notify: notify2, unwatched }) {
40
- let currentVersion = 0;
41
- return {
42
- link: link2,
43
- unlink: unlink4,
44
- propagate: propagate2,
45
- checkDirty: checkDirty2,
46
- endTracking: endTracking2,
47
- startTracking: startTracking2,
48
- shallowPropagate: shallowPropagate2
49
- };
50
- function link2(dep, sub) {
51
- const prevDep = sub.depsTail;
52
- if (prevDep !== void 0 && prevDep.dep === dep) {
53
- return;
54
- }
55
- const nextDep = prevDep !== void 0 ? prevDep.nextDep : sub.deps;
56
- if (nextDep !== void 0 && nextDep.dep === dep) {
57
- nextDep.version = currentVersion;
58
- sub.depsTail = nextDep;
59
- return;
60
- }
61
- const prevSub = dep.subsTail;
62
- if (prevSub !== void 0 && prevSub.version === currentVersion && prevSub.sub === sub) {
63
- return;
64
- }
65
- const newLink = sub.depsTail = dep.subsTail = {
66
- version: currentVersion,
67
- dep,
68
- sub,
69
- prevDep,
70
- nextDep,
71
- prevSub,
72
- nextSub: void 0
73
- };
74
- if (nextDep !== void 0) {
75
- nextDep.prevDep = newLink;
76
- }
77
- if (prevDep !== void 0) {
78
- prevDep.nextDep = newLink;
79
- } else {
80
- sub.deps = newLink;
81
- }
82
- if (prevSub !== void 0) {
83
- prevSub.nextSub = newLink;
84
- } else {
85
- dep.subs = newLink;
86
- }
87
- }
88
- function unlink4(link3, sub = link3.sub) {
89
- const dep = link3.dep;
90
- const prevDep = link3.prevDep;
91
- const nextDep = link3.nextDep;
92
- const nextSub = link3.nextSub;
93
- const prevSub = link3.prevSub;
94
- if (nextDep !== void 0) {
95
- nextDep.prevDep = prevDep;
96
- } else {
97
- sub.depsTail = prevDep;
98
- }
99
- if (prevDep !== void 0) {
100
- prevDep.nextDep = nextDep;
101
- } else {
102
- sub.deps = nextDep;
103
- }
104
- if (nextSub !== void 0) {
105
- nextSub.prevSub = prevSub;
106
- } else {
107
- dep.subsTail = prevSub;
108
- }
109
- if (prevSub !== void 0) {
110
- prevSub.nextSub = nextSub;
111
- } else if ((dep.subs = nextSub) === void 0) {
112
- unwatched(dep);
113
- }
114
- return nextDep;
115
- }
116
- function propagate2(link3) {
117
- let next2 = link3.nextSub;
118
- let stack;
119
- top:
120
- do {
121
- const sub = link3.sub;
122
- let flags = sub.flags;
123
- if (!(flags & 60)) {
124
- sub.flags = flags | 32;
125
- } else if (!(flags & 12)) {
126
- flags = 0;
127
- } else if (!(flags & 4)) {
128
- sub.flags = flags & ~8 | 32;
129
- } else if (!(flags & 48) && isValidLink(link3, sub)) {
130
- sub.flags = flags | 40;
131
- flags &= 1;
132
- } else {
133
- flags = 0;
134
- }
135
- if (flags & 2) {
136
- notify2(sub);
137
- }
138
- if (flags & 1) {
139
- const subSubs = sub.subs;
140
- if (subSubs !== void 0) {
141
- const nextSub = (link3 = subSubs).nextSub;
142
- if (nextSub !== void 0) {
143
- stack = { value: next2, prev: stack };
144
- next2 = nextSub;
145
- }
146
- continue;
147
- }
148
- }
149
- if ((link3 = next2) !== void 0) {
150
- next2 = link3.nextSub;
151
- continue;
152
- }
153
- while (stack !== void 0) {
154
- link3 = stack.value;
155
- stack = stack.prev;
156
- if (link3 !== void 0) {
157
- next2 = link3.nextSub;
158
- continue top;
159
- }
160
- }
161
- break;
162
- } while (true);
163
- }
164
- function startTracking2(sub) {
165
- ++currentVersion;
166
- sub.depsTail = void 0;
167
- sub.flags = sub.flags & ~56 | 4;
168
- }
169
- function endTracking2(sub) {
170
- const depsTail = sub.depsTail;
171
- let toRemove = depsTail !== void 0 ? depsTail.nextDep : sub.deps;
172
- while (toRemove !== void 0) {
173
- toRemove = unlink4(toRemove, sub);
174
- }
175
- sub.flags &= ~4;
176
- }
177
- function checkDirty2(link3, sub) {
178
- let stack;
179
- let checkDepth = 0;
180
- top:
181
- do {
182
- const dep = link3.dep;
183
- const flags = dep.flags;
184
- let dirty = false;
185
- if (sub.flags & 16) {
186
- dirty = true;
187
- } else if ((flags & 17) === 17) {
188
- if (update(dep)) {
189
- const subs = dep.subs;
190
- if (subs.nextSub !== void 0) {
191
- shallowPropagate2(subs);
192
- }
193
- dirty = true;
194
- }
195
- } else if ((flags & 33) === 33) {
196
- if (link3.nextSub !== void 0 || link3.prevSub !== void 0) {
197
- stack = { value: link3, prev: stack };
198
- }
199
- link3 = dep.deps;
200
- sub = dep;
201
- ++checkDepth;
202
- continue;
203
- }
204
- if (!dirty) {
205
- const nextDep = link3.nextDep;
206
- if (nextDep !== void 0) {
207
- link3 = nextDep;
208
- continue;
209
- }
210
- }
211
- while (checkDepth--) {
212
- const firstSub = sub.subs;
213
- const hasMultipleSubs = firstSub.nextSub !== void 0;
214
- if (hasMultipleSubs) {
215
- link3 = stack.value;
216
- stack = stack.prev;
217
- } else {
218
- link3 = firstSub;
219
- }
220
- if (dirty) {
221
- if (update(sub)) {
222
- if (hasMultipleSubs) {
223
- shallowPropagate2(firstSub);
224
- }
225
- sub = link3.sub;
226
- continue;
227
- }
228
- } else {
229
- sub.flags &= ~32;
230
- }
231
- sub = link3.sub;
232
- const nextDep = link3.nextDep;
233
- if (nextDep !== void 0) {
234
- link3 = nextDep;
235
- continue top;
236
- }
237
- dirty = false;
238
- }
239
- return dirty;
240
- } while (true);
241
- }
242
- function shallowPropagate2(link3) {
243
- do {
244
- const sub = link3.sub;
245
- const flags = sub.flags;
246
- if ((flags & 48) === 32) {
247
- sub.flags = flags | 16;
248
- if (flags & 2) {
249
- notify2(sub);
250
- }
251
- }
252
- } while ((link3 = link3.nextSub) !== void 0);
253
- }
254
- function isValidLink(checkLink, sub) {
255
- let link3 = sub.depsTail;
256
- while (link3 !== void 0) {
257
- if (link3 === checkLink) {
258
- return true;
259
- }
260
- link3 = link3.prevDep;
261
- }
262
- return false;
263
- }
264
- }
265
-
266
- // node_modules/.pnpm/alien-signals@2.0.7/node_modules/alien-signals/esm/index.mjs
267
- var queuedEffects = [];
268
- var { link, unlink, propagate, checkDirty, endTracking, startTracking, shallowPropagate } = createReactiveSystem({
269
- update(signal2) {
270
- if ("getter" in signal2) {
271
- return updateComputed(signal2);
272
- } else {
273
- return updateSignal(signal2, signal2.value);
274
- }
275
- },
276
- notify,
277
- unwatched(node2) {
278
- if ("getter" in node2) {
279
- let toRemove = node2.deps;
280
- if (toRemove !== void 0) {
281
- node2.flags = 17;
282
- do {
283
- toRemove = unlink(toRemove, node2);
284
- } while (toRemove !== void 0);
285
- }
286
- } else if (!("previousValue" in node2)) {
287
- effectOper.call(node2);
288
- }
289
- }
290
- });
291
- var batchDepth = 0;
292
- var notifyIndex = 0;
293
- var queuedEffectsLength = 0;
294
- var activeSub;
295
- var activeScope;
296
- function setCurrentSub(sub) {
297
- const prevSub = activeSub;
298
- activeSub = sub;
299
- return prevSub;
300
- }
301
- function signal(initialValue) {
302
- return signalOper.bind({
303
- previousValue: initialValue,
304
- value: initialValue,
305
- subs: void 0,
306
- subsTail: void 0,
307
- flags: 1
308
- });
309
- }
310
- function computed(getter) {
311
- return computedOper.bind({
312
- value: void 0,
313
- subs: void 0,
314
- subsTail: void 0,
315
- deps: void 0,
316
- depsTail: void 0,
317
- flags: 17,
318
- getter
319
- });
320
- }
321
- function effect(fn) {
322
- const e = {
323
- fn,
324
- subs: void 0,
325
- subsTail: void 0,
326
- deps: void 0,
327
- depsTail: void 0,
328
- flags: 2
329
- };
330
- if (activeSub !== void 0) {
331
- link(e, activeSub);
332
- } else if (activeScope !== void 0) {
333
- link(e, activeScope);
334
- }
335
- const prev = setCurrentSub(e);
336
- try {
337
- e.fn();
338
- } finally {
339
- setCurrentSub(prev);
340
- }
341
- return effectOper.bind(e);
342
- }
343
- function updateComputed(c2) {
344
- const prevSub = setCurrentSub(c2);
345
- startTracking(c2);
346
- try {
347
- const oldValue = c2.value;
348
- return oldValue !== (c2.value = c2.getter(oldValue));
349
- } finally {
350
- setCurrentSub(prevSub);
351
- endTracking(c2);
352
- }
353
- }
354
- function updateSignal(s, value2) {
355
- s.flags = 1;
356
- return s.previousValue !== (s.previousValue = value2);
357
- }
358
- function notify(e) {
359
- const flags = e.flags;
360
- if (!(flags & 64)) {
361
- e.flags = flags | 64;
362
- const subs = e.subs;
363
- if (subs !== void 0) {
364
- notify(subs.sub);
365
- } else {
366
- queuedEffects[queuedEffectsLength++] = e;
367
- }
368
- }
369
- }
370
- function run(e, flags) {
371
- if (flags & 16 || flags & 32 && checkDirty(e.deps, e)) {
372
- const prev = setCurrentSub(e);
373
- startTracking(e);
374
- try {
375
- e.fn();
376
- } finally {
377
- setCurrentSub(prev);
378
- endTracking(e);
379
- }
380
- return;
381
- } else if (flags & 32) {
382
- e.flags = flags & ~32;
383
- }
384
- let link2 = e.deps;
385
- while (link2 !== void 0) {
386
- const dep = link2.dep;
387
- const depFlags = dep.flags;
388
- if (depFlags & 64) {
389
- run(dep, dep.flags = depFlags & ~64);
390
- }
391
- link2 = link2.nextDep;
392
- }
393
- }
394
- function flush() {
395
- while (notifyIndex < queuedEffectsLength) {
396
- const effect2 = queuedEffects[notifyIndex];
397
- queuedEffects[notifyIndex++] = void 0;
398
- run(effect2, effect2.flags &= ~64);
399
- }
400
- notifyIndex = 0;
401
- queuedEffectsLength = 0;
402
- }
403
- function computedOper() {
404
- const flags = this.flags;
405
- if (flags & 16 || flags & 32 && checkDirty(this.deps, this)) {
406
- if (updateComputed(this)) {
407
- const subs = this.subs;
408
- if (subs !== void 0) {
409
- shallowPropagate(subs);
410
- }
411
- }
412
- } else if (flags & 32) {
413
- this.flags = flags & ~32;
414
- }
415
- if (activeSub !== void 0) {
416
- link(this, activeSub);
417
- } else if (activeScope !== void 0) {
418
- link(this, activeScope);
419
- }
420
- return this.value;
421
- }
422
- function signalOper(...value2) {
423
- if (value2.length) {
424
- if (this.value !== (this.value = value2[0])) {
425
- this.flags = 17;
426
- const subs = this.subs;
427
- if (subs !== void 0) {
428
- propagate(subs);
429
- if (!batchDepth) {
430
- flush();
431
- }
432
- }
433
- }
434
- } else {
435
- const value3 = this.value;
436
- if (this.flags & 16) {
437
- if (updateSignal(this, value3)) {
438
- const subs = this.subs;
439
- if (subs !== void 0) {
440
- shallowPropagate(subs);
441
- }
442
- }
443
- }
444
- if (activeSub !== void 0) {
445
- link(this, activeSub);
446
- }
447
- return value3;
448
- }
449
- }
450
- function effectOper() {
451
- let dep = this.deps;
452
- while (dep !== void 0) {
453
- dep = unlink(dep, this);
454
- }
455
- const sub = this.subs;
456
- if (sub !== void 0) {
457
- unlink(sub);
458
- }
459
- this.flags = 0;
460
- }
461
-
462
- // src/caddy/index.ts
28
+ import { execFile } from "node:child_process";
29
+ import { chmodSync, createWriteStream, existsSync as existsSync5, mkdirSync, unlinkSync as unlinkSync2 } from "node:fs";
30
+ import { readFile as readFile3, rename, unlink, 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 process8 from "node:process";
463
34
  import { got } from "got-cjs";
464
35
  import { HttpProxyAgent } from "http-proxy-agent";
465
36
  import { HttpsProxyAgent } from "https-proxy-agent";
466
- import * as lockfile from "proper-lockfile";
467
-
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
37
 
511
38
  // node_modules/.pnpm/@ark+util@0.46.0/node_modules/@ark/util/out/arrays.js
512
39
  var liftArray = (data) => Array.isArray(data) ? data : [data];
@@ -8831,7 +8358,7 @@ function isIterator(val) {
8831
8358
  function escapeRegex(str) {
8832
8359
  return str.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
8833
8360
  }
8834
- function promisify2(fn) {
8361
+ function promisify(fn) {
8835
8362
  return function(...args2) {
8836
8363
  return new Promise((resolve2, reject2) => {
8837
8364
  fn(...args2, (err, result) => {
@@ -10167,8 +9694,8 @@ function requireResolve(file) {
10167
9694
  const require2 = createRequire(process.cwd() + "/");
10168
9695
  return require2.resolve(file);
10169
9696
  }
10170
- var statAsync = promisify2(stat);
10171
- var readFileAsync = promisify2(readFile$1);
9697
+ var statAsync = promisify(stat);
9698
+ var readFileAsync = promisify(readFile$1);
10172
9699
  function exists(filepath) {
10173
9700
  return __awaiter(this, void 0, void 0, function* () {
10174
9701
  try {
@@ -13364,6 +12891,7 @@ var ProxyType = type({
13364
12891
  });
13365
12892
  var CaddyContext = type({
13366
12893
  caddy_root: "string",
12894
+ admin_socket: "string",
13367
12895
  proxies: ProxyType.array()
13368
12896
  });
13369
12897
  function validateTemplateContext(ctx) {
@@ -13375,6 +12903,8 @@ function validateTemplateContext(ctx) {
13375
12903
  var caddyTemplate = `{
13376
12904
  debug
13377
12905
  auto_https disable_redirects ignore_loaded_certs
12906
+ skip_install_trust
12907
+ admin unix/{{ admin_socket }}
13378
12908
  }
13379
12909
 
13380
12910
  :7601 {
@@ -13455,13 +12985,14 @@ async function genCaddyfile(ctx) {
13455
12985
  }
13456
12986
 
13457
12987
  // src/caddy/config.ts
13458
- import { existsSync as existsSync2, readFileSync as readFileSync2, watch, writeFileSync } from "node:fs";
13459
- import { unlink as unlink2 } from "node:fs/promises";
12988
+ import { existsSync as existsSync2, readFileSync as readFileSync2, renameSync, unlinkSync, writeFileSync } from "node:fs";
12989
+ import process3 from "node:process";
12990
+ import * as lockfile from "proper-lockfile";
13460
12991
 
13461
12992
  // src/caddy/constants.ts
13462
12993
  import os from "node:os";
13463
12994
  import { join as join2 } from "node:path";
13464
- import process3 from "node:process";
12995
+ import process2 from "node:process";
13465
12996
  import dotenvFlow from "dotenv-flow";
13466
12997
  dotenvFlow.config({
13467
12998
  silent: true
@@ -13471,11 +13002,20 @@ function resolvePath(path) {
13471
13002
  return join2(os.homedir() || "", path.slice(1));
13472
13003
  return path;
13473
13004
  }
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" : ""}`);
13005
+ function defaultTempDir() {
13006
+ const fromEnv = process2.env.TEMP || process2.env.TMPDIR;
13007
+ if (fromEnv)
13008
+ return resolvePath(fromEnv);
13009
+ if (process2.platform === "linux")
13010
+ return join2(process2.env.XDG_CACHE_HOME || join2(os.homedir(), ".cache"), "uhrp");
13011
+ return "/tmp";
13012
+ }
13013
+ var TEMP_DIR = resolvePath(process2.env.UHRP_CADDY_PATH || defaultTempDir());
13014
+ var caddyPath = join2(TEMP_DIR, `caddy${process2.platform === "win32" ? ".exe" : ""}`);
13476
13015
  var caddyFilePath = join2(TEMP_DIR, "CADDYFILE");
13477
13016
  var caddyConfigPath = join2(TEMP_DIR, ".CADDYFILE.config.json");
13478
13017
  var caddyLockFilePath = join2(TEMP_DIR, "caddylock");
13018
+ var caddyAdminSocketPath = join2(TEMP_DIR, "caddy-admin.sock");
13479
13019
  var supportList = [
13480
13020
  {
13481
13021
  platform: "dragonfly",
@@ -13588,71 +13128,738 @@ var supportList = [
13588
13128
  ];
13589
13129
 
13590
13130
  // src/caddy/config.ts
13591
- function useCaddyConfig() {
13592
- const configContentRef = signal("{}");
13593
- const configJsonRef = computed(() => {
13131
+ function isAlive(pid) {
13132
+ if (pid === void 0)
13133
+ return true;
13134
+ try {
13135
+ process3.kill(pid, 0);
13136
+ return true;
13137
+ } catch {
13138
+ return false;
13139
+ }
13140
+ }
13141
+ function readConfig(path = caddyConfigPath) {
13142
+ if (!existsSync2(path))
13143
+ return {};
13144
+ let parsed2;
13145
+ try {
13146
+ parsed2 = JSON.parse(readFileSync2(path, "utf-8"));
13147
+ } catch {
13148
+ return {};
13149
+ }
13150
+ const alive = {};
13151
+ for (const [key, entry] of Object.entries(parsed2)) {
13152
+ if (isAlive(entry == null ? void 0 : entry.ownerPid))
13153
+ alive[key] = entry;
13154
+ }
13155
+ return alive;
13156
+ }
13157
+ function writeConfig(proxies, path = caddyConfigPath) {
13158
+ const content = JSON.stringify(proxies, null, 2);
13159
+ const temp = `${path}.${process3.pid}.tmp`;
13160
+ writeFileSync(temp, content);
13161
+ renameSync(temp, path);
13162
+ }
13163
+ function useCaddyConfig(options = {}) {
13164
+ const lock3 = options.lock ?? createFileLock();
13165
+ const configPath = options.configPath ?? caddyConfigPath;
13166
+ async function mutate(apply) {
13167
+ var _a4;
13168
+ const release = await lock3.acquire();
13594
13169
  try {
13595
- return JSON.parse(configContentRef());
13596
- } catch {
13170
+ const proxies = readConfig(configPath);
13171
+ apply(proxies);
13172
+ writeConfig(proxies, configPath);
13173
+ await ((_a4 = options.renderCaddyfile) == null ? void 0 : _a4.call(options, proxies));
13174
+ return proxies;
13175
+ } finally {
13176
+ release();
13177
+ }
13178
+ }
13179
+ return {
13180
+ configJsonRef: () => existsSync2(configPath) ? readConfig(configPath) : void 0,
13181
+ async writeCaddyConfig(_proxies, key) {
13182
+ await mutate((proxies) => {
13183
+ for (const p of _proxies)
13184
+ proxies[routeKey(p, key)] = { ...p, base: normalizeBase(p.base), ownerPid: process3.pid };
13185
+ });
13186
+ },
13187
+ async removeProxy(key) {
13188
+ await mutate((current) => {
13189
+ for (const route of Object.keys(current)) {
13190
+ if (route.endsWith(`#${key}`))
13191
+ delete current[route];
13192
+ }
13193
+ });
13194
+ },
13195
+ readProxies: () => readConfig(configPath),
13196
+ async cleanUp() {
13197
+ removeConfigFile(configPath);
13198
+ }
13199
+ };
13200
+ }
13201
+ function removeConfigFile(path = caddyConfigPath) {
13202
+ try {
13203
+ if (existsSync2(path))
13204
+ unlinkSync(path);
13205
+ } catch {
13206
+ }
13207
+ }
13208
+ function normalizeBase(base) {
13209
+ let out = base || "/";
13210
+ if (!out.startsWith("/"))
13211
+ out = `/${out}`;
13212
+ if (out !== "/" && !out.endsWith("/"))
13213
+ out = `${out}/`;
13214
+ return out;
13215
+ }
13216
+ function routeKey(proxy, ownerKey) {
13217
+ return `${proxy.target}${proxy.portSuffix}${normalizeBase(proxy.base)}#${ownerKey}`;
13218
+ }
13219
+ function createFileLock() {
13220
+ return {
13221
+ async acquire() {
13222
+ if (!existsSync2(caddyConfigPath))
13223
+ writeFileSync(caddyConfigPath, "{}");
13224
+ const release = await lockfile.lock(caddyConfigPath, {
13225
+ realpath: false,
13226
+ stale: 1e4,
13227
+ retries: { retries: 20, minTimeout: 10, maxTimeout: 100 }
13228
+ });
13229
+ return () => {
13230
+ void release().catch(() => {
13231
+ });
13232
+ };
13233
+ }
13234
+ };
13235
+ }
13236
+
13237
+ // src/caddy/log.ts
13238
+ function isCaddyReloadCancellation(line) {
13239
+ try {
13240
+ const entry = JSON.parse(line);
13241
+ return entry.logger === "tls" && typeof entry.error === "string" && entry.error.endsWith("context canceled");
13242
+ } catch {
13243
+ return false;
13244
+ }
13245
+ }
13246
+
13247
+ // src/caddy/privileged.ts
13248
+ import { Buffer as Buffer2 } from "node:buffer";
13249
+ import { EventEmitter } from "node:events";
13250
+ import { dirname as dirname3, join as join5 } from "node:path";
13251
+ import process7 from "node:process";
13252
+ import { fileURLToPath } from "node:url";
13253
+
13254
+ // src/privileged/entry.ts
13255
+ import { existsSync as existsSync3 } from "node:fs";
13256
+ import { dirname as dirname2, join as join3 } from "node:path";
13257
+ import process4 from "node:process";
13258
+ function resolveHelperEntry(options) {
13259
+ const { moduleDir, nodeBin = process4.execPath, exists: exists2 = existsSync3 } = options;
13260
+ for (const name of ["privileged-helper.js", "privileged-helper.cjs", "privileged-helper.mjs"]) {
13261
+ const candidate = findUp(moduleDir, name, exists2);
13262
+ if (candidate)
13263
+ return { entry: nodeBin, args: [candidate] };
13264
+ }
13265
+ const source = findUp(moduleDir, "privileged-helper.ts", exists2);
13266
+ const tsxCli = findUp(moduleDir, "node_modules/tsx/dist/cli.mjs", exists2);
13267
+ if (source && tsxCli)
13268
+ return { entry: nodeBin, args: [tsxCli, source] };
13269
+ throw new Error(`privileged helper entry not found in ${moduleDir}. Build the package first.`);
13270
+ }
13271
+ function findUp(from, relative, exists2) {
13272
+ let current = from;
13273
+ while (true) {
13274
+ const candidate = join3(current, relative);
13275
+ if (exists2(candidate))
13276
+ return candidate;
13277
+ const parent = dirname2(current);
13278
+ if (parent === current)
13597
13279
  return void 0;
13280
+ current = parent;
13281
+ }
13282
+ }
13283
+
13284
+ // src/privileged/session.ts
13285
+ import { Buffer } from "node:buffer";
13286
+ import { existsSync as existsSync4 } from "node:fs";
13287
+ import { readFile as readFile2, writeFile } from "node:fs/promises";
13288
+ import { platform as platform2 } from "node:os";
13289
+ import { join as join4 } from "node:path";
13290
+ import * as lockfile2 from "proper-lockfile";
13291
+
13292
+ // src/privileged/launch.ts
13293
+ import { spawn as spawn2, spawnSync } from "node:child_process";
13294
+ import { randomBytes } from "node:crypto";
13295
+ import { platform } from "node:os";
13296
+ import process6 from "node:process";
13297
+
13298
+ // src/privileged/client.ts
13299
+ import { connect } from "node:net";
13300
+ import process5 from "node:process";
13301
+ var FORWARDED_ENV_KEYS = [
13302
+ "HOME",
13303
+ "USER",
13304
+ "LOGNAME",
13305
+ "TMPDIR",
13306
+ "HTTP_PROXY",
13307
+ "HTTPS_PROXY",
13308
+ "http_proxy",
13309
+ "https_proxy",
13310
+ "NO_PROXY",
13311
+ "no_proxy"
13312
+ ];
13313
+ function collectForwardedEnv(source = process5.env) {
13314
+ const result = {};
13315
+ for (const key of FORWARDED_ENV_KEYS) {
13316
+ const value2 = source[key];
13317
+ if (typeof value2 === "string" && value2 !== "")
13318
+ result[key] = value2;
13319
+ }
13320
+ return result;
13321
+ }
13322
+ var HelperConnectionError = class extends Error {
13323
+ constructor(message) {
13324
+ super(message);
13325
+ this.name = "HelperConnectionError";
13326
+ }
13327
+ };
13328
+ function openSocket(socketPath) {
13329
+ return new Promise((resolve2, reject2) => {
13330
+ const socket = connect(socketPath);
13331
+ function onConnect() {
13332
+ socket.removeListener("error", onError);
13333
+ resolve2(socket);
13598
13334
  }
13599
- });
13600
- function setConfigContent() {
13601
- if (!existsSync2(caddyConfigPath)) {
13602
- writeFileSync(caddyConfigPath, "{}");
13335
+ function onError(error) {
13336
+ socket.removeListener("connect", onConnect);
13337
+ reject2(error);
13603
13338
  }
13339
+ socket.once("error", onError);
13340
+ socket.once("connect", onConnect);
13341
+ });
13342
+ }
13343
+ async function connectClient(options) {
13344
+ const {
13345
+ socketPath,
13346
+ token,
13347
+ timeoutMs = 12e4,
13348
+ retryIntervalMs = 100,
13349
+ callTimeoutMs = 3e4
13350
+ } = options;
13351
+ const deadline = Date.now() + timeoutMs;
13352
+ let lastError;
13353
+ while (Date.now() < deadline) {
13604
13354
  try {
13605
- configContentRef(readFileSync2(caddyConfigPath, "utf-8"));
13606
- } catch {
13607
- configContentRef("");
13355
+ return await handshake(socketPath, token, callTimeoutMs);
13356
+ } catch (error) {
13357
+ lastError = error;
13358
+ const code = lastError.code;
13359
+ if (code === "EACCES" || lastError instanceof HelperConnectionError)
13360
+ throw lastError;
13361
+ await new Promise((resolve2) => setTimeout(resolve2, retryIntervalMs));
13608
13362
  }
13609
13363
  }
13610
- if (!existsSync2(caddyConfigPath)) {
13611
- writeFileSync(caddyConfigPath, "{}");
13612
- }
13613
- const watchCaddyConfig = watch(caddyConfigPath, () => {
13614
- setConfigContent();
13364
+ throw new HelperConnectionError(
13365
+ `privileged helper is not reachable at ${socketPath}: ${(lastError == null ? void 0 : lastError.message) ?? "timed out"}`
13366
+ );
13367
+ }
13368
+ function handshake(socketPath, token, callTimeoutMs) {
13369
+ return new Promise((resolve2, reject2) => {
13370
+ void openSocket(socketPath).then((socket) => {
13371
+ let buffer = "";
13372
+ let settled = false;
13373
+ const fail = (error) => {
13374
+ if (settled)
13375
+ return;
13376
+ settled = true;
13377
+ socket.destroy();
13378
+ reject2(error);
13379
+ };
13380
+ const onData = (chunk) => {
13381
+ if (settled)
13382
+ return;
13383
+ const split2 = splitLines(buffer, chunk.toString("utf8"));
13384
+ buffer = split2.rest;
13385
+ const line = split2.lines[0];
13386
+ if (line === void 0)
13387
+ return;
13388
+ let hello;
13389
+ try {
13390
+ hello = JSON.parse(line);
13391
+ } catch (error) {
13392
+ return fail(new HelperConnectionError(`invalid handshake reply: ${error.message}`));
13393
+ }
13394
+ if (hello.type !== "handshake")
13395
+ return fail(new HelperConnectionError("helper did not answer the handshake"));
13396
+ if (!hello.ok)
13397
+ return fail(new HelperConnectionError(hello.reason ?? "helper rejected the handshake"));
13398
+ settled = true;
13399
+ socket.removeListener("data", onData);
13400
+ socket.removeListener("error", onError);
13401
+ const remaining = split2.lines.slice(1);
13402
+ resolve2(createClient(socket, [split2.rest, ...remaining].filter(Boolean).join("\n"), callTimeoutMs));
13403
+ };
13404
+ function onError(error) {
13405
+ fail(error);
13406
+ }
13407
+ socket.on("data", onData);
13408
+ socket.on("error", onError);
13409
+ const greeting = { type: "handshake", token };
13410
+ socket.write(serializeMessage(greeting));
13411
+ }, reject2);
13615
13412
  });
13616
- function writeCaddyConfig(_proxies) {
13617
- const proxies = configJsonRef() || {};
13618
- _proxies.forEach((p) => {
13619
- let base = p.base || "/";
13620
- if (!base.startsWith("/"))
13621
- base = `/${base}`;
13622
- if (base !== "/" && !base.endsWith("/"))
13623
- base = `${base}/`;
13624
- const index = `${p.target}${p.portSuffix}${base}`;
13625
- proxies[index] = { ...p, base };
13413
+ }
13414
+ function createClient(socket, initialBuffer, callTimeoutMs) {
13415
+ let buffer = initialBuffer;
13416
+ let connected = true;
13417
+ let nextId = 1;
13418
+ const pending = /* @__PURE__ */ new Map();
13419
+ const listeners = /* @__PURE__ */ new Set();
13420
+ socket.on("data", (chunk) => {
13421
+ const split2 = splitLines(buffer, chunk.toString("utf8"));
13422
+ buffer = split2.rest;
13423
+ for (const line of split2.lines) {
13424
+ const decoded = decodeMessage(line);
13425
+ if (!decoded.ok)
13426
+ continue;
13427
+ const message = decoded.message;
13428
+ if (!("id" in message)) {
13429
+ for (const listener of listeners)
13430
+ listener(message);
13431
+ continue;
13432
+ }
13433
+ const entry = pending.get(message.id);
13434
+ if (!entry)
13435
+ continue;
13436
+ pending.delete(message.id);
13437
+ clearTimeout(entry.timer);
13438
+ if (message.ok)
13439
+ entry.resolve(message.result);
13440
+ else
13441
+ entry.reject(new Error(message.error.message));
13442
+ }
13443
+ });
13444
+ const disconnect = () => {
13445
+ if (!connected)
13446
+ return;
13447
+ connected = false;
13448
+ for (const [id, entry] of pending) {
13449
+ clearTimeout(entry.timer);
13450
+ pending.delete(id);
13451
+ entry.reject(new HelperConnectionError("privileged helper connection closed"));
13452
+ }
13453
+ };
13454
+ socket.on("close", disconnect);
13455
+ socket.on("error", disconnect);
13456
+ function call(method, params) {
13457
+ if (!connected)
13458
+ return Promise.reject(new HelperConnectionError("privileged helper is not connected"));
13459
+ const id = nextId++;
13460
+ const request = { id, method, params };
13461
+ return new Promise((resolve2, reject2) => {
13462
+ const timer = setTimeout(() => {
13463
+ pending.delete(id);
13464
+ reject2(new HelperConnectionError(`privileged helper did not answer "${method}" in time`));
13465
+ }, callTimeoutMs);
13466
+ pending.set(id, { resolve: resolve2, reject: reject2, timer });
13467
+ socket.write(serializeMessage(request));
13626
13468
  });
13627
- const content = JSON.stringify(proxies, null, 2);
13628
- configContentRef(content);
13629
- return writeFileSync(caddyConfigPath, content);
13630
13469
  }
13631
- async function cleanUp() {
13632
- await unlink2(caddyConfigPath).catch(() => {
13470
+ return {
13471
+ get connected() {
13472
+ return connected;
13473
+ },
13474
+ call,
13475
+ onEvent(listener) {
13476
+ listeners.add(listener);
13477
+ return () => {
13478
+ listeners.delete(listener);
13479
+ };
13480
+ },
13481
+ async close() {
13482
+ disconnect();
13483
+ socket.destroy();
13484
+ }
13485
+ };
13486
+ }
13487
+
13488
+ // src/privileged/windows-elevation.ts
13489
+ import { spawn } from "node:child_process";
13490
+ function quotePowerShell(value2) {
13491
+ return `'${value2.replace(/'/g, "''")}'`;
13492
+ }
13493
+ function buildElevationCommand(options) {
13494
+ const argumentList = options.args.map(quotePowerShell).join(",");
13495
+ const parts = [
13496
+ "Start-Process",
13497
+ "-FilePath",
13498
+ quotePowerShell(options.file)
13499
+ ];
13500
+ if (argumentList)
13501
+ parts.push("-ArgumentList", argumentList);
13502
+ if (options.cwd)
13503
+ parts.push("-WorkingDirectory", quotePowerShell(options.cwd));
13504
+ parts.push("-Verb", "RunAs");
13505
+ parts.push("-WindowStyle", "Hidden");
13506
+ return parts.join(" ");
13507
+ }
13508
+ function spawnElevatedOnWindows(options) {
13509
+ return new Promise((resolve2, reject2) => {
13510
+ const script = buildElevationCommand(options);
13511
+ const child = spawn(
13512
+ "powershell.exe",
13513
+ ["-NoProfile", "-NonInteractive", "-Command", script],
13514
+ { stdio: "ignore", windowsHide: true }
13515
+ );
13516
+ child.once("error", reject2);
13517
+ child.once("exit", (code) => {
13518
+ if (code === 0)
13519
+ return resolve2(child);
13520
+ reject2(new Error(
13521
+ `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.`
13522
+ ));
13633
13523
  });
13634
- configContentRef("{}");
13635
- watchCaddyConfig.close();
13524
+ });
13525
+ }
13526
+
13527
+ // src/privileged/launch.ts
13528
+ function createHelperToken() {
13529
+ return randomBytes(24).toString("hex");
13530
+ }
13531
+ function describePasswordReason(target, https) {
13532
+ const port = https ? "443" : "80";
13533
+ return [
13534
+ `reverse proxy needs administrator permission for ${target}`,
13535
+ ` \xB7 bind port ${port}${https ? ` for https://${target}` : ""}`,
13536
+ ` \xB7 add ${target} to the hosts file`,
13537
+ "",
13538
+ "This is the only prompt; the rest of the dev server keeps running as you.",
13539
+ "Press Ctrl+C at the prompt to skip the proxy and keep the dev server."
13540
+ ];
13541
+ }
13542
+ async function authenticateSudo(sudoCommand = "sudo", options = {}) {
13543
+ if (platform() === "win32")
13544
+ return { ok: true };
13545
+ if (spawnSync(sudoCommand, ["-n", "true"], { stdio: "ignore" }).status === 0)
13546
+ return { ok: true };
13547
+ if (options.target && !options.quiet) {
13548
+ for (const line of describePasswordReason(options.target, options.https ?? false))
13549
+ process6.stderr.write(`${line}
13550
+ `);
13551
+ process6.stderr.write("\n");
13636
13552
  }
13637
- return {
13638
- configJsonRef,
13639
- writeCaddyConfig,
13640
- cleanUp
13553
+ let interrupted = false;
13554
+ const onSigint = () => {
13555
+ interrupted = true;
13641
13556
  };
13557
+ process6.on("SIGINT", onSigint);
13558
+ try {
13559
+ const { status, signal } = await runPrompt(sudoCommand);
13560
+ if (status === 0)
13561
+ return { ok: true };
13562
+ const cancelled = interrupted || signal === "SIGINT";
13563
+ return {
13564
+ ok: false,
13565
+ denied: true,
13566
+ message: cancelled ? "administrator permission was cancelled" : "administrator permission is required to edit the hosts file and bind ports 80/443"
13567
+ };
13568
+ } finally {
13569
+ process6.off("SIGINT", onSigint);
13570
+ }
13571
+ }
13572
+ function runPrompt(sudoCommand) {
13573
+ return new Promise((resolve2) => {
13574
+ const restore = takeBackTerminal();
13575
+ const child = spawn2(sudoCommand, ["-v"], { stdio: "inherit" });
13576
+ const finish = (result) => {
13577
+ restore();
13578
+ resolve2(result);
13579
+ };
13580
+ child.on("error", () => finish({ status: 1, signal: null }));
13581
+ child.on("exit", (status, signal) => finish({ status, signal }));
13582
+ });
13583
+ }
13584
+ function takeBackTerminal() {
13585
+ const stdin = process6.stdin;
13586
+ if (!stdin.isTTY || typeof stdin.setRawMode !== "function")
13587
+ return () => {
13588
+ };
13589
+ const wasRaw = stdin.isRaw === true;
13590
+ stdin.pause();
13591
+ try {
13592
+ stdin.setRawMode(false);
13593
+ } catch {
13594
+ stdin.resume();
13595
+ return () => {
13596
+ };
13597
+ }
13598
+ return () => {
13599
+ if (wasRaw) {
13600
+ try {
13601
+ stdin.setRawMode(true);
13602
+ } catch {
13603
+ }
13604
+ }
13605
+ stdin.resume();
13606
+ };
13607
+ }
13608
+ var PrivilegeDeniedError = class extends Error {
13609
+ constructor(message) {
13610
+ super(message);
13611
+ this.name = "PrivilegeDeniedError";
13612
+ }
13613
+ };
13614
+ async function startPrivilegedHelper(options) {
13615
+ var _a4, _b3;
13616
+ const {
13617
+ socketPath,
13618
+ token,
13619
+ helperEntry,
13620
+ helperArgs = [],
13621
+ sudoCommand = "sudo",
13622
+ skipAuth = false,
13623
+ direct = false,
13624
+ env: env2 = process6.env,
13625
+ log,
13626
+ connectTimeoutMs = 12e4
13627
+ } = options;
13628
+ if (!skipAuth && !direct) {
13629
+ const auth = await authenticateSudo(sudoCommand, options.reason);
13630
+ if (!auth.ok) {
13631
+ const message = auth.message ?? "administrator permission is required";
13632
+ throw auth.denied ? new PrivilegeDeniedError(message) : new Error(message);
13633
+ }
13634
+ }
13635
+ const forwarded = collectForwardedEnv(env2);
13636
+ const forwardedArgs = Object.entries(forwarded).map(([key, value2]) => `${key}=${value2}`);
13637
+ const childArgv = [
13638
+ ...helperArgs,
13639
+ "--socket",
13640
+ socketPath,
13641
+ "--token",
13642
+ token,
13643
+ ...typeof process6.getuid === "function" ? ["--owner-uid", String(process6.getuid())] : [],
13644
+ ...typeof process6.getgid === "function" ? ["--owner-gid", String(process6.getgid())] : [],
13645
+ ...options.caddyStoragePath ? ["--caddy-storage", options.caddyStoragePath] : [],
13646
+ "--caddy",
13647
+ options.caddyBin,
13648
+ "--caddy-config",
13649
+ options.caddyConfigPath,
13650
+ ...options.caddyAdminSocket ? ["--caddy-admin", options.caddyAdminSocket] : []
13651
+ ];
13652
+ let child;
13653
+ if (!direct && platform() === "win32") {
13654
+ await spawnElevatedOnWindows({ file: helperEntry, args: childArgv, cwd: process6.cwd() });
13655
+ } else {
13656
+ const command = direct ? helperEntry : sudoCommand;
13657
+ const spawnArgs = direct ? childArgv : ["-n", "env", ...forwardedArgs, helperEntry, ...childArgv];
13658
+ child = spawn2(command, spawnArgs, {
13659
+ stdio: ["ignore", "pipe", "pipe"]
13660
+ });
13661
+ (_a4 = child.stdout) == null ? void 0 : _a4.on("data", (data) => log == null ? void 0 : log(data.toString().trimEnd()));
13662
+ (_b3 = child.stderr) == null ? void 0 : _b3.on("data", (data) => log == null ? void 0 : log(data.toString().trimEnd()));
13663
+ const exited = new Promise((resolve2) => child.once("exit", (code) => resolve2(code)));
13664
+ const earlyExit = await Promise.race([
13665
+ exited,
13666
+ new Promise((resolve2) => setTimeout(() => resolve2(void 0), 500))
13667
+ ]);
13668
+ if (earlyExit !== void 0 && earlyExit !== 0) {
13669
+ throw new Error(
13670
+ `privileged helper exited with code ${earlyExit}. Administrator permission was refused, or sudo is not available.`
13671
+ );
13672
+ }
13673
+ }
13674
+ try {
13675
+ const client = await connectClient({ socketPath, token, timeoutMs: connectTimeoutMs });
13676
+ return {
13677
+ client,
13678
+ async close() {
13679
+ await client.close().catch(() => {
13680
+ });
13681
+ child == null ? void 0 : child.unref();
13682
+ }
13683
+ };
13684
+ } catch (error) {
13685
+ try {
13686
+ child == null ? void 0 : child.kill();
13687
+ } catch {
13688
+ }
13689
+ throw error;
13690
+ }
13691
+ }
13692
+ async function connectExistingHelper(socketPath, token, timeoutMs = 1500) {
13693
+ try {
13694
+ return await connectClient({ socketPath, token, timeoutMs });
13695
+ } catch {
13696
+ return void 0;
13697
+ }
13642
13698
  }
13643
13699
 
13644
- // src/caddy/log.ts
13645
- function isCaddyReloadCancellation(line) {
13700
+ // src/privileged/session.ts
13701
+ function tokenPath(runtimeDir) {
13702
+ return join4(runtimeDir, "helper.token");
13703
+ }
13704
+ function sessionSocketPath(runtimeDir) {
13705
+ if (platform2() === "win32")
13706
+ return `\\\\.\\pipe\\uhrp-${Buffer.from(runtimeDir).toString("hex").slice(0, 40)}`;
13707
+ return join4(runtimeDir, "helper.sock");
13708
+ }
13709
+ async function openHelperSession(scope2) {
13710
+ const socketPath = sessionSocketPath(scope2.runtimeDir);
13711
+ const release = await acquireStartLock(scope2.runtimeDir);
13646
13712
  try {
13647
- const entry = JSON.parse(line);
13648
- return entry.logger === "tls" && typeof entry.error === "string" && entry.error.endsWith("context canceled");
13713
+ const reused = await tryReuse(socketPath, scope2);
13714
+ if (reused)
13715
+ return reused;
13716
+ return await startNew(socketPath, scope2);
13717
+ } finally {
13718
+ release();
13719
+ }
13720
+ }
13721
+ async function tryReuse(socketPath, scope2) {
13722
+ if (!existsSync4(socketPath) && platform2() !== "win32")
13723
+ return void 0;
13724
+ const token = await readToken(scope2.runtimeDir);
13725
+ if (!token)
13726
+ return void 0;
13727
+ const reused = await connectExistingHelper(socketPath, token);
13728
+ if (!reused)
13729
+ return void 0;
13730
+ return {
13731
+ client: reused,
13732
+ reused: true,
13733
+ close: async () => {
13734
+ await reused.close();
13735
+ }
13736
+ };
13737
+ }
13738
+ async function startNew(socketPath, scope2) {
13739
+ const token = createHelperToken();
13740
+ const started = await startPrivilegedHelper({
13741
+ socketPath,
13742
+ token,
13743
+ helperEntry: scope2.helperEntry,
13744
+ helperArgs: scope2.helperArgs,
13745
+ sudoCommand: scope2.sudoCommand,
13746
+ skipAuth: scope2.skipAuth,
13747
+ direct: scope2.direct,
13748
+ env: scope2.env,
13749
+ caddyStoragePath: scope2.caddyStoragePath,
13750
+ caddyBin: scope2.caddyBin,
13751
+ caddyConfigPath: scope2.caddyConfigPath,
13752
+ caddyAdminSocket: scope2.caddyAdminSocket,
13753
+ reason: scope2.reason,
13754
+ log: scope2.log
13755
+ });
13756
+ await writeToken(scope2.runtimeDir, token);
13757
+ return {
13758
+ client: started.client,
13759
+ reused: false,
13760
+ close: async () => {
13761
+ await started.close();
13762
+ }
13763
+ };
13764
+ }
13765
+ async function acquireStartLock(runtimeDir) {
13766
+ const lockPath = join4(runtimeDir, "helper.start.lock");
13767
+ try {
13768
+ await writeFile(lockPath, "", { flag: "a" });
13649
13769
  } catch {
13650
- return false;
13651
13770
  }
13771
+ const release = await lockfile2.lock(lockPath, {
13772
+ realpath: false,
13773
+ stale: 3e4,
13774
+ retries: { retries: 100, minTimeout: 50, maxTimeout: 200 }
13775
+ });
13776
+ return () => {
13777
+ void release().catch(() => {
13778
+ });
13779
+ };
13780
+ }
13781
+ async function readToken(runtimeDir) {
13782
+ try {
13783
+ const content = await readFile2(tokenPath(runtimeDir), "utf8");
13784
+ const token = content.trim();
13785
+ return token === "" ? void 0 : token;
13786
+ } catch {
13787
+ return void 0;
13788
+ }
13789
+ }
13790
+ async function writeToken(runtimeDir, token) {
13791
+ try {
13792
+ await writeFile(tokenPath(runtimeDir), token, { mode: 384 });
13793
+ } catch {
13794
+ }
13795
+ }
13796
+
13797
+ // src/caddy/privileged.ts
13798
+ function resolvePrivilegedEnv() {
13799
+ const moduleDir = typeof __dirname === "string" ? __dirname : dirname3(fileURLToPath(import.meta.url));
13800
+ const resolved = resolveHelperEntry({ moduleDir });
13801
+ return { helperEntry: resolved.entry, helperArgs: resolved.args };
13802
+ }
13803
+ var HelperCaddyProcess = class extends EventEmitter {
13804
+ constructor(client) {
13805
+ super();
13806
+ this.client = client;
13807
+ this.stdout = new EventEmitter();
13808
+ this.stderr = new EventEmitter();
13809
+ this.finished = false;
13810
+ this.unsubscribe = client.onEvent((event) => this.handleEvent(event));
13811
+ }
13812
+ handleEvent(event) {
13813
+ if (event.type !== "event")
13814
+ return;
13815
+ if (event.kind === "caddy.stdout") {
13816
+ this.stdout.emit("data", Buffer2.from(event.data));
13817
+ return;
13818
+ }
13819
+ if (event.kind === "caddy.stderr") {
13820
+ this.stderr.emit("data", Buffer2.from(event.data));
13821
+ return;
13822
+ }
13823
+ if (event.kind === "caddy.exit") {
13824
+ this.finished = true;
13825
+ this.emit("exit", event.code, event.signal);
13826
+ }
13827
+ }
13828
+ /** Asks the helper to stop Caddy; the helper also stops it on disconnect. */
13829
+ kill() {
13830
+ this.unsubscribe();
13831
+ if (this.finished)
13832
+ return;
13833
+ this.finished = true;
13834
+ void this.client.call("caddy.stop").catch(() => {
13835
+ });
13836
+ }
13837
+ };
13838
+ function caddyStoragePath() {
13839
+ return process7.platform === "win32" ? join5(process7.env.AppData ?? "", "Caddy") : join5(process7.env.HOME ?? "", "Library/Application Support/Caddy");
13840
+ }
13841
+ function openPrivilegedSession(runtimeDir, options) {
13842
+ const env2 = resolvePrivilegedEnv();
13843
+ return openHelperSession({
13844
+ runtimeDir,
13845
+ helperEntry: env2.helperEntry,
13846
+ helperArgs: env2.helperArgs,
13847
+ direct: options.direct,
13848
+ // Caddy keeps its PKI under the user's home; the helper runs it as root, so
13849
+ // it must know which tree to hand back afterwards.
13850
+ caddyStoragePath: caddyStoragePath(),
13851
+ // The binary and Caddyfile are fixed here: the privileged helper must never
13852
+ // execute a path supplied over the socket.
13853
+ caddyBin: options.caddyBin,
13854
+ caddyConfigPath: options.caddyConfigPath,
13855
+ caddyAdminSocket: options.caddyAdminSocket,
13856
+ reason: options.reason,
13857
+ log: options.log
13858
+ });
13652
13859
  }
13653
13860
 
13654
13861
  // src/caddy/tls-health.ts
13655
- import { checkServerIdentity, connect } from "node:tls";
13862
+ import { checkServerIdentity, connect as connect2 } from "node:tls";
13656
13863
  function assessTlsCertificate(certificate, hostname, now = Date.now(), verifyHostname = checkServerIdentity) {
13657
13864
  if (!certificate.valid_to)
13658
13865
  return { healthy: false, reason: "certificate_missing" };
@@ -13671,7 +13878,7 @@ function assessTlsCertificate(certificate, hostname, now = Date.now(), verifyHos
13671
13878
  }
13672
13879
  function probeLocalTls(hostname, options = {}) {
13673
13880
  const {
13674
- connect: openTlsConnection = connect,
13881
+ connect: openTlsConnection = connect2,
13675
13882
  port = 443,
13676
13883
  timeoutMs = 1e3
13677
13884
  } = options;
@@ -13733,40 +13940,8 @@ function formatTlsHealthFailure(hostname, result) {
13733
13940
  }
13734
13941
 
13735
13942
  // src/caddy/utils.ts
13736
- import { exec as exec2 } from "node:child_process";
13737
- import { createServer } from "node:net";
13738
13943
  import ora from "ora";
13739
13944
  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
13945
  function getNumber(number2) {
13771
13946
  if (number2 <= 0)
13772
13947
  return "0%";
@@ -13805,26 +13980,26 @@ async function download() {
13805
13980
  if (await testCaddy())
13806
13981
  return caddyPath;
13807
13982
  return new Promise((resolve2, reject2) => {
13808
- if (!existsSync3(TEMP_DIR)) {
13983
+ if (!existsSync5(TEMP_DIR)) {
13809
13984
  mkdirSync(TEMP_DIR, { recursive: true });
13810
- chmodSync2(TEMP_DIR, 511);
13985
+ chmodSync(TEMP_DIR, 448);
13811
13986
  }
13812
13987
  const file = createWriteStream(caddyPath);
13813
- let _platform = platform().toString();
13988
+ let _platform = platform3().toString();
13814
13989
  _platform === "win32" && (_platform = "windows");
13815
- let _arch = process4.arch.toString();
13990
+ let _arch = process8.arch.toString();
13816
13991
  _arch === "x64" && (_arch = "amd64");
13817
13992
  const support = supportList.find((item) => item.platform === _platform && item.arch === _arch);
13818
13993
  if (!support)
13819
13994
  return reject2(new Error("not support"));
13820
13995
  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;
13996
+ existsSync5(caddyPath) && unlinkSync2(caddyPath);
13997
+ const httpProxy = process8.env.HTTP_PROXY || process8.env.http_proxy;
13998
+ const httpsProxy = process8.env.HTTPS_PROXY || process8.env.https_proxy;
13824
13999
  const httpAgent = httpProxy ? new HttpProxyAgent(httpProxy) : void 0;
13825
14000
  const httpsAgent = httpsProxy ? new HttpsProxyAgent(httpsProxy) : void 0;
13826
14001
  const chmodCaddyOnce = once(() => {
13827
- chmodSync2(caddyPath, 511);
14002
+ chmodSync(caddyPath, 493);
13828
14003
  });
13829
14004
  got.stream(dowmloadLink, {
13830
14005
  agent: {
@@ -13836,9 +14011,9 @@ async function download() {
13836
14011
  chmodCaddyOnce();
13837
14012
  }).pipe(file).on("finish", () => {
13838
14013
  logProgressOver();
13839
- if (process4.platform === "win32")
14014
+ if (process8.platform === "win32")
13840
14015
  return resolve2(caddyPath);
13841
- chmodSync2(caddyPath, 511);
14016
+ chmodSync(caddyPath, 493);
13842
14017
  resolve2(caddyPath);
13843
14018
  }).on("error", (err) => {
13844
14019
  reject2(err);
@@ -13846,26 +14021,41 @@ async function download() {
13846
14021
  });
13847
14022
  }
13848
14023
  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", () => {
14024
+ return new Promise((resolve2) => {
14025
+ if (!existsSync5(caddyPath))
13855
14026
  return resolve2(false);
13856
- });
13857
- child.on("error", (err) => {
13858
- return reject2(err);
13859
- });
13860
- child.stdout.on("data", (_data) => {
13861
- return resolve2(true);
14027
+ try {
14028
+ chmodSync(caddyPath, 493);
14029
+ } catch {
14030
+ }
14031
+ execFile(caddyPath, [], { timeout: 1e4 }, (error, stdout) => {
14032
+ if (error && !stdout)
14033
+ return resolve2(false);
14034
+ resolve2(stdout.length > 0);
13862
14035
  });
13863
14036
  });
13864
14037
  }
14038
+ function caddyRootPath() {
14039
+ return join6(
14040
+ process8.platform === "win32" ? `${process8.env.AppData}/Caddy` : `${process8.env.HOME}/Library/Application Support/Caddy`,
14041
+ "./pki/authorities/local"
14042
+ );
14043
+ }
14044
+ async function renderCaddyfile(proxies) {
14045
+ const ctx = validateTemplateContext({
14046
+ caddy_root: caddyRootPath(),
14047
+ admin_socket: caddyAdminSocketPath,
14048
+ proxies: Object.values(proxies)
14049
+ });
14050
+ const content = await genCaddyfile(ctx);
14051
+ const temp = `${caddyFilePath}.${process8.pid}.tmp`;
14052
+ await writeFile2(temp, content);
14053
+ await rename(temp, caddyFilePath);
14054
+ }
13865
14055
  var caddyConfig;
13866
14056
  function getCaddyConfig() {
13867
14057
  if (!caddyConfig) {
13868
- caddyConfig = useCaddyConfig();
14058
+ caddyConfig = useCaddyConfig({ renderCaddyfile });
13869
14059
  }
13870
14060
  return caddyConfig;
13871
14061
  }
@@ -13880,80 +14070,92 @@ function splitHostPort(addr) {
13880
14070
  }
13881
14071
  return { host: addr.slice(0, lastColon), port: addr.slice(lastColon + 1) };
13882
14072
  }
14073
+ var defaultDependencies = {
14074
+ openSession: (runtimeDir, reason) => openPrivilegedSession(runtimeDir, {
14075
+ log: (message) => consola.debug(message),
14076
+ // Both paths are fixed here, before any socket traffic: the privileged
14077
+ // helper must never execute something named in a request.
14078
+ caddyBin: caddyPath,
14079
+ caddyConfigPath: caddyFilePath,
14080
+ caddyAdminSocket: caddyAdminSocketPath,
14081
+ reason
14082
+ }),
14083
+ config: () => getCaddyConfig()
14084
+ };
13883
14085
  var CaddyInstant = class {
13884
- constructor() {
14086
+ constructor(deps = {}) {
13885
14087
  this.inited = false;
13886
14088
  this.stoped = false;
13887
- /** has locked when start */
13888
- this.locked = false;
13889
14089
  this._stopEffects = [];
13890
- testCaddy().then(async () => {
13891
- this.inited = true;
13892
- });
13893
- this.locked = this.checkLock();
14090
+ /** Identifies this instance's routes in the shared config. */
14091
+ this.proxyKey = `${process8.pid}-${Math.random().toString(36).slice(2, 8)}`;
14092
+ this.deps = { ...defaultDependencies, ...deps };
13894
14093
  }
13895
- checkLock() {
13896
- if (!existsSync3(caddyLockFilePath))
13897
- writeFileSync2(caddyLockFilePath, "");
13898
- return lockfile.checkSync(caddyLockFilePath);
14094
+ /**
14095
+ * Connects to the privileged helper, starting it once if needed. It is
14096
+ * reused across instances so a second dev server does not ask for a
14097
+ * password again.
14098
+ */
14099
+ async session(reason) {
14100
+ if (this._session && !this._session.client.connected)
14101
+ this._session = void 0;
14102
+ if (!this._session)
14103
+ this._session = await this.deps.openSession(TEMP_DIR, reason);
14104
+ return this._session;
13899
14105
  }
13900
14106
  async getCaddyfile() {
13901
- if (!existsSync3(caddyFilePath)) {
14107
+ if (!existsSync5(caddyFilePath)) {
13902
14108
  this.caddyfile = "";
13903
14109
  return "";
13904
14110
  }
13905
- this.caddyfile = await readFile2(caddyFilePath, "utf-8");
14111
+ this.caddyfile = await readFile3(caddyFilePath, "utf-8");
13906
14112
  return this.caddyfile;
13907
14113
  }
13908
14114
  get caddyRoot() {
13909
- return join3(
13910
- process4.platform === "win32" ? `${process4.env.AppData}/Caddy` : `${process4.env.HOME}/Library/Application Support/Caddy`,
13911
- "./pki/authorities/local"
13912
- );
14115
+ return caddyRootPath();
13913
14116
  }
13914
14117
  async writeCaddyfile() {
13915
- return await writeFile(caddyFilePath, this.caddyfile || "");
14118
+ return await writeFile2(caddyFilePath, this.caddyfile || "");
13916
14119
  }
13917
14120
  async deleteCaddyfile() {
13918
- return await unlink3(caddyFilePath);
14121
+ return await unlink(caddyFilePath);
13919
14122
  }
13920
14123
  async init() {
13921
14124
  await download();
13922
14125
  this.inited = true;
13923
14126
  }
14127
+ /**
14128
+ * Hands the Caddy storage directory back to the developer. Local CA data
14129
+ * created by an earlier root-owned run must stay readable for `tls internal`
14130
+ * to keep serving the same certificate the browser already trusts.
14131
+ */
14132
+ /**
14133
+ * Installs Caddy's local root CA so the browser stops warning about
14134
+ * `tls internal` certificates. Generating the CA and trusting it are separate
14135
+ * steps: a new CA appears whenever the previous one expires or the storage is
14136
+ * replaced, so this runs on every start instead of once.
14137
+ *
14138
+ * The helper owns both the binary path and the command, so nothing here can
14139
+ * be turned into an arbitrary root execution.
14140
+ */
14141
+ async trustLocalCa(session) {
14142
+ try {
14143
+ const result = await session.client.call("ca.trust");
14144
+ if (result.trusted)
14145
+ consola.debug(`Caddy local CA is trusted
14146
+ ${result.output}`);
14147
+ } catch (error) {
14148
+ consola.warn(
14149
+ `could not install the Caddy root certificate automatically: ${error.message}
14150
+ Run \`${caddyPath} trust\` manually if the browser warns about the certificate.`
14151
+ );
14152
+ }
14153
+ }
13924
14154
  async ensureTlsReady(targetHost) {
13925
14155
  const health = await waitForLocalTls(targetHost);
13926
14156
  if (!health.healthy)
13927
14157
  throw new Error(formatTlsHealthFailure(targetHost, health));
13928
14158
  }
13929
- async updateCaddyfile() {
13930
- const { configJsonRef } = getCaddyConfig();
13931
- const proxies = Object.values(configJsonRef() || {});
13932
- const ctx = validateTemplateContext({
13933
- caddy_root: this.caddyRoot,
13934
- proxies
13935
- });
13936
- this.caddyfile = await genCaddyfile(ctx);
13937
- await this.writeCaddyfile();
13938
- }
13939
- async stopCaddy() {
13940
- var _a4;
13941
- try {
13942
- await got.post("http://127.0.0.1:2019/stop", {
13943
- headers: {
13944
- Origin: "http://localhost:2019"
13945
- },
13946
- retry: {
13947
- limit: 0
13948
- },
13949
- timeout: {
13950
- request: 2e3
13951
- }
13952
- });
13953
- } catch {
13954
- }
13955
- (_a4 = this._caddyChild) == null ? void 0 : _a4.kill();
13956
- }
13957
14159
  /**
13958
14160
  * @param source like `127.0.0.1:8080`
13959
14161
  * @param target like `test.abc.com`. And if you provide a port ,it will be ignore.
@@ -13974,10 +14176,10 @@ var CaddyInstant = class {
13974
14176
  await this.init();
13975
14177
  const sourceHost = splitHostPort(source).host;
13976
14178
  const targetHost = splitHostPort(target).host;
13977
- if (!await addHost(sourceHost, targetHost))
13978
- throw new Error("update host failed");
14179
+ const session = await this.session({ target: targetHost, https });
14180
+ await session.client.call("hosts.add", { ip: sourceHost, host: targetHost });
13979
14181
  consola.success("update host success\n");
13980
- const normalizeBase = (b) => {
14182
+ const normalizeBase2 = (b) => {
13981
14183
  let out = b || "/";
13982
14184
  if (!out.startsWith("/"))
13983
14185
  out = `/${out}`;
@@ -13985,7 +14187,7 @@ var CaddyInstant = class {
13985
14187
  out = `${out}/`;
13986
14188
  return out;
13987
14189
  };
13988
- const baseNormalized = normalizeBase(base);
14190
+ const baseNormalized = normalizeBase2(base);
13989
14191
  const proxies = [
13990
14192
  {
13991
14193
  target: targetHost,
@@ -13996,176 +14198,138 @@ var CaddyInstant = class {
13996
14198
  healthCheck
13997
14199
  }
13998
14200
  ];
13999
- const { writeCaddyConfig } = getCaddyConfig();
14000
- writeCaddyConfig(proxies);
14001
- await this.updateCaddyfile();
14002
- let skipInitialCaddyfileEffect = true;
14003
- this._stopEffects.push(
14004
- effect(() => {
14005
- getCaddyConfig().configJsonRef();
14006
- if (skipInitialCaddyfileEffect) {
14007
- skipInitialCaddyfileEffect = false;
14008
- return;
14009
- }
14010
- void this.updateCaddyfile();
14011
- })
14012
- );
14013
- if (!existsSync3(caddyLockFilePath))
14014
- writeFileSync2(caddyLockFilePath, "");
14015
- 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);
14020
- }
14201
+ const { writeCaddyConfig } = this.deps.config();
14202
+ await writeCaddyConfig(proxies, this.proxyKey);
14203
+ await session.client.call("port.free", { port: 443 });
14204
+ if (process8.platform === "win32" || !https)
14205
+ await session.client.call("port.free", { port: 80 });
14021
14206
  return new Promise((resolve2, reject2) => {
14022
- var _a4, _b3;
14023
14207
  let startupCheckStarted = false;
14024
14208
  const resolveWhenReady = async () => {
14025
14209
  if (startupCheckStarted)
14026
14210
  return;
14027
14211
  startupCheckStarted = true;
14028
14212
  try {
14029
- if (https)
14213
+ if (https) {
14214
+ await this.trustLocalCa(session);
14030
14215
  await this.ensureTlsReady(targetHost);
14216
+ }
14031
14217
  resolve2();
14032
14218
  } catch (error) {
14033
- if (!this.locked)
14034
- await this.baseCleanup(restore);
14219
+ await this.baseCleanup(restore);
14035
14220
  reject2(error);
14036
14221
  }
14037
14222
  };
14038
14223
  const setupCleanup = () => {
14039
- process4.on("SIGINT", async () => {
14224
+ process8.on("SIGINT", async () => {
14040
14225
  if (this.stoped)
14041
14226
  return;
14042
- process4.stdin.resume();
14227
+ process8.stdin.resume();
14043
14228
  try {
14044
14229
  await this.baseCleanup(restore);
14045
14230
  } finally {
14046
14231
  this.stoped = true;
14047
- process4.nextTick(() => {
14048
- process4.exit();
14232
+ process8.nextTick(() => {
14233
+ process8.exit();
14049
14234
  });
14050
14235
  }
14051
14236
  });
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
- });
14237
+ const originalExit = process8.exit.bind(process8);
14238
+ process8.exit = async (code) => {
14074
14239
  if (this.stoped)
14075
14240
  return originalExit(code);
14076
- process4.stdin.resume();
14241
+ process8.stdin.resume();
14077
14242
  try {
14078
14243
  await this.baseCleanup();
14079
14244
  } finally {
14080
14245
  this.stoped = true;
14081
- process4.nextTick(() => {
14246
+ process8.nextTick(() => {
14082
14247
  originalExit(code);
14083
14248
  });
14084
14249
  }
14085
14250
  };
14086
14251
  };
14087
- if (!this.locked) {
14088
- this._caddyChild = process4.platform !== "win32" ? spawn("sudo", ["-E", caddyPath, "run", "--config", caddyFilePath, "--watch"]) : spawn(caddyPath, ["run", "--config", caddyFilePath, "--watch"]);
14089
- 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}
14252
+ setupCleanup();
14253
+ void (async () => {
14254
+ try {
14255
+ const child = new HelperCaddyProcess(session.client);
14256
+ this._caddyChild = child;
14257
+ const started = await session.client.call("caddy.start");
14258
+ child.on("exit", (code) => {
14259
+ if (code !== null && code !== 0)
14260
+ reject2(new Error(`Caddy exited with code ${code}`));
14261
+ });
14262
+ if ((started == null ? void 0 : started.started) === false) {
14263
+ consola.info("Caddy is already running; added this route to it.");
14264
+ void resolveWhenReady();
14265
+ return;
14266
+ }
14267
+ child.stderr.on("data", async (data) => {
14268
+ const lines = data.toString().split("\n").map((line) => line.trim());
14269
+ for (const line of lines) {
14270
+ showCaddyLog && line && console.info(line);
14271
+ if (isCaddyReloadCancellation(line)) {
14272
+ consola.info("Caddy restarted before TLS issuance completed; retrying.\n");
14273
+ continue;
14274
+ }
14275
+ try {
14276
+ if (line.includes("Error:") || line && JSON.parse(line).level === "error") {
14277
+ if (line.includes("parsing caddyfile tokens")) {
14278
+ consola.error("Caddyfile syntax error, please contact the author:\n", `${this.caddyfile}
14105
14279
 
14106
14280
  ${line}
14107
14281
  `);
14108
- await this.baseCleanup();
14109
- process4.exit();
14110
- } else {
14111
- consola.error(`${line}
14282
+ await this.baseCleanup();
14283
+ process8.exit();
14284
+ } else {
14285
+ consola.error(`${line}
14112
14286
  `);
14113
- return reject2(line);
14287
+ return reject2(line);
14288
+ }
14114
14289
  }
14290
+ } catch {
14115
14291
  }
14116
- } catch {
14292
+ if (line.includes("config file changed"))
14293
+ consola.success("Detect added a new reverse proxy config, restarted.\n");
14294
+ if (line.includes("caddy proxying") || line.includes("serving initial"))
14295
+ void resolveWhenReady();
14117
14296
  }
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"))
14121
- void resolveWhenReady();
14122
- }
14123
- });
14124
- (_b3 = this._caddyChild.stdout) == null ? void 0 : _b3.on("data", (_data) => {
14125
- consola.info(_data.toString());
14126
- void resolveWhenReady();
14127
- });
14128
- setupCleanup();
14129
- } else {
14130
- consola.info("Caddy is running in another process.");
14131
- void (async () => {
14132
- try {
14133
- if (https)
14134
- await this.ensureTlsReady(targetHost);
14135
- setupCleanup();
14136
- resolve2();
14137
- } catch (error) {
14138
- reject2(error);
14139
- }
14140
- })();
14141
- }
14297
+ });
14298
+ child.stdout.on("data", (data) => {
14299
+ consola.info(data.toString());
14300
+ void resolveWhenReady();
14301
+ });
14302
+ } catch (error) {
14303
+ await this.baseCleanup(restore);
14304
+ reject2(error);
14305
+ }
14306
+ })();
14142
14307
  });
14143
14308
  }
14144
14309
  async baseCleanup(restore = true) {
14310
+ var _a4;
14145
14311
  this._stopEffects.forEach((fn) => fn());
14312
+ this._stopEffects.length = 0;
14146
14313
  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");
14314
+ if (restore && this._source && this._target && this._session) {
14315
+ const sourceHost = splitHostPort(this._source).host;
14316
+ const targetHost = splitHostPort(this._target).host;
14317
+ await this._session.client.call("hosts.remove", { ip: sourceHost, host: targetHost });
14318
+ if (sourceHost === "localhost")
14319
+ await this._session.client.call("hosts.remove", { ip: "127.0.0.1", host: targetHost });
14320
+ consola.success("Restore host success.\n");
14152
14321
  }
14153
14322
  } catch (e) {
14154
- consola.error(e);
14155
- consola.fail("Restore host failed.\n");
14323
+ if (((_a4 = this._session) == null ? void 0 : _a4.client.connected) === false) {
14324
+ consola.debug("hosts entries are restored by the privileged helper on disconnect");
14325
+ } else {
14326
+ consola.error(e);
14327
+ consola.fail("Restore host failed.\n");
14328
+ }
14156
14329
  }
14157
- if (!this.locked && !this.stoped) {
14158
- await this.stopCaddy();
14330
+ if (!this.stoped) {
14159
14331
  try {
14160
- await lockfile.unlock(caddyLockFilePath).catch(() => {
14161
- });
14162
- await unlink3(caddyFilePath).catch(() => {
14163
- });
14164
- await unlink3(caddyLockFilePath).catch(() => {
14165
- });
14166
- if (caddyConfig) {
14167
- await caddyConfig.cleanUp();
14168
- }
14332
+ await this.deps.config().removeProxy(this.proxyKey);
14169
14333
  } catch (e) {
14170
14334
  consola.error(e);
14171
14335
  }
@@ -14177,7 +14341,7 @@ ${line}
14177
14341
  var config;
14178
14342
  var caddy;
14179
14343
  var hmrSseBridgeActive = false;
14180
- var cwd = process5.cwd();
14344
+ var cwd = process9.cwd();
14181
14345
  function colorUrl(url2) {
14182
14346
  return c.green(url2.replace(/:(\d+)\//, (_, port) => `:${c.bold(port)}/`));
14183
14347
  }
@@ -14212,16 +14376,27 @@ async function printForwardProxy() {
14212
14376
  }
14213
14377
  var vitePrintUrls = once((options, source, target, base = "/", _printUrls) => {
14214
14378
  _printUrls == null ? void 0 : _printUrls();
14379
+ if (isPrivilegeDenied())
14380
+ return;
14215
14381
  if (caddy)
14216
14382
  return;
14217
- caddy = new CaddyInstant();
14218
- caddy.run(source, target, {
14383
+ const instance = new CaddyInstant();
14384
+ caddy = instance;
14385
+ instance.run(source, target, {
14219
14386
  base,
14220
14387
  ...options
14221
14388
  }).then(async () => {
14222
14389
  await printForwardProxy();
14223
14390
  consola.success(` ${c.green("\u279C")} ${c.bold("run caddy reverse proxy success")}: ${colorUrl(`${options.https ? "https" : "http"}://${target}${base}`)}`);
14224
14391
  }).catch((e) => {
14392
+ if (caddy === instance)
14393
+ caddy = void 0;
14394
+ if (e instanceof PrivilegeDeniedError) {
14395
+ markPrivilegeDenied();
14396
+ consola.warn("reverse proxy skipped: administrator permission was not granted.");
14397
+ consola.info("Restart the dev server to enable it again.");
14398
+ return;
14399
+ }
14225
14400
  throw e;
14226
14401
  });
14227
14402
  });
@@ -14242,10 +14417,6 @@ var unpluginFactory = (options) => ({
14242
14417
  } = options;
14243
14418
  if (!enable)
14244
14419
  return;
14245
- if (!isAdmin()) {
14246
- consola.warn("please run as administrator");
14247
- return;
14248
- }
14249
14420
  if (!target) {
14250
14421
  consola.fail("please provide target");
14251
14422
  return;
@@ -14281,7 +14452,7 @@ var unpluginFactory = (options) => ({
14281
14452
  },
14282
14453
  webpack(compiler) {
14283
14454
  var _a4, _b3, _c2;
14284
- if (process5.env.NODE_ENV !== "development")
14455
+ if (process9.env.NODE_ENV !== "development")
14285
14456
  return;
14286
14457
  const {
14287
14458
  enable = true,
@@ -14289,10 +14460,6 @@ var unpluginFactory = (options) => ({
14289
14460
  } = options;
14290
14461
  if (!enable)
14291
14462
  return;
14292
- if (!isAdmin()) {
14293
- consola.warn("please run as administrator");
14294
- return;
14295
- }
14296
14463
  if (!target) {
14297
14464
  consola.fail("please provide target");
14298
14465
  return;
@@ -14306,9 +14473,11 @@ var unpluginFactory = (options) => ({
14306
14473
  port: 8080,
14307
14474
  ...compiler.options.devServer,
14308
14475
  // @ts-expect-error vuecli
14309
- ...(_a4 = process5.VUE_CLI_SERVICE) == null ? void 0 : _a4.projectOptions.devServer
14476
+ ...(_a4 = process9.VUE_CLI_SERVICE) == null ? void 0 : _a4.projectOptions.devServer
14310
14477
  };
14311
14478
  const source = `${devServer.host}:${devServer.port}`;
14479
+ if (isPrivilegeDenied())
14480
+ return;
14312
14481
  if (caddy)
14313
14482
  return;
14314
14483
  let base = "/";
@@ -14323,15 +14492,16 @@ var unpluginFactory = (options) => ({
14323
14492
  const _close = (_c2 = compiler.close) == null ? void 0 : _c2.bind(compiler);
14324
14493
  if (_close) {
14325
14494
  compiler.close = async (callback) => {
14326
- process5.on("exit", () => {
14495
+ process9.on("exit", () => {
14327
14496
  _close && _close(callback);
14328
14497
  });
14329
14498
  };
14330
14499
  } else {
14331
14500
  options.https = false;
14332
14501
  }
14333
- caddy = new CaddyInstant();
14334
- caddy.run(source, target, {
14502
+ const instance = new CaddyInstant();
14503
+ caddy = instance;
14504
+ instance.run(source, target, {
14335
14505
  base,
14336
14506
  ...options
14337
14507
  }).then(() => {
@@ -14340,12 +14510,20 @@ var unpluginFactory = (options) => ({
14340
14510
  consola.success(` ${c.green("\u279C")} ${c.bold("run caddy reverse proxy success")}: ${colorUrl(`${options.https ? "https" : "http"}://${target}${base}`)}`);
14341
14511
  });
14342
14512
  }).catch((e) => {
14513
+ if (caddy === instance)
14514
+ caddy = void 0;
14515
+ if (e instanceof PrivilegeDeniedError) {
14516
+ markPrivilegeDenied();
14517
+ consola.warn("reverse proxy skipped: administrator permission was not granted.");
14518
+ consola.info("Restart the dev server to enable it again.");
14519
+ return;
14520
+ }
14343
14521
  throw e;
14344
14522
  });
14345
14523
  },
14346
14524
  async rspack(compiler) {
14347
14525
  var _a4, _b3, _c2, _d2;
14348
- if (process5.env.NODE_ENV !== "development")
14526
+ if (process9.env.NODE_ENV !== "development")
14349
14527
  return;
14350
14528
  const {
14351
14529
  enable = true,
@@ -14353,10 +14531,6 @@ var unpluginFactory = (options) => ({
14353
14531
  } = options;
14354
14532
  if (!enable)
14355
14533
  return;
14356
- if (!isAdmin()) {
14357
- consola.warn("please run as administrator");
14358
- return;
14359
- }
14360
14534
  if (!target) {
14361
14535
  consola.fail("please provide target");
14362
14536
  return;
@@ -14374,9 +14548,10 @@ var unpluginFactory = (options) => ({
14374
14548
  }))) == null ? void 0 : _b3.content) == null ? void 0 : _c2.server
14375
14549
  };
14376
14550
  const source = `${devServer.host}:${devServer.port}`;
14551
+ if (isPrivilegeDenied())
14552
+ return;
14377
14553
  if (caddy)
14378
14554
  return;
14379
- caddy = new CaddyInstant();
14380
14555
  let base = "/";
14381
14556
  const publicPath = (_d2 = compiler.options.output) == null ? void 0 : _d2.publicPath;
14382
14557
  if (typeof publicPath === "string" && publicPath) {
@@ -14386,13 +14561,23 @@ var unpluginFactory = (options) => ({
14386
14561
  base = `/${base}`;
14387
14562
  if (base !== "/" && !base.endsWith("/"))
14388
14563
  base = `${base}/`;
14389
- caddy.run(source, target, {
14564
+ const instance = new CaddyInstant();
14565
+ caddy = instance;
14566
+ instance.run(source, target, {
14390
14567
  base,
14391
14568
  ...options
14392
14569
  }).then(async () => {
14393
14570
  await printForwardProxy();
14394
14571
  consola.success(` ${c.green("\u279C")} ${c.bold("run caddy reverse proxy success")}: ${colorUrl(`${options.https ? "https" : "http"}://${target}${base}`)}`);
14395
14572
  }).catch((e) => {
14573
+ if (caddy === instance)
14574
+ caddy = void 0;
14575
+ if (e instanceof PrivilegeDeniedError) {
14576
+ markPrivilegeDenied();
14577
+ consola.warn("reverse proxy skipped: administrator permission was not granted.");
14578
+ consola.info("Restart the dev server to enable it again.");
14579
+ return;
14580
+ }
14396
14581
  throw e;
14397
14582
  });
14398
14583
  }