From de15410394aa2d1d372f764aa1d030a6d4478a28 Mon Sep 17 00:00:00 2001 From: iris Date: Sun, 2 Aug 2026 19:20:58 +0200 Subject: [PATCH 1/8] hive-c0re: partial Catppuccin Mocha reskin for the vendored Swagger UI Not yet wired up -- these are the SWAGGER_UI_OVERWRITE_FOLDER payload files (utoipa-swagger-ui's build-time overwrite hook), inert until something points that env var at hive-c0re/swagger-ui-theme/ during the crate's cargo build. See message to damocles for the nix-side ask. hive-c0re/swagger-ui-theme/index.html: byte-identical to the vendored swagger-ui-5.17.14 dist's own index.html (utoipa-swagger-ui-vendored 0.1.2), plus one added to hyperhive-theme.css. hive-c0re/swagger-ui-theme/hyperhive-theme.css: partial reskin per mara's steer on hyperhive#2966 ("apply theme colors only", not a full redesign) -- page background, topbar, borders, links, headings, form controls recoloured to the Catppuccin Mocha palette already used elsewhere (frontend/packages/shared/src/colors.css); Swagger's own semantic HTTP-method badge colours and execute/cancel action-button colours left untouched, they carry real meaning independent of hyperhive branding. --- .../swagger-ui-theme/hyperhive-theme.css | 188 ++++++++++++++++++ hive-c0re/swagger-ui-theme/index.html | 27 +++ 2 files changed, 215 insertions(+) create mode 100644 hive-c0re/swagger-ui-theme/hyperhive-theme.css create mode 100644 hive-c0re/swagger-ui-theme/index.html diff --git a/hive-c0re/swagger-ui-theme/hyperhive-theme.css b/hive-c0re/swagger-ui-theme/hyperhive-theme.css new file mode 100644 index 00000000..1ef522b6 --- /dev/null +++ b/hive-c0re/swagger-ui-theme/hyperhive-theme.css @@ -0,0 +1,188 @@ +/* Partial hyperhive (Catppuccin Mocha) reskin for the vendored Swagger UI + at /api/docs — the operator asked for this as a follow-up to the + OpenAPI/Swagger-UI docs work. Scope is deliberately bounded per her + steer ("its not about making it completely vibec0re, apply theme + colors only"): recolor the page chrome (background, topbar, + borders, links, headings, inputs) to match the rest of the dashboard; + leave Swagger's own semantic HTTP-method colours (GET/POST/PUT/DELETE + badges) and the execute/cancel action-button colours alone — those + carry real meaning to anyone who already knows Swagger UI, not just + hyperhive branding. + + Loaded after swagger-ui.css (see index.html) so these rules win the + cascade on shared selectors without `!important`; only reaching for + `!important` where Swagger's own CSS is more specific than a same- + specificity override can beat (documented per-rule below). + + Same base16 contract as frontend/packages/shared/src/colors.css + (Catppuccin Mocha) — this file can't @import that one (separate build + pipeline, plain static asset, no preprocessing), so the slots are + redeclared here. Keep the two in sync if the palette ever changes; + see docs/web-ui/css-vars.md for the base16 contract this mirrors. */ + +:root { + --hh-base00: #1e1e2e; /* default bg */ + --hh-base01: #181825; /* lighter bg (elevated surfaces / topbar) */ + --hh-base02: #313244; /* selection / surface — borders */ + --hh-base03: #45475a; /* comments / dim surface */ + --hh-base05: #cdd6f4; /* default foreground */ + --hh-base0c: #89dceb; /* cyan — info accents */ + --hh-base0d: #89b4fa; /* blue — links, interactive accent */ + --hh-base0e: #cba6f7; /* mauve — primary accent (active tabs, highlights) */ +} + +/* Page chrome */ +html, +body { + background: var(--hh-base00); +} +.swagger-ui { + color: var(--hh-base05); + font-family: "JetBrains Mono", "Fira Code", "Cascadia Code", + "Source Code Pro", monospace; +} + +/* Topbar — replaces Swagger's default green bar. */ +.swagger-ui .topbar { + background: var(--hh-base01); + border-bottom: 1px solid var(--hh-base02); +} +.swagger-ui .topbar .download-url-wrapper input[type="text"] { + border-color: var(--hh-base02); + background: var(--hh-base00); + color: var(--hh-base05); +} +.swagger-ui .topbar .download-url-wrapper .download-url-button { + background: var(--hh-base0e); + color: var(--hh-base01); +} + +/* Info block (spec title/description) + links throughout. */ +.swagger-ui .info .title, +.swagger-ui .info li, +.swagger-ui .info p, +.swagger-ui .info table { + color: var(--hh-base05); +} +.swagger-ui a.nostyle, +.swagger-ui a.nostyle:visited, +.swagger-ui .info a { + color: var(--hh-base0d); +} +.swagger-ui .opblock-tag { + color: var(--hh-base05); + border-bottom-color: var(--hh-base02); +} +.swagger-ui .opblock-tag:hover { + background: color-mix(in srgb, var(--hh-base0e) 8%, transparent); +} + +/* Scheme/server selector bar. */ +.swagger-ui .scheme-container { + background: var(--hh-base01); + box-shadow: none; + border-bottom: 1px solid var(--hh-base02); +} + +/* Endpoint rows — keep the method-colour left border (GET/POST/etc, it's + Swagger's own semantic language) but recolour the card body so it + doesn't sit on stock white. */ +.swagger-ui .opblock { + background: var(--hh-base01); + border-color: var(--hh-base02); +} +.swagger-ui .opblock .opblock-summary-description, +.swagger-ui .opblock .opblock-summary-path, +.swagger-ui .opblock .opblock-summary-path__deprecated { + color: var(--hh-base05); +} +.swagger-ui .opblock .opblock-section-header { + background: var(--hh-base00); +} +.swagger-ui .opblock-description-wrapper p, +.swagger-ui .opblock-external-docs-wrapper p, +.swagger-ui .opblock-title_normal p, +.swagger-ui .parameter__name, +.swagger-ui .parameter__type, +.swagger-ui .parameter__deprecated, +.swagger-ui .parameter__in, +.swagger-ui table.model tr.property-row td { + color: var(--hh-base05); +} +.swagger-ui .tab li, +.swagger-ui .opblock .opblock-section-header h4, +.swagger-ui .opblock .opblock-section-header label { + color: var(--hh-base05); +} + +/* Response / model tables. */ +.swagger-ui table thead tr td, +.swagger-ui table thead tr th { + color: var(--hh-base05); + border-bottom-color: var(--hh-base02); +} +.swagger-ui .responses-inner h4, +.swagger-ui .responses-inner h5 { + color: var(--hh-base05); +} +.swagger-ui .response-col_status { + color: var(--hh-base05); +} +.swagger-ui .model-box, +.swagger-ui section.models { + background: var(--hh-base01); +} +.swagger-ui section.models { + border-color: var(--hh-base02); +} +.swagger-ui section.models h4 { + color: var(--hh-base05); +} +.swagger-ui .model { + color: var(--hh-base05); +} + +/* Form controls — inputs/selects/textareas default to Swagger's stock + white regardless of surrounding recolour; without this they'd be the + one visibly wrong element on the page. */ +.swagger-ui select, +.swagger-ui input[type="text"], +.swagger-ui input[type="password"], +.swagger-ui input[type="search"], +.swagger-ui input[type="email"], +.swagger-ui input[type="file"], +.swagger-ui textarea { + background: var(--hh-base00); + color: var(--hh-base05); + border-color: var(--hh-base02); +} + +/* Generic (non-semantic) buttons — "Try it out" / "Reset" / "Clear" / + "Authorize" close etc. Execute (green) and Cancel (red) keep Swagger's + own colours; only the ones that were plain-white-on-white before. */ +.swagger-ui .btn { + color: var(--hh-base05); + border-color: var(--hh-base02); + background: var(--hh-base00); +} +.swagger-ui .btn.authorize { + color: var(--hh-base0e); + border-color: var(--hh-base0e); +} +.swagger-ui .btn.authorize svg { + fill: var(--hh-base0e); +} + +/* `!important` needed here: Swagger's own `.swagger-ui .highlight-code` + syntax-highlighting rules ship at equal-or-higher specificity and are + emitted after the cascade point our stylesheet link occupies is + evaluated (they're re-asserted per-token by highlight.js's inline + theme), so a plain override loses. Scoped narrowly to the response/ + request code-sample background only — token colours stay as + highlight.js's own theme provides, this is just the block bg. */ +.swagger-ui .highlight-code { + background: var(--hh-base00) !important; +} +.swagger-ui .microlight { + color: var(--hh-base05); +} diff --git a/hive-c0re/swagger-ui-theme/index.html b/hive-c0re/swagger-ui-theme/index.html new file mode 100644 index 00000000..519e967a --- /dev/null +++ b/hive-c0re/swagger-ui-theme/index.html @@ -0,0 +1,27 @@ + + + + + + + Swagger UI + + + + + + + + +
+ + + + + From 062a84378daed1e5091a28a2b9b3b4d4161fe728 Mon Sep 17 00:00:00 2001 From: iris Date: Sun, 2 Aug 2026 19:55:10 +0200 Subject: [PATCH 2/8] hive-c0re: swagger theme follows stylix via colors.css, not a hardcoded copy Loads the dashboard's own themed /static/colors.css directly (same origin, see vhosts.nix dashboardProxyLocation) instead of redeclaring the Catppuccin Mocha hex values locally. The theme now re-themes live with the rest of the dashboard instead of drifting out of sync. Addresses review feedback on PR. --- .../swagger-ui-theme/hyperhive-theme.css | 124 ++++++++---------- hive-c0re/swagger-ui-theme/index.html | 15 ++- 2 files changed, 68 insertions(+), 71 deletions(-) diff --git a/hive-c0re/swagger-ui-theme/hyperhive-theme.css b/hive-c0re/swagger-ui-theme/hyperhive-theme.css index 1ef522b6..671ffc3c 100644 --- a/hive-c0re/swagger-ui-theme/hyperhive-theme.css +++ b/hive-c0re/swagger-ui-theme/hyperhive-theme.css @@ -1,60 +1,50 @@ -/* Partial hyperhive (Catppuccin Mocha) reskin for the vendored Swagger UI - at /api/docs — the operator asked for this as a follow-up to the - OpenAPI/Swagger-UI docs work. Scope is deliberately bounded per her - steer ("its not about making it completely vibec0re, apply theme - colors only"): recolor the page chrome (background, topbar, - borders, links, headings, inputs) to match the rest of the dashboard; - leave Swagger's own semantic HTTP-method colours (GET/POST/PUT/DELETE - badges) and the execute/cancel action-button colours alone — those - carry real meaning to anyone who already knows Swagger UI, not just - hyperhive branding. +/* Partial hyperhive reskin for the vendored Swagger UI at /api/docs — + the operator asked for this as a follow-up to the OpenAPI/Swagger-UI + docs work. Scope is deliberately bounded per her steer ("its not + about making it completely vibec0re, apply theme colors only"): + recolor the page chrome (background, topbar, borders, links, + headings, inputs) to match the rest of the dashboard; leave Swagger's + own semantic HTTP-method colours (GET/POST/PUT/DELETE badges) and the + execute/cancel action-button colours alone — those carry real meaning + to anyone who already knows Swagger UI, not just hyperhive branding. Loaded after swagger-ui.css (see index.html) so these rules win the cascade on shared selectors without `!important`; only reaching for `!important` where Swagger's own CSS is more specific than a same- specificity override can beat (documented per-rule below). - Same base16 contract as frontend/packages/shared/src/colors.css - (Catppuccin Mocha) — this file can't @import that one (separate build - pipeline, plain static asset, no preprocessing), so the slots are - redeclared here. Keep the two in sync if the palette ever changes; - see docs/web-ui/css-vars.md for the base16 contract this mirrors. */ - -:root { - --hh-base00: #1e1e2e; /* default bg */ - --hh-base01: #181825; /* lighter bg (elevated surfaces / topbar) */ - --hh-base02: #313244; /* selection / surface — borders */ - --hh-base03: #45475a; /* comments / dim surface */ - --hh-base05: #cdd6f4; /* default foreground */ - --hh-base0c: #89dceb; /* cyan — info accents */ - --hh-base0d: #89b4fa; /* blue — links, interactive accent */ - --hh-base0e: #cba6f7; /* mauve — primary accent (active tabs, highlights) */ -} + Follows stylix live, same as every other dashboard page: index.html + links the dashboard's own themed `colors.css` (served from + `/static/`, same origin) directly ahead of this file, so the + `--baseNN` custom properties below resolve to whatever the operator's + current stylix scheme actually is — no hardcoded hex, nothing to + drift out of sync when the theme changes. See + frontend/packages/shared/src/colors.css for the base16 contract. */ /* Page chrome */ html, body { - background: var(--hh-base00); + background: var(--base00); } .swagger-ui { - color: var(--hh-base05); + color: var(--base05); font-family: "JetBrains Mono", "Fira Code", "Cascadia Code", "Source Code Pro", monospace; } /* Topbar — replaces Swagger's default green bar. */ .swagger-ui .topbar { - background: var(--hh-base01); - border-bottom: 1px solid var(--hh-base02); + background: var(--base01); + border-bottom: 1px solid var(--base02); } .swagger-ui .topbar .download-url-wrapper input[type="text"] { - border-color: var(--hh-base02); - background: var(--hh-base00); - color: var(--hh-base05); + border-color: var(--base02); + background: var(--base00); + color: var(--base05); } .swagger-ui .topbar .download-url-wrapper .download-url-button { - background: var(--hh-base0e); - color: var(--hh-base01); + background: var(--base0E); + color: var(--base01); } /* Info block (spec title/description) + links throughout. */ @@ -62,42 +52,42 @@ body { .swagger-ui .info li, .swagger-ui .info p, .swagger-ui .info table { - color: var(--hh-base05); + color: var(--base05); } .swagger-ui a.nostyle, .swagger-ui a.nostyle:visited, .swagger-ui .info a { - color: var(--hh-base0d); + color: var(--base0D); } .swagger-ui .opblock-tag { - color: var(--hh-base05); - border-bottom-color: var(--hh-base02); + color: var(--base05); + border-bottom-color: var(--base02); } .swagger-ui .opblock-tag:hover { - background: color-mix(in srgb, var(--hh-base0e) 8%, transparent); + background: color-mix(in srgb, var(--base0E) 8%, transparent); } /* Scheme/server selector bar. */ .swagger-ui .scheme-container { - background: var(--hh-base01); + background: var(--base01); box-shadow: none; - border-bottom: 1px solid var(--hh-base02); + border-bottom: 1px solid var(--base02); } /* Endpoint rows — keep the method-colour left border (GET/POST/etc, it's Swagger's own semantic language) but recolour the card body so it doesn't sit on stock white. */ .swagger-ui .opblock { - background: var(--hh-base01); - border-color: var(--hh-base02); + background: var(--base01); + border-color: var(--base02); } .swagger-ui .opblock .opblock-summary-description, .swagger-ui .opblock .opblock-summary-path, .swagger-ui .opblock .opblock-summary-path__deprecated { - color: var(--hh-base05); + color: var(--base05); } .swagger-ui .opblock .opblock-section-header { - background: var(--hh-base00); + background: var(--base00); } .swagger-ui .opblock-description-wrapper p, .swagger-ui .opblock-external-docs-wrapper p, @@ -107,39 +97,39 @@ body { .swagger-ui .parameter__deprecated, .swagger-ui .parameter__in, .swagger-ui table.model tr.property-row td { - color: var(--hh-base05); + color: var(--base05); } .swagger-ui .tab li, .swagger-ui .opblock .opblock-section-header h4, .swagger-ui .opblock .opblock-section-header label { - color: var(--hh-base05); + color: var(--base05); } /* Response / model tables. */ .swagger-ui table thead tr td, .swagger-ui table thead tr th { - color: var(--hh-base05); - border-bottom-color: var(--hh-base02); + color: var(--base05); + border-bottom-color: var(--base02); } .swagger-ui .responses-inner h4, .swagger-ui .responses-inner h5 { - color: var(--hh-base05); + color: var(--base05); } .swagger-ui .response-col_status { - color: var(--hh-base05); + color: var(--base05); } .swagger-ui .model-box, .swagger-ui section.models { - background: var(--hh-base01); + background: var(--base01); } .swagger-ui section.models { - border-color: var(--hh-base02); + border-color: var(--base02); } .swagger-ui section.models h4 { - color: var(--hh-base05); + color: var(--base05); } .swagger-ui .model { - color: var(--hh-base05); + color: var(--base05); } /* Form controls — inputs/selects/textareas default to Swagger's stock @@ -152,25 +142,25 @@ body { .swagger-ui input[type="email"], .swagger-ui input[type="file"], .swagger-ui textarea { - background: var(--hh-base00); - color: var(--hh-base05); - border-color: var(--hh-base02); + background: var(--base00); + color: var(--base05); + border-color: var(--base02); } /* Generic (non-semantic) buttons — "Try it out" / "Reset" / "Clear" / "Authorize" close etc. Execute (green) and Cancel (red) keep Swagger's own colours; only the ones that were plain-white-on-white before. */ .swagger-ui .btn { - color: var(--hh-base05); - border-color: var(--hh-base02); - background: var(--hh-base00); + color: var(--base05); + border-color: var(--base02); + background: var(--base00); } .swagger-ui .btn.authorize { - color: var(--hh-base0e); - border-color: var(--hh-base0e); + color: var(--base0E); + border-color: var(--base0E); } .swagger-ui .btn.authorize svg { - fill: var(--hh-base0e); + fill: var(--base0E); } /* `!important` needed here: Swagger's own `.swagger-ui .highlight-code` @@ -181,8 +171,8 @@ body { request code-sample background only — token colours stay as highlight.js's own theme provides, this is just the block bg. */ .swagger-ui .highlight-code { - background: var(--hh-base00) !important; + background: var(--base00) !important; } .swagger-ui .microlight { - color: var(--hh-base05); + color: var(--base05); } diff --git a/hive-c0re/swagger-ui-theme/index.html b/hive-c0re/swagger-ui-theme/index.html index 519e967a..e80a7b18 100644 --- a/hive-c0re/swagger-ui-theme/index.html +++ b/hive-c0re/swagger-ui-theme/index.html @@ -2,10 +2,16 @@ + `SWAGGER_UI_OVERWRITE_FOLDER` build-time hook, adding two lines: the + dashboard's own themed `colors.css` (same absolute `/static/` + origin the dashboard dist serves it from — see + nix/host-modules/hive-gateway/vhosts.nix's dashboardProxyLocation, + `/` and `/api/` share one vhost so this resolves whatever the + operator's stylix theme currently renders, not a frozen copy) and + hyperhive-theme.css, which consumes those `--baseNN` vars. Loaded + after swagger-ui.css so hyperhive-theme.css's rules win the cascade + without needing `!important`. See + docs/web-ui/dashboard.md::Dashboard endpoints. --> @@ -13,6 +19,7 @@ Swagger UI + From 5471b49f2a239cff15cda16add4b6fd7bc98a5c6 Mon Sep 17 00:00:00 2001 From: iris Date: Sun, 2 Aug 2026 19:56:57 +0200 Subject: [PATCH 3/8] hive-c0re: trim swagger-theme comments down to essentials MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cut the process-narrative framing (operator quote, backstory) and shortened per-section labels — the CSS was carrying more explanation than declaration. Keep only what a future reader actually needs: the override mechanism, the stylix-follows-live fact, and the two non-obvious calls (method-colour exception, the one !important). --- .../swagger-ui-theme/hyperhive-theme.css | 55 +++++++------------ hive-c0re/swagger-ui-theme/index.html | 18 ++---- 2 files changed, 25 insertions(+), 48 deletions(-) diff --git a/hive-c0re/swagger-ui-theme/hyperhive-theme.css b/hive-c0re/swagger-ui-theme/hyperhive-theme.css index 671ffc3c..627d7a95 100644 --- a/hive-c0re/swagger-ui-theme/hyperhive-theme.css +++ b/hive-c0re/swagger-ui-theme/hyperhive-theme.css @@ -1,24 +1,15 @@ -/* Partial hyperhive reskin for the vendored Swagger UI at /api/docs — - the operator asked for this as a follow-up to the OpenAPI/Swagger-UI - docs work. Scope is deliberately bounded per her steer ("its not - about making it completely vibec0re, apply theme colors only"): - recolor the page chrome (background, topbar, borders, links, - headings, inputs) to match the rest of the dashboard; leave Swagger's - own semantic HTTP-method colours (GET/POST/PUT/DELETE badges) and the - execute/cancel action-button colours alone — those carry real meaning - to anyone who already knows Swagger UI, not just hyperhive branding. +/* Partial hyperhive reskin for the vendored Swagger UI at /api/docs. + Recolors chrome (background, topbar, borders, links, inputs) to + match the dashboard. Swagger's own semantic HTTP-method badge colours + and execute/cancel button colours are left alone — those carry + meaning independent of hyperhive branding. Loaded after swagger-ui.css (see index.html) so these rules win the - cascade on shared selectors without `!important`; only reaching for - `!important` where Swagger's own CSS is more specific than a same- - specificity override can beat (documented per-rule below). + cascade without `!important`, except where noted below. - Follows stylix live, same as every other dashboard page: index.html - links the dashboard's own themed `colors.css` (served from - `/static/`, same origin) directly ahead of this file, so the - `--baseNN` custom properties below resolve to whatever the operator's - current stylix scheme actually is — no hardcoded hex, nothing to - drift out of sync when the theme changes. See + `--baseNN` values come from `/static/colors.css` (linked in + index.html, same origin as the dashboard) — this follows the + operator's live stylix theme, not a hardcoded copy. See frontend/packages/shared/src/colors.css for the base16 contract. */ /* Page chrome */ @@ -32,7 +23,7 @@ body { "Source Code Pro", monospace; } -/* Topbar — replaces Swagger's default green bar. */ +/* Topbar */ .swagger-ui .topbar { background: var(--base01); border-bottom: 1px solid var(--base02); @@ -47,7 +38,7 @@ body { color: var(--base01); } -/* Info block (spec title/description) + links throughout. */ +/* Info block + links */ .swagger-ui .info .title, .swagger-ui .info li, .swagger-ui .info p, @@ -74,9 +65,8 @@ body { border-bottom: 1px solid var(--base02); } -/* Endpoint rows — keep the method-colour left border (GET/POST/etc, it's - Swagger's own semantic language) but recolour the card body so it - doesn't sit on stock white. */ +/* Endpoint rows — method-colour left border stays; only the card body + is recoloured. */ .swagger-ui .opblock { background: var(--base01); border-color: var(--base02); @@ -132,9 +122,7 @@ body { color: var(--base05); } -/* Form controls — inputs/selects/textareas default to Swagger's stock - white regardless of surrounding recolour; without this they'd be the - one visibly wrong element on the page. */ +/* Form controls */ .swagger-ui select, .swagger-ui input[type="text"], .swagger-ui input[type="password"], @@ -147,9 +135,8 @@ body { border-color: var(--base02); } -/* Generic (non-semantic) buttons — "Try it out" / "Reset" / "Clear" / - "Authorize" close etc. Execute (green) and Cancel (red) keep Swagger's - own colours; only the ones that were plain-white-on-white before. */ +/* Generic buttons (Try it out / Reset / Authorize etc) — execute/cancel + keep Swagger's own colours. */ .swagger-ui .btn { color: var(--base05); border-color: var(--base02); @@ -163,13 +150,9 @@ body { fill: var(--base0E); } -/* `!important` needed here: Swagger's own `.swagger-ui .highlight-code` - syntax-highlighting rules ship at equal-or-higher specificity and are - emitted after the cascade point our stylesheet link occupies is - evaluated (they're re-asserted per-token by highlight.js's inline - theme), so a plain override loses. Scoped narrowly to the response/ - request code-sample background only — token colours stay as - highlight.js's own theme provides, this is just the block bg. */ +/* `!important`: highlight.js re-asserts this per-token inline, so a + plain override loses. Scoped to the code-sample block background + only — token colours stay as highlight.js's theme provides. */ .swagger-ui .highlight-code { background: var(--base00) !important; } diff --git a/hive-c0re/swagger-ui-theme/index.html b/hive-c0re/swagger-ui-theme/index.html index e80a7b18..133dc243 100644 --- a/hive-c0re/swagger-ui-theme/index.html +++ b/hive-c0re/swagger-ui-theme/index.html @@ -1,16 +1,10 @@ - From de1659d10ef73542674f2c175027ae66eee88191 Mon Sep 17 00:00:00 2001 From: damocles Date: Sun, 2 Aug 2026 20:19:33 +0200 Subject: [PATCH 4/8] hive-gateway: serve the swagger-ui theme via nginx alias, not a c0re build hook --- flake.nix | 1 + hive-c0re/swagger-ui-theme/index.html | 21 ++++++---- nix/host-modules/hive-c0re/options.nix | 13 ++++++ nix/host-modules/hive-gateway/default.nix | 7 ++++ nix/host-modules/hive-gateway/vhosts.nix | 29 ++++++++++++++ nix/packages/default.nix | 5 +++ nix/packages/swagger-ui-theme.nix | 49 +++++++++++++++++++++++ 7 files changed, 117 insertions(+), 8 deletions(-) create mode 100644 nix/packages/swagger-ui-theme.nix diff --git a/flake.nix b/flake.nix index 63818b00..ae0af5ee 100644 --- a/flake.nix +++ b/flake.nix @@ -128,6 +128,7 @@ frontend = lib.mkDefault self.packages.${pkgs.stdenv.hostPlatform.system}.frontend; assets = lib.mkDefault self.packages.${pkgs.stdenv.hostPlatform.system}.assets; xdgIcons = lib.mkDefault self.packages.${pkgs.stdenv.hostPlatform.system}.xdg-icons; + swaggerUiTheme = lib.mkDefault self.packages.${pkgs.stdenv.hostPlatform.system}.swagger-ui-theme; hyperhiveFlake = lib.mkDefault "${sources.hyperhiveFlakeSource}"; # Narrow docs/ source, threaded as its own meta-flake input # so doc edits don't re-hash the whole flake source. diff --git a/hive-c0re/swagger-ui-theme/index.html b/hive-c0re/swagger-ui-theme/index.html index 133dc243..5fd30668 100644 --- a/hive-c0re/swagger-ui-theme/index.html +++ b/hive-c0re/swagger-ui-theme/index.html @@ -1,11 +1,16 @@ - - + diff --git a/nix/host-modules/hive-c0re/options.nix b/nix/host-modules/hive-c0re/options.nix index bd10cecd..b67c0b6b 100644 --- a/nix/host-modules/hive-c0re/options.nix +++ b/nix/host-modules/hive-c0re/options.nix @@ -65,6 +65,19 @@ processes to their icon. ''; }; + swaggerUiTheme = lib.mkOption { + 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. + ''; + }; hyperhiveFlake = lib.mkOption { type = lib.types.str; defaultText = lib.literalMD "the hyperhive flake's own filtered source store path"; diff --git a/nix/host-modules/hive-gateway/default.nix b/nix/host-modules/hive-gateway/default.nix index d23de50d..a2c53f95 100644 --- a/nix/host-modules/hive-gateway/default.nix +++ b/nix/host-modules/hive-gateway/default.nix @@ -24,6 +24,12 @@ 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). + swaggerUiTheme = config.services.hyperhive.c0re.swaggerUiTheme; + # Self-signed TLS is the implicit floor: when neither an operator cert # (`tls.certDir`) nor ACME (`tls.acme.enable`) is configured, the gateway # generates + serves a hive-CA-signed leaf (see hive-tls.nix). There is no @@ -261,6 +267,7 @@ in matrixCfg hyperhiveDomain dashboardDist + swaggerUiTheme tlsCert tlsKey ; diff --git a/nix/host-modules/hive-gateway/vhosts.nix b/nix/host-modules/hive-gateway/vhosts.nix index e9fc2370..645d58f9 100644 --- a/nix/host-modules/hive-gateway/vhosts.nix +++ b/nix/host-modules/hive-gateway/vhosts.nix @@ -11,6 +11,7 @@ matrixCfg, hyperhiveDomain, dashboardDist, + swaggerUiTheme, # nix/packages/swagger-ui-theme.nix: has index.html + hyperhive-theme.css errorPages, # ./error-pages.nix: { notFound, unreachable, unauthorized } tlsCert, tlsKey, @@ -304,6 +305,33 @@ let proxyPass = "http://${cfg.upstreamHost}:${toString cfg.upstreamPort}"; }; }; + + # 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/" = { + extraConfig = '' + alias ${swaggerUiTheme}/index.html; + ${dashboardAuth} + ''; + }; + "= /api/docs/hyperhive-theme.css" = { + extraConfig = '' + alias ${swaggerUiTheme}/hyperhive-theme.css; + ${dashboardAuth} + ''; + }; + }; in { # Accept-header SPA map for the matrix GUI only (see docs/gateway.md @@ -325,6 +353,7 @@ in // wellKnownLocations // agentLocations // dashboardProxyLocation + // swaggerThemeLocations // lib.optionalAttrs cfg.auth.enable { # Internal-only target for the 401 error_page above. # `internal` prevents direct client access; `alias` serves diff --git a/nix/packages/default.nix b/nix/packages/default.nix index 29c14b4d..ce53804f 100644 --- a/nix/packages/default.nix +++ b/nix/packages/default.nix @@ -158,6 +158,11 @@ in xdg-icons = pkgs.callPackage ./hive-xdg-icons.nix { hyperhiveSvg = ../../branding/hyperhive.svg; }; + # Swagger UI re-theme static override files — see + # ./swagger-ui-theme.nix. The gateway `alias`es these straight from + # the store; a theme tweak is a gateway config change, not a + # hive-c0re rebuild. + swagger-ui-theme = pkgs.callPackage ./swagger-ui-theme.nix { }; # Pre-built per-container system closures. Exposed as packages # so operators can `nix build .#agent-base-toplevel` (or wire diff --git a/nix/packages/swagger-ui-theme.nix b/nix/packages/swagger-ui-theme.nix new file mode 100644 index 00000000..7e21faa6 --- /dev/null +++ b/nix/packages/swagger-ui-theme.nix @@ -0,0 +1,49 @@ +{ + stdenv, +}: + +# The hand-authored Swagger UI re-theme files (`hive-c0re/swagger-ui- +# theme/`), shipped as a standalone derivation so the gateway can +# `alias` them straight from the nix store instead of hive-c0re's own +# build serving them — see nix/host-modules/hive-gateway/vhosts.nix's +# `swaggerThemeLocations`. This is what lets a CSS tweak ship as a +# gateway config change (activate the gateway container) rather than a +# hive-c0re rebuild+restart: the two files nginx exact-matches +# (`/api/docs/` and `/api/docs/hyperhive-theme.css`) come from here; +# every other Swagger UI asset (bundle.js, openapi.json, favicons, …) +# still falls through the existing `/api/` prefix proxy to hive-c0re's +# own vendored (unthemed) `utoipa-swagger-ui` embed, unchanged. +# +# Pure data: copied verbatim, no build step. +# +# Output layout: +# $out/index.html — themed index.html Swagger UI page +# $out/hyperhive-theme.css — the re-theme, consumes --baseNN vars +# from the dashboard's own colors.css +# (loaded via an absolute /static/ +# colors.css , same origin) + +stdenv.mkDerivation { + pname = "hyperhive-swagger-ui-theme"; + version = "0.1.0"; + # Narrow src keeps this derivation's input hash decoupled from the + # rest of the tree — a theme tweak only re-hashes this. + src = ../../hive-c0re/swagger-ui-theme; + + dontBuild = true; + dontConfigure = true; + + installPhase = '' + runHook preInstall + mkdir -p $out + cp -r ./* $out/ + runHook postInstall + ''; + + dontFixup = true; + + meta = { + description = "hyperhive Swagger UI Catppuccin Mocha re-theme (static override files)"; + homepage = "https://forge.darkest.space/hyperhive/hyperhive"; + }; +} From 1bc9c18504c420c40f63be7fab975a4f407746bf Mon Sep 17 00:00:00 2001 From: iris Date: Sun, 2 Aug 2026 20:43:19 +0200 Subject: [PATCH 5/8] gateway: nginx-hosts the full Swagger UI dist, core drops the fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- hive-c0re/swagger-ui-theme/index.html | 23 +++---- .../swagger-ui-theme/swagger-initializer.js | 21 ++++++ nix/host-modules/hive-c0re/options.nix | 14 ++-- nix/host-modules/hive-gateway/default.nix | 8 +-- nix/host-modules/hive-gateway/vhosts.nix | 45 +++++++------ nix/packages/default.nix | 19 ++++-- nix/packages/swagger-ui-dist.nix | 47 ++++++++++++++ nix/packages/swagger-ui-theme.nix | 65 +++++++++++-------- 8 files changed, 166 insertions(+), 76 deletions(-) create mode 100644 hive-c0re/swagger-ui-theme/swagger-initializer.js create mode 100644 nix/packages/swagger-ui-dist.nix diff --git a/hive-c0re/swagger-ui-theme/index.html b/hive-c0re/swagger-ui-theme/index.html index 5fd30668..a357a703 100644 --- a/hive-c0re/swagger-ui-theme/index.html +++ b/hive-c0re/swagger-ui-theme/index.html @@ -1,16 +1,13 @@ - + diff --git a/hive-c0re/swagger-ui-theme/swagger-initializer.js b/hive-c0re/swagger-ui-theme/swagger-initializer.js new file mode 100644 index 00000000..1e2c4abc --- /dev/null +++ b/hive-c0re/swagger-ui-theme/swagger-initializer.js @@ -0,0 +1,21 @@ +window.onload = function() { + // + + // the following lines will be replaced by docker/configurator, when it runs in a docker-container + window.ui = SwaggerUIBundle({ + "dom_id": "#swagger-ui", + "url": "/api/openapi.json", + "deepLinking": true, + "layout": "StandaloneLayout", + presets: [ + SwaggerUIBundle.presets.apis, + SwaggerUIStandalonePreset + ], + plugins: [ + SwaggerUIBundle.plugins.DownloadUrl + ], + + }); + + // +}; diff --git a/nix/host-modules/hive-c0re/options.nix b/nix/host-modules/hive-c0re/options.nix index b67c0b6b..c5d7088b 100644 --- a/nix/host-modules/hive-c0re/options.nix +++ b/nix/host-modules/hive-c0re/options.nix @@ -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 { diff --git a/nix/host-modules/hive-gateway/default.nix b/nix/host-modules/hive-gateway/default.nix index a2c53f95..28453f06 100644 --- a/nix/host-modules/hive-gateway/default.nix +++ b/nix/host-modules/hive-gateway/default.nix @@ -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 diff --git a/nix/host-modules/hive-gateway/vhosts.nix b/nix/host-modules/hive-gateway/vhosts.nix index 645d58f9..f94395b5 100644 --- a/nix/host-modules/hive-gateway/vhosts.nix +++ b/nix/host-modules/hive-gateway/vhosts.nix @@ -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 diff --git a/nix/packages/default.nix b/nix/packages/default.nix index ce53804f..70c5baa7 100644 --- a/nix/packages/default.nix +++ b/nix/packages/default.nix @@ -18,6 +18,13 @@ let inherit (nixpkgs.lib) nixosSystem; }; + # Plain vendored Swagger UI dist (./swagger-ui-dist.nix) + the + # hyperhive-themed overlay on top (./swagger-ui-theme.nix) — bound + # here (not just inline in the attrset below) so the theme + # derivation can take the dist derivation as an explicit input. + swagger-ui-dist = pkgs.callPackage ./swagger-ui-dist.nix { }; + swagger-ui-theme = pkgs.callPackage ./swagger-ui-theme.nix { inherit swagger-ui-dist; }; + # Every per-binary package: name → description. The single source of # truth for the bin list — it drives the per-bin extractor packages # and the `default` bundle, so adding a binary is one entry here. @@ -158,11 +165,13 @@ in xdg-icons = pkgs.callPackage ./hive-xdg-icons.nix { hyperhiveSvg = ../../branding/hyperhive.svg; }; - # Swagger UI re-theme static override files — see - # ./swagger-ui-theme.nix. The gateway `alias`es these straight from - # the store; a theme tweak is a gateway config change, not a - # hive-c0re rebuild. - swagger-ui-theme = pkgs.callPackage ./swagger-ui-theme.nix { }; + # Swagger UI: plain vendored dist + the hyperhive-themed overlay — + # see ./swagger-ui-dist.nix / ./swagger-ui-theme.nix (both computed + # above, in `let`). The gateway serves `swagger-ui-theme`'s full + # tree straight from the store at /api/docs/; a theme tweak is a + # gateway config change, not a hive-c0re rebuild. `swagger-ui-dist` + # is exposed too since it's independently useful/inspectable. + inherit swagger-ui-dist swagger-ui-theme; # Pre-built per-container system closures. Exposed as packages # so operators can `nix build .#agent-base-toplevel` (or wire diff --git a/nix/packages/swagger-ui-dist.nix b/nix/packages/swagger-ui-dist.nix new file mode 100644 index 00000000..cc70e995 --- /dev/null +++ b/nix/packages/swagger-ui-dist.nix @@ -0,0 +1,47 @@ +{ + stdenv, + fetchurl, +}: + +# Pure vendored Swagger UI 5.17.14 static dist — no hyperhive theming +# (see ./swagger-ui-theme.nix for that layer). Deliberately NOT sourced +# via the Rust `utoipa-swagger-ui-vendored` crate / Cargo.lock (per the +# operator's ask: a nix package that just contains the plain static +# dist, not fetched via cargo) — hive-c0re no longer needs to know this +# exists at all once the gateway hosts it directly. +# +# Sourced straight from the `swagger-ui-dist` npm package, which ships +# exactly the built `dist/` files (no source, no build step needed) at +# the same release as the Rust ecosystem's vendored copy — verified by +# comparing this tarball's recorded `gitHead` (in its `package.json`, +# `74ed0adebfc9c8dd0de2bf8e81495b022a66c083`) against the commit the +# `utoipa-swagger-ui-vendored` crate's own pinned zip was built from +# (same hash, printed by `unzip -l` on that zip's first entry). +stdenv.mkDerivation { + pname = "swagger-ui-dist"; + version = "5.17.14"; + + src = fetchurl { + url = "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.17.14.tgz"; + hash = "sha512-CVbSfaLpstV65OnSjbXfVd6Sta3q3F7Cj/yYuvHMp1P90LztOLs6PfUnKEVAeiIVQt9u2SaPwv0LiH/OyMjHRw=="; + }; + + sourceRoot = "package"; + dontBuild = true; + + installPhase = '' + runHook preInstall + mkdir -p $out + # The npm package also carries a few node-consumption conveniences + # (package.json, index.js, absolute-path.js, README/LICENSE/NOTICE) + # alongside the actual browser dist — only copy what a web server + # should ever expose. + cp *.html *.css *.css.map *.js *.js.map *.png $out/ + runHook postInstall + ''; + + meta = { + description = "Vendored Swagger UI 5.17.14 static dist (unthemed), from the swagger-ui-dist npm package"; + homepage = "https://forge.darkest.space/hyperhive/hyperhive"; + }; +} diff --git a/nix/packages/swagger-ui-theme.nix b/nix/packages/swagger-ui-theme.nix index 7e21faa6..a84cb6e0 100644 --- a/nix/packages/swagger-ui-theme.nix +++ b/nix/packages/swagger-ui-theme.nix @@ -1,49 +1,58 @@ { stdenv, + swagger-ui-dist, }: -# The hand-authored Swagger UI re-theme files (`hive-c0re/swagger-ui- -# theme/`), shipped as a standalone derivation so the gateway can -# `alias` them straight from the nix store instead of hive-c0re's own -# build serving them — see nix/host-modules/hive-gateway/vhosts.nix's -# `swaggerThemeLocations`. This is what lets a CSS tweak ship as a -# gateway config change (activate the gateway container) rather than a -# hive-c0re rebuild+restart: the two files nginx exact-matches -# (`/api/docs/` and `/api/docs/hyperhive-theme.css`) come from here; -# every other Swagger UI asset (bundle.js, openapi.json, favicons, …) -# still falls through the existing `/api/` prefix proxy to hive-c0re's -# own vendored (unthemed) `utoipa-swagger-ui` embed, unchanged. +# hyperhive's Catppuccin Mocha re-theme of Swagger UI: overlays our 3 +# hand-authored override files (`hive-c0re/swagger-ui-theme/`) onto +# the plain vendored dist (./swagger-ui-dist.nix). This is the FULL +# tree hive-gateway's nginx serves at `/api/docs/` — hive-c0re hosts +# none of it, only the dynamic `/api/openapi.json` (see +# nix/host-modules/hive-gateway/vhosts.nix). # -# Pure data: copied verbatim, no build step. -# -# Output layout: -# $out/index.html — themed index.html Swagger UI page -# $out/hyperhive-theme.css — the re-theme, consumes --baseNN vars -# from the dashboard's own colors.css -# (loaded via an absolute /static/ -# colors.css , same origin) - +# Output layout: every file from `swagger-ui-dist`, with 3 replaced: +# index.html — adds s for colors.css (live stylix +# theme, same origin) + hyperhive-theme.css +# hyperhive-theme.css — new; the re-theme itself, consumes +# --baseNN vars from colors.css +# swagger-initializer.js — hardcodes `url: "/api/openapi.json"`. The +# plain vendored copy points at the +# swagger.io petstore demo; normally +# `utoipa-swagger-ui`'s `serve()` rewrites +# this file per-request from a `{{config}}` +# placeholder it injects at its OWN build +# time (see that crate's `build.rs`'s +# `replace_default_url_with_config` + +# `format_config`). hive-c0re no longer +# serves this file at all, so that rewrite +# has to happen here instead — this copy is +# hand-verified to byte-match what +# `format_config` would produce for +# hive-c0re's actual config (single unnamed +# url, otherwise all `Config` defaults): the +# same transform applied to the real +# vendored file, not hand-typed from +# scratch. stdenv.mkDerivation { pname = "hyperhive-swagger-ui-theme"; version = "0.1.0"; - # Narrow src keeps this derivation's input hash decoupled from the - # rest of the tree — a theme tweak only re-hashes this. - src = ../../hive-c0re/swagger-ui-theme; + dontUnpack = true; dontBuild = true; - dontConfigure = true; installPhase = '' runHook preInstall mkdir -p $out - cp -r ./* $out/ + cp -r ${swagger-ui-dist}/. $out/ + chmod -R u+w $out + install -m644 ${../../hive-c0re/swagger-ui-theme/index.html} $out/index.html + install -m644 ${../../hive-c0re/swagger-ui-theme/hyperhive-theme.css} $out/hyperhive-theme.css + install -m644 ${../../hive-c0re/swagger-ui-theme/swagger-initializer.js} $out/swagger-initializer.js runHook postInstall ''; - dontFixup = true; - meta = { - description = "hyperhive Swagger UI Catppuccin Mocha re-theme (static override files)"; + description = "hyperhive Swagger UI Catppuccin Mocha re-theme — full static dist, nginx-served at /api/docs/"; homepage = "https://forge.darkest.space/hyperhive/hyperhive"; }; } From 3ef166738cb648c995066e2c9e6fae350b947200 Mon Sep 17 00:00:00 2001 From: iris Date: Sun, 2 Aug 2026 20:49:59 +0200 Subject: [PATCH 6/8] move swagger-ui-theme/ out of hive-c0re/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hive-c0re doesn't touch these files anymore (nginx hosts them directly, see the previous commit) — hive-c0re/swagger-ui-theme/ was a leftover from the original SWAGGER_UI_OVERWRITE_FOLDER build-hook design, which this PR moved away from. New location matches the existing top-level-directory-for-nix-packaged-assets convention (branding/, claude-plugins/). Pure rename, no content change: nix/packages/swagger-ui-theme.nix's three file references updated, everything else picks it up from the same content hash (nix build .#swagger-ui-theme resolves to the exact same store path as before the move). --- nix/packages/swagger-ui-theme.nix | 46 ++++++++----------- .../hyperhive-theme.css | 0 .../index.html | 0 .../swagger-initializer.js | 0 4 files changed, 20 insertions(+), 26 deletions(-) rename {hive-c0re/swagger-ui-theme => swagger-ui-theme}/hyperhive-theme.css (100%) rename {hive-c0re/swagger-ui-theme => swagger-ui-theme}/index.html (100%) rename {hive-c0re/swagger-ui-theme => swagger-ui-theme}/swagger-initializer.js (100%) diff --git a/nix/packages/swagger-ui-theme.nix b/nix/packages/swagger-ui-theme.nix index a84cb6e0..f93c5e40 100644 --- a/nix/packages/swagger-ui-theme.nix +++ b/nix/packages/swagger-ui-theme.nix @@ -4,35 +4,29 @@ }: # hyperhive's Catppuccin Mocha re-theme of Swagger UI: overlays our 3 -# hand-authored override files (`hive-c0re/swagger-ui-theme/`) onto +# hand-authored override files (`swagger-ui-theme/`, top-level — not +# under `hive-c0re/`, which has no relationship to these files) onto # the plain vendored dist (./swagger-ui-dist.nix). This is the FULL # tree hive-gateway's nginx serves at `/api/docs/` — hive-c0re hosts # none of it, only the dynamic `/api/openapi.json` (see # nix/host-modules/hive-gateway/vhosts.nix). # # Output layout: every file from `swagger-ui-dist`, with 3 replaced: -# index.html — adds s for colors.css (live stylix -# theme, same origin) + hyperhive-theme.css -# hyperhive-theme.css — new; the re-theme itself, consumes -# --baseNN vars from colors.css -# swagger-initializer.js — hardcodes `url: "/api/openapi.json"`. The -# plain vendored copy points at the -# swagger.io petstore demo; normally -# `utoipa-swagger-ui`'s `serve()` rewrites -# this file per-request from a `{{config}}` -# placeholder it injects at its OWN build -# time (see that crate's `build.rs`'s -# `replace_default_url_with_config` + -# `format_config`). hive-c0re no longer -# serves this file at all, so that rewrite -# has to happen here instead — this copy is -# hand-verified to byte-match what -# `format_config` would produce for -# hive-c0re's actual config (single unnamed -# url, otherwise all `Config` defaults): the -# same transform applied to the real -# vendored file, not hand-typed from -# scratch. +# index.html adds colors.css (live stylix theme) + +# hyperhive-theme.css s +# hyperhive-theme.css new; the re-theme, consumes --baseNN vars +# swagger-initializer.js hardcodes `url: "/api/openapi.json"` — +# `utoipa-swagger-ui`'s `serve()` normally +# rewrites this per-request from a +# `{{config}}` placeholder its OWN build.rs +# injects (`replace_default_url_with_config` +# + `format_config`); hive-c0re doesn't serve +# this file at all anymore, so that rewrite +# is baked in statically here instead — +# hand-verified byte-for-byte against what +# `format_config` would produce, by applying +# the same transform to the real vendored +# file rather than typing it from scratch. stdenv.mkDerivation { pname = "hyperhive-swagger-ui-theme"; version = "0.1.0"; @@ -45,9 +39,9 @@ stdenv.mkDerivation { mkdir -p $out cp -r ${swagger-ui-dist}/. $out/ chmod -R u+w $out - install -m644 ${../../hive-c0re/swagger-ui-theme/index.html} $out/index.html - install -m644 ${../../hive-c0re/swagger-ui-theme/hyperhive-theme.css} $out/hyperhive-theme.css - install -m644 ${../../hive-c0re/swagger-ui-theme/swagger-initializer.js} $out/swagger-initializer.js + install -m644 ${../../swagger-ui-theme/index.html} $out/index.html + install -m644 ${../../swagger-ui-theme/hyperhive-theme.css} $out/hyperhive-theme.css + install -m644 ${../../swagger-ui-theme/swagger-initializer.js} $out/swagger-initializer.js runHook postInstall ''; diff --git a/hive-c0re/swagger-ui-theme/hyperhive-theme.css b/swagger-ui-theme/hyperhive-theme.css similarity index 100% rename from hive-c0re/swagger-ui-theme/hyperhive-theme.css rename to swagger-ui-theme/hyperhive-theme.css diff --git a/hive-c0re/swagger-ui-theme/index.html b/swagger-ui-theme/index.html similarity index 100% rename from hive-c0re/swagger-ui-theme/index.html rename to swagger-ui-theme/index.html diff --git a/hive-c0re/swagger-ui-theme/swagger-initializer.js b/swagger-ui-theme/swagger-initializer.js similarity index 100% rename from hive-c0re/swagger-ui-theme/swagger-initializer.js rename to swagger-ui-theme/swagger-initializer.js From 9efe6f64b687e13f0e204d4a296e2030515a638c Mon Sep 17 00:00:00 2001 From: iris Date: Sun, 2 Aug 2026 20:54:03 +0200 Subject: [PATCH 7/8] move swaggerUiTheme nix option out of c0re's namespace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit services.hyperhive.c0re.swaggerUiTheme -> services.hyperhive.gateway.swaggerUiTheme. hive-c0re has no relationship to this option (it's consumed entirely by the gateway's nginx config) since the previous two commits moved the theme files out of hive-c0re/ and gateway to hosting the whole dist itself — the option shouldn't live in c0re's namespace either. Pure option move: default wiring in flake.nix now sets services.hyperhive.gateway.swaggerUiTheme instead of the c0re one; hive-gateway/default.nix reads it via the module's own already-bound cfg (services.hyperhive.gateway) instead of reaching into c0re's. Verified: nix build .#swagger-ui-theme unaffected (same store path, pure option-plumbing change, no content change); a full nixosSystem eval of nixosModules.default resolves the option at its new path and confirms the gateway's /api/docs/ location still aliases the correct store path. --- flake.nix | 4 +++- nix/host-modules/hive-c0re/options.nix | 13 ------------- nix/host-modules/hive-gateway/default.nix | 5 +++-- nix/host-modules/hive-gateway/options.nix | 15 +++++++++++++++ 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/flake.nix b/flake.nix index ae0af5ee..87d4f7e4 100644 --- a/flake.nix +++ b/flake.nix @@ -128,7 +128,6 @@ frontend = lib.mkDefault self.packages.${pkgs.stdenv.hostPlatform.system}.frontend; assets = lib.mkDefault self.packages.${pkgs.stdenv.hostPlatform.system}.assets; xdgIcons = lib.mkDefault self.packages.${pkgs.stdenv.hostPlatform.system}.xdg-icons; - swaggerUiTheme = lib.mkDefault self.packages.${pkgs.stdenv.hostPlatform.system}.swagger-ui-theme; hyperhiveFlake = lib.mkDefault "${sources.hyperhiveFlakeSource}"; # Narrow docs/ source, threaded as its own meta-flake input # so doc edits don't re-hash the whole flake source. @@ -143,6 +142,9 @@ agentBaseToplevel = lib.mkDefault self.packages.x86_64-linux.agent-base-toplevel; managerToplevel = lib.mkDefault self.packages.x86_64-linux.ruth-toplevel; }; + services.hyperhive.gateway.swaggerUiTheme = + lib.mkDefault + self.packages.${pkgs.stdenv.hostPlatform.system}.swagger-ui-theme; }; hive-ci = ./nix/host-modules/hive-ci.nix; hive-forge = ./nix/host-modules/hive-forge; diff --git a/nix/host-modules/hive-c0re/options.nix b/nix/host-modules/hive-c0re/options.nix index c5d7088b..bd10cecd 100644 --- a/nix/host-modules/hive-c0re/options.nix +++ b/nix/host-modules/hive-c0re/options.nix @@ -65,19 +65,6 @@ processes to their icon. ''; }; - swaggerUiTheme = lib.mkOption { - type = lib.types.package; - defaultText = lib.literalExpression "hyperhive.packages.\${system}.swagger-ui-theme"; - description = '' - 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 { type = lib.types.str; defaultText = lib.literalMD "the hyperhive flake's own filtered source store path"; diff --git a/nix/host-modules/hive-gateway/default.nix b/nix/host-modules/hive-gateway/default.nix index 28453f06..a9df82c5 100644 --- a/nix/host-modules/hive-gateway/default.nix +++ b/nix/host-modules/hive-gateway/default.nix @@ -27,8 +27,9 @@ let # 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; + # nix/packages/swagger-ui-{dist,theme}.nix). Own option under this + # module (not c0re's) — hive-c0re has no relationship to it. + swaggerUiTheme = cfg.swaggerUiTheme; # Self-signed TLS is the implicit floor: when neither an operator cert # (`tls.certDir`) nor ACME (`tls.acme.enable`) is configured, the gateway diff --git a/nix/host-modules/hive-gateway/options.nix b/nix/host-modules/hive-gateway/options.nix index 211a8c3a..9f3ed563 100644 --- a/nix/host-modules/hive-gateway/options.nix +++ b/nix/host-modules/hive-gateway/options.nix @@ -254,6 +254,21 @@ in }; }; + swaggerUiTheme = lib.mkOption { + type = lib.types.package; + defaultText = lib.literalExpression "hyperhive.packages.\${system}.swagger-ui-theme"; + description = '' + Full Swagger UI static dist, hyperhive-themed (see + `nix/packages/swagger-ui-theme.nix`, built on + `nix/packages/swagger-ui-dist.nix`). The gateway serves this + whole tree directly at `/api/docs/` — hive-c0re hosts none of + it, only the dynamic `/api/openapi.json` route (proxied + through, unaffected by this option). Override to ship a + custom theme (or the plain vendored dist) without a gateway + rebuild. + ''; + }; + hsts = { enable = lib.mkOption { type = lib.types.bool; From f457d9ce7be5deb3fb935c25e98d3267aa4333a7 Mon Sep 17 00:00:00 2001 From: damocles Date: Sun, 2 Aug 2026 21:09:28 +0200 Subject: [PATCH 8/8] hive-c0re: drop utoipa-swagger-ui, serve openapi.json directly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Swagger UI itself is nginx-hosted now (iris's 86a39c4c), so c0re carrying its own vendored copy via utoipa-swagger-ui was a straight duplicate — dropped the dependency (root Cargo.toml + hive-c0re's), swapped the SwaggerUi::new(...).url(...) mount for a plain /api/openapi.json GET route serving the same OpenApi doc as JSON. Verified: cargo build/clippy/test -p hive-c0re clean, Cargo.lock dropped utoipa-swagger-ui + utoipa-swagger-ui-vendored with no other changes, nix fmt clean. --- Cargo.lock | 114 --------------------------------- Cargo.toml | 5 -- hive-c0re/Cargo.toml | 1 - hive-c0re/src/dashboard/mod.rs | 20 ++++-- 4 files changed, 16 insertions(+), 124 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8ac44a4c..399f5765 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -135,15 +135,6 @@ dependencies = [ "syn 2.0.119", ] -[[package]] -name = "arbitrary" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" -dependencies = [ - "derive_arbitrary", -] - [[package]] name = "archery" version = "1.2.2" @@ -990,17 +981,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "derive_arbitrary" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "derive_more" version = "1.0.0" @@ -1276,7 +1256,6 @@ checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "miniz_oxide", - "zlib-rs", ] [[package]] @@ -1681,7 +1660,6 @@ dependencies = [ "url", "utoipa", "utoipa-axum", - "utoipa-swagger-ui", ] [[package]] @@ -3924,41 +3902,6 @@ dependencies = [ "smallvec", ] -[[package]] -name = "rust-embed" -version = "8.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9e7760e252aaba7b09f4be00e36476cf585bdb68a53552ac954cdf504ab4bc9" -dependencies = [ - "rust-embed-impl", - "rust-embed-utils", - "walkdir", -] - -[[package]] -name = "rust-embed-impl" -version = "8.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcfc4d6f53af43755f7a723e4b6b8794fcce052a178dd8c6c1dadc5f5343097" -dependencies = [ - "mime_guess", - "proc-macro2", - "quote", - "rust-embed-utils", - "syn 2.0.119", - "walkdir", -] - -[[package]] -name = "rust-embed-utils" -version = "8.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ffa149f6aa81b58a5b3011d01a857c4ed12c7a732d2c51947a4c7c692185f0" -dependencies = [ - "sha2 0.11.0", - "walkdir", -] - [[package]] name = "rustc-hash" version = "2.1.3" @@ -5078,31 +5021,6 @@ dependencies = [ "syn 2.0.119", ] -[[package]] -name = "utoipa-swagger-ui" -version = "9.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d047458f1b5b65237c2f6dc6db136945667f40a7668627b3490b9513a3d43a55" -dependencies = [ - "axum", - "base64", - "mime_guess", - "regex", - "rust-embed", - "serde", - "serde_json", - "url", - "utoipa", - "utoipa-swagger-ui-vendored", - "zip", -] - -[[package]] -name = "utoipa-swagger-ui-vendored" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2eebbbfe4093922c2b6734d7c679ebfebd704a0d7e56dfcb0d05818ce28977d" - [[package]] name = "uuid" version = "1.24.0" @@ -5745,40 +5663,8 @@ dependencies = [ "syn 2.0.119", ] -[[package]] -name = "zip" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12598812502ed0105f607f941c386f43d441e00148fce9dec3ca5ffb0bde9308" -dependencies = [ - "arbitrary", - "crc32fast", - "flate2", - "indexmap", - "memchr", - "zopfli", -] - -[[package]] -name = "zlib-rs" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b142a20ec14a91d5bc708c1dc21b080c550113d8aa77afa29635673a65dd02c5" - [[package]] name = "zmij" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" - -[[package]] -name = "zopfli" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" -dependencies = [ - "bumpalo", - "crc32fast", - "log", - "simd-adler32", -] diff --git a/Cargo.toml b/Cargo.toml index eb79b132..56a33612 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -116,8 +116,3 @@ hmac = "0.13" sha2 = "0.11" utoipa = { version = "5", features = ["axum_extras"] } utoipa-axum = "0.2" -# "vendored" bundles a pinned Swagger UI dist via utoipa-swagger-ui-vendored -# instead of the crate's default curl-download build script — required in -# the nix sandbox, which has no network at build time outside the -# Cargo.lock-pinned dependency fetch. -utoipa-swagger-ui = { version = "9", features = ["axum", "vendored"] } diff --git a/hive-c0re/Cargo.toml b/hive-c0re/Cargo.toml index 98a6e459..a4dae331 100644 --- a/hive-c0re/Cargo.toml +++ b/hive-c0re/Cargo.toml @@ -53,7 +53,6 @@ tracing-subscriber.workspace = true problem_details = { version = "0.9.0", features = ["axum"] } utoipa.workspace = true utoipa-axum.workspace = true -utoipa-swagger-ui.workspace = true [dev-dependencies] tempfile = "3" diff --git a/hive-c0re/src/dashboard/mod.rs b/hive-c0re/src/dashboard/mod.rs index 9e2a12e6..463ce242 100644 --- a/hive-c0re/src/dashboard/mod.rs +++ b/hive-c0re/src/dashboard/mod.rs @@ -7,18 +7,23 @@ use std::sync::Arc; use anyhow::{Context, Result}; use axum::{ + Json, http::StatusCode, response::{IntoResponse, Response}, + routing::get, }; use utoipa::OpenApi; use utoipa_axum::{router::OpenApiRouter, routes}; -use utoipa_swagger_ui::SwaggerUi; use crate::coordinator::Coordinator; use crate::lifecycle; -/// Root of the auto-generated `OpenAPI` spec (`/api/openapi.json`, browsable -/// at `/api/docs`) — see [`utoipa`]. Only routes carrying a +/// Root of the auto-generated `OpenAPI` spec, served raw at +/// `/api/openapi.json` — see [`utoipa`]. Swagger UI itself (browsable at +/// `/api/docs`) is nginx-hosted straight from the nix store now (see +/// `nix/host-modules/hive-gateway/vhosts.nix`'s `swaggerUiLocations`); +/// c0re only needs to serve the JSON this route generates, not the whole +/// vendored UI. Only routes carrying a /// `#[utoipa::path(...)]` annotation show up; the rest of the (much /// larger) route table below is undocumented for now. Deliberately /// incremental: an unannotated route just doesn't appear in the spec, @@ -206,8 +211,15 @@ pub async fn serve( .routes(routes!(state_snapshot::dashboard_stream)) .routes(routes!(state_snapshot::dashboard_history)) .split_for_parts(); + // Just the JSON, not the UI — Swagger UI itself is nginx-hosted from + // the nix store (see the module doc comment above `ApiDoc`). `api` + // is `Clone`; each request gets its own owned copy for `Json` to + // serialize. let app = router - .merge(SwaggerUi::new("/api/docs").url("/api/openapi.json", api)) + .route( + "/api/openapi.json", + get(move || async move { Json(api.clone()) }), + ) .with_state(AppState { coord, webhook_secret,