@hamedb89/localghost 0.1.0 → 0.1.6
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/README.md +100 -13
- package/dist/cli.js +645 -83
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +102 -6
- package/dist/index.js +294 -50
- package/dist/index.js.map +1 -1
- package/dist/vite.d.ts +3 -0
- package/dist/vite.js +460 -16
- package/dist/vite.js.map +1 -1
- package/docs/flows.md +27 -5
- package/docs/github.md +46 -8
- package/docs/localghost.1.md +45 -9
- package/package.json +7 -4
package/dist/index.js
CHANGED
|
@@ -1,6 +1,100 @@
|
|
|
1
|
+
// src/activity.ts
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
3
|
+
import { homedir } from "os";
|
|
4
|
+
import { dirname, join } from "path";
|
|
5
|
+
var LOCALGHOST_ACTIVITY_VERSION = 1;
|
|
6
|
+
function getLocalghostActivityPath(env = process.env) {
|
|
7
|
+
if (env.LOCALGHOST_ACTIVITY_PATH) return env.LOCALGHOST_ACTIVITY_PATH;
|
|
8
|
+
const stateRoot = env.XDG_STATE_HOME || join(homedir(), ".local/state");
|
|
9
|
+
return join(stateRoot, "localghost", "activity.json");
|
|
10
|
+
}
|
|
11
|
+
function isProcessRunning(pid) {
|
|
12
|
+
if (!Number.isInteger(pid) || pid < 1) return false;
|
|
13
|
+
try {
|
|
14
|
+
process.kill(pid, 0);
|
|
15
|
+
return true;
|
|
16
|
+
} catch (error) {
|
|
17
|
+
const code = typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
|
|
18
|
+
return code === "EPERM";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function emptyActivity() {
|
|
22
|
+
return { version: LOCALGHOST_ACTIVITY_VERSION, runs: [] };
|
|
23
|
+
}
|
|
24
|
+
function readLocalghostActivity(path = getLocalghostActivityPath()) {
|
|
25
|
+
if (!existsSync(path)) return emptyActivity();
|
|
26
|
+
try {
|
|
27
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
28
|
+
return {
|
|
29
|
+
version: LOCALGHOST_ACTIVITY_VERSION,
|
|
30
|
+
runs: Array.isArray(parsed.runs) ? parsed.runs : []
|
|
31
|
+
};
|
|
32
|
+
} catch {
|
|
33
|
+
return emptyActivity();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function writeLocalghostActivity(activity, path = getLocalghostActivityPath()) {
|
|
37
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
38
|
+
writeFileSync(path, `${JSON.stringify(activity, null, 2)}
|
|
39
|
+
`, "utf8");
|
|
40
|
+
return path;
|
|
41
|
+
}
|
|
42
|
+
function createRunId(input, pid) {
|
|
43
|
+
return `${input.projectName}:${input.mode}:${pid}:${Date.now()}`;
|
|
44
|
+
}
|
|
45
|
+
function pruneLocalghostActivity(path = getLocalghostActivityPath()) {
|
|
46
|
+
const activity = readLocalghostActivity(path);
|
|
47
|
+
const activeRuns = activity.runs.filter((run) => isProcessRunning(run.pid));
|
|
48
|
+
const pruned = activeRuns.length !== activity.runs.length;
|
|
49
|
+
if (pruned) {
|
|
50
|
+
writeLocalghostActivity({ version: LOCALGHOST_ACTIVITY_VERSION, runs: activeRuns }, path);
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
path,
|
|
54
|
+
pruned,
|
|
55
|
+
runs: activeRuns
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function listLocalghostRuns(path = getLocalghostActivityPath()) {
|
|
59
|
+
return pruneLocalghostActivity(path).runs;
|
|
60
|
+
}
|
|
61
|
+
function registerLocalghostRun(input, path = getLocalghostActivityPath()) {
|
|
62
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
63
|
+
const pid = input.pid ?? process.pid;
|
|
64
|
+
const record = {
|
|
65
|
+
id: input.id ?? createRunId(input, pid),
|
|
66
|
+
mode: input.mode,
|
|
67
|
+
pid,
|
|
68
|
+
cwd: input.cwd,
|
|
69
|
+
projectName: input.projectName,
|
|
70
|
+
startedAt: input.startedAt ?? now,
|
|
71
|
+
updatedAt: now,
|
|
72
|
+
...input.configPath ? { configPath: input.configPath } : {},
|
|
73
|
+
...input.caddyfilePath ? { caddyfilePath: input.caddyfilePath } : {},
|
|
74
|
+
...input.caddyPid ? { caddyPid: input.caddyPid } : {},
|
|
75
|
+
...input.childPid ? { childPid: input.childPid } : {},
|
|
76
|
+
...input.childCommand ? { childCommand: input.childCommand } : {},
|
|
77
|
+
...typeof input.https === "boolean" ? { https: input.https } : {},
|
|
78
|
+
...input.requestedPort ? { requestedPort: input.requestedPort } : {},
|
|
79
|
+
...input.port ? { port: input.port } : {},
|
|
80
|
+
...typeof input.dynamicPort === "boolean" ? { dynamicPort: input.dynamicPort } : {},
|
|
81
|
+
entries: input.entries
|
|
82
|
+
};
|
|
83
|
+
const current = pruneLocalghostActivity(path).runs.filter((run) => run.id !== record.id);
|
|
84
|
+
writeLocalghostActivity({ version: LOCALGHOST_ACTIVITY_VERSION, runs: [...current, record] }, path);
|
|
85
|
+
return record;
|
|
86
|
+
}
|
|
87
|
+
function unregisterLocalghostRun(id, path = getLocalghostActivityPath()) {
|
|
88
|
+
const activity = readLocalghostActivity(path);
|
|
89
|
+
const runs = activity.runs.filter((run) => run.id !== id);
|
|
90
|
+
if (runs.length !== activity.runs.length) {
|
|
91
|
+
writeLocalghostActivity({ version: LOCALGHOST_ACTIVITY_VERSION, runs }, path);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
1
95
|
// src/config.ts
|
|
2
|
-
import { existsSync, readFileSync, readdirSync } from "fs";
|
|
3
|
-
import { basename, join, resolve } from "path";
|
|
96
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, readdirSync } from "fs";
|
|
97
|
+
import { basename, join as join2, resolve } from "path";
|
|
4
98
|
|
|
5
99
|
// src/parse.ts
|
|
6
100
|
var HOST_PATTERN = /^(?=.{1,253}$)(?!-)[a-z0-9-]+(\.[a-z0-9-]+)*\.?$/i;
|
|
@@ -68,7 +162,7 @@ function resolveDevHostsPath(options = {}) {
|
|
|
68
162
|
const searchedFiles = getConfigFileCandidates(options);
|
|
69
163
|
for (const fileName2 of searchedFiles) {
|
|
70
164
|
const path = resolve(cwd, fileName2);
|
|
71
|
-
if (
|
|
165
|
+
if (existsSync2(path)) {
|
|
72
166
|
return {
|
|
73
167
|
path,
|
|
74
168
|
fileName: basename(fileName2),
|
|
@@ -104,11 +198,11 @@ function readDevHosts(options = {}) {
|
|
|
104
198
|
`Missing Localghost config in ${cwd}. Looked for ${formatSearchedFiles(resolvedPath.searchedFiles, resolvedPath.configPattern)}. Run \`localghost init\` or pass --config/--config-pattern.`
|
|
105
199
|
);
|
|
106
200
|
}
|
|
107
|
-
return parseDevHosts(
|
|
201
|
+
return parseDevHosts(readFileSync2(resolvedPath.path, "utf8"), resolvedPath.fileName);
|
|
108
202
|
}
|
|
109
203
|
function getProjectName(cwd = process.cwd()) {
|
|
110
204
|
try {
|
|
111
|
-
const pkg = JSON.parse(
|
|
205
|
+
const pkg = JSON.parse(readFileSync2(join2(cwd, "package.json"), "utf8"));
|
|
112
206
|
const name = typeof pkg.name === "string" && pkg.name ? pkg.name : "app";
|
|
113
207
|
return sanitizeProjectName(name.replace(/^@/, ""));
|
|
114
208
|
} catch {
|
|
@@ -121,18 +215,18 @@ function sanitizeProjectName(value) {
|
|
|
121
215
|
}
|
|
122
216
|
|
|
123
217
|
// src/caddy.ts
|
|
124
|
-
import { dirname as
|
|
218
|
+
import { dirname as dirname3, join as join3 } from "path";
|
|
125
219
|
import { execa } from "execa";
|
|
126
220
|
|
|
127
221
|
// src/fs.ts
|
|
128
|
-
import { mkdirSync, readFileSync as
|
|
129
|
-
import { dirname } from "path";
|
|
222
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
223
|
+
import { dirname as dirname2 } from "path";
|
|
130
224
|
function readTextFile(path) {
|
|
131
|
-
return
|
|
225
|
+
return readFileSync3(path, "utf8");
|
|
132
226
|
}
|
|
133
227
|
function writeTextFile(path, value) {
|
|
134
|
-
|
|
135
|
-
|
|
228
|
+
mkdirSync2(dirname2(path), { recursive: true });
|
|
229
|
+
writeFileSync2(path, value, "utf8");
|
|
136
230
|
return path;
|
|
137
231
|
}
|
|
138
232
|
|
|
@@ -147,41 +241,140 @@ function groupByPort(entries) {
|
|
|
147
241
|
return groups;
|
|
148
242
|
}
|
|
149
243
|
function getCaddyfilePath(cwd = process.cwd()) {
|
|
150
|
-
return
|
|
244
|
+
return join3(cwd, "ops/local/Caddyfile");
|
|
151
245
|
}
|
|
152
|
-
function renderCaddyfile(entries) {
|
|
246
|
+
function renderCaddyfile(entries, options = {}) {
|
|
153
247
|
const groups = groupByPort(entries);
|
|
248
|
+
const https = options.https === true;
|
|
154
249
|
const blocks = [...groups.entries()].sort(([leftPort], [rightPort]) => leftPort - rightPort).map(([port, group]) => {
|
|
155
|
-
const hosts = group.map((entry) => entry.host).sort().join(", ");
|
|
250
|
+
const hosts = group.map((entry) => https ? entry.host : `http://${entry.host}`).sort().join(", ");
|
|
156
251
|
return `${hosts} {
|
|
157
252
|
reverse_proxy 127.0.0.1:${port}
|
|
158
253
|
}`;
|
|
159
254
|
});
|
|
160
|
-
|
|
255
|
+
const globalOptions = https ? `{
|
|
161
256
|
local_certs
|
|
162
257
|
}
|
|
163
258
|
|
|
164
|
-
|
|
259
|
+
` : "";
|
|
260
|
+
return `${globalOptions}${blocks.join("\n\n")}
|
|
165
261
|
`;
|
|
166
262
|
}
|
|
167
|
-
async function writeCaddyfile(entries, cwd = process.cwd()) {
|
|
263
|
+
async function writeCaddyfile(entries, cwd = process.cwd(), options = {}) {
|
|
168
264
|
const path = getCaddyfilePath(cwd);
|
|
169
|
-
writeTextFile(path, renderCaddyfile(entries));
|
|
265
|
+
writeTextFile(path, renderCaddyfile(entries, options));
|
|
170
266
|
return path;
|
|
171
267
|
}
|
|
172
268
|
async function validateCaddyfile(path) {
|
|
173
269
|
await execa("caddy", ["validate", "--config", path], {
|
|
174
|
-
cwd:
|
|
270
|
+
cwd: dirname3(path),
|
|
175
271
|
stdio: "inherit"
|
|
176
272
|
});
|
|
177
273
|
}
|
|
178
274
|
async function runCaddy(path) {
|
|
179
275
|
await execa("caddy", ["run", "--config", path], {
|
|
180
|
-
cwd:
|
|
276
|
+
cwd: dirname3(path),
|
|
277
|
+
stdio: "inherit"
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
function startCaddy(path) {
|
|
281
|
+
return execa("caddy", ["run", "--config", path], {
|
|
282
|
+
cwd: dirname3(path),
|
|
181
283
|
stdio: "inherit"
|
|
182
284
|
});
|
|
183
285
|
}
|
|
184
286
|
|
|
287
|
+
// src/port.ts
|
|
288
|
+
import { createServer } from "net";
|
|
289
|
+
async function isPortAvailable(port, host = "127.0.0.1") {
|
|
290
|
+
return new Promise((resolve2) => {
|
|
291
|
+
const server = createServer();
|
|
292
|
+
server.once("error", () => {
|
|
293
|
+
resolve2(false);
|
|
294
|
+
});
|
|
295
|
+
server.once("listening", () => {
|
|
296
|
+
server.close(() => resolve2(true));
|
|
297
|
+
});
|
|
298
|
+
server.listen(port, host);
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
async function findAvailablePort(startPort, options = {}) {
|
|
302
|
+
const host = options.host ?? "127.0.0.1";
|
|
303
|
+
const maxAttempts = options.maxAttempts ?? 50;
|
|
304
|
+
for (let offset = 0; offset < maxAttempts; offset += 1) {
|
|
305
|
+
const port = startPort + offset;
|
|
306
|
+
if (await isPortAvailable(port, host)) {
|
|
307
|
+
return port;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
throw new Error(`No available port found from ${startPort} to ${startPort + maxAttempts - 1}.`);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// src/context.ts
|
|
314
|
+
function parsePort(value) {
|
|
315
|
+
if (!value) return void 0;
|
|
316
|
+
const port = Number.parseInt(value, 10);
|
|
317
|
+
return Number.isInteger(port) && port > 0 && port <= 65535 ? port : void 0;
|
|
318
|
+
}
|
|
319
|
+
function envPort() {
|
|
320
|
+
return parsePort(process.env.LOCALGHOST_PORT) ?? parsePort(process.env.VITE_PORT);
|
|
321
|
+
}
|
|
322
|
+
function envDynamicPort() {
|
|
323
|
+
const value = process.env.LOCALGHOST_DYNAMIC_PORT;
|
|
324
|
+
if (!value) return void 0;
|
|
325
|
+
return ["1", "true", "yes", "on"].includes(value.toLowerCase());
|
|
326
|
+
}
|
|
327
|
+
function readOptionsFromContext(options) {
|
|
328
|
+
return {
|
|
329
|
+
cwd: options.cwd ?? process.cwd(),
|
|
330
|
+
...options.fileName ? { fileName: options.fileName } : {},
|
|
331
|
+
...options.configFiles ? { configFiles: options.configFiles } : {},
|
|
332
|
+
...options.configPattern ? { configPattern: options.configPattern } : {}
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
function withRuntimePort(entries, requestedPort, port) {
|
|
336
|
+
if (requestedPort === port) return entries;
|
|
337
|
+
const hasRequestedPort = entries.some((entry) => entry.port === requestedPort);
|
|
338
|
+
if (!hasRequestedPort) return entries;
|
|
339
|
+
return entries.map((entry) => entry.port === requestedPort ? { ...entry, port } : entry);
|
|
340
|
+
}
|
|
341
|
+
function uniqueHosts(entries) {
|
|
342
|
+
return [...new Set(entries.map((entry) => entry.host))];
|
|
343
|
+
}
|
|
344
|
+
function defineLocalghostConfig(config) {
|
|
345
|
+
return config;
|
|
346
|
+
}
|
|
347
|
+
async function resolveLocalghostContext(options = {}) {
|
|
348
|
+
const cwd = options.cwd ?? process.cwd();
|
|
349
|
+
const readOptions = readOptionsFromContext({ ...options, cwd });
|
|
350
|
+
const resolvedPath = resolveDevHostsPath(readOptions);
|
|
351
|
+
const configEntries = readDevHosts(readOptions);
|
|
352
|
+
const requestedPort = options.port ?? envPort() ?? configEntries[0]?.port ?? 5173;
|
|
353
|
+
const dynamicPort = options.dynamicPort ?? envDynamicPort() ?? false;
|
|
354
|
+
const bindHost = options.bindHost ?? "127.0.0.1";
|
|
355
|
+
const probeHost = typeof bindHost === "string" ? bindHost : "127.0.0.1";
|
|
356
|
+
const port = dynamicPort ? await findAvailablePort(requestedPort, { host: probeHost }) : requestedPort;
|
|
357
|
+
const entries = withRuntimePort(configEntries, requestedPort, port);
|
|
358
|
+
const hosts = uniqueHosts(entries);
|
|
359
|
+
const primaryHost = options.primaryHost ?? entries.find((entry) => entry.port === port)?.host ?? hosts[0] ?? `${sanitizeProjectName(getProjectName(cwd))}.localhost`;
|
|
360
|
+
return {
|
|
361
|
+
cwd,
|
|
362
|
+
projectName: sanitizeProjectName(options.project ?? getProjectName(cwd)),
|
|
363
|
+
readOptions,
|
|
364
|
+
configPath: resolvedPath.path,
|
|
365
|
+
configFileName: resolvedPath.fileName,
|
|
366
|
+
configEntries,
|
|
367
|
+
entries,
|
|
368
|
+
hosts,
|
|
369
|
+
requestedPort,
|
|
370
|
+
port,
|
|
371
|
+
dynamicPort,
|
|
372
|
+
bindHost,
|
|
373
|
+
primaryHost,
|
|
374
|
+
https: options.https === true
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
|
|
185
378
|
// src/doctor.ts
|
|
186
379
|
import { execa as execa2 } from "execa";
|
|
187
380
|
async function checkCaddy() {
|
|
@@ -208,10 +401,34 @@ async function runDoctor() {
|
|
|
208
401
|
};
|
|
209
402
|
}
|
|
210
403
|
|
|
404
|
+
// src/env.ts
|
|
405
|
+
var PRODUCTION_ENV_KEYS = ["NODE_ENV", "VERCEL_ENV", "NETLIFY", "CF_PAGES_BRANCH", "LOCALGHOST_ENV"];
|
|
406
|
+
function getProductionReason(env = process.env) {
|
|
407
|
+
if (env.LOCALGHOST_ENV === "production") return "LOCALGHOST_ENV=production";
|
|
408
|
+
if (env.NODE_ENV === "production") return "NODE_ENV=production";
|
|
409
|
+
if (env.VERCEL_ENV === "production") return "VERCEL_ENV=production";
|
|
410
|
+
if (env.NETLIFY === "true" && env.CONTEXT === "production") return "NETLIFY=true and CONTEXT=production";
|
|
411
|
+
if (env.CF_PAGES_BRANCH && env.CF_PAGES_BRANCH === env.CF_PAGES_PRODUCTION_BRANCH) {
|
|
412
|
+
return "CF_PAGES_BRANCH matches CF_PAGES_PRODUCTION_BRANCH";
|
|
413
|
+
}
|
|
414
|
+
return null;
|
|
415
|
+
}
|
|
416
|
+
function isProductionLike(env = process.env) {
|
|
417
|
+
return getProductionReason(env) !== null;
|
|
418
|
+
}
|
|
419
|
+
function assertLocalDevelopment(command, env = process.env) {
|
|
420
|
+
const reason = getProductionReason(env);
|
|
421
|
+
if (!reason) return;
|
|
422
|
+
throw new Error(`Localghost only runs in local development. Refusing \`${command}\` because ${reason}.`);
|
|
423
|
+
}
|
|
424
|
+
function getProductionEnvKeys() {
|
|
425
|
+
return PRODUCTION_ENV_KEYS;
|
|
426
|
+
}
|
|
427
|
+
|
|
211
428
|
// src/hosts-file.ts
|
|
212
|
-
import { writeFileSync as
|
|
429
|
+
import { writeFileSync as writeFileSync3 } from "fs";
|
|
213
430
|
import { tmpdir } from "os";
|
|
214
|
-
import { join as
|
|
431
|
+
import { join as join4 } from "path";
|
|
215
432
|
import { execa as execa3 } from "execa";
|
|
216
433
|
function escapeRegExp(value) {
|
|
217
434
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -253,8 +470,8 @@ function removeManagedBlock(existing, projectName) {
|
|
|
253
470
|
}
|
|
254
471
|
async function writeSystemHostsFile(hostsPath, next, projectName) {
|
|
255
472
|
const sanitizedProjectName = sanitizeProjectName(projectName);
|
|
256
|
-
const tempPath =
|
|
257
|
-
|
|
473
|
+
const tempPath = join4(tmpdir(), `localghost-${sanitizedProjectName}-hosts`);
|
|
474
|
+
writeFileSync3(tempPath, next, "utf8");
|
|
258
475
|
if (process.platform === "win32") {
|
|
259
476
|
throw new Error(`Windows support: run as administrator and copy ${tempPath} to ${hostsPath}.`);
|
|
260
477
|
}
|
|
@@ -286,11 +503,11 @@ async function removeSystemHosts(projectName) {
|
|
|
286
503
|
}
|
|
287
504
|
|
|
288
505
|
// src/init.ts
|
|
289
|
-
import { existsSync as
|
|
290
|
-
import { join as
|
|
506
|
+
import { existsSync as existsSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
507
|
+
import { join as join5 } from "path";
|
|
291
508
|
function detectPackageManager(cwd = process.cwd()) {
|
|
292
|
-
if (
|
|
293
|
-
if (
|
|
509
|
+
if (existsSync3(join5(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
510
|
+
if (existsSync3(join5(cwd, "yarn.lock"))) return "yarn";
|
|
294
511
|
return "npm";
|
|
295
512
|
}
|
|
296
513
|
function packageRunCommand(packageManager, script) {
|
|
@@ -315,7 +532,7 @@ function renderConfig(options) {
|
|
|
315
532
|
}
|
|
316
533
|
function readPackageJson(path) {
|
|
317
534
|
try {
|
|
318
|
-
return JSON.parse(
|
|
535
|
+
return JSON.parse(readFileSync4(path, "utf8"));
|
|
319
536
|
} catch {
|
|
320
537
|
return null;
|
|
321
538
|
}
|
|
@@ -336,17 +553,24 @@ function updatePackageScripts(packageJsonPath, configFile) {
|
|
|
336
553
|
...scripts,
|
|
337
554
|
"localghost:setup": scripts["localghost:setup"] ?? `localghost setup${configFlag}`,
|
|
338
555
|
"localghost:proxy": scripts["localghost:proxy"] ?? `localghost dev${configFlag}`,
|
|
556
|
+
"localghost:proxy:https": scripts["localghost:proxy:https"] ?? `localghost dev${configFlag} --https`,
|
|
557
|
+
"localghost:run": scripts["localghost:run"] ?? `localghost run${configFlag} --`,
|
|
558
|
+
"localghost:ready": scripts["localghost:ready"] ?? `localghost status${configFlag} --ready`,
|
|
559
|
+
"localghost:ps": scripts["localghost:ps"] ?? "localghost ps",
|
|
339
560
|
"localghost:print": scripts["localghost:print"] ?? `localghost print${configFlag}`,
|
|
340
561
|
"localghost:routes": scripts["localghost:routes"] ?? `localghost routes${configFlag}`,
|
|
341
562
|
"localghost:status": scripts["localghost:status"] ?? "localghost status",
|
|
563
|
+
"localghost:reset": scripts["localghost:reset"] ?? "localghost reset",
|
|
342
564
|
"localghost:teardown": scripts["localghost:teardown"] ?? "localghost teardown",
|
|
343
565
|
"localghost:doctor": scripts["localghost:doctor"] ?? "localghost doctor",
|
|
344
|
-
"localghost:update": scripts["localghost:update"] ?? "localghost update"
|
|
566
|
+
"localghost:update": scripts["localghost:update"] ?? "localghost update",
|
|
567
|
+
"caddy:setup": scripts["caddy:setup"] ?? `localghost setup${configFlag}`,
|
|
568
|
+
"caddy:dev": scripts["caddy:dev"] ?? `localghost dev${configFlag}`
|
|
345
569
|
};
|
|
346
570
|
const changed = JSON.stringify(scripts) !== JSON.stringify(nextScripts);
|
|
347
571
|
if (!changed) return false;
|
|
348
572
|
pkg.scripts = nextScripts;
|
|
349
|
-
|
|
573
|
+
writeFileSync4(packageJsonPath, `${JSON.stringify(pkg, null, 2)}
|
|
350
574
|
`, "utf8");
|
|
351
575
|
return true;
|
|
352
576
|
}
|
|
@@ -359,8 +583,8 @@ function initLocalghost(options = {}) {
|
|
|
359
583
|
const apiPort = options.apiPort ?? 8787;
|
|
360
584
|
const packageManager = options.packageManager ?? detectPackageManager(cwd);
|
|
361
585
|
const configFile = options.configFile ?? LOCALGHOST_CONFIG_FILE;
|
|
362
|
-
const configPath =
|
|
363
|
-
const configExists =
|
|
586
|
+
const configPath = join5(cwd, configFile);
|
|
587
|
+
const configExists = existsSync3(configPath);
|
|
364
588
|
if (configExists && !options.force) {
|
|
365
589
|
return {
|
|
366
590
|
configPath,
|
|
@@ -370,22 +594,24 @@ function initLocalghost(options = {}) {
|
|
|
370
594
|
nextSteps: [
|
|
371
595
|
packageRunCommand(packageManager, "localghost:doctor"),
|
|
372
596
|
packageRunCommand(packageManager, "localghost:setup"),
|
|
597
|
+
packageRunCommand(packageManager, "localghost:ready"),
|
|
373
598
|
packageRunCommand(packageManager, "localghost:proxy")
|
|
374
599
|
]
|
|
375
600
|
};
|
|
376
601
|
}
|
|
377
602
|
writeTextFile(configPath, renderConfig({ host, port, apiHost, apiPort }));
|
|
378
|
-
const packageJsonPath =
|
|
603
|
+
const packageJsonPath = join5(cwd, "package.json");
|
|
379
604
|
const packageJsonChanged = options.writeScripts ? updatePackageScripts(packageJsonPath, configFile) : false;
|
|
380
605
|
return {
|
|
381
606
|
configPath,
|
|
382
607
|
configCreated: true,
|
|
383
|
-
...
|
|
608
|
+
...existsSync3(packageJsonPath) ? { packageJsonPath } : {},
|
|
384
609
|
packageJsonChanged,
|
|
385
610
|
packageManager,
|
|
386
611
|
nextSteps: [
|
|
387
612
|
packageRunCommand(packageManager, "localghost:doctor"),
|
|
388
613
|
packageRunCommand(packageManager, "localghost:setup"),
|
|
614
|
+
packageRunCommand(packageManager, "localghost:ready"),
|
|
389
615
|
packageRunCommand(packageManager, "localghost:proxy")
|
|
390
616
|
]
|
|
391
617
|
};
|
|
@@ -393,7 +619,7 @@ function initLocalghost(options = {}) {
|
|
|
393
619
|
|
|
394
620
|
// src/routes.ts
|
|
395
621
|
function getDomainRoutes(entries, options = {}) {
|
|
396
|
-
const protocol = options.https ===
|
|
622
|
+
const protocol = options.https === true ? "https" : "http";
|
|
397
623
|
return [...entries].sort((left, right) => left.host.localeCompare(right.host) || left.port - right.port).map((entry) => ({
|
|
398
624
|
host: entry.host,
|
|
399
625
|
port: entry.port,
|
|
@@ -413,15 +639,15 @@ function formatDomainRoutes(entries, options = {}) {
|
|
|
413
639
|
}
|
|
414
640
|
|
|
415
641
|
// src/state.ts
|
|
416
|
-
import { existsSync as
|
|
417
|
-
import { join as
|
|
642
|
+
import { existsSync as existsSync4 } from "fs";
|
|
643
|
+
import { join as join6 } from "path";
|
|
418
644
|
var LOCALGHOST_STATE_FILE = "ops/local/localghost-state.json";
|
|
419
645
|
function getLocalghostStatePath(cwd = process.cwd()) {
|
|
420
|
-
return
|
|
646
|
+
return join6(cwd, LOCALGHOST_STATE_FILE);
|
|
421
647
|
}
|
|
422
648
|
function readLocalghostState(cwd = process.cwd()) {
|
|
423
649
|
const path = getLocalghostStatePath(cwd);
|
|
424
|
-
if (!
|
|
650
|
+
if (!existsSync4(path)) return null;
|
|
425
651
|
return JSON.parse(readTextFile(path));
|
|
426
652
|
}
|
|
427
653
|
function writeLocalghostState(cwd, state) {
|
|
@@ -432,11 +658,11 @@ function writeLocalghostState(cwd, state) {
|
|
|
432
658
|
}
|
|
433
659
|
|
|
434
660
|
// src/update-check.ts
|
|
435
|
-
import { existsSync as
|
|
436
|
-
import { homedir } from "os";
|
|
437
|
-
import { dirname as
|
|
661
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
|
|
662
|
+
import { homedir as homedir2 } from "os";
|
|
663
|
+
import { dirname as dirname4, join as join7 } from "path";
|
|
438
664
|
var LOCALGHOST_PACKAGE_NAME = "@hamedb89/localghost";
|
|
439
|
-
var LOCALGHOST_VERSION = "0.1.
|
|
665
|
+
var LOCALGHOST_VERSION = "0.1.6";
|
|
440
666
|
var UPDATE_CHECK_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
441
667
|
var UPDATE_CHECK_NOTIFY_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
442
668
|
var UPDATE_CHECK_TIMEOUT_MS = 900;
|
|
@@ -448,21 +674,21 @@ function isUpdateCheckDisabled(env = process.env) {
|
|
|
448
674
|
}
|
|
449
675
|
function getUpdateCheckCachePath(env = process.env) {
|
|
450
676
|
if (env.LOCALGHOST_UPDATE_CHECK_CACHE) return env.LOCALGHOST_UPDATE_CHECK_CACHE;
|
|
451
|
-
const cacheRoot = env.XDG_CACHE_HOME ||
|
|
452
|
-
return
|
|
677
|
+
const cacheRoot = env.XDG_CACHE_HOME || join7(homedir2(), ".cache");
|
|
678
|
+
return join7(cacheRoot, "localghost", "update-check.json");
|
|
453
679
|
}
|
|
454
680
|
function readCache(path = getUpdateCheckCachePath()) {
|
|
455
|
-
if (!
|
|
681
|
+
if (!existsSync5(path)) return null;
|
|
456
682
|
try {
|
|
457
|
-
return JSON.parse(
|
|
683
|
+
return JSON.parse(readFileSync5(path, "utf8"));
|
|
458
684
|
} catch {
|
|
459
685
|
return null;
|
|
460
686
|
}
|
|
461
687
|
}
|
|
462
688
|
function writeCache(cache, path = getUpdateCheckCachePath()) {
|
|
463
689
|
try {
|
|
464
|
-
|
|
465
|
-
|
|
690
|
+
mkdirSync3(dirname4(path), { recursive: true });
|
|
691
|
+
writeFileSync5(path, `${JSON.stringify(cache, null, 2)}
|
|
466
692
|
`, "utf8");
|
|
467
693
|
} catch {
|
|
468
694
|
}
|
|
@@ -598,6 +824,7 @@ ${message}`);
|
|
|
598
824
|
markUpdateNotified(result, cachePath);
|
|
599
825
|
}
|
|
600
826
|
export {
|
|
827
|
+
LOCALGHOST_ACTIVITY_VERSION,
|
|
601
828
|
LOCALGHOST_CONFIG_FILE,
|
|
602
829
|
LOCALGHOST_PACKAGE_NAME,
|
|
603
830
|
LOCALGHOST_STATE_FILE,
|
|
@@ -605,10 +832,13 @@ export {
|
|
|
605
832
|
UPDATE_CHECK_CACHE_TTL_MS,
|
|
606
833
|
UPDATE_CHECK_NOTIFY_TTL_MS,
|
|
607
834
|
UPDATE_CHECK_TIMEOUT_MS,
|
|
835
|
+
assertLocalDevelopment,
|
|
608
836
|
checkCaddy,
|
|
609
837
|
checkForUpdate,
|
|
610
838
|
compareVersions,
|
|
839
|
+
defineLocalghostConfig,
|
|
611
840
|
detectPackageManager,
|
|
841
|
+
findAvailablePort,
|
|
612
842
|
findLocalMdnsHosts,
|
|
613
843
|
formatDomainRoutes,
|
|
614
844
|
formatUpdateMessage,
|
|
@@ -616,33 +846,47 @@ export {
|
|
|
616
846
|
getConfigFileCandidates,
|
|
617
847
|
getDevHostsPath,
|
|
618
848
|
getDomainRoutes,
|
|
849
|
+
getLocalghostActivityPath,
|
|
619
850
|
getLocalghostStatePath,
|
|
851
|
+
getProductionEnvKeys,
|
|
852
|
+
getProductionReason,
|
|
620
853
|
getProjectName,
|
|
621
854
|
getSystemHostsPath,
|
|
622
855
|
getUpdateCheckCachePath,
|
|
623
856
|
initLocalghost,
|
|
624
857
|
isNewerVersion,
|
|
858
|
+
isPortAvailable,
|
|
859
|
+
isProcessRunning,
|
|
860
|
+
isProductionLike,
|
|
625
861
|
isUpdateCheckDisabled,
|
|
862
|
+
listLocalghostRuns,
|
|
626
863
|
markUpdateNotified,
|
|
627
864
|
maybeNotifyAboutUpdate,
|
|
628
865
|
packageAddCommand,
|
|
629
866
|
packageRunCommand,
|
|
630
867
|
parseDevHosts,
|
|
868
|
+
pruneLocalghostActivity,
|
|
631
869
|
readDevHosts,
|
|
870
|
+
readLocalghostActivity,
|
|
632
871
|
readLocalghostState,
|
|
872
|
+
registerLocalghostRun,
|
|
633
873
|
removeManagedBlock,
|
|
634
874
|
removeSystemHosts,
|
|
635
875
|
renderCaddyfile,
|
|
636
876
|
renderHostsBlock,
|
|
637
877
|
resolveDevHostsPath,
|
|
878
|
+
resolveLocalghostContext,
|
|
638
879
|
runCaddy,
|
|
639
880
|
runDoctor,
|
|
640
881
|
sanitizeProjectName,
|
|
641
882
|
shouldNotifyAboutUpdate,
|
|
883
|
+
startCaddy,
|
|
884
|
+
unregisterLocalghostRun,
|
|
642
885
|
updateSystemHosts,
|
|
643
886
|
upsertManagedBlock,
|
|
644
887
|
validateCaddyfile,
|
|
645
888
|
writeCaddyfile,
|
|
889
|
+
writeLocalghostActivity,
|
|
646
890
|
writeLocalghostState
|
|
647
891
|
};
|
|
648
892
|
//# sourceMappingURL=index.js.map
|