unplugin-https-reverse-proxy 1.0.0-beta.8 → 1.0.0

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.
@@ -1,36 +1,34 @@
1
1
  import {
2
- __spreadValues,
3
2
  chmodRecursive,
4
3
  consola,
5
4
  isAdmin,
6
5
  once
7
- } from "./chunk-RUJE3YFB.js";
6
+ } from "./chunk-2VGRJ3QS.js";
8
7
 
9
8
  // src/index.ts
10
- import process4 from "process";
9
+ import process4 from "node:process";
11
10
  import { createUnplugin } from "unplugin";
12
11
  import c from "picocolors";
13
12
 
14
13
  // src/caddy/index.ts
15
- import { platform } from "os";
16
- import process3 from "process";
17
- import { chmodSync as chmodSync2, createWriteStream, existsSync, mkdirSync, unlinkSync } from "fs";
18
- import { spawn } from "child_process";
14
+ import { platform } from "node:os";
15
+ import process3 from "node:process";
16
+ import { chmodSync as chmodSync2, createWriteStream, existsSync, mkdirSync, unlinkSync, writeFileSync } from "node:fs";
17
+ import { spawn } from "node:child_process";
18
+ import { readFile, unlink, writeFile } from "node:fs/promises";
19
19
  import { got } from "got-cjs";
20
20
  import { HttpProxyAgent } from "http-proxy-agent";
21
21
  import { HttpsProxyAgent } from "https-proxy-agent";
22
- import kill from "kill-port";
22
+ import * as lockfile from "proper-lockfile";
23
23
 
24
24
  // src/host/index.ts
25
- import process from "process";
26
- import { exec } from "child_process";
27
- import { chmodSync } from "fs";
28
- import _Hosts from "hosts-so-easy";
29
- var Hosts = _Hosts.default || _Hosts;
30
- var hostInstance = new Hosts({
31
- debounceTime: 50,
32
- hostsFile: getPathOfSystemHostsPath()
33
- });
25
+ import process from "node:process";
26
+ import { exec } from "node:child_process";
27
+ import { chmodSync } from "node:fs";
28
+ import { promisify } from "node:util";
29
+ import hostile from "hostile";
30
+ var _setHost = promisify(hostile.set);
31
+ var _removeHost = promisify(hostile.remove);
34
32
  function getPathOfSystemHostsPath() {
35
33
  return process.platform === "win32" ? `${process.env.windir || "C:\\WINDOWS"}\\system32\\drivers\\etc\\hosts` : "/etc/hosts";
36
34
  }
@@ -51,27 +49,25 @@ async function syncHost() {
51
49
  async function addHost(ip, host) {
52
50
  if (process.platform !== "win32")
53
51
  chmodSync(getPathOfSystemHostsPath(), 511);
54
- hostInstance.add("127.0.0.1", "localhost");
55
- hostInstance.add(ip, host);
52
+ await _setHost("127.0.0.1", "localhost");
53
+ await _setHost(ip, host);
56
54
  if (ip === "localhost")
57
- hostInstance.add("127.0.0.1", host);
58
- await hostInstance.updateFinish();
55
+ await _setHost("127.0.0.1", host);
59
56
  return await syncHost();
60
57
  }
61
58
  async function removeHost(ip, host) {
62
59
  if (process.platform !== "win32")
63
60
  chmodSync(getPathOfSystemHostsPath(), 511);
64
- hostInstance.remove(ip, host);
61
+ await _removeHost(ip, host);
65
62
  if (ip === "localhost")
66
- hostInstance.remove("127.0.0.1", host);
67
- await hostInstance.updateFinish();
63
+ await _removeHost("127.0.0.1", host);
68
64
  return await syncHost();
69
65
  }
70
66
 
71
67
  // src/caddy/constants.ts
72
- import { join } from "path";
73
- import os from "os";
74
- import process2 from "process";
68
+ import { join } from "node:path";
69
+ import os from "node:os";
70
+ import process2 from "node:process";
75
71
  import dotenvFlow from "dotenv-flow";
76
72
  dotenvFlow.config({
77
73
  silent: true
@@ -84,6 +80,7 @@ function resolvePath(path) {
84
80
  var TEMP_DIR = resolvePath(process2.env.UHRP_CADDY_PATH || process2.env.TEMP || process2.env.TMPDIR || "/tmp");
85
81
  var caddyPath = join(TEMP_DIR, `caddy${process2.platform === "win32" ? ".exe" : ""}`);
86
82
  var caddyFilePath = join(TEMP_DIR, "CADDYFILE");
83
+ var caddyLockFilePath = join(TEMP_DIR, "caddylock");
87
84
  var supportList = [
88
85
  {
89
86
  platform: "dragonfly",
@@ -196,7 +193,8 @@ var supportList = [
196
193
  ];
197
194
 
198
195
  // src/caddy/utils.ts
199
- import { createServer } from "net";
196
+ import { createServer } from "node:net";
197
+ import { exec as exec2 } from "node:child_process";
200
198
  import ora from "ora";
201
199
  var spinner;
202
200
  function tryPort(port) {
@@ -217,6 +215,18 @@ function tryPort(port) {
217
215
  }
218
216
  });
219
217
  }
218
+ async function kill(port) {
219
+ return new Promise((resolve, reject) => {
220
+ exec2(`npx @maxbo/free-port ${port} -s`, (err, stdout, stderr) => {
221
+ if (err) {
222
+ reject(err);
223
+ } else {
224
+ consola.log(stdout);
225
+ resolve();
226
+ }
227
+ });
228
+ });
229
+ }
220
230
  function getNumber(number) {
221
231
  if (number <= 0)
222
232
  return "0%";
@@ -316,9 +326,41 @@ var CaddyInstant = class {
316
326
  constructor() {
317
327
  this.inited = false;
318
328
  this.stoped = false;
319
- testCaddy().then(() => {
329
+ /** has locked */
330
+ this.locked = false;
331
+ testCaddy().then(async () => {
332
+ await this.getCaddyfile();
320
333
  this.inited = true;
321
334
  });
335
+ this.locked = this.checkLock();
336
+ }
337
+ checkLock() {
338
+ if (!existsSync(caddyLockFilePath))
339
+ writeFileSync(caddyLockFilePath, "");
340
+ return lockfile.checkSync(caddyLockFilePath);
341
+ }
342
+ async getCaddyfile() {
343
+ if (!existsSync(caddyFilePath))
344
+ await this.initCaddyfile();
345
+ this.caddyfile = await readFile(caddyFilePath, "utf-8");
346
+ return this.caddyfile;
347
+ }
348
+ async initCaddyfile() {
349
+ const contet = `
350
+ {
351
+ debug
352
+ auto_https disable_redirects
353
+ }
354
+
355
+ `;
356
+ await writeFile(caddyFilePath, contet);
357
+ this.caddyfile = contet;
358
+ }
359
+ async writeCaddyfile() {
360
+ return await writeFile(caddyFilePath, this.caddyfile || "");
361
+ }
362
+ async deleteCaddyfile() {
363
+ return await unlink(caddyFilePath);
322
364
  }
323
365
  async init() {
324
366
  await download();
@@ -337,100 +379,184 @@ var CaddyInstant = class {
337
379
  showCaddyLog = false,
338
380
  https = false
339
381
  } = options || {};
382
+ this._source = source;
383
+ this._target = target;
340
384
  if (!this.inited)
341
385
  await this.init();
342
- if (https && await tryPort(443))
343
- await kill(443, "tcp");
344
- if ((process3.platform === "win32" || !https) && await tryPort(80))
345
- await kill(80, "tcp");
346
386
  if (!await addHost(source.split(":")[0], target.split(":")[0]))
347
387
  throw new Error("update host failed");
348
388
  consola.success("update host success\n");
389
+ await this.getCaddyfile();
390
+ if (!(this.caddyfile || "").includes(`${target.split(":")[0]}${https ? "" : ":80"}`)) {
391
+ this.caddyfile = `${this.caddyfile}
392
+ ${target.split(":")[0]}${https ? "" : ":80"} {
393
+ ${https ? "tls internal" : ""}
394
+ reverse_proxy http://${source} {
395
+ health_uri ${base}
396
+ health_interval 2s
397
+ health_timeout 5s
398
+ fail_duration 2s
399
+ unhealthy_status 502 503 504 404
400
+ lb_try_duration 3s
401
+ lb_try_interval 300ms
402
+ health_headers {
403
+ Accept text/html
404
+ Accept-Encoding gzip, deflate, br
405
+ User-Agent Caddy-Health-Check
406
+ }
407
+
408
+ @error status 502 503 504 404
409
+ handle_response @error {
410
+ respond * 503 {
411
+ body "Service Unavailable"
412
+ close
413
+ }
414
+ }
415
+ }
416
+ }
417
+
418
+ `;
419
+ await this.writeCaddyfile();
420
+ }
421
+ if (!existsSync(caddyLockFilePath))
422
+ writeFileSync(caddyLockFilePath, "");
423
+ if (!this.locked) {
424
+ if (await tryPort(443))
425
+ await kill(443);
426
+ if ((process3.platform === "win32" || !https) && await tryPort(80))
427
+ await kill(80);
428
+ }
349
429
  return new Promise((resolve, reject) => {
350
- const child = process3.platform !== "win32" ? spawn("sudo", ["-E", caddyPath, "reverse-proxy", "--from", `${target.split(":")[0]}${https ? "" : ":80"}`, "--to", `${source}`, "--internal-certs", "--insecure", "--disable-redirects"]) : spawn(caddyPath, ["reverse-proxy", "--from", `${target.split(":")[0]}`, "--to", `${source}`, "--internal-certs"]);
351
- child.on("error", (err) => {
352
- return reject(err);
353
- });
354
- process3.on("SIGINT", async () => {
355
- if (!restore || this.stoped)
356
- return;
357
- try {
358
- if (await removeHost(source.split(":")[0], target.split(":")[0]))
359
- consola.success("restore host success\n");
360
- else
361
- consola.fail("restore host failed\n");
362
- } catch (e) {
363
- consola.error(e);
364
- consola.fail("restore host failed\n");
365
- } finally {
366
- this.stoped = true;
367
- process3.nextTick(() => {
368
- process3.exit();
369
- });
370
- }
371
- });
372
- const originalExit = process3.exit.bind(process3);
373
- process3.exit = async (code) => {
374
- const port = Number(source.split(":")[1]);
375
- if (!Number.isNaN(port) && await tryPort(port))
376
- await kill(port, "tcp");
377
- const pwd2 = process3.cwd();
378
- const viteCacheDir = `${pwd2}/node_modules/.vite`;
379
- if (existsSync(viteCacheDir))
380
- chmodRecursive(viteCacheDir, 511);
381
- const nuxtCacheDir = `${pwd2}/.nuxt`;
382
- if (existsSync(nuxtCacheDir))
383
- await chmodRecursive(nuxtCacheDir, 511);
384
- const webpackCacheDir = `${pwd2}/node_modules/.cache`;
385
- if (existsSync(webpackCacheDir))
386
- chmodRecursive(webpackCacheDir, 511);
387
- if (!restore || this.stoped)
388
- return originalExit(code);
389
- try {
390
- if (await removeHost(source.split(":")[0], target.split(":")[0]))
391
- consola.success("restore host success\n");
392
- else
393
- consola.fail("restore host failed\n");
394
- } catch (e) {
395
- consola.error(e);
396
- consola.fail("restore host failed\n");
397
- } finally {
398
- this.stoped = true;
399
- process3.nextTick(() => {
400
- originalExit(code);
401
- });
402
- }
430
+ var _a, _b;
431
+ const setupCleanup = () => {
432
+ process3.on("SIGINT", async () => {
433
+ if (this.stoped)
434
+ return;
435
+ process3.stdin.resume();
436
+ try {
437
+ await this.baseCleanup(restore);
438
+ } finally {
439
+ this.stoped = true;
440
+ process3.nextTick(() => {
441
+ process3.exit();
442
+ });
443
+ }
444
+ });
445
+ const originalExit = process3.exit.bind(process3);
446
+ process3.exit = async (code) => {
447
+ const port = Number(source.split(":")[1]);
448
+ if (!Number.isNaN(port) && await tryPort(port))
449
+ await kill(port);
450
+ const pwd = process3.cwd();
451
+ const viteCacheDir = `${pwd}/node_modules/.vite`;
452
+ if (existsSync(viteCacheDir))
453
+ await chmodRecursive(viteCacheDir, 511).catch(() => {
454
+ });
455
+ const nuxtCacheDir = `${pwd}/.nuxt`;
456
+ if (existsSync(nuxtCacheDir))
457
+ await chmodRecursive(nuxtCacheDir, 511).catch(() => {
458
+ });
459
+ const webpackCacheDir = `${pwd}/node_modules/.cache`;
460
+ if (existsSync(webpackCacheDir))
461
+ await chmodRecursive(webpackCacheDir, 511).catch(() => {
462
+ });
463
+ if (this.stoped)
464
+ return originalExit(code);
465
+ process3.stdin.resume();
466
+ try {
467
+ await this.baseCleanup();
468
+ } finally {
469
+ this.stoped = true;
470
+ process3.nextTick(() => {
471
+ originalExit(code);
472
+ });
473
+ }
474
+ };
403
475
  };
404
- child.stderr.on("data", (data) => {
405
- const lines = data.toString().split("\n").map((line) => line.trim());
406
- for (const line of lines) {
407
- showCaddyLog && line && console.info(line);
408
- if (line.includes("Error:") || line && JSON.parse(line).level === "error") {
409
- consola.error(line);
410
- return reject(line);
476
+ if (!this.locked) {
477
+ this._caddyChild = process3.platform !== "win32" ? spawn("sudo", ["-E", caddyPath, "run", "--config", caddyFilePath, "--watch"]) : spawn(caddyPath, ["run", "--config", caddyFilePath, "--watch"]);
478
+ lockfile.lockSync(caddyLockFilePath);
479
+ this._caddyChild.on("error", (err) => {
480
+ return reject(err);
481
+ });
482
+ (_a = this._caddyChild.stderr) == null ? void 0 : _a.on("data", async (data) => {
483
+ const lines = data.toString().split("\n").map((line) => line.trim());
484
+ for (const line of lines) {
485
+ showCaddyLog && line && console.info(line);
486
+ if (line.includes("Error:") || line && JSON.parse(line).level === "error") {
487
+ if (line.includes("parsing caddyfile tokens")) {
488
+ consola.error("Caddyfile syntax error, please contact the author:\n", `${this.caddyfile}
489
+
490
+ ${line}
491
+ `);
492
+ await this.baseCleanup();
493
+ process3.exit();
494
+ } else {
495
+ consola.error(`${line}
496
+ `);
497
+ return reject(line);
498
+ }
499
+ }
500
+ if (line.includes("config file changed"))
501
+ consola.success("Detect added a new reverse proxy config, restarted.\n");
502
+ if (line.includes("caddy proxying") || line.includes("serving initial"))
503
+ return resolve();
411
504
  }
412
- }
413
- });
414
- child.stdout.on("data", (_data) => {
415
- consola.info(_data.toString());
416
- resolve();
417
- });
505
+ });
506
+ (_b = this._caddyChild.stdout) == null ? void 0 : _b.on("data", (_data) => {
507
+ consola.info(_data.toString());
508
+ resolve();
509
+ });
510
+ setupCleanup();
511
+ } else {
512
+ consola.info("Caddy is running in another process.");
513
+ setupCleanup();
514
+ return resolve();
515
+ }
418
516
  });
419
517
  }
518
+ async baseCleanup(restore = true) {
519
+ var _a;
520
+ try {
521
+ if (restore && this._source && this._target) {
522
+ if (await removeHost(this._source.split(":")[0], this._target.split(":")[0]))
523
+ consola.success("Restore host success.\n");
524
+ else
525
+ consola.fail("Restore host failed.\n");
526
+ }
527
+ } catch (e) {
528
+ consola.error(e);
529
+ consola.fail("Restore host failed.\n");
530
+ }
531
+ if (!this.locked && !this.stoped) {
532
+ (_a = this._caddyChild) == null ? void 0 : _a.kill();
533
+ try {
534
+ await lockfile.unlock(caddyLockFilePath).catch(() => {
535
+ });
536
+ await unlink(caddyFilePath).catch(() => {
537
+ });
538
+ await unlink(caddyLockFilePath).catch(() => {
539
+ });
540
+ } catch (e) {
541
+ consola.error(e);
542
+ }
543
+ }
544
+ }
420
545
  };
421
546
 
422
547
  // src/index.ts
423
548
  var config;
424
549
  var caddy;
425
- var pwd = process4.cwd();
550
+ var cwd = process4.cwd();
426
551
  var vitePrintUrls = once((options, source, target, base = "/", _printUrls) => {
427
552
  _printUrls == null ? void 0 : _printUrls();
428
553
  if (caddy)
429
554
  return;
430
555
  caddy = new CaddyInstant();
431
- caddy.run(source, target, __spreadValues({
432
- base
433
- }, options)).then(() => {
556
+ caddy.run(source, target, {
557
+ base,
558
+ ...options
559
+ }).then(() => {
434
560
  const colorUrl = (url) => c.green(url.replace(/:(\d+)\//, (_, port) => `:${c.bold(port)}/`));
435
561
  consola.success(` ${c.green("\u279C")} ${c.bold("run caddy reverse proxy success")}: ${colorUrl(`${options.https ? "https" : "http"}://${target}${base}`)}`);
436
562
  }).catch((e) => {
@@ -448,16 +574,16 @@ var unpluginFactory = (options) => ({
448
574
  var _a;
449
575
  if (config.command !== "serve")
450
576
  return;
451
- if (!isAdmin()) {
452
- consola.warn("please run as administrator");
453
- return;
454
- }
455
577
  const {
456
578
  enable = true,
457
579
  target = ""
458
580
  } = options;
459
581
  if (!enable)
460
582
  return;
583
+ if (!isAdmin()) {
584
+ consola.warn("please run as administrator");
585
+ return;
586
+ }
461
587
  if (!target) {
462
588
  consola.fail("please provide target");
463
589
  return;
@@ -474,31 +600,34 @@ var unpluginFactory = (options) => ({
474
600
  }
475
601
  },
476
602
  webpack(compiler) {
477
- var _a;
603
+ var _a, _b;
478
604
  if (process4.env.NODE_ENV !== "development")
479
605
  return;
480
- if (!isAdmin()) {
481
- consola.warn("please run as administrator");
482
- return;
483
- }
484
606
  const {
485
607
  enable = true,
486
608
  target = ""
487
609
  } = options;
488
610
  if (!enable)
489
611
  return;
612
+ if (!isAdmin()) {
613
+ consola.warn("please run as administrator");
614
+ return;
615
+ }
490
616
  if (!target) {
491
617
  consola.fail("please provide target");
492
618
  return;
493
619
  }
494
- const devServer = __spreadValues(__spreadValues({
620
+ const devServer = {
495
621
  host: "localhost",
496
- port: 8080
497
- }, compiler.options.devServer), process4.VUE_CLI_SERVICE.projectOptions.devServer);
622
+ port: 8080,
623
+ ...compiler.options.devServer,
624
+ // @ts-expect-error vuecli
625
+ ...(_a = process4.VUE_CLI_SERVICE) == null ? void 0 : _a.projectOptions.devServer
626
+ };
498
627
  const source = `${devServer.host}:${devServer.port}`;
499
628
  if (caddy)
500
629
  return;
501
- const _close = (_a = compiler.close) == null ? void 0 : _a.bind(compiler);
630
+ const _close = (_b = compiler.close) == null ? void 0 : _b.bind(compiler);
502
631
  if (_close) {
503
632
  compiler.close = async (callback) => {
504
633
  process4.on("exit", () => {
@@ -509,7 +638,9 @@ var unpluginFactory = (options) => ({
509
638
  options.https = false;
510
639
  }
511
640
  caddy = new CaddyInstant();
512
- caddy.run(source, target, __spreadValues({}, options)).then(() => {
641
+ caddy.run(source, target, {
642
+ ...options
643
+ }).then(() => {
513
644
  const colorUrl = (url) => c.green(url.replace(/:(\d+)\//, (_, port) => `:${c.bold(port)}/`));
514
645
  compiler.hooks.done.tap("unplugin-https-reverse-proxy", () => {
515
646
  consola.success(` ${c.green("\u279C")} ${c.bold("run caddy reverse proxy success")}: ${colorUrl(`${options.https ? "https" : "http"}://${target}`)}`);
@@ -517,6 +648,45 @@ var unpluginFactory = (options) => ({
517
648
  }).catch((e) => {
518
649
  throw e;
519
650
  });
651
+ },
652
+ async rspack(compiler) {
653
+ var _a, _b, _c;
654
+ if (process4.env.NODE_ENV !== "development")
655
+ return;
656
+ const {
657
+ enable = true,
658
+ target = ""
659
+ } = options;
660
+ if (!enable)
661
+ return;
662
+ if (!isAdmin()) {
663
+ consola.warn("please run as administrator");
664
+ return;
665
+ }
666
+ if (!target) {
667
+ consola.fail("please provide target");
668
+ return;
669
+ }
670
+ const devServer = {
671
+ host: "localhost",
672
+ port: 8080,
673
+ ...compiler.options.devServer,
674
+ ...(_c = (_b = await ((_a = await import("@rsbuild/core")) == null ? void 0 : _a.loadConfig({
675
+ cwd
676
+ }))) == null ? void 0 : _b.content) == null ? void 0 : _c.server
677
+ };
678
+ const source = `${devServer.host}:${devServer.port}`;
679
+ if (caddy)
680
+ return;
681
+ caddy = new CaddyInstant();
682
+ caddy.run(source, target, {
683
+ ...options
684
+ }).then(() => {
685
+ const colorUrl = (url) => c.green(url.replace(/:(\d+)\//, (_, port) => `:${c.bold(port)}/`));
686
+ consola.success(` ${c.green("\u279C")} ${c.bold("run caddy reverse proxy success")}: ${colorUrl(`${options.https ? "https" : "http"}://${target}`)}`);
687
+ }).catch((e) => {
688
+ throw e;
689
+ });
520
690
  }
521
691
  });
522
692
  var unplugin = /* @__PURE__ */ createUnplugin(unpluginFactory);