# sr-ht-ecore Extended core for the custom services of a self-hosted SourceHut instance (compare, spec, dolt, cover, bench, ...). Everything these services share that is *ours* — not upstream's — lives here, so the sr-ht-core fork can stay a clean mirror of upstream core-go, and so the services stop carrying drifting copies of the same code. ## Packages - `chrome` — the shared page chrome: service-switcher nav built from the shared config.ini (`chrome.BuildNav`), per-request `chrome.Page` with login/logout/profile URLs against meta.sr.ht's unified login, embedded `srht-nav` / `srht-env-banner` template partials (circle brand + red service label + switcher + login box), and the generic template helpers (`dict`, `shortsha`). - `grants` — the grant vocabulary of tokens.sr.ht (SPEC ch. 3): `:` members split on ASCII whitespace, `*` for every action of every service, the reserved `id:` member a registered token carries, and the subset rule an exchange narrows by. Shared because the daemon that mints and every service that validates have to read one grammar — two parsers that disagree about what counts as a permission is a hole on the security path, not a cosmetic divergence. ## Usage: chrome ```go svc := chrome.NewService(conf, "compare.sr.ht") svc.StyleHref = cssHref // after discovering the hashed stylesheet t := chrome.MustAttach(template.New("layout").Funcs(chrome.Funcs())) // ... parse the service's own templates into t ... page := svc.Page(r, "Page title", username) // username "" = anonymous ``` In the layout: ```html {{template "srht-env-banner" .}} ``` The template dot must expose the `chrome.Page` fields — either a `Page` itself, or a service view struct that embeds one (promoted fields resolve in templates). ## Policy: chrome The chrome bakes in the instance-wide decisions instead of parameterizing them: the switcher renders only for authenticated viewers; paste, pages and hub never appear in it; the brand is always circle + site name + red service label and links to the service's own root; the profile link prefers hub's `~username` page when hub is configured. Service-specific nav entries go through `Service.ExtraNav`; per-page width through `Page.ContainerClass`.