preview

package
v0.700.0 Latest Latest
Warning

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

Go to latest
Published: Aug 31, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package preview serves design artifacts over HTTP so every surface — the WebUI iframe, a system browser opened from the TUI, a Zed resource link — looks at the same running document instead of a file:// copy.

The package deliberately knows nothing about the design model: it is handed a directory and an entry document and hands back a URL. That keeps it free of any dependency on internal/design, so internal/design can import it to mint URLs while internal/api mounts the very same handler on the main listener.

Two deployments share one implementation:

  • mounted: internal/api registers Server.ServeHTTP under Prefix on the API listener, so the preview lives on the Pando origin and is reachable remotely through the existing external-access toggle.
  • loopback: processes without an API server (plain TUI, ACP, CLI) call Server.StartLoopback, which binds 127.0.0.1:0 and serves the same routes.

Every artifact is addressed through an unguessable per-artifact token in the path. The token is the capability: it is bound to the session that created it and dies with the grant, so a stale URL in someone's browser history stops resolving instead of exposing whatever now sits in that directory.

Index

Constants

View Source
const BridgePath = Prefix + "_bridge.js"

BridgePath serves the selection bridge. It sits outside the token space on purpose: it is a static asset with no artifact content in it, and keeping it token-free means one cached copy serves every artifact.

View Source
const DefaultTTL = 12 * time.Hour

DefaultTTL is how long a grant stays resolvable without being refreshed. Presenting an artifact refreshes it, so an artifact under active iteration never expires while the user is looking at it.

View Source
const Prefix = "/preview/"

Prefix is the single route prefix the server owns. Everything below it is artifact content; nothing above it is ever touched.

Variables

View Source
var ErrForbidden = errors.New("preview: refused")

ErrForbidden is returned by an access guard that refuses to serve. The API server uses it to keep previews off a network-facing listener that has no authentication in front of it.

Functions

This section is empty.

Types

type Grant

type Grant struct {
	Token      string `json:"token"`
	ArtifactID string `json:"artifact_id"`
	SessionID  string `json:"session_id,omitempty"`
	// Dir is the absolute artifact directory. Nothing outside it is served.
	Dir string `json:"-"`
	// Entry is the directory-relative default document.
	Entry     string    `json:"entry"`
	ExpiresAt time.Time `json:"expires_at"`
	// contains filtered or unexported fields
}

Grant is one artifact published for viewing.

type Options

type Options struct {
	// BaseURL resolves the origin to build absolute URLs with. It is a function
	// because the API server's bind address changes at runtime when the
	// external-access toggle is flipped. When it is nil or returns an empty
	// string the server falls back to its own loopback listener, and to a
	// relative URL when it has none.
	BaseURL func() string
	// Access is consulted on every request and before every publish. A non-nil
	// error refuses the operation. It exists so the API server can enforce
	// "never on a non-loopback bind without basic auth".
	Access func() error
	// TTL overrides DefaultTTL.
	TTL time.Duration
	// FrameAncestors overrides the CSP frame-ancestors list. It defaults to
	// 'self', which is right whenever the preview and the UI framing it share
	// an origin — the mounted deployment. A shell that runs the UI on its own
	// origin (the Wails desktop app) has to widen it, and doing that here keeps
	// the decision in the caller that knows its own origin.
	FrameAncestors string
	// Inject is JavaScript spliced into a ?bridge=1 document ahead of the
	// bridge itself. internal/design supplies the renderer's own element
	// walker here, so the data-pando-id a user clicks in the browser is the
	// same id the stored node index holds. Keeping it an option is what lets
	// this package stay ignorant of the design model.
	Inject []byte
}

Options configures a server.

type Server

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

Server is the grant registry and the HTTP handler over it.

func New

func New(opts Options) *Server

New builds a server. It serves nothing until an artifact is published.

func (*Server) Addr

func (s *Server) Addr() string

Addr reports the loopback listener address, empty when there is none.

func (*Server) Bump

func (s *Server) Bump(artifactID string)

Bump increments the live-reload revision of a published artifact. It is a no-op when the artifact has no active grant on this server.

func (*Server) Close

func (s *Server) Close()

Close stops the loopback listener and drops every grant.

func (*Server) Grants

func (s *Server) Grants() []Grant

Grants lists the live grants, newest expiry first is not guaranteed; the order is unspecified. It exists for diagnostics and tests.

func (*Server) Publish

func (s *Server) Publish(artifactID, sessionID, absDir, entry string) (Grant, error)

Publish registers (or refreshes) a grant for an artifact directory and returns it. The token is stable for the lifetime of the grant so reloading a preview keeps the same URL, which is what lets an iframe survive a re-render.

func (*Server) Revoke

func (s *Server) Revoke(artifactID string)

Revoke drops the grant of one artifact.

func (*Server) RevokeSession

func (s *Server) RevokeSession(sessionID string)

RevokeSession drops every grant a session published. Sessions end; their preview URLs must stop resolving with them.

func (*Server) ServeHTTP

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP serves artifact files under Prefix.

func (*Server) StartLoopback

func (s *Server) StartLoopback() error

StartLoopback binds 127.0.0.1:0 and serves the preview routes there. It is the fallback for processes with no API server; calling it twice is a no-op.

func (*Server) URL

func (s *Server) URL(artifactID string, opts URLOptions) (string, error)

URL returns the address of a published artifact.

type URLOptions

type URLOptions struct {
	// Slide adds a #slide-N fragment (decks).
	Slide int
	// Bridge asks for the selection bridge to be injected. Only the Pando UI
	// sets it; a URL opened in a plain browser stays untouched markup.
	Bridge bool
	// Doc overrides the entry document with another directory-relative file.
	Doc string
}

URLOptions tunes the address Publish hands out.

Jump to

Keyboard shortcuts

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