gospa

package module
v0.1.41 Latest Latest
Warning

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

Go to latest
Published: Apr 27, 2026 License: Apache-2.0 Imports: 36 Imported by: 4

README

GoSPA (Alpha)

GoSPA Logo 1 GoSPA Logo 2

GoSPA (Go Spa and Go S-P-A are the only valid pronunciations) brings Svelte-like reactive primitives (Runes, Effects, Derived) to the Go ecosystem. It is a high-performance framework for building reactive SPAs with Templ, Fiber, file-based routing, and real-time state synchronization.

Table of Contents

Highlights

  • Native Reactivity - Rune, Derived, Effect primitives that work exactly like Svelte 5.
  • WebSocket Sync - Transparent client-server state synchronization with GZIP delta patching.
  • SFC System - Single File Components (.gospa) with scoped CSS and Go-based logic.
  • File-Based Routing - SvelteKit-style directory structure for .templ and .gospa files.
  • Hybrid Rendering - Mix SSR, SSG, ISR, and PPR on a per-page basis.
  • Type-Safe RPC - Call server functions directly from the client without boilerplate endpoints.
  • High Performance - Integrated go-json and optional MessagePack for minimal overhead.

Quick Start

0. Prerequisites
  • Go 1.26.0+ (matches go.mod; use a current stable toolchain)
  • Node.js Tooling: Bun is preferred for the client-side build process (zero-config JS bundling, CSS extraction). pnpm and npm are supported as fallbacks using esbuild, but Bun remains the recommended choice for maximum performance.
  • JWT_SECRET: Ensure this environment variable is set for production authentication contexts (when using the Auth plugin).
1. Install CLI
go install github.com/aydenstechdungeon/gospa/cmd/gospa@latest

or

go run github.com/aydenstechdungeon/gospa/cmd/gospa@latest
2. Scaffold & Run
gospa create myapp
cd myapp
go mod tidy
gospa doctor
gospa dev

or

go run github.com/aydenstechdungeon/gospa/cmd/gospa@latest create myapp
cd myapp
go mod tidy
go run github.com/aydenstechdungeon/gospa/cmd/gospa@latest doctor
go run github.com/aydenstechdungeon/gospa/cmd/gospa@latest dev

For local client/runtime tooling, Bun is strongly preferred. The GoSPA CLI provides fallbacks for pnpm and npm using esbuild, but Bun's integrated bundler is the authoritative development target.

3. A Simple SFC
// islands/Counter.gospa
<script lang="go">
  var count = $state(0)
  func increment() { count++ }
</script>

<template>
  <button on:click={increment}>
    Count is {count}
  </button>
</template>

<style>
  button { padding: 1rem; border-radius: 8px; }
</style>

GoSPA automatically compiles this to a reactive Templ component and a TypeScript hydration island.

Comparison

Feature GoSPA HTMX Alpine SvelteKit MoonZoon
Language Go HTML JS JS/TS Rust
Runtime ~15KB ~14KB ~15KB Varies ~27KB
App Speed Very High High High Very High Very High
DX Speed High Very High Very High High Moderate
Reactivity
WS Sync
File Routing
Type Safety

GoSPA Docs page (gospa.onrender.com - free hosting) Screenshot_20260415_184459-1

SvelteKit Docs page (svelte.dev/docs/kit/introduction) Screenshot_20260415_184329

Start from gospa.ProductionConfig() and tighten only what your app needs:

config := gospa.ProductionConfig()
config.AllowedOrigins = []string{"https://example.com"}
config.AppName = "myapp"

For prefork deployments, add external Storage and PubSub backends so state and realtime traffic stay consistent across workers.

Dynamic HTML (data-bind="html:*" and stream HTML chunks) is escaped by default in the runtime. If you need to render raw HTML, only use trusted server-controlled content.

Documentation

Explore the full GoSPA documentation:

Known Issues

  • CSP nonce mismatch can block runtime scripts
    • Symptom: Browser console shows CSP violations such as Refused to execute inline script or Refused to load the script.
    • Cause: custom CSP policy does not include 'nonce-{nonce}', or custom inline/module scripts are missing the per-request nonce.
    • Manual Developer Fix:
cspPolicy := "default-src 'self'; script-src 'self' 'nonce-{nonce}'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' wss: https:; frame-ancestors 'none'; base-uri 'self'; form-action 'self';"
app.Fiber.Use(gospafiber.SecurityHeadersMiddleware(cspPolicy))
<script type="module" nonce={ gospatempl.GetNonce(ctx) }>
  // custom client bootstrap code
</script>

Use the same nonce source (gospatempl.GetNonce(ctx)) for every custom inline or module script in your layout.

Accessibility (A11y)

Building accessible SPAs is a first-class citizen in GoSPA:

  • Live Announcer: Use GoSPA.announce("Message") to trigger screened reader notifications.
  • Focus Management: Built-in utilities for focus trapping and restoration during navigation.
  • ARIA Helpers: Lightweight helpers for managing ARIA attributes and roles reactively.

Contributing

We welcome contributions! Please see our Contributing Guide.

License

GoSPA is licensed under the Apache-2.0 license.

Documentation

Overview

Package gospa provides a modern SPA framework for Go with Fiber and Templ. It brings Svelte-like reactivity and state management to Go.

Index

Constants

View Source
const (
	// SerializationJSON uses standard JSON for state.
	SerializationJSON = "json"
	// SerializationMsgPack uses MessagePack for more compact state.
	SerializationMsgPack = "msgpack"
)

Serialization format constants.

View Source
const (
	RuntimeTierMicro = compiler.RuntimeTierMicro
	RuntimeTierCore  = compiler.RuntimeTierCore
	RuntimeTierFull  = compiler.RuntimeTierFull
)

RuntimeTier constants (pointing to compiler package)

View Source
const Version = "0.1.41"

Version is the current version of GoSPA.

Variables

View Source
var ErrJSONTooDeep = errors.New("json nesting exceeds maximum")

ErrJSONTooDeep is returned when remote action JSON exceeds [remoteJSONMaxNesting].

Functions

func Broadcast added in v0.1.30

func Broadcast(message interface{}) error

Broadcast is a global convenience function to broadcast a message to all clients.

Types

type App

type App struct {
	// Config is the application configuration.
	Config Config
	// Router is the file-based router.
	Router *routing.Router
	// Fiber is the underlying Fiber app.
	Fiber *fiberpkg.App
	// Hub is the WebSocket hub for real-time updates.
	Hub *fiber.WSHub
	// StateMap is the global state map.
	StateMap *state.StateMap
	// contains filtered or unexported fields
}

App is the main GoSPA application.

func New

func New(config Config) *App

New creates a new GoSPA application with the given configuration.

func (*App) Broadcast

func (a *App) Broadcast(message []byte)

Broadcast sends a message to all connected WebSocket clients.

func (*App) BroadcastState

func (a *App) BroadcastState(key string, value interface{}) error

BroadcastState broadcasts a state update to all connected clients.

func (*App) Computed added in v0.1.32

func (a *App) Computed(key string, deps []string, fn func(map[string]interface{}) interface{}) *App

Computed adds a computed state variable to the application's global state. It automatically updates when its dependencies change and broadcasts the result to all clients.

func (*App) Context added in v0.1.36

func (a *App) Context() context.Context

Context returns the application-level context.

func (*App) Delete

func (a *App) Delete(path string, handlers ...fiberpkg.Handler)

Delete registers a DELETE route with the specified path and handlers.

func (*App) Get

func (a *App) Get(path string, handlers ...fiberpkg.Handler)

Get registers a GET route with the specified path and handlers.

func (*App) GetFiber

func (a *App) GetFiber() *fiberpkg.App

GetFiber returns the underlying Fiber application instance.

func (*App) GetHub

func (a *App) GetHub() *fiber.WSHub

GetHub returns the application's WebSocket hub.

func (*App) GetPlugin added in v0.1.29

func (a *App) GetPlugin(name string) (plugin.Plugin, bool)

GetPlugin retrieves a registered plugin by name.

func (*App) GetRouter

func (a *App) GetRouter() *routing.Router

GetRouter returns the application's file-based router.

func (*App) GetTemplateFuncs added in v0.1.29

func (a *App) GetTemplateFuncs() map[string]any

GetTemplateFuncs returns template functions registered by plugins.

func (*App) Group

func (a *App) Group(prefix string, handlers ...fiberpkg.Handler) fiberpkg.Router

Group creates a new route group with the specified prefix and optional handlers.

func (*App) Invalidate added in v0.1.38

func (a *App) Invalidate(path string) int

Invalidate removes cache entries associated with the provided route path.

func (*App) InvalidateAll added in v0.1.41

func (a *App) InvalidateAll() int

InvalidateAll removes all in-memory route caches and clears index mappings. Returns number of entries removed across SSG and PPR caches.

func (*App) InvalidateKey added in v0.1.38

func (a *App) InvalidateKey(key string) int

InvalidateKey removes all cache entries indexed under the provided key.

func (*App) InvalidateTag added in v0.1.38

func (a *App) InvalidateTag(tag string) int

InvalidateTag removes all cache entries indexed under the provided tag.

func (*App) ListPlugins added in v0.1.29

func (a *App) ListPlugins() []plugin.Info

ListPlugins returns information about all registered plugins.

func (*App) Logger added in v0.1.24

func (a *App) Logger() *slog.Logger

Logger returns the application logger.

func (*App) Post

func (a *App) Post(path string, handlers ...fiberpkg.Handler)

Post registers a POST route with the specified path and handlers.

func (*App) Put

func (a *App) Put(path string, handlers ...fiberpkg.Handler)

Put registers a PUT route with the specified path and handlers.

func (*App) RegisterRoutes

func (a *App) RegisterRoutes() error

RegisterRoutes manually triggers route registration.

func (*App) Run

func (a *App) Run(addr string) error

Run starts the GoSPA application on the specified address.

func (*App) RunTLS

func (a *App) RunTLS(addr, certFile, keyFile string) error

RunTLS starts the GoSPA application on the specified address with TLS.

func (*App) Scan

func (a *App) Scan() error

Scan scans the routes directory for page and layout components.

func (*App) Shutdown

func (a *App) Shutdown() error

Shutdown gracefully shuts down the GoSPA application.

func (*App) Static

func (a *App) Static(prefix, root string)

Static registers a static directory with the specified prefix.

func (*App) UsePlugin added in v0.1.29

func (a *App) UsePlugin(p plugin.Plugin) error

UsePlugin registers a plugin with the application.

func (*App) UsePlugins added in v0.1.29

func (a *App) UsePlugins(plugins ...plugin.Plugin) error

UsePlugins registers multiple plugins with the application.

type Config

type Config struct {
	// RoutesDir is the directory containing route files.
	RoutesDir string
	// RoutesFS is the filesystem containing route files (optional). Takes precedence over RoutesDir if provided.
	RoutesFS fs.FS
	// DevMode enables development features.
	DevMode bool
	// RuntimeScript is the path to the client runtime script.
	RuntimeScript string
	// StaticDir is the directory for static files.
	StaticDir string
	// StaticPrefix is the URL prefix for static files.
	StaticPrefix string
	// AppName is the application name.
	AppName string
	// DefaultState is the initial state for new sessions.
	DefaultState map[string]interface{}
	// EnableWebSocket enables WebSocket support.
	EnableWebSocket bool
	// WebSocketPath is the WebSocket endpoint path.
	WebSocketPath string
	// WebSocketMiddleware allows injecting session/auth middleware before WebSocket upgrade.
	WebSocketMiddleware fiberpkg.Handler
	// Logger is the structured logger. Defaults to slog.Default().
	Logger *slog.Logger

	// Performance Options
	// CompressState enables gzip compression of outbound WebSocket state payloads.
	CompressState bool
	// StateDiffing enables delta-only "patch" WebSocket messages for state syncs.
	StateDiffing   bool
	CacheTemplates bool // Cache compiled templates (SSG only)
	// RuntimeTier specifies the complexity of the client runtime.
	RuntimeTier compiler.RuntimeTier
	// SimpleRuntimeSVGs allows SVG elements in the simple runtime sanitizer.
	SimpleRuntimeSVGs bool
	// DisableSanitization disables client-side HTML sanitization for SPA navigation.
	DisableSanitization bool
	// NotificationBufferSize sets the size of the state change notification queue (default 1024).
	NotificationBufferSize int

	// WebSocket Options — these values are passed directly to the client runtime's init() call.
	WSReconnectDelay time.Duration // Initial reconnect delay (default 1s)
	WSMaxReconnect   int           // Max reconnect attempts (default 10)
	WSHeartbeat      time.Duration // Heartbeat ping interval (default 30s)

	// WSMaxMessageSize limits the maximum payload size for WebSocket messages (default 64KB).
	WSMaxMessageSize int
	// WSConnRateLimit sets the refilling rate in connections per second for WebSocket upgrades (default 1.5).
	WSConnRateLimit float64
	// WSConnBurst sets the burst capacity for WebSocket connection upgrades (default 15.0).
	WSConnBurst float64

	// Hydration Options
	HydrationMode    string
	HydrationTimeout int // ms before force hydrate

	// Serialization Options
	SerializationFormat string
	StateSerializer     StateSerializerFunc
	StateDeserializer   StateDeserializerFunc

	// Routing Options
	DisableSPA bool // Disable SPA navigation completely

	// Rendering Strategy Defaults
	DefaultRenderStrategy  routing.RenderStrategy
	DefaultRevalidateAfter time.Duration

	// Remote Action Options
	MaxRequestBodySize                int              // Maximum allowed size for remote action request bodies
	RemotePrefix                      string           // Prefix for remote action endpoints (default "/_gospa/remote")
	RemoteActionMiddleware            fiberpkg.Handler // Optional middleware
	AllowUnauthenticatedRemoteActions bool             // Default false

	// Security Options
	AllowedOrigins        []string
	EnableCSRF            bool
	ContentSecurityPolicy string
	PublicOrigin          string
	// StrictProduction enforces hard startup validation for production deployments.
	StrictProduction bool
	// AllowInsecureWS allows unsecure ws:// connections even on https:// pages.
	// This is useful for development setups with reverse proxies that don't support wss://.
	AllowInsecureWS bool
	// AllowPortsWithInsecureWS allows unsecure ws:// connections for these specific ports, even on https:// pages.
	// This is useful for development setups with reverse proxies that don't support wss://.
	// Defaults to []int{3000}.
	AllowPortsWithInsecureWS []int
	SSGCacheMaxEntries       int           // Default: 500
	SSGCacheTTL              time.Duration // Default: 0 (no expiry)

	// Prefork enables Fiber's prefork mode.
	Prefork bool

	// Storage defines the external storage backend for sessions and state.
	Storage store.Storage

	// PubSub defines the messaging backend for multi-process broadcasting.
	PubSub store.PubSub

	// NavigationOptions configures optional client-side navigation behavior.
	NavigationOptions NavigationOptions

	// ISR Options
	// ISRSemaphoreLimit limits concurrent ISR background revalidations.
	ISRSemaphoreLimit int
	// ISRTimeout sets the maximum time for a background ISR revalidation.
	ISRTimeout time.Duration

	// IslandsBundlePath is the path to the islands bundle script.
	IslandsBundlePath string
	// PreloadCSS contains paths to CSS files that should be preloaded with high priority.
	PreloadCSS []string

	// BuildManifest is the loaded manifest.json (optional).
	BuildManifest map[string]string
	// ManifestPath is the path to manifest.json (default: "./manifest.json").
	ManifestPath string
}

Config holds the application configuration.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns the default configuration.

func MinimalConfig added in v0.1.30

func MinimalConfig() Config

MinimalConfig returns a smaller baseline.

func ProductionConfig added in v0.1.30

func ProductionConfig() Config

ProductionConfig returns an opinionated production-ready baseline.

func StrictProductionConfig added in v0.1.39

func StrictProductionConfig() Config

StrictProductionConfig returns a hardened production baseline that fails fast on missing security and runtime safety settings.

type ConfigOption added in v0.1.33

type ConfigOption func(*Config)

ConfigOption is a functional option for configuring the app.

func WithAppName added in v0.1.33

func WithAppName(name string) ConfigOption

WithAppName sets the application name.

func WithCacheTemplates added in v0.1.33

func WithCacheTemplates(enabled bool) ConfigOption

WithCacheTemplates enables template caching for SSG/ISR.

func WithDevMode added in v0.1.33

func WithDevMode(enabled bool) ConfigOption

WithDevMode enables development mode.

func WithLogger added in v0.1.33

func WithLogger(logger *slog.Logger) ConfigOption

WithLogger sets the logger.

func WithPort added in v0.1.33

func WithPort(_ string) ConfigOption

WithPort sets the server port. Note: This option is a no-op for the App; the port is passed directly to app.Run(addr) instead.

func WithRoutesDir added in v0.1.33

func WithRoutesDir(dir string) ConfigOption

WithRoutesDir sets the routes directory.

func WithStaticDir added in v0.1.33

func WithStaticDir(dir string) ConfigOption

WithStaticDir sets the static files directory.

func WithStaticPrefix added in v0.1.33

func WithStaticPrefix(prefix string) ConfigOption

WithStaticPrefix sets the URL prefix for static files.

func WithWebSocket added in v0.1.33

func WithWebSocket(enabled bool) ConfigOption

WithWebSocket enables or disables WebSocket support.

func WithWebSocketPath added in v0.1.33

func WithWebSocketPath(path string) ConfigOption

WithWebSocketPath sets the WebSocket endpoint path.

type NavigationIdleCallbackBatchUpdatesConfig struct {
	Enabled             *bool `json:"enabled,omitempty"`
	FallbackToMicrotask *bool `json:"fallbackToMicrotask,omitempty"`
}

NavigationIdleCallbackBatchUpdatesConfig configures idle callback batching

type NavigationLazyRuntimeInitializationConfig struct {
	Enabled       *bool `json:"enabled,omitempty"`
	DeferBindings *bool `json:"deferBindings,omitempty"`
}

NavigationLazyRuntimeInitializationConfig configures lazy runtime init

type NavigationOptions struct {
	SpeculativePrefetching         *NavigationSpeculativePrefetchingConfig    `json:"speculativePrefetching,omitempty"`
	URLParsingCache                *NavigationURLParsingCacheConfig           `json:"urlParsingCache,omitempty"`
	IdleCallbackBatchUpdates       *NavigationIdleCallbackBatchUpdatesConfig  `json:"idleCallbackBatchUpdates,omitempty"`
	LazyRuntimeInitialization      *NavigationLazyRuntimeInitializationConfig `json:"lazyRuntimeInitialization,omitempty"`
	ServiceWorkerNavigationCaching *NavigationServiceWorkerCachingConfig      `json:"serviceWorkerNavigationCaching,omitempty"`
	ViewTransitions                *NavigationViewTransitionsConfig           `json:"viewTransitions,omitempty"`
	ProgressBar                    *NavigationProgressBarConfig               `json:"progressBar,omitempty"`
}

NavigationOptions configures client-side navigation

type NavigationProgressBarConfig struct {
	Enabled *bool   `json:"enabled,omitempty"`
	Color   *string `json:"color,omitempty"`
	Height  *string `json:"height,omitempty"`
	Delay   *int    `json:"delay,omitempty"`
}

NavigationProgressBarConfig configures the navigation progress bar

type NavigationServiceWorkerCachingConfig struct {
	Enabled   *bool  `json:"enabled,omitempty"`
	CacheName string `json:"cacheName,omitempty"`
	Path      string `json:"path,omitempty"`
}

NavigationServiceWorkerCachingConfig configures service worker caching

type NavigationSpeculativePrefetchingConfig struct {
	Enabled        *bool `json:"enabled,omitempty"`
	TTL            *int  `json:"ttl,omitempty"`
	HoverDelay     *int  `json:"hoverDelay,omitempty"`
	ViewportMargin *int  `json:"viewportMargin,omitempty"`
}

NavigationSpeculativePrefetchingConfig configures speculative prefetching

type NavigationURLParsingCacheConfig struct {
	Enabled *bool `json:"enabled,omitempty"`
	MaxSize *int  `json:"maxSize,omitempty"`
	TTL     *int  `json:"ttl,omitempty"`
}

NavigationURLParsingCacheConfig configures the URL parsing cache

type NavigationViewTransitionsConfig struct {
	Enabled           *bool `json:"enabled,omitempty"`
	FallbackToClassic *bool `json:"fallbackToClassic,omitempty"`
}

NavigationViewTransitionsConfig configures view transitions

type StateDeserializerFunc

type StateDeserializerFunc func([]byte, interface{}) error

StateDeserializerFunc defines a function for state deserialization

type StateSerializerFunc

type StateSerializerFunc func(interface{}) ([]byte, error)

StateSerializerFunc defines a function for state serialization

Directories

Path Synopsis
Package cli provides command-line interface tools for GoSPA.
Package cli provides command-line interface tools for GoSPA.
cmd
gospa command
Package main provides the GoSPA CLI entry point.
Package main provides the GoSPA CLI entry point.
gospa-gen command
Package main provides a code generator for GoSPA route registration.
Package main provides a code generator for GoSPA route registration.
gospa-lsp command
Package main implements the GoSPA Language Server Protocol.
Package main implements the GoSPA Language Server Protocol.
Package compiler provides a compiler for GoSPA Single File Components (.gospa).
Package compiler provides a compiler for GoSPA Single File Components (.gospa).
sfc
Package sfc provides a parser for GoSPA Single File Components (.gospa).
Package sfc provides a parser for GoSPA Single File Components (.gospa).
Package component provides island architecture support for GoSPA.
Package component provides island architecture support for GoSPA.
starter
Package starter provides a library of reusable UI components for GoSPA applications
Package starter provides a library of reusable UI components for GoSPA applications
Package embed provides embedded static assets for the GoSPA framework.
Package embed provides embedded static assets for the GoSPA framework.
examples
form-remote module
Package fiber provides error overlay functionality for development.
Package fiber provides error overlay functionality for development.
Package plugin provides external plugin loading capabilities for GoSPA.
Package plugin provides external plugin loading capabilities for GoSPA.
auth
Package auth provides authentication for GoSPA projects.
Package auth provides authentication for GoSPA projects.
image
Package image provides image optimization for GoSPA projects.
Package image provides image optimization for GoSPA projects.
pathsafety
Package pathsafety provides safe path resolution helpers.
Package pathsafety provides safe path resolution helpers.
postcss
Package postcss provides a PostCSS plugin for GoSPA with Tailwind CSS v4 support.
Package postcss provides a PostCSS plugin for GoSPA with Tailwind CSS v4 support.
qrcode
Package qrcode provides QR code generation for GoSPA applications.
Package qrcode provides QR code generation for GoSPA applications.
seo
Package seo provides SEO optimization for GoSPA projects.
Package seo provides SEO optimization for GoSPA projects.
tailwind
Package tailwind provides a Tailwind CSS v4 plugin for GoSPA.
Package tailwind provides a Tailwind CSS v4 plugin for GoSPA.
validation
Package validation provides form validation for GoSPA projects.
Package validation provides form validation for GoSPA projects.
Package routing provides file-based routing similar to SvelteKit.
Package routing provides file-based routing similar to SvelteKit.
generator
Package generator provides code generation for automatic route registration.
Package generator provides code generation for automatic route registration.
kit
Package kit provides control-flow helpers for route load/action handlers.
Package kit provides control-flow helpers for route load/action handlers.
scripts
check-docs-sync command
Package main provides a script to audit documentation consistency between website routes and authoritative markdown files.
Package main provides a script to audit documentation consistency between website routes and authoritative markdown files.
codemod-sfc-events command
Package main rewrites legacy SFC event attribute syntaxes to `on:<event>=`.
Package main rewrites legacy SFC event attribute syntaxes to `on:<event>=`.
fix-docs-links command
Package main provides a script to fix legacy documentation links in markdown files.
Package main provides a script to fix legacy documentation links in markdown files.
tag command
Package main provides a script to bump version and create a new git tag.
Package main provides a script to bump version and create a new git tag.
validate-docs-routes command
Package main validates docs route and search index integrity.
Package main validates docs route and search index integrity.
validate-helper-promotion command
Package main validates that promoted helper APIs have docs, migration mapping, and tests references.
Package main validates that promoted helper APIs have docs, migration mapping, and tests references.
Package state provides batch update support for reactive primitives.
Package state provides batch update support for reactive primitives.
Package store provides pubsub state backends for GoSPA.
Package store provides pubsub state backends for GoSPA.
redis
Package redis provides a Redis-backed implementation of the store.Storage interface.
Package redis provides a Redis-backed implementation of the store.Storage interface.
Package templ provides Templ integration helpers for GoSPA reactive bindings.
Package templ provides Templ integration helpers for GoSPA reactive bindings.
Package main is the benchmark tool for GoSPA.
Package main is the benchmark tool for GoSPA.
website module

Jump to

Keyboard shortcuts

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