@vlandoss/localproxy 0.0.1 → 0.0.2-git-b8d71ee.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vlandoss/localproxy",
3
- "version": "0.0.1",
3
+ "version": "0.0.2-git-b8d71ee.0",
4
4
  "description": "Simple local development proxy automation",
5
5
  "homepage": "https://github.com/variableland/dx/tree/main/packages/localproxy#readme",
6
6
  "bugs": {
@@ -26,8 +26,8 @@
26
26
  "dependencies": {
27
27
  "@inquirer/prompts": "^7.8.4",
28
28
  "commander": "13.1.0",
29
- "@vlandoss/clibuddy": "0.0.5",
30
- "@vlandoss/loggy": "0.0.4"
29
+ "@vlandoss/loggy": "0.0.4",
30
+ "@vlandoss/clibuddy": "0.0.5"
31
31
  },
32
32
  "publishConfig": {
33
33
  "access": "public"
@@ -1,3 +1,4 @@
1
+ import { password as passwordPrompt } from "@inquirer/prompts";
1
2
  import { createCommand } from "commander";
2
3
  import { CaddyService } from "~/services/caddy";
3
4
  import { HostsService } from "~/services/hosts";
@@ -19,8 +20,12 @@ export function createCleanCommand({ caddyfilePath }: Context) {
19
20
  const localDomains = caddyService.getLocalDomains();
20
21
  const hosts = localDomains.map((d) => d.host);
21
22
 
23
+ const password = await passwordPrompt({
24
+ message: "sudo password to manage hosts",
25
+ });
26
+
22
27
  const hostsService = new HostsService(hosts);
23
- await hostsService.clean(options);
28
+ await hostsService.clean({ ...options, password });
24
29
 
25
30
  logger.success("localproxy clean completed");
26
31
  });
@@ -1,6 +1,6 @@
1
1
  import * as fs from "node:fs/promises";
2
2
  import path from "node:path";
3
- import { editor } from "@inquirer/prompts";
3
+ import { editor as editorPrompt, password as passwordPrompt } from "@inquirer/prompts";
4
4
  import { createCommand } from "commander";
5
5
  import { CaddyService } from "~/services/caddy";
6
6
  import { HostsService } from "~/services/hosts";
@@ -65,7 +65,7 @@ export function createSetupCommand({ binDir, installDir, caddyfilePath }: Contex
65
65
  ? await fs.readFile(caddyfilePath, "utf-8")
66
66
  : await fs.readFile(exampleCaddyFilePath, "utf-8");
67
67
 
68
- const fileContent = await editor({
68
+ const fileContent = await editorPrompt({
69
69
  message: "Caddyfile",
70
70
  default: defaultContent,
71
71
  });
@@ -80,8 +80,12 @@ export function createSetupCommand({ binDir, installDir, caddyfilePath }: Contex
80
80
  const localDomains = caddyService.getLocalDomains();
81
81
  const hosts = localDomains.map((d) => d.host);
82
82
 
83
+ const password = await passwordPrompt({
84
+ message: "sudo password to manage hosts",
85
+ });
86
+
83
87
  const hostsService = new HostsService(hosts);
84
- await hostsService.setup(options);
88
+ await hostsService.setup({ ...options, password });
85
89
 
86
90
  logger.success("localproxy setup completed");
87
91
  });
@@ -56,11 +56,11 @@ export class CaddyService {
56
56
  const { $ } = this.#shell({ verbose });
57
57
 
58
58
  try {
59
- debug("Starting Caddy...");
59
+ logger.start("Starting Caddy");
60
60
 
61
61
  await $`caddy start -c ${this.#configPath} --pidfile ${this.#pidFilePath} > /dev/null 2>&1`;
62
62
 
63
- debug("Caddy started");
63
+ logger.success("Caddy started");
64
64
  } catch {
65
65
  logger.error("Can't start Caddy");
66
66
  process.exit(1);
@@ -71,12 +71,12 @@ export class CaddyService {
71
71
  const { $ } = this.#shell({ verbose });
72
72
 
73
73
  try {
74
- debug("Stopping Caddy...");
74
+ logger.start("Stopping Caddy");
75
75
 
76
76
  await $`caddy stop -c ${this.#configPath}`;
77
77
  this.#deleteCaddyPid();
78
78
 
79
- debug("Caddy stopped");
79
+ logger.success("Caddy stopped");
80
80
  } catch {
81
81
  logger.error("Can't stop Caddy");
82
82
  process.exit(1);
@@ -3,6 +3,7 @@ import { quietShell, silentShell, verboseShell } from "./shell";
3
3
 
4
4
  type SetupOptions = {
5
5
  verbose: boolean;
6
+ password: string;
6
7
  };
7
8
 
8
9
  const debug = logger.subdebug("hosts");
@@ -18,8 +19,24 @@ export class HostsService {
18
19
  return verbose ? verboseShell : silentShell;
19
20
  }
20
21
 
22
+ async #auth(password: string) {
23
+ if (!password) {
24
+ throw new Error("Password is required");
25
+ }
26
+
27
+ // Asking sudo directly in JS is unreliable,
28
+ // so we do it through a shell command
29
+ await silentShell.child({
30
+ stdio: ["ignore", "ignore", "pipe"],
31
+ }).$`echo "${password}" | sudo -S -v`;
32
+ }
33
+
21
34
  async setup(options: SetupOptions) {
22
- await verboseShell.$`sudo hosts backups create`;
35
+ await this.#auth(options.password);
36
+
37
+ const { stdout } = await verboseShell.$`sudo hosts backups create`;
38
+ const backupPath = stdout.match(/(\/[^\s]+)/)?.[1];
39
+ debug("Backup created at %s", backupPath);
23
40
 
24
41
  for (const host of this.#hosts) {
25
42
  await this.addHost(host, options);
@@ -27,23 +44,25 @@ export class HostsService {
27
44
  }
28
45
 
29
46
  async clean(options: SetupOptions) {
47
+ await this.#auth(options.password);
48
+
30
49
  for (const host of this.#hosts) {
31
50
  await this.removeHost(host, options);
32
51
  }
33
52
  }
34
53
 
35
54
  async findHost(host: string) {
36
- const currentHost = await quietShell.$`hosts show "${host}"`.text();
37
- debug("Host %s is %s", host, currentHost ? "present" : "absent");
38
- return currentHost;
55
+ const { exitCode } = await quietShell.$`hosts show "${host}"`.nothrow();
56
+ debug("Host %s is %s", host, !exitCode ? "present" : "absent");
57
+ return !exitCode;
39
58
  }
40
59
 
41
60
  async addHost(host: string, options: SetupOptions) {
42
61
  const { $ } = this.#shell(options);
43
62
 
44
- const currentHost = await this.findHost(host);
63
+ const found = await this.findHost(host);
45
64
 
46
- if (!currentHost) {
65
+ if (!found) {
47
66
  await $`sudo hosts add 127.0.0.1 ${host}`;
48
67
  }
49
68
  }
@@ -51,9 +70,9 @@ export class HostsService {
51
70
  async removeHost(host: string, options: SetupOptions) {
52
71
  const { $ } = this.#shell(options);
53
72
 
54
- const currentHost = await this.findHost(host);
73
+ const found = await this.findHost(host);
55
74
 
56
- if (!currentHost) {
75
+ if (!found) {
57
76
  await $`sudo hosts remove ${host}`;
58
77
  }
59
78
  }
@@ -6,11 +6,11 @@ export const quietShell = createShellService({
6
6
  });
7
7
 
8
8
  export const silentShell = quietShell.child({
9
- stdio: ["ignore", "ignore", "ignore"],
9
+ stdio: "ignore",
10
10
  });
11
11
 
12
12
  export const verboseShell = quietShell.child({
13
13
  quiet: false,
14
14
  verbose: true,
15
- stdio: ["inherit", "inherit", "inherit"],
15
+ stdio: "inherit",
16
16
  });