Documentation
¶
Index ¶
- Constants
- Variables
- func AssetHandler() http.Handler
- func AssetsVersion() string
- func CacheHandler(hash string, next http.Handler) http.Handler
- func CreateUsernameFromBech32(username string) string
- func GetClientErrorStatusView(_ *weburl.GnoURL, err error, height int64) (int, *components.View)
- func NewDefaultChromaOptions() []chromahtml.Option
- func NewDefaultGoldmarkOptions() []goldmark.Option
- func NewRouter(logger *slog.Logger, cfg *AppConfig) (http.Handler, error)
- func NoCacheHandler(next http.Handler) http.Handler
- func RedirectMiddleware(next http.Handler, meta StaticMetadata) http.Handler
- type AliasKind
- type AliasTarget
- type AppConfig
- type ClientAdapter
- type FileMeta
- type HTMLRenderer
- func (r *HTMLRenderer) RenderDocumentation(w io.Writer, src []byte) error
- func (r *HTMLRenderer) RenderRealm(w io.Writer, u *weburl.GnoURL, src []byte, ctx RealmRenderContext) (md.Toc, error)
- func (r *HTMLRenderer) RenderSource(w io.Writer, name string, src []byte) error
- func (r *HTMLRenderer) WriteChromaCSS(w io.Writer) error
- type HTTPHandler
- func (h *HTTPHandler) Get(w http.ResponseWriter, r *http.Request)
- func (h *HTTPHandler) GetDirectoryView(ctx context.Context, gnourl *weburl.GnoURL, indexData *components.IndexData) (int, *components.View)
- func (h *HTTPHandler) GetHelpView(ctx context.Context, gnourl *weburl.GnoURL) (int, *components.View)
- func (h *HTTPHandler) GetMarkdownRealmView(ctx context.Context, gnourl *weburl.GnoURL, indexData *components.IndexData) (int, *components.View)
- func (h *HTTPHandler) GetMarkdownView(gnourl *weburl.GnoURL, mdContent string) (int, *components.View)
- func (h *HTTPHandler) GetOverviewView(ctx context.Context, gnourl *weburl.GnoURL) (int, *components.View)
- func (h *HTTPHandler) GetPackageView(ctx context.Context, gnourl *weburl.GnoURL, indexData *components.IndexData, ...) (int, *components.View)
- func (h *HTTPHandler) GetPathsListView(ctx context.Context, gnourl *weburl.GnoURL, indexData *components.IndexData) (int, *components.View)
- func (h *HTTPHandler) GetRealmView(ctx context.Context, gnourl *weburl.GnoURL, indexData *components.IndexData) (int, *components.View)
- func (h *HTTPHandler) GetSourceView(ctx context.Context, gnourl *weburl.GnoURL) (int, *components.View)
- func (h *HTTPHandler) GetUserView(ctx context.Context, gnourl *weburl.GnoURL) (int, *components.View)
- func (h *HTTPHandler) Post(w http.ResponseWriter, r *http.Request)
- func (h *HTTPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
- func (h *HTTPHandler) ServeHelpJSON(ctx context.Context, gnourl *weburl.GnoURL, w http.ResponseWriter)
- func (h *HTTPHandler) ServeSourceDownload(ctx context.Context, gnourl *weburl.GnoURL, w http.ResponseWriter, ...)
- type HTTPHandlerConfig
- type MockClient
- func (m *MockClient) Doc(ctx context.Context, path string, _ int64) (*doc.JSONDocumentation, error)
- func (m *MockClient) Eval(ctx context.Context, _, _ string) ([]byte, error)
- func (m *MockClient) File(ctx context.Context, pkgPath, fileName string, _ int64) ([]byte, FileMeta, error)
- func (m *MockClient) ListFiles(ctx context.Context, path string, _ int64) ([]string, error)
- func (m *MockClient) ListPaths(ctx context.Context, prefix string, limit int) ([]string, error)
- func (m *MockClient) PackageMeta(ctx context.Context, path string) (*vm.PackageMeta, error)
- func (m *MockClient) Realm(ctx context.Context, path, args string) ([]byte, error)
- func (m *MockClient) StateObject(_ context.Context, _ string, _ int64) ([]byte, error)
- func (m *MockClient) StatePkg(_ context.Context, path string, _ int64) ([]byte, error)
- func (m *MockClient) StateType(_ context.Context, _ string, _ int64) ([]byte, error)
- type MockPackage
- type RealmDirectory
- type RealmRenderContext
- type RenderConfig
- type Renderer
- type StaticMetadata
Constants ¶
const MaxUserContributions = 200
MaxUserContributions caps how many contributions /u/<user> renders per namespace; a resolved user lists two. Each entry costs a weburl parse and a sort comparison; an unbounded cap turns a single GET into a 10k-iteration amplifier. Exported so external tests assert against the documented cap. TODO: paginate via ?page= when a contributor exceeds this cap.
const ReadmeFileName = "README.md"
const RealmNoticeHeader = "X-Gnoweb-Realm-Notice"
RealmNoticeHeader is set to "community" on markdown responses of pages that show the realm notice, whose body is served verbatim.
const UserRegistryPath = "/r/sys/users"
UserRegistryPath is the realm that maps gno.land names to addresses, and the only source gnoweb has for either side of the pair.
Variables ¶
var ( ErrClientPackageNotFound = errors.New("package not found") ErrClientFileNotFound = errors.New("file not found") ErrClientObjectNotFound = errors.New("object not found") ErrClientRenderNotDeclared = errors.New("render function not declared") ErrClientBadRequest = errors.New("bad request") ErrClientTimeout = errors.New("RPC node request timeout") ErrClientResponse = errors.New("RPC node response error") ErrClientResponseTooLarge = errors.New("RPC node response too large") )
var DefaultAliases = map[string]AliasTarget{ "/": {"/r/gnoland/home", GnowebPath}, "/about": {"/r/gnoland/pages:p/about", GnowebPath}, "/gnolang": {"/r/gnoland/pages:p/gnolang", GnowebPath}, "/ecosystem": {"/r/gnoland/pages:p/ecosystem", GnowebPath}, "/start": {"/r/gnoland/pages:p/start", GnowebPath}, "/license": {"/r/gnoland/pages:p/license", GnowebPath}, "/contribute": {"/r/gnoland/pages:p/contribute", GnowebPath}, "/links": {"/r/gnoland/pages:p/links", GnowebPath}, "/events": {"/r/devrels/events", GnowebPath}, "/partners": {"/r/gnoland/pages:p/partners", GnowebPath}, "/docs": {"/u/docs", GnowebPath}, }
var DefaultCacheAssetsHandler = func(next http.Handler) http.Handler { return CacheHandler(assetsHash, next) }
var DefaultChromaDarkRenderStyle = styles.Get("nord")
var DefaultChromaRenderStyle = styles.Get("friendly")
var Redirects = map[string]string{
"/r/demo/boards:gnolang/6": "/r/demo/boards:gnolang/3",
"/blog": "/r/gnoland/blog",
"/gor": "/contribute",
"/game-of-realms": "/contribute",
"/grants": "/partners",
"/language": "/gnolang",
"/getting-started": "/start",
"/newsletter": "/r/gnoland/pages:p/newsletter",
}
Redirects is a map of gnoweb paths that are redirected using RedirectMiddleware.
Functions ¶
func AssetHandler ¶
AssetHandler returns an http.Handler to serve static assets from the embedded filesystem. Assets are always served from the embedded /public directory.
func AssetsVersion ¶
func AssetsVersion() string
AssetsVersion returns the token stamped on asset URLs so a cache keyed on the URL refetches an asset once it changes. It is derived from the content of the embedded assets, so it is identical across restarts and across replicas running the same binary, and changes only when an asset changes.
func CacheHandler ¶
CacheHandler adds ETag and Cache-Control headers to all asset responses for caching.
func CreateUsernameFromBech32 ¶
CreateUsernameFromBech32 creates a shortened version of the username if it's a valid bech32 address.
func NewDefaultChromaOptions ¶
func NewDefaultChromaOptions() []chromahtml.Option
NewDefaultChromaOptions returns the default Chroma options for syntax highlighting.
func NewDefaultGoldmarkOptions ¶
NewDefaultGoldmarkOptions returns the default Goldmark options for Markdown rendering.
func NewRouter ¶
NewRouter initializes the gnoweb router with the specified logger and configuration. It sets up all routes, static asset handling, and middleware.
func NoCacheHandler ¶
NoCacheHandler always invalidates cache for all responses.
func RedirectMiddleware ¶
func RedirectMiddleware(next http.Handler, meta StaticMetadata) http.Handler
RedirectMiddleware redirects all incoming requests whose path matches any of the Redirects to the corresponding URL, and renders a redirect view.
Types ¶
type AliasTarget ¶
type AppConfig ¶
type AppConfig struct {
// UnsafeHTML, if enabled, allows to use HTML in the markdown.
UnsafeHTML bool
// Analytics enables SimpleAnalytics.
Analytics bool
// AnalyticsHostname, when non-empty, is rendered as data-hostname on the
// SimpleAnalytics script tag to override the hostname SA reports.
// Set this when the site listens on a host SA would otherwise report
// incorrectly (for example a non-default port in local development).
AnalyticsHostname string
// NodeRemote is the remote address of the gno.land node.
NodeRemote string
// NodeRequestTimeout define how much time a request to the remote node should live before timeout.
NodeRequestTimeout time.Duration
// RemoteHelp is the remote of the gno.land node, as used in the help page.
RemoteHelp string
// AssetsPath is the base path to the gnoweb assets.
AssetsPath string
// NoAssetsCache disables assets caching.
NoAssetsCache bool
// ChainID is the chain id, used for constructing the help page.
ChainID string
// FaucetURL, if specified, will be the URL to which `/faucet` redirects.
FaucetURL string
// Domain is the domain used by the node.
Domain string
// Banner, if set, displays a site-wide banner above the header.
Banner components.BannerData
// RealmNotice, if set, is shown as the header's second row on pages of
// packages outside TrustedPaths.
RealmNotice components.RealmNotice
// TrustedPaths are namespaces or package paths ("gnoland", "gnoswap/v1/pool";
// no "/r/" or "/p/" prefix) whose pages never show RealmNotice.
TrustedPaths []string
// Aliases is a map of aliases pointing to another path or a static file.
Aliases map[string]AliasTarget
// RenderConfig defines the default configuration for rendering realms and source files.
RenderConfig RenderConfig
// StateRateLimitPerMinute caps the per-IP request rate against
// ?state* URLs (also used as the token-bucket burst). 0 ⇒ the
// HTTPHandler default (100/min). ADR-003 §Resource bounds.
StateRateLimitPerMinute int
// StateRateLimitTrustedProxies is the list of trusted reverse-proxy
// CIDRs (or bare IPs) for the per-IP rate limiter. X-Real-IP is honored
// only for connections originating inside one of these networks, and so
// is X-Forwarded-Host for the page origin (shareable links, AI prompts);
// empty (the default) trusts nothing, so untrusted deployments never
// trust attacker-controlled headers. ADR-003 §Resource bounds.
StateRateLimitTrustedProxies []string
// MaxConcurrentRPC caps in-flight outbound RPCs per gnoweb instance
// against the chain node. 0 ⇒ the rpcClient default (32). Tighten on
// chain nodes under pressure; relax when capacity allows. ADR-003
// §Resource bounds.
MaxConcurrentRPC int
}
AppConfig contains configuration for gnoweb.
func NewDefaultAppConfig ¶
func NewDefaultAppConfig() *AppConfig
NewDefaultAppConfig returns a new default AppConfig. The default sets 127.0.0.1:26657 as the remote node, "dev" as the chain ID, and sets up assets to be served on /public/.
type ClientAdapter ¶
type ClientAdapter interface {
// Realm fetch the content of a realm from a given path and
// return the data.
Realm(ctx context.Context, path, args string) ([]byte, error) // raw Render() bytes
// File fetches the source file from a given package path and
// filename. `height = 0` queries the latest block; positive values
// pin the query to that historical height.
File(ctx context.Context, path, filename string, height int64) ([]byte, FileMeta, error)
// ListFiles lists all source files available in a specified
// package path. `height = 0` queries the latest block; non-zero
// pins the listing to a historical block.
ListFiles(ctx context.Context, path string, height int64) ([]string, error)
// QueryPath list any path given the specified prefix
ListPaths(ctx context.Context, prefix string, limit int) ([]string, error)
// Doc retrieves the JSON doc suitable for printing from a
// specified package path. `height = 0` queries the latest block;
// any positive value pins the query to that historical height.
Doc(ctx context.Context, path string, height int64) (*doc.JSONDocumentation, error)
// StatePkg retrieves the root state tree for a package. `height
// = 0` queries the latest block; positive values are forwarded
// to ABCI as-is.
StatePkg(ctx context.Context, path string, height int64) ([]byte, error)
// StateObject retrieves the children of an object by ObjectID at
// the given block height (0 for latest).
StateObject(ctx context.Context, oid string, height int64) ([]byte, error)
// StateType retrieves a type definition by TypeID at the given
// block height (0 for latest).
StateType(ctx context.Context, typeId string, height int64) ([]byte, error)
// PackageMeta reports whether a path holds a live package, one parked
// awaiting an approver, or nothing. An absent path is a nil error with
// status "absent", not ErrClientPackageNotFound: the caller needs to tell
// "nothing here" from "the node did not answer".
PackageMeta(ctx context.Context, path string) (*vm.PackageMeta, error)
// Eval evaluates a read-only Gno expression (`vm/qeval`) and returns the
// raw result, one line per return value. pkgPath carries no domain, since
// the client adds its own, and no dot: the node splits pkgPath from expr on
// the first dot after the first slash. expr is the caller's to keep safe.
Eval(ctx context.Context, pkgPath, expr string) ([]byte, error)
}
func NewRPCClientAdapter ¶
func NewRPCClientAdapter(logger *slog.Logger, cli *client.RPCClient, domain string, maxConcurrentRPC int) ClientAdapter
NewRPCClientAdapter creates a new instance of rpcClient. maxConcurrentRPC ≤ 0 ⇒ defaultMaxConcurrentRPC; positive values cap in-flight outbound RPCs at that count.
type HTMLRenderer ¶
type HTMLRenderer struct {
// contains filtered or unexported fields
}
HTMLRenderer implements the Renderer interface for HTML output.
func NewHTMLRenderer ¶
func NewHTMLRenderer(logger *slog.Logger, cfg RenderConfig, client ClientAdapter) *HTMLRenderer
func (*HTMLRenderer) RenderDocumentation ¶
func (r *HTMLRenderer) RenderDocumentation(w io.Writer, src []byte) error
RenderDocumentation writes the HTML representation of doc-context markdown to w. HTML escaping is delegated to Goldmark.
func (*HTMLRenderer) RenderRealm ¶
func (r *HTMLRenderer) RenderRealm(w io.Writer, u *weburl.GnoURL, src []byte, ctx RealmRenderContext) (md.Toc, error)
RenderRealm renders a realm to HTML and returns a table of contents.
func (*HTMLRenderer) RenderSource ¶
RenderSource renders a source file into HTML with syntax highlighting based on its extension.
func (*HTMLRenderer) WriteChromaCSS ¶
func (r *HTMLRenderer) WriteChromaCSS(w io.Writer) error
WriteChromaCSS writes the CSS for syntax highlighting to the provided writer. It outputs the light theme by default and, if configured, the dark theme scoped under [data-theme="dark"] using CSS nesting.
type HTTPHandler ¶
type HTTPHandler struct {
Logger *slog.Logger
Static StaticMetadata
Client ClientAdapter
Renderer Renderer
Aliases map[string]AliasTarget
Timeout time.Duration
// State is the feature/state handler that owns every ?state* URL.
// Built in NewHTTPHandler so the wire-in dispatch hook is a single
// method call (ADR-003 §Architecture).
State *state.Handler
// contains filtered or unexported fields
}
HTTPHandler processes HTTP requests for gnoweb.
func NewHTTPHandler ¶
func NewHTTPHandler(logger *slog.Logger, cfg *HTTPHandlerConfig) (*HTTPHandler, error)
NewHTTPHandler creates a new HTTPHandler.
func (*HTTPHandler) Get ¶
func (h *HTTPHandler) Get(w http.ResponseWriter, r *http.Request)
Get processes a GET HTTP request and renders the appropriate page.
func (*HTTPHandler) GetDirectoryView ¶
func (h *HTTPHandler) GetDirectoryView(ctx context.Context, gnourl *weburl.GnoURL, indexData *components.IndexData) (int, *components.View)
GetDirectoryView renders the directory view for a package, showing available files.
func (*HTTPHandler) GetHelpView ¶
func (h *HTTPHandler) GetHelpView(ctx context.Context, gnourl *weburl.GnoURL) (int, *components.View)
func (*HTTPHandler) GetMarkdownRealmView ¶
func (h *HTTPHandler) GetMarkdownRealmView(ctx context.Context, gnourl *weburl.GnoURL, indexData *components.IndexData) (int, *components.View)
GetMarkdownRealmView serves a realm's raw Render() output as text/markdown. It falls back to the directory, paths-list, or error view when the realm cannot be fetched.
func (*HTTPHandler) GetMarkdownView ¶
func (h *HTTPHandler) GetMarkdownView(gnourl *weburl.GnoURL, mdContent string) (int, *components.View)
GetMarkdownView handles rendering of markdown files.
func (*HTTPHandler) GetOverviewView ¶
func (h *HTTPHandler) GetOverviewView(ctx context.Context, gnourl *weburl.GnoURL) (int, *components.View)
GetOverviewView renders the package overview landing page at /r/<pkg>$source. It fans out ListFiles, Doc, README and ListPaths in parallel, then builds a pure OverviewData that the template renders.
func (*HTTPHandler) GetPackageView ¶
func (h *HTTPHandler) GetPackageView(ctx context.Context, gnourl *weburl.GnoURL, indexData *components.IndexData, wantMarkdown bool) (int, *components.View)
GetPackageView handles package pages, including help, source, directory, and user views.
func (*HTTPHandler) GetPathsListView ¶
func (h *HTTPHandler) GetPathsListView(ctx context.Context, gnourl *weburl.GnoURL, indexData *components.IndexData) (int, *components.View)
func (*HTTPHandler) GetRealmView ¶
func (h *HTTPHandler) GetRealmView(ctx context.Context, gnourl *weburl.GnoURL, indexData *components.IndexData) (int, *components.View)
GetRealmView renders a realm page as HTML, or returns an error/status if not available.
func (*HTTPHandler) GetSourceView ¶
func (h *HTTPHandler) GetSourceView(ctx context.Context, gnourl *weburl.GnoURL) (int, *components.View)
func (*HTTPHandler) GetUserView ¶
func (h *HTTPHandler) GetUserView(ctx context.Context, gnourl *weburl.GnoURL) (int, *components.View)
GetUserView returns the user profile view for a given GnoURL. The segment may be either half of the pair: /u/<name> and /u/<address> serve the same page, and each prints the other half. A page is served only for an address, a namespace holding packages, a current name r/sys/users resolves to itself, or a path this gnoweb's own aliases publish; anything else would be a fabricated profile.
func (*HTTPHandler) Post ¶
func (h *HTTPHandler) Post(w http.ResponseWriter, r *http.Request)
Post processes a POST HTTP request.
func (*HTTPHandler) ServeHTTP ¶
func (h *HTTPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP handles HTTP requests and only allows GET requests.
func (*HTTPHandler) ServeHelpJSON ¶
func (h *HTTPHandler) ServeHelpJSON(ctx context.Context, gnourl *weburl.GnoURL, w http.ResponseWriter)
ServeHelpJSON serves the callable functions of a package as JSON.
func (*HTTPHandler) ServeSourceDownload ¶
func (h *HTTPHandler) ServeSourceDownload(ctx context.Context, gnourl *weburl.GnoURL, w http.ResponseWriter, r *http.Request)
ServeSourceDownload handles downloading a source file as plain text.
type HTTPHandlerConfig ¶
type HTTPHandlerConfig struct {
Meta StaticMetadata
ClientAdapter ClientAdapter
Renderer Renderer
Aliases map[string]AliasTarget
// TrustedPaths — see AppConfig field of the same name.
TrustedPaths []string
Timeout time.Duration
// StateRateLimitPerMinute caps per-IP requests against ?state* URLs.
// 0 ⇒ defaultStateRateLimitPerMinute. Also used as the token-bucket
// burst. ADR-003 §Resource bounds.
StateRateLimitPerMinute int
// StateRateLimitTrustedProxies — see AppConfig field of the same name.
// Also gates X-Forwarded-Host in requestOrigin.
StateRateLimitTrustedProxies []string
}
HTTPHandlerConfig configures an HTTPHandler.
type MockClient ¶
type MockClient struct {
Packages map[string]*MockPackage // path -> package
}
MockClient is a mock implementation of the ClientAdapter interface for testing.
func NewMockClient ¶
func NewMockClient(pkgs ...*MockPackage) *MockClient
NewMockClient creates a new MockClient from one or more MockPackages.
func (*MockClient) Doc ¶
func (m *MockClient) Doc(ctx context.Context, path string, _ int64) (*doc.JSONDocumentation, error)
Doc retrieves the JSON documentation for a specified package path.
func (*MockClient) File ¶
func (m *MockClient) File(ctx context.Context, pkgPath, fileName string, _ int64) ([]byte, FileMeta, error)
File fetches the source file from a given package path and filename, returning its content and metadata.
func (*MockClient) ListFiles ¶
ListFiles lists all source files available in a specified package path.
func (*MockClient) ListPaths ¶
ListPaths lists all package paths that match the specified prefix, up to the given limit.
func (*MockClient) PackageMeta ¶
func (m *MockClient) PackageMeta(ctx context.Context, path string) (*vm.PackageMeta, error)
PackageMeta reports the mock's view of a path. A package present in the mock is live; Pending is set from MockPackage.Pending so a test can stage the parked case, which is the one gnoweb has to render differently.
func (*MockClient) Realm ¶
Realm fetches the content of a realm from a given path and returns the data, or an error if not found or not declared.
func (*MockClient) StateObject ¶
StateObject returns mock object state data for testing.
type MockPackage ¶
type MockPackage struct {
Path string
Domain string
Files map[string]string // filename -> body
Functions []*doc.JSONFunc
// Inert stages a package that was submitted but not yet approved. The
// other methods still refuse it the way the chain does -- Render and the
// file queries read the live key space -- so a test gets the real shape.
Inert bool
// Pending stages a redeploy parked over a live package.
Pending bool
// Reason overrides the parked reason; defaults to awaiting-an-approver.
Reason string
}
MockPackage represents a mock package with files and function signatures for testing.
type RealmDirectory ¶
type RealmDirectory interface {
// Paths returns the realm (/r/) and package (/p/) paths known to the chain.
Paths(ctx context.Context) (realms, packages []string, err error)
}
RealmDirectory exposes realm and package paths for discovery. It is the seam behind which the source can evolve (live RPC today, a dedicated search index later) without touching callers.
type RealmRenderContext ¶
RealmRenderContext holds context information for rendering realms
type RenderConfig ¶
type RenderConfig struct {
ChromaStyle *chroma.Style
ChromaDarkStyle *chroma.Style
ChromaOptions []chromahtml.Option
GoldmarkOptions []goldmark.Option
}
RenderConfig holds configuration for syntax highlighting and Markdown rendering.
func NewDefaultRenderConfig ¶
func NewDefaultRenderConfig() (cfg RenderConfig)
NewDefaultRenderConfig returns a RenderConfig with default styles and options.
type Renderer ¶
type Renderer interface {
RenderRealm(w io.Writer, u *weburl.GnoURL, src []byte, ctx RealmRenderContext) (md.Toc, error)
RenderSource(w io.Writer, name string, src []byte) error
// RenderDocumentation renders doc-context markdown (from vm/qdoc) to HTML.
// Fenced and indented code blocks are wrapped in collapsible <details>
// with Chroma highlighting. HTML escaping is delegated to Goldmark.
RenderDocumentation(w io.Writer, src []byte) error
}
Renderer defines the interface for rendering realms, source files, and doc-context markdown (function/type/package documentation).
type StaticMetadata ¶
type StaticMetadata struct {
Domain string
AssetsPath string
ChromaPath string
RemoteHelp string
ChainId string
Analytics bool
AnalyticsHostname string
AssetsVersion string
Banner components.BannerData
RealmNotice components.RealmNotice
}
StaticMetadata holds static configuration for a web handler.
func (StaticMetadata) RedirectAnalytics ¶
func (s StaticMetadata) RedirectAnalytics() components.AnalyticsData
RedirectAnalytics builds the AnalyticsData for a redirect view. The redirect view is rendered outside IndexLayout, so the analytics fields must be populated explicitly rather than derived from HeadData.