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
- Variables
- type Artboard
- type CanvasGrant
- type Grant
- type Options
- type Server
- func (s *Server) Addr() string
- func (s *Server) Bump(artifactID string)
- func (s *Server) CanvasURL(sessionID string) (string, error)
- func (s *Server) Close()
- func (s *Server) Grants() []Grant
- func (s *Server) Publish(artifactID, sessionID, absDir, entry string) (Grant, error)
- func (s *Server) PublishCanvas(sessionID string) (CanvasGrant, error)
- func (s *Server) Revision(artifactID string) uint64
- func (s *Server) Revoke(artifactID string)
- func (s *Server) RevokeCanvas(sessionID string)
- func (s *Server) RevokeSession(sessionID string)
- func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)
- func (s *Server) StartLoopback() error
- func (s *Server) URL(artifactID string, opts URLOptions) (string, error)
- type URLOptions
Constants ¶
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.
const CanvasPath = Prefix + CanvasSegment + "/"
CanvasPath is the route prefix the canvas owns.
const CanvasSegment = "_canvas"
CanvasSegment is the token-free first segment of every canvas URL. It cannot collide with an artifact token because tokens are hex and this is not.
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.
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 ¶
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 Artboard ¶ added in v0.703.4
type Artboard struct {
ID string `json:"id"`
Title string `json:"title"`
Slug string `json:"slug,omitempty"`
Kind string `json:"kind,omitempty"`
// URL is the address of the artifact document the artboard frames.
URL string `json:"url"`
// Width and Height are the logical viewport the artboard is rendered at,
// before the canvas zoom scales it. A deck is 1280x720, a page 1440x900.
Width int `json:"width"`
Height int `json:"height"`
// Version is the artifact's snapshot number, shown on the artboard label.
Version int `json:"version,omitempty"`
// Status is "ready", "building" or "error". The canvas renders a badge for
// anything that is not ready.
Status string `json:"status,omitempty"`
// Note carries the error message, or whatever the status needs to explain.
Note string `json:"note,omitempty"`
// Revision changes whenever the document underneath changes. The canvas
// watches it to flash the artboard and to force a reload of its frame.
Revision uint64 `json:"revision"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
}
Artboard is one artifact as the canvas sees it. The preview package knows nothing about the design model, so the whole struct is filled in by the Options.Artboards provider that internal/design installs.
type CanvasGrant ¶ added in v0.703.4
type CanvasGrant struct {
Token string `json:"token"`
SessionID string `json:"session_id,omitempty"`
ExpiresAt time.Time `json:"expires_at"`
}
CanvasGrant is one canvas published for viewing.
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
// Artboards supplies the canvas view with the session's artifacts. It is a
// function for the same reason Inject is a byte slice: the canvas needs the
// design model and this package must not depend on it. A nil provider
// leaves the canvas served but empty.
Artboards func(sessionID string) ([]Artboard, error)
}
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 (*Server) Bump ¶
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 ¶
Grants lists the live grants, newest expiry first is not guaranteed; the order is unspecified. It exists for diagnostics and tests.
func (*Server) Publish ¶
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) PublishCanvas ¶ added in v0.703.4
func (s *Server) PublishCanvas(sessionID string) (CanvasGrant, error)
PublishCanvas mints (or refreshes) the canvas grant of a session and returns it. Sessions without an id share the process-wide canvas, which is what a plain CLI invocation wants.
func (*Server) Revision ¶ added in v0.703.4
Revision returns the live-reload revision of a published artifact, or zero when it has no grant. The canvas compares it between polls to tell an artboard whose document changed from one that merely moved.
func (*Server) RevokeCanvas ¶ added in v0.703.4
RevokeCanvas drops the canvas grant of a session.
func (*Server) RevokeSession ¶
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 ¶
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.
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.