unplugin-https-reverse-proxy 4.0.3 → 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 (62) hide show
  1. package/README.md +30 -6
  2. package/dist/{chunk-RSBXFJ3Z.js → chunk-C5A7XLKL.js} +9 -2
  3. package/dist/{chunk-2P7SUCQ3.js → chunk-EY3HXBJ4.js} +0 -26
  4. package/dist/chunk-RKHJN6KY.js +53 -0
  5. package/dist/{chunk-MD5CVZP7.js → chunk-U7KAIPZC.js} +982 -797
  6. package/dist/chunk-WOMR3ZLM.js +17 -0
  7. package/dist/esbuild.cjs +1086 -867
  8. package/dist/esbuild.js +5 -3
  9. package/dist/hmr-sse-bridge.cjs +12 -4
  10. package/dist/hmr-sse-bridge.d.cts +4 -3
  11. package/dist/hmr-sse-bridge.d.ts +4 -3
  12. package/dist/hmr-sse-bridge.js +5 -3
  13. package/dist/index.cjs +1086 -867
  14. package/dist/index.js +5 -3
  15. package/dist/nuxt.cjs +1057 -852
  16. package/dist/nuxt.js +6 -9
  17. package/dist/privilege-state.cjs +44 -0
  18. package/dist/privilege-state.d.cts +7 -0
  19. package/dist/privilege-state.d.ts +7 -0
  20. package/dist/privilege-state.js +10 -0
  21. package/dist/privileged-helper.cjs +824 -0
  22. package/dist/privileged-helper.d.cts +2 -0
  23. package/dist/privileged-helper.d.ts +2 -0
  24. package/dist/privileged-helper.js +797 -0
  25. package/dist/rollup.cjs +1086 -867
  26. package/dist/rollup.js +5 -3
  27. package/dist/rspack.cjs +1086 -867
  28. package/dist/rspack.js +5 -3
  29. package/dist/utils.cjs +0 -28
  30. package/dist/utils.d.cts +1 -3
  31. package/dist/utils.d.ts +1 -3
  32. package/dist/utils.js +1 -5
  33. package/dist/vite.cjs +1086 -867
  34. package/dist/vite.js +5 -3
  35. package/dist/webpack.cjs +1086 -867
  36. package/dist/webpack.js +5 -3
  37. package/package.json +1 -4
  38. package/src/caddy/caddyfile.ts +3 -0
  39. package/src/caddy/config.ts +195 -53
  40. package/src/caddy/constants.ts +30 -1
  41. package/src/caddy/index.ts +239 -206
  42. package/src/caddy/privileged.ts +124 -0
  43. package/src/caddy/utils.ts +0 -43
  44. package/src/hmr-sse-bridge.ts +14 -3
  45. package/src/index.ts +52 -25
  46. package/src/nuxt.ts +1 -6
  47. package/src/privilege-state.ts +23 -0
  48. package/src/privileged/bootstrap.ts +289 -0
  49. package/src/privileged/client.ts +288 -0
  50. package/src/privileged/entry.ts +73 -0
  51. package/src/privileged/hosts-file.ts +142 -0
  52. package/src/privileged/launch.ts +332 -0
  53. package/src/privileged/path-guard.ts +74 -0
  54. package/src/privileged/ports.ts +45 -0
  55. package/src/privileged/protocol.ts +111 -0
  56. package/src/privileged/server.ts +578 -0
  57. package/src/privileged/session.ts +169 -0
  58. package/src/privileged/validation.ts +38 -0
  59. package/src/privileged/windows-elevation.ts +80 -0
  60. package/src/privileged-helper.ts +123 -0
  61. package/src/utils.ts +0 -28
  62. package/src/host/index.ts +0 -52
package/dist/nuxt.cjs CHANGED
@@ -33,490 +33,34 @@ __export(nuxt_exports, {
33
33
  default: () => nuxt_default
34
34
  });
35
35
  module.exports = __toCommonJS(nuxt_exports);
36
- var import_node_process6 = __toESM(require("process"), 1);
36
+ var import_node_process10 = __toESM(require("process"), 1);
37
37
  var import_kit = require("@nuxt/kit");
38
38
 
39
39
  // src/index.ts
40
- var import_node_process5 = __toESM(require("process"), 1);
40
+ var import_node_process9 = __toESM(require("process"), 1);
41
41
  var import_console_table_printer = require("console-table-printer");
42
42
  var import_picocolors2 = __toESM(require("picocolors"), 1);
43
43
  var import_unplugin = require("unplugin");
44
44
 
45
45
  // src/caddy/index.ts
46
- var import_node_child_process4 = require("child_process");
47
- var import_node_fs3 = require("fs");
48
- var import_promises3 = require("fs/promises");
49
- var import_node_os3 = require("os");
50
- var import_node_path3 = require("path");
51
- var import_node_process4 = __toESM(require("process"), 1);
52
-
53
- // node_modules/.pnpm/alien-signals@2.0.7/node_modules/alien-signals/esm/system.mjs
54
- var ReactiveFlags;
55
- (function(ReactiveFlags2) {
56
- ReactiveFlags2[ReactiveFlags2["None"] = 0] = "None";
57
- ReactiveFlags2[ReactiveFlags2["Mutable"] = 1] = "Mutable";
58
- ReactiveFlags2[ReactiveFlags2["Watching"] = 2] = "Watching";
59
- ReactiveFlags2[ReactiveFlags2["RecursedCheck"] = 4] = "RecursedCheck";
60
- ReactiveFlags2[ReactiveFlags2["Recursed"] = 8] = "Recursed";
61
- ReactiveFlags2[ReactiveFlags2["Dirty"] = 16] = "Dirty";
62
- ReactiveFlags2[ReactiveFlags2["Pending"] = 32] = "Pending";
63
- })(ReactiveFlags || (ReactiveFlags = {}));
64
- function createReactiveSystem({ update, notify: notify2, unwatched }) {
65
- let currentVersion = 0;
66
- return {
67
- link: link2,
68
- unlink: unlink4,
69
- propagate: propagate2,
70
- checkDirty: checkDirty2,
71
- endTracking: endTracking2,
72
- startTracking: startTracking2,
73
- shallowPropagate: shallowPropagate2
74
- };
75
- function link2(dep, sub) {
76
- const prevDep = sub.depsTail;
77
- if (prevDep !== void 0 && prevDep.dep === dep) {
78
- return;
79
- }
80
- const nextDep = prevDep !== void 0 ? prevDep.nextDep : sub.deps;
81
- if (nextDep !== void 0 && nextDep.dep === dep) {
82
- nextDep.version = currentVersion;
83
- sub.depsTail = nextDep;
84
- return;
85
- }
86
- const prevSub = dep.subsTail;
87
- if (prevSub !== void 0 && prevSub.version === currentVersion && prevSub.sub === sub) {
88
- return;
89
- }
90
- const newLink = sub.depsTail = dep.subsTail = {
91
- version: currentVersion,
92
- dep,
93
- sub,
94
- prevDep,
95
- nextDep,
96
- prevSub,
97
- nextSub: void 0
98
- };
99
- if (nextDep !== void 0) {
100
- nextDep.prevDep = newLink;
101
- }
102
- if (prevDep !== void 0) {
103
- prevDep.nextDep = newLink;
104
- } else {
105
- sub.deps = newLink;
106
- }
107
- if (prevSub !== void 0) {
108
- prevSub.nextSub = newLink;
109
- } else {
110
- dep.subs = newLink;
111
- }
112
- }
113
- function unlink4(link3, sub = link3.sub) {
114
- const dep = link3.dep;
115
- const prevDep = link3.prevDep;
116
- const nextDep = link3.nextDep;
117
- const nextSub = link3.nextSub;
118
- const prevSub = link3.prevSub;
119
- if (nextDep !== void 0) {
120
- nextDep.prevDep = prevDep;
121
- } else {
122
- sub.depsTail = prevDep;
123
- }
124
- if (prevDep !== void 0) {
125
- prevDep.nextDep = nextDep;
126
- } else {
127
- sub.deps = nextDep;
128
- }
129
- if (nextSub !== void 0) {
130
- nextSub.prevSub = prevSub;
131
- } else {
132
- dep.subsTail = prevSub;
133
- }
134
- if (prevSub !== void 0) {
135
- prevSub.nextSub = nextSub;
136
- } else if ((dep.subs = nextSub) === void 0) {
137
- unwatched(dep);
138
- }
139
- return nextDep;
140
- }
141
- function propagate2(link3) {
142
- let next2 = link3.nextSub;
143
- let stack;
144
- top:
145
- do {
146
- const sub = link3.sub;
147
- let flags = sub.flags;
148
- if (!(flags & 60)) {
149
- sub.flags = flags | 32;
150
- } else if (!(flags & 12)) {
151
- flags = 0;
152
- } else if (!(flags & 4)) {
153
- sub.flags = flags & ~8 | 32;
154
- } else if (!(flags & 48) && isValidLink(link3, sub)) {
155
- sub.flags = flags | 40;
156
- flags &= 1;
157
- } else {
158
- flags = 0;
159
- }
160
- if (flags & 2) {
161
- notify2(sub);
162
- }
163
- if (flags & 1) {
164
- const subSubs = sub.subs;
165
- if (subSubs !== void 0) {
166
- const nextSub = (link3 = subSubs).nextSub;
167
- if (nextSub !== void 0) {
168
- stack = { value: next2, prev: stack };
169
- next2 = nextSub;
170
- }
171
- continue;
172
- }
173
- }
174
- if ((link3 = next2) !== void 0) {
175
- next2 = link3.nextSub;
176
- continue;
177
- }
178
- while (stack !== void 0) {
179
- link3 = stack.value;
180
- stack = stack.prev;
181
- if (link3 !== void 0) {
182
- next2 = link3.nextSub;
183
- continue top;
184
- }
185
- }
186
- break;
187
- } while (true);
188
- }
189
- function startTracking2(sub) {
190
- ++currentVersion;
191
- sub.depsTail = void 0;
192
- sub.flags = sub.flags & ~56 | 4;
193
- }
194
- function endTracking2(sub) {
195
- const depsTail = sub.depsTail;
196
- let toRemove = depsTail !== void 0 ? depsTail.nextDep : sub.deps;
197
- while (toRemove !== void 0) {
198
- toRemove = unlink4(toRemove, sub);
199
- }
200
- sub.flags &= ~4;
201
- }
202
- function checkDirty2(link3, sub) {
203
- let stack;
204
- let checkDepth = 0;
205
- top:
206
- do {
207
- const dep = link3.dep;
208
- const flags = dep.flags;
209
- let dirty = false;
210
- if (sub.flags & 16) {
211
- dirty = true;
212
- } else if ((flags & 17) === 17) {
213
- if (update(dep)) {
214
- const subs = dep.subs;
215
- if (subs.nextSub !== void 0) {
216
- shallowPropagate2(subs);
217
- }
218
- dirty = true;
219
- }
220
- } else if ((flags & 33) === 33) {
221
- if (link3.nextSub !== void 0 || link3.prevSub !== void 0) {
222
- stack = { value: link3, prev: stack };
223
- }
224
- link3 = dep.deps;
225
- sub = dep;
226
- ++checkDepth;
227
- continue;
228
- }
229
- if (!dirty) {
230
- const nextDep = link3.nextDep;
231
- if (nextDep !== void 0) {
232
- link3 = nextDep;
233
- continue;
234
- }
235
- }
236
- while (checkDepth--) {
237
- const firstSub = sub.subs;
238
- const hasMultipleSubs = firstSub.nextSub !== void 0;
239
- if (hasMultipleSubs) {
240
- link3 = stack.value;
241
- stack = stack.prev;
242
- } else {
243
- link3 = firstSub;
244
- }
245
- if (dirty) {
246
- if (update(sub)) {
247
- if (hasMultipleSubs) {
248
- shallowPropagate2(firstSub);
249
- }
250
- sub = link3.sub;
251
- continue;
252
- }
253
- } else {
254
- sub.flags &= ~32;
255
- }
256
- sub = link3.sub;
257
- const nextDep = link3.nextDep;
258
- if (nextDep !== void 0) {
259
- link3 = nextDep;
260
- continue top;
261
- }
262
- dirty = false;
263
- }
264
- return dirty;
265
- } while (true);
266
- }
267
- function shallowPropagate2(link3) {
268
- do {
269
- const sub = link3.sub;
270
- const flags = sub.flags;
271
- if ((flags & 48) === 32) {
272
- sub.flags = flags | 16;
273
- if (flags & 2) {
274
- notify2(sub);
275
- }
276
- }
277
- } while ((link3 = link3.nextSub) !== void 0);
278
- }
279
- function isValidLink(checkLink, sub) {
280
- let link3 = sub.depsTail;
281
- while (link3 !== void 0) {
282
- if (link3 === checkLink) {
283
- return true;
284
- }
285
- link3 = link3.prevDep;
286
- }
287
- return false;
288
- }
289
- }
290
-
291
- // node_modules/.pnpm/alien-signals@2.0.7/node_modules/alien-signals/esm/index.mjs
292
- var queuedEffects = [];
293
- var { link, unlink, propagate, checkDirty, endTracking, startTracking, shallowPropagate } = createReactiveSystem({
294
- update(signal2) {
295
- if ("getter" in signal2) {
296
- return updateComputed(signal2);
297
- } else {
298
- return updateSignal(signal2, signal2.value);
299
- }
300
- },
301
- notify,
302
- unwatched(node2) {
303
- if ("getter" in node2) {
304
- let toRemove = node2.deps;
305
- if (toRemove !== void 0) {
306
- node2.flags = 17;
307
- do {
308
- toRemove = unlink(toRemove, node2);
309
- } while (toRemove !== void 0);
310
- }
311
- } else if (!("previousValue" in node2)) {
312
- effectOper.call(node2);
313
- }
314
- }
315
- });
316
- var batchDepth = 0;
317
- var notifyIndex = 0;
318
- var queuedEffectsLength = 0;
319
- var activeSub;
320
- var activeScope;
321
- function setCurrentSub(sub) {
322
- const prevSub = activeSub;
323
- activeSub = sub;
324
- return prevSub;
325
- }
326
- function signal(initialValue) {
327
- return signalOper.bind({
328
- previousValue: initialValue,
329
- value: initialValue,
330
- subs: void 0,
331
- subsTail: void 0,
332
- flags: 1
333
- });
334
- }
335
- function computed(getter) {
336
- return computedOper.bind({
337
- value: void 0,
338
- subs: void 0,
339
- subsTail: void 0,
340
- deps: void 0,
341
- depsTail: void 0,
342
- flags: 17,
343
- getter
344
- });
345
- }
346
- function effect(fn) {
347
- const e = {
348
- fn,
349
- subs: void 0,
350
- subsTail: void 0,
351
- deps: void 0,
352
- depsTail: void 0,
353
- flags: 2
354
- };
355
- if (activeSub !== void 0) {
356
- link(e, activeSub);
357
- } else if (activeScope !== void 0) {
358
- link(e, activeScope);
359
- }
360
- const prev = setCurrentSub(e);
361
- try {
362
- e.fn();
363
- } finally {
364
- setCurrentSub(prev);
365
- }
366
- return effectOper.bind(e);
367
- }
368
- function updateComputed(c3) {
369
- const prevSub = setCurrentSub(c3);
370
- startTracking(c3);
371
- try {
372
- const oldValue = c3.value;
373
- return oldValue !== (c3.value = c3.getter(oldValue));
374
- } finally {
375
- setCurrentSub(prevSub);
376
- endTracking(c3);
377
- }
378
- }
379
- function updateSignal(s, value2) {
380
- s.flags = 1;
381
- return s.previousValue !== (s.previousValue = value2);
382
- }
383
- function notify(e) {
384
- const flags = e.flags;
385
- if (!(flags & 64)) {
386
- e.flags = flags | 64;
387
- const subs = e.subs;
388
- if (subs !== void 0) {
389
- notify(subs.sub);
390
- } else {
391
- queuedEffects[queuedEffectsLength++] = e;
392
- }
393
- }
394
- }
395
- function run(e, flags) {
396
- if (flags & 16 || flags & 32 && checkDirty(e.deps, e)) {
397
- const prev = setCurrentSub(e);
398
- startTracking(e);
399
- try {
400
- e.fn();
401
- } finally {
402
- setCurrentSub(prev);
403
- endTracking(e);
404
- }
405
- return;
406
- } else if (flags & 32) {
407
- e.flags = flags & ~32;
408
- }
409
- let link2 = e.deps;
410
- while (link2 !== void 0) {
411
- const dep = link2.dep;
412
- const depFlags = dep.flags;
413
- if (depFlags & 64) {
414
- run(dep, dep.flags = depFlags & ~64);
415
- }
416
- link2 = link2.nextDep;
417
- }
418
- }
419
- function flush() {
420
- while (notifyIndex < queuedEffectsLength) {
421
- const effect2 = queuedEffects[notifyIndex];
422
- queuedEffects[notifyIndex++] = void 0;
423
- run(effect2, effect2.flags &= ~64);
424
- }
425
- notifyIndex = 0;
426
- queuedEffectsLength = 0;
427
- }
428
- function computedOper() {
429
- const flags = this.flags;
430
- if (flags & 16 || flags & 32 && checkDirty(this.deps, this)) {
431
- if (updateComputed(this)) {
432
- const subs = this.subs;
433
- if (subs !== void 0) {
434
- shallowPropagate(subs);
435
- }
436
- }
437
- } else if (flags & 32) {
438
- this.flags = flags & ~32;
439
- }
440
- if (activeSub !== void 0) {
441
- link(this, activeSub);
442
- } else if (activeScope !== void 0) {
443
- link(this, activeScope);
444
- }
445
- return this.value;
446
- }
447
- function signalOper(...value2) {
448
- if (value2.length) {
449
- if (this.value !== (this.value = value2[0])) {
450
- this.flags = 17;
451
- const subs = this.subs;
452
- if (subs !== void 0) {
453
- propagate(subs);
454
- if (!batchDepth) {
455
- flush();
456
- }
457
- }
458
- }
459
- } else {
460
- const value3 = this.value;
461
- if (this.flags & 16) {
462
- if (updateSignal(this, value3)) {
463
- const subs = this.subs;
464
- if (subs !== void 0) {
465
- shallowPropagate(subs);
466
- }
467
- }
468
- }
469
- if (activeSub !== void 0) {
470
- link(this, activeSub);
471
- }
472
- return value3;
473
- }
474
- }
475
- function effectOper() {
476
- let dep = this.deps;
477
- while (dep !== void 0) {
478
- dep = unlink(dep, this);
479
- }
480
- const sub = this.subs;
481
- if (sub !== void 0) {
482
- unlink(sub);
483
- }
484
- this.flags = 0;
485
- }
486
-
487
- // src/caddy/index.ts
46
+ var import_node_child_process3 = require("child_process");
47
+ var import_node_fs4 = require("fs");
48
+ var import_promises2 = require("fs/promises");
49
+ var import_node_os5 = require("os");
50
+ var import_node_path5 = require("path");
51
+ var import_node_process8 = __toESM(require("process"), 1);
488
52
  var import_got_cjs = require("got-cjs");
489
53
  var import_http_proxy_agent = require("http-proxy-agent");
490
54
  var import_https_proxy_agent = require("https-proxy-agent");
491
- var lockfile = __toESM(require("proper-lockfile"), 1);
492
-
493
- // src/host/index.ts
494
- var import_node_child_process2 = require("child_process");
495
- var import_node_fs = require("fs");
496
- var import_node_process2 = __toESM(require("process"), 1);
497
- var import_node_util = require("util");
498
- var import_hostile = __toESM(require("hostile"), 1);
499
55
 
500
56
  // src/utils.ts
501
- var import_node_child_process = require("child_process");
502
- var import_promises = require("fs/promises");
503
57
  var import_node_os = require("os");
504
- var import_node_path = __toESM(require("path"), 1);
505
- var import_node_process = __toESM(require("process"), 1);
506
58
  var import_consola = require("consola");
507
59
  var import_picocolors = __toESM(require("picocolors"), 1);
508
60
  var import_qrcode_terminal = __toESM(require("qrcode-terminal"), 1);
509
61
  var consola = (0, import_consola.createConsola)({
510
62
  level: 3
511
63
  }).withTag("reverse-proxy");
512
- async function chmodRecursive(_path, mode) {
513
- await (0, import_promises.chmod)(_path, mode);
514
- if ((await (0, import_promises.stat)(_path)).isDirectory()) {
515
- const children = await (0, import_promises.readdir)(_path);
516
- for (const child of children)
517
- await chmodRecursive(import_node_path.default.join(_path, child), mode);
518
- }
519
- }
520
64
  function once(fn) {
521
65
  let called = false;
522
66
  return (...args2) => {
@@ -526,18 +70,6 @@ function once(fn) {
526
70
  return fn(...args2);
527
71
  };
528
72
  }
529
- function isAdmin() {
530
- if (import_node_process.default.platform === "win32") {
531
- try {
532
- (0, import_node_child_process.execSync)("net session", { stdio: "ignore" });
533
- return true;
534
- } catch {
535
- return false;
536
- }
537
- } else {
538
- return !!(import_node_process.default.getuid && import_node_process.default.getuid() === 0);
539
- }
540
- }
541
73
  function getIpv4List() {
542
74
  const interfaces = (0, import_node_os.networkInterfaces)();
543
75
  return Object.values(interfaces).flatMap((nInterface) => nInterface ?? []).filter(
@@ -552,44 +84,6 @@ async function generateQrcode(input) {
552
84
  });
553
85
  }
554
86
 
555
- // src/host/index.ts
556
- var _setHost = (0, import_node_util.promisify)(import_hostile.default.set);
557
- var _removeHost = (0, import_node_util.promisify)(import_hostile.default.remove);
558
- function getPathOfSystemHostsPath() {
559
- return import_node_process2.default.platform === "win32" ? `${import_node_process2.default.env.windir || "C:\\WINDOWS"}\\system32\\drivers\\etc\\hosts` : "/etc/hosts";
560
- }
561
- async function syncHost() {
562
- return new Promise((resolve2, _reject) => {
563
- (0, import_node_child_process2.exec)(
564
- import_node_process2.default.platform === "win32" ? "ipconfig /flushdns" : "sudo -E killall -HUP mDNSResponder",
565
- (error, _stdout, _stderr) => {
566
- if (error) {
567
- consola.error(`exec error: ${error}`);
568
- return resolve2(false);
569
- }
570
- return resolve2(true);
571
- }
572
- );
573
- });
574
- }
575
- async function addHost(ip2, host) {
576
- if (import_node_process2.default.platform !== "win32")
577
- (0, import_node_fs.chmodSync)(getPathOfSystemHostsPath(), 511);
578
- await _setHost("127.0.0.1", "localhost");
579
- await _setHost(ip2, host);
580
- if (ip2 === "localhost")
581
- await _setHost("127.0.0.1", host);
582
- return await syncHost();
583
- }
584
- async function removeHost(ip2, host) {
585
- if (import_node_process2.default.platform !== "win32")
586
- (0, import_node_fs.chmodSync)(getPathOfSystemHostsPath(), 511);
587
- await _removeHost(ip2, host);
588
- if (ip2 === "localhost")
589
- await _removeHost("127.0.0.1", host);
590
- return await syncHost();
591
- }
592
-
593
87
  // node_modules/.pnpm/@ark+util@0.46.0/node_modules/@ark/util/out/arrays.js
594
88
  var liftArray = (data) => Array.isArray(data) ? data : [data];
595
89
  var spliterate = (arr, predicate) => {
@@ -1217,29 +711,29 @@ var timeWithUnnecessarySeconds = /:\d\d:00$/;
1217
711
  var pad = (value2, length) => String(value2).padStart(length, "0");
1218
712
 
1219
713
  // node_modules/.pnpm/@ark+util@0.46.0/node_modules/@ark/util/out/path.js
1220
- var appendStringifiedKey = (path2, prop, ...[opts]) => {
714
+ var appendStringifiedKey = (path, prop, ...[opts]) => {
1221
715
  const stringifySymbol = (opts == null ? void 0 : opts.stringifySymbol) ?? printable;
1222
- let propAccessChain = path2;
716
+ let propAccessChain = path;
1223
717
  switch (typeof prop) {
1224
718
  case "string":
1225
- propAccessChain = isDotAccessible(prop) ? path2 === "" ? prop : `${path2}.${prop}` : `${path2}[${JSON.stringify(prop)}]`;
719
+ propAccessChain = isDotAccessible(prop) ? path === "" ? prop : `${path}.${prop}` : `${path}[${JSON.stringify(prop)}]`;
1226
720
  break;
1227
721
  case "number":
1228
- propAccessChain = `${path2}[${prop}]`;
722
+ propAccessChain = `${path}[${prop}]`;
1229
723
  break;
1230
724
  case "symbol":
1231
- propAccessChain = `${path2}[${stringifySymbol(prop)}]`;
725
+ propAccessChain = `${path}[${stringifySymbol(prop)}]`;
1232
726
  break;
1233
727
  default:
1234
728
  if (opts == null ? void 0 : opts.stringifyNonKey)
1235
- propAccessChain = `${path2}[${opts.stringifyNonKey(prop)}]`;
729
+ propAccessChain = `${path}[${opts.stringifyNonKey(prop)}]`;
1236
730
  else {
1237
731
  throwParseError(`${printable(prop)} must be a PropertyKey or stringifyNonKey must be passed to options`);
1238
732
  }
1239
733
  }
1240
734
  return propAccessChain;
1241
735
  };
1242
- var stringifyPath = (path2, ...opts) => path2.reduce((s, k) => appendStringifiedKey(s, k, ...opts), "");
736
+ var stringifyPath = (path, ...opts) => path.reduce((s, k) => appendStringifiedKey(s, k, ...opts), "");
1243
737
  var ReadonlyPath = class extends ReadonlyArray {
1244
738
  // alternate strategy for caching since the base object is frozen
1245
739
  cache = {};
@@ -1266,8 +760,8 @@ var ReadonlyPath = class extends ReadonlyArray {
1266
760
  return this.cache.stringifyAncestors;
1267
761
  let propString = "";
1268
762
  const result = [propString];
1269
- for (const path2 of this) {
1270
- propString = appendStringifiedKey(propString, path2);
763
+ for (const path of this) {
764
+ propString = appendStringifiedKey(propString, path);
1271
765
  result.push(propString);
1272
766
  }
1273
767
  return this.cache.stringifyAncestors = result;
@@ -1860,15 +1354,15 @@ var ArkErrors = class _ArkErrors extends ReadonlyArray {
1860
1354
  /**
1861
1355
  * @internal
1862
1356
  */
1863
- affectsPath(path2) {
1357
+ affectsPath(path) {
1864
1358
  if (this.length === 0)
1865
1359
  return false;
1866
1360
  return (
1867
1361
  // this would occur if there is an existing error at a prefix of path
1868
1362
  // e.g. the path is ["foo", "bar"] and there is an error at ["foo"]
1869
- path2.stringifyAncestors().some((s) => s in this.byPath) || // this would occur if there is an existing error at a suffix of path
1363
+ path.stringifyAncestors().some((s) => s in this.byPath) || // this would occur if there is an existing error at a suffix of path
1870
1364
  // e.g. the path is ["foo"] and there is an error at ["foo", "bar"]
1871
- path2.stringify() in this.byAncestorPath
1365
+ path.stringify() in this.byAncestorPath
1872
1366
  );
1873
1367
  }
1874
1368
  /**
@@ -2075,22 +1569,22 @@ var Traversal = class {
2075
1569
  while (this.queuedMorphs.length) {
2076
1570
  const queuedMorphs = this.queuedMorphs;
2077
1571
  this.queuedMorphs = [];
2078
- for (const { path: path2, morphs } of queuedMorphs) {
2079
- if (this.errors.affectsPath(path2))
1572
+ for (const { path, morphs } of queuedMorphs) {
1573
+ if (this.errors.affectsPath(path))
2080
1574
  continue;
2081
- this.applyMorphsAtPath(path2, morphs);
1575
+ this.applyMorphsAtPath(path, morphs);
2082
1576
  }
2083
1577
  }
2084
1578
  }
2085
- applyMorphsAtPath(path2, morphs) {
2086
- const key = path2.at(-1);
1579
+ applyMorphsAtPath(path, morphs) {
1580
+ const key = path.at(-1);
2087
1581
  let parent;
2088
1582
  if (key !== void 0) {
2089
1583
  parent = this.root;
2090
- for (let pathIndex = 0; pathIndex < path2.length - 1; pathIndex++)
2091
- parent = parent[path2[pathIndex]];
1584
+ for (let pathIndex = 0; pathIndex < path.length - 1; pathIndex++)
1585
+ parent = parent[path[pathIndex]];
2092
1586
  }
2093
- this.path = [...path2];
1587
+ this.path = [...path];
2094
1588
  for (const morph of morphs) {
2095
1589
  const morphIsNode = isNode(morph);
2096
1590
  const result = morph(parent === void 0 ? this.root : parent[key], this);
@@ -2460,15 +1954,15 @@ var NodeSelector = {
2460
1954
  normalize: (selector) => typeof selector === "function" ? { boundary: "references", method: "filter", where: selector } : typeof selector === "string" ? isKeyOf(selector, NodeSelector.applyBoundary) ? { method: "filter", boundary: selector } : { boundary: "references", method: "filter", kind: selector } : { boundary: "references", method: "filter", ...selector }
2461
1955
  };
2462
1956
  var writeSelectAssertionMessage = (from, selector) => `${from} had no references matching ${printable(selector)}.`;
2463
- var typePathToPropString = (path2) => stringifyPath(path2, {
1957
+ var typePathToPropString = (path) => stringifyPath(path, {
2464
1958
  stringifyNonKey: (node2) => node2.expression
2465
1959
  });
2466
1960
  var referenceMatcher = /"(\$ark\.[^"]+)"/g;
2467
1961
  var compileMeta = (metaJson) => JSON.stringify(metaJson).replaceAll(referenceMatcher, "$1");
2468
- var flatRef = (path2, node2) => ({
2469
- path: path2,
1962
+ var flatRef = (path, node2) => ({
1963
+ path,
2470
1964
  node: node2,
2471
- propString: typePathToPropString(path2)
1965
+ propString: typePathToPropString(path)
2472
1966
  });
2473
1967
  var flatRefsAreEqual = (l, r) => l.propString === r.propString && l.node.equals(r.node);
2474
1968
  var appendUniqueFlatRefs = (existing, refs) => appendUnique(existing, refs, {
@@ -2504,12 +1998,12 @@ var Disjoint = class _Disjoint extends Array {
2504
1998
  }
2505
1999
  describeReasons() {
2506
2000
  if (this.length === 1) {
2507
- const { path: path2, l, r } = this[0];
2508
- const pathString = stringifyPath(path2);
2001
+ const { path, l, r } = this[0];
2002
+ const pathString = stringifyPath(path);
2509
2003
  return writeUnsatisfiableExpressionError(`Intersection${pathString && ` at ${pathString}`} of ${describeReasons(l, r)}`);
2510
2004
  }
2511
2005
  return `The following intersections result in unsatisfiable types:
2512
- \u2022 ${this.map(({ path: path2, l, r }) => `${path2}: ${describeReasons(l, r)}`).join("\n\u2022 ")}`;
2006
+ \u2022 ${this.map(({ path, l, r }) => `${path}: ${describeReasons(l, r)}`).join("\n\u2022 ")}`;
2513
2007
  }
2514
2008
  throw() {
2515
2009
  return throwParseError(this.describeReasons());
@@ -3869,10 +3363,10 @@ var BaseRoot = class extends BaseNode {
3869
3363
  });
3870
3364
  });
3871
3365
  }
3872
- get(...path2) {
3873
- if (path2[0] === void 0)
3366
+ get(...path) {
3367
+ if (path[0] === void 0)
3874
3368
  return this;
3875
- return this.$.schema(this.applyStructuralOperation("get", path2));
3369
+ return this.$.schema(this.applyStructuralOperation("get", path));
3876
3370
  }
3877
3371
  extract(r) {
3878
3372
  const rNode = this.$.parseDefinition(r);
@@ -4807,13 +4301,13 @@ var implementation17 = implementNode({
4807
4301
  description: (node2) => node2.distribute((branch) => branch.description, describeBranches),
4808
4302
  expected: (ctx) => {
4809
4303
  const byPath = groupBy(ctx.errors, "propString");
4810
- const pathDescriptions = Object.entries(byPath).map(([path2, errors]) => {
4304
+ const pathDescriptions = Object.entries(byPath).map(([path, errors]) => {
4811
4305
  const branchesAtPath = [];
4812
4306
  for (const errorAtPath of errors)
4813
4307
  appendUnique(branchesAtPath, errorAtPath.expected);
4814
4308
  const expected = describeBranches(branchesAtPath);
4815
4309
  const actual = errors.every((e) => e.actual === errors[0].actual) ? errors[0].actual : printable(errors[0].data);
4816
- return `${path2 && `${path2} `}must be ${expected}${actual && ` (was ${actual})`}`;
4310
+ return `${path && `${path} `}must be ${expected}${actual && ` (was ${actual})`}`;
4817
4311
  });
4818
4312
  return describeBranches(pathDescriptions);
4819
4313
  },
@@ -5177,10 +4671,10 @@ var orderCandidates = (candidates, originalBranches) => {
5177
4671
  });
5178
4672
  return viableCandidates;
5179
4673
  };
5180
- var discriminantCaseToNode = (caseDiscriminant, path2, $) => {
4674
+ var discriminantCaseToNode = (caseDiscriminant, path, $) => {
5181
4675
  let node2 = caseDiscriminant === "undefined" ? $.node("unit", { unit: void 0 }) : caseDiscriminant === "null" ? $.node("unit", { unit: null }) : caseDiscriminant === "boolean" ? $.units([true, false]) : caseDiscriminant;
5182
- for (let i = path2.length - 1; i >= 0; i--) {
5183
- const key = path2[i];
4676
+ for (let i = path.length - 1; i >= 0; i--) {
4677
+ const key = path[i];
5184
4678
  node2 = $.node("intersection", typeof key === "number" ? {
5185
4679
  proto: "Array",
5186
4680
  // create unknown for preceding elements (could be optimized with safe imports)
@@ -5192,7 +4686,7 @@ var discriminantCaseToNode = (caseDiscriminant, path2, $) => {
5192
4686
  }
5193
4687
  return node2;
5194
4688
  };
5195
- var optionallyChainPropString = (path2) => path2.reduce((acc, k) => acc + compileLiteralPropAccess(k, true), "data");
4689
+ var optionallyChainPropString = (path) => path.reduce((acc, k) => acc + compileLiteralPropAccess(k, true), "data");
5196
4690
  var serializedTypeOfDescriptions = registeredReference(jsTypeOfDescriptions);
5197
4691
  var serializedPrintable = registeredReference(printable);
5198
4692
  var Union = {
@@ -6150,7 +5644,7 @@ var StructureNode = class extends BaseConstraint {
6150
5644
  return throwParseError(writeInvalidKeysMessage(this.expression, invalidKeys));
6151
5645
  }
6152
5646
  }
6153
- get(indexer, ...path2) {
5647
+ get(indexer, ...path) {
6154
5648
  var _a4;
6155
5649
  let value2;
6156
5650
  let required = false;
@@ -6187,7 +5681,7 @@ var StructureNode = class extends BaseConstraint {
6187
5681
  }
6188
5682
  return throwParseError(writeInvalidKeysMessage(this.expression, [key]));
6189
5683
  }
6190
- const result = value2.get(...path2);
5684
+ const result = value2.get(...path);
6191
5685
  return required ? result : result.or($ark.intrinsic.undefined);
6192
5686
  }
6193
5687
  pick(...keys) {
@@ -8913,7 +8407,7 @@ function isIterator(val) {
8913
8407
  function escapeRegex(str) {
8914
8408
  return str.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
8915
8409
  }
8916
- function promisify2(fn) {
8410
+ function promisify(fn) {
8917
8411
  return function(...args2) {
8918
8412
  return new Promise((resolve2, reject2) => {
8919
8413
  fn(...args2, (err, result) => {
@@ -10249,8 +9743,8 @@ function requireResolve(file) {
10249
9743
  const require2 = (0, import_module3.createRequire)(process.cwd() + "/");
10250
9744
  return require2.resolve(file);
10251
9745
  }
10252
- var statAsync = promisify2(import_fs.stat);
10253
- var readFileAsync = promisify2(import_fs.readFile);
9746
+ var statAsync = promisify(import_fs.stat);
9747
+ var readFileAsync = promisify(import_fs.readFile);
10254
9748
  function exists(filepath) {
10255
9749
  return __awaiter(this, void 0, void 0, function* () {
10256
9750
  try {
@@ -11492,10 +10986,10 @@ var Loader = class {
11492
10986
  yield filepath;
11493
10987
  }
11494
10988
  }
11495
- dirname(path2) {
10989
+ dirname(path) {
11496
10990
  const fs2 = this.options.fs;
11497
10991
  assert(fs2.dirname, "`fs.dirname` is required for relative reference");
11498
- return fs2.dirname(path2);
10992
+ return fs2.dirname(path);
11499
10993
  }
11500
10994
  lookupError(file, roots) {
11501
10995
  const err = new Error("ENOENT");
@@ -13446,6 +12940,7 @@ var ProxyType = type({
13446
12940
  });
13447
12941
  var CaddyContext = type({
13448
12942
  caddy_root: "string",
12943
+ admin_socket: "string",
13449
12944
  proxies: ProxyType.array()
13450
12945
  });
13451
12946
  function validateTemplateContext(ctx) {
@@ -13457,6 +12952,8 @@ function validateTemplateContext(ctx) {
13457
12952
  var caddyTemplate = `{
13458
12953
  debug
13459
12954
  auto_https disable_redirects ignore_loaded_certs
12955
+ skip_install_trust
12956
+ admin unix/{{ admin_socket }}
13460
12957
  }
13461
12958
 
13462
12959
  :7601 {
@@ -13537,27 +13034,37 @@ async function genCaddyfile(ctx) {
13537
13034
  }
13538
13035
 
13539
13036
  // src/caddy/config.ts
13540
- var import_node_fs2 = require("fs");
13541
- var import_promises2 = require("fs/promises");
13037
+ var import_node_fs = require("fs");
13038
+ var import_node_process2 = __toESM(require("process"), 1);
13039
+ var lockfile = __toESM(require("proper-lockfile"), 1);
13542
13040
 
13543
13041
  // src/caddy/constants.ts
13544
13042
  var import_node_os2 = __toESM(require("os"), 1);
13545
- var import_node_path2 = require("path");
13546
- var import_node_process3 = __toESM(require("process"), 1);
13043
+ var import_node_path = require("path");
13044
+ var import_node_process = __toESM(require("process"), 1);
13547
13045
  var import_dotenv_flow = __toESM(require("dotenv-flow"), 1);
13548
13046
  import_dotenv_flow.default.config({
13549
13047
  silent: true
13550
13048
  });
13551
- function resolvePath(path2) {
13552
- if (path2.startsWith("~"))
13553
- return (0, import_node_path2.join)(import_node_os2.default.homedir() || "", path2.slice(1));
13554
- return path2;
13555
- }
13556
- var TEMP_DIR = resolvePath(import_node_process3.default.env.UHRP_CADDY_PATH || import_node_process3.default.env.TEMP || import_node_process3.default.env.TMPDIR || "/tmp");
13557
- var caddyPath = (0, import_node_path2.join)(TEMP_DIR, `caddy${import_node_process3.default.platform === "win32" ? ".exe" : ""}`);
13558
- var caddyFilePath = (0, import_node_path2.join)(TEMP_DIR, "CADDYFILE");
13559
- var caddyConfigPath = (0, import_node_path2.join)(TEMP_DIR, ".CADDYFILE.config.json");
13560
- var caddyLockFilePath = (0, import_node_path2.join)(TEMP_DIR, "caddylock");
13049
+ function resolvePath(path) {
13050
+ if (path.startsWith("~"))
13051
+ return (0, import_node_path.join)(import_node_os2.default.homedir() || "", path.slice(1));
13052
+ return path;
13053
+ }
13054
+ function defaultTempDir() {
13055
+ const fromEnv = import_node_process.default.env.TEMP || import_node_process.default.env.TMPDIR;
13056
+ if (fromEnv)
13057
+ return resolvePath(fromEnv);
13058
+ if (import_node_process.default.platform === "linux")
13059
+ return (0, import_node_path.join)(import_node_process.default.env.XDG_CACHE_HOME || (0, import_node_path.join)(import_node_os2.default.homedir(), ".cache"), "uhrp");
13060
+ return "/tmp";
13061
+ }
13062
+ var TEMP_DIR = resolvePath(import_node_process.default.env.UHRP_CADDY_PATH || defaultTempDir());
13063
+ var caddyPath = (0, import_node_path.join)(TEMP_DIR, `caddy${import_node_process.default.platform === "win32" ? ".exe" : ""}`);
13064
+ var caddyFilePath = (0, import_node_path.join)(TEMP_DIR, "CADDYFILE");
13065
+ var caddyConfigPath = (0, import_node_path.join)(TEMP_DIR, ".CADDYFILE.config.json");
13066
+ var caddyLockFilePath = (0, import_node_path.join)(TEMP_DIR, "caddylock");
13067
+ var caddyAdminSocketPath = (0, import_node_path.join)(TEMP_DIR, "caddy-admin.sock");
13561
13068
  var supportList = [
13562
13069
  {
13563
13070
  platform: "dragonfly",
@@ -13670,69 +13177,788 @@ var supportList = [
13670
13177
  ];
13671
13178
 
13672
13179
  // src/caddy/config.ts
13673
- function useCaddyConfig() {
13674
- const configContentRef = signal("{}");
13675
- const configJsonRef = computed(() => {
13180
+ function isAlive(pid) {
13181
+ if (pid === void 0)
13182
+ return true;
13183
+ try {
13184
+ import_node_process2.default.kill(pid, 0);
13185
+ return true;
13186
+ } catch {
13187
+ return false;
13188
+ }
13189
+ }
13190
+ function readConfig(path = caddyConfigPath) {
13191
+ if (!(0, import_node_fs.existsSync)(path))
13192
+ return {};
13193
+ let parsed2;
13194
+ try {
13195
+ parsed2 = JSON.parse((0, import_node_fs.readFileSync)(path, "utf-8"));
13196
+ } catch {
13197
+ return {};
13198
+ }
13199
+ const alive = {};
13200
+ for (const [key, entry] of Object.entries(parsed2)) {
13201
+ if (isAlive(entry == null ? void 0 : entry.ownerPid))
13202
+ alive[key] = entry;
13203
+ }
13204
+ return alive;
13205
+ }
13206
+ function writeConfig(proxies, path = caddyConfigPath) {
13207
+ const content = JSON.stringify(proxies, null, 2);
13208
+ const temp = `${path}.${import_node_process2.default.pid}.tmp`;
13209
+ (0, import_node_fs.writeFileSync)(temp, content);
13210
+ (0, import_node_fs.renameSync)(temp, path);
13211
+ }
13212
+ function useCaddyConfig(options = {}) {
13213
+ const lock3 = options.lock ?? createFileLock();
13214
+ const configPath = options.configPath ?? caddyConfigPath;
13215
+ async function mutate(apply) {
13216
+ var _a4;
13217
+ const release = await lock3.acquire();
13676
13218
  try {
13677
- return JSON.parse(configContentRef());
13678
- } catch {
13219
+ const proxies = readConfig(configPath);
13220
+ apply(proxies);
13221
+ writeConfig(proxies, configPath);
13222
+ await ((_a4 = options.renderCaddyfile) == null ? void 0 : _a4.call(options, proxies));
13223
+ return proxies;
13224
+ } finally {
13225
+ release();
13226
+ }
13227
+ }
13228
+ return {
13229
+ configJsonRef: () => (0, import_node_fs.existsSync)(configPath) ? readConfig(configPath) : void 0,
13230
+ async writeCaddyConfig(_proxies, key) {
13231
+ await mutate((proxies) => {
13232
+ for (const p of _proxies)
13233
+ proxies[routeKey(p, key)] = { ...p, base: normalizeBase(p.base), ownerPid: import_node_process2.default.pid };
13234
+ });
13235
+ },
13236
+ async removeProxy(key) {
13237
+ await mutate((current) => {
13238
+ for (const route of Object.keys(current)) {
13239
+ if (route.endsWith(`#${key}`))
13240
+ delete current[route];
13241
+ }
13242
+ });
13243
+ },
13244
+ readProxies: () => readConfig(configPath),
13245
+ async cleanUp() {
13246
+ removeConfigFile(configPath);
13247
+ }
13248
+ };
13249
+ }
13250
+ function removeConfigFile(path = caddyConfigPath) {
13251
+ try {
13252
+ if ((0, import_node_fs.existsSync)(path))
13253
+ (0, import_node_fs.unlinkSync)(path);
13254
+ } catch {
13255
+ }
13256
+ }
13257
+ function normalizeBase(base) {
13258
+ let out = base || "/";
13259
+ if (!out.startsWith("/"))
13260
+ out = `/${out}`;
13261
+ if (out !== "/" && !out.endsWith("/"))
13262
+ out = `${out}/`;
13263
+ return out;
13264
+ }
13265
+ function routeKey(proxy, ownerKey) {
13266
+ return `${proxy.target}${proxy.portSuffix}${normalizeBase(proxy.base)}#${ownerKey}`;
13267
+ }
13268
+ function createFileLock() {
13269
+ return {
13270
+ async acquire() {
13271
+ if (!(0, import_node_fs.existsSync)(caddyConfigPath))
13272
+ (0, import_node_fs.writeFileSync)(caddyConfigPath, "{}");
13273
+ const release = await lockfile.lock(caddyConfigPath, {
13274
+ realpath: false,
13275
+ stale: 1e4,
13276
+ retries: { retries: 20, minTimeout: 10, maxTimeout: 100 }
13277
+ });
13278
+ return () => {
13279
+ void release().catch(() => {
13280
+ });
13281
+ };
13282
+ }
13283
+ };
13284
+ }
13285
+
13286
+ // src/caddy/log.ts
13287
+ function isCaddyReloadCancellation(line) {
13288
+ try {
13289
+ const entry = JSON.parse(line);
13290
+ return entry.logger === "tls" && typeof entry.error === "string" && entry.error.endsWith("context canceled");
13291
+ } catch {
13292
+ return false;
13293
+ }
13294
+ }
13295
+
13296
+ // src/caddy/privileged.ts
13297
+ var import_node_buffer2 = require("buffer");
13298
+ var import_node_events = require("events");
13299
+ var import_node_path4 = require("path");
13300
+ var import_node_process7 = __toESM(require("process"), 1);
13301
+ var import_node_url = require("url");
13302
+
13303
+ // src/privileged/entry.ts
13304
+ var import_node_fs2 = require("fs");
13305
+ var import_node_path2 = require("path");
13306
+ var import_node_process3 = __toESM(require("process"), 1);
13307
+ function resolveHelperEntry(options) {
13308
+ const { moduleDir, nodeBin = import_node_process3.default.execPath, exists: exists2 = import_node_fs2.existsSync } = options;
13309
+ for (const name of ["privileged-helper.js", "privileged-helper.cjs", "privileged-helper.mjs"]) {
13310
+ const candidate = findUp(moduleDir, name, exists2);
13311
+ if (candidate)
13312
+ return { entry: nodeBin, args: [candidate] };
13313
+ }
13314
+ const source = findUp(moduleDir, "privileged-helper.ts", exists2);
13315
+ const tsxCli = findUp(moduleDir, "node_modules/tsx/dist/cli.mjs", exists2);
13316
+ if (source && tsxCli)
13317
+ return { entry: nodeBin, args: [tsxCli, source] };
13318
+ throw new Error(`privileged helper entry not found in ${moduleDir}. Build the package first.`);
13319
+ }
13320
+ function findUp(from, relative, exists2) {
13321
+ let current = from;
13322
+ while (true) {
13323
+ const candidate = (0, import_node_path2.join)(current, relative);
13324
+ if (exists2(candidate))
13325
+ return candidate;
13326
+ const parent = (0, import_node_path2.dirname)(current);
13327
+ if (parent === current)
13679
13328
  return void 0;
13329
+ current = parent;
13330
+ }
13331
+ }
13332
+
13333
+ // src/privileged/session.ts
13334
+ var import_node_buffer = require("buffer");
13335
+ var import_node_fs3 = require("fs");
13336
+ var import_promises = require("fs/promises");
13337
+ var import_node_os4 = require("os");
13338
+ var import_node_path3 = require("path");
13339
+ var lockfile2 = __toESM(require("proper-lockfile"), 1);
13340
+
13341
+ // src/privileged/launch.ts
13342
+ var import_node_child_process2 = require("child_process");
13343
+ var import_node_crypto = require("crypto");
13344
+ var import_node_os3 = require("os");
13345
+ var import_node_process6 = __toESM(require("process"), 1);
13346
+
13347
+ // src/privileged/client.ts
13348
+ var import_node_net = require("net");
13349
+ var import_node_process4 = __toESM(require("process"), 1);
13350
+
13351
+ // src/privileged/protocol.ts
13352
+ function serializeMessage(message) {
13353
+ return `${JSON.stringify(message)}
13354
+ `;
13355
+ }
13356
+ function splitLines(buffer, chunk) {
13357
+ const parts = (buffer + chunk).split("\n");
13358
+ const rest = parts.pop() ?? "";
13359
+ return { lines: parts.filter((line) => line.trim() !== ""), rest };
13360
+ }
13361
+ function isRecord(value2) {
13362
+ return typeof value2 === "object" && value2 !== null;
13363
+ }
13364
+ function decodeMessage(line) {
13365
+ let parsed2;
13366
+ try {
13367
+ parsed2 = JSON.parse(line);
13368
+ } catch (error) {
13369
+ return { ok: false, error: `invalid JSON: ${error.message}` };
13370
+ }
13371
+ if (!isRecord(parsed2))
13372
+ return { ok: false, error: "message must be an object" };
13373
+ if (parsed2.type === "event") {
13374
+ if (typeof parsed2.kind !== "string")
13375
+ return { ok: false, error: "event.kind must be a string" };
13376
+ return { ok: true, message: parsed2 };
13377
+ }
13378
+ if (typeof parsed2.id !== "number")
13379
+ return { ok: false, error: "response.id must be a number" };
13380
+ if (parsed2.ok === true)
13381
+ return { ok: true, message: { id: parsed2.id, ok: true, result: parsed2.result } };
13382
+ if (parsed2.ok === false) {
13383
+ const error = isRecord(parsed2.error) ? parsed2.error : {};
13384
+ return {
13385
+ ok: true,
13386
+ message: {
13387
+ id: parsed2.id,
13388
+ ok: false,
13389
+ error: {
13390
+ message: typeof error.message === "string" ? error.message : "helper request failed",
13391
+ code: typeof error.code === "string" ? error.code : void 0
13392
+ }
13393
+ }
13394
+ };
13395
+ }
13396
+ return { ok: false, error: "response.ok must be a boolean" };
13397
+ }
13398
+
13399
+ // src/privileged/client.ts
13400
+ var FORWARDED_ENV_KEYS = [
13401
+ "HOME",
13402
+ "USER",
13403
+ "LOGNAME",
13404
+ "TMPDIR",
13405
+ "HTTP_PROXY",
13406
+ "HTTPS_PROXY",
13407
+ "http_proxy",
13408
+ "https_proxy",
13409
+ "NO_PROXY",
13410
+ "no_proxy"
13411
+ ];
13412
+ function collectForwardedEnv(source = import_node_process4.default.env) {
13413
+ const result = {};
13414
+ for (const key of FORWARDED_ENV_KEYS) {
13415
+ const value2 = source[key];
13416
+ if (typeof value2 === "string" && value2 !== "")
13417
+ result[key] = value2;
13418
+ }
13419
+ return result;
13420
+ }
13421
+ var HelperConnectionError = class extends Error {
13422
+ constructor(message) {
13423
+ super(message);
13424
+ this.name = "HelperConnectionError";
13425
+ }
13426
+ };
13427
+ function openSocket(socketPath) {
13428
+ return new Promise((resolve2, reject2) => {
13429
+ const socket = (0, import_node_net.connect)(socketPath);
13430
+ function onConnect() {
13431
+ socket.removeListener("error", onError);
13432
+ resolve2(socket);
13680
13433
  }
13681
- });
13682
- function setConfigContent() {
13683
- if (!(0, import_node_fs2.existsSync)(caddyConfigPath)) {
13684
- (0, import_node_fs2.writeFileSync)(caddyConfigPath, "{}");
13434
+ function onError(error) {
13435
+ socket.removeListener("connect", onConnect);
13436
+ reject2(error);
13685
13437
  }
13438
+ socket.once("error", onError);
13439
+ socket.once("connect", onConnect);
13440
+ });
13441
+ }
13442
+ async function connectClient(options) {
13443
+ const {
13444
+ socketPath,
13445
+ token,
13446
+ timeoutMs = 12e4,
13447
+ retryIntervalMs = 100,
13448
+ callTimeoutMs = 3e4
13449
+ } = options;
13450
+ const deadline = Date.now() + timeoutMs;
13451
+ let lastError;
13452
+ while (Date.now() < deadline) {
13686
13453
  try {
13687
- configContentRef((0, import_node_fs2.readFileSync)(caddyConfigPath, "utf-8"));
13688
- } catch {
13689
- configContentRef("");
13454
+ return await handshake(socketPath, token, callTimeoutMs);
13455
+ } catch (error) {
13456
+ lastError = error;
13457
+ const code = lastError.code;
13458
+ if (code === "EACCES" || lastError instanceof HelperConnectionError)
13459
+ throw lastError;
13460
+ await new Promise((resolve2) => setTimeout(resolve2, retryIntervalMs));
13690
13461
  }
13691
13462
  }
13692
- if (!(0, import_node_fs2.existsSync)(caddyConfigPath)) {
13693
- (0, import_node_fs2.writeFileSync)(caddyConfigPath, "{}");
13694
- }
13695
- const watchCaddyConfig = (0, import_node_fs2.watch)(caddyConfigPath, () => {
13696
- setConfigContent();
13463
+ throw new HelperConnectionError(
13464
+ `privileged helper is not reachable at ${socketPath}: ${(lastError == null ? void 0 : lastError.message) ?? "timed out"}`
13465
+ );
13466
+ }
13467
+ function handshake(socketPath, token, callTimeoutMs) {
13468
+ return new Promise((resolve2, reject2) => {
13469
+ void openSocket(socketPath).then((socket) => {
13470
+ let buffer = "";
13471
+ let settled = false;
13472
+ const fail = (error) => {
13473
+ if (settled)
13474
+ return;
13475
+ settled = true;
13476
+ socket.destroy();
13477
+ reject2(error);
13478
+ };
13479
+ const onData = (chunk) => {
13480
+ if (settled)
13481
+ return;
13482
+ const split2 = splitLines(buffer, chunk.toString("utf8"));
13483
+ buffer = split2.rest;
13484
+ const line = split2.lines[0];
13485
+ if (line === void 0)
13486
+ return;
13487
+ let hello;
13488
+ try {
13489
+ hello = JSON.parse(line);
13490
+ } catch (error) {
13491
+ return fail(new HelperConnectionError(`invalid handshake reply: ${error.message}`));
13492
+ }
13493
+ if (hello.type !== "handshake")
13494
+ return fail(new HelperConnectionError("helper did not answer the handshake"));
13495
+ if (!hello.ok)
13496
+ return fail(new HelperConnectionError(hello.reason ?? "helper rejected the handshake"));
13497
+ settled = true;
13498
+ socket.removeListener("data", onData);
13499
+ socket.removeListener("error", onError);
13500
+ const remaining = split2.lines.slice(1);
13501
+ resolve2(createClient(socket, [split2.rest, ...remaining].filter(Boolean).join("\n"), callTimeoutMs));
13502
+ };
13503
+ function onError(error) {
13504
+ fail(error);
13505
+ }
13506
+ socket.on("data", onData);
13507
+ socket.on("error", onError);
13508
+ const greeting = { type: "handshake", token };
13509
+ socket.write(serializeMessage(greeting));
13510
+ }, reject2);
13697
13511
  });
13698
- function writeCaddyConfig(_proxies) {
13699
- const proxies = configJsonRef() || {};
13700
- _proxies.forEach((p) => {
13701
- let base = p.base || "/";
13702
- if (!base.startsWith("/"))
13703
- base = `/${base}`;
13704
- if (base !== "/" && !base.endsWith("/"))
13705
- base = `${base}/`;
13706
- const index = `${p.target}${p.portSuffix}${base}`;
13707
- proxies[index] = { ...p, base };
13512
+ }
13513
+ function createClient(socket, initialBuffer, callTimeoutMs) {
13514
+ let buffer = initialBuffer;
13515
+ let connected = true;
13516
+ let nextId = 1;
13517
+ const pending = /* @__PURE__ */ new Map();
13518
+ const listeners = /* @__PURE__ */ new Set();
13519
+ socket.on("data", (chunk) => {
13520
+ const split2 = splitLines(buffer, chunk.toString("utf8"));
13521
+ buffer = split2.rest;
13522
+ for (const line of split2.lines) {
13523
+ const decoded = decodeMessage(line);
13524
+ if (!decoded.ok)
13525
+ continue;
13526
+ const message = decoded.message;
13527
+ if (!("id" in message)) {
13528
+ for (const listener of listeners)
13529
+ listener(message);
13530
+ continue;
13531
+ }
13532
+ const entry = pending.get(message.id);
13533
+ if (!entry)
13534
+ continue;
13535
+ pending.delete(message.id);
13536
+ clearTimeout(entry.timer);
13537
+ if (message.ok)
13538
+ entry.resolve(message.result);
13539
+ else
13540
+ entry.reject(new Error(message.error.message));
13541
+ }
13542
+ });
13543
+ const disconnect = () => {
13544
+ if (!connected)
13545
+ return;
13546
+ connected = false;
13547
+ for (const [id, entry] of pending) {
13548
+ clearTimeout(entry.timer);
13549
+ pending.delete(id);
13550
+ entry.reject(new HelperConnectionError("privileged helper connection closed"));
13551
+ }
13552
+ };
13553
+ socket.on("close", disconnect);
13554
+ socket.on("error", disconnect);
13555
+ function call(method, params) {
13556
+ if (!connected)
13557
+ return Promise.reject(new HelperConnectionError("privileged helper is not connected"));
13558
+ const id = nextId++;
13559
+ const request = { id, method, params };
13560
+ return new Promise((resolve2, reject2) => {
13561
+ const timer = setTimeout(() => {
13562
+ pending.delete(id);
13563
+ reject2(new HelperConnectionError(`privileged helper did not answer "${method}" in time`));
13564
+ }, callTimeoutMs);
13565
+ pending.set(id, { resolve: resolve2, reject: reject2, timer });
13566
+ socket.write(serializeMessage(request));
13708
13567
  });
13709
- const content = JSON.stringify(proxies, null, 2);
13710
- configContentRef(content);
13711
- return (0, import_node_fs2.writeFileSync)(caddyConfigPath, content);
13712
13568
  }
13713
- async function cleanUp() {
13714
- await (0, import_promises2.unlink)(caddyConfigPath).catch(() => {
13569
+ return {
13570
+ get connected() {
13571
+ return connected;
13572
+ },
13573
+ call,
13574
+ onEvent(listener) {
13575
+ listeners.add(listener);
13576
+ return () => {
13577
+ listeners.delete(listener);
13578
+ };
13579
+ },
13580
+ async close() {
13581
+ disconnect();
13582
+ socket.destroy();
13583
+ }
13584
+ };
13585
+ }
13586
+
13587
+ // src/privileged/windows-elevation.ts
13588
+ var import_node_child_process = require("child_process");
13589
+ var import_node_process5 = __toESM(require("process"), 1);
13590
+ function quotePowerShell(value2) {
13591
+ return `'${value2.replace(/'/g, "''")}'`;
13592
+ }
13593
+ function buildElevationCommand(options) {
13594
+ const argumentList = options.args.map(quotePowerShell).join(",");
13595
+ const parts = [
13596
+ "Start-Process",
13597
+ "-FilePath",
13598
+ quotePowerShell(options.file)
13599
+ ];
13600
+ if (argumentList)
13601
+ parts.push("-ArgumentList", argumentList);
13602
+ if (options.cwd)
13603
+ parts.push("-WorkingDirectory", quotePowerShell(options.cwd));
13604
+ parts.push("-Verb", "RunAs");
13605
+ parts.push("-WindowStyle", "Hidden");
13606
+ return parts.join(" ");
13607
+ }
13608
+ function spawnElevatedOnWindows(options) {
13609
+ return new Promise((resolve2, reject2) => {
13610
+ const script = buildElevationCommand(options);
13611
+ const child = (0, import_node_child_process.spawn)(
13612
+ "powershell.exe",
13613
+ ["-NoProfile", "-NonInteractive", "-Command", script],
13614
+ { stdio: "ignore", windowsHide: true }
13615
+ );
13616
+ child.once("error", reject2);
13617
+ child.once("exit", (code) => {
13618
+ if (code === 0)
13619
+ return resolve2(child);
13620
+ reject2(new Error(
13621
+ `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.`
13622
+ ));
13715
13623
  });
13716
- configContentRef("{}");
13717
- watchCaddyConfig.close();
13624
+ });
13625
+ }
13626
+
13627
+ // src/privileged/launch.ts
13628
+ function createHelperToken() {
13629
+ return (0, import_node_crypto.randomBytes)(24).toString("hex");
13630
+ }
13631
+ function describePasswordReason(target, https) {
13632
+ const port = https ? "443" : "80";
13633
+ return [
13634
+ `reverse proxy needs administrator permission for ${target}`,
13635
+ ` \xB7 bind port ${port}${https ? ` for https://${target}` : ""}`,
13636
+ ` \xB7 add ${target} to the hosts file`,
13637
+ "",
13638
+ "This is the only prompt; the rest of the dev server keeps running as you.",
13639
+ "Press Ctrl+C at the prompt to skip the proxy and keep the dev server."
13640
+ ];
13641
+ }
13642
+ async function authenticateSudo(sudoCommand = "sudo", options = {}) {
13643
+ if ((0, import_node_os3.platform)() === "win32")
13644
+ return { ok: true };
13645
+ if ((0, import_node_child_process2.spawnSync)(sudoCommand, ["-n", "true"], { stdio: "ignore" }).status === 0)
13646
+ return { ok: true };
13647
+ if (options.target && !options.quiet) {
13648
+ for (const line of describePasswordReason(options.target, options.https ?? false))
13649
+ import_node_process6.default.stderr.write(`${line}
13650
+ `);
13651
+ import_node_process6.default.stderr.write("\n");
13718
13652
  }
13719
- return {
13720
- configJsonRef,
13721
- writeCaddyConfig,
13722
- cleanUp
13653
+ let interrupted = false;
13654
+ const onSigint = () => {
13655
+ interrupted = true;
13723
13656
  };
13657
+ import_node_process6.default.on("SIGINT", onSigint);
13658
+ try {
13659
+ const { status, signal } = await runPrompt(sudoCommand);
13660
+ if (status === 0)
13661
+ return { ok: true };
13662
+ const cancelled = interrupted || signal === "SIGINT";
13663
+ return {
13664
+ ok: false,
13665
+ denied: true,
13666
+ message: cancelled ? "administrator permission was cancelled" : "administrator permission is required to edit the hosts file and bind ports 80/443"
13667
+ };
13668
+ } finally {
13669
+ import_node_process6.default.off("SIGINT", onSigint);
13670
+ }
13671
+ }
13672
+ function runPrompt(sudoCommand) {
13673
+ return new Promise((resolve2) => {
13674
+ const restore = takeBackTerminal();
13675
+ const child = (0, import_node_child_process2.spawn)(sudoCommand, ["-v"], { stdio: "inherit" });
13676
+ const finish = (result) => {
13677
+ restore();
13678
+ resolve2(result);
13679
+ };
13680
+ child.on("error", () => finish({ status: 1, signal: null }));
13681
+ child.on("exit", (status, signal) => finish({ status, signal }));
13682
+ });
13683
+ }
13684
+ function takeBackTerminal() {
13685
+ const stdin = import_node_process6.default.stdin;
13686
+ if (!stdin.isTTY || typeof stdin.setRawMode !== "function")
13687
+ return () => {
13688
+ };
13689
+ const wasRaw = stdin.isRaw === true;
13690
+ stdin.pause();
13691
+ try {
13692
+ stdin.setRawMode(false);
13693
+ } catch {
13694
+ stdin.resume();
13695
+ return () => {
13696
+ };
13697
+ }
13698
+ return () => {
13699
+ if (wasRaw) {
13700
+ try {
13701
+ stdin.setRawMode(true);
13702
+ } catch {
13703
+ }
13704
+ }
13705
+ stdin.resume();
13706
+ };
13707
+ }
13708
+ var PrivilegeDeniedError = class extends Error {
13709
+ constructor(message) {
13710
+ super(message);
13711
+ this.name = "PrivilegeDeniedError";
13712
+ }
13713
+ };
13714
+ async function startPrivilegedHelper(options) {
13715
+ var _a4, _b3;
13716
+ const {
13717
+ socketPath,
13718
+ token,
13719
+ helperEntry,
13720
+ helperArgs = [],
13721
+ sudoCommand = "sudo",
13722
+ skipAuth = false,
13723
+ direct = false,
13724
+ env: env2 = import_node_process6.default.env,
13725
+ log,
13726
+ connectTimeoutMs = 12e4
13727
+ } = options;
13728
+ if (!skipAuth && !direct) {
13729
+ const auth = await authenticateSudo(sudoCommand, options.reason);
13730
+ if (!auth.ok) {
13731
+ const message = auth.message ?? "administrator permission is required";
13732
+ throw auth.denied ? new PrivilegeDeniedError(message) : new Error(message);
13733
+ }
13734
+ }
13735
+ const forwarded = collectForwardedEnv(env2);
13736
+ const forwardedArgs = Object.entries(forwarded).map(([key, value2]) => `${key}=${value2}`);
13737
+ const childArgv = [
13738
+ ...helperArgs,
13739
+ "--socket",
13740
+ socketPath,
13741
+ "--token",
13742
+ token,
13743
+ ...typeof import_node_process6.default.getuid === "function" ? ["--owner-uid", String(import_node_process6.default.getuid())] : [],
13744
+ ...typeof import_node_process6.default.getgid === "function" ? ["--owner-gid", String(import_node_process6.default.getgid())] : [],
13745
+ ...options.caddyStoragePath ? ["--caddy-storage", options.caddyStoragePath] : [],
13746
+ "--caddy",
13747
+ options.caddyBin,
13748
+ "--caddy-config",
13749
+ options.caddyConfigPath,
13750
+ ...options.caddyAdminSocket ? ["--caddy-admin", options.caddyAdminSocket] : []
13751
+ ];
13752
+ let child;
13753
+ if (!direct && (0, import_node_os3.platform)() === "win32") {
13754
+ await spawnElevatedOnWindows({ file: helperEntry, args: childArgv, cwd: import_node_process6.default.cwd() });
13755
+ } else {
13756
+ const command = direct ? helperEntry : sudoCommand;
13757
+ const spawnArgs = direct ? childArgv : ["-n", "env", ...forwardedArgs, helperEntry, ...childArgv];
13758
+ child = (0, import_node_child_process2.spawn)(command, spawnArgs, {
13759
+ stdio: ["ignore", "pipe", "pipe"]
13760
+ });
13761
+ (_a4 = child.stdout) == null ? void 0 : _a4.on("data", (data) => log == null ? void 0 : log(data.toString().trimEnd()));
13762
+ (_b3 = child.stderr) == null ? void 0 : _b3.on("data", (data) => log == null ? void 0 : log(data.toString().trimEnd()));
13763
+ const exited = new Promise((resolve2) => child.once("exit", (code) => resolve2(code)));
13764
+ const earlyExit = await Promise.race([
13765
+ exited,
13766
+ new Promise((resolve2) => setTimeout(() => resolve2(void 0), 500))
13767
+ ]);
13768
+ if (earlyExit !== void 0 && earlyExit !== 0) {
13769
+ throw new Error(
13770
+ `privileged helper exited with code ${earlyExit}. Administrator permission was refused, or sudo is not available.`
13771
+ );
13772
+ }
13773
+ }
13774
+ try {
13775
+ const client = await connectClient({ socketPath, token, timeoutMs: connectTimeoutMs });
13776
+ return {
13777
+ client,
13778
+ async close() {
13779
+ await client.close().catch(() => {
13780
+ });
13781
+ child == null ? void 0 : child.unref();
13782
+ }
13783
+ };
13784
+ } catch (error) {
13785
+ try {
13786
+ child == null ? void 0 : child.kill();
13787
+ } catch {
13788
+ }
13789
+ throw error;
13790
+ }
13791
+ }
13792
+ async function connectExistingHelper(socketPath, token, timeoutMs = 1500) {
13793
+ try {
13794
+ return await connectClient({ socketPath, token, timeoutMs });
13795
+ } catch {
13796
+ return void 0;
13797
+ }
13724
13798
  }
13725
13799
 
13726
- // src/caddy/log.ts
13727
- function isCaddyReloadCancellation(line) {
13800
+ // src/privileged/session.ts
13801
+ function tokenPath(runtimeDir) {
13802
+ return (0, import_node_path3.join)(runtimeDir, "helper.token");
13803
+ }
13804
+ function sessionSocketPath(runtimeDir) {
13805
+ if ((0, import_node_os4.platform)() === "win32")
13806
+ return `\\\\.\\pipe\\uhrp-${import_node_buffer.Buffer.from(runtimeDir).toString("hex").slice(0, 40)}`;
13807
+ return (0, import_node_path3.join)(runtimeDir, "helper.sock");
13808
+ }
13809
+ async function openHelperSession(scope2) {
13810
+ const socketPath = sessionSocketPath(scope2.runtimeDir);
13811
+ const release = await acquireStartLock(scope2.runtimeDir);
13728
13812
  try {
13729
- const entry = JSON.parse(line);
13730
- return entry.logger === "tls" && typeof entry.error === "string" && entry.error.endsWith("context canceled");
13813
+ const reused = await tryReuse(socketPath, scope2);
13814
+ if (reused)
13815
+ return reused;
13816
+ return await startNew(socketPath, scope2);
13817
+ } finally {
13818
+ release();
13819
+ }
13820
+ }
13821
+ async function tryReuse(socketPath, scope2) {
13822
+ if (!(0, import_node_fs3.existsSync)(socketPath) && (0, import_node_os4.platform)() !== "win32")
13823
+ return void 0;
13824
+ const token = await readToken(scope2.runtimeDir);
13825
+ if (!token)
13826
+ return void 0;
13827
+ const reused = await connectExistingHelper(socketPath, token);
13828
+ if (!reused)
13829
+ return void 0;
13830
+ return {
13831
+ client: reused,
13832
+ reused: true,
13833
+ close: async () => {
13834
+ await reused.close();
13835
+ }
13836
+ };
13837
+ }
13838
+ async function startNew(socketPath, scope2) {
13839
+ const token = createHelperToken();
13840
+ const started = await startPrivilegedHelper({
13841
+ socketPath,
13842
+ token,
13843
+ helperEntry: scope2.helperEntry,
13844
+ helperArgs: scope2.helperArgs,
13845
+ sudoCommand: scope2.sudoCommand,
13846
+ skipAuth: scope2.skipAuth,
13847
+ direct: scope2.direct,
13848
+ env: scope2.env,
13849
+ caddyStoragePath: scope2.caddyStoragePath,
13850
+ caddyBin: scope2.caddyBin,
13851
+ caddyConfigPath: scope2.caddyConfigPath,
13852
+ caddyAdminSocket: scope2.caddyAdminSocket,
13853
+ reason: scope2.reason,
13854
+ log: scope2.log
13855
+ });
13856
+ await writeToken(scope2.runtimeDir, token);
13857
+ return {
13858
+ client: started.client,
13859
+ reused: false,
13860
+ close: async () => {
13861
+ await started.close();
13862
+ }
13863
+ };
13864
+ }
13865
+ async function acquireStartLock(runtimeDir) {
13866
+ const lockPath = (0, import_node_path3.join)(runtimeDir, "helper.start.lock");
13867
+ try {
13868
+ await (0, import_promises.writeFile)(lockPath, "", { flag: "a" });
13869
+ } catch {
13870
+ }
13871
+ const release = await lockfile2.lock(lockPath, {
13872
+ realpath: false,
13873
+ stale: 3e4,
13874
+ retries: { retries: 100, minTimeout: 50, maxTimeout: 200 }
13875
+ });
13876
+ return () => {
13877
+ void release().catch(() => {
13878
+ });
13879
+ };
13880
+ }
13881
+ async function readToken(runtimeDir) {
13882
+ try {
13883
+ const content = await (0, import_promises.readFile)(tokenPath(runtimeDir), "utf8");
13884
+ const token = content.trim();
13885
+ return token === "" ? void 0 : token;
13886
+ } catch {
13887
+ return void 0;
13888
+ }
13889
+ }
13890
+ async function writeToken(runtimeDir, token) {
13891
+ try {
13892
+ await (0, import_promises.writeFile)(tokenPath(runtimeDir), token, { mode: 384 });
13731
13893
  } catch {
13732
- return false;
13733
13894
  }
13734
13895
  }
13735
13896
 
13897
+ // src/caddy/privileged.ts
13898
+ var import_meta = {};
13899
+ function resolvePrivilegedEnv() {
13900
+ const moduleDir = typeof __dirname === "string" ? __dirname : (0, import_node_path4.dirname)((0, import_node_url.fileURLToPath)(import_meta.url));
13901
+ const resolved = resolveHelperEntry({ moduleDir });
13902
+ return { helperEntry: resolved.entry, helperArgs: resolved.args };
13903
+ }
13904
+ var HelperCaddyProcess = class extends import_node_events.EventEmitter {
13905
+ constructor(client) {
13906
+ super();
13907
+ this.client = client;
13908
+ this.stdout = new import_node_events.EventEmitter();
13909
+ this.stderr = new import_node_events.EventEmitter();
13910
+ this.finished = false;
13911
+ this.unsubscribe = client.onEvent((event) => this.handleEvent(event));
13912
+ }
13913
+ handleEvent(event) {
13914
+ if (event.type !== "event")
13915
+ return;
13916
+ if (event.kind === "caddy.stdout") {
13917
+ this.stdout.emit("data", import_node_buffer2.Buffer.from(event.data));
13918
+ return;
13919
+ }
13920
+ if (event.kind === "caddy.stderr") {
13921
+ this.stderr.emit("data", import_node_buffer2.Buffer.from(event.data));
13922
+ return;
13923
+ }
13924
+ if (event.kind === "caddy.exit") {
13925
+ this.finished = true;
13926
+ this.emit("exit", event.code, event.signal);
13927
+ }
13928
+ }
13929
+ /** Asks the helper to stop Caddy; the helper also stops it on disconnect. */
13930
+ kill() {
13931
+ this.unsubscribe();
13932
+ if (this.finished)
13933
+ return;
13934
+ this.finished = true;
13935
+ void this.client.call("caddy.stop").catch(() => {
13936
+ });
13937
+ }
13938
+ };
13939
+ function caddyStoragePath() {
13940
+ return import_node_process7.default.platform === "win32" ? (0, import_node_path4.join)(import_node_process7.default.env.AppData ?? "", "Caddy") : (0, import_node_path4.join)(import_node_process7.default.env.HOME ?? "", "Library/Application Support/Caddy");
13941
+ }
13942
+ function openPrivilegedSession(runtimeDir, options) {
13943
+ const env2 = resolvePrivilegedEnv();
13944
+ return openHelperSession({
13945
+ runtimeDir,
13946
+ helperEntry: env2.helperEntry,
13947
+ helperArgs: env2.helperArgs,
13948
+ direct: options.direct,
13949
+ // Caddy keeps its PKI under the user's home; the helper runs it as root, so
13950
+ // it must know which tree to hand back afterwards.
13951
+ caddyStoragePath: caddyStoragePath(),
13952
+ // The binary and Caddyfile are fixed here: the privileged helper must never
13953
+ // execute a path supplied over the socket.
13954
+ caddyBin: options.caddyBin,
13955
+ caddyConfigPath: options.caddyConfigPath,
13956
+ caddyAdminSocket: options.caddyAdminSocket,
13957
+ reason: options.reason,
13958
+ log: options.log
13959
+ });
13960
+ }
13961
+
13736
13962
  // src/caddy/tls-health.ts
13737
13963
  var import_node_tls = require("tls");
13738
13964
  function assessTlsCertificate(certificate, hostname, now = Date.now(), verifyHostname = import_node_tls.checkServerIdentity) {
@@ -13815,40 +14041,8 @@ function formatTlsHealthFailure(hostname, result) {
13815
14041
  }
13816
14042
 
13817
14043
  // src/caddy/utils.ts
13818
- var import_node_child_process3 = require("child_process");
13819
- var import_node_net = require("net");
13820
14044
  var import_ora = __toESM(require("ora"), 1);
13821
14045
  var spinner;
13822
- function tryPort(port) {
13823
- return new Promise((resolve2, _reject) => {
13824
- try {
13825
- const server = (0, import_node_net.createServer)().listen(port);
13826
- server.on("listening", () => {
13827
- server.close();
13828
- resolve2(false);
13829
- });
13830
- server.on("error", (err) => {
13831
- if (err.code === "EADDRINUSE")
13832
- resolve2(true);
13833
- server.close();
13834
- });
13835
- } catch {
13836
- resolve2(true);
13837
- }
13838
- });
13839
- }
13840
- async function kill(port) {
13841
- return new Promise((resolve2, reject2) => {
13842
- (0, import_node_child_process3.exec)(`npx @maxbo/free-port ${port} -s`, (err, stdout, _stderr) => {
13843
- if (err) {
13844
- reject2(err);
13845
- } else {
13846
- consola.log(stdout);
13847
- resolve2();
13848
- }
13849
- });
13850
- });
13851
- }
13852
14046
  function getNumber(number2) {
13853
14047
  if (number2 <= 0)
13854
14048
  return "0%";
@@ -13887,26 +14081,26 @@ async function download() {
13887
14081
  if (await testCaddy())
13888
14082
  return caddyPath;
13889
14083
  return new Promise((resolve2, reject2) => {
13890
- if (!(0, import_node_fs3.existsSync)(TEMP_DIR)) {
13891
- (0, import_node_fs3.mkdirSync)(TEMP_DIR, { recursive: true });
13892
- (0, import_node_fs3.chmodSync)(TEMP_DIR, 511);
14084
+ if (!(0, import_node_fs4.existsSync)(TEMP_DIR)) {
14085
+ (0, import_node_fs4.mkdirSync)(TEMP_DIR, { recursive: true });
14086
+ (0, import_node_fs4.chmodSync)(TEMP_DIR, 448);
13893
14087
  }
13894
- const file = (0, import_node_fs3.createWriteStream)(caddyPath);
13895
- let _platform = (0, import_node_os3.platform)().toString();
14088
+ const file = (0, import_node_fs4.createWriteStream)(caddyPath);
14089
+ let _platform = (0, import_node_os5.platform)().toString();
13896
14090
  _platform === "win32" && (_platform = "windows");
13897
- let _arch = import_node_process4.default.arch.toString();
14091
+ let _arch = import_node_process8.default.arch.toString();
13898
14092
  _arch === "x64" && (_arch = "amd64");
13899
14093
  const support = supportList.find((item) => item.platform === _platform && item.arch === _arch);
13900
14094
  if (!support)
13901
14095
  return reject2(new Error("not support"));
13902
14096
  const dowmloadLink = `https://caddyserver.com/api/download?os=${support.platform}&arch=${support.arch}&p=github.com%2Fcaddyserver%2Fforwardproxy`;
13903
- (0, import_node_fs3.existsSync)(caddyPath) && (0, import_node_fs3.unlinkSync)(caddyPath);
13904
- const httpProxy = import_node_process4.default.env.HTTP_PROXY || import_node_process4.default.env.http_proxy;
13905
- const httpsProxy = import_node_process4.default.env.HTTPS_PROXY || import_node_process4.default.env.https_proxy;
14097
+ (0, import_node_fs4.existsSync)(caddyPath) && (0, import_node_fs4.unlinkSync)(caddyPath);
14098
+ const httpProxy = import_node_process8.default.env.HTTP_PROXY || import_node_process8.default.env.http_proxy;
14099
+ const httpsProxy = import_node_process8.default.env.HTTPS_PROXY || import_node_process8.default.env.https_proxy;
13906
14100
  const httpAgent = httpProxy ? new import_http_proxy_agent.HttpProxyAgent(httpProxy) : void 0;
13907
14101
  const httpsAgent = httpsProxy ? new import_https_proxy_agent.HttpsProxyAgent(httpsProxy) : void 0;
13908
14102
  const chmodCaddyOnce = once(() => {
13909
- (0, import_node_fs3.chmodSync)(caddyPath, 511);
14103
+ (0, import_node_fs4.chmodSync)(caddyPath, 493);
13910
14104
  });
13911
14105
  import_got_cjs.got.stream(dowmloadLink, {
13912
14106
  agent: {
@@ -13918,9 +14112,9 @@ async function download() {
13918
14112
  chmodCaddyOnce();
13919
14113
  }).pipe(file).on("finish", () => {
13920
14114
  logProgressOver();
13921
- if (import_node_process4.default.platform === "win32")
14115
+ if (import_node_process8.default.platform === "win32")
13922
14116
  return resolve2(caddyPath);
13923
- (0, import_node_fs3.chmodSync)(caddyPath, 511);
14117
+ (0, import_node_fs4.chmodSync)(caddyPath, 493);
13924
14118
  resolve2(caddyPath);
13925
14119
  }).on("error", (err) => {
13926
14120
  reject2(err);
@@ -13928,26 +14122,41 @@ async function download() {
13928
14122
  });
13929
14123
  }
13930
14124
  function testCaddy() {
13931
- return new Promise((resolve2, reject2) => {
13932
- if (!(0, import_node_fs3.existsSync)(caddyPath))
13933
- return resolve2(false);
13934
- (0, import_node_fs3.chmodSync)(caddyPath, 511);
13935
- const child = import_node_process4.default.platform === "win32" ? (0, import_node_child_process4.spawn)(caddyPath, []) : (0, import_node_child_process4.spawn)("sudo", ["-E", caddyPath]);
13936
- child.on("close", () => {
14125
+ return new Promise((resolve2) => {
14126
+ if (!(0, import_node_fs4.existsSync)(caddyPath))
13937
14127
  return resolve2(false);
13938
- });
13939
- child.on("error", (err) => {
13940
- return reject2(err);
13941
- });
13942
- child.stdout.on("data", (_data) => {
13943
- return resolve2(true);
14128
+ try {
14129
+ (0, import_node_fs4.chmodSync)(caddyPath, 493);
14130
+ } catch {
14131
+ }
14132
+ (0, import_node_child_process3.execFile)(caddyPath, [], { timeout: 1e4 }, (error, stdout) => {
14133
+ if (error && !stdout)
14134
+ return resolve2(false);
14135
+ resolve2(stdout.length > 0);
13944
14136
  });
13945
14137
  });
13946
14138
  }
14139
+ function caddyRootPath() {
14140
+ return (0, import_node_path5.join)(
14141
+ import_node_process8.default.platform === "win32" ? `${import_node_process8.default.env.AppData}/Caddy` : `${import_node_process8.default.env.HOME}/Library/Application Support/Caddy`,
14142
+ "./pki/authorities/local"
14143
+ );
14144
+ }
14145
+ async function renderCaddyfile(proxies) {
14146
+ const ctx = validateTemplateContext({
14147
+ caddy_root: caddyRootPath(),
14148
+ admin_socket: caddyAdminSocketPath,
14149
+ proxies: Object.values(proxies)
14150
+ });
14151
+ const content = await genCaddyfile(ctx);
14152
+ const temp = `${caddyFilePath}.${import_node_process8.default.pid}.tmp`;
14153
+ await (0, import_promises2.writeFile)(temp, content);
14154
+ await (0, import_promises2.rename)(temp, caddyFilePath);
14155
+ }
13947
14156
  var caddyConfig;
13948
14157
  function getCaddyConfig() {
13949
14158
  if (!caddyConfig) {
13950
- caddyConfig = useCaddyConfig();
14159
+ caddyConfig = useCaddyConfig({ renderCaddyfile });
13951
14160
  }
13952
14161
  return caddyConfig;
13953
14162
  }
@@ -13962,80 +14171,92 @@ function splitHostPort(addr) {
13962
14171
  }
13963
14172
  return { host: addr.slice(0, lastColon), port: addr.slice(lastColon + 1) };
13964
14173
  }
14174
+ var defaultDependencies = {
14175
+ openSession: (runtimeDir, reason) => openPrivilegedSession(runtimeDir, {
14176
+ log: (message) => consola.debug(message),
14177
+ // Both paths are fixed here, before any socket traffic: the privileged
14178
+ // helper must never execute something named in a request.
14179
+ caddyBin: caddyPath,
14180
+ caddyConfigPath: caddyFilePath,
14181
+ caddyAdminSocket: caddyAdminSocketPath,
14182
+ reason
14183
+ }),
14184
+ config: () => getCaddyConfig()
14185
+ };
13965
14186
  var CaddyInstant = class {
13966
- constructor() {
14187
+ constructor(deps = {}) {
13967
14188
  this.inited = false;
13968
14189
  this.stoped = false;
13969
- /** has locked when start */
13970
- this.locked = false;
13971
14190
  this._stopEffects = [];
13972
- testCaddy().then(async () => {
13973
- this.inited = true;
13974
- });
13975
- this.locked = this.checkLock();
14191
+ /** Identifies this instance's routes in the shared config. */
14192
+ this.proxyKey = `${import_node_process8.default.pid}-${Math.random().toString(36).slice(2, 8)}`;
14193
+ this.deps = { ...defaultDependencies, ...deps };
13976
14194
  }
13977
- checkLock() {
13978
- if (!(0, import_node_fs3.existsSync)(caddyLockFilePath))
13979
- (0, import_node_fs3.writeFileSync)(caddyLockFilePath, "");
13980
- return lockfile.checkSync(caddyLockFilePath);
14195
+ /**
14196
+ * Connects to the privileged helper, starting it once if needed. It is
14197
+ * reused across instances so a second dev server does not ask for a
14198
+ * password again.
14199
+ */
14200
+ async session(reason) {
14201
+ if (this._session && !this._session.client.connected)
14202
+ this._session = void 0;
14203
+ if (!this._session)
14204
+ this._session = await this.deps.openSession(TEMP_DIR, reason);
14205
+ return this._session;
13981
14206
  }
13982
14207
  async getCaddyfile() {
13983
- if (!(0, import_node_fs3.existsSync)(caddyFilePath)) {
14208
+ if (!(0, import_node_fs4.existsSync)(caddyFilePath)) {
13984
14209
  this.caddyfile = "";
13985
14210
  return "";
13986
14211
  }
13987
- this.caddyfile = await (0, import_promises3.readFile)(caddyFilePath, "utf-8");
14212
+ this.caddyfile = await (0, import_promises2.readFile)(caddyFilePath, "utf-8");
13988
14213
  return this.caddyfile;
13989
14214
  }
13990
14215
  get caddyRoot() {
13991
- return (0, import_node_path3.join)(
13992
- import_node_process4.default.platform === "win32" ? `${import_node_process4.default.env.AppData}/Caddy` : `${import_node_process4.default.env.HOME}/Library/Application Support/Caddy`,
13993
- "./pki/authorities/local"
13994
- );
14216
+ return caddyRootPath();
13995
14217
  }
13996
14218
  async writeCaddyfile() {
13997
- return await (0, import_promises3.writeFile)(caddyFilePath, this.caddyfile || "");
14219
+ return await (0, import_promises2.writeFile)(caddyFilePath, this.caddyfile || "");
13998
14220
  }
13999
14221
  async deleteCaddyfile() {
14000
- return await (0, import_promises3.unlink)(caddyFilePath);
14222
+ return await (0, import_promises2.unlink)(caddyFilePath);
14001
14223
  }
14002
14224
  async init() {
14003
14225
  await download();
14004
14226
  this.inited = true;
14005
14227
  }
14228
+ /**
14229
+ * Hands the Caddy storage directory back to the developer. Local CA data
14230
+ * created by an earlier root-owned run must stay readable for `tls internal`
14231
+ * to keep serving the same certificate the browser already trusts.
14232
+ */
14233
+ /**
14234
+ * Installs Caddy's local root CA so the browser stops warning about
14235
+ * `tls internal` certificates. Generating the CA and trusting it are separate
14236
+ * steps: a new CA appears whenever the previous one expires or the storage is
14237
+ * replaced, so this runs on every start instead of once.
14238
+ *
14239
+ * The helper owns both the binary path and the command, so nothing here can
14240
+ * be turned into an arbitrary root execution.
14241
+ */
14242
+ async trustLocalCa(session) {
14243
+ try {
14244
+ const result = await session.client.call("ca.trust");
14245
+ if (result.trusted)
14246
+ consola.debug(`Caddy local CA is trusted
14247
+ ${result.output}`);
14248
+ } catch (error) {
14249
+ consola.warn(
14250
+ `could not install the Caddy root certificate automatically: ${error.message}
14251
+ Run \`${caddyPath} trust\` manually if the browser warns about the certificate.`
14252
+ );
14253
+ }
14254
+ }
14006
14255
  async ensureTlsReady(targetHost) {
14007
14256
  const health = await waitForLocalTls(targetHost);
14008
14257
  if (!health.healthy)
14009
14258
  throw new Error(formatTlsHealthFailure(targetHost, health));
14010
14259
  }
14011
- async updateCaddyfile() {
14012
- const { configJsonRef } = getCaddyConfig();
14013
- const proxies = Object.values(configJsonRef() || {});
14014
- const ctx = validateTemplateContext({
14015
- caddy_root: this.caddyRoot,
14016
- proxies
14017
- });
14018
- this.caddyfile = await genCaddyfile(ctx);
14019
- await this.writeCaddyfile();
14020
- }
14021
- async stopCaddy() {
14022
- var _a4;
14023
- try {
14024
- await import_got_cjs.got.post("http://127.0.0.1:2019/stop", {
14025
- headers: {
14026
- Origin: "http://localhost:2019"
14027
- },
14028
- retry: {
14029
- limit: 0
14030
- },
14031
- timeout: {
14032
- request: 2e3
14033
- }
14034
- });
14035
- } catch {
14036
- }
14037
- (_a4 = this._caddyChild) == null ? void 0 : _a4.kill();
14038
- }
14039
14260
  /**
14040
14261
  * @param source like `127.0.0.1:8080`
14041
14262
  * @param target like `test.abc.com`. And if you provide a port ,it will be ignore.
@@ -14056,10 +14277,10 @@ var CaddyInstant = class {
14056
14277
  await this.init();
14057
14278
  const sourceHost = splitHostPort(source).host;
14058
14279
  const targetHost = splitHostPort(target).host;
14059
- if (!await addHost(sourceHost, targetHost))
14060
- throw new Error("update host failed");
14280
+ const session = await this.session({ target: targetHost, https });
14281
+ await session.client.call("hosts.add", { ip: sourceHost, host: targetHost });
14061
14282
  consola.success("update host success\n");
14062
- const normalizeBase = (b) => {
14283
+ const normalizeBase2 = (b) => {
14063
14284
  let out = b || "/";
14064
14285
  if (!out.startsWith("/"))
14065
14286
  out = `/${out}`;
@@ -14067,7 +14288,7 @@ var CaddyInstant = class {
14067
14288
  out = `${out}/`;
14068
14289
  return out;
14069
14290
  };
14070
- const baseNormalized = normalizeBase(base);
14291
+ const baseNormalized = normalizeBase2(base);
14071
14292
  const proxies = [
14072
14293
  {
14073
14294
  target: targetHost,
@@ -14078,176 +14299,138 @@ var CaddyInstant = class {
14078
14299
  healthCheck
14079
14300
  }
14080
14301
  ];
14081
- const { writeCaddyConfig } = getCaddyConfig();
14082
- writeCaddyConfig(proxies);
14083
- await this.updateCaddyfile();
14084
- let skipInitialCaddyfileEffect = true;
14085
- this._stopEffects.push(
14086
- effect(() => {
14087
- getCaddyConfig().configJsonRef();
14088
- if (skipInitialCaddyfileEffect) {
14089
- skipInitialCaddyfileEffect = false;
14090
- return;
14091
- }
14092
- void this.updateCaddyfile();
14093
- })
14094
- );
14095
- if (!(0, import_node_fs3.existsSync)(caddyLockFilePath))
14096
- (0, import_node_fs3.writeFileSync)(caddyLockFilePath, "");
14097
- if (!this.locked) {
14098
- if (await tryPort(443))
14099
- await kill(443);
14100
- if ((import_node_process4.default.platform === "win32" || !https) && await tryPort(80))
14101
- await kill(80);
14102
- }
14302
+ const { writeCaddyConfig } = this.deps.config();
14303
+ await writeCaddyConfig(proxies, this.proxyKey);
14304
+ await session.client.call("port.free", { port: 443 });
14305
+ if (import_node_process8.default.platform === "win32" || !https)
14306
+ await session.client.call("port.free", { port: 80 });
14103
14307
  return new Promise((resolve2, reject2) => {
14104
- var _a4, _b3;
14105
14308
  let startupCheckStarted = false;
14106
14309
  const resolveWhenReady = async () => {
14107
14310
  if (startupCheckStarted)
14108
14311
  return;
14109
14312
  startupCheckStarted = true;
14110
14313
  try {
14111
- if (https)
14314
+ if (https) {
14315
+ await this.trustLocalCa(session);
14112
14316
  await this.ensureTlsReady(targetHost);
14317
+ }
14113
14318
  resolve2();
14114
14319
  } catch (error) {
14115
- if (!this.locked)
14116
- await this.baseCleanup(restore);
14320
+ await this.baseCleanup(restore);
14117
14321
  reject2(error);
14118
14322
  }
14119
14323
  };
14120
14324
  const setupCleanup = () => {
14121
- import_node_process4.default.on("SIGINT", async () => {
14325
+ import_node_process8.default.on("SIGINT", async () => {
14122
14326
  if (this.stoped)
14123
14327
  return;
14124
- import_node_process4.default.stdin.resume();
14328
+ import_node_process8.default.stdin.resume();
14125
14329
  try {
14126
14330
  await this.baseCleanup(restore);
14127
14331
  } finally {
14128
14332
  this.stoped = true;
14129
- import_node_process4.default.nextTick(() => {
14130
- import_node_process4.default.exit();
14333
+ import_node_process8.default.nextTick(() => {
14334
+ import_node_process8.default.exit();
14131
14335
  });
14132
14336
  }
14133
14337
  });
14134
- const originalExit = import_node_process4.default.exit.bind(import_node_process4.default);
14135
- import_node_process4.default.exit = async (code) => {
14136
- const port = Number(splitHostPort(source).port);
14137
- if (!Number.isNaN(port) && await tryPort(port))
14138
- await kill(port);
14139
- const pwd = import_node_process4.default.cwd();
14140
- const viteCacheDir = `${pwd}/node_modules/.vite`;
14141
- if ((0, import_node_fs3.existsSync)(viteCacheDir))
14142
- await chmodRecursive(viteCacheDir, 511).catch(() => {
14143
- });
14144
- const viteTempCacheDir = `${pwd}/node_modules/.vite-temp`;
14145
- if ((0, import_node_fs3.existsSync)(viteTempCacheDir))
14146
- await chmodRecursive(viteTempCacheDir, 511).catch(() => {
14147
- });
14148
- const nuxtCacheDir = `${pwd}/.nuxt`;
14149
- if ((0, import_node_fs3.existsSync)(nuxtCacheDir))
14150
- await chmodRecursive(nuxtCacheDir, 511).catch(() => {
14151
- });
14152
- const webpackCacheDir = `${pwd}/node_modules/.cache`;
14153
- if ((0, import_node_fs3.existsSync)(webpackCacheDir))
14154
- await chmodRecursive(webpackCacheDir, 511).catch(() => {
14155
- });
14338
+ const originalExit = import_node_process8.default.exit.bind(import_node_process8.default);
14339
+ import_node_process8.default.exit = async (code) => {
14156
14340
  if (this.stoped)
14157
14341
  return originalExit(code);
14158
- import_node_process4.default.stdin.resume();
14342
+ import_node_process8.default.stdin.resume();
14159
14343
  try {
14160
14344
  await this.baseCleanup();
14161
14345
  } finally {
14162
14346
  this.stoped = true;
14163
- import_node_process4.default.nextTick(() => {
14347
+ import_node_process8.default.nextTick(() => {
14164
14348
  originalExit(code);
14165
14349
  });
14166
14350
  }
14167
14351
  };
14168
14352
  };
14169
- if (!this.locked) {
14170
- this._caddyChild = import_node_process4.default.platform !== "win32" ? (0, import_node_child_process4.spawn)("sudo", ["-E", caddyPath, "run", "--config", caddyFilePath, "--watch"]) : (0, import_node_child_process4.spawn)(caddyPath, ["run", "--config", caddyFilePath, "--watch"]);
14171
- lockfile.lockSync(caddyLockFilePath);
14172
- this._caddyChild.on("error", (err) => {
14173
- return reject2(err);
14174
- });
14175
- (_a4 = this._caddyChild.stderr) == null ? void 0 : _a4.on("data", async (data) => {
14176
- const lines = data.toString().split("\n").map((line) => line.trim());
14177
- for (const line of lines) {
14178
- showCaddyLog && line && console.info(line);
14179
- if (isCaddyReloadCancellation(line)) {
14180
- consola.info("Caddy restarted before TLS issuance completed; retrying.\n");
14181
- continue;
14182
- }
14183
- try {
14184
- if (line.includes("Error:") || line && JSON.parse(line).level === "error") {
14185
- if (line.includes("parsing caddyfile tokens")) {
14186
- consola.error("Caddyfile syntax error, please contact the author:\n", `${this.caddyfile}
14353
+ setupCleanup();
14354
+ void (async () => {
14355
+ try {
14356
+ const child = new HelperCaddyProcess(session.client);
14357
+ this._caddyChild = child;
14358
+ const started = await session.client.call("caddy.start");
14359
+ child.on("exit", (code) => {
14360
+ if (code !== null && code !== 0)
14361
+ reject2(new Error(`Caddy exited with code ${code}`));
14362
+ });
14363
+ if ((started == null ? void 0 : started.started) === false) {
14364
+ consola.info("Caddy is already running; added this route to it.");
14365
+ void resolveWhenReady();
14366
+ return;
14367
+ }
14368
+ child.stderr.on("data", async (data) => {
14369
+ const lines = data.toString().split("\n").map((line) => line.trim());
14370
+ for (const line of lines) {
14371
+ showCaddyLog && line && console.info(line);
14372
+ if (isCaddyReloadCancellation(line)) {
14373
+ consola.info("Caddy restarted before TLS issuance completed; retrying.\n");
14374
+ continue;
14375
+ }
14376
+ try {
14377
+ if (line.includes("Error:") || line && JSON.parse(line).level === "error") {
14378
+ if (line.includes("parsing caddyfile tokens")) {
14379
+ consola.error("Caddyfile syntax error, please contact the author:\n", `${this.caddyfile}
14187
14380
 
14188
14381
  ${line}
14189
14382
  `);
14190
- await this.baseCleanup();
14191
- import_node_process4.default.exit();
14192
- } else {
14193
- consola.error(`${line}
14383
+ await this.baseCleanup();
14384
+ import_node_process8.default.exit();
14385
+ } else {
14386
+ consola.error(`${line}
14194
14387
  `);
14195
- return reject2(line);
14388
+ return reject2(line);
14389
+ }
14196
14390
  }
14391
+ } catch {
14197
14392
  }
14198
- } catch {
14393
+ if (line.includes("config file changed"))
14394
+ consola.success("Detect added a new reverse proxy config, restarted.\n");
14395
+ if (line.includes("caddy proxying") || line.includes("serving initial"))
14396
+ void resolveWhenReady();
14199
14397
  }
14200
- if (line.includes("config file changed"))
14201
- consola.success("Detect added a new reverse proxy config, restarted.\n");
14202
- if (line.includes("caddy proxying") || line.includes("serving initial"))
14203
- void resolveWhenReady();
14204
- }
14205
- });
14206
- (_b3 = this._caddyChild.stdout) == null ? void 0 : _b3.on("data", (_data) => {
14207
- consola.info(_data.toString());
14208
- void resolveWhenReady();
14209
- });
14210
- setupCleanup();
14211
- } else {
14212
- consola.info("Caddy is running in another process.");
14213
- void (async () => {
14214
- try {
14215
- if (https)
14216
- await this.ensureTlsReady(targetHost);
14217
- setupCleanup();
14218
- resolve2();
14219
- } catch (error) {
14220
- reject2(error);
14221
- }
14222
- })();
14223
- }
14398
+ });
14399
+ child.stdout.on("data", (data) => {
14400
+ consola.info(data.toString());
14401
+ void resolveWhenReady();
14402
+ });
14403
+ } catch (error) {
14404
+ await this.baseCleanup(restore);
14405
+ reject2(error);
14406
+ }
14407
+ })();
14224
14408
  });
14225
14409
  }
14226
14410
  async baseCleanup(restore = true) {
14411
+ var _a4;
14227
14412
  this._stopEffects.forEach((fn) => fn());
14413
+ this._stopEffects.length = 0;
14228
14414
  try {
14229
- if (restore && this._source && this._target) {
14230
- if (await removeHost(splitHostPort(this._source).host, splitHostPort(this._target).host))
14231
- consola.success("Restore host success.\n");
14232
- else
14233
- consola.fail("Restore host failed.\n");
14415
+ if (restore && this._source && this._target && this._session) {
14416
+ const sourceHost = splitHostPort(this._source).host;
14417
+ const targetHost = splitHostPort(this._target).host;
14418
+ await this._session.client.call("hosts.remove", { ip: sourceHost, host: targetHost });
14419
+ if (sourceHost === "localhost")
14420
+ await this._session.client.call("hosts.remove", { ip: "127.0.0.1", host: targetHost });
14421
+ consola.success("Restore host success.\n");
14234
14422
  }
14235
14423
  } catch (e) {
14236
- consola.error(e);
14237
- consola.fail("Restore host failed.\n");
14424
+ if (((_a4 = this._session) == null ? void 0 : _a4.client.connected) === false) {
14425
+ consola.debug("hosts entries are restored by the privileged helper on disconnect");
14426
+ } else {
14427
+ consola.error(e);
14428
+ consola.fail("Restore host failed.\n");
14429
+ }
14238
14430
  }
14239
- if (!this.locked && !this.stoped) {
14240
- await this.stopCaddy();
14431
+ if (!this.stoped) {
14241
14432
  try {
14242
- await lockfile.unlock(caddyLockFilePath).catch(() => {
14243
- });
14244
- await (0, import_promises3.unlink)(caddyFilePath).catch(() => {
14245
- });
14246
- await (0, import_promises3.unlink)(caddyLockFilePath).catch(() => {
14247
- });
14248
- if (caddyConfig) {
14249
- await caddyConfig.cleanUp();
14250
- }
14433
+ await this.deps.config().removeProxy(this.proxyKey);
14251
14434
  } catch (e) {
14252
14435
  consola.error(e);
14253
14436
  }
@@ -14259,10 +14442,16 @@ ${line}
14259
14442
  var SSE_PATH = "/__hmr_sse";
14260
14443
  var SEND_PATH = "/__hmr_send";
14261
14444
  var MAX_POST_BODY = 64 * 1024;
14445
+ function shouldUseHmrSseBridge(protocol, userAgent) {
14446
+ if (protocol !== "https:")
14447
+ return false;
14448
+ const isApplePlatform = /Macintosh|iPhone|iPad|iPod/.test(userAgent);
14449
+ const isSafari = /Version\//.test(userAgent) && /Safari\//.test(userAgent) && !/(?:Chrome|Chromium|CriOS|Edg|EdgiOS|OPR|OPiOS|Firefox|FxiOS)\//.test(userAgent);
14450
+ return isApplePlatform && isSafari;
14451
+ }
14262
14452
  var hmrSseBridgeClientScript = `
14263
14453
  (function() {
14264
- // Activate when served over HTTPS to bypass WSS self-signed cert issues
14265
- if (location.protocol !== 'https:') return;
14454
+ if (!(${shouldUseHmrSseBridge.toString()})(location.protocol, navigator.userAgent)) return;
14266
14455
 
14267
14456
  var OriginalWebSocket = window.WebSocket;
14268
14457
 
@@ -14386,9 +14575,18 @@ var hmrSseBridgeClientScript = `
14386
14575
  })();
14387
14576
  `;
14388
14577
 
14578
+ // src/privilege-state.ts
14579
+ var denied = false;
14580
+ function markPrivilegeDenied() {
14581
+ denied = true;
14582
+ }
14583
+ function isPrivilegeDenied() {
14584
+ return denied;
14585
+ }
14586
+
14389
14587
  // src/index.ts
14390
14588
  var caddy;
14391
- var cwd = import_node_process5.default.cwd();
14589
+ var cwd = import_node_process9.default.cwd();
14392
14590
  function colorUrl(url2) {
14393
14591
  return import_picocolors2.default.green(url2.replace(/:(\d+)\//, (_, port) => `:${import_picocolors2.default.bold(port)}/`));
14394
14592
  }
@@ -14423,16 +14621,27 @@ async function printForwardProxy() {
14423
14621
  }
14424
14622
  var vitePrintUrls = once((options, source, target, base = "/", _printUrls) => {
14425
14623
  _printUrls == null ? void 0 : _printUrls();
14624
+ if (isPrivilegeDenied())
14625
+ return;
14426
14626
  if (caddy)
14427
14627
  return;
14428
- caddy = new CaddyInstant();
14429
- caddy.run(source, target, {
14628
+ const instance = new CaddyInstant();
14629
+ caddy = instance;
14630
+ instance.run(source, target, {
14430
14631
  base,
14431
14632
  ...options
14432
14633
  }).then(async () => {
14433
14634
  await printForwardProxy();
14434
14635
  consola.success(` ${import_picocolors2.default.green("\u279C")} ${import_picocolors2.default.bold("run caddy reverse proxy success")}: ${colorUrl(`${options.https ? "https" : "http"}://${target}${base}`)}`);
14435
14636
  }).catch((e) => {
14637
+ if (caddy === instance)
14638
+ caddy = void 0;
14639
+ if (e instanceof PrivilegeDeniedError) {
14640
+ markPrivilegeDenied();
14641
+ consola.warn("reverse proxy skipped: administrator permission was not granted.");
14642
+ consola.info("Restart the dev server to enable it again.");
14643
+ return;
14644
+ }
14436
14645
  throw e;
14437
14646
  });
14438
14647
  });
@@ -14445,7 +14654,7 @@ var nuxt_default = (0, import_kit.defineNuxtModule)({
14445
14654
  configKey: "unpluginHttpsReverseProxy"
14446
14655
  },
14447
14656
  setup(options, _nuxt) {
14448
- if (import_node_process6.default.env.NODE_ENV !== "development")
14657
+ if (import_node_process10.default.env.NODE_ENV !== "development")
14449
14658
  return;
14450
14659
  const {
14451
14660
  enable = true,
@@ -14453,10 +14662,6 @@ var nuxt_default = (0, import_kit.defineNuxtModule)({
14453
14662
  } = options;
14454
14663
  if (!enable)
14455
14664
  return;
14456
- if (!isAdmin()) {
14457
- consola.warn("please run as administrator");
14458
- return;
14459
- }
14460
14665
  if (!target) {
14461
14666
  consola.fail("please provide target");
14462
14667
  return;