@vlandoss/localproxy 0.0.10 → 0.0.11-git-06df4ba.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/bin.ts +2 -1
- package/dist/bin.mjs +416 -0
- package/package.json +16 -7
package/bin.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
4
5
|
import { main } from "./src/main";
|
|
5
6
|
|
|
6
7
|
main({
|
|
7
|
-
binDir:
|
|
8
|
+
binDir: path.dirname(fileURLToPath(import.meta.url)),
|
|
8
9
|
installDir: path.join(homedir(), ".localproxy"),
|
|
9
10
|
});
|
package/dist/bin.mjs
ADDED
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { createPkgService, createShellService, getVersion, palette } from "@vlandoss/clibuddy";
|
|
6
|
+
import { createCommand } from "commander";
|
|
7
|
+
import * as fs$2 from "node:fs";
|
|
8
|
+
import { createLoggy } from "@vlandoss/loggy";
|
|
9
|
+
import * as fs$1 from "node:fs/promises";
|
|
10
|
+
import fs from "node:fs/promises";
|
|
11
|
+
import { editor, password } from "@inquirer/prompts";
|
|
12
|
+
//#region src/services/logger.ts
|
|
13
|
+
const logger = createLoggy({ namespace: "localproxy" });
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/services/shell.ts
|
|
16
|
+
const quietShell = createShellService({
|
|
17
|
+
quiet: true,
|
|
18
|
+
verbose: false
|
|
19
|
+
});
|
|
20
|
+
const silentShell = quietShell.child({ stdio: "ignore" });
|
|
21
|
+
const verboseShell = quietShell.child({
|
|
22
|
+
quiet: false,
|
|
23
|
+
verbose: true,
|
|
24
|
+
stdio: "inherit"
|
|
25
|
+
});
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/services/caddy.ts
|
|
28
|
+
const debug$4 = logger.subdebug("caddy");
|
|
29
|
+
var CaddyService = class {
|
|
30
|
+
#configPath;
|
|
31
|
+
#pidFilePath;
|
|
32
|
+
constructor(configPath) {
|
|
33
|
+
this.#configPath = configPath;
|
|
34
|
+
this.#pidFilePath = path.join(path.dirname(configPath), "caddy.pid");
|
|
35
|
+
this.#initCaddyPid();
|
|
36
|
+
}
|
|
37
|
+
#initCaddyPid() {
|
|
38
|
+
if (!this.#hasCaddyPid()) fs$2.writeFileSync(this.#pidFilePath, "");
|
|
39
|
+
}
|
|
40
|
+
#hasCaddyPid() {
|
|
41
|
+
return fs$2.existsSync(this.#pidFilePath);
|
|
42
|
+
}
|
|
43
|
+
#deleteCaddyPid() {
|
|
44
|
+
if (this.#hasCaddyPid()) fs$2.rmSync(this.#pidFilePath);
|
|
45
|
+
}
|
|
46
|
+
#shell({ verbose }) {
|
|
47
|
+
return verbose ? verboseShell : silentShell;
|
|
48
|
+
}
|
|
49
|
+
#getPID() {
|
|
50
|
+
return this.#hasCaddyPid() ? fs$2.readFileSync(this.#pidFilePath, "utf-8").trim() : null;
|
|
51
|
+
}
|
|
52
|
+
async reboot(options) {
|
|
53
|
+
if (await this.isRunning()) await this.stop(options);
|
|
54
|
+
await this.start(options);
|
|
55
|
+
}
|
|
56
|
+
async start({ verbose }) {
|
|
57
|
+
if (await this.isRunning()) {
|
|
58
|
+
logger.warn("Caddy is already running. PID: %d", this.#getPID());
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const { $ } = this.#shell({ verbose });
|
|
62
|
+
try {
|
|
63
|
+
logger.start("Starting Caddy");
|
|
64
|
+
await $`caddy start -c ${this.#configPath} --pidfile ${this.#pidFilePath} > /dev/null 2>&1`;
|
|
65
|
+
logger.success("Caddy started");
|
|
66
|
+
} catch {
|
|
67
|
+
logger.error("Can't start Caddy");
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async stop({ verbose }) {
|
|
72
|
+
const { $ } = this.#shell({ verbose });
|
|
73
|
+
try {
|
|
74
|
+
logger.start("Stopping Caddy");
|
|
75
|
+
await $`caddy stop -c ${this.#configPath}`;
|
|
76
|
+
this.#deleteCaddyPid();
|
|
77
|
+
logger.success("Caddy stopped");
|
|
78
|
+
} catch {
|
|
79
|
+
logger.error("Can't stop Caddy");
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async isRunning() {
|
|
84
|
+
if (!this.#hasCaddyPid()) return false;
|
|
85
|
+
const pid = this.#getPID();
|
|
86
|
+
debug$4("caddy PID: %d", pid);
|
|
87
|
+
const { exitCode } = await quietShell.$`kill -0 ${pid}`.nothrow();
|
|
88
|
+
const isRunning = exitCode === 0;
|
|
89
|
+
debug$4("caddy is %s", isRunning ? "running" : "stopped");
|
|
90
|
+
return isRunning;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
//#endregion
|
|
94
|
+
//#region src/services/caddyfile/parser.ts
|
|
95
|
+
var CaddyfileParser = class {
|
|
96
|
+
#content;
|
|
97
|
+
constructor(content) {
|
|
98
|
+
this.#content = content;
|
|
99
|
+
}
|
|
100
|
+
parse() {
|
|
101
|
+
return { siteBlocks: this.#extractSiteBlocks(this.#content) };
|
|
102
|
+
}
|
|
103
|
+
#extractSiteBlocks(content) {
|
|
104
|
+
const siteBlocks = [];
|
|
105
|
+
const bracedBlockRegex = /([^{]+)\s*\{([^}]*)\}/gs;
|
|
106
|
+
let match;
|
|
107
|
+
const processedContent = /* @__PURE__ */ new Set();
|
|
108
|
+
while ((match = bracedBlockRegex.exec(content)) !== null) {
|
|
109
|
+
const [fullMatch, sitesStr, directivesStr] = match;
|
|
110
|
+
processedContent.add(fullMatch.trim());
|
|
111
|
+
const sites = sitesStr ? this.#parseSites(sitesStr.trim()) : [];
|
|
112
|
+
const directives = directivesStr ? this.#parseDirectives(directivesStr.trim()) : [];
|
|
113
|
+
if (sites.length > 0) siteBlocks.push({
|
|
114
|
+
sites,
|
|
115
|
+
directives
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return siteBlocks;
|
|
119
|
+
}
|
|
120
|
+
#parseSites(sitesStr) {
|
|
121
|
+
if (!sitesStr.trim()) return [];
|
|
122
|
+
return sitesStr.split(/[,\s]+/).map((site) => site.trim()).filter((site) => site.length > 0);
|
|
123
|
+
}
|
|
124
|
+
#parseDirectives(directivesStr) {
|
|
125
|
+
const directives = [];
|
|
126
|
+
if (!directivesStr.trim()) return directives;
|
|
127
|
+
const lines = directivesStr.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
|
|
128
|
+
for (const line of lines) {
|
|
129
|
+
const directive = this.#parseDirectiveLine(line);
|
|
130
|
+
if (directive) directives.push(directive);
|
|
131
|
+
}
|
|
132
|
+
return directives;
|
|
133
|
+
}
|
|
134
|
+
#parseDirectiveLine(line) {
|
|
135
|
+
const match = line.match(/^(\w+)(?:\s+(.+))?$/);
|
|
136
|
+
if (!match) return null;
|
|
137
|
+
const [, directiveType, argsStr] = match;
|
|
138
|
+
const directive = {
|
|
139
|
+
type: directiveType,
|
|
140
|
+
arguments: []
|
|
141
|
+
};
|
|
142
|
+
if (argsStr) {
|
|
143
|
+
const args = argsStr.split(/\s+/).filter((arg) => arg.length > 0);
|
|
144
|
+
if (args.length > 0 && this.#looksLikeMatcher(args[0])) {
|
|
145
|
+
directive.matchToken = args[0];
|
|
146
|
+
directive.arguments = args.slice(1);
|
|
147
|
+
} else directive.arguments = args;
|
|
148
|
+
}
|
|
149
|
+
return directive;
|
|
150
|
+
}
|
|
151
|
+
#looksLikeMatcher(token) {
|
|
152
|
+
return token === "*" || token.startsWith("/") || token.startsWith("@");
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
//#endregion
|
|
156
|
+
//#region src/services/caddyfile/service.ts
|
|
157
|
+
const debug$3 = logger.subdebug("caddyfile-service");
|
|
158
|
+
const LOCALHOST_REGEX = /localhost(:\d+)?/;
|
|
159
|
+
var CaddyfileService = class {
|
|
160
|
+
#filepath;
|
|
161
|
+
constructor(filepath) {
|
|
162
|
+
this.#filepath = filepath;
|
|
163
|
+
}
|
|
164
|
+
async getLocalDomains() {
|
|
165
|
+
const domains = new CaddyfileParser(await fs$1.readFile(this.#filepath, "utf-8")).parse().siteBlocks.flatMap((block) => {
|
|
166
|
+
const ports = block.directives.filter((d) => d.type === "reverse_proxy" && d.arguments.some((arg) => this.#isLocalhost(arg))).flatMap((d) => d.arguments).filter((arg) => this.#isLocalhost(arg)).map((arg) => arg.split(":")[1]);
|
|
167
|
+
return block.sites.map((site) => {
|
|
168
|
+
return {
|
|
169
|
+
hostname: site,
|
|
170
|
+
ports
|
|
171
|
+
};
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
debug$3("detected domains: %o", domains);
|
|
175
|
+
return domains;
|
|
176
|
+
}
|
|
177
|
+
#isLocalhost(arg) {
|
|
178
|
+
return LOCALHOST_REGEX.test(arg);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
//#endregion
|
|
182
|
+
//#region src/services/sudo.ts
|
|
183
|
+
const debug$2 = logger.subdebug("sudo");
|
|
184
|
+
var SudoService = class {
|
|
185
|
+
#shell;
|
|
186
|
+
constructor() {
|
|
187
|
+
this.#shell = silentShell.child({ stdio: [
|
|
188
|
+
"ignore",
|
|
189
|
+
"ignore",
|
|
190
|
+
"pipe"
|
|
191
|
+
] });
|
|
192
|
+
}
|
|
193
|
+
async auth() {
|
|
194
|
+
if (!await this.isAuthorized()) await this.authenticate();
|
|
195
|
+
}
|
|
196
|
+
async isAuthorized() {
|
|
197
|
+
const { exitCode } = await this.#shell.$`sudo -v -n`.nothrow();
|
|
198
|
+
return exitCode === 0;
|
|
199
|
+
}
|
|
200
|
+
async authenticate() {
|
|
201
|
+
let intent = 1;
|
|
202
|
+
let exitCode = null;
|
|
203
|
+
await password({
|
|
204
|
+
message: "Enter sudo password to manage hosts",
|
|
205
|
+
mask: true,
|
|
206
|
+
validate: async (value) => {
|
|
207
|
+
debug$2("Attempting sudo authentication %o", { intent });
|
|
208
|
+
const output = await this.#shell.$`echo "${value}" | sudo -S -v`.nothrow();
|
|
209
|
+
exitCode = output.exitCode;
|
|
210
|
+
debug$2("Sudo authentication exitCode(%d)", exitCode);
|
|
211
|
+
if (intent >= 3) return true;
|
|
212
|
+
intent++;
|
|
213
|
+
return output.exitCode === 0 ? true : "Invalid password";
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
if (exitCode !== 0) {
|
|
217
|
+
logger.error("`sudo` authentication failed");
|
|
218
|
+
process.exit(1);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
//#endregion
|
|
223
|
+
//#region src/services/hosts.ts
|
|
224
|
+
const debug$1 = logger.subdebug("hosts");
|
|
225
|
+
var HostsService = class {
|
|
226
|
+
#sudo;
|
|
227
|
+
constructor() {
|
|
228
|
+
this.#sudo = new SudoService();
|
|
229
|
+
}
|
|
230
|
+
#shell({ verbose }) {
|
|
231
|
+
return verbose ? verboseShell : silentShell;
|
|
232
|
+
}
|
|
233
|
+
async setup(options) {
|
|
234
|
+
const { hostnames } = options;
|
|
235
|
+
logger.start("Setting up hosts");
|
|
236
|
+
await this.#sudo.auth();
|
|
237
|
+
const { $ } = this.#shell(options);
|
|
238
|
+
await $`sudo hosts backups create`;
|
|
239
|
+
for (const host of hostnames) await this.addHost(host, options);
|
|
240
|
+
logger.success("Hosts ready");
|
|
241
|
+
}
|
|
242
|
+
async clean(options) {
|
|
243
|
+
const { hostnames } = options;
|
|
244
|
+
await this.#sudo.auth();
|
|
245
|
+
for (const host of hostnames) await this.removeHost(host, options);
|
|
246
|
+
}
|
|
247
|
+
async findHost(host) {
|
|
248
|
+
const { exitCode } = await quietShell.$`hosts show "${host}"`.nothrow();
|
|
249
|
+
const found = exitCode === 0;
|
|
250
|
+
debug$1("Host %s is %s", host, found ? "present" : "absent");
|
|
251
|
+
return found;
|
|
252
|
+
}
|
|
253
|
+
async addHost(host, options) {
|
|
254
|
+
const { $ } = this.#shell(options);
|
|
255
|
+
if (!await this.findHost(host)) await $`sudo hosts add 127.0.0.1 ${host}`;
|
|
256
|
+
}
|
|
257
|
+
async removeHost(host, options) {
|
|
258
|
+
const { $ } = this.#shell(options);
|
|
259
|
+
if (!await this.findHost(host)) await $`sudo hosts remove ${host}`;
|
|
260
|
+
}
|
|
261
|
+
async getEnabledHosts() {
|
|
262
|
+
return (await quietShell.$`hosts list enabled`.text()).split("\n").map((line) => {
|
|
263
|
+
const [ip, hostname] = line.split(/\s+/);
|
|
264
|
+
if (!ip || !hostname) return null;
|
|
265
|
+
return {
|
|
266
|
+
ip,
|
|
267
|
+
hostname
|
|
268
|
+
};
|
|
269
|
+
}).filter(Boolean);
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
//#endregion
|
|
273
|
+
//#region src/commands/clean.ts
|
|
274
|
+
function createCleanCommand({ caddyfilePath }) {
|
|
275
|
+
return createCommand("clean").description("clean up config files").option("--verbose", "verbose mode, show background output", false).action(async function cleanAction(options) {
|
|
276
|
+
const { verbose } = options;
|
|
277
|
+
await new CaddyService(caddyfilePath).stop({ verbose });
|
|
278
|
+
const hostnames = (await new CaddyfileService(caddyfilePath).getLocalDomains()).map((d) => d.hostname);
|
|
279
|
+
await new HostsService().clean({
|
|
280
|
+
verbose,
|
|
281
|
+
hostnames
|
|
282
|
+
});
|
|
283
|
+
logger.success("Clean completed!");
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
//#endregion
|
|
287
|
+
//#region src/services/file.ts
|
|
288
|
+
var FileService = class {
|
|
289
|
+
#filePath;
|
|
290
|
+
constructor(filePath) {
|
|
291
|
+
this.#filePath = filePath;
|
|
292
|
+
}
|
|
293
|
+
async print() {
|
|
294
|
+
const fileContent = (await fs.readFile(this.#filePath)).toString();
|
|
295
|
+
console.log(`${this.#filePath}:\n`);
|
|
296
|
+
console.log(fileContent.trim());
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
//#endregion
|
|
300
|
+
//#region src/commands/setup.ts
|
|
301
|
+
const debug = logger.subdebug("setup");
|
|
302
|
+
async function checkInternalTools() {
|
|
303
|
+
const { $ } = quietShell;
|
|
304
|
+
const caddyVersion = await $`caddy --version`.nothrow();
|
|
305
|
+
if (caddyVersion.exitCode) {
|
|
306
|
+
logger.error("Caddy is not installed. Please install Caddy first:");
|
|
307
|
+
logger.info("macOS: brew install caddy");
|
|
308
|
+
logger.info("Linux: https://caddyserver.com/docs/install");
|
|
309
|
+
process.exit(1);
|
|
310
|
+
}
|
|
311
|
+
debug("caddy version: %s", caddyVersion.stdout.trim());
|
|
312
|
+
const hostsVersion = await $`hosts --version`.nothrow();
|
|
313
|
+
if (!hostsVersion) {
|
|
314
|
+
logger.error("hosts CLI tool is not installed. Please install hosts first:");
|
|
315
|
+
logger.info("macOS: brew tap xwmx/taps && brew install hosts");
|
|
316
|
+
logger.info("Linux: Check https://github.com/xwmx/hosts for installation");
|
|
317
|
+
process.exit(1);
|
|
318
|
+
}
|
|
319
|
+
debug("hosts version: %s", hostsVersion.stdout.trim());
|
|
320
|
+
}
|
|
321
|
+
function createSetupCommand({ binDir, installDir, caddyfilePath }) {
|
|
322
|
+
return createCommand("setup").description("setup config files").option("--verbose", "verbose mode, show background output", false).action(async function setupAction(options) {
|
|
323
|
+
const { verbose } = options;
|
|
324
|
+
await checkInternalTools();
|
|
325
|
+
if (!await fs$1.exists(installDir)) await fs$1.mkdir(installDir);
|
|
326
|
+
const exampleCaddyFilePath = path.join(binDir, "config", "Caddyfile.example");
|
|
327
|
+
const fileContent = await editor({
|
|
328
|
+
message: "Caddyfile",
|
|
329
|
+
default: await fs$1.exists(caddyfilePath) ? await fs$1.readFile(caddyfilePath, "utf-8") : await fs$1.readFile(exampleCaddyFilePath, "utf-8")
|
|
330
|
+
});
|
|
331
|
+
await fs$1.writeFile(caddyfilePath, fileContent);
|
|
332
|
+
await new FileService(caddyfilePath).print();
|
|
333
|
+
await new CaddyService(caddyfilePath).reboot({ verbose });
|
|
334
|
+
const hostnames = (await new CaddyfileService(caddyfilePath).getLocalDomains()).map((d) => d.hostname);
|
|
335
|
+
await new HostsService().setup({
|
|
336
|
+
verbose,
|
|
337
|
+
hostnames
|
|
338
|
+
});
|
|
339
|
+
logger.success("Setup completed!");
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
//#endregion
|
|
343
|
+
//#region src/commands/start.ts
|
|
344
|
+
function createStartCommand({ caddyfilePath }) {
|
|
345
|
+
return createCommand("start").description("start caddy server").option("--verbose", "verbose mode, show background output", false).action(async function startAction(options) {
|
|
346
|
+
await new CaddyService(caddyfilePath).start(options);
|
|
347
|
+
logger.success("Start completed!");
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
//#endregion
|
|
351
|
+
//#region src/commands/status.ts
|
|
352
|
+
function createStatusCommand({ caddyfilePath }) {
|
|
353
|
+
return createCommand("status").description("show configured localhosts").action(async function statusAction() {
|
|
354
|
+
if (await new CaddyService(caddyfilePath).isRunning()) logger.info("Caddy is running");
|
|
355
|
+
else logger.warn("Caddy is not running. Use `localp start` to start it.");
|
|
356
|
+
await new FileService(caddyfilePath).print();
|
|
357
|
+
const localDomains = await new CaddyfileService(caddyfilePath).getLocalDomains();
|
|
358
|
+
const enabledHosts = await new HostsService().getEnabledHosts();
|
|
359
|
+
localDomains.forEach(({ hostname, ports }) => {
|
|
360
|
+
const enabled = enabledHosts.some((h) => h.hostname === hostname);
|
|
361
|
+
const formattedPorts = ports.map((p) => `:${p}`).join(", ");
|
|
362
|
+
if (enabled) logger.success("`%s` is configured -> %s", hostname, formattedPorts);
|
|
363
|
+
else logger.warn("`%s` is not configured -> %s", hostname, formattedPorts);
|
|
364
|
+
});
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
//#endregion
|
|
368
|
+
//#region src/commands/stop.ts
|
|
369
|
+
function createStopCommand({ caddyfilePath }) {
|
|
370
|
+
return createCommand("stop").description("stop caddy server").option("--verbose", "verbose mode, show background output", false).action(async function stopAction(options) {
|
|
371
|
+
await new CaddyService(caddyfilePath).stop(options);
|
|
372
|
+
logger.success("Stop completed!");
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
const BANNER_TEXT = `${`🛠️ ${palette.bold("localproxy")}`}: Simple local development proxy automation\n`;
|
|
376
|
+
const CREDITS_TEXT = `\nAcknowledgment:
|
|
377
|
+
- Caddy: for being a powerful proxy server
|
|
378
|
+
${palette.link("https://caddyserver.com")}
|
|
379
|
+
|
|
380
|
+
- hosts: making it easier to manage host file
|
|
381
|
+
${palette.link("https://github.com/xwmx/hosts")}`;
|
|
382
|
+
//#endregion
|
|
383
|
+
//#region src/main.ts
|
|
384
|
+
async function createContext({ binDir, installDir }) {
|
|
385
|
+
const binPkg = await createPkgService(binDir);
|
|
386
|
+
if (!binPkg) throw new Error("Could not find bin package.json");
|
|
387
|
+
return {
|
|
388
|
+
installDir,
|
|
389
|
+
caddyfilePath: path.join(installDir, "Caddyfile"),
|
|
390
|
+
binDir,
|
|
391
|
+
binPkg
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
async function createProgram(options) {
|
|
395
|
+
const ctx = await createContext(options);
|
|
396
|
+
return createCommand("localproxy").alias("localp").version(getVersion(ctx.binPkg), "-v, --version").addHelpText("before", BANNER_TEXT).addHelpText("after", CREDITS_TEXT).addCommand(createSetupCommand(ctx)).addCommand(createStatusCommand(ctx)).addCommand(createStartCommand(ctx)).addCommand(createStopCommand(ctx)).addCommand(createCleanCommand(ctx));
|
|
397
|
+
}
|
|
398
|
+
async function main(options) {
|
|
399
|
+
try {
|
|
400
|
+
await (await createProgram(options)).parseAsync();
|
|
401
|
+
} catch (error) {
|
|
402
|
+
if (error instanceof Error && error.name === "ExitPromptError") logger.success("👋 cancelled, until next time!");
|
|
403
|
+
else {
|
|
404
|
+
logger.error(error);
|
|
405
|
+
process.exit(1);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
//#endregion
|
|
410
|
+
//#region bin.ts
|
|
411
|
+
main({
|
|
412
|
+
binDir: path.dirname(fileURLToPath(import.meta.url)),
|
|
413
|
+
installDir: path.join(homedir(), ".localproxy")
|
|
414
|
+
});
|
|
415
|
+
//#endregion
|
|
416
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vlandoss/localproxy",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11-git-06df4ba.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": {
|
|
@@ -8,34 +8,43 @@
|
|
|
8
8
|
},
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
11
|
-
"url": "git+https://github.com/variableland/dx.git"
|
|
11
|
+
"url": "git+https://github.com/variableland/dx.git",
|
|
12
|
+
"directory": "packages/localproxy"
|
|
12
13
|
},
|
|
13
14
|
"license": "MIT",
|
|
14
15
|
"author": "rcrd <rcrd@variable.land>",
|
|
15
16
|
"type": "module",
|
|
16
17
|
"bin": {
|
|
17
|
-
"localproxy": "./bin.
|
|
18
|
-
"localp": "./bin.
|
|
18
|
+
"localproxy": "./dist/bin.mjs",
|
|
19
|
+
"localp": "./dist/bin.mjs"
|
|
19
20
|
},
|
|
20
21
|
"files": [
|
|
21
|
-
"bin",
|
|
22
|
+
"bin.ts",
|
|
23
|
+
"dist",
|
|
22
24
|
"src",
|
|
25
|
+
"!src/**/__tests__",
|
|
26
|
+
"!src/**/*.test.*",
|
|
23
27
|
"config",
|
|
24
28
|
"tsconfig.json"
|
|
25
29
|
],
|
|
26
30
|
"dependencies": {
|
|
27
31
|
"@inquirer/prompts": "8.3.0",
|
|
28
32
|
"commander": "14.0.3",
|
|
29
|
-
"@vlandoss/
|
|
30
|
-
"@vlandoss/
|
|
33
|
+
"@vlandoss/loggy": "0.0.8-git-06df4ba.0",
|
|
34
|
+
"@vlandoss/clibuddy": "0.0.11-git-06df4ba.0"
|
|
31
35
|
},
|
|
32
36
|
"publishConfig": {
|
|
33
37
|
"access": "public"
|
|
34
38
|
},
|
|
35
39
|
"engines": {
|
|
40
|
+
"node": ">=20.0.0",
|
|
36
41
|
"bun": ">=1.0.0"
|
|
37
42
|
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@vlandoss/tsdown-config": "^0.0.2-git-06df4ba.0"
|
|
45
|
+
},
|
|
38
46
|
"scripts": {
|
|
47
|
+
"build": "tsdown",
|
|
39
48
|
"test": "bun test",
|
|
40
49
|
"test:types": "rr tsc"
|
|
41
50
|
}
|