unplugin-https-reverse-proxy 4.1.0-beta.2 → 4.1.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/webpack.cjs CHANGED
@@ -36,7 +36,7 @@ module.exports = __toCommonJS(webpack_exports);
36
36
  var import_unplugin2 = require("unplugin");
37
37
 
38
38
  // src/index.ts
39
- var import_node_process8 = __toESM(require("process"), 1);
39
+ var import_node_process9 = __toESM(require("process"), 1);
40
40
  var import_console_table_printer = require("console-table-printer");
41
41
  var import_picocolors2 = __toESM(require("picocolors"), 1);
42
42
  var import_unplugin = require("unplugin");
@@ -44,450 +44,13 @@ var import_unplugin = require("unplugin");
44
44
  // src/caddy/index.ts
45
45
  var import_node_child_process3 = require("child_process");
46
46
  var import_node_fs4 = require("fs");
47
- var import_promises3 = require("fs/promises");
47
+ var import_promises2 = require("fs/promises");
48
48
  var import_node_os5 = require("os");
49
49
  var import_node_path5 = require("path");
50
- var import_node_process7 = __toESM(require("process"), 1);
51
-
52
- // node_modules/.pnpm/alien-signals@2.0.7/node_modules/alien-signals/esm/system.mjs
53
- var ReactiveFlags;
54
- (function(ReactiveFlags2) {
55
- ReactiveFlags2[ReactiveFlags2["None"] = 0] = "None";
56
- ReactiveFlags2[ReactiveFlags2["Mutable"] = 1] = "Mutable";
57
- ReactiveFlags2[ReactiveFlags2["Watching"] = 2] = "Watching";
58
- ReactiveFlags2[ReactiveFlags2["RecursedCheck"] = 4] = "RecursedCheck";
59
- ReactiveFlags2[ReactiveFlags2["Recursed"] = 8] = "Recursed";
60
- ReactiveFlags2[ReactiveFlags2["Dirty"] = 16] = "Dirty";
61
- ReactiveFlags2[ReactiveFlags2["Pending"] = 32] = "Pending";
62
- })(ReactiveFlags || (ReactiveFlags = {}));
63
- function createReactiveSystem({ update, notify: notify2, unwatched }) {
64
- let currentVersion = 0;
65
- return {
66
- link: link2,
67
- unlink: unlink4,
68
- propagate: propagate2,
69
- checkDirty: checkDirty2,
70
- endTracking: endTracking2,
71
- startTracking: startTracking2,
72
- shallowPropagate: shallowPropagate2
73
- };
74
- function link2(dep, sub) {
75
- const prevDep = sub.depsTail;
76
- if (prevDep !== void 0 && prevDep.dep === dep) {
77
- return;
78
- }
79
- const nextDep = prevDep !== void 0 ? prevDep.nextDep : sub.deps;
80
- if (nextDep !== void 0 && nextDep.dep === dep) {
81
- nextDep.version = currentVersion;
82
- sub.depsTail = nextDep;
83
- return;
84
- }
85
- const prevSub = dep.subsTail;
86
- if (prevSub !== void 0 && prevSub.version === currentVersion && prevSub.sub === sub) {
87
- return;
88
- }
89
- const newLink = sub.depsTail = dep.subsTail = {
90
- version: currentVersion,
91
- dep,
92
- sub,
93
- prevDep,
94
- nextDep,
95
- prevSub,
96
- nextSub: void 0
97
- };
98
- if (nextDep !== void 0) {
99
- nextDep.prevDep = newLink;
100
- }
101
- if (prevDep !== void 0) {
102
- prevDep.nextDep = newLink;
103
- } else {
104
- sub.deps = newLink;
105
- }
106
- if (prevSub !== void 0) {
107
- prevSub.nextSub = newLink;
108
- } else {
109
- dep.subs = newLink;
110
- }
111
- }
112
- function unlink4(link3, sub = link3.sub) {
113
- const dep = link3.dep;
114
- const prevDep = link3.prevDep;
115
- const nextDep = link3.nextDep;
116
- const nextSub = link3.nextSub;
117
- const prevSub = link3.prevSub;
118
- if (nextDep !== void 0) {
119
- nextDep.prevDep = prevDep;
120
- } else {
121
- sub.depsTail = prevDep;
122
- }
123
- if (prevDep !== void 0) {
124
- prevDep.nextDep = nextDep;
125
- } else {
126
- sub.deps = nextDep;
127
- }
128
- if (nextSub !== void 0) {
129
- nextSub.prevSub = prevSub;
130
- } else {
131
- dep.subsTail = prevSub;
132
- }
133
- if (prevSub !== void 0) {
134
- prevSub.nextSub = nextSub;
135
- } else if ((dep.subs = nextSub) === void 0) {
136
- unwatched(dep);
137
- }
138
- return nextDep;
139
- }
140
- function propagate2(link3) {
141
- let next2 = link3.nextSub;
142
- let stack;
143
- top:
144
- do {
145
- const sub = link3.sub;
146
- let flags = sub.flags;
147
- if (!(flags & 60)) {
148
- sub.flags = flags | 32;
149
- } else if (!(flags & 12)) {
150
- flags = 0;
151
- } else if (!(flags & 4)) {
152
- sub.flags = flags & ~8 | 32;
153
- } else if (!(flags & 48) && isValidLink(link3, sub)) {
154
- sub.flags = flags | 40;
155
- flags &= 1;
156
- } else {
157
- flags = 0;
158
- }
159
- if (flags & 2) {
160
- notify2(sub);
161
- }
162
- if (flags & 1) {
163
- const subSubs = sub.subs;
164
- if (subSubs !== void 0) {
165
- const nextSub = (link3 = subSubs).nextSub;
166
- if (nextSub !== void 0) {
167
- stack = { value: next2, prev: stack };
168
- next2 = nextSub;
169
- }
170
- continue;
171
- }
172
- }
173
- if ((link3 = next2) !== void 0) {
174
- next2 = link3.nextSub;
175
- continue;
176
- }
177
- while (stack !== void 0) {
178
- link3 = stack.value;
179
- stack = stack.prev;
180
- if (link3 !== void 0) {
181
- next2 = link3.nextSub;
182
- continue top;
183
- }
184
- }
185
- break;
186
- } while (true);
187
- }
188
- function startTracking2(sub) {
189
- ++currentVersion;
190
- sub.depsTail = void 0;
191
- sub.flags = sub.flags & ~56 | 4;
192
- }
193
- function endTracking2(sub) {
194
- const depsTail = sub.depsTail;
195
- let toRemove = depsTail !== void 0 ? depsTail.nextDep : sub.deps;
196
- while (toRemove !== void 0) {
197
- toRemove = unlink4(toRemove, sub);
198
- }
199
- sub.flags &= ~4;
200
- }
201
- function checkDirty2(link3, sub) {
202
- let stack;
203
- let checkDepth = 0;
204
- top:
205
- do {
206
- const dep = link3.dep;
207
- const flags = dep.flags;
208
- let dirty = false;
209
- if (sub.flags & 16) {
210
- dirty = true;
211
- } else if ((flags & 17) === 17) {
212
- if (update(dep)) {
213
- const subs = dep.subs;
214
- if (subs.nextSub !== void 0) {
215
- shallowPropagate2(subs);
216
- }
217
- dirty = true;
218
- }
219
- } else if ((flags & 33) === 33) {
220
- if (link3.nextSub !== void 0 || link3.prevSub !== void 0) {
221
- stack = { value: link3, prev: stack };
222
- }
223
- link3 = dep.deps;
224
- sub = dep;
225
- ++checkDepth;
226
- continue;
227
- }
228
- if (!dirty) {
229
- const nextDep = link3.nextDep;
230
- if (nextDep !== void 0) {
231
- link3 = nextDep;
232
- continue;
233
- }
234
- }
235
- while (checkDepth--) {
236
- const firstSub = sub.subs;
237
- const hasMultipleSubs = firstSub.nextSub !== void 0;
238
- if (hasMultipleSubs) {
239
- link3 = stack.value;
240
- stack = stack.prev;
241
- } else {
242
- link3 = firstSub;
243
- }
244
- if (dirty) {
245
- if (update(sub)) {
246
- if (hasMultipleSubs) {
247
- shallowPropagate2(firstSub);
248
- }
249
- sub = link3.sub;
250
- continue;
251
- }
252
- } else {
253
- sub.flags &= ~32;
254
- }
255
- sub = link3.sub;
256
- const nextDep = link3.nextDep;
257
- if (nextDep !== void 0) {
258
- link3 = nextDep;
259
- continue top;
260
- }
261
- dirty = false;
262
- }
263
- return dirty;
264
- } while (true);
265
- }
266
- function shallowPropagate2(link3) {
267
- do {
268
- const sub = link3.sub;
269
- const flags = sub.flags;
270
- if ((flags & 48) === 32) {
271
- sub.flags = flags | 16;
272
- if (flags & 2) {
273
- notify2(sub);
274
- }
275
- }
276
- } while ((link3 = link3.nextSub) !== void 0);
277
- }
278
- function isValidLink(checkLink, sub) {
279
- let link3 = sub.depsTail;
280
- while (link3 !== void 0) {
281
- if (link3 === checkLink) {
282
- return true;
283
- }
284
- link3 = link3.prevDep;
285
- }
286
- return false;
287
- }
288
- }
289
-
290
- // node_modules/.pnpm/alien-signals@2.0.7/node_modules/alien-signals/esm/index.mjs
291
- var queuedEffects = [];
292
- var { link, unlink, propagate, checkDirty, endTracking, startTracking, shallowPropagate } = createReactiveSystem({
293
- update(signal2) {
294
- if ("getter" in signal2) {
295
- return updateComputed(signal2);
296
- } else {
297
- return updateSignal(signal2, signal2.value);
298
- }
299
- },
300
- notify,
301
- unwatched(node2) {
302
- if ("getter" in node2) {
303
- let toRemove = node2.deps;
304
- if (toRemove !== void 0) {
305
- node2.flags = 17;
306
- do {
307
- toRemove = unlink(toRemove, node2);
308
- } while (toRemove !== void 0);
309
- }
310
- } else if (!("previousValue" in node2)) {
311
- effectOper.call(node2);
312
- }
313
- }
314
- });
315
- var batchDepth = 0;
316
- var notifyIndex = 0;
317
- var queuedEffectsLength = 0;
318
- var activeSub;
319
- var activeScope;
320
- function setCurrentSub(sub) {
321
- const prevSub = activeSub;
322
- activeSub = sub;
323
- return prevSub;
324
- }
325
- function signal(initialValue) {
326
- return signalOper.bind({
327
- previousValue: initialValue,
328
- value: initialValue,
329
- subs: void 0,
330
- subsTail: void 0,
331
- flags: 1
332
- });
333
- }
334
- function computed(getter) {
335
- return computedOper.bind({
336
- value: void 0,
337
- subs: void 0,
338
- subsTail: void 0,
339
- deps: void 0,
340
- depsTail: void 0,
341
- flags: 17,
342
- getter
343
- });
344
- }
345
- function effect(fn) {
346
- const e = {
347
- fn,
348
- subs: void 0,
349
- subsTail: void 0,
350
- deps: void 0,
351
- depsTail: void 0,
352
- flags: 2
353
- };
354
- if (activeSub !== void 0) {
355
- link(e, activeSub);
356
- } else if (activeScope !== void 0) {
357
- link(e, activeScope);
358
- }
359
- const prev = setCurrentSub(e);
360
- try {
361
- e.fn();
362
- } finally {
363
- setCurrentSub(prev);
364
- }
365
- return effectOper.bind(e);
366
- }
367
- function updateComputed(c3) {
368
- const prevSub = setCurrentSub(c3);
369
- startTracking(c3);
370
- try {
371
- const oldValue = c3.value;
372
- return oldValue !== (c3.value = c3.getter(oldValue));
373
- } finally {
374
- setCurrentSub(prevSub);
375
- endTracking(c3);
376
- }
377
- }
378
- function updateSignal(s, value2) {
379
- s.flags = 1;
380
- return s.previousValue !== (s.previousValue = value2);
381
- }
382
- function notify(e) {
383
- const flags = e.flags;
384
- if (!(flags & 64)) {
385
- e.flags = flags | 64;
386
- const subs = e.subs;
387
- if (subs !== void 0) {
388
- notify(subs.sub);
389
- } else {
390
- queuedEffects[queuedEffectsLength++] = e;
391
- }
392
- }
393
- }
394
- function run(e, flags) {
395
- if (flags & 16 || flags & 32 && checkDirty(e.deps, e)) {
396
- const prev = setCurrentSub(e);
397
- startTracking(e);
398
- try {
399
- e.fn();
400
- } finally {
401
- setCurrentSub(prev);
402
- endTracking(e);
403
- }
404
- return;
405
- } else if (flags & 32) {
406
- e.flags = flags & ~32;
407
- }
408
- let link2 = e.deps;
409
- while (link2 !== void 0) {
410
- const dep = link2.dep;
411
- const depFlags = dep.flags;
412
- if (depFlags & 64) {
413
- run(dep, dep.flags = depFlags & ~64);
414
- }
415
- link2 = link2.nextDep;
416
- }
417
- }
418
- function flush() {
419
- while (notifyIndex < queuedEffectsLength) {
420
- const effect2 = queuedEffects[notifyIndex];
421
- queuedEffects[notifyIndex++] = void 0;
422
- run(effect2, effect2.flags &= ~64);
423
- }
424
- notifyIndex = 0;
425
- queuedEffectsLength = 0;
426
- }
427
- function computedOper() {
428
- const flags = this.flags;
429
- if (flags & 16 || flags & 32 && checkDirty(this.deps, this)) {
430
- if (updateComputed(this)) {
431
- const subs = this.subs;
432
- if (subs !== void 0) {
433
- shallowPropagate(subs);
434
- }
435
- }
436
- } else if (flags & 32) {
437
- this.flags = flags & ~32;
438
- }
439
- if (activeSub !== void 0) {
440
- link(this, activeSub);
441
- } else if (activeScope !== void 0) {
442
- link(this, activeScope);
443
- }
444
- return this.value;
445
- }
446
- function signalOper(...value2) {
447
- if (value2.length) {
448
- if (this.value !== (this.value = value2[0])) {
449
- this.flags = 17;
450
- const subs = this.subs;
451
- if (subs !== void 0) {
452
- propagate(subs);
453
- if (!batchDepth) {
454
- flush();
455
- }
456
- }
457
- }
458
- } else {
459
- const value3 = this.value;
460
- if (this.flags & 16) {
461
- if (updateSignal(this, value3)) {
462
- const subs = this.subs;
463
- if (subs !== void 0) {
464
- shallowPropagate(subs);
465
- }
466
- }
467
- }
468
- if (activeSub !== void 0) {
469
- link(this, activeSub);
470
- }
471
- return value3;
472
- }
473
- }
474
- function effectOper() {
475
- let dep = this.deps;
476
- while (dep !== void 0) {
477
- dep = unlink(dep, this);
478
- }
479
- const sub = this.subs;
480
- if (sub !== void 0) {
481
- unlink(sub);
482
- }
483
- this.flags = 0;
484
- }
485
-
486
- // src/caddy/index.ts
50
+ var import_node_process8 = __toESM(require("process"), 1);
487
51
  var import_got_cjs = require("got-cjs");
488
52
  var import_http_proxy_agent = require("http-proxy-agent");
489
53
  var import_https_proxy_agent = require("https-proxy-agent");
490
- var lockfile = __toESM(require("proper-lockfile"), 1);
491
54
 
492
55
  // src/utils.ts
493
56
  var import_node_os = require("os");
@@ -13469,7 +13032,8 @@ async function genCaddyfile(ctx) {
13469
13032
 
13470
13033
  // src/caddy/config.ts
13471
13034
  var import_node_fs = require("fs");
13472
- var import_promises = require("fs/promises");
13035
+ var import_node_process2 = __toESM(require("process"), 1);
13036
+ var lockfile = __toESM(require("proper-lockfile"), 1);
13473
13037
 
13474
13038
  // src/caddy/constants.ts
13475
13039
  var import_node_os2 = __toESM(require("os"), 1);
@@ -13601,56 +13165,108 @@ var supportList = [
13601
13165
  ];
13602
13166
 
13603
13167
  // src/caddy/config.ts
13604
- function useCaddyConfig() {
13605
- const configContentRef = signal("{}");
13606
- const configJsonRef = computed(() => {
13607
- try {
13608
- return JSON.parse(configContentRef());
13609
- } catch {
13610
- return void 0;
13611
- }
13612
- });
13613
- function setConfigContent() {
13614
- if (!(0, import_node_fs.existsSync)(caddyConfigPath)) {
13615
- (0, import_node_fs.writeFileSync)(caddyConfigPath, "{}");
13616
- }
13617
- try {
13618
- configContentRef((0, import_node_fs.readFileSync)(caddyConfigPath, "utf-8"));
13619
- } catch {
13620
- configContentRef("");
13621
- }
13168
+ function isAlive(pid) {
13169
+ if (pid === void 0)
13170
+ return true;
13171
+ try {
13172
+ import_node_process2.default.kill(pid, 0);
13173
+ return true;
13174
+ } catch {
13175
+ return false;
13622
13176
  }
13623
- if (!(0, import_node_fs.existsSync)(caddyConfigPath)) {
13624
- (0, import_node_fs.writeFileSync)(caddyConfigPath, "{}");
13177
+ }
13178
+ function readConfig() {
13179
+ if (!(0, import_node_fs.existsSync)(caddyConfigPath))
13180
+ return {};
13181
+ let parsed2;
13182
+ try {
13183
+ parsed2 = JSON.parse((0, import_node_fs.readFileSync)(caddyConfigPath, "utf-8"));
13184
+ } catch {
13185
+ return {};
13625
13186
  }
13626
- const watchCaddyConfig = (0, import_node_fs.watch)(caddyConfigPath, () => {
13627
- setConfigContent();
13628
- });
13629
- function writeCaddyConfig(_proxies) {
13630
- const proxies = configJsonRef() || {};
13631
- _proxies.forEach((p) => {
13632
- let base = p.base || "/";
13633
- if (!base.startsWith("/"))
13634
- base = `/${base}`;
13635
- if (base !== "/" && !base.endsWith("/"))
13636
- base = `${base}/`;
13637
- const index = `${p.target}${p.portSuffix}${base}`;
13638
- proxies[index] = { ...p, base };
13639
- });
13640
- const content = JSON.stringify(proxies, null, 2);
13641
- configContentRef(content);
13642
- return (0, import_node_fs.writeFileSync)(caddyConfigPath, content);
13187
+ const alive = {};
13188
+ for (const [key, entry] of Object.entries(parsed2)) {
13189
+ if (isAlive(entry == null ? void 0 : entry.ownerPid))
13190
+ alive[key] = entry;
13643
13191
  }
13644
- async function cleanUp() {
13645
- await (0, import_promises.unlink)(caddyConfigPath).catch(() => {
13646
- });
13647
- configContentRef("{}");
13648
- watchCaddyConfig.close();
13192
+ return alive;
13193
+ }
13194
+ function writeConfig(proxies) {
13195
+ const content = JSON.stringify(proxies, null, 2);
13196
+ const temp = `${caddyConfigPath}.${import_node_process2.default.pid}.tmp`;
13197
+ (0, import_node_fs.writeFileSync)(temp, content);
13198
+ (0, import_node_fs.renameSync)(temp, caddyConfigPath);
13199
+ }
13200
+ async function mutateConfig(lock3, mutate) {
13201
+ const release = await lock3.acquire();
13202
+ try {
13203
+ const proxies = readConfig();
13204
+ mutate(proxies);
13205
+ writeConfig(proxies);
13206
+ return proxies;
13207
+ } finally {
13208
+ release();
13209
+ }
13210
+ }
13211
+ function useCaddyConfig(options = {}) {
13212
+ const lock3 = options.lock ?? createFileLock();
13213
+ return {
13214
+ configJsonRef: () => (0, import_node_fs.existsSync)(caddyConfigPath) ? readConfig() : void 0,
13215
+ async writeCaddyConfig(_proxies, key) {
13216
+ await mutateConfig(lock3, (proxies) => {
13217
+ for (const p of _proxies)
13218
+ proxies[routeKey(p, key)] = { ...p, base: normalizeBase(p.base), ownerPid: import_node_process2.default.pid };
13219
+ });
13220
+ },
13221
+ async removeProxy(key) {
13222
+ const proxies = await mutateConfig(lock3, (current) => {
13223
+ for (const route of Object.keys(current)) {
13224
+ if (route.endsWith(`#${key}`))
13225
+ delete current[route];
13226
+ }
13227
+ });
13228
+ if (Object.keys(proxies).length === 0)
13229
+ removeConfigFile();
13230
+ },
13231
+ readProxies: () => readConfig(),
13232
+ async cleanUp() {
13233
+ removeConfigFile();
13234
+ }
13235
+ };
13236
+ }
13237
+ function removeConfigFile() {
13238
+ try {
13239
+ if ((0, import_node_fs.existsSync)(caddyConfigPath))
13240
+ (0, import_node_fs.unlinkSync)(caddyConfigPath);
13241
+ } catch {
13649
13242
  }
13243
+ }
13244
+ function normalizeBase(base) {
13245
+ let out = base || "/";
13246
+ if (!out.startsWith("/"))
13247
+ out = `/${out}`;
13248
+ if (out !== "/" && !out.endsWith("/"))
13249
+ out = `${out}/`;
13250
+ return out;
13251
+ }
13252
+ function routeKey(proxy, ownerKey) {
13253
+ return `${proxy.target}${proxy.portSuffix}${normalizeBase(proxy.base)}#${ownerKey}`;
13254
+ }
13255
+ function createFileLock() {
13650
13256
  return {
13651
- configJsonRef,
13652
- writeCaddyConfig,
13653
- cleanUp
13257
+ async acquire() {
13258
+ if (!(0, import_node_fs.existsSync)(caddyConfigPath))
13259
+ (0, import_node_fs.writeFileSync)(caddyConfigPath, "{}");
13260
+ const release = await lockfile.lock(caddyConfigPath, {
13261
+ realpath: false,
13262
+ stale: 1e4,
13263
+ retries: { retries: 20, minTimeout: 10, maxTimeout: 100 }
13264
+ });
13265
+ return () => {
13266
+ void release().catch(() => {
13267
+ });
13268
+ };
13269
+ }
13654
13270
  };
13655
13271
  }
13656
13272
 
@@ -13668,43 +13284,56 @@ function isCaddyReloadCancellation(line) {
13668
13284
  var import_node_buffer2 = require("buffer");
13669
13285
  var import_node_events = require("events");
13670
13286
  var import_node_path4 = require("path");
13671
- var import_node_process6 = __toESM(require("process"), 1);
13287
+ var import_node_process7 = __toESM(require("process"), 1);
13672
13288
  var import_node_url = require("url");
13673
13289
 
13674
13290
  // src/privileged/entry.ts
13675
13291
  var import_node_fs2 = require("fs");
13676
13292
  var import_node_path2 = require("path");
13677
- var import_node_process2 = __toESM(require("process"), 1);
13293
+ var import_node_process3 = __toESM(require("process"), 1);
13678
13294
  function resolveHelperEntry(options) {
13679
- const { moduleDir, nodeBin = import_node_process2.default.execPath, exists: exists2 = import_node_fs2.existsSync } = options;
13295
+ const { moduleDir, nodeBin = import_node_process3.default.execPath, exists: exists2 = import_node_fs2.existsSync } = options;
13680
13296
  for (const name of ["privileged-helper.js", "privileged-helper.cjs", "privileged-helper.mjs"]) {
13681
- const candidate = (0, import_node_path2.join)(moduleDir, name);
13682
- if (exists2(candidate))
13297
+ const candidate = findUp(moduleDir, name, exists2);
13298
+ if (candidate)
13683
13299
  return { entry: nodeBin, args: [candidate] };
13684
13300
  }
13685
- const source = (0, import_node_path2.join)(moduleDir, "privileged-helper.ts");
13686
- const tsxCli = (0, import_node_path2.join)(moduleDir, "../node_modules/tsx/dist/cli.mjs");
13687
- if (exists2(source) && exists2(tsxCli))
13301
+ const source = findUp(moduleDir, "privileged-helper.ts", exists2);
13302
+ const tsxCli = findUp(moduleDir, "node_modules/tsx/dist/cli.mjs", exists2);
13303
+ if (source && tsxCli)
13688
13304
  return { entry: nodeBin, args: [tsxCli, source] };
13689
13305
  throw new Error(`privileged helper entry not found in ${moduleDir}. Build the package first.`);
13690
13306
  }
13307
+ function findUp(from, relative, exists2) {
13308
+ let current = from;
13309
+ while (true) {
13310
+ const candidate = (0, import_node_path2.join)(current, relative);
13311
+ if (exists2(candidate))
13312
+ return candidate;
13313
+ const parent = (0, import_node_path2.dirname)(current);
13314
+ if (parent === current)
13315
+ return void 0;
13316
+ current = parent;
13317
+ }
13318
+ }
13691
13319
 
13692
13320
  // src/privileged/session.ts
13693
13321
  var import_node_buffer = require("buffer");
13694
13322
  var import_node_fs3 = require("fs");
13695
- var import_promises2 = require("fs/promises");
13323
+ var import_promises = require("fs/promises");
13696
13324
  var import_node_os4 = require("os");
13697
13325
  var import_node_path3 = require("path");
13326
+ var lockfile2 = __toESM(require("proper-lockfile"), 1);
13698
13327
 
13699
13328
  // src/privileged/launch.ts
13700
13329
  var import_node_child_process2 = require("child_process");
13701
13330
  var import_node_crypto = require("crypto");
13702
13331
  var import_node_os3 = require("os");
13703
- var import_node_process5 = __toESM(require("process"), 1);
13332
+ var import_node_process6 = __toESM(require("process"), 1);
13704
13333
 
13705
13334
  // src/privileged/client.ts
13706
13335
  var import_node_net = require("net");
13707
- var import_node_process3 = __toESM(require("process"), 1);
13336
+ var import_node_process4 = __toESM(require("process"), 1);
13708
13337
 
13709
13338
  // src/privileged/protocol.ts
13710
13339
  function serializeMessage(message) {
@@ -13767,7 +13396,7 @@ var FORWARDED_ENV_KEYS = [
13767
13396
  "NO_PROXY",
13768
13397
  "no_proxy"
13769
13398
  ];
13770
- function collectForwardedEnv(source = import_node_process3.default.env) {
13399
+ function collectForwardedEnv(source = import_node_process4.default.env) {
13771
13400
  const result = {};
13772
13401
  for (const key of FORWARDED_ENV_KEYS) {
13773
13402
  const value2 = source[key];
@@ -13944,7 +13573,7 @@ function createClient(socket, initialBuffer, callTimeoutMs) {
13944
13573
 
13945
13574
  // src/privileged/windows-elevation.ts
13946
13575
  var import_node_child_process = require("child_process");
13947
- var import_node_process4 = __toESM(require("process"), 1);
13576
+ var import_node_process5 = __toESM(require("process"), 1);
13948
13577
  function quotePowerShell(value2) {
13949
13578
  return `'${value2.replace(/'/g, "''")}'`;
13950
13579
  }
@@ -13986,18 +13615,42 @@ function spawnElevatedOnWindows(options) {
13986
13615
  function createHelperToken() {
13987
13616
  return (0, import_node_crypto.randomBytes)(24).toString("hex");
13988
13617
  }
13989
- function authenticateSudo(sudoCommand = "sudo") {
13618
+ function describePasswordReason(target, https) {
13619
+ const port = https ? "443" : "80";
13620
+ return [
13621
+ `reverse proxy needs administrator permission for ${target}`,
13622
+ ` \xB7 bind port ${port}${https ? ` for https://${target}` : ""}`,
13623
+ ` \xB7 add ${target} to the hosts file`,
13624
+ "",
13625
+ "This is the only prompt; the rest of the dev server keeps running as you.",
13626
+ "Press Ctrl+C at the prompt to skip the proxy and keep the dev server."
13627
+ ];
13628
+ }
13629
+ function authenticateSudo(sudoCommand = "sudo", options = {}) {
13990
13630
  if ((0, import_node_os3.platform)() === "win32")
13991
13631
  return { ok: true };
13992
13632
  if ((0, import_node_child_process2.spawnSync)(sudoCommand, ["-n", "true"], { stdio: "ignore" }).status === 0)
13993
13633
  return { ok: true };
13634
+ if (options.target) {
13635
+ for (const line of describePasswordReason(options.target, options.https ?? false))
13636
+ import_node_process6.default.stderr.write(`${line}
13637
+ `);
13638
+ import_node_process6.default.stderr.write("\n");
13639
+ }
13994
13640
  if ((0, import_node_child_process2.spawnSync)(sudoCommand, ["-v"], { stdio: "inherit" }).status === 0)
13995
13641
  return { ok: true };
13996
13642
  return {
13997
13643
  ok: false,
13644
+ denied: true,
13998
13645
  message: "administrator permission is required to edit the hosts file and bind ports 80/443"
13999
13646
  };
14000
13647
  }
13648
+ var PrivilegeDeniedError = class extends Error {
13649
+ constructor(message) {
13650
+ super(message);
13651
+ this.name = "PrivilegeDeniedError";
13652
+ }
13653
+ };
14001
13654
  async function startPrivilegedHelper(options) {
14002
13655
  var _a4, _b3;
14003
13656
  const {
@@ -14008,14 +13661,16 @@ async function startPrivilegedHelper(options) {
14008
13661
  sudoCommand = "sudo",
14009
13662
  skipAuth = false,
14010
13663
  direct = false,
14011
- env: env2 = import_node_process5.default.env,
13664
+ env: env2 = import_node_process6.default.env,
14012
13665
  log,
14013
13666
  connectTimeoutMs = 12e4
14014
13667
  } = options;
14015
13668
  if (!skipAuth && !direct) {
14016
- const auth = authenticateSudo(sudoCommand);
14017
- if (!auth.ok)
14018
- throw new Error(auth.message);
13669
+ const auth = authenticateSudo(sudoCommand, options.reason);
13670
+ if (!auth.ok) {
13671
+ const message = auth.message ?? "administrator permission is required";
13672
+ throw auth.denied ? new PrivilegeDeniedError(message) : new Error(message);
13673
+ }
14019
13674
  }
14020
13675
  const forwarded = collectForwardedEnv(env2);
14021
13676
  const forwardedArgs = Object.entries(forwarded).map(([key, value2]) => `${key}=${value2}`);
@@ -14025,8 +13680,8 @@ async function startPrivilegedHelper(options) {
14025
13680
  socketPath,
14026
13681
  "--token",
14027
13682
  token,
14028
- ...typeof import_node_process5.default.getuid === "function" ? ["--owner-uid", String(import_node_process5.default.getuid())] : [],
14029
- ...typeof import_node_process5.default.getgid === "function" ? ["--owner-gid", String(import_node_process5.default.getgid())] : [],
13683
+ ...typeof import_node_process6.default.getuid === "function" ? ["--owner-uid", String(import_node_process6.default.getuid())] : [],
13684
+ ...typeof import_node_process6.default.getgid === "function" ? ["--owner-gid", String(import_node_process6.default.getgid())] : [],
14030
13685
  ...options.caddyStoragePath ? ["--caddy-storage", options.caddyStoragePath] : [],
14031
13686
  "--caddy",
14032
13687
  options.caddyBin,
@@ -14035,7 +13690,7 @@ async function startPrivilegedHelper(options) {
14035
13690
  ];
14036
13691
  let child;
14037
13692
  if (!direct && (0, import_node_os3.platform)() === "win32") {
14038
- await spawnElevatedOnWindows({ file: helperEntry, args: childArgv, cwd: import_node_process5.default.cwd() });
13693
+ await spawnElevatedOnWindows({ file: helperEntry, args: childArgv, cwd: import_node_process6.default.cwd() });
14039
13694
  } else {
14040
13695
  const command = direct ? helperEntry : sudoCommand;
14041
13696
  const spawnArgs = direct ? childArgv : ["-n", "env", ...forwardedArgs, helperEntry, ...childArgv];
@@ -14092,21 +13747,34 @@ function sessionSocketPath(runtimeDir) {
14092
13747
  }
14093
13748
  async function openHelperSession(scope2) {
14094
13749
  const socketPath = sessionSocketPath(scope2.runtimeDir);
14095
- if ((0, import_node_fs3.existsSync)(socketPath) || (0, import_node_os4.platform)() === "win32") {
14096
- const token2 = await readToken(scope2.runtimeDir);
14097
- if (token2) {
14098
- const reused = await connectExistingHelper(socketPath, token2);
14099
- if (reused) {
14100
- return {
14101
- client: reused,
14102
- reused: true,
14103
- close: async () => {
14104
- await reused.close();
14105
- }
14106
- };
14107
- }
14108
- }
13750
+ const release = await acquireStartLock(scope2.runtimeDir);
13751
+ try {
13752
+ const reused = await tryReuse(socketPath, scope2);
13753
+ if (reused)
13754
+ return reused;
13755
+ return await startNew(socketPath, scope2);
13756
+ } finally {
13757
+ release();
14109
13758
  }
13759
+ }
13760
+ async function tryReuse(socketPath, scope2) {
13761
+ if (!(0, import_node_fs3.existsSync)(socketPath) && (0, import_node_os4.platform)() !== "win32")
13762
+ return void 0;
13763
+ const token = await readToken(scope2.runtimeDir);
13764
+ if (!token)
13765
+ return void 0;
13766
+ const reused = await connectExistingHelper(socketPath, token);
13767
+ if (!reused)
13768
+ return void 0;
13769
+ return {
13770
+ client: reused,
13771
+ reused: true,
13772
+ close: async () => {
13773
+ await reused.close();
13774
+ }
13775
+ };
13776
+ }
13777
+ async function startNew(socketPath, scope2) {
14110
13778
  const token = createHelperToken();
14111
13779
  const started = await startPrivilegedHelper({
14112
13780
  socketPath,
@@ -14120,6 +13788,7 @@ async function openHelperSession(scope2) {
14120
13788
  caddyStoragePath: scope2.caddyStoragePath,
14121
13789
  caddyBin: scope2.caddyBin,
14122
13790
  caddyConfigPath: scope2.caddyConfigPath,
13791
+ reason: scope2.reason,
14123
13792
  log: scope2.log
14124
13793
  });
14125
13794
  await writeToken(scope2.runtimeDir, token);
@@ -14131,9 +13800,25 @@ async function openHelperSession(scope2) {
14131
13800
  }
14132
13801
  };
14133
13802
  }
13803
+ async function acquireStartLock(runtimeDir) {
13804
+ const lockPath = (0, import_node_path3.join)(runtimeDir, "helper.start.lock");
13805
+ try {
13806
+ await (0, import_promises.writeFile)(lockPath, "", { flag: "a" });
13807
+ } catch {
13808
+ }
13809
+ const release = await lockfile2.lock(lockPath, {
13810
+ realpath: false,
13811
+ stale: 3e4,
13812
+ retries: { retries: 100, minTimeout: 50, maxTimeout: 200 }
13813
+ });
13814
+ return () => {
13815
+ void release().catch(() => {
13816
+ });
13817
+ };
13818
+ }
14134
13819
  async function readToken(runtimeDir) {
14135
13820
  try {
14136
- const content = await (0, import_promises2.readFile)(tokenPath(runtimeDir), "utf8");
13821
+ const content = await (0, import_promises.readFile)(tokenPath(runtimeDir), "utf8");
14137
13822
  const token = content.trim();
14138
13823
  return token === "" ? void 0 : token;
14139
13824
  } catch {
@@ -14142,7 +13827,7 @@ async function readToken(runtimeDir) {
14142
13827
  }
14143
13828
  async function writeToken(runtimeDir, token) {
14144
13829
  try {
14145
- await (0, import_promises2.writeFile)(tokenPath(runtimeDir), token, { mode: 384 });
13830
+ await (0, import_promises.writeFile)(tokenPath(runtimeDir), token, { mode: 384 });
14146
13831
  } catch {
14147
13832
  }
14148
13833
  }
@@ -14190,7 +13875,7 @@ var HelperCaddyProcess = class extends import_node_events.EventEmitter {
14190
13875
  }
14191
13876
  };
14192
13877
  function caddyStoragePath() {
14193
- return import_node_process6.default.platform === "win32" ? (0, import_node_path4.join)(import_node_process6.default.env.AppData ?? "", "Caddy") : (0, import_node_path4.join)(import_node_process6.default.env.HOME ?? "", "Library/Application Support/Caddy");
13878
+ 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");
14194
13879
  }
14195
13880
  function openPrivilegedSession(runtimeDir, options) {
14196
13881
  const env2 = resolvePrivilegedEnv();
@@ -14206,6 +13891,7 @@ function openPrivilegedSession(runtimeDir, options) {
14206
13891
  // execute a path supplied over the socket.
14207
13892
  caddyBin: options.caddyBin,
14208
13893
  caddyConfigPath: options.caddyConfigPath,
13894
+ reason: options.reason,
14209
13895
  log: options.log
14210
13896
  });
14211
13897
  }
@@ -14339,15 +14025,15 @@ async function download() {
14339
14025
  const file = (0, import_node_fs4.createWriteStream)(caddyPath);
14340
14026
  let _platform = (0, import_node_os5.platform)().toString();
14341
14027
  _platform === "win32" && (_platform = "windows");
14342
- let _arch = import_node_process7.default.arch.toString();
14028
+ let _arch = import_node_process8.default.arch.toString();
14343
14029
  _arch === "x64" && (_arch = "amd64");
14344
14030
  const support = supportList.find((item) => item.platform === _platform && item.arch === _arch);
14345
14031
  if (!support)
14346
14032
  return reject2(new Error("not support"));
14347
14033
  const dowmloadLink = `https://caddyserver.com/api/download?os=${support.platform}&arch=${support.arch}&p=github.com%2Fcaddyserver%2Fforwardproxy`;
14348
14034
  (0, import_node_fs4.existsSync)(caddyPath) && (0, import_node_fs4.unlinkSync)(caddyPath);
14349
- const httpProxy = import_node_process7.default.env.HTTP_PROXY || import_node_process7.default.env.http_proxy;
14350
- const httpsProxy = import_node_process7.default.env.HTTPS_PROXY || import_node_process7.default.env.https_proxy;
14035
+ const httpProxy = import_node_process8.default.env.HTTP_PROXY || import_node_process8.default.env.http_proxy;
14036
+ const httpsProxy = import_node_process8.default.env.HTTPS_PROXY || import_node_process8.default.env.https_proxy;
14351
14037
  const httpAgent = httpProxy ? new import_http_proxy_agent.HttpProxyAgent(httpProxy) : void 0;
14352
14038
  const httpsAgent = httpsProxy ? new import_https_proxy_agent.HttpsProxyAgent(httpsProxy) : void 0;
14353
14039
  const chmodCaddyOnce = once(() => {
@@ -14363,7 +14049,7 @@ async function download() {
14363
14049
  chmodCaddyOnce();
14364
14050
  }).pipe(file).on("finish", () => {
14365
14051
  logProgressOver();
14366
- if (import_node_process7.default.platform === "win32")
14052
+ if (import_node_process8.default.platform === "win32")
14367
14053
  return resolve2(caddyPath);
14368
14054
  (0, import_node_fs4.chmodSync)(caddyPath, 493);
14369
14055
  resolve2(caddyPath);
@@ -14406,43 +14092,35 @@ function splitHostPort(addr) {
14406
14092
  return { host: addr.slice(0, lastColon), port: addr.slice(lastColon + 1) };
14407
14093
  }
14408
14094
  var defaultDependencies = {
14409
- openSession: (runtimeDir) => openPrivilegedSession(runtimeDir, {
14095
+ openSession: (runtimeDir, reason) => openPrivilegedSession(runtimeDir, {
14410
14096
  log: (message) => consola.debug(message),
14411
14097
  // Both paths are fixed here, before any socket traffic: the privileged
14412
14098
  // helper must never execute something named in a request.
14413
14099
  caddyBin: caddyPath,
14414
- caddyConfigPath: caddyFilePath
14415
- })
14100
+ caddyConfigPath: caddyFilePath,
14101
+ reason
14102
+ }),
14103
+ config: () => getCaddyConfig()
14416
14104
  };
14417
14105
  var CaddyInstant = class {
14418
14106
  constructor(deps = {}) {
14419
14107
  this.inited = false;
14420
14108
  this.stoped = false;
14421
- /** has locked when start */
14422
- this.locked = false;
14423
14109
  this._stopEffects = [];
14110
+ /** Identifies this instance's routes in the shared config. */
14111
+ this.proxyKey = `${import_node_process8.default.pid}-${Math.random().toString(36).slice(2, 8)}`;
14424
14112
  this.deps = { ...defaultDependencies, ...deps };
14425
- this.locked = this.checkLock();
14426
- }
14427
- checkLock() {
14428
- if (!(0, import_node_fs4.existsSync)(caddyLockFilePath))
14429
- (0, import_node_fs4.writeFileSync)(caddyLockFilePath, "");
14430
- try {
14431
- return lockfile.checkSync(caddyLockFilePath);
14432
- } catch {
14433
- return false;
14434
- }
14435
14113
  }
14436
14114
  /**
14437
14115
  * Connects to the privileged helper, starting it once if needed. It is
14438
14116
  * reused across instances so a second dev server does not ask for a
14439
14117
  * password again.
14440
14118
  */
14441
- async session() {
14119
+ async session(reason) {
14442
14120
  if (this._session && !this._session.client.connected)
14443
14121
  this._session = void 0;
14444
14122
  if (!this._session)
14445
- this._session = await this.deps.openSession(TEMP_DIR);
14123
+ this._session = await this.deps.openSession(TEMP_DIR, reason);
14446
14124
  return this._session;
14447
14125
  }
14448
14126
  async getCaddyfile() {
@@ -14450,20 +14128,20 @@ var CaddyInstant = class {
14450
14128
  this.caddyfile = "";
14451
14129
  return "";
14452
14130
  }
14453
- this.caddyfile = await (0, import_promises3.readFile)(caddyFilePath, "utf-8");
14131
+ this.caddyfile = await (0, import_promises2.readFile)(caddyFilePath, "utf-8");
14454
14132
  return this.caddyfile;
14455
14133
  }
14456
14134
  get caddyRoot() {
14457
14135
  return (0, import_node_path5.join)(
14458
- import_node_process7.default.platform === "win32" ? `${import_node_process7.default.env.AppData}/Caddy` : `${import_node_process7.default.env.HOME}/Library/Application Support/Caddy`,
14136
+ import_node_process8.default.platform === "win32" ? `${import_node_process8.default.env.AppData}/Caddy` : `${import_node_process8.default.env.HOME}/Library/Application Support/Caddy`,
14459
14137
  "./pki/authorities/local"
14460
14138
  );
14461
14139
  }
14462
14140
  async writeCaddyfile() {
14463
- return await (0, import_promises3.writeFile)(caddyFilePath, this.caddyfile || "");
14141
+ return await (0, import_promises2.writeFile)(caddyFilePath, this.caddyfile || "");
14464
14142
  }
14465
14143
  async deleteCaddyfile() {
14466
- return await (0, import_promises3.unlink)(caddyFilePath);
14144
+ return await (0, import_promises2.unlink)(caddyFilePath);
14467
14145
  }
14468
14146
  async init() {
14469
14147
  await download();
@@ -14501,9 +14179,15 @@ Run \`${caddyPath} trust\` manually if the browser warns about the certificate.`
14501
14179
  if (!health.healthy)
14502
14180
  throw new Error(formatTlsHealthFailure(targetHost, health));
14503
14181
  }
14182
+ /**
14183
+ * Regenerates the Caddyfile from the config on disk.
14184
+ *
14185
+ * Reading the file rather than a cached view matters here: another project
14186
+ * may have added its route since this instance last looked.
14187
+ */
14504
14188
  async updateCaddyfile() {
14505
- const { configJsonRef } = getCaddyConfig();
14506
- const proxies = Object.values(configJsonRef() || {});
14189
+ const { readProxies } = this.deps.config();
14190
+ const proxies = Object.values(readProxies());
14507
14191
  const ctx = validateTemplateContext({
14508
14192
  caddy_root: this.caddyRoot,
14509
14193
  proxies
@@ -14547,12 +14231,12 @@ Run \`${caddyPath} trust\` manually if the browser warns about the certificate.`
14547
14231
  this._target = target;
14548
14232
  if (!this.inited)
14549
14233
  await this.init();
14550
- const session = await this.session();
14551
14234
  const sourceHost = splitHostPort(source).host;
14552
14235
  const targetHost = splitHostPort(target).host;
14236
+ const session = await this.session({ target: targetHost, https });
14553
14237
  await session.client.call("hosts.add", { ip: sourceHost, host: targetHost });
14554
14238
  consola.success("update host success\n");
14555
- const normalizeBase = (b) => {
14239
+ const normalizeBase2 = (b) => {
14556
14240
  let out = b || "/";
14557
14241
  if (!out.startsWith("/"))
14558
14242
  out = `/${out}`;
@@ -14560,7 +14244,7 @@ Run \`${caddyPath} trust\` manually if the browser warns about the certificate.`
14560
14244
  out = `${out}/`;
14561
14245
  return out;
14562
14246
  };
14563
- const baseNormalized = normalizeBase(base);
14247
+ const baseNormalized = normalizeBase2(base);
14564
14248
  const proxies = [
14565
14249
  {
14566
14250
  target: targetHost,
@@ -14571,27 +14255,12 @@ Run \`${caddyPath} trust\` manually if the browser warns about the certificate.`
14571
14255
  healthCheck
14572
14256
  }
14573
14257
  ];
14574
- const { writeCaddyConfig } = getCaddyConfig();
14575
- writeCaddyConfig(proxies);
14258
+ const { writeCaddyConfig } = this.deps.config();
14259
+ await writeCaddyConfig(proxies, this.proxyKey);
14576
14260
  await this.updateCaddyfile();
14577
- let skipInitialCaddyfileEffect = true;
14578
- this._stopEffects.push(
14579
- effect(() => {
14580
- getCaddyConfig().configJsonRef();
14581
- if (skipInitialCaddyfileEffect) {
14582
- skipInitialCaddyfileEffect = false;
14583
- return;
14584
- }
14585
- void this.updateCaddyfile();
14586
- })
14587
- );
14588
- if (!(0, import_node_fs4.existsSync)(caddyLockFilePath))
14589
- (0, import_node_fs4.writeFileSync)(caddyLockFilePath, "");
14590
- if (!this.locked) {
14591
- await session.client.call("port.free", { port: 443 });
14592
- if (import_node_process7.default.platform === "win32" || !https)
14593
- await session.client.call("port.free", { port: 80 });
14594
- }
14261
+ await session.client.call("port.free", { port: 443 });
14262
+ if (import_node_process8.default.platform === "win32" || !https)
14263
+ await session.client.call("port.free", { port: 80 });
14595
14264
  return new Promise((resolve2, reject2) => {
14596
14265
  let startupCheckStarted = false;
14597
14266
  const resolveWhenReady = async () => {
@@ -14605,106 +14274,89 @@ Run \`${caddyPath} trust\` manually if the browser warns about the certificate.`
14605
14274
  }
14606
14275
  resolve2();
14607
14276
  } catch (error) {
14608
- if (!this.locked)
14609
- await this.baseCleanup(restore);
14277
+ await this.baseCleanup(restore);
14610
14278
  reject2(error);
14611
14279
  }
14612
14280
  };
14613
14281
  const setupCleanup = () => {
14614
- import_node_process7.default.on("SIGINT", async () => {
14282
+ import_node_process8.default.on("SIGINT", async () => {
14615
14283
  if (this.stoped)
14616
14284
  return;
14617
- import_node_process7.default.stdin.resume();
14285
+ import_node_process8.default.stdin.resume();
14618
14286
  try {
14619
14287
  await this.baseCleanup(restore);
14620
14288
  } finally {
14621
14289
  this.stoped = true;
14622
- import_node_process7.default.nextTick(() => {
14623
- import_node_process7.default.exit();
14290
+ import_node_process8.default.nextTick(() => {
14291
+ import_node_process8.default.exit();
14624
14292
  });
14625
14293
  }
14626
14294
  });
14627
- const originalExit = import_node_process7.default.exit.bind(import_node_process7.default);
14628
- import_node_process7.default.exit = async (code) => {
14295
+ const originalExit = import_node_process8.default.exit.bind(import_node_process8.default);
14296
+ import_node_process8.default.exit = async (code) => {
14629
14297
  if (this.stoped)
14630
14298
  return originalExit(code);
14631
- import_node_process7.default.stdin.resume();
14299
+ import_node_process8.default.stdin.resume();
14632
14300
  try {
14633
14301
  await this.baseCleanup();
14634
14302
  } finally {
14635
14303
  this.stoped = true;
14636
- import_node_process7.default.nextTick(() => {
14304
+ import_node_process8.default.nextTick(() => {
14637
14305
  originalExit(code);
14638
14306
  });
14639
14307
  }
14640
14308
  };
14641
14309
  };
14642
- if (!this.locked) {
14643
- lockfile.lockSync(caddyLockFilePath);
14644
- setupCleanup();
14645
- void (async () => {
14646
- try {
14647
- const child = new HelperCaddyProcess(session.client);
14648
- this._caddyChild = child;
14649
- await session.client.call("caddy.start");
14650
- child.on("exit", (code) => {
14651
- if (code !== null && code !== 0)
14652
- reject2(new Error(`Caddy exited with code ${code}`));
14653
- });
14654
- child.stderr.on("data", async (data) => {
14655
- const lines = data.toString().split("\n").map((line) => line.trim());
14656
- for (const line of lines) {
14657
- showCaddyLog && line && console.info(line);
14658
- if (isCaddyReloadCancellation(line)) {
14659
- consola.info("Caddy restarted before TLS issuance completed; retrying.\n");
14660
- continue;
14661
- }
14662
- try {
14663
- if (line.includes("Error:") || line && JSON.parse(line).level === "error") {
14664
- if (line.includes("parsing caddyfile tokens")) {
14665
- consola.error("Caddyfile syntax error, please contact the author:\n", `${this.caddyfile}
14310
+ setupCleanup();
14311
+ void (async () => {
14312
+ try {
14313
+ const child = new HelperCaddyProcess(session.client);
14314
+ this._caddyChild = child;
14315
+ await session.client.call("caddy.start");
14316
+ child.on("exit", (code) => {
14317
+ if (code !== null && code !== 0)
14318
+ reject2(new Error(`Caddy exited with code ${code}`));
14319
+ });
14320
+ child.stderr.on("data", async (data) => {
14321
+ const lines = data.toString().split("\n").map((line) => line.trim());
14322
+ for (const line of lines) {
14323
+ showCaddyLog && line && console.info(line);
14324
+ if (isCaddyReloadCancellation(line)) {
14325
+ consola.info("Caddy restarted before TLS issuance completed; retrying.\n");
14326
+ continue;
14327
+ }
14328
+ try {
14329
+ if (line.includes("Error:") || line && JSON.parse(line).level === "error") {
14330
+ if (line.includes("parsing caddyfile tokens")) {
14331
+ consola.error("Caddyfile syntax error, please contact the author:\n", `${this.caddyfile}
14666
14332
 
14667
14333
  ${line}
14668
14334
  `);
14669
- await this.baseCleanup();
14670
- import_node_process7.default.exit();
14671
- } else {
14672
- consola.error(`${line}
14335
+ await this.baseCleanup();
14336
+ import_node_process8.default.exit();
14337
+ } else {
14338
+ consola.error(`${line}
14673
14339
  `);
14674
- return reject2(line);
14675
- }
14340
+ return reject2(line);
14676
14341
  }
14677
- } catch {
14678
14342
  }
14679
- if (line.includes("config file changed"))
14680
- consola.success("Detect added a new reverse proxy config, restarted.\n");
14681
- if (line.includes("caddy proxying") || line.includes("serving initial"))
14682
- void resolveWhenReady();
14343
+ } catch {
14683
14344
  }
14684
- });
14685
- child.stdout.on("data", (data) => {
14686
- consola.info(data.toString());
14687
- void resolveWhenReady();
14688
- });
14689
- } catch (error) {
14690
- if (!this.locked)
14691
- await this.baseCleanup(restore);
14692
- reject2(error);
14693
- }
14694
- })();
14695
- } else {
14696
- consola.info("Caddy is running in another process.");
14697
- void (async () => {
14698
- try {
14699
- if (https)
14700
- await this.ensureTlsReady(targetHost);
14701
- setupCleanup();
14702
- resolve2();
14703
- } catch (error) {
14704
- reject2(error);
14705
- }
14706
- })();
14707
- }
14345
+ if (line.includes("config file changed"))
14346
+ consola.success("Detect added a new reverse proxy config, restarted.\n");
14347
+ if (line.includes("caddy proxying") || line.includes("serving initial"))
14348
+ void resolveWhenReady();
14349
+ }
14350
+ });
14351
+ child.stdout.on("data", (data) => {
14352
+ consola.info(data.toString());
14353
+ void resolveWhenReady();
14354
+ });
14355
+ } catch (error) {
14356
+ await this.baseCleanup(restore);
14357
+ reject2(error);
14358
+ }
14359
+ })();
14708
14360
  });
14709
14361
  }
14710
14362
  async baseCleanup(restore = true) {
@@ -14728,18 +14380,9 @@ ${line}
14728
14380
  consola.fail("Restore host failed.\n");
14729
14381
  }
14730
14382
  }
14731
- if (!this.locked && !this.stoped) {
14732
- await this.stopCaddy();
14383
+ if (!this.stoped) {
14733
14384
  try {
14734
- await lockfile.unlock(caddyLockFilePath).catch(() => {
14735
- });
14736
- await (0, import_promises3.unlink)(caddyFilePath).catch(() => {
14737
- });
14738
- await (0, import_promises3.unlink)(caddyLockFilePath).catch(() => {
14739
- });
14740
- if (caddyConfig) {
14741
- await caddyConfig.cleanUp();
14742
- }
14385
+ await this.deps.config().removeProxy(this.proxyKey);
14743
14386
  } catch (e) {
14744
14387
  consola.error(e);
14745
14388
  }
@@ -14981,11 +14624,20 @@ var hmrSseBridgeClientScript = `
14981
14624
  })();
14982
14625
  `;
14983
14626
 
14627
+ // src/privilege-state.ts
14628
+ var denied = false;
14629
+ function markPrivilegeDenied() {
14630
+ denied = true;
14631
+ }
14632
+ function isPrivilegeDenied() {
14633
+ return denied;
14634
+ }
14635
+
14984
14636
  // src/index.ts
14985
14637
  var config;
14986
14638
  var caddy;
14987
14639
  var hmrSseBridgeActive = false;
14988
- var cwd = import_node_process8.default.cwd();
14640
+ var cwd = import_node_process9.default.cwd();
14989
14641
  function colorUrl(url2) {
14990
14642
  return import_picocolors2.default.green(url2.replace(/:(\d+)\//, (_, port) => `:${import_picocolors2.default.bold(port)}/`));
14991
14643
  }
@@ -15020,16 +14672,27 @@ async function printForwardProxy() {
15020
14672
  }
15021
14673
  var vitePrintUrls = once((options, source, target, base = "/", _printUrls) => {
15022
14674
  _printUrls == null ? void 0 : _printUrls();
14675
+ if (isPrivilegeDenied())
14676
+ return;
15023
14677
  if (caddy)
15024
14678
  return;
15025
- caddy = new CaddyInstant();
15026
- caddy.run(source, target, {
14679
+ const instance = new CaddyInstant();
14680
+ caddy = instance;
14681
+ instance.run(source, target, {
15027
14682
  base,
15028
14683
  ...options
15029
14684
  }).then(async () => {
15030
14685
  await printForwardProxy();
15031
14686
  consola.success(` ${import_picocolors2.default.green("\u279C")} ${import_picocolors2.default.bold("run caddy reverse proxy success")}: ${colorUrl(`${options.https ? "https" : "http"}://${target}${base}`)}`);
15032
14687
  }).catch((e) => {
14688
+ if (caddy === instance)
14689
+ caddy = void 0;
14690
+ if (e instanceof PrivilegeDeniedError) {
14691
+ markPrivilegeDenied();
14692
+ consola.warn("reverse proxy skipped: administrator permission was not granted.");
14693
+ consola.info("Restart the dev server to enable it again.");
14694
+ return;
14695
+ }
15033
14696
  throw e;
15034
14697
  });
15035
14698
  });
@@ -15085,7 +14748,7 @@ var unpluginFactory = (options) => ({
15085
14748
  },
15086
14749
  webpack(compiler) {
15087
14750
  var _a4, _b3, _c2;
15088
- if (import_node_process8.default.env.NODE_ENV !== "development")
14751
+ if (import_node_process9.default.env.NODE_ENV !== "development")
15089
14752
  return;
15090
14753
  const {
15091
14754
  enable = true,
@@ -15106,9 +14769,11 @@ var unpluginFactory = (options) => ({
15106
14769
  port: 8080,
15107
14770
  ...compiler.options.devServer,
15108
14771
  // @ts-expect-error vuecli
15109
- ...(_a4 = import_node_process8.default.VUE_CLI_SERVICE) == null ? void 0 : _a4.projectOptions.devServer
14772
+ ...(_a4 = import_node_process9.default.VUE_CLI_SERVICE) == null ? void 0 : _a4.projectOptions.devServer
15110
14773
  };
15111
14774
  const source = `${devServer.host}:${devServer.port}`;
14775
+ if (isPrivilegeDenied())
14776
+ return;
15112
14777
  if (caddy)
15113
14778
  return;
15114
14779
  let base = "/";
@@ -15123,15 +14788,16 @@ var unpluginFactory = (options) => ({
15123
14788
  const _close = (_c2 = compiler.close) == null ? void 0 : _c2.bind(compiler);
15124
14789
  if (_close) {
15125
14790
  compiler.close = async (callback) => {
15126
- import_node_process8.default.on("exit", () => {
14791
+ import_node_process9.default.on("exit", () => {
15127
14792
  _close && _close(callback);
15128
14793
  });
15129
14794
  };
15130
14795
  } else {
15131
14796
  options.https = false;
15132
14797
  }
15133
- caddy = new CaddyInstant();
15134
- caddy.run(source, target, {
14798
+ const instance = new CaddyInstant();
14799
+ caddy = instance;
14800
+ instance.run(source, target, {
15135
14801
  base,
15136
14802
  ...options
15137
14803
  }).then(() => {
@@ -15140,12 +14806,20 @@ var unpluginFactory = (options) => ({
15140
14806
  consola.success(` ${import_picocolors2.default.green("\u279C")} ${import_picocolors2.default.bold("run caddy reverse proxy success")}: ${colorUrl(`${options.https ? "https" : "http"}://${target}${base}`)}`);
15141
14807
  });
15142
14808
  }).catch((e) => {
14809
+ if (caddy === instance)
14810
+ caddy = void 0;
14811
+ if (e instanceof PrivilegeDeniedError) {
14812
+ markPrivilegeDenied();
14813
+ consola.warn("reverse proxy skipped: administrator permission was not granted.");
14814
+ consola.info("Restart the dev server to enable it again.");
14815
+ return;
14816
+ }
15143
14817
  throw e;
15144
14818
  });
15145
14819
  },
15146
14820
  async rspack(compiler) {
15147
14821
  var _a4, _b3, _c2, _d2;
15148
- if (import_node_process8.default.env.NODE_ENV !== "development")
14822
+ if (import_node_process9.default.env.NODE_ENV !== "development")
15149
14823
  return;
15150
14824
  const {
15151
14825
  enable = true,
@@ -15170,9 +14844,10 @@ var unpluginFactory = (options) => ({
15170
14844
  }))) == null ? void 0 : _b3.content) == null ? void 0 : _c2.server
15171
14845
  };
15172
14846
  const source = `${devServer.host}:${devServer.port}`;
14847
+ if (isPrivilegeDenied())
14848
+ return;
15173
14849
  if (caddy)
15174
14850
  return;
15175
- caddy = new CaddyInstant();
15176
14851
  let base = "/";
15177
14852
  const publicPath = (_d2 = compiler.options.output) == null ? void 0 : _d2.publicPath;
15178
14853
  if (typeof publicPath === "string" && publicPath) {
@@ -15182,13 +14857,23 @@ var unpluginFactory = (options) => ({
15182
14857
  base = `/${base}`;
15183
14858
  if (base !== "/" && !base.endsWith("/"))
15184
14859
  base = `${base}/`;
15185
- caddy.run(source, target, {
14860
+ const instance = new CaddyInstant();
14861
+ caddy = instance;
14862
+ instance.run(source, target, {
15186
14863
  base,
15187
14864
  ...options
15188
14865
  }).then(async () => {
15189
14866
  await printForwardProxy();
15190
14867
  consola.success(` ${import_picocolors2.default.green("\u279C")} ${import_picocolors2.default.bold("run caddy reverse proxy success")}: ${colorUrl(`${options.https ? "https" : "http"}://${target}${base}`)}`);
15191
14868
  }).catch((e) => {
14869
+ if (caddy === instance)
14870
+ caddy = void 0;
14871
+ if (e instanceof PrivilegeDeniedError) {
14872
+ markPrivilegeDenied();
14873
+ consola.warn("reverse proxy skipped: administrator permission was not granted.");
14874
+ consola.info("Restart the dev server to enable it again.");
14875
+ return;
14876
+ }
15192
14877
  throw e;
15193
14878
  });
15194
14879
  }