server

package
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 21, 2026 License: MIT Imports: 29 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ActionMiddleware

func ActionMiddleware(registry *ActionRegistry) http.Handler

ActionMiddleware wraps registry so every request's method, path, duration, and resulting status code are logged with a "[Zyra Action]" prefix when registry.DevMode is true.

func ErrorHandler

func ErrorHandler(next http.Handler, devMode bool) http.Handler

ErrorHandler wraps next with panic recovery. Every panic is logged as "[Zyra Error] [timestamp] path [error]" followed by its Go stack trace (via the standard log package, which writes to stderr by default). In dev mode the HTTP response itself is a dark HTML page containing the same message and stack trace; in production it is a generic 500 page with no error detail exposed.

func ServeHTMXPage added in v1.1.0

func ServeHTMXPage(cfg *config.Config, route *router.Route, params map[string]string) http.HandlerFunc

ServeHTMXPage renders an HTML page using standard Go templates.

func ServeSSRPage

func ServeSSRPage(engine *SSREngine, cfg *config.Config, route *router.Route, params map[string]string) http.HandlerFunc

ServeSSRPage returns an http.HandlerFunc that renders route on the server via engine, injects the result and route params into Zyra's HTML shell, and writes the resulting document. Route params are forwarded to the worker as both the request's "params" field and, via RenderWithParams, as props.params on the rendered component; they are also embedded in the response as window.__ROUTE_PARAMS__ for client-side hydration.

Types

type ActionRegistry

type ActionRegistry struct {
	// DevMode enables Access-Control-Allow-Origin: * on responses and
	// request logging via ActionMiddleware.
	DevMode bool

	// Tracer, when non-nil, receives a broadcast after every action call
	// during dev mode so the browser DevTools panel can display it.
	Tracer TraceBroadcaster
	// contains filtered or unexported fields
}

ActionRegistry holds every Go function registered as a Zyra action and serves them over HTTP by reflecting each call's JSON body into the function's parameters.

func NewActionRegistry

func NewActionRegistry() *ActionRegistry

NewActionRegistry creates an empty ActionRegistry.

func (*ActionRegistry) Register

func (reg *ActionRegistry) Register(action codegen.ActionFunc, fn interface{})

Register associates a Go function with its action metadata so it can be invoked over HTTP at POST /__zyra/action/{Package}/{Name}. fn must be a function value; if it is not, Register logs a warning and does not register the action.

func (*ActionRegistry) ServeHTTP

func (reg *ActionRegistry) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements http.Handler, routing POST /__zyra/action/{package}/{functionName} requests to the matching registered action.

type DevServer

type DevServer struct {
	// ConfigPath is the path to zyra.config.json. Defaults to
	// config.ConfigFileName when empty.
	ConfigPath string
	// contains filtered or unexported fields
}

DevServer orchestrates Zyra's full development experience: loading configuration, running an initial build and codegen pass, starting file watchers, and serving the result over HTTP with hot reload, until it receives a shutdown signal.

func NewDevServer

func NewDevServer(configPath string) *DevServer

NewDevServer creates a DevServer that loads its configuration from configPath (or config.ConfigFileName if configPath is empty) when Start is called.

func (*DevServer) Start

func (d *DevServer) Start() error

Start runs Zyra's dev server startup sequence - banner, config, initial build, initial codegen, file watchers, HTTP server - prints a ready message once listening, and then blocks until it receives SIGINT or SIGTERM, at which point it shuts down gracefully.

type Middleware

type Middleware func(http.Handler) http.Handler

Middleware is a function that wraps an http.Handler with additional behaviour (logging, auth, rate limiting, etc.) and returns a new http.Handler. Middlewares are applied in the order they were registered with Use, outermost first.

func LoggingMiddleware

func LoggingMiddleware() Middleware

LoggingMiddleware logs every HTTP request in the format:

[Zyra] GET /path 200 1.23ms

Requests to internal Zyra paths (/__zyra/) are skipped to reduce noise in the dev terminal.

func RateLimitMiddleware

func RateLimitMiddleware(rate float64, burst int) Middleware

RateLimitMiddleware limits each remote IP to rate requests per second, with an initial burst of burst requests. Requests that exceed the limit receive HTTP 429 Too Many Requests with a Retry-After header.

Example — allow 10 req/s with an initial burst of 20:

server.Use(RateLimitMiddleware(10, 20))

func SecurityHeadersMiddleware

func SecurityHeadersMiddleware() Middleware

SecurityHeadersMiddleware sets a standard set of defensive HTTP response headers on every request:

  • X-Frame-Options: DENY – prevents clickjacking
  • X-Content-Type-Options: nosniff – prevents MIME sniffing
  • X-XSS-Protection: 1; mode=block – legacy XSS filter
  • Referrer-Policy: strict-origin-when-cross-origin
  • Content-Security-Policy – a restrictive CSP baseline

Call it unconditionally; it is a no-op overhead only for the header writes, which are cheap.

type PageCache

type PageCache struct {
	// contains filtered or unexported fields
}

PageCache is a thread-safe, in-memory store for fully-rendered SSR page HTML. Entries expire after a per-call TTL; stale entries are evicted lazily on the next Get for the same key, and all entries can be purged at once with Clear (used by the HMR watcher so a live reload never serves a stale page).

func (*PageCache) Clear

func (c *PageCache) Clear()

Clear removes all cached pages. It is called whenever the dev server's HMR watcher triggers a reload so stale HTML is never served during development.

func (*PageCache) Get

func (c *PageCache) Get(key string) ([]byte, bool)

Get returns the cached HTML for key and true when a live (not yet expired) entry exists. It returns nil, false otherwise and removes the stale entry in that case.

func (*PageCache) Len

func (c *PageCache) Len() int

Len returns the number of entries currently in the cache (including entries that have expired but not yet been lazily evicted).

func (*PageCache) Set

func (c *PageCache) Set(key string, html []byte, ttl time.Duration)

Set stores a copy of html for key, valid for ttl.

type SSREngine

type SSREngine struct {
	// ScriptPath is the path to the SSR worker script passed to
	// `bun run`. Defaults to "runtime/ssr-worker.ts" when empty.
	ScriptPath string
	// RenderTimeout bounds how long a single Render call waits for the
	// worker to respond. Defaults to 10s when zero.
	RenderTimeout time.Duration
	// contains filtered or unexported fields
}

SSREngine manages a long-running Bun subprocess that renders Zyra pages to HTML using React's renderToString, communicating over a newline-delimited JSON protocol on the worker's stdin/stdout.

An SSREngine is safe for concurrent use: Render/RenderWithParams may be called from multiple goroutines at once, each request is tagged with a unique ID, and a single background goroutine reads the worker's stdout and dispatches each response back to whichever call is waiting for that ID.

func (*SSREngine) Render

func (e *SSREngine) Render(page string, props map[string]interface{}) (*SSRResult, error)

Render asks the SSR worker to render page (a path to a .tsx page component, e.g. "pages/index.tsx") with the given props, returning the resulting HTML and head markup. If the engine has not been started yet, Render starts it automatically.

func (*SSREngine) RenderWithParams

func (e *SSREngine) RenderWithParams(page string, props map[string]interface{}, params map[string]string) (*SSRResult, error)

RenderWithParams is like Render but also forwards route params to the worker (and, from there, to the page component as props.params). ServeSSRPage uses this to pass a matched route's dynamic segments through to the rendered page.

func (*SSREngine) Start

func (e *SSREngine) Start() error

Start spawns the SSR worker subprocess and begins reading its responses in the background. Calling Start when the engine is already running is a no-op.

func (*SSREngine) Stop

func (e *SSREngine) Stop()

Stop terminates the SSR worker subprocess. It closes the worker's stdin first, giving it a chance to exit cleanly, then waits for the process to finish. Calling Stop when the engine is not running is a no-op.

type SSRResult

type SSRResult struct {
	HTML string
	Head string
}

SSRResult is the outcome of rendering a page on the server: the rendered markup for <div id="root"> and any extra markup for <head>.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server is the Zyra HTTP server used both in development (with hot reload) and to serve production builds.

func New

func New(cfg *config.Config) *Server

New creates a Server bound to the given Zyra configuration.

func (*Server) Actions

func (s *Server) Actions() *ActionRegistry

Actions returns the server's action registry. Register a Go function against it to make it callable at POST /__zyra/action/{package}/{name}.

func (*Server) BroadcastActionTrace added in v1.1.0

func (s *Server) BroadcastActionTrace(pkg, name, method string, status int, latencyMs float64, sizeBytes int64)

BroadcastActionTrace sends action call metrics to the DevTools panel. Only called when DevMode is true.

func (*Server) BroadcastActionUpdate

func (s *Server) BroadcastActionUpdate(pkg string)

BroadcastActionUpdate tells every connected client that generated action bindings for pkg have been regenerated.

func (*Server) BroadcastBuildStart

func (s *Server) BroadcastBuildStart()

BroadcastBuildStart tells every connected client that a rebuild has started, used to show a "Building..." state before the matching reload/css-update/action-update/error notification arrives.

func (*Server) BroadcastCSSUpdate

func (s *Server) BroadcastCSSUpdate()

BroadcastCSSUpdate tells every connected client to hot-swap the compiled stylesheet without a full page reload.

func (*Server) BroadcastError

func (s *Server) BroadcastError(message, stack string)

BroadcastError tells every connected client that a build/codegen step failed, so they can show a build-error overlay.

func (*Server) BroadcastReload

func (s *Server) BroadcastReload()

BroadcastReload tells every connected client to perform a full page reload, used when page or action source files change.

func (*Server) BroadcastSSRTrace added in v1.1.0

func (s *Server) BroadcastSSRTrace(route string, renderMs float64)

BroadcastSSRTrace sends SSR render timing to the DevTools panel. Only called when DevMode is true.

func (*Server) Close

func (s *Server) Close() error

Close stops the SSR engine subprocess, closes every HMR WebSocket connection, and gracefully shuts down the HTTP server, giving in-flight requests up to shutdownTimeout to finish.

func (*Server) ListenAndServe

func (s *Server) ListenAndServe() error

ListenAndServe starts the HTTP server and blocks until it exits.

func (*Server) Reload

func (s *Server) Reload() error

Reload rescans the file-based page routes and prints Zyra's route table. It clears the SSR page cache so any in-flight file changes are reflected immediately on the next request.

func (*Server) Streams added in v1.1.0

func (s *Server) Streams() *StreamRegistry

Streams returns the server's stream registry. Register a Go channel function against it to make it streamable over WebSocket at GET /__zyra/stream/{package}/{name}.

func (*Server) Use

func (s *Server) Use(m Middleware)

Use registers an additional middleware to be applied around every HTTP request. Middlewares are applied in registration order (first-registered is outermost). Use must be called before ListenAndServe; calling it afterwards has no effect.

type StreamRegistry added in v1.1.0

type StreamRegistry struct {
	// contains filtered or unexported fields
}

StreamRegistry holds every Go function registered as a Zyra stream and serves them over WebSocket at GET /__zyra/stream/{package}/{name}.

When a client connects, the registry calls the Go function, reads values from the returned channel, and sends each value as a JSON WebSocket message. The WebSocket connection is closed when the channel closes or the client disconnects.

func NewStreamRegistry added in v1.1.0

func NewStreamRegistry() *StreamRegistry

NewStreamRegistry creates an empty StreamRegistry.

func (*StreamRegistry) Register added in v1.1.0

func (reg *StreamRegistry) Register(stream codegen.StreamFunc, fn interface{})

Register associates a Go function with its stream metadata. fn must be a function value whose return type includes a channel. If fn is not a function or does not return a channel, Register logs a warning and does not register.

func (*StreamRegistry) ServeHTTP added in v1.1.0

func (reg *StreamRegistry) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements http.Handler for stream WebSocket connections. GET /__zyra/stream/{package}/{name}?param1=val1&...

type TraceBroadcaster added in v1.1.0

type TraceBroadcaster interface {
	BroadcastActionTrace(pkg, name, method string, status int, latencyMs float64, sizeBytes int64)
}

TraceBroadcaster is implemented by the server to forward action call metrics to the browser DevTools panel during development.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL