hive-gateway: route dashboard by path, not Accept header
The dashboard vhost split static-vs-backend on the request Accept header (map $http_accept $dashboard_spa_target), so the same URL behaved differently by content-type — e.g. /api/state fetched with Accept: text/html wrongly returned index.html. Now that all hive-c0re routes live under /api/ plus the single /webhook/knowledge endpoint, route by path instead: /api/ and /webhook/ proxy to c0re (SSE settings on /api/), everything else serves the dist with try_files $uri /index.html. Drops the dashboard Accept-header map and the @c0re named location. Updates docs/gateway.md accordingly.
This commit is contained in:
parent
5ae5657ca4
commit
d4f106d590
2 changed files with 38 additions and 27 deletions
|
|
@ -6,7 +6,7 @@ Single nginx in front of every hyperhive web surface. Container `hive-gateway`,
|
|||
|
||||
| URL | vhost | upstream | source |
|
||||
| --- | --- | --- | --- |
|
||||
| `<hive>/` | `_` (catch-all) | dashboard dist (static, from `servedFrontend`) + API/SSE/actions → hive-c0re (`7000`) via `@c0re` | always |
|
||||
| `<hive>/` | `_` (catch-all) | dashboard dist (static, from `servedFrontend`); `/api/` + `/webhook/` → hive-c0re (`7000`) | always |
|
||||
| `<hive>/agent/<name>/` | `_` | per-agent harness (UDS or TCP) | `agents.conf` (runtime-generated) |
|
||||
| `<hive>/.well-known/matrix/{client,server}` | `_` | inline JSON (no upstream) | `matrix.enable && domain != null` |
|
||||
| `<hive>/matrix/` (deprecated) | `_` | 301 → `matrix.<hive>/` | `matrix.gui.enable` |
|
||||
|
|
@ -31,17 +31,24 @@ Federation peers fetch `.well-known/matrix/server` → `{"m.server":"matrix.<hiv
|
|||
|
||||
## SPA fallback (Accept-header pattern)
|
||||
|
||||
The `<hive>` catch-all (operator dashboard), the per-agent UIs, and the `matrix.<hive>` vhost all serve a flutter/SPA bundle. Two requirements collide:
|
||||
The per-agent UIs and the `matrix.<hive>` vhost serve a flutter/SPA bundle via the Accept-header pattern below. (The `<hive>` dashboard catch-all used this too but now routes by **path** — see the dashboard note after.) Two requirements collide:
|
||||
|
||||
- hard-refresh on a sub-route must serve `index.html` (SPA's client-side router takes over after JS bootstrap)
|
||||
- a non-navigation request that isn't an on-disk asset must NOT get HTML with the wrong content-type
|
||||
|
||||
Solution: an `nginx http`-context `map $http_accept $<name>_spa_target { ... }` keyed on the request's Accept header. Browser navigations (`Accept: text/html,...`) get `index.html`; everything else (`Accept: image/*`, `*/*`, `application/json`, `text/event-stream`, …) gets a sentinel nonexistent path, so `try_files $uri $<name>_spa_target <final>` falls through to `<final>`. No extension allowlist, no `if` block, no regex heuristics.
|
||||
|
||||
The two vhosts differ only in `<final>`:
|
||||
For matrix / per-agent static assets, `<final>` is `=404` (a missing asset is just missing).
|
||||
|
||||
- **matrix / per-agent static assets** → `=404` (a missing asset is just missing).
|
||||
- **dashboard** → `@c0re` (a named location that reverse-proxies to hive-c0re `7000`). The dashboard's dynamic surface — every `/api/*`, the two SSE streams, the ~20 bare action/mutation routes (`/approve/{id}`, `/kill/{name}`, `/op-send`, …), and `/webhook/knowledge` — is all `Accept != text/html`, so it lands on `@c0re` automatically, **without enumerating a single backend prefix**. This is what lets the gateway static-serve the dashboard dist (from the `servedFrontend` nix-store path) while hive-c0re stays API-only — so a frontend-only change no longer rebuilds + restarts the core daemon. `@c0re` carries `proxy_buffering off` + a 1d read timeout (for the SSE streams) and a duplicated `auth_basic` block (named locations don't inherit it). Follow-up #1846 will move every backend route under `/api/`, collapsing this to a trivial `/api/* → c0re, else static` split.
|
||||
### Dashboard: path-based routing (not Accept-header)
|
||||
|
||||
Now that every hive-c0re backend route lives under `/api/` plus the single `/webhook/knowledge` endpoint, the dashboard vhost routes by **path**, not Accept header:
|
||||
|
||||
- `location /api/` → hive-c0re (`7000`): all dashboard data, actions/mutations, and the two SSE streams (`/api/dashboard/stream`, `/api/build-logs/id/{id}/stream`). Carries `proxy_buffering off` + a 1d read timeout for the streams.
|
||||
- `location /webhook/` → hive-c0re: the knowledge webhook.
|
||||
- `location /` → the dashboard dist (from the `servedFrontend` nix-store path) with `try_files $uri /index.html` (SPA fallback).
|
||||
|
||||
Each location carries a duplicated `auth_basic` block (separate locations don't inherit it). This keeps the gateway static-serving the dashboard dist while hive-c0re stays API-only — a frontend-only change no longer rebuilds + restarts the core daemon. The earlier `map $http_accept` Accept-header split was replaced because it made the *same* URL behave differently by content-type (e.g. `/api/state` fetched with `Accept: text/html` wrongly returned `index.html`); path routing is deterministic. A new top-level c0re route prefix (beyond `/api` + `/webhook`) needs a matching `location` added to the dashboard vhost.
|
||||
|
||||
## Local dev (`localHostsEntry`)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue