home-hosted 0.7.1 → 0.7.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 +36 -19
- package/README.md +26 -20
- package/dist/cli.js +5353 -2362
- package/dist/cli.js.map +1 -1
- package/docs/DDNS.md +3 -2
- package/docs/NOTIFICATIONS.md +6 -4
- package/docs/REVERSE_PROXY.md +242 -0
- package/docs/UI_CREATION.md +17 -1
- package/package.json +3 -2
- package/uis/stock/dist/assets/{index-Ocn66d5H.js → index-DoDrajgK.js} +26 -26
- package/uis/stock/dist/assets/index-JGpABIqV.css +2 -0
- package/uis/stock/dist/index.html +2 -2
- package/uis/stock/dist/ui.json +3 -3
- package/uis/stock/dist/assets/index-S1nhkKEu.css +0 -2
package/AGENTS.md
CHANGED
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
`home-hosted` is a Node 24 / TypeScript harness for self-hosted servers: `up` starts a Hono/srvx
|
|
4
4
|
panel (default `127.0.0.1:3999`) that supervises the entries in each workspace's
|
|
5
5
|
`servers.config.json` and serves a UI. User docs: `README.md`, `docs/SERVERS.md` (entries and port
|
|
6
|
-
conflicts), `docs/NOTIFICATIONS.md`, `docs/DDNS.md`; UI authors:
|
|
6
|
+
conflicts), `docs/NOTIFICATIONS.md`, `docs/DDNS.md`, `docs/REVERSE_PROXY.md`; UI authors:
|
|
7
|
+
`docs/UI_CREATION.md`.
|
|
7
8
|
|
|
8
9
|
State lives only in `$HHOSTED_HOME/.hh` (default `~/.home-hosted/.hh`). Global files sit at its top
|
|
9
|
-
level: `settings.json` (listener, auth, TLS policy, host vitals, backups),
|
|
10
|
-
`.control-secrets.json` (0600: password hash, API token hash), `.tls/`,
|
|
11
|
-
(the panel console),
|
|
10
|
+
level: `settings.json` (listener, auth, TLS policy, host vitals, backups, reverse proxy),
|
|
11
|
+
`workspaces.json`, `.control-secrets.json` (0600: password hash, API token hash), `.tls/`,
|
|
12
|
+
`.backups/`, `.ui/`, `.logs/` (the panel console), `.proxy/` (the reverse-proxy engine, its generated
|
|
13
|
+
configuration and its nanny state), and `run.json` — the live daemon's pid/url/token, 0600. Every workspace owns
|
|
12
14
|
`.hh/<id>/`: `settings.json` (server defaults, log retention, notifications, DDNS), `servers.config.json`,
|
|
13
15
|
`.secrets.json` (0600: Telegram bot token and DDNS credentials sealed with AES-256-GCM under
|
|
14
16
|
`HHOSTED_DDNS_SECRET`), `.logs/`, and `.state/` (a persistent entry's nanny state plus its 0600 spawn
|
|
@@ -109,12 +111,13 @@ a minor without one.
|
|
|
109
111
|
`identity` (which port holder is this entry's own successor: marker first, then resolved image +
|
|
110
112
|
argv), `nanny` (a persistent entry's spec/state files and the liveness rules for one),
|
|
111
113
|
`log-tail` (an offset reader that survives rotation and truncation), `ddns/` (one `DdnsProvider` per
|
|
112
|
-
registrar over one HTTP call each, plus `ip` and `zone` helpers),
|
|
113
|
-
|
|
114
|
+
registrar over one HTTP call each, plus `ip` and `zone` helpers), `proxy/` (the reverse-proxy
|
|
115
|
+
engines this build can drive: where the binary comes from and how to start it — the route model
|
|
116
|
+
stays the panel's), health-check, host, telegram, archive.
|
|
114
117
|
- `src/services/` — stateful orchestration: `panel` (one `WorkspaceRuntime` per workspace, workspace
|
|
115
118
|
CRUD, and the single aggregate state frame — every per-workspace service hangs off it), supervisor,
|
|
116
119
|
control-server, config-watch, state, auth + exposure, dependencies, history, log-buffer/log-files,
|
|
117
|
-
notifications, host-monitor, ddns, backups, tls, ui, plus `init` (the scaffold behind
|
|
120
|
+
notifications, host-monitor, ddns, proxy, backups, tls, ui, plus `init` (the scaffold behind
|
|
118
121
|
`home-hosted init`: a manifest, a `.gitignore`, and the prompts stay in the CLI), `nanny` (the
|
|
119
122
|
process a persistent entry runs under) and `log-relay` (the tailer that feeds its lines to the
|
|
120
123
|
supervisor). It names no server — the scaffold must stay as neutral as the supervisor.
|
|
@@ -132,23 +135,28 @@ a minor without one.
|
|
|
132
135
|
`repo`/`tag`/`asset` (which release carries it, for `ui-update`) and `unix` (when it was built).
|
|
133
136
|
`UiService` carries those fields into the installed `$HHOSTED_HOME/.ui/ui.json` unchanged and adds
|
|
134
137
|
`uploadedAt`/`files` of its own.
|
|
135
|
-
- **Bumping a UI ships a new asset, so its `ui.json` is part of the change
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
138
|
+
- **Bumping a UI ships a new asset, so its `ui.json` is part of the change — and it is bumped once,
|
|
139
|
+
when the commit is made, not on every edit.** A commit that alters what a UI *ships*
|
|
140
|
+
(`uis/<name>/src`, `public`, its build inputs — not `test/`, which is not in the asset) raises that
|
|
141
|
+
`ui.json`'s `version`: patch for a fix, minor for a feature, and **major only for a rewrite or a
|
|
142
|
+
restyle**. The number is what tells a person how big the change is — `ui-update` prints it and holds
|
|
143
|
+
it against the release it is offering. `unix` is that commit's own epoch, never a leftover from
|
|
144
|
+
whenever the file was edited: `scripts/stamp-uis.mjs` runs from the pre-commit hook, stamps it, and
|
|
145
|
+
refuses a commit that changed a shipped UI without raising its version. `tag` is what pairs an
|
|
146
|
+
official UI with its panel, and it is **stamped by `build-uis.mjs`**, not trusted from the source
|
|
147
|
+
file: a UI zip is built before its release is cut, so the committed value is always a release behind
|
|
148
|
+
the asset it ends up inside. The release workflow passes `HHOSTED_UI_TAG`; anywhere else the build
|
|
149
|
+
stamps `v<package.json version>`. Do not hand-edit `tag` to chase a release — a stale one makes
|
|
150
|
+
`ui-update` re-install the same UI on every boot.
|
|
144
151
|
- `bin/home-hosted.mjs` — the published bin: `dist/cli.js`, or `src/cli.ts` through tsx when the
|
|
145
152
|
build is missing (a linked checkout).
|
|
146
153
|
- `scripts/` — `build-uis.mjs` (build one UI, optionally zip it), `typecheck-uis.mjs`,
|
|
147
154
|
`capture-media.mjs` (the README's media), `check-release-version.mjs` and `release-notes.mjs`
|
|
148
155
|
(used by the release workflow), `dev.mjs` (`pnpm dev`).
|
|
149
|
-
- `docs/` — the topic docs (`SERVERS.md`, `NOTIFICATIONS.md`, `DDNS.md`, `
|
|
156
|
+
- `docs/` — the topic docs (`SERVERS.md`, `NOTIFICATIONS.md`, `DDNS.md`, `REVERSE_PROXY.md`,
|
|
157
|
+
`UI_CREATION.md`),
|
|
150
158
|
`mockups/*.html` (hand-written UI examples in four directions) and `media/*`: their screenshots plus
|
|
151
|
-
the README's `tour.gif`, all regenerated by `pnpm run media`. Only the
|
|
159
|
+
the README's `tour.gif`, all regenerated by `pnpm run media`. Only the five `.md` files are
|
|
152
160
|
published; the media is a build artifact.
|
|
153
161
|
|
|
154
162
|
## Conventions
|
|
@@ -293,6 +301,12 @@ either is a last resort, and never an accidental one.
|
|
|
293
301
|
`$HHOSTED_HOME/.hh/.ui` overrides the packaged UI at runtime.
|
|
294
302
|
- **A restore writes only where a config says** — archive allowlist, `origin` matching first,
|
|
295
303
|
symlinks never recreated.
|
|
304
|
+
- **The reverse proxy's engine is a process the panel owns, not a server entry.** Its generated
|
|
305
|
+
configuration is applied through the engine's admin API (atomic, never hand-edited), the engine runs
|
|
306
|
+
under the same nanny a `persistent: true` entry uses so a panel restart does not drop the socket,
|
|
307
|
+
and its admin endpoint stays panel-side — a unix socket in a `0700` directory, loopback plus the
|
|
308
|
+
engine's origin check on Windows. A route that points at the panel is exposure and obeys
|
|
309
|
+
`checkProxyExposure()`, the same bar as a non-loopback bind.
|
|
296
310
|
- **Cross-platform.** Linux/macOS/Windows: `/proc` vs `ps` vs Win32_Process, process groups vs
|
|
297
311
|
`taskkill /T`, graceful fallbacks, no shell utilities assumed.
|
|
298
312
|
- **Writes are atomic** (`writeFileAtomic`) and validated before commit.
|
|
@@ -345,6 +359,9 @@ either is a last resort, and never an accidental one.
|
|
|
345
359
|
file-only blocks on their own. The copy has to be **detached**, too: a shallow one leaves a nested
|
|
346
360
|
group (`health.http`) aliased to live state, so an edit to "Healthy below status" mutated the very
|
|
347
361
|
config the guard compared against and the next frame reset the whole editor (`cloneHealth`).
|
|
362
|
+
- **An absolutely positioned element inside a *static* scroll container resolves against the
|
|
363
|
+
page, not the scroller** — an `sr-only` label in a table row was enough to give the document a
|
|
364
|
+
second, empty scrollbar. The shell's `main` carries `relative` for that reason; keep it there.
|
|
348
365
|
- **A dialog's footer has to be a flex sibling of a scrolling body** (`uis/stock/src/components/ui/Modal.vue`):
|
|
349
366
|
the sheet is `flex flex-col` with `max-h-[88dvh]`, the body `min-h-0 flex-1 overflow-y-auto`. When
|
|
350
367
|
only the body carried a max-height, a tall form pushed its own save button below the clipped
|
|
@@ -400,5 +417,5 @@ either is a last resort, and never an accidental one.
|
|
|
400
417
|
## Publishing
|
|
401
418
|
|
|
402
419
|
`pnpm pack` runs `prepack` (a full build) and ships `bin/`, `dist/`, `uis/stock/dist`, `README.md`, `docs/DDNS.md`,
|
|
403
|
-
`docs/SERVERS.md`, `docs/NOTIFICATIONS.md`, `docs/UI_CREATION.md`, `AGENTS.md` and `LICENSE`. The bin falls back to tsx so `pnpm link` works before a
|
|
420
|
+
`docs/SERVERS.md`, `docs/NOTIFICATIONS.md`, `docs/REVERSE_PROXY.md`, `docs/UI_CREATION.md`, `AGENTS.md` and `LICENSE`. The bin falls back to tsx so `pnpm link` works before a
|
|
404
421
|
build; `vue`/`vue-router` are devDependencies because the UIs are prebuilt.
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
Point it at the things you run — a gateway, a media server, a bot, a database — and it starts
|
|
10
10
|
them, watches them, restarts what dies, and shows you one page of what is going on. Split them into
|
|
11
|
-
[workspaces](#-workspaces) when one panel holds more than one setup.
|
|
11
|
+
[workspaces](#-workspaces) when one panel holds more than one setup. And
|
|
12
12
|
[BYOU](#-bring-your-own-ui-byou), for a specialized UI that fits you exactly.
|
|
13
13
|
|
|
14
14
|
[](https://www.npmjs.com/package/home-hosted)
|
|
@@ -17,7 +17,7 @@ them, watches them, restarts what dies, and shows you one page of what is going
|
|
|
17
17
|
[](./LICENSE)
|
|
18
18
|
[](https://nodejs.org)
|
|
19
19
|
|
|
20
|
-
[🚀 Quick start](#-quick-start) · [🗂 Workspaces](#-workspaces) · [🧩 Servers](./docs/SERVERS.md) · [🤖 Agents & API](#-agents-scripts-and-tools) · [✨ Features](#-features) · [🛠 CLI](#-cli) · [🔔 Notifications](./docs/NOTIFICATIONS.md) · [🎨 BYOU](#-bring-your-own-ui-byou)
|
|
20
|
+
[🚀 Quick start](#-quick-start) · [🗂 Workspaces](#-workspaces) · [🧩 Servers](./docs/SERVERS.md) · [🤖 Agents & API](#-agents-scripts-and-tools) · [✨ Features](#-features) · [🛠 CLI](#-cli) · [🔔 Notifications](./docs/NOTIFICATIONS.md) · [🔀 Reverse proxy](./docs/REVERSE_PROXY.md) · [🎨 BYOU](#-bring-your-own-ui-byou)
|
|
21
21
|
|
|
22
22
|
</div>
|
|
23
23
|
|
|
@@ -213,19 +213,26 @@ default workspace.
|
|
|
213
213
|
<details>
|
|
214
214
|
<summary><b>🌐 The endpoints worth knowing</b></summary>
|
|
215
215
|
|
|
216
|
-
| | |
|
|
217
|
-
| --- | --- |
|
|
218
|
-
| `GET /api/state` | the full snapshot: global settings, every workspace with its servers, host vitals |
|
|
219
|
-
| `GET`/`POST /api/workspaces`, `PATCH`/`DELETE /api/workspaces/:id` | the registry: list, create, rename, remove |
|
|
220
|
-
| `GET /api/events` | SSE: the live state, plus logs (`?logs=0`, `?serverId=…`; a `server` payload carries its `workspaceId`) |
|
|
221
|
-
| `GET /api/servers
|
|
222
|
-
| `
|
|
223
|
-
| `POST /api/servers/:id/free-port` |
|
|
224
|
-
| `
|
|
225
|
-
| `GET /api/logs
|
|
226
|
-
| `PUT
|
|
227
|
-
| `
|
|
228
|
-
| `GET /api/
|
|
216
|
+
| | | `?workspace` |
|
|
217
|
+
| --- | --- | --- |
|
|
218
|
+
| `GET /api/state` | the full snapshot: global settings, every workspace with its servers, host vitals | ❌ |
|
|
219
|
+
| `GET`/`POST /api/workspaces`, `PATCH`/`DELETE /api/workspaces/:id` | the registry: list, create, rename, remove | ❌ |
|
|
220
|
+
| `GET /api/events` | SSE: the live state, plus logs (`?logs=0`, `?serverId=…`; a `server` payload carries its `workspaceId`) | ❌ |
|
|
221
|
+
| `GET`/`POST /api/servers`, `POST /api/servers/{start,stop}-all` | that workspace's entries, and its lifecycle for all of them | ✅ |
|
|
222
|
+
| `GET`/`PATCH`/`DELETE /api/servers/:id` | one entry | ✅ |
|
|
223
|
+
| `POST /api/servers/:id/{start,stop,restart}`, `POST /api/servers/:id/free-port` | one entry's lifecycle, and freeing its port | ✅ |
|
|
224
|
+
| `GET /api/servers/:id/logs`, `GET /api/servers/:id/stream` | that entry's buffered lines, and its SSE | ✅ |
|
|
225
|
+
| `GET /api/logs` | persisted history and files | ✅ |
|
|
226
|
+
| `GET`/`PUT /api/ddns`, `/api/ddns/credentials/:id`, `/api/ddns/check` | that workspace's Dynamic DNS policy, credentials and a check | ✅ |
|
|
227
|
+
| `PUT`/`DELETE /api/notifications/token`, `POST /api/notifications/{test,detect-chats}` | that workspace's bot credential and a test send | ✅ |
|
|
228
|
+
| `GET`/`PATCH /api/settings/workspace` | server defaults, logs, notifications | ✅ |
|
|
229
|
+
| `GET`/`PATCH /api/settings` | panel-wide: listener, authentication, TLS, host vitals, backups | ❌ |
|
|
230
|
+
| `GET`/`POST /api/backups`, restore | archives | ❌ |
|
|
231
|
+
| `GET /healthz` | no session needed — the one an external monitor wants (its per-server detail needs a credential) | ❌ |
|
|
232
|
+
| `GET /api/metrics` | Prometheus text (needs a token or session, like every `/api` route) | ❌ |
|
|
233
|
+
|
|
234
|
+
✅ takes `?workspace=<id>`; ❌ is panel-wide. Omitting it means the panel's default workspace — never
|
|
235
|
+
another one.
|
|
229
236
|
|
|
230
237
|
`GET /openapi/spec.json` describes all of it, `/openapi/ui` is the browsable version, and every error
|
|
231
238
|
comes back as one envelope (`{ message, code, detail }`) with a stable `code` a tool can branch on.
|
|
@@ -265,6 +272,7 @@ can be told what to be: *"Help me build a UI for home-hosted: nostalgic game the
|
|
|
265
272
|
| 🤖 **Token API** | Scripts and agents drive it with `Authorization: Bearer` — no browser, no session. [↑](#-agents-scripts-and-tools) |
|
|
266
273
|
| 🔔 **Notifications** | Telegram on crash, unhealthy, forced restart, recovery, host thresholds and DNS changes — [setup here](./docs/NOTIFICATIONS.md). |
|
|
267
274
|
| 🌐 **Dynamic DNS** | Keep hostnames pointed at your public IP — Cloudflare, Namecheap, Spaceship, Porkbun, GoDaddy, Gandi and more. [DDNS.md](./docs/DDNS.md) |
|
|
275
|
+
| 🔀 **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) |
|
|
268
276
|
| 💾 **Backups** | Two levels: pick global settings, global secrets, TLS or a whole workspace at the top, then the pieces inside it (settings, servers, secrets, data directories) — plain `.zip`, or AES-256 with a password, restored per path. |
|
|
269
277
|
| 🎨 **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) |
|
|
270
278
|
| 🔐 **Security** | Cookie sessions, API tokens, scrypt hashes, per-IP lockout, optional TLS, and a refusal to expose itself without a password. |
|
|
@@ -496,10 +504,7 @@ Two ship in this repo: `uis/stock`, and `uis/noc-console` for TUI and shortcuts
|
|
|
496
504
|
attaches both as `home-hosted-ui-<name>.zip`. Yours can be anything that compiles to static files —
|
|
497
505
|
the server never cares what built it.
|
|
498
506
|
|
|
499
|
-
<sub>Install a UI from the CLI: `home-hosted ui-switch`
|
|
500
|
-
built for this release. An **official** UI keeps itself paired with the panel: upgrade the panel and
|
|
501
|
-
the next `up` re-installs the matching asset. Someone else's UI declares its own `repo`/`asset` in
|
|
502
|
-
`ui.json`, and `home-hosted ui-update` offers its newer releases to pick from — `--old` for older ones.</sub>
|
|
507
|
+
<sub>Install a UI from the CLI: `home-hosted ui-switch` `--asset noc-console` selects an UI directly, no flags interactively show official assets. Official UIs's version auto-sync when you update `home-hosted`. For unofficial UIs, `home-hosted ui-update` offers its newer releases to pick from — or `--old` for older (author must set up `ui.json` and GH releases).</sub>
|
|
503
508
|
|
|
504
509
|
<details>
|
|
505
510
|
<summary><b>🤖 Or have an agent build the UI you actually want</b></summary>
|
|
@@ -617,6 +622,7 @@ plus types; `pnpm test` is vitest; `pnpm run media` regenerates the GIF above.
|
|
|
617
622
|
| --- | --- |
|
|
618
623
|
| declare a server: every field, placeholders, port conflicts | [SERVERS.md](./docs/SERVERS.md) |
|
|
619
624
|
| get Telegram alerts working end to end | [NOTIFICATIONS.md](./docs/NOTIFICATIONS.md) |
|
|
625
|
+
| expose the stack behind one hostname, with HTTPS | [REVERSE_PROXY.md](./docs/REVERSE_PROXY.md) |
|
|
620
626
|
| build a UI against the API | [UI_CREATION.md](./docs/UI_CREATION.md) |
|
|
621
627
|
| change the internals: architecture and the rules | [AGENTS.md](./AGENTS.md) |
|
|
622
628
|
| poke the live API on your own panel | [/openapi/ui](http://127.0.0.1:3999/openapi/ui) |
|
|
@@ -628,7 +634,7 @@ plus types; `pnpm test` is vitest; `pnpm run media` regenerates the GIF above.
|
|
|
628
634
|
<details>
|
|
629
635
|
<summary><b>🔗 Interesting resources</b></summary>
|
|
630
636
|
|
|
631
|
-
- [dsh-home-hosted](https://github.com/NamesMT/dsh-home-hosted) — home-hosted servers management with boot autostart from [DeepSeek Harness](https://github.com/deepseek-ai/dsh)
|
|
637
|
+
- [dsh-home-hosted](https://github.com/NamesMT/dsh-home-hosted) — home-hosted servers management with boot autostart from inside [DeepSeek Harness](https://github.com/deepseek-ai/dsh)
|
|
632
638
|
|
|
633
639
|
<sub><i>+ PR to add yours</i></sub>
|
|
634
640
|
|