@hamedb89/localghost 0.1.9 → 0.1.10
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 +43 -445
- package/dist/cli.js +8 -4
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +8 -4
- package/dist/index.js.map +1 -1
- package/dist/vite.js +9 -4
- package/dist/vite.js.map +1 -1
- package/docs/flows.md +1 -1
- package/docs/ghost-tunnel.md +45 -1
- package/docs/localghost.1.md +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,46 +9,18 @@ Buh. Friendly local hostnames for app repos.
|
|
|
9
9
|
[](https://github.com/hamedb89/localghost/actions/workflows/ci.yml)
|
|
10
10
|
[](https://github.com/hamedb89/localghost/actions/workflows/pages.yml)
|
|
11
11
|
[](https://github.com/hamedb89/localghost/actions/workflows/publish-npm.yml)
|
|
12
|
-
[](https://www.npmjs.com/package/@hamedb89/localghost)
|
|
13
13
|
|
|
14
|
-
Localghost is a tiny Node.js CLI for
|
|
14
|
+
Localghost is a tiny Node.js CLI for clean local app domains. Add it as a dev dependency, keep running the command your team already knows, and use `http://app.localhost/` instead of remembering which port belongs to which process.
|
|
15
15
|
|
|
16
|
-
[Website](https://hamedb89.github.io/localghost/) · [npm](https://www.npmjs.com/package/@hamedb89/localghost) · [GitHub](https://github.com/hamedb89/localghost)
|
|
16
|
+
[Website](https://hamedb89.github.io/localghost/) · [Docs](https://hamedb89.github.io/localghost/docs/) · [npm](https://www.npmjs.com/package/@hamedb89/localghost) · [GitHub](https://github.com/hamedb89/localghost)
|
|
17
17
|
|
|
18
|
-
##
|
|
19
|
-
|
|
20
|
-
- Creates and reads `.localghost` in your app repo.
|
|
21
|
-
- Lets repos choose explicit config files or filename patterns when `.localghost` is not enough.
|
|
22
|
-
- Updates only a managed Localghost block in `/etc/hosts` during explicit setup.
|
|
23
|
-
- Generates `ops/local/Caddyfile` for local reverse proxying. HTTP is the default; HTTPS is explicit with `--https` or `--ssl`.
|
|
24
|
-
- Checks whether Caddy is installed, but does not run Homebrew for you.
|
|
25
|
-
- Provides a Vite plugin that sets explicit `server.allowedHosts` entries.
|
|
26
|
-
- Defaults Vite dev to the configured Localghost domain and no-ops during production/build.
|
|
27
|
-
- Prints parsed config and project-local state as JSON for scripts, Codex, agents, and future MCP tools.
|
|
28
|
-
- Checks npm for newer Localghost releases at most once per day, with an explicit opt-out.
|
|
29
|
-
|
|
30
|
-
## Trust
|
|
31
|
-
|
|
32
|
-
- CI runs typecheck, build, site build, and npm package dry-run on Node 20 and 22.
|
|
33
|
-
- GitHub Pages is deployed by Actions from the checked-in `site/` and `assets/` sources.
|
|
34
|
-
- Preview the exact Pages artifact locally with `npm run site:serve`, then open `http://127.0.0.1:4173/`.
|
|
35
|
-
- npm publish is guarded by `prepublishOnly` and the release workflow publishes with npm provenance.
|
|
36
|
-
- Runtime dependencies are intentionally small: `commander` for the CLI and `execa` for process execution. Vite is an optional peer dependency for the Vite plugin.
|
|
37
|
-
- No postinstall scripts, hidden Homebrew installs, or broad hosts-file rewrites.
|
|
38
|
-
- Update checks are best-effort, cached for 24 hours, and can be disabled with `LOCALGHOST_NO_UPDATE_CHECK=1` or `--no-update-check`.
|
|
39
|
-
|
|
40
|
-
<p align="center">
|
|
41
|
-
<img src="./assets/localghost-app-icon.png" alt="Localghost app icon" width="180">
|
|
42
|
-
</p>
|
|
43
|
-
|
|
44
|
-
## Start Here
|
|
18
|
+
## Quick Start
|
|
45
19
|
|
|
46
20
|
```sh
|
|
47
21
|
yarn add -D @hamedb89/localghost
|
|
48
22
|
```
|
|
49
23
|
|
|
50
|
-
That is the entrypoint you are optimizing for: install the dev dependency, keep using the dev command your team already knows, and let Localghost handle the local-domain setup around it.
|
|
51
|
-
|
|
52
24
|
For Vite apps, add the plugin once:
|
|
53
25
|
|
|
54
26
|
```ts
|
|
@@ -60,15 +32,13 @@ export default defineConfig({
|
|
|
60
32
|
});
|
|
61
33
|
```
|
|
62
34
|
|
|
63
|
-
|
|
35
|
+
Then keep using the command your repo already expects:
|
|
64
36
|
|
|
65
37
|
```sh
|
|
66
38
|
yarn dev
|
|
67
39
|
```
|
|
68
40
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
On the first interactive `yarn dev`, Localghost can create `.localghost`, explain the `/etc/hosts` change, write the local Caddyfile, and then print the browser-facing URL:
|
|
41
|
+
On the first interactive run, Localghost can create `.localghost`, explain the `/etc/hosts` change, write `ops/local/Caddyfile`, and print the browser-facing URL:
|
|
72
42
|
|
|
73
43
|
```txt
|
|
74
44
|
localghost
|
|
@@ -77,7 +47,7 @@ also: http://www.app.localhost/
|
|
|
77
47
|
target: http://127.0.0.1:5173/
|
|
78
48
|
```
|
|
79
49
|
|
|
80
|
-
|
|
50
|
+
For non-Vite apps, wrap your raw dev command:
|
|
81
51
|
|
|
82
52
|
```json
|
|
83
53
|
{
|
|
@@ -88,413 +58,67 @@ If your project does not use Vite, or you want one command that starts Caddy and
|
|
|
88
58
|
}
|
|
89
59
|
```
|
|
90
60
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
```sh
|
|
94
|
-
yarn dev
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
## Configuration
|
|
98
|
-
|
|
99
|
-
Most apps only need a `.localghost` file when they want explicit hostnames or multiple services:
|
|
100
|
-
|
|
101
|
-
```txt
|
|
102
|
-
# Buh. Friendly names for local services.
|
|
103
|
-
# Format: <host> <port>
|
|
104
|
-
app.localhost 5173
|
|
105
|
-
www.app.localhost 5173
|
|
106
|
-
api.app.localhost 8787
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
If `.localghost` is missing, the Vite plugin can prompt to create it during `yarn dev`. You can also create it directly:
|
|
110
|
-
|
|
111
|
-
```sh
|
|
112
|
-
yarn localghost init
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
Check the machine:
|
|
116
|
-
|
|
117
|
-
```sh
|
|
118
|
-
yarn localghost doctor
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
If Caddy is missing, Localghost prints:
|
|
122
|
-
|
|
123
|
-
```txt
|
|
124
|
-
Caddy: missing
|
|
125
|
-
Run: brew install caddy
|
|
126
|
-
Localghost will not install it for you. No surprise spells.
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
Prepare or repair the machine setup directly:
|
|
130
|
-
|
|
131
|
-
```sh
|
|
132
|
-
yarn localghost setup
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
Check that the hosts block and Caddyfile are ready:
|
|
136
|
-
|
|
137
|
-
```sh
|
|
138
|
-
yarn localghost status --ready
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
Run only the proxy when your app server is started separately:
|
|
142
|
-
|
|
143
|
-
```sh
|
|
144
|
-
yarn localghost dev
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
Use HTTPS only when you explicitly want Caddy local certificates:
|
|
148
|
-
|
|
149
|
-
```sh
|
|
150
|
-
yarn localghost dev --https
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
Trust Caddy's local HTTPS CA when you want browsers to stop showing local certificate warnings:
|
|
154
|
-
|
|
155
|
-
```sh
|
|
156
|
-
yarn localghost trust
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
Reset generated setup without deleting `.localghost`:
|
|
160
|
-
|
|
161
|
-
```sh
|
|
162
|
-
yarn localghost reset
|
|
163
|
-
yarn localghost setup
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
Prefer `.localhost` names. `.local` is supported, but Localghost warns because `.local` can collide with mDNS/Bonjour.
|
|
167
|
-
|
|
168
|
-
## Config Files
|
|
169
|
-
|
|
170
|
-
By default, Localghost reads `.localghost` from the project root. Repos that need another name can be explicit:
|
|
171
|
-
|
|
172
|
-
```sh
|
|
173
|
-
localghost print --config .localghost.preview
|
|
174
|
-
localghost setup --config .localghost.preview
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
You can pass `--config` more than once. Localghost uses the first file that exists:
|
|
178
|
-
|
|
179
|
-
```sh
|
|
180
|
-
localghost print --config .localghost.private --config .localghost
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
You can also search project-root filenames with a regular expression:
|
|
184
|
-
|
|
185
|
-
```sh
|
|
186
|
-
localghost print --config-pattern '^\.localghost\.(private|preview)$'
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
The Vite plugin accepts the same shape through `fileName`, `configFiles`, or `configPattern`. If you run `localghost init --config .localghost.preview --write-scripts`, generated package scripts include the matching `--config` flag.
|
|
190
|
-
|
|
191
|
-
## Package Scripts
|
|
192
|
-
|
|
193
|
-
`localghost init --write-scripts` adds these scripts when they are missing:
|
|
194
|
-
|
|
195
|
-
```json
|
|
196
|
-
{
|
|
197
|
-
"scripts": {
|
|
198
|
-
"localghost:setup": "localghost setup",
|
|
199
|
-
"localghost:proxy": "localghost dev",
|
|
200
|
-
"localghost:proxy:https": "localghost dev --https",
|
|
201
|
-
"localghost:run": "localghost run --",
|
|
202
|
-
"localghost:ready": "localghost status --ready",
|
|
203
|
-
"localghost:trust": "localghost trust",
|
|
204
|
-
"localghost:ps": "localghost ps",
|
|
205
|
-
"localghost:print": "localghost print",
|
|
206
|
-
"localghost:routes": "localghost routes",
|
|
207
|
-
"localghost:status": "localghost status",
|
|
208
|
-
"localghost:reset": "localghost reset",
|
|
209
|
-
"localghost:teardown": "localghost teardown",
|
|
210
|
-
"localghost:doctor": "localghost doctor",
|
|
211
|
-
"localghost:update": "localghost update",
|
|
212
|
-
"caddy:setup": "localghost setup",
|
|
213
|
-
"caddy:dev": "localghost dev"
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
A full app might compose them with its own servers:
|
|
219
|
-
|
|
220
|
-
```json
|
|
221
|
-
{
|
|
222
|
-
"scripts": {
|
|
223
|
-
"dev": "localghost run -- yarn dev:raw",
|
|
224
|
-
"dev:raw": "vite"
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
In Turborepo, let Localghost wrap the dev runner and keep dev uncached:
|
|
230
|
-
|
|
231
|
-
```json
|
|
232
|
-
{
|
|
233
|
-
"scripts": {
|
|
234
|
-
"dev": "localghost run -- yarn dev:raw",
|
|
235
|
-
"dev:raw": "turbo dev"
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
Then keep persistent dev tasks uncached:
|
|
241
|
-
|
|
242
|
-
```json
|
|
243
|
-
{
|
|
244
|
-
"tasks": {
|
|
245
|
-
"dev": { "cache": false, "persistent": true }
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
`localghost run` resolves one shared Localghost context, starts Caddy, handles the optional HTTPS trust prompt, then starts the child command. That keeps Localghost setup/proxy output before Vite's ready log. It passes the selected port to the child command through `LOCALGHOST_PORT` and `VITE_PORT`, and stops Caddy when the child exits. Dynamic ports are on by default: Localghost starts at the configured port, checks `127.0.0.1:<port>`, and walks upward until it finds a free port. Use `--dynamic-port=no` when you want strict fixed-port behavior.
|
|
251
|
-
|
|
252
|
-
Most repos do not need `localghost.config.mjs`. Localghost derives `project` from `package.json`, defaults to port `5173`, keeps HTTPS off by default, enables dynamic ports by default, and adds `www.` aliases by default. Add `localghost.config.mjs` only when you want to override those defaults:
|
|
253
|
-
|
|
254
|
-
```js
|
|
255
|
-
import { defineLocalghostConfig } from "@hamedb89/localghost";
|
|
256
|
-
|
|
257
|
-
export default defineLocalghostConfig({
|
|
258
|
-
https: true
|
|
259
|
-
});
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
Then the daily script can stay small:
|
|
263
|
-
|
|
264
|
-
```json
|
|
265
|
-
{
|
|
266
|
-
"scripts": {
|
|
267
|
-
"dev": "localghost run -- yarn dev:raw",
|
|
268
|
-
"dev:raw": "vite"
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
`www.` aliases are enabled by default. A `.localghost` entry like `app.localhost 5173` also sets up `www.app.localhost` unless `wwwAlias: false` is set in `localghost.config.mjs`.
|
|
274
|
-
|
|
275
|
-
`ghostTunnel` is the production opt-in for a wildcard product entrypoint on top of your deployed Vite app. The default namespace is `<route>-<project>-<owner>.ghost.<domain>`, and omitted domains are shown as `*` in logs:
|
|
276
|
-
|
|
277
|
-
```js
|
|
278
|
-
import { defineLocalghostConfig } from "@hamedb89/localghost";
|
|
279
|
-
|
|
280
|
-
export default defineLocalghostConfig({
|
|
281
|
-
ghostTunnel: {
|
|
282
|
-
domains: "socialworkouts.app",
|
|
283
|
-
mode: "manual"
|
|
284
|
-
}
|
|
285
|
-
});
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
With `ghostTunnel: { domains }`, local route and Vite startup logs use local defaults for `route`, `project`, and `owner`, then fill the configured domain:
|
|
289
|
-
|
|
290
|
-
```txt
|
|
291
|
-
localghost ghost tunnel
|
|
292
|
-
mode: manual
|
|
293
|
-
expected: https://app-decision-layer-hamed.ghost.socialworkouts.app/
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
Without `domains`, the expected URL stays wildcarded:
|
|
297
|
-
|
|
298
|
-
```txt
|
|
299
|
-
localghost ghost tunnel
|
|
300
|
-
mode: manual
|
|
301
|
-
expected: https://app-decision-layer-hamed.ghost.*/
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
`ghostTunnel: "manual"` and `ghostTunnel: "public"` are shorthand modes. `manual` is the default; use `enabled: false` to keep domains/config in the file without exposing the tunnel surface.
|
|
305
|
-
|
|
306
|
-
Use object form to override defaults or provide a concrete preview URL:
|
|
307
|
-
|
|
308
|
-
```js
|
|
309
|
-
export default defineLocalghostConfig({
|
|
310
|
-
ghostTunnel: {
|
|
311
|
-
domains: "socialworkouts.app",
|
|
312
|
-
preview: {
|
|
313
|
-
route: "plan",
|
|
314
|
-
project: "summer-base",
|
|
315
|
-
owner: "hamed"
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
});
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
Production apps can read that flag without requiring the local `.localghost` file, then construct and validate tunnel URLs:
|
|
322
|
-
|
|
323
|
-
```ts
|
|
324
|
-
import {
|
|
325
|
-
assertSecureGhostTunnelRequest,
|
|
326
|
-
constructGhostTunnelUrl,
|
|
327
|
-
readLocalghostProjectConfig
|
|
328
|
-
} from "@hamedb89/localghost";
|
|
329
|
-
|
|
330
|
-
const { config } = await readLocalghostProjectConfig();
|
|
331
|
-
const url = constructGhostTunnelUrl({
|
|
332
|
-
domain: "socialworkouts.app",
|
|
333
|
-
route: "plan",
|
|
334
|
-
project: "summer-base",
|
|
335
|
-
owner: "hamed",
|
|
336
|
-
ghostTunnel: config.ghostTunnel
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
const route = assertSecureGhostTunnelRequest({
|
|
340
|
-
host: request.headers.get("host") ?? "",
|
|
341
|
-
domain: "socialworkouts.app",
|
|
342
|
-
protocol: "https",
|
|
343
|
-
authenticated: Boolean(session),
|
|
344
|
-
ghostTunnel: config.ghostTunnel
|
|
345
|
-
});
|
|
346
|
-
```
|
|
347
|
-
|
|
348
|
-
That constructs `https://plan-summer-base-hamed.ghost.socialworkouts.app/`, validates the same host shape, requires HTTPS by default, and requires the app to confirm auth by default. See [Ghost Tunnel](./docs/ghost-tunnel.md) for the production DNS and routing flow.
|
|
349
|
-
|
|
350
|
-
When `ghostTunnel.preview` is configured, local route and Vite startup logs include the concrete URL as `expected: https://plan-summer-base-hamed.ghost.socialworkouts.app/`. In an interactive Vite terminal, press `g` to show the Ghost Tunnel configuration and open a numbered concrete URL. Wildcard `*` URLs are shown for clarity, but the menu only opens configured concrete domains.
|
|
351
|
-
|
|
352
|
-
Relay guardrails are private-by-default: public requests never choose the local target, route registration requires a matching local-agent bearer token, signed route claims are exact/scoped/expiring, and default targets are limited to `localhost`, `127.0.0.1`, and `::1` with dangerous ports blocked. The package exports relay helpers for registration, target validation, header stripping, log redaction, limits, and safe offline responses.
|
|
353
|
-
|
|
354
|
-
Local security checks:
|
|
355
|
-
|
|
356
|
-
```sh
|
|
357
|
-
npm test
|
|
358
|
-
npm run test:cli
|
|
359
|
-
npm run test:coverage
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
`localghost dev` and `localghost run` also register their active sessions in a user-local activity file. Use `localghost ps` to see the Localghost apps currently running on the machine:
|
|
363
|
-
|
|
364
|
-
```txt
|
|
365
|
-
localghost ps
|
|
366
|
-
|
|
367
|
-
app run: vite
|
|
368
|
-
cwd: /Users/you/Projects/app
|
|
369
|
-
pid: 12345, caddy: 12346, child: 12347
|
|
370
|
-
started: 2026-07-05T12:00:00.000Z
|
|
371
|
-
app.localhost -> 127.0.0.1:5173 (listening)
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
Pass `--json` when another helper, such as a menu bar app, needs to poll the same state.
|
|
375
|
-
|
|
376
|
-
## macOS Widget
|
|
377
|
-
|
|
378
|
-
Localghost includes a tiny native macOS widget in `apps/macos-widget`. One widget tracks all active Localghost sessions across the machine. It shows `LG n` in the top bar and opens a small floating desktop panel with the Localghost route list, target ports, and listening state.
|
|
379
|
-
|
|
380
|
-
Build it from source:
|
|
381
|
-
|
|
382
|
-
```sh
|
|
383
|
-
npm run build
|
|
384
|
-
npm run macos:widget:build
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
The app bundle is written to `dist/LocalghostWidget.app`. See [docs/macos-widget.md](./docs/macos-widget.md) for local development notes.
|
|
388
|
-
|
|
389
|
-
## Vite
|
|
390
|
-
|
|
391
|
-
```ts
|
|
392
|
-
import { defineConfig } from "vite";
|
|
393
|
-
import { localGhostPlugin } from "@hamedb89/localghost/vite";
|
|
394
|
-
|
|
395
|
-
export default defineConfig({
|
|
396
|
-
plugins: [
|
|
397
|
-
localGhostPlugin({
|
|
398
|
-
port: 5173,
|
|
399
|
-
configFiles: [".localghost.private", ".localghost"]
|
|
400
|
-
})
|
|
401
|
-
]
|
|
402
|
-
});
|
|
403
|
-
```
|
|
404
|
-
|
|
405
|
-
The plugin binds Vite to `127.0.0.1` by default, prints the selected Localghost domain, generates an explicit `server.allowedHosts` list from the selected config file, and does not set `allowedHosts: true`. It runs only during local `vite serve`; production/build mode no-ops. Dynamic ports are enabled by default, so the plugin uses the configured port when available and otherwise moves to the next free port before Vite starts. Set `dynamicPort: false` when strict fixed-port behavior matters.
|
|
406
|
-
|
|
407
|
-
If `.localghost` is missing and Vite is running in an interactive terminal, the plugin asks whether to create one, prompts for the primary domain and optional extra domains, and then asks whether to run setup. Before touching `/etc/hosts`, it explains why macOS may ask for your password and confirms that only Localghost's managed block is changed.
|
|
408
|
-
|
|
409
|
-
When Vite starts, Localghost prints the browser-facing URLs:
|
|
410
|
-
|
|
411
|
-
```txt
|
|
412
|
-
localghost
|
|
413
|
-
local: http://app.localhost/
|
|
414
|
-
also: http://www.app.localhost/
|
|
415
|
-
target: http://127.0.0.1:5173/
|
|
416
|
-
```
|
|
417
|
-
|
|
418
|
-
`https: true` means the browser-facing URL is expected to go through Caddy on HTTPS, while Vite still runs behind it on `127.0.0.1:<port>`. The plugin uses that to set Vite websocket/HMR proxy settings and to print `https://...` local host URLs. Localghost never opens browser tabs by default.
|
|
61
|
+
## What It Does
|
|
419
62
|
|
|
420
|
-
|
|
63
|
+
- Reads `.localghost` from your app repo and turns hostnames into local routes.
|
|
64
|
+
- Updates only a managed Localghost block in `/etc/hosts` during explicit setup.
|
|
65
|
+
- Generates `ops/local/Caddyfile` for local reverse proxying.
|
|
66
|
+
- Keeps HTTP as the default; HTTPS is explicit with `--https`, `--ssl`, or config.
|
|
67
|
+
- Checks whether Caddy is installed, but never installs Homebrew packages for you.
|
|
68
|
+
- Gives Vite explicit `server.allowedHosts` entries without using `allowedHosts: true`.
|
|
69
|
+
- Exposes CLI, config, state, and route output for scripts and agent workflows.
|
|
421
70
|
|
|
422
|
-
##
|
|
71
|
+
## Common Commands
|
|
423
72
|
|
|
424
73
|
```sh
|
|
425
|
-
localghost init
|
|
426
74
|
localghost init --write-scripts
|
|
427
75
|
localghost doctor
|
|
428
76
|
localghost setup
|
|
429
|
-
localghost setup --project app
|
|
430
|
-
localghost setup --config .localghost.preview
|
|
431
|
-
localghost setup --https
|
|
432
|
-
localghost trust
|
|
433
|
-
localghost status
|
|
434
77
|
localghost status --ready
|
|
78
|
+
localghost dev
|
|
79
|
+
localghost run -- vite
|
|
80
|
+
localghost routes
|
|
435
81
|
localghost ps
|
|
436
|
-
localghost ps --json
|
|
437
82
|
localghost reset
|
|
438
83
|
localghost teardown
|
|
439
|
-
localghost teardown --remove-caddyfile
|
|
440
84
|
localghost update
|
|
441
|
-
localghost --no-update-check doctor
|
|
442
|
-
localghost run -- vite
|
|
443
|
-
localghost run --trust -- vite
|
|
444
|
-
localghost run --dynamic-port=no -- vite
|
|
445
|
-
localghost dev --config-pattern '^\.localghost\.'
|
|
446
|
-
localghost dev --https
|
|
447
|
-
localghost print
|
|
448
85
|
```
|
|
449
86
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
`setup`, `dev`, and `teardown` refuse to run in production-like environments such as `NODE_ENV=production`, `VERCEL_ENV=production`, or `LOCALGHOST_ENV=production`.
|
|
87
|
+
Prefer `.localhost` names. `.local` is supported, but Localghost warns because `.local` can collide with mDNS/Bonjour.
|
|
453
88
|
|
|
454
|
-
|
|
89
|
+
## Configuration
|
|
455
90
|
|
|
456
|
-
|
|
91
|
+
Most apps only need a `.localghost` file when they want explicit hostnames or multiple services:
|
|
457
92
|
|
|
458
93
|
```txt
|
|
459
|
-
#
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
Localghost does not rewrite the whole hosts file. It replaces only its own managed block for the selected project.
|
|
465
|
-
|
|
466
|
-
## Teardown And State
|
|
467
|
-
|
|
468
|
-
`setup` writes a project-local state file at `ops/local/localghost-state.json`. It records the last Localghost action, selected config path, generated Caddyfile path, hosts file path, proxy mode, and the host entries that were applied. This is durable enough for project tooling and avoids relying on OS temp folders for tracking. Most apps should treat it as generated local state and ignore it in git.
|
|
469
|
-
|
|
470
|
-
```sh
|
|
471
|
-
localghost status
|
|
472
|
-
localghost status --ready
|
|
473
|
-
localghost status --json
|
|
94
|
+
# Format: <host> <port>
|
|
95
|
+
app.localhost 5173
|
|
96
|
+
www.app.localhost 5173
|
|
97
|
+
api.app.localhost 8787
|
|
474
98
|
```
|
|
475
99
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
When a project no longer needs Localghost, teardown removes only the managed hosts block for the selected project:
|
|
479
|
-
|
|
480
|
-
```sh
|
|
481
|
-
localghost teardown
|
|
482
|
-
```
|
|
100
|
+
Most repos do not need `localghost.config.mjs`. Add it only for decisions like HTTPS, dynamic-port behavior, `www.` aliases, custom config files, or `ghostTunnel` preview domains.
|
|
483
101
|
|
|
484
|
-
|
|
102
|
+
## Trust
|
|
485
103
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
104
|
+
- CI runs typecheck, build, site build, and npm package dry-run on Node 20 and 22.
|
|
105
|
+
- GitHub Pages is deployed by Actions from the checked-in `site/`, `docs/`, and `assets/` sources.
|
|
106
|
+
- Preview the exact Pages artifact locally with `npm run site:serve`, then open `http://127.0.0.1:4173/`.
|
|
107
|
+
- npm publish is guarded by `prepublishOnly` and the release workflow publishes with npm provenance.
|
|
108
|
+
- Runtime dependencies are intentionally small: `commander` and `execa`. Vite is an optional peer dependency.
|
|
109
|
+
- No postinstall scripts, hidden Homebrew installs, surprise browser tabs, or broad hosts-file rewrites.
|
|
110
|
+
- Update checks are best-effort, cached for 24 hours, and can be disabled with `LOCALGHOST_NO_UPDATE_CHECK=1` or `--no-update-check`.
|
|
490
111
|
|
|
491
|
-
|
|
112
|
+
## Docs
|
|
492
113
|
|
|
493
|
-
|
|
494
|
-
localghost teardown --remove-caddyfile
|
|
495
|
-
```
|
|
114
|
+
The full docs are served on GitHub Pages:
|
|
496
115
|
|
|
497
|
-
|
|
116
|
+
- [User flows](https://hamedb89.github.io/localghost/docs/flows/)
|
|
117
|
+
- [CLI reference](https://hamedb89.github.io/localghost/docs/localghost.1/)
|
|
118
|
+
- [Ghost Tunnel guide](https://hamedb89.github.io/localghost/docs/ghost-tunnel/)
|
|
119
|
+
- [macOS widget notes](https://hamedb89.github.io/localghost/docs/macos-widget/)
|
|
120
|
+
- [Brand guidelines](https://hamedb89.github.io/localghost/docs/brand/)
|
|
121
|
+
- [All docs](https://hamedb89.github.io/localghost/docs/)
|
|
498
122
|
|
|
499
123
|
## API
|
|
500
124
|
|
|
@@ -511,35 +135,9 @@ import {
|
|
|
511
135
|
updateSystemHosts
|
|
512
136
|
} from "@hamedb89/localghost";
|
|
513
137
|
|
|
514
|
-
readDevHosts({ configFiles: [".localghost.private", ".localghost"] });
|
|
515
|
-
readDevHosts({ configPattern: /^\.localghost\.(private|preview)$/ });
|
|
516
|
-
```
|
|
517
|
-
|
|
518
|
-
Vite helper:
|
|
519
|
-
|
|
520
|
-
```ts
|
|
521
138
|
import { localGhostPlugin } from "@hamedb89/localghost/vite";
|
|
522
139
|
```
|
|
523
140
|
|
|
524
|
-
`localHostsPlugin` is also exported as a compatibility alias.
|
|
525
|
-
|
|
526
|
-
## More Docs
|
|
527
|
-
|
|
528
|
-
Localghost copy can be mysterious, goofy, magical, funny, and a little absurd. The product behavior should stay boring in the best way: explicit commands, exact paths, clear errors, and no hidden installs.
|
|
529
|
-
|
|
530
|
-
- [Website](https://hamedb89.github.io/localghost/)
|
|
531
|
-
- [Brand guidelines](./docs/brand.md)
|
|
532
|
-
- [Job-to-be-done flows](./docs/flows.md)
|
|
533
|
-
- [CLI reference](./docs/localghost.1.md)
|
|
534
|
-
|
|
535
|
-
## Assets
|
|
536
|
-
|
|
537
|
-
<p align="center">
|
|
538
|
-
<img src="./assets/localghost-mascot.png" alt="Localghost mascot" width="180">
|
|
539
|
-
<br>
|
|
540
|
-
<img src="./assets/localghost-wordmark.png" alt="Localghost wordmark" width="420">
|
|
541
|
-
</p>
|
|
542
|
-
|
|
543
141
|
## License
|
|
544
142
|
|
|
545
143
|
MIT
|
package/dist/cli.js
CHANGED
|
@@ -495,8 +495,11 @@ function getDisplayValues(input2) {
|
|
|
495
495
|
...input2.values
|
|
496
496
|
};
|
|
497
497
|
}
|
|
498
|
+
function getDisplayDefaults(config, defaults) {
|
|
499
|
+
return config.mode === "public" && !config.preview ? void 0 : defaults;
|
|
500
|
+
}
|
|
498
501
|
function createDisplayUrl(config, defaults, domain) {
|
|
499
|
-
const input2 = getPreviewDefaults(config.preview, defaults);
|
|
502
|
+
const input2 = getPreviewDefaults(config.preview, getDisplayDefaults(config, defaults));
|
|
500
503
|
const protocol = input2.protocol ?? "https";
|
|
501
504
|
const slug = createNamespaceDisplaySlug(config.namespace, getDisplayValues(input2));
|
|
502
505
|
const entryHost = domain ? getGhostTunnelEntryHost(domain, config) : input2.domain ? getGhostTunnelEntryHost(input2.domain, config) : `${config.subdomain}.*`;
|
|
@@ -505,8 +508,9 @@ function createDisplayUrl(config, defaults, domain) {
|
|
|
505
508
|
return `${url}${input2.path.replace(/^\/+/, "")}`;
|
|
506
509
|
}
|
|
507
510
|
function createDisplayUrls(config, defaults) {
|
|
508
|
-
const
|
|
509
|
-
const
|
|
511
|
+
const displayDefaults = getDisplayDefaults(config, defaults);
|
|
512
|
+
const domains = config.domains.length > 0 ? config.domains : displayDefaults?.domain ? [displayDefaults.domain] : [];
|
|
513
|
+
const urls = domains.length > 0 ? domains.map((domain) => createDisplayUrl(config, displayDefaults, domain)) : [createDisplayUrl(config, displayDefaults)];
|
|
510
514
|
return [...new Set(urls)];
|
|
511
515
|
}
|
|
512
516
|
function maybeConstructPreviewUrl(config, defaults) {
|
|
@@ -1091,7 +1095,7 @@ import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as rea
|
|
|
1091
1095
|
import { homedir as homedir2 } from "os";
|
|
1092
1096
|
import { dirname as dirname4, join as join8 } from "path";
|
|
1093
1097
|
var LOCALGHOST_PACKAGE_NAME = "@hamedb89/localghost";
|
|
1094
|
-
var LOCALGHOST_VERSION = "0.1.
|
|
1098
|
+
var LOCALGHOST_VERSION = "0.1.10";
|
|
1095
1099
|
var UPDATE_CHECK_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
1096
1100
|
var UPDATE_CHECK_NOTIFY_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
1097
1101
|
var UPDATE_CHECK_TIMEOUT_MS = 900;
|