package server import ( "fmt" "html/template" "log/slog" "net/http" "net/http/httptest" "net/url" ) // Server-side composition (spec page-anatomy "A page arrives complete"; // docs/design-system.md ยง6). A page region that also exists as an HTMX // partial, so a mutation can swap it back in, is rendered into the page by // the server on first paint through an in-process request to the partial's // own route. The browser never fetches first-paint content after load: one // response, no spinner, and the partial stays the single source of the // region's markup. // Include renders a GET route in-process, with the caller's request context // (session, request ID) and headers, and returns its HTML fragment. Core // builds one against its router and hands it to integrations through Deps // so their card bodies compose the same way. type Include func(r *http.Request, path string) (template.HTML, error) // NewInclude returns an Include that dispatches through router. The router // is the mux the partial routes are registered on; the middleware stack sits // outside it, so an include never re-authenticates: the session already // rides the context it is given. func NewInclude(router http.Handler) Include { return func(r *http.Request, path string) (template.HTML, error) { u, err := url.Parse(path) if err != nil { return "", fmt.Errorf("include %s: %w", path, err) } req := r.Clone(r.Context()) req.Method = http.MethodGet req.URL = u req.RequestURI = path req.Body = http.NoBody req.ContentLength = 0 req.Header.Set("HX-Request", "true") rec := httptest.NewRecorder() router.ServeHTTP(rec, req) if rec.Code != http.StatusOK { return "", fmt.Errorf("include %s: status %d", path, rec.Code) } return template.HTML(rec.Body.String()), nil } } // IncludeOr renders the fragment, or an inline notice naming what could not // be loaded, so a failing region never fails the page and never renders // blank. A nil Include (a test set without a router) renders nothing. func IncludeOr(inc Include, logger *slog.Logger, r *http.Request, path, what string) template.HTML { if inc == nil { return "" } out, err := inc(r, path) if err != nil { if logger != nil { logger.Error("page region failed to compose", slog.String("path", path), slog.Any("error", err)) } return template.HTML(`