@hamedb89/localghost 0.1.10 → 0.1.12

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 CHANGED
@@ -9,7 +9,7 @@ Buh. Friendly local hostnames for app repos.
9
9
  [![CI](https://github.com/hamedb89/localghost/actions/workflows/ci.yml/badge.svg)](https://github.com/hamedb89/localghost/actions/workflows/ci.yml)
10
10
  [![GitHub Pages](https://github.com/hamedb89/localghost/actions/workflows/pages.yml/badge.svg)](https://github.com/hamedb89/localghost/actions/workflows/pages.yml)
11
11
  [![Publish npm](https://github.com/hamedb89/localghost/actions/workflows/publish-npm.yml/badge.svg)](https://github.com/hamedb89/localghost/actions/workflows/publish-npm.yml)
12
- [![npm version](https://img.shields.io/badge/npm-v0.1.10-CB3837?logo=npm)](https://www.npmjs.com/package/@hamedb89/localghost)
12
+ [![npm version](https://img.shields.io/badge/npm-v0.1.12-CB3837?logo=npm)](https://www.npmjs.com/package/@hamedb89/localghost)
13
13
 
14
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
 
@@ -17,6 +17,8 @@ Localghost is a tiny Node.js CLI for clean local app domains. Add it as a dev de
17
17
 
18
18
  ## Quick Start
19
19
 
20
+ Install it as a dev dependency:
21
+
20
22
  ```sh
21
23
  yarn add -D @hamedb89/localghost
22
24
  ```
@@ -58,76 +60,540 @@ For non-Vite apps, wrap your raw dev command:
58
60
  }
59
61
  ```
60
62
 
61
- ## What It Does
63
+ ## The Simple Stuff
62
64
 
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.
65
+ Start the detected development server with Localghost:
66
+
67
+ ```sh
68
+ npm exec localghost
69
+ ```
70
+
71
+ Localghost detects the package manager, prefers a non-recursive `dev:raw` script, falls back to `dev`, repairs stale setup when needed, then starts Caddy and the server. Preview the decision without starting anything:
72
+
73
+ ```sh
74
+ npm exec localghost -- --dry-run
75
+ ```
70
76
 
71
- ## Common Commands
77
+ Create the repo-local hostname contract:
72
78
 
73
79
  ```sh
74
80
  localghost init --write-scripts
81
+ ```
82
+
83
+ Check whether the machine is ready:
84
+
85
+ ```sh
75
86
  localghost doctor
87
+ ```
88
+
89
+ Prepare `/etc/hosts` and the local Caddyfile:
90
+
91
+ ```sh
76
92
  localghost setup
93
+ ```
94
+
95
+ Check setup readiness:
96
+
97
+ ```sh
77
98
  localghost status --ready
99
+ ```
100
+
101
+ Repair stale hosts, Caddy configuration, or setup state:
102
+
103
+ ```sh
104
+ localghost repair
105
+ ```
106
+
107
+ Run only the local proxy:
108
+
109
+ ```sh
78
110
  localghost dev
111
+ ```
112
+
113
+ Wrap an app server:
114
+
115
+ ```sh
79
116
  localghost run -- vite
117
+ ```
118
+
119
+ See the domain layer:
120
+
121
+ ```sh
122
+ localghost routes
123
+ ```
124
+
125
+ ```txt
80
126
  localghost routes
127
+ http://app.localhost/ -> http://127.0.0.1:5173
128
+ http://api.app.localhost/ -> http://127.0.0.1:8787
129
+ ```
130
+
131
+ See active Localghost sessions:
132
+
133
+ ```sh
81
134
  localghost ps
82
- localghost reset
83
- localghost teardown
135
+ localghost ps --json
136
+ ```
137
+
138
+ Check for updates:
139
+
140
+ ```sh
84
141
  localghost update
85
142
  ```
86
143
 
87
144
  Prefer `.localhost` names. `.local` is supported, but Localghost warns because `.local` can collide with mDNS/Bonjour.
88
145
 
89
- ## Configuration
146
+ ## What It Changes
147
+
148
+ Localghost is intentionally small and explicit:
149
+
150
+ - Reads `.localghost` from your app repo and turns hostnames into local routes.
151
+ - Updates only a managed Localghost block in `/etc/hosts` during explicit setup.
152
+ - Generates `ops/local/Caddyfile` for local reverse proxying.
153
+ - Records setup state in `ops/local/localghost-state.json`.
154
+ - Keeps HTTP as the default; HTTPS is explicit with `--https`, `--ssl`, or config.
155
+ - Checks whether Caddy is installed, but never installs Homebrew packages for you.
156
+ - Gives Vite explicit `server.allowedHosts` entries without using `allowedHosts: true`.
157
+ - Never opens browser tabs by default.
158
+
159
+ `setup`, `dev`, and `teardown` refuse to run in production-like environments such as `NODE_ENV=production`, `VERCEL_ENV=production`, or `LOCALGHOST_ENV=production`.
160
+
161
+ ## Configuration By Use Case
90
162
 
91
- Most apps only need a `.localghost` file when they want explicit hostnames or multiple services:
163
+ ### One App Domain
164
+
165
+ Use a `.localghost` file when you want one stable local domain:
92
166
 
93
167
  ```txt
94
- # Format: <host> <port>
168
+ # .localghost
169
+ app.localhost 5173
170
+ ```
171
+
172
+ Then run:
173
+
174
+ ```sh
175
+ localghost setup
176
+ localghost run -- vite
177
+ ```
178
+
179
+ ### Multiple Local Services
180
+
181
+ Map each browser-facing host to the upstream port:
182
+
183
+ ```txt
184
+ # .localghost
95
185
  app.localhost 5173
96
186
  www.app.localhost 5173
97
187
  api.app.localhost 8787
188
+ admin.app.localhost 5174
98
189
  ```
99
190
 
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.
191
+ `localghost routes` prints the same `domain -> upstream` map that `setup` and `dev` use.
101
192
 
102
- ## Trust
193
+ ### Add Package Scripts
103
194
 
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`.
195
+ `localghost init --write-scripts` adds missing scripts without replacing your existing ones:
196
+
197
+ ```json
198
+ {
199
+ "scripts": {
200
+ "localghost:setup": "localghost setup",
201
+ "localghost:proxy": "localghost dev",
202
+ "localghost:proxy:https": "localghost dev --https",
203
+ "localghost:run": "localghost run --",
204
+ "localghost:ready": "localghost status --ready",
205
+ "localghost:repair": "localghost repair",
206
+ "localghost:trust": "localghost trust",
207
+ "localghost:ps": "localghost ps",
208
+ "localghost:print": "localghost print",
209
+ "localghost:routes": "localghost routes",
210
+ "localghost:status": "localghost status",
211
+ "localghost:reset": "localghost reset",
212
+ "localghost:teardown": "localghost teardown",
213
+ "localghost:doctor": "localghost doctor",
214
+ "localghost:update": "localghost update",
215
+ "caddy:setup": "localghost setup",
216
+ "caddy:dev": "localghost dev"
217
+ }
218
+ }
219
+ ```
220
+
221
+ ### Keep `yarn dev` As The Daily Command
222
+
223
+ Wrap the raw app server so teammates keep typing the normal command:
224
+
225
+ ```json
226
+ {
227
+ "scripts": {
228
+ "dev": "localghost run -- yarn dev:raw",
229
+ "dev:raw": "vite"
230
+ }
231
+ }
232
+ ```
111
233
 
112
- ## Docs
234
+ For Turborepo, wrap the dev runner and keep dev uncached:
235
+
236
+ ```json
237
+ {
238
+ "scripts": {
239
+ "dev": "localghost run -- yarn dev:raw",
240
+ "dev:raw": "turbo dev"
241
+ }
242
+ }
243
+ ```
244
+
245
+ ```json
246
+ {
247
+ "tasks": {
248
+ "dev": { "cache": false, "persistent": true }
249
+ }
250
+ }
251
+ ```
252
+
253
+ `localghost run` starts Caddy, handles optional HTTPS trust, starts the child command, passes `LOCALGHOST_PORT` and `VITE_PORT`, and stops Caddy when the child exits.
254
+
255
+ ### Vite Plugin
256
+
257
+ Use the plugin when you want Vite to bind to `127.0.0.1`, use the selected Localghost port, set strict `allowedHosts`, and print the browser-facing domain:
258
+
259
+ ```ts
260
+ import { defineConfig } from "vite";
261
+ import { localGhostPlugin } from "@hamedb89/localghost/vite";
262
+
263
+ export default defineConfig({
264
+ plugins: [
265
+ localGhostPlugin({
266
+ port: 5173,
267
+ configFiles: [".localghost.private", ".localghost"]
268
+ })
269
+ ]
270
+ });
271
+ ```
272
+
273
+ The plugin runs only during local `vite serve`; production/build mode does not configure Vite dev-server hosting. If `ghostTunnel` is configured, the build hook can still print the production URL shape for visibility.
274
+
275
+ ### Custom Config Files
276
+
277
+ By default, Localghost reads `.localghost`. Repos that need another file name can be explicit:
278
+
279
+ ```sh
280
+ localghost print --config .localghost.preview
281
+ localghost setup --config .localghost.preview
282
+ ```
283
+
284
+ You can pass `--config` more than once. Localghost uses the first file that exists:
285
+
286
+ ```sh
287
+ localghost print --config .localghost.private --config .localghost
288
+ ```
289
+
290
+ You can also search project-root filenames with a regular expression:
291
+
292
+ ```sh
293
+ localghost print --config-pattern '^\.localghost\.(private|preview)$'
294
+ ```
113
295
 
114
- The full docs are served on GitHub Pages:
296
+ The Vite plugin accepts the same idea through `fileName`, `configFiles`, or `configPattern`.
115
297
 
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/)
298
+ ### Shared Project Defaults
299
+
300
+ Most repos do not need `localghost.config.mjs`. Add it when you want shared defaults for CLI and Vite:
301
+
302
+ ```js
303
+ import { defineLocalghostConfig } from "@hamedb89/localghost";
304
+
305
+ export default defineLocalghostConfig({
306
+ project: "app",
307
+ port: 5173,
308
+ dynamicPort: true,
309
+ autoRepair: true,
310
+ command: ["pnpm", "dev"],
311
+ wwwAlias: true
312
+ });
313
+ ```
314
+
315
+ Localghost derives `project` from `package.json`, defaults to port `5173`, keeps HTTP as the default, enables dynamic ports and setup repair by default, and adds `www.` aliases by default. `run`, `dev`, and the Vite plugin perform a read-only readiness check first and repair only when the managed hosts block or setup state is stale.
316
+
317
+ With no subcommand, `command` takes precedence. Otherwise Localghost detects npm, pnpm, Yarn, or Bun and runs `dev:raw` or `dev`. Scripts that invoke Localghost are skipped to prevent recursion.
318
+
319
+ ### Multiple Apps
320
+
321
+ For a monorepo where one root command already starts every app, keep using `command` and list the routes in `.localghost`.
322
+
323
+ When Localghost should own each process, configure explicit services:
324
+
325
+ ```js
326
+ export default defineLocalghostConfig({
327
+ services: [
328
+ {
329
+ name: "web",
330
+ cwd: "apps/web",
331
+ host: "xyz.localhost",
332
+ port: 5173,
333
+ command: ["pnpm", "dev"]
334
+ },
335
+ {
336
+ name: "api",
337
+ cwd: "apps/api",
338
+ host: "api.xyz.localhost",
339
+ port: 8787,
340
+ command: ["pnpm", "dev"]
341
+ }
342
+ ]
343
+ });
344
+ ```
345
+
346
+ Then bare `localghost` starts one Caddy instance and both services. Each command runs in its own `cwd` and receives its own `LOCALGHOST_PORT`, `VITE_PORT`, and `LOCALGHOST_SERVICE`. Dynamic-port selection and setup repair apply to every service. When Caddy or any service exits, Localghost stops the remaining processes.
347
+
348
+ Omit a service `command` to detect `dev:raw` or `dev` from that service directory. Service directories must stay inside the project root, and names and hosts must be unique.
349
+
350
+ Caddy startup and validation logs are quiet after success; configuration errors remain visible. Set `LOCALGHOST_CADDY_VERBOSE=1` when debugging Caddy itself. Once all service ports are listening, Localghost prints the final hostname-to-upstream map beneath the service startup logs.
351
+
352
+ Try the runnable Node example in [`examples/multi-service`](./examples/multi-service).
353
+
354
+ Disable automatic repair when you want strict failure behavior:
355
+
356
+ ```sh
357
+ localghost run --auto-repair=no -- vite
358
+ ```
359
+
360
+ Or set `autoRepair: false` in `localghost.config.mjs`. HTTPS certificate trust remains explicit.
361
+
362
+ ### Fixed Ports
363
+
364
+ 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.
365
+
366
+ Use strict fixed-port behavior when you want startup to fail instead:
367
+
368
+ ```sh
369
+ localghost run --dynamic-port=no -- vite
370
+ ```
371
+
372
+ Or in config:
373
+
374
+ ```js
375
+ export default defineLocalghostConfig({
376
+ dynamicPort: false
377
+ });
378
+ ```
379
+
380
+ ### Local HTTPS
381
+
382
+ HTTP is the default. Use HTTPS only when you explicitly want Caddy local certificates:
383
+
384
+ ```sh
385
+ localghost setup --https
386
+ localghost dev --https
387
+ ```
388
+
389
+ Trust Caddy's local HTTPS CA when you want browsers to stop showing local certificate warnings:
390
+
391
+ ```sh
392
+ localghost trust
393
+ localghost run --trust -- vite
394
+ ```
395
+
396
+ macOS may ask for your password so Caddy can add its local CA to Keychain. Localghost records the trust result in `ops/local/localghost-state.json`.
397
+
398
+ You can also make HTTPS the repo default:
399
+
400
+ ```js
401
+ export default defineLocalghostConfig({
402
+ https: true
403
+ });
404
+ ```
405
+
406
+ ### Disable `www.` Aliases
407
+
408
+ By default, `app.localhost 5173` also creates `www.app.localhost`.
409
+
410
+ Disable that when the repo wants only exact hosts:
411
+
412
+ ```js
413
+ export default defineLocalghostConfig({
414
+ wwwAlias: false
415
+ });
416
+ ```
417
+
418
+ ### Public Ghost Tunnel
419
+
420
+ `ghostTunnel` is an opt-in production URL shape for deployed wildcard endpoints. It does not change local Caddy or `/etc/hosts` setup.
421
+
422
+ Use public mode when the deployed app should react to whatever route arrives:
423
+
424
+ ```js
425
+ import { defineLocalghostConfig } from "@hamedb89/localghost";
426
+
427
+ export default defineLocalghostConfig({
428
+ ghostTunnel: {
429
+ mode: "public",
430
+ domains: "copper-comet.example"
431
+ }
432
+ });
433
+ ```
434
+
435
+ Build output stays flexible instead of filling slots from the build machine:
436
+
437
+ ```txt
438
+ localghost ghost tunnel
439
+ mode: public
440
+ configured: https://<route>-<project>-<owner>.ghost.copper-comet.example/
441
+ ```
442
+
443
+ Production code can parse and validate the incoming wildcard host:
444
+
445
+ ```ts
446
+ import {
447
+ assertSecureGhostTunnelRequest,
448
+ readLocalghostProjectConfig
449
+ } from "@hamedb89/localghost";
450
+
451
+ const { config } = await readLocalghostProjectConfig();
452
+
453
+ const route = assertSecureGhostTunnelRequest({
454
+ host: request.headers.get("host") ?? "",
455
+ domain: "copper-comet.example",
456
+ protocol: "https",
457
+ authenticated: Boolean(session),
458
+ ghostTunnel: config.ghostTunnel
459
+ });
460
+ ```
461
+
462
+ By default, secure requests require HTTPS and app-authenticated access.
463
+
464
+ ### Concrete Ghost Tunnel Preview
465
+
466
+ Use `preview` only when you want one concrete URL in logs or menus:
467
+
468
+ ```js
469
+ export default defineLocalghostConfig({
470
+ ghostTunnel: {
471
+ mode: "public",
472
+ domains: "copper-comet.example",
473
+ preview: {
474
+ route: "decisionlayer",
475
+ project: "decision-layer",
476
+ owner: "hamedbahrami"
477
+ }
478
+ }
479
+ });
480
+ ```
481
+
482
+ That prints:
483
+
484
+ ```txt
485
+ localghost ghost tunnel
486
+ mode: public
487
+ configured: https://decisionlayer-decision-layer-hamedbahrami.ghost.copper-comet.example/
488
+ ```
489
+
490
+ ### Manual Ghost Tunnel
491
+
492
+ Manual mode is the default. It is useful for private or operator-mediated sharing flows:
493
+
494
+ ```js
495
+ export default defineLocalghostConfig({
496
+ ghostTunnel: {
497
+ mode: "manual",
498
+ domains: "moonlit-otter.example"
499
+ }
500
+ });
501
+ ```
502
+
503
+ Manual relay helpers are private by default: registration requires a local-agent bearer token plus an exact signed route claim, targets must be explicit local host/port objects, dangerous ports are blocked, sensitive headers/logs are redacted, and offline agents get a safe 503 page.
504
+
505
+ ### Script And Agent Output
506
+
507
+ Use JSON when scripts, menu bar tools, or agents need stable output:
508
+
509
+ ```sh
510
+ localghost print
511
+ localghost status --json
512
+ localghost ps --json
513
+ localghost update --json
514
+ ```
515
+
516
+ `print` parses the selected config file. `status` reports the project-local setup state. `ps` reports active sessions across projects and whether each upstream port is listening.
517
+
518
+ ### Reset Or Remove Localghost
519
+
520
+ Reconcile the managed hosts block, regenerate and validate the Caddyfile, and refresh setup state:
521
+
522
+ ```sh
523
+ localghost repair
524
+ ```
525
+
526
+ For HTTPS certificate trust problems, explicitly re-run Caddy's trust step:
527
+
528
+ ```sh
529
+ localghost repair --https --trust
530
+ ```
531
+
532
+ If a running Caddy process exits, `localghost run` exits with it; starting the normal development command again launches a fresh Caddy process.
533
+
534
+ Retest setup without deleting `.localghost`:
535
+
536
+ ```sh
537
+ localghost reset
538
+ localghost setup
539
+ ```
540
+
541
+ Remove only the managed hosts block for this project:
542
+
543
+ ```sh
544
+ localghost teardown
545
+ ```
546
+
547
+ Remove the generated Caddyfile too:
548
+
549
+ ```sh
550
+ localghost teardown --remove-caddyfile
551
+ ```
552
+
553
+ ### macOS Widget
554
+
555
+ Localghost includes a tiny native macOS widget under `apps/macos-widget`. It reads the shared activity file and shows known setup/running instances.
556
+
557
+ Build it from source:
558
+
559
+ ```sh
560
+ npm run build
561
+ npm run macos:widget:build
562
+ ```
563
+
564
+ The app bundle is written to `dist/LocalghostWidget.app`.
565
+
566
+ ## CLI Reference
567
+
568
+ ```sh
569
+ localghost [--cwd path] [--dry-run]
570
+ localghost init [--write-scripts] [--config file] [--host host] [--port port]
571
+ localghost doctor
572
+ localghost setup [--project name] [--config file] [--config-pattern regex] [--https|--ssl]
573
+ localghost repair [--project name] [--config file] [--config-pattern regex] [--https|--ssl] [--trust]
574
+ localghost trust [--project name] [--config file] [--config-pattern regex] [--https|--ssl]
575
+ localghost reset [--project name]
576
+ localghost teardown [--project name] [--remove-caddyfile]
577
+ localghost status [--ready] [--json]
578
+ localghost ps [--json]
579
+ localghost update [--json]
580
+ localghost dev [--config file] [--config-pattern regex] [--https|--ssl] [--auto-repair yes|no] [--trust]
581
+ localghost run [--config file] [--config-pattern regex] [--https|--ssl] [--auto-repair yes|no] [--trust] [--dynamic-port] -- command
582
+ localghost routes [--https|--ssl]
583
+ localghost print [--config file] [--config-pattern regex]
584
+ ```
122
585
 
123
586
  ## API
124
587
 
125
588
  ```ts
126
589
  import {
590
+ assertSecureGhostTunnelRequest,
591
+ constructGhostTunnelUrl,
127
592
  getConfigFileCandidates,
128
593
  initLocalghost,
129
594
  readDevHosts,
130
595
  readLocalghostState,
596
+ readLocalghostProjectConfig,
131
597
  removeSystemHosts,
132
598
  renderCaddyfile,
133
599
  renderHostsBlock,
@@ -138,6 +604,28 @@ import {
138
604
  import { localGhostPlugin } from "@hamedb89/localghost/vite";
139
605
  ```
140
606
 
607
+ `localHostsPlugin` is also exported as a compatibility alias for the Vite helper.
608
+
609
+ ## Trust
610
+
611
+ - CI runs typecheck, build, site build, and npm package dry-run on Node 20 and 22.
612
+ - GitHub Pages is deployed by Actions from the checked-in `site/`, `docs/`, and `assets/` sources.
613
+ - Preview the exact Pages artifact locally with `npm run site:serve`, then open `http://127.0.0.1:4173/`.
614
+ - npm publish is guarded by `prepublishOnly` and the release workflow publishes with npm provenance.
615
+ - Runtime dependencies are intentionally small: `commander` and `execa`. Vite is an optional peer dependency.
616
+ - No postinstall scripts, hidden Homebrew installs, surprise browser tabs, or broad hosts-file rewrites.
617
+ - Update checks are best-effort, cached for 24 hours, and can be disabled with `LOCALGHOST_NO_UPDATE_CHECK=1` or `--no-update-check`.
618
+
619
+ ## More Docs
620
+
621
+ - [Website](https://hamedb89.github.io/localghost/)
622
+ - [Rendered docs](https://hamedb89.github.io/localghost/docs/)
623
+ - [User flows](./docs/flows.md)
624
+ - [CLI reference](./docs/localghost.1.md)
625
+ - [Ghost Tunnel guide](./docs/ghost-tunnel.md)
626
+ - [macOS widget notes](./docs/macos-widget.md)
627
+ - [Brand guidelines](./docs/brand.md)
628
+
141
629
  ## License
142
630
 
143
631
  MIT