[package]
name = "holger-ui-web"
version = "2.0.0"
edition = "2021"
authors = ["Ignalina ApS", "Vetra Automation AB"]
description = "Web operator console for holger — Leptos/WASM over gRPC-web"
license = "AGPL-3.0-only"
repository = "https://git.gunnar.rs/nordisk/holger-ui"
publish = false
# Development notes, agent instructions and machine-local tooling stay in the
# repository; they are not part of the published crate.
exclude = [
".nornir/",
".cargo/",
"deploy/",
"docs/ai-context.md",
"docs/ai-context-full.md",
"docs/tailscale-access.md",
]
# NOTE on the name: the holger main repo's egui/eframe operator app in
# `server/ui` was once the crate `holger-ui` (renamed `holger-server-ui` on
# 2026-08-01). This package stays `holger-ui-web` so the two can never collide
# in a workspace or patch table, even though the repository is `holger-ui`.
# `xtask` holds the deploy verbs (`cargo xtask publish | verify-chain | build`),
# and `crates/` holds the build declaration this repository is described by.
#
# `default-members` keeps a bare `cargo build` / `trunk build` on the console
# alone — the recipe is a native rlib nothing in the bundle links,
# `holger-ui-build-thing` is a cdylib that exists for the dwarves forge to load,
# and `holger-ui-server` is a NATIVE binary that cannot compile for wasm32 at
# all (tokio, axum, hyper). A `cargo build --target wasm32-unknown-unknown` must
# therefore never reach it, and with the console as the only default member it
# does not. Build it by name: `cargo build --release -p holger-ui-server`.
# `cargo test --workspace` is what runs the parity test; `cargo xtask build`
# checks the same thing before it builds anything.
[workspace]
members = [
".", # holger-ui-web: the console, the wasm bundle a browser runs
"crates/holger-ui-server", # the thin server: the bundle + a same-origin pass-through to holger
"crates/holger-public-site", # holger.rs's public face (robots, sitemap, llms.txt, head tags); only behind holger-ui-server `public-site`
"crates/holger-ui-recipe", # THE BUILD DECLARATION: every build point, in Rust
"crates/holger-ui-build-thing", # its wasm32 cdylib shim + the `emit` door (nothing depends on it)
"xtask", # repository tasks. Nothing depends on it.
]
default-members = ["."]
# The browser tests link holger, its front and monetize from the sibling checkouts: their own
# workspace and lock (browser-tests/Cargo.toml), run by `cargo xtask browser`.
exclude = ["browser-tests"]
[features]
default = []
# **The paid half of the console** (A28 M13; gunnar-ui-web's `metered`, the same word
# holger-ui-server, holger and holger-estate-front use). Without it the bundle renders no
# word about money: no "My plan" page, no buy link in the topbar, no "More room" panel, no
# order button and no payments card on the admin page. The metered bundle (`dist-metered/`,
# the page `metered/index.html`, the recipe's `mvp-ui-web-metered` row) also carries the
# sign-up, welcome and order pages. holger's paid front embeds that bundle.
metered = []
[dependencies]
# ── UI ────────────────────────────────────────────────────────────────────────
# Leptos in client-side-rendering mode; no SSR server in this repo.
leptos = { version = "0.8", features = ["csr"] }
leptos_router = "0.8"
console_error_panic_hook = "0.1"
# ── gRPC-web client ───────────────────────────────────────────────────────────
# The browser cannot speak native gRPC (HTTP/2 trailers), so the wire is
# gRPC-web via fetch. holger's server terminates it with a tonic-web layer.
#
# tonic here is 0.14 (codegen only, no transport — hyper does not build on
# wasm); holger's server is on tonic 0.13. That skew is fine: the gRPC-web
# protocol on the wire is independent of either side's tonic version.
tonic = { version = "0.14", default-features = false, features = ["codegen"] }
tonic-prost = "0.14"
prost = "0.14"
tonic-web-wasm-client = "0.9"
wasm-bindgen = "0.2"
wasm-bindgen-futures = "0.4"
js-sys = "0.3"
# The OIDC dance (discovery + token exchange) is plain JSON-over-fetch;
# gloo-net is already in the tree via tonic-web-wasm-client.
gloo-net = { version = "0.7", default-features = false, features = ["http", "json"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
# The estate board's renderer (Holger v2.0 H2 #1): the server serves the board as data and
# draws nothing, so the console draws it (`src/board.rs`) with the renderer Gunnar's console
# uses. Zero dependencies, wasm-clean. From monetize's open `crates/estate-svg` (the sibling
# patch in `.cargo/estate-siblings.toml` until it is on crates.io).
nordisk-estate-svg = "0.1.0"
# Blob/Url/anchor: the Download button materializes FetchArtifact bytes as an
# object URL and clicks a temporary <a download> — no server round-trip twice.
web-sys = { version = "0.3", features = [
"Window", "Location", "Blob", "BlobPropertyBag", "Url",
"Document", "Element", "HtmlElement", "HtmlAnchorElement",
"File", "FileList", "HtmlInputElement", "Storage",
"Crypto", "SubtleCrypto", "History", "UrlSearchParams",
"Clipboard", "Navigator", "KeyboardEvent", "NodeList",
# A28 M9: the in-place step-up touch (navigator.credentials.get).
"CredentialsContainer", "CredentialRequestOptions",
] }
# 2026-10-05 (merge to main): no [patch.crates-io] any more — crates.io serves
# nornir-auth-webauthn, nornir-git (published 2026-10-04; the siblings carry the same code, at most test/doc edits since).
# TEMPORARY until nornir-git 0.1.12 (its first release on russh 0.63) is published (2026-10-03, finish-bump).
# holger-ui-build-thing -> registry nornir-build-thing -> registry nornir-git, whose
# russh 0.61 pins `ecdsa =0.17.0-rc.18`; that cannot coexist with the stable ecdsa
# 0.17 p256 0.14 brings (one semver slot), so the workspace would not resolve.
# edda's nornir-git (same 0.1.11 number, unpublished) is on russh 0.63.
[build-dependencies]
# Generates the client stubs into OUT_DIR at build time. protox parses the proto
# in pure Rust, so no `protoc` binary is needed. Server codegen is off; this
# repo is a client only.
tonic-prost-build = "0.14"
protox = "0.10"
[profile.release]
opt-level = "z"
lto = true
codegen-units = 1
# Holger v2.0 (H1): every holger-ui crate says `version.workspace = true`.
[workspace.package]
version = "2.0.0"