home-hosted 0.8.1 → 0.8.3

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/AGENTS.md CHANGED
@@ -58,6 +58,8 @@ pnpm dev # tsx-watch panel :6000 + the stock UI's Vite
58
58
  pnpm dev --ui noc-console # the same, for another UI; --port/--ui-port override
59
59
  pnpm run build # dist/cli.js + the stock UI (uis/stock/dist)
60
60
  pnpm run build:uis # every UI under uis/, zipped into uis/dist/ (release assets)
61
+ pnpm run build:locales # i18n/sheets/*.csv -> the git-ignored i18n/generated/*.json (also
62
+ # runs on install and before every UI build)
61
63
  pnpm run quickcheck # eslint + tsc + vue-tsc + the doc links — NOT the tests
62
64
  pnpm exec vitest run # `pnpm test` is vitest in watch mode
63
65
  pnpm run check # ← THE GATE: quickcheck + vitest run --coverage. Run before every
@@ -123,7 +125,8 @@ These prevent defects if broken. The *why* for the non-obvious ones is in
123
125
  an old panel keeps serving, so a required field blanks the app.
124
126
  - **UIs move together.** A change to `uis/stock` — or to a shared contract it reads — lands in every
125
127
  other UI under `uis/`, and each altered UI raises its `ui.json` version; `scripts/stamp-uis.mjs`
126
- **refuses** a commit that changed a shipped UI without raising it (`uis/<name>/test/**` is exempt).
128
+ **refuses** a commit that changed a shipped UI without raising it (a UI's `test/` and its own
129
+ `README.md` are exempt — neither is in the built asset).
127
130
  `src/shared/**` is a UI build input, so a runtime contract needs the bump too — the hook does not
128
131
  inspect that commit.
129
132
  - **Paths.** `dataRoot` is state, under `dataRoot/.hh`; `projectDir` is the base for relative entry
package/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  <div align="center">
2
2
 
3
- # 🏠 home-hosted
3
+ <img src="docs/branding/logo.svg" alt="home-hosted" width="128" height="128">
4
+
5
+ # home-hosted
4
6
 
5
7
  **The control panel for everything you self-host at home.**
6
8
 
@@ -81,7 +83,8 @@ some arguments, and the environment you give it:
81
83
  ```
82
84
 
83
85
  <sub>Manage them from the panel, `home-hosted start|stop <id>` from a shell, `home-hosted status --json`,
84
- or `GET /api/state`; `GET /healthz` is the same status line for your own monitor, no session needed.</sub>
86
+ or `GET /api/state`; `GET /healthz` is the same status line for your own monitor, no session needed —
87
+ `503` when an autostart server has crashed or a running one is failing its health check.</sub>
85
88
 
86
89
  ---
87
90
 
@@ -267,7 +270,7 @@ can be told what to be: *"Help me build a UI for home-hosted: nostalgic game the
267
270
  | 🗂 **Workspaces** | One panel, many scopes: pick a workspace in the header and it owns its servers, secrets, logs and settings. Create, rename and delete them there. Panel-wide things — listener, auth, host vitals, backups, TLS, UI — stay in **Global settings**. |
268
271
  | 🚦 **Lifecycle** | Start, stop, restart from the panel or the API; `autostart` entries come up with it. |
269
272
  | 📝 **Hand edits welcome** | Change a workspace's `servers.config.json` in an editor, a `git checkout` or a config tool: the panel notices within seconds, no restart. A file it cannot read is reported in the panel, and the running servers are left alone. |
270
- | ♻️ **Auto-restart** | Exponential backoff on crash, with the counter reset once a process stays up. |
273
+ | ♻️ **Auto-restart** | Exponential backoff on crash, with the counter reset once a process stays up. The budget is remembered across a restart of the panel. |
271
274
  | 🩺 **Health that acts** | TCP or HTTP probes per server: warn on the card, force a restart after a timeout, check ports before starting — and [follow or replace](./docs/SERVERS.md#when-a-program-restarts-itself) a program that restarts itself. |
272
275
  | 🔗 **Ordered startup** | `dependsOn` waits for a dependency to be *healthy* — not merely spawned. `stop-all`/`down` stop dependents before their dependencies; stopping one server names the dependents it leaves running. [SERVERS.md](./docs/SERVERS.md#field-reference) |
273
276
  | 📜 **Logs** | Live per-server stream, buffer plus rotated files on disk, search, filter to one stream, download, one click to clear. |
@@ -277,7 +280,7 @@ can be told what to be: *"Help me build a UI for home-hosted: nostalgic game the
277
280
  | 🔔 **Notifications** | Telegram on crash, unhealthy, forced restart, recovery, host thresholds and DNS changes — [setup here](./docs/NOTIFICATIONS.md). |
278
281
  | 🌐 **Dynamic DNS** | Keep hostnames pointed at your public IP — Cloudflare, Namecheap, Spaceship, Porkbun, GoDaddy, Gandi and more. [DDNS.md](./docs/DDNS.md) |
279
282
  | 🔀 **Reverse proxy** | One engine in front of everything, with automatic HTTPS: `git.example.com` → a Gitea entry, `media.example.com` → a service on another box, `panel.example.com` → the panel. Caddy, installed and supervised by the panel. [REVERSE_PROXY.md](./docs/REVERSE_PROXY.md) |
280
- | 💾 **Backups** | Deep and customizable: pick global settings, global secrets, TLS, Workspaces, then the pieces inside it (workspace settings, servers, secrets, data directories) — plain `.zip`, or AES-256 with a password, customized restore is supported too! |
283
+ | 💾 **Backups** | Global settings, TLS, workspaces, and inside each one its settings, servers, secrets and declared data — plain `.zip`, or AES-256 with a password. Each secret is picked separately, and a restore can be customized. |
281
284
  | 🌍 **Nine languages** | English, Vietnamese, Chinese, Japanese, Spanish, Korean, Russian, French, German — picked on the login page or in **Global settings → Language**, kept per browser. |
282
285
  | 🎨 **BYOU — Bring Your Own UI** | Upload a static build, `ui-update` to follow its releases, `ui-revert` to go back. [UI_CREATION.md](./docs/UI_CREATION.md) |
283
286
  | 🔐 **Security** | Cookie sessions, API tokens, scrypt hashes, per-IP lockout, optional TLS, and a refusal to expose itself without a password. |
@@ -485,11 +488,32 @@ Provider tokens stay in the workspace's secrets file. **Providers and the config
485
488
 
486
489
  **Global settings → Backups** archives the panel's own settings, its secrets and the TLS pair — plus
487
490
  every workspace you pick. It is two-level: the top of *Create backup…* lists the global items and
488
- each workspace; opening a workspace lists its **settings**, **servers**, **secrets** and every data
489
- directory its entries declare, and you can drop any single piece. *Restore…* shows the same list from
490
- an archive before anything is written. Either way it is an ordinary `.zip`, or WinZip AES-256 with a
491
- password, restored per path. Known build output and dependency directories (`node_modules`, `dist`,
492
- `.next`, framework caches) are skipped per entry; `backupIgnoreGenerated: false` captures them anyway.
491
+ each workspace; opening one lists its **settings**, **servers**, its **secrets** and every data
492
+ directory its entries declare, and you can drop any single piece. Each secret has its own checkbox.
493
+ *Restore…* shows the same list from an archive before anything is written. Either way it is an
494
+ ordinary `.zip`, or WinZip AES-256 with a password, restored per path. Known build output and
495
+ dependency directories (`node_modules`, `dist`, `.next`, framework caches) are skipped per entry;
496
+ `backupIgnoreGenerated: false` captures them anyway.
497
+
498
+ <details>
499
+ <summary><b>🔑 Restoring a secret</b></summary>
500
+
501
+ An archive records **which release wrote it and the config schema it understood**; a restore refuses
502
+ a newer schema outright rather than restoring the parts it recognizes.
503
+
504
+ Ticking a **single secret** merges by field: it lands and the others in that file are left alone. So
505
+ restoring the Telegram token does not clear the DDNS credentials. Ticking the whole **Secrets** entry
506
+ replaces the file with the archive's copy instead, which is what makes the two worth telling apart.
507
+
508
+ Two things to know before restoring onto a machine already in use:
509
+
510
+ - **The password hash and API token hash are secrets like any other.** Restoring them reinstates the
511
+ old machine's password and long-lived token, so anyone holding that token keeps access. Leave them
512
+ unticked, or rotate afterwards with `pnpm run set-token --generate`.
513
+ - **`HHOSTED_DDNS_SECRET` is not in the archive.** DDNS credentials travel sealed under it, so a host
514
+ with a different value cannot open them. Supply the same secret, or re-enter the credentials.
515
+
516
+ </details>
493
517
 
494
518
  <details>
495
519
  <summary><b>🚚 One archive is a whole setup</b></summary>
@@ -649,6 +673,7 @@ src/cli.ts the command line; one file per command under src/cli/
649
673
  src/index.ts the control plane itself, used by `up --foreground`
650
674
  uis/ UIs: `stock` (shipped in the package) and alternatives — any framework, static output
651
675
  bin/ the published entry point
676
+ docs/branding/ logo, icons and the social preview; the SVGs are the source, `pnpm run brand` renders them
652
677
  docs/ topic docs, UI examples and the README's media
653
678
  scripts/ builds, typechecks, media capture, release helpers
654
679
  test/ the vitest suite