Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f457d9ce7b | ||
|
|
9efe6f64b6 | ||
|
|
3ef166738c | ||
|
|
1bc9c18504 | ||
|
|
de1659d10e | ||
|
|
5471b49f2a | ||
|
|
062a84378d | ||
|
|
de15410394 |
14 changed files with 403 additions and 124 deletions
114
Cargo.lock
generated
114
Cargo.lock
generated
|
|
@ -135,15 +135,6 @@ dependencies = [
|
||||||
"syn 2.0.119",
|
"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]]
|
[[package]]
|
||||||
name = "archery"
|
name = "archery"
|
||||||
version = "1.2.2"
|
version = "1.2.2"
|
||||||
|
|
@ -990,17 +981,6 @@ dependencies = [
|
||||||
"syn 1.0.109",
|
"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]]
|
[[package]]
|
||||||
name = "derive_more"
|
name = "derive_more"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
|
@ -1276,7 +1256,6 @@ checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crc32fast",
|
"crc32fast",
|
||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
"zlib-rs",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1681,7 +1660,6 @@ dependencies = [
|
||||||
"url",
|
"url",
|
||||||
"utoipa",
|
"utoipa",
|
||||||
"utoipa-axum",
|
"utoipa-axum",
|
||||||
"utoipa-swagger-ui",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -3924,41 +3902,6 @@ dependencies = [
|
||||||
"smallvec",
|
"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]]
|
[[package]]
|
||||||
name = "rustc-hash"
|
name = "rustc-hash"
|
||||||
version = "2.1.3"
|
version = "2.1.3"
|
||||||
|
|
@ -5078,31 +5021,6 @@ dependencies = [
|
||||||
"syn 2.0.119",
|
"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]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.24.0"
|
version = "1.24.0"
|
||||||
|
|
@ -5745,40 +5663,8 @@ dependencies = [
|
||||||
"syn 2.0.119",
|
"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]]
|
[[package]]
|
||||||
name = "zmij"
|
name = "zmij"
|
||||||
version = "1.0.23"
|
version = "1.0.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
|
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",
|
|
||||||
]
|
|
||||||
|
|
|
||||||
|
|
@ -116,8 +116,3 @@ hmac = "0.13"
|
||||||
sha2 = "0.11"
|
sha2 = "0.11"
|
||||||
utoipa = { version = "5", features = ["axum_extras"] }
|
utoipa = { version = "5", features = ["axum_extras"] }
|
||||||
utoipa-axum = "0.2"
|
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"] }
|
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,9 @@
|
||||||
agentBaseToplevel = lib.mkDefault self.packages.x86_64-linux.agent-base-toplevel;
|
agentBaseToplevel = lib.mkDefault self.packages.x86_64-linux.agent-base-toplevel;
|
||||||
managerToplevel = lib.mkDefault self.packages.x86_64-linux.ruth-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-ci = ./nix/host-modules/hive-ci.nix;
|
||||||
hive-forge = ./nix/host-modules/hive-forge;
|
hive-forge = ./nix/host-modules/hive-forge;
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,6 @@ tracing-subscriber.workspace = true
|
||||||
problem_details = { version = "0.9.0", features = ["axum"] }
|
problem_details = { version = "0.9.0", features = ["axum"] }
|
||||||
utoipa.workspace = true
|
utoipa.workspace = true
|
||||||
utoipa-axum.workspace = true
|
utoipa-axum.workspace = true
|
||||||
utoipa-swagger-ui.workspace = true
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3"
|
tempfile = "3"
|
||||||
|
|
|
||||||
|
|
@ -7,18 +7,23 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use axum::{
|
use axum::{
|
||||||
|
Json,
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
response::{IntoResponse, Response},
|
response::{IntoResponse, Response},
|
||||||
|
routing::get,
|
||||||
};
|
};
|
||||||
use utoipa::OpenApi;
|
use utoipa::OpenApi;
|
||||||
use utoipa_axum::{router::OpenApiRouter, routes};
|
use utoipa_axum::{router::OpenApiRouter, routes};
|
||||||
use utoipa_swagger_ui::SwaggerUi;
|
|
||||||
|
|
||||||
use crate::coordinator::Coordinator;
|
use crate::coordinator::Coordinator;
|
||||||
use crate::lifecycle;
|
use crate::lifecycle;
|
||||||
|
|
||||||
/// Root of the auto-generated `OpenAPI` spec (`/api/openapi.json`, browsable
|
/// Root of the auto-generated `OpenAPI` spec, served raw at
|
||||||
/// at `/api/docs`) — see [`utoipa`]. Only routes carrying a
|
/// `/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
|
/// `#[utoipa::path(...)]` annotation show up; the rest of the (much
|
||||||
/// larger) route table below is undocumented for now. Deliberately
|
/// larger) route table below is undocumented for now. Deliberately
|
||||||
/// incremental: an unannotated route just doesn't appear in the spec,
|
/// 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_stream))
|
||||||
.routes(routes!(state_snapshot::dashboard_history))
|
.routes(routes!(state_snapshot::dashboard_history))
|
||||||
.split_for_parts();
|
.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
|
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 {
|
.with_state(AppState {
|
||||||
coord,
|
coord,
|
||||||
webhook_secret,
|
webhook_secret,
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,13 @@ let
|
||||||
# container's).
|
# container's).
|
||||||
dashboardDist = "${config.services.hyperhive.c0re.servedFrontend}/dashboard";
|
dashboardDist = "${config.services.hyperhive.c0re.servedFrontend}/dashboard";
|
||||||
|
|
||||||
|
# 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). 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
|
# Self-signed TLS is the implicit floor: when neither an operator cert
|
||||||
# (`tls.certDir`) nor ACME (`tls.acme.enable`) is configured, the gateway
|
# (`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
|
# generates + serves a hive-CA-signed leaf (see hive-tls.nix). There is no
|
||||||
|
|
@ -261,6 +268,7 @@ in
|
||||||
matrixCfg
|
matrixCfg
|
||||||
hyperhiveDomain
|
hyperhiveDomain
|
||||||
dashboardDist
|
dashboardDist
|
||||||
|
swaggerUiTheme
|
||||||
tlsCert
|
tlsCert
|
||||||
tlsKey
|
tlsKey
|
||||||
;
|
;
|
||||||
|
|
|
||||||
|
|
@ -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 = {
|
hsts = {
|
||||||
enable = lib.mkOption {
|
enable = lib.mkOption {
|
||||||
type = lib.types.bool;
|
type = lib.types.bool;
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
matrixCfg,
|
matrixCfg,
|
||||||
hyperhiveDomain,
|
hyperhiveDomain,
|
||||||
dashboardDist,
|
dashboardDist,
|
||||||
|
swaggerUiTheme, # nix/packages/swagger-ui-theme.nix: has index.html + hyperhive-theme.css
|
||||||
errorPages, # ./error-pages.nix: { notFound, unreachable, unauthorized }
|
errorPages, # ./error-pages.nix: { notFound, unreachable, unauthorized }
|
||||||
tlsCert,
|
tlsCert,
|
||||||
tlsKey,
|
tlsKey,
|
||||||
|
|
@ -304,6 +305,40 @@ let
|
||||||
proxyPass = "http://${cfg.upstreamHost}:${toString cfg.upstreamPort}";
|
proxyPass = "http://${cfg.upstreamHost}:${toString cfg.upstreamPort}";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# 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 = ''
|
||||||
|
return 301 /api/docs/;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
"/api/docs/" = {
|
||||||
|
alias = "${swaggerUiTheme}/";
|
||||||
|
extraConfig = ''
|
||||||
|
index index.html;
|
||||||
|
${dashboardAuth}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
# Accept-header SPA map for the matrix GUI only (see docs/gateway.md
|
# Accept-header SPA map for the matrix GUI only (see docs/gateway.md
|
||||||
|
|
@ -325,6 +360,7 @@ in
|
||||||
// wellKnownLocations
|
// wellKnownLocations
|
||||||
// agentLocations
|
// agentLocations
|
||||||
// dashboardProxyLocation
|
// dashboardProxyLocation
|
||||||
|
// swaggerUiLocations
|
||||||
// lib.optionalAttrs cfg.auth.enable {
|
// lib.optionalAttrs cfg.auth.enable {
|
||||||
# Internal-only target for the 401 error_page above.
|
# Internal-only target for the 401 error_page above.
|
||||||
# `internal` prevents direct client access; `alias` serves
|
# `internal` prevents direct client access; `alias` serves
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,13 @@ let
|
||||||
inherit (nixpkgs.lib) nixosSystem;
|
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
|
# Every per-binary package: name → description. The single source of
|
||||||
# truth for the bin list — it drives the per-bin extractor packages
|
# truth for the bin list — it drives the per-bin extractor packages
|
||||||
# and the `default` bundle, so adding a binary is one entry here.
|
# and the `default` bundle, so adding a binary is one entry here.
|
||||||
|
|
@ -158,6 +165,13 @@ in
|
||||||
xdg-icons = pkgs.callPackage ./hive-xdg-icons.nix {
|
xdg-icons = pkgs.callPackage ./hive-xdg-icons.nix {
|
||||||
hyperhiveSvg = ../../branding/hyperhive.svg;
|
hyperhiveSvg = ../../branding/hyperhive.svg;
|
||||||
};
|
};
|
||||||
|
# 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
|
# Pre-built per-container system closures. Exposed as packages
|
||||||
# so operators can `nix build .#agent-base-toplevel` (or wire
|
# so operators can `nix build .#agent-base-toplevel` (or wire
|
||||||
|
|
|
||||||
47
nix/packages/swagger-ui-dist.nix
Normal file
47
nix/packages/swagger-ui-dist.nix
Normal file
|
|
@ -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";
|
||||||
|
};
|
||||||
|
}
|
||||||
52
nix/packages/swagger-ui-theme.nix
Normal file
52
nix/packages/swagger-ui-theme.nix
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
{
|
||||||
|
stdenv,
|
||||||
|
swagger-ui-dist,
|
||||||
|
}:
|
||||||
|
|
||||||
|
# hyperhive's Catppuccin Mocha re-theme of Swagger UI: overlays our 3
|
||||||
|
# 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 colors.css (live stylix theme) +
|
||||||
|
# hyperhive-theme.css <link>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";
|
||||||
|
|
||||||
|
dontUnpack = true;
|
||||||
|
dontBuild = true;
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
runHook preInstall
|
||||||
|
mkdir -p $out
|
||||||
|
cp -r ${swagger-ui-dist}/. $out/
|
||||||
|
chmod -R u+w $out
|
||||||
|
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
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
description = "hyperhive Swagger UI Catppuccin Mocha re-theme — full static dist, nginx-served at /api/docs/";
|
||||||
|
homepage = "https://forge.darkest.space/hyperhive/hyperhive";
|
||||||
|
};
|
||||||
|
}
|
||||||
161
swagger-ui-theme/hyperhive-theme.css
Normal file
161
swagger-ui-theme/hyperhive-theme.css
Normal file
|
|
@ -0,0 +1,161 @@
|
||||||
|
/* 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 without `!important`, except where noted below.
|
||||||
|
|
||||||
|
`--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 */
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
background: var(--base00);
|
||||||
|
}
|
||||||
|
.swagger-ui {
|
||||||
|
color: var(--base05);
|
||||||
|
font-family: "JetBrains Mono", "Fira Code", "Cascadia Code",
|
||||||
|
"Source Code Pro", monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Topbar */
|
||||||
|
.swagger-ui .topbar {
|
||||||
|
background: var(--base01);
|
||||||
|
border-bottom: 1px solid var(--base02);
|
||||||
|
}
|
||||||
|
.swagger-ui .topbar .download-url-wrapper input[type="text"] {
|
||||||
|
border-color: var(--base02);
|
||||||
|
background: var(--base00);
|
||||||
|
color: var(--base05);
|
||||||
|
}
|
||||||
|
.swagger-ui .topbar .download-url-wrapper .download-url-button {
|
||||||
|
background: var(--base0E);
|
||||||
|
color: var(--base01);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Info block + links */
|
||||||
|
.swagger-ui .info .title,
|
||||||
|
.swagger-ui .info li,
|
||||||
|
.swagger-ui .info p,
|
||||||
|
.swagger-ui .info table {
|
||||||
|
color: var(--base05);
|
||||||
|
}
|
||||||
|
.swagger-ui a.nostyle,
|
||||||
|
.swagger-ui a.nostyle:visited,
|
||||||
|
.swagger-ui .info a {
|
||||||
|
color: var(--base0D);
|
||||||
|
}
|
||||||
|
.swagger-ui .opblock-tag {
|
||||||
|
color: var(--base05);
|
||||||
|
border-bottom-color: var(--base02);
|
||||||
|
}
|
||||||
|
.swagger-ui .opblock-tag:hover {
|
||||||
|
background: color-mix(in srgb, var(--base0E) 8%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scheme/server selector bar. */
|
||||||
|
.swagger-ui .scheme-container {
|
||||||
|
background: var(--base01);
|
||||||
|
box-shadow: none;
|
||||||
|
border-bottom: 1px solid var(--base02);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Endpoint rows — method-colour left border stays; only the card body
|
||||||
|
is recoloured. */
|
||||||
|
.swagger-ui .opblock {
|
||||||
|
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(--base05);
|
||||||
|
}
|
||||||
|
.swagger-ui .opblock .opblock-section-header {
|
||||||
|
background: var(--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(--base05);
|
||||||
|
}
|
||||||
|
.swagger-ui .tab li,
|
||||||
|
.swagger-ui .opblock .opblock-section-header h4,
|
||||||
|
.swagger-ui .opblock .opblock-section-header label {
|
||||||
|
color: var(--base05);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Response / model tables. */
|
||||||
|
.swagger-ui table thead tr td,
|
||||||
|
.swagger-ui table thead tr th {
|
||||||
|
color: var(--base05);
|
||||||
|
border-bottom-color: var(--base02);
|
||||||
|
}
|
||||||
|
.swagger-ui .responses-inner h4,
|
||||||
|
.swagger-ui .responses-inner h5 {
|
||||||
|
color: var(--base05);
|
||||||
|
}
|
||||||
|
.swagger-ui .response-col_status {
|
||||||
|
color: var(--base05);
|
||||||
|
}
|
||||||
|
.swagger-ui .model-box,
|
||||||
|
.swagger-ui section.models {
|
||||||
|
background: var(--base01);
|
||||||
|
}
|
||||||
|
.swagger-ui section.models {
|
||||||
|
border-color: var(--base02);
|
||||||
|
}
|
||||||
|
.swagger-ui section.models h4 {
|
||||||
|
color: var(--base05);
|
||||||
|
}
|
||||||
|
.swagger-ui .model {
|
||||||
|
color: var(--base05);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Form controls */
|
||||||
|
.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(--base00);
|
||||||
|
color: var(--base05);
|
||||||
|
border-color: var(--base02);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
background: var(--base00);
|
||||||
|
}
|
||||||
|
.swagger-ui .btn.authorize {
|
||||||
|
color: var(--base0E);
|
||||||
|
border-color: var(--base0E);
|
||||||
|
}
|
||||||
|
.swagger-ui .btn.authorize svg {
|
||||||
|
fill: var(--base0E);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* `!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;
|
||||||
|
}
|
||||||
|
.swagger-ui .microlight {
|
||||||
|
color: var(--base05);
|
||||||
|
}
|
||||||
30
swagger-ui-theme/index.html
Normal file
30
swagger-ui-theme/index.html
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
<!-- Served by the gateway's nginx — one of 3 files (see also
|
||||||
|
hyperhive-theme.css, swagger-initializer.js) that
|
||||||
|
nix/packages/swagger-ui-theme.nix overlays onto the plain vendored
|
||||||
|
dist (swagger-ui-dist.nix), and the whole result is what
|
||||||
|
vhosts.nix's `swaggerUiLocations` serves at /api/docs/, wholesale,
|
||||||
|
with NO hive-c0re fallback for any file in the tree. Byte-identical
|
||||||
|
to the vendored Swagger UI's dist/index.html except two added
|
||||||
|
<link>s: `colors.css` (same origin as the dashboard — so this
|
||||||
|
resolves the operator's live stylix theme, not a frozen copy) and
|
||||||
|
hyperhive-theme.css, which consumes its `--baseNN` vars. -->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Swagger UI</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="index.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="/static/colors.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="hyperhive-theme.css" />
|
||||||
|
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
|
||||||
|
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="swagger-ui"></div>
|
||||||
|
<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>
|
||||||
|
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
|
||||||
|
<script src="./swagger-initializer.js" charset="UTF-8"> </script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
21
swagger-ui-theme/swagger-initializer.js
Normal file
21
swagger-ui-theme/swagger-initializer.js
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
window.onload = function() {
|
||||||
|
//<editor-fold desc="Changeable Configuration Block">
|
||||||
|
|
||||||
|
// 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
|
||||||
|
],
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
//</editor-fold>
|
||||||
|
};
|
||||||
Loading…
Reference in a new issue