gateway: nginx-hosts the full Swagger UI dist, core drops the fallback

Extends the theme-only alias into the full shape mara asked for on the
PR thread:

1. nix/packages/swagger-ui-dist.nix — plain vendored Swagger UI 5.17.14
   dist, sourced directly from the swagger-ui-dist npm package (same
   release the Rust utoipa-swagger-ui-vendored crate ships, verified
   via matching gitHead commit) rather than through Cargo.lock/cargo.
2. nix/packages/swagger-ui-theme.nix — overlays our 3 override files
   (index.html, hyperhive-theme.css, and now swagger-initializer.js)
   onto (1).
3. vhosts.nix's swaggerUiLocations now prefix-matches the whole
   /api/docs/ tree (not just 2 exact-match files) straight from (2),
   plus a `= /api/docs` redirect shim since hive-c0re's own redirect
   is going away too. /api/openapi.json (outside this prefix) keeps
   proxying to c0re unchanged — that's the one thing that stays
   dynamic.

New file swagger-initializer.js needed hand-verification: the plain
vendored copy hardcodes the swagger.io petstore demo URL.
utoipa-swagger-ui normally rewrites it per-request from a {{config}}
placeholder its own build.rs injects — since hive-c0re won't be
serving this file at all once its SwaggerUi mount is removed, that
rewrite has to be baked in statically here instead. Derived by
actually running build.rs's own two transforms (strip the default
layout: line, splice the Config JSON in place of the url/deepLinking
block) against the real vendored file, not typed from scratch —
verified byte-for-byte against what format_config() would produce for
hive-c0re's actual single-URL config, and checked with node --check.

Coordinated with damocles: he's taking the corresponding hive-c0re
side (drop the utoipa-swagger-ui dependency + SwaggerUi::new(...)
mount, keep only the plain /api/openapi.json route) once this lands.

Verified: nix fmt clean; nix build .#swagger-ui-theme succeeds, output
byte-matches the checked-in override files and node --check passes on
swagger-initializer.js; a full nixosSystem eval of nixosModules.default
resolves both new locations (/api/docs/ aliased to the right store
path, = /api/docs redirecting) with auth threaded through.
This commit is contained in:
iris 2026-08-02 20:43:19 +02:00 committed by mara
commit 1bc9c18504
8 changed files with 166 additions and 76 deletions

View file

@ -69,13 +69,13 @@
type = lib.types.package;
defaultText = lib.literalExpression "hyperhive.packages.\${system}.swagger-ui-theme";
description = ''
Swagger UI re-theme static override files (see
`nix/packages/swagger-ui-theme.nix`; output has `index.html` +
`hyperhive-theme.css`). The hive-gateway module `alias`es these
two files straight from the store over `/api/docs/`, so a theme
tweak is a gateway config change hive-c0re's own vendored
Swagger UI build is untouched. Override to ship a custom theme
(or the vendored default) without a hive-c0re rebuild.
Full Swagger UI static dist, hyperhive-themed (see
`nix/packages/swagger-ui-theme.nix`, built on
`nix/packages/swagger-ui-dist.nix`). hive-gateway serves this
whole tree directly at `/api/docs/` hive-c0re hosts none of
it, only the dynamic `/api/openapi.json` route. Override to
ship a custom theme (or the plain vendored dist) without a
hive-c0re rebuild.
'';
};
hyperhiveFlake = lib.mkOption {

View file

@ -24,10 +24,10 @@ let
# container's).
dashboardDist = "${config.services.hyperhive.c0re.servedFrontend}/dashboard";
# Swagger UI re-theme static override files — nginx `alias`es these
# straight from the store over `/api/docs/`, so a theme tweak ships
# as a gateway config change (see vhosts.nix's `swaggerThemeLocations`
# and nix/packages/swagger-ui-theme.nix).
# Full hyperhive-themed Swagger UI dist — nginx serves this whole
# tree straight from the store at /api/docs/, no hive-c0re fallback
# (see vhosts.nix's `swaggerUiLocations` and
# nix/packages/swagger-ui-{dist,theme}.nix).
swaggerUiTheme = config.services.hyperhive.c0re.swaggerUiTheme;
# Self-signed TLS is the implicit floor: when neither an operator cert

View file

@ -306,28 +306,35 @@ let
};
};
# Swagger UI re-theme: exact-match locations `alias`ed straight to
# `swaggerUiTheme`'s store path, nginx-served with no involvement
# from hive-c0re at all. `=` locations win over the `/api/` prefix
# block above regardless of declaration order (nginx's own location-
# matching precedence — exact match beats longest-prefix), so this
# doesn't need to be declared before it. Every OTHER Swagger UI asset
# (bundle.js, openapi.json, favicons, the *vendored* index.html c0re
# would otherwise serve) still falls through `/api/` to c0re's own
# embedded `utoipa-swagger-ui` dist unchanged — only these two exact
# paths are intercepted. A theme tweak is therefore a change to
# `hive-c0re/swagger-ui-theme/` + a gateway container activation, not
# a hive-c0re rebuild+restart. See nix/packages/swagger-ui-theme.nix.
swaggerThemeLocations = {
"= /api/docs/" = {
# Swagger UI: nginx hosts the FULL themed dist (`swaggerUiTheme` —
# vendored Swagger UI + our overlay, see nix/packages/swagger-ui-
# dist.nix + swagger-ui-theme.nix) straight from the store, with NO
# fallback to hive-c0re at all — per the operator's shape: "core
# should not need the swagger ui at all if it is hosted in gateway"
# / "core only hosts the json". Only `/api/openapi.json`
# (the live-generated spec `index.html` fetches; not under this
# prefix) still proxies to c0re via "/api/" below — that's the one
# thing that has to stay dynamic.
#
# Prefix location, not exact-match: wins over "/api/" on plain
# prefix length (no ordering/`=` needed), and now needs to cover
# every file in the tree (bundle.js, maps, favicons, …), not just
# our 2 override files — hive-c0re no longer serves any of this as
# a fallback once its own `utoipa-swagger-ui` mount is removed.
# `= /api/docs` (no trailing slash) issues the same redirect
# `utoipa-swagger-ui`'s router used to: that mount is going away
# too, so nginx has to own it now, or the H0M3 hub's own `/api/docs`
# link (no trailing slash) would 404 once hive-c0re drops the route.
swaggerUiLocations = {
"= /api/docs" = {
extraConfig = ''
alias ${swaggerUiTheme}/index.html;
${dashboardAuth}
return 301 /api/docs/;
'';
};
"= /api/docs/hyperhive-theme.css" = {
"/api/docs/" = {
alias = "${swaggerUiTheme}/";
extraConfig = ''
alias ${swaggerUiTheme}/hyperhive-theme.css;
index index.html;
${dashboardAuth}
'';
};
@ -353,7 +360,7 @@ in
// wellKnownLocations
// agentLocations
// dashboardProxyLocation
// swaggerThemeLocations
// swaggerUiLocations
// lib.optionalAttrs cfg.auth.enable {
# Internal-only target for the 401 error_page above.
# `internal` prevents direct client access; `alias` serves