Documentation
¶
Overview ¶
Package uihost wires a core-ui application onto a framework.App's router. It mounts page rendering, runtime.js, compiled action JS, SSE island streaming, sessions, and signal-driven updates as routes — there is no standalone server. The framework.App owns the HTTP listener.
Index ¶
- func GetBuilder() *strings.Builder
- func PutBuilder(b *strings.Builder)
- func ReadCustomCSSFile(path string) string
- type HreflangLink
- type NotFoundRenderer
- type OG
- type Option
- func WithCanonicalURL(url string) Option
- func WithCustomCSS(css string) Option
- func WithDescription(desc string) Option
- func WithExtraScripts(urls ...string) Option
- func WithFavicon(href string) Option
- func WithHeadHTML(html string) Option
- func WithNotFoundScreen(c component.Component) Option
- func WithOpenGraph(og OG) Option
- func WithPreconnect(origins ...string) Option
- func WithPublicLLMMD() Option
- func WithRobots(cfg RobotsConfig) Option
- func WithSitemap(cfg SitemapConfig) Option
- func WithStaticDir(dir string) Option
- func WithThemeColor(color string) Option
- func WithTwitterCard(tc TwitterCard) Option
- type RobotsConfig
- type SEO
- type SEOScreen
- type ScreenCanonical
- type ScreenHreflangs
- type ScreenSEO
- type ScreenSchema
- type Session
- type SignalAny
- type SitemapConfig
- type TwitterCard
- type UIHost
- func (ds *UIHost) ActiveTheme() style.Theme
- func (ds *UIHost) AppCSS() string
- func (ds *UIHost) AutoCompileActions()
- func (ds *UIHost) CompileActions(componentID string, comp component.Component) string
- func (ds *UIHost) ComponentCSSFiles() map[string]string
- func (ds *UIHost) CreateSession() *Session
- func (ds *UIHost) CustomCSS() string
- func (ds *UIHost) GetActionJS() string
- func (ds *UIHost) GetSession(id string) (*Session, bool)
- func (ds *UIHost) HasStaticFS() bool
- func (ds *UIHost) Mount(r *router.Router)
- func (ds *UIHost) PushIsland(islandID string) error
- func (ds *UIHost) PushUpdate(islandID string, html string, sessionID string)
- func (ds *UIHost) RegisterSignal(id string, s SignalAny)
- func (ds *UIHost) RegisterWidget(sessionID string, w *component.Widget) *island.Island
- func (ds *UIHost) RenderStaticPage(ctx context.Context, path string) (string, error)
- func (ds *UIHost) ServeHTTP(w http.ResponseWriter, r *http.Request)
- func (ds *UIHost) SetStaticFS(fsys fs.FS)
- func (ds *UIHost) StaticDir() string
- func (ds *UIHost) StaticFS() fs.FS
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func GetBuilder ¶
GetBuilder gets a strings.Builder from the pool, reset to zero length.
func ReadCustomCSSFile ¶
ReadCustomCSSFile reads a CSS file and returns its content. This is a helper for the demo main.go.
Types ¶
type HreflangLink ¶
type HreflangLink struct {
Lang string // BCP-47 tag (e.g. "en", "en-US", "x-default")
URL string // canonical URL for that locale
}
HreflangLink declares a locale → URL alternate for the current page. Emitted as <link rel="alternate" hreflang="…" href="…">.
type NotFoundRenderer ¶
NotFoundRenderer is an optional interface a custom 404 screen (see WithNotFoundScreen) may implement to receive the unmatched request path. The path arrives as an argument, so a single shared screen instance can render per-request detail without a data race. Screens that don't implement it just render via component.Component.Render.
type OG ¶
OG holds Open Graph meta tag values for social sharing. Zero-value fields are omitted from output.
type Option ¶
type Option func(*UIHost)
Option configures a UIHost.
func WithCanonicalURL ¶
WithCanonicalURL adds a <link rel="canonical"> tag to <head>. Unsafe URLs (non-http(s)/relative) are dropped.
func WithCustomCSS ¶
WithCustomCSS adds extra CSS to inject into every page.
func WithDescription ¶
WithDescription adds a <meta name="description"> tag to <head>.
func WithExtraScripts ¶
WithExtraScripts adds external <script src="…"> URLs to inject before </body> on every page. Use for dev-only tooling like livereload. CSP-safe — every URL becomes an external resource, no inline JS.
func WithFavicon ¶
WithFavicon adds a <link rel="icon"> tag to <head>. The host also auto-serves 204 No Content at the configured URL when no static file matches, so a host that ships no favicon doesn't 404 on every page load. Place a real file at the path in staticDir / staticFS to override.
func WithHeadHTML ¶
WithHeadHTML injects raw HTML into every page's <head>. This is the escape hatch for arbitrary head content. The HTML is injected verbatim — callers must ensure it is CSP-compatible (no inline <script> or <style> tags). For safe, auto-escaped alternatives, see WithFavicon, WithThemeColor, WithDescription, WithOpenGraph, WithTwitterCard, WithCanonicalURL, and WithPreconnect.
func WithNotFoundScreen ¶
WithNotFoundScreen overrides the default bare 404 fallback. When a request misses every registered screen, static file, and configured favicon, the host renders this component through the active layout — so the 404 page sees the same nav/footer chrome every other page gets. The component's Render() result is wrapped in the default layout; pages without their own layout end up with the framework's bare <main>.
func WithOpenGraph ¶
WithOpenGraph adds Open Graph <meta property="og:..."> tags to <head>. Zero-value fields are omitted. URL-typed fields (Image, URL) are dropped if they fail the head-URL allow-list (http(s)/relative only) — a `javascript:`/`data:` URL there is reflected XSS via any social preview crawler that auto-clicks the link.
func WithPreconnect ¶
WithPreconnect adds <link rel="preconnect"> tags for the given origins. Use for early DNS/TCP/TLS connections to external resources (fonts, CDNs).
func WithPublicLLMMD ¶
func WithPublicLLMMD() Option
WithPublicLLMMD opts the host into mounting the page-level LLM-friendly markdown routes (/llm-pages.md, /<screen>/llm.md). Disabled by default because the documents enumerate every screen and the data shape attached to it — useful for AI agents in trusted environments, schema disclosure elsewhere.
func WithRobots ¶
func WithRobots(cfg RobotsConfig) Option
WithRobots registers a /robots.txt handler. A nil-zero RobotsConfig is fine — it ships the open default (allow everything).
func WithSitemap ¶
func WithSitemap(cfg SitemapConfig) Option
WithSitemap registers a /sitemap.xml handler.
func WithStaticDir ¶
WithStaticDir sets the directory to serve static files from.
func WithThemeColor ¶
WithThemeColor adds a <meta name="theme-color"> tag to <head>.
func WithTwitterCard ¶
func WithTwitterCard(tc TwitterCard) Option
WithTwitterCard adds Twitter Card <meta name="twitter:..."> tags to <head>. Zero-value fields are omitted. URL-typed fields are scheme-restricted per WithOpenGraph.
type RobotsConfig ¶
type RobotsConfig struct {
// UserAgent is the target crawler. Empty defaults to "*" (all
// crawlers).
UserAgent string
// Allow lists the path prefixes the crawler may visit. Empty +
// empty Disallow is the open default ("Allow: /").
Allow []string
// Disallow lists path prefixes the crawler must not visit.
Disallow []string
// SitemapURL is the absolute URL of the sitemap. When empty and
// WithSitemap was also configured, the handler derives it from
// SitemapConfig.BaseURL + "/sitemap.xml".
SitemapURL string
// CrawlDelay seconds between requests. Zero omits the directive.
CrawlDelay int
}
RobotsConfig configures the /robots.txt endpoint.
type SEO ¶
type SEO struct {
Description string // <meta name="description">
Canonical string // <link rel="canonical">
Hreflangs []HreflangLink // <link rel="alternate" hreflang>
Robots string // <meta name="robots"> (e.g. "noindex,nofollow")
OG *OG // Open Graph block
Twitter *TwitterCard // Twitter Card block
Schema []seo.Thing // JSON-LD items
}
SEO bundles every per-page SEO declaration in one struct. Use it as the return type of ScreenSEO when you'd rather declare everything from one method than implement the per-concern interfaces individually. Empty fields are silently skipped — only what's set is emitted.
type SEOScreen ¶
type SEOScreen interface {
HeadHTML() string
}
SEOScreen is an optional interface that screens can implement to inject per-screen HTML into <head>. This enables per-page SEO: Open Graph tags, description meta, structured data, etc. The returned HTML is injected alongside any global head tags from WithHeadHTML / WithFavicon / etc.
WARNING: the returned HTML is injected verbatim. Implementers must escape any dynamic content (e.g. html.EscapeString for user-supplied titles or descriptions) to prevent XSS.
type ScreenCanonical ¶
type ScreenCanonical interface {
ScreenCanonical() string
}
ScreenCanonical is an optional screen interface that declares the canonical URL for the current page. Emitted as <link rel="canonical" href="…">. Use to prevent duplicate-content issues when a page is reachable at multiple URLs (filters, sorts).
type ScreenHreflangs ¶
type ScreenHreflangs interface {
ScreenHreflangs() []HreflangLink
}
ScreenHreflangs is an optional screen interface that declares per-page hreflang alternates for multi-locale apps. When present, the host emits one <link rel="alternate"> per returned link.
type ScreenSEO ¶
type ScreenSEO interface {
ScreenSEO() SEO
}
ScreenSEO is the bundle-style alternative to the per-concern interfaces. When a screen implements both ScreenSEO AND any of ScreenDescriber / ScreenCanonical / ScreenHreflangs / ScreenSchema, ScreenSEO wins — its fields override.
Returning a zero-value SEO from ScreenSEO opts out of all per-page emission for the screen (useful for routes you want fully naked).
type ScreenSchema ¶
ScreenSchema is an optional screen interface that returns one or more typed Schema.org items (from core-ui/seo) to emit as <script type="application/ld+json"> blocks.
Implementations typically return:
[]seo.Thing{
seo.NewArticle(),
seo.NewBreadcrumbList(...),
}
type SignalAny ¶
type SignalAny interface {
GetAsInterface() interface{}
UpdateAsInterface(v interface{})
Subscribe() <-chan struct{}
}
SignalAny is an interface to allow storing heterogeneous signals.
type SitemapConfig ¶
type SitemapConfig struct {
// BaseURL is the canonical origin (scheme + host) for emitted
// <loc> elements. Required — sitemap.xml entries must be absolute
// URLs per the protocol spec.
BaseURL string
// LastMod sets the <lastmod> timestamp emitted for every page.
// Zero defaults to the time the server started, which is a
// reasonable signal that anything older was content the build
// already covered.
LastMod time.Time
// ExcludePaths lists route prefixes to omit from the sitemap.
// Useful for admin routes, drafts, etc. Prefix match.
ExcludePaths []string
}
SitemapConfig configures the /sitemap.xml endpoint.
type TwitterCard ¶
type TwitterCard struct {
Card string // e.g. "summary", "summary_large_image"
Title string
Description string
Image string
Site string // @username
}
TwitterCard holds Twitter Card meta tag values. Zero-value fields are omitted from output.
type UIHost ¶
type UIHost struct {
App *app.App
Islands *island.Manager
// contains filtered or unexported fields
}
UIHost mounts a core-ui application onto a router. It serves rendered pages with runtime.js, compiled action JS, SSE streaming for islands, sessions, and signal-driven live updates. The framework.App is responsible for ListenAndServe.
func (*UIHost) ActiveTheme ¶
ActiveTheme returns the configured theme or the default if unset. Exposed for tooling (e.g. the static-site builder) that needs to resolve theme tokens at build time.
func (*UIHost) AppCSS ¶
AppCSS returns the merged app-level stylesheet body: theme :root custom properties + every registered theme override (.fui-theme-<hash> blocks for ui.Themed wrappers) + customCSS, in that order. Used by the SSG so static export ships the same single asset the live server serves.
The :root block is ALWAYS emitted, even when the host has no explicit App.Theme. Per-component CSS emits bare var(--*) references (no in-CSS fallbacks); without the :root floor every component would render with UA defaults. The DefaultTheme() floor guarantees var() resolution.
func (*UIHost) AutoCompileActions ¶
func (ds *UIHost) AutoCompileActions()
AutoCompileActions scans all registered screens and compiles actions for any that implement InteractiveComponent. The component ID is derived from ScreenComponentID.ComponentID() if implemented, otherwise from the route path.
func (*UIHost) CompileActions ¶
CompileActions compiles a component's action methods to JS and caches them. It also stores the action registry so handleServerAction can invoke Go handlers.
func (*UIHost) ComponentCSSFiles ¶
ComponentCSSFiles returns one asset per registered component: urlPath ("/__gofastr/comp/<name>.css") and the scoped CSS body resolved under the active theme. Used by the static-site builder.
func (*UIHost) CreateSession ¶
CreateSession creates a new browser session. The ID is 16 bytes of crypto/rand encoded as hex — the prior `sess-<UnixNano()>` form could collide under load when two CreateSession calls landed in the same nanosecond.
func (*UIHost) GetActionJS ¶
GetActionJS returns all compiled action JS concatenated.
func (*UIHost) GetSession ¶
GetSession retrieves a session by ID.
func (*UIHost) HasStaticFS ¶
HasStaticFS reports whether an embedded static FS is configured.
func (*UIHost) Mount ¶
Mount registers the UI's HTTP handlers on the given router.
It registers:
- All `/__gofastr/*` infrastructure endpoints (runtime.js, actions.js, SSE, session, signal updates, server actions, widget JS, CSS chunks)
- A NotFound handler that first attempts static-file resolution (from either staticDir or staticFS) and falls back to page rendering.
Mount must be called after the framework.App has registered its other routes (entity CRUD, custom endpoints) so the page handler only takes requests that nothing else claimed.
func (*UIHost) PushIsland ¶
PushIsland re-renders an island and pushes the update via SSE.
func (*UIHost) PushUpdate ¶
PushUpdate pushes an island update for a specific session. This is a convenience method that wraps the island manager's push mechanism.
func (*UIHost) RegisterSignal ¶
RegisterSignal registers a signal with the devserver so the signal update endpoint can apply client-sent values. Safe for concurrent use; the signal-update HTTP handler reads the same map.
func (*UIHost) RegisterWidget ¶
RegisterWidget registers a widget with the island manager for a session. Returns the widget wrapped as an island for rendering.
func (*UIHost) RenderStaticPage ¶
RenderStaticPage produces a fully-rendered page suitable for static-site generation: it runs the screen's Load(ctx) hook, applies layout/theme, and injects runtime.js, compiled actions, custom CSS, and the route graph — but skips the SSE meta tag because there is no live session. The result is safe to write to disk and serve from any static host.
func (*UIHost) ServeHTTP ¶
func (ds *UIHost) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP makes UIHost satisfy http.Handler by routing through a private router that has Mount called on it. Production wiring goes through framework.App.Mount(host); ServeHTTP exists so the host can also be used standalone (tests, embedded experiments) without dragging in the full framework App.
func (*UIHost) SetStaticFS ¶
SetStaticFS sets an embedded filesystem for serving static files.