Documentation
¶
Index ¶
- Variables
- func CopyFileSys(filesys fs.FS, onHook OnHookFunc) (*memfs.FS, error)
- func InjectWebEnv(filesys fs.FS, conf any, ns string) (*memfs.FS, error)
- func NewSpaServer(filesys fs.FS, fn ...interface{}) (http.Handler, error)
- func NewStaticFilesHandler(filesys fs.FS, fn ...staticFilesHandlerFunc) (http.Handler, error)
- func WithBasePath(basePath string) staticFilesHandlerFunc
- func WithHtmlPageWhitelist(whitelist []string) spaServerOption
- func WithInjectWebEnv(env any, namespace string) staticFilesHandlerFunc
- func WithLogger(logger *slog.Logger) staticFilesHandlerFunc
- func WithMuxErrorHandler(handler func(int) http.Handler) staticFilesHandlerFunc
- func WithSpaFallbackPath(spaFallbackPath string) spaServerOption
- func WithTargets(targets []TargetConfig) spaServerOption
- type CSPContentNonceModifier
- type CSPContentNonceModifierOptions
- type CSPResponseHeaderModifier
- type Cache
- type CompositeModifier
- type FSFileChecker
- type FileChecker
- type FileContentModifier
- type FileModifier
- type FileModifierContext
- type FileModifierContextRequest
- type FileResponseHeaderModifier
- type HtmlScriptTagEnvModifier
- type MemoryCache
- type NonceElementDecider
- type OnHookFunc
- type SpaServerConfig
- type StaticFilesHandler
- type TargetConfig
Constants ¶
This section is empty.
Variables ¶
var ErrConfigTargetMissing = errors.New("spaserve: target config missing modifier or target file path")
var ErrCouldNotAppendScript = errors.New("spaserve: could not append script")
var ErrCouldNotAppendToIndex = errors.New("spaserve: could not append to index")
var ErrCouldNotFindHead = errors.New("spaserve: could not find <head> tag in HTML")
var ErrCouldNotMakeDir = errors.New("spaserve: could not make dir")
var ErrCouldNotMarshalConfig = errors.New("spaserve: could not marshal config")
injectWebEnv.InjectWindowVars
var ErrCouldNotMarshalEnv = errors.New("spaserve: could not marshal environment data to JSON")
Pre-defined errors for modifier operations.
var ErrCouldNotOpenFile = errors.New("spaserve: could not open file")
var ErrCouldNotParseHtml = errors.New("spaserve: could not parse target file as HTML")
var ErrCouldNotParseIndex = errors.New("spaserve: could not parse index")
injectWebEnv.appendToIndex
var ErrCouldNotParseNamespace = errors.New("spaserve: namespace must match regex: ^[a-zA-Z_][a-zA-Z0-9_]*$")
var ErrCouldNotReadFile = errors.New("spaserve: could not read file")
var ErrCouldNotRenderHtml = errors.New("spaserve: could not render modified HTML")
var ErrCouldNotWriteFile = errors.New("spaserve: could not write file")
var ErrCouldNotWriteIndex = errors.New("spaserve: could not write index")
var ErrFileNotFound = errors.New("spaserve: source file not found in fs")
var ErrInvalidBasePath = errors.New("spaserve: base path must start with '/'")
var ErrInvalidNamespace = errors.New("spaserve: HTML script namespace must be a valid JavaScript identifier")
var ErrMissingFS = errors.New("spaserve: configuration must include a source FS")
Pre-defined errors for configuration.
var ErrModifierFailed = errors.New("spaserve: file modification failed")
var ErrNoIndexFound = errors.New("spaserve: no index.html found")
var ErrNoNamespace = errors.New("spaserve: no namespace provided")
var ErrUnexpectedWalkError = errors.New("spaserve: unexpected walk error")
Functions ¶
func CopyFileSys ¶
func InjectWebEnv ¶
InjectWebEnv injects the web environment into the index.html file of the given file system.
- filesys: the file system to inject the web environment into
- conf: the web environment to inject, use json struct tags to drive the marshalling
- ns: the namespace to use for the web environment, must match regex: ^[a-zA-Z_][a-zA-Z0-9_]*$
func NewSpaServer ¶ added in v1.1.0
NewSpaServer creates a new http.Handler configured to serve a Single Page Application. It applies file modifications, handles SPA routing fallbacks, and serves static files.
func NewStaticFilesHandler ¶
StaticFilesHandler creates a static file server handler that serves files from the given fs.FS. It serves index.html for the root path and 404 for actual static file requests that don't exist.
- ctx: the context
- filesys: the file system to serve files from - this will be copied to a memfs
- fn: optional functions to configure the handler (e.g. WithLogger, WithBasePath, WithMuxErrorHandler, WithInjectWebEnv)
func WithBasePath ¶
func WithBasePath(basePath string) staticFilesHandlerFunc
WithBasePath sets the base path for the web server which will be trimmed from the request path before looking up files.
func WithHtmlPageWhitelist ¶ added in v1.1.0
func WithHtmlPageWhitelist(whitelist []string) spaServerOption
func WithInjectWebEnv ¶
WithInjectWebEnv injects the web environment into the static file server.
env: the web environment to inject, use json struct tags to drive the marshalling namespace: the namespace to use for the web environment, defaults to "APP_ENV"
func WithLogger ¶
WithLogger sets the logger for the static file server. Defaults to slog.Logger.
func WithMuxErrorHandler ¶
WithMuxErrorHandler sets custom error handlers for the static file server.
handler: a function that returns an http.Handler for the given status code
func WithSpaFallbackPath ¶ added in v1.1.0
func WithSpaFallbackPath(spaFallbackPath string) spaServerOption
func WithTargets ¶ added in v1.1.0
func WithTargets(targets []TargetConfig) spaServerOption
Types ¶
type CSPContentNonceModifier ¶ added in v1.2.0
type CSPContentNonceModifier struct {
// contains filtered or unexported fields
}
CSPContentNonceModifier allows injecting a Content-Security-Policy header
func NewCSPContentNonceModifier ¶ added in v1.2.0
func NewCSPContentNonceModifier(options CSPContentNonceModifierOptions) *CSPContentNonceModifier
NewCSPContentNonceModifier creates a FileContentModifier that applies CSP to a response.
func (*CSPContentNonceModifier) ModifyContent ¶ added in v1.2.0
func (csp *CSPContentNonceModifier) ModifyContent(context FileModifierContext, content []byte) ([]byte, error)
func (*CSPContentNonceModifier) ModifyResponseHeaders ¶ added in v1.2.0
func (csp *CSPContentNonceModifier) ModifyResponseHeaders(context FileModifierContext) (http.Header, error)
type CSPContentNonceModifierOptions ¶ added in v1.2.0
type CSPContentNonceModifierOptions struct {
// NonceElementDecider allows targeted inclusion/exclusion of particular nodes
NonceElementDecider NonceElementDecider
// NonceLength is the number of bytes underlying the actual nonce value
NonceLength int
// NonceStringReplacements is a list of strings that will be directly replaced with the nonce (unescaped) everywhere in the content
NonceStringReplacements []string
}
type CSPResponseHeaderModifier ¶ added in v1.2.0
type CSPResponseHeaderModifier struct {
// contains filtered or unexported fields
}
CSPResponseHeaderModifier allows injecting a Content-Security-Policy header
func NewCSPResponseHeaderModifier ¶ added in v1.2.0
func NewCSPResponseHeaderModifier(getCsp func(context FileModifierContext) (string, error)) *CSPResponseHeaderModifier
NewCSPResponseHeaderModifier creates a FileModifier that applies CSP to a response.
func (*CSPResponseHeaderModifier) ModifyResponseHeaders ¶ added in v1.2.0
func (csp *CSPResponseHeaderModifier) ModifyResponseHeaders(context FileModifierContext) (http.Header, error)
type Cache ¶ added in v1.1.0
Cache defines the interface for storing and retrieving processed file content. Implementations must be safe for concurrent use.
type CompositeModifier ¶ added in v1.1.0
type CompositeModifier struct {
// contains filtered or unexported fields
}
CompositeModifier applies a list of modifiers in sequence.
func NewCompositeModifier ¶ added in v1.1.0
func NewCompositeModifier(modifiers ...FileModifier) *CompositeModifier
NewCompositeModifier creates a modifier that chains others. It's recommended to provide a logger via config or it will default.
func (*CompositeModifier) ModifyContent ¶ added in v1.2.0
func (cm *CompositeModifier) ModifyContent(context FileModifierContext, content []byte) ([]byte, error)
func (*CompositeModifier) ModifyResponseHeaders ¶ added in v1.2.0
func (cm *CompositeModifier) ModifyResponseHeaders(context FileModifierContext) (http.Header, error)
type FSFileChecker ¶ added in v1.1.0
type FSFileChecker struct {
// contains filtered or unexported fields
}
FSFileChecker implements FileChecker using an underlying fs.FS.
func NewFSFileChecker ¶ added in v1.1.0
func NewFSFileChecker(fsys fs.FS) *FSFileChecker
NewFSFileChecker creates a FileChecker for the given filesystem.
func (*FSFileChecker) Exists ¶ added in v1.1.0
func (fc *FSFileChecker) Exists(name string) bool
Exists checks if a file exists and is not a directory. Note: This uses fs.Stat. If the fs.FS doesn't support Stat efficiently, trying fs.ReadFile might be an alternative, but Stat is preferred.
type FileChecker ¶ added in v1.1.0
type FileChecker interface {
// Exists checks if a file exists at the given path within its associated fs.FS.
Exists(name string) bool
}
FileChecker defines the interface for checking file existence.
type FileContentModifier ¶ added in v1.2.0
type FileContentModifier interface {
FileModifier // Embeds FileModifier
// ModifyContent takes the original file path and content,
// returns the modified content or an error.
ModifyContent(context FileModifierContext, content []byte) (modifiedContent []byte, err error)
}
FileContentModifier defines the interface for transforming file content.
type FileModifier ¶ added in v1.1.0
type FileModifier interface {
}
func CreateCompositeModifier ¶ added in v1.1.0
func CreateCompositeModifier(modifiers ...FileModifier) FileModifier
Helper function to easily create a composite modifier.
func CreateHtmlScriptTagEnvModifier ¶ added in v1.1.0
func CreateHtmlScriptTagEnvModifier(env any, namespace string) (FileModifier, error)
Helper function to easily create the common HTML script modifier. Returns the modifier and nil error if successful, otherwise nil modifier and error.
type FileModifierContext ¶ added in v1.2.0
type FileModifierContext struct {
Request FileModifierContextRequest
Scratch map[string]any
}
type FileModifierContextRequest ¶ added in v1.2.0
type FileResponseHeaderModifier ¶ added in v1.2.0
type FileResponseHeaderModifier interface {
FileModifier // Embeds FileModifier
// ModifyResponseHeaders returns a map of HTTP headers that should be applied to the response
// for the given path and its (potentially modified) content.
ModifyResponseHeaders(context FileModifierContext) (http.Header, error)
}
FileResponseHeaderModifier allows HTTP headers to be set for the response of a file.
type HtmlScriptTagEnvModifier ¶ added in v1.1.0
type HtmlScriptTagEnvModifier struct {
Env any // The data structure to marshal into JSON.
Namespace string // The JavaScript global variable name (e.g., "APP_CONFIG").
}
HtmlScriptTagEnvModifier injects a JavaScript variable assignment into the <head> of an HTML document.
func NewHtmlScriptTagEnvModifier ¶ added in v1.1.0
func NewHtmlScriptTagEnvModifier(env any, namespace string) (*HtmlScriptTagEnvModifier, error)
NewHtmlScriptTagEnvModifier creates a FileModifier that injects env data into an HTML file. 'env' will be JSON marshaled. 'namespace' must be a valid JS identifier.
func (*HtmlScriptTagEnvModifier) ModifyContent ¶ added in v1.2.0
func (hsm *HtmlScriptTagEnvModifier) ModifyContent(context FileModifierContext, originalContent []byte) ([]byte, error)
type MemoryCache ¶ added in v1.1.0
type MemoryCache[T any] struct { // contains filtered or unexported fields }
MemoryCache provides a thread-safe in-memory cache using sync.Map.
func NewMemoryCache ¶ added in v1.1.0
func NewMemoryCache[T any]() *MemoryCache[T]
NewMemoryCache creates a new empty MemoryCache.
func (*MemoryCache[T]) Get ¶ added in v1.1.0
func (mc *MemoryCache[T]) Get(key string) (data *T, found bool)
Get retrieves an item from the cache.
func (*MemoryCache[T]) Set ¶ added in v1.1.0
func (mc *MemoryCache[T]) Set(key string, data *T)
Set adds or updates an item in the cache.
type NonceElementDecider ¶ added in v1.2.0
type OnHookFunc ¶
OnHookFunc is a function that can be used to modify the data of a file before it is written to the memfs. The function should return the modified data and an error if one occurred.
type SpaServerConfig ¶ added in v1.1.0
type SpaServerConfig struct {
// The source filesystem containing the static assets. (Required)
FS fs.FS
// List of file modification rules. (Optional)
Targets []TargetConfig
// List of valid HTML files
HtmlPageWhitelist []string
// The path (relative to FS root) to serve when a requested path
// doesn't correspond to an existing file and appears to be an SPA route
// (i.e., doesn't have a file extension). Defaults to "index.html".
SpaFallbackPath string
// The base path prefix for server requests (e.g., "/app"). Requests must
// start with this path. The prefix is stripped before looking up files
// in the FS. Defaults to "/". Must start and end with '/'.
BasePath string
// Optional logger. Defaults to slog.Default().
Logger *slog.Logger
// Optional custom HTTP error handler function. It's given the status code
// and should write the error response. Defaults to a basic http.Error response.
MuxErrorHandler func(statusCode int, w http.ResponseWriter, r *http.Request)
}
SpaServerConfig holds the overall configuration for the SPA server handler.
type StaticFilesHandler ¶
type StaticFilesHandler struct {
// contains filtered or unexported fields
}
func (*StaticFilesHandler) ServeHTTP ¶
func (h *StaticFilesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
type TargetConfig ¶ added in v1.1.0
type TargetConfig struct {
// Path within the fs.FS to target for modification (e.g., "index.html", "assets/config.js").
// This path should be relative to the FS root and use forward slashes.
TargetFile string
// The modifier implementation to apply to this file.
Modifier FileModifier
// If true, the result of Modifier.Modify will be stored in the cache.
// Set to false if the modification is dynamic or should always re-run.
CacheResult bool
}
TargetConfig defines how a specific file path should be handled.