liveflux

package module
v0.26.0 Latest Latest
Warning

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

Go to latest
Published: May 16, 2026 License: AGPL-3.0 Imports: 19 Imported by: 0

README

Liveflux — Server-driven UI Components for Go

Tests Status Go Report Card PkgGoDev

Liveflux is a server-driven component system for Go. It uses github.com/dracory/hb for HTML generation but works with any server or frontend—the transport is plain HTML over HTTP or WebSocket.

Highlights

  • Server-first rendering: Components run on the server, returning HTML for any client.
  • Lightweight runtime: Bundled JS handles mounts, actions, redirects, and optional WebSockets.
  • Composable state: Per-component state persists via pluggable stores (MemoryStore by default).
  • Event-driven UX: Dispatch server events and respond via Go or JavaScript listeners.
  • Transport flexibility: Use standard HTTP POST/GET or upgrade seamlessly to WebSockets.
  • Declarative triggers: Bind DOM events to actions with data-flux-trigger for live search, auto-save, and validation without custom JavaScript.
  • Form-less submission: Collect fields from anywhere in the DOM using data-flux-include and data-flux-exclude.
  • Targeted updates: Update only specific DOM regions instead of full component re-renders for better performance.

Quick start

  • Install: go get github.com/dracory/liveflux
  • Register a component and embed liveflux.Base
  • Mount the handler at /liveflux
  • Include liveflux.Script() and use liveflux.PlaceholderByKind() or liveflux.SSR()
Serving the client script endpoint

liveflux.NewHandler also responds to GET requests by returning the embedded client runtime. Mount the handler where you want to serve both HTML updates and the script:

mux := http.NewServeMux()
handler := liveflux.NewHandler(nil)
mux.Handle("/liveflux", handler)

Then include the JS by reference from your layout:

<script src="/liveflux" defer></script>

If you prefer to inline the script instead, call liveflux.Script() (see docs/getting_started.md).

Examples

Full walkthroughs live in docs/getting_started.md and docs/components.md.

Counter (two instances side-by-side)

Run from repo root:

go run ./examples/counter
# or, with Task
task examples:counter:run

Screenshot:

Counter Example

Source: examples/counter/

Tree (nested list with modal add/edit)

Run from repo root:

go run ./examples/tree
# or, with Task
task examples:tree:run

Screenshots:

Source: examples/tree/

Events (server-dispatched listeners)

Run from repo root:

go run ./examples/events
# or, with Task
task examples:events:run

What it shows:

  • Post creation dispatches a post-created event with metadata.
  • PostList automatically registers OnPostCreated and updates its state.
  • Client runtime mirrors events to JS via $wire.on() or liveflux.on().

Source: examples/events/

CRUD (modals + list with events)

Run from repo root:

go run ./examples/crud
# or, with Task
task examples:crud:run

Screenshots:

User List

Create User

Update User

Delete User

Source: examples/crud/

WebSocket Counter (two instances)

Run from repo root:

go run ./examples/websocket
# or, with Task
task examples:websocket:run

Screenshot:

WebSocket Counter Example

Source: examples/websocket/

Form-less Submission (flexible field collection)

Run from repo root:

go run ./examples/formless
# or, with Task
task examples:formless:run

What it shows:

  • Shared filters across multiple components using data-flux-include.
  • Multi-step forms collecting fields from multiple DOM sections.
  • Excluding sensitive fields with data-flux-exclude.
  • Progressive enhancement without requiring <form> wrappers.

Source: examples/formless/

Targeted Updates (selective DOM updates)

Run from repo root:

go run ./examples/target
# or, with Task
task examples:target:run

What it shows:

  • Implementing TargetRenderer to return only changed fragments.
  • Marking targets dirty with MarkTargetDirty().
  • Independent updates for multiple components and document-scoped elements (see Targeted updates guide).
  • 80-95% reduction in network payload for large components.
  • Preserving client state (focus, scroll, media playback).

Source: examples/target/

Triggers (live search with debouncing)

Run from repo root:

go run ./examples/triggers
# or, with Task
task examples:triggers:run

What it shows:

  • Declarative event handling with data-flux-trigger.
  • Live search with automatic debouncing using keyup changed delay:300ms.
  • No custom JavaScript required for interactive features.
  • Built-in change detection prevents redundant requests.

Source: examples/triggers/

Documentation

Start with the focused guides under docs/:

Package API

  • Components: ComponentInterface, Base, and registry helpers (Register, RegisterByKind, New). See docs/components.md and docs/architecture.md.
  • Handlers: HTTP + WebSocket entry points (NewHandler, NewHandlerWS, NewWebSocketHandler). See docs/handler_and_transport.md and docs/websocket.md.
  • SSR helpers: SSR, SSRHTML for first render hydration. See docs/ssr.md.
  • Stores: Store interface with default MemoryStore. See docs/state_management.md for custom implementations.

Production notes

  • Validate inputs in Handle and sanitize client data.
  • Use session-backed or distributed stores in multi-instance deployments.
  • Configure CSRF and allowed origins for HTTP/WebSocket endpoints.
  • Decompose large views into smaller Liveflux components.

License

This project is dual-licensed under the following terms:

  • For non-commercial use, you may choose either the GNU Affero General Public License v3.0 (AGPLv3) or a separate commercial license (see below). You can find a copy of the AGPLv3 at: https://www.gnu.org/licenses/agpl-3.0.txt

  • For commercial use, a separate commercial license is required. Commercial licenses are available for various use cases. Please contact me via my contact page to obtain a commercial license.

Similar projects

Documentation

Index

Constants

View Source
const (
	DataFluxAction        = "data-flux-action"
	DataFluxDispatchTo    = "data-flux-dispatch-to"
	DataFluxComponentKind = "data-flux-component-kind"
	DataFluxComponentID   = "data-flux-component-id"
	DataFluxExclude       = "data-flux-exclude"
	DataFluxInclude       = "data-flux-include"
	DataFluxIndicator     = "data-flux-indicator"
	DataFluxSelect        = "data-flux-select"
	DataFluxMount         = "data-flux-mount"
	DataFluxParam         = "data-flux-param"
	DataFluxSubmit        = "data-flux-submit"
	DataFluxWS            = "data-flux-ws"
	DataFluxWSURL         = "data-flux-ws-url"
	DefaultEndpoint       = "/liveflux"

	// used by external controls to target liveflux components
	DataFluxTargetKind = "data-flux-target-kind"
	DataFluxTargetID   = "data-flux-target-id"
)
View Source
const (
	FormComponentKind = "liveflux_component_kind"
	FormComponentID   = "liveflux_component_id"
	FormAction        = "liveflux_action"
)

Form field names used by the handler

View Source
const (
	RedirectHeader      = "X-Liveflux-Redirect"
	RedirectAfterHeader = "X-Liveflux-Redirect-After"
	EventsHeader        = "X-Liveflux-Events"
)

Response header names for client-side redirect handling and events

View Source
const (
	SwapReplace     = "replace"     // Replace the target element entirely
	SwapInner       = "inner"       // Replace the target's innerHTML
	SwapBeforeBegin = "beforebegin" // Insert before the target element
	SwapAfterBegin  = "afterbegin"  // Insert as first child of target
	SwapBeforeEnd   = "beforeend"   // Insert as last child of target (append)
	SwapAfterEnd    = "afterend"    // Insert after the target element
)

SwapMode constants for common swap operations

View Source
const (
	TargetScopeComponent = "component" // Resolve selector within component root (default)
	TargetScopeDocument  = "document"  // Resolve selector within the entire document
)

Target scope constants

Variables

View Source
var (
	// DefaultWebSocketUpgrader is the default upgrader for WebSocket connections.
	DefaultWebSocketUpgrader = websocket.Upgrader{
		ReadBufferSize:  1024,
		WriteBufferSize: 1024,

		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}
)

Functions

func BindEventToActionScript added in v0.25.0

func BindEventToActionScript(componentKind string, componentID string, eventName string, actionName string) hb.TagInterface

func BuildTargetResponse added in v0.15.0

func BuildTargetResponse(fragments []TargetFragment, fullRender string, comp ComponentInterface) string

BuildTargetResponse constructs an HTML response containing template elements for each fragment, plus an optional full component render as fallback.

func DefaultKindFromType added in v0.17.0

func DefaultKindFromType(c ComponentInterface) string

DefaultKindFromType derives a sensible default kind from a component's Go type. Rules: - Use the package name and kebab-cased struct name: "<pkg>.<type-kebab>" - If struct name matches package name (case-insensitive), just use the package name. Examples:

package counter, type Counter -> "counter"
package users, type UserList -> "users.user-list"

func ExcludeSelectors added in v0.12.0

func ExcludeSelectors(selectors ...string) string

ExcludeSelectors joins CSS selectors with commas for use with data-flux-exclude. This is a convenience helper for building the attribute value.

Example:

hb.Button().
  Attr(liveflux.DataFluxAction, "update").
  Attr(liveflux.DataFluxInclude, "#user-form").
  Attr(liveflux.DataFluxExclude, liveflux.ExcludeSelectors(".sensitive", ".internal")).
  Text("Update Profile")

func IncludeSelectors added in v0.12.0

func IncludeSelectors(selectors ...string) string

IncludeSelectors joins CSS selectors with commas for use with data-flux-include. This is a convenience helper for building the attribute value.

Example:

hb.Button().
  Attr(liveflux.DataFluxAction, "save").
  Attr(liveflux.DataFluxInclude, liveflux.IncludeSelectors("#extra-fields", ".shared-inputs")).
  Text("Save")

func JS

func JS(opts ...ClientOptions) string

JS returns the Liveflux client script. Optional ClientOptions configure the client (merged into window.liveflux before the runtime). Include once per page.

func KindOf added in v0.17.0

func KindOf(c ComponentInterface) string

KindOf returns the registered kind for the given component instance's type. Returns empty string if not found.

func NewHandlerEx added in v0.6.0

func NewHandlerEx(store Store, enableWebSocket bool) http.Handler

NewHandlerEx returns a handler depending on the enableWebSocket flag:

  • If enableWebSocket is true, it returns a handler that can upgrade to WebSocket and also handle regular HTTP (POST/GET) requests.
  • If false, it returns the standard HTTP-only handler.

This allows simple usage like: mux.Handle("/liveflux", liveflux.NewHandlerEx(nil, true))

func NewHandlerWS added in v0.6.0

func NewHandlerWS(store Store) http.Handler

NewHandlerWS returns a handler that supports both WebSocket upgrades and regular HTTP POST/GET. It is a convenience wrapper around NewWebSocketHandler(store) so developers don't have to think about which transport is being used.

func NewID

func NewID() string

NewID generates a URL-safe random ID string.

func Placeholder

func Placeholder(c ComponentInterface, params ...map[string]string) hb.TagInterface

PlaceholderFor uses a Component's kind to build a placeholder. Note: the instance ID is not available until after the first mount.

func PlaceholderByKind added in v0.17.0

func PlaceholderByKind(kind string, params ...map[string]string) hb.TagInterface

PlaceholderByKind returns a generic mount placeholder for a component by kind. The inline JS client should look for elements with data-flux-mount="1" and use the data-flux-component-kind value to POST an initial mount.

func Register

func Register(c ComponentInterface) error

Register registers a component constructor using the component's GetKind() as the registry kind. Component must implement GetKind() (enforced by interface).

func RegisterByKind added in v0.17.0

func RegisterByKind(kind string, c ComponentInterface) error

RegisterByKind makes a component constructor available by kind. Typically called from init() in the component's package.

func RegisterEventListeners added in v0.9.0

func RegisterEventListeners(component ComponentInterface, dispatcher *EventDispatcher)

RegisterEventListeners automatically registers event listeners based on method naming.

func SSR

func SSR(c ComponentInterface, params ...map[string]string) hb.TagInterface

SSR mounts the component on the server and returns its rendered HB tag. Useful for SEO/static-first rendering while still enabling JS-driven updates after the client runtime hydrates.

func SSRHTML

func SSRHTML(c ComponentInterface, params ...map[string]string) string

SSRHTML mounts and renders the component, returning HTML as string.

func Script

func Script(opts ...ClientOptions) hb.TagInterface

Script returns an hb.Script tag containing the client JS with optional configuration.

func TargetAttr added in v0.15.0

func TargetAttr(attr, value string) string

TargetAttr builds a selector for elements with a specific attribute value.

func TargetClass added in v0.15.0

func TargetClass(class string) string

TargetClass builds a selector for elements with a specific class.

func TargetID added in v0.15.0

func TargetID(id string) string

TargetID builds a selector for an element with a specific ID.

func TargetSelector added in v0.15.0

func TargetSelector(selector string) string

TargetSelector is a helper to build common CSS selectors. Examples:

  • TargetSelector("#cart-total") -> "#cart-total"
  • TargetSelector(".line-items") -> ".line-items"
  • TargetSelector("[data-id='42']") -> "[data-id='42']"

Types

type Base

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

Base provides minimal implementation for kind and ID handling and is exported so downstream packages can embed `liveflux.Base` for shared behavior.

func (*Base) ClearDirtyTargets added in v0.15.0

func (b *Base) ClearDirtyTargets()

ClearDirtyTargets clears all dirty target markers.

func (*Base) Dispatch added in v0.9.0

func (b *Base) Dispatch(eventName string, data ...map[string]any)

Dispatch queues an event to be sent to the client and other components. Usage: component.Dispatch("post-created", map[string]any{"id": 1, "title": "My Post"})

func (*Base) DispatchSelf added in v0.9.0

func (b *Base) DispatchSelf(eventName string, data ...map[string]any)

DispatchSelf queues an event to be sent only to the current component. Usage: component.DispatchSelf("post-created", map[string]any{"id": 1, "title": "My Post"})

func (*Base) DispatchToKind added in v0.17.0

func (b *Base) DispatchToKind(componentKind string, eventName string, data ...map[string]any)

DispatchToKind queues an event to be sent to a specific component kind. Usage: component.DispatchToKind("users.list", "post-created", map[string]any{"id": 1, "title": "My Post"})

func (*Base) DispatchToKindAndID added in v0.17.0

func (b *Base) DispatchToKindAndID(componentKind string, componentID string, eventName string, data ...map[string]any)

DispatchToKindAndID queues an event to be sent to a specific component kind and ID. Usage: component.DispatchToKindAndID("users.list", someID, "post-updated", map[string]any{"id": 1})

func (*Base) GetDirtyTargets added in v0.15.0

func (b *Base) GetDirtyTargets() map[string]bool

GetDirtyTargets returns a copy of the dirty targets map.

func (*Base) GetEventDispatcher added in v0.9.0

func (b *Base) GetEventDispatcher() *EventDispatcher

GetEventDispatcher returns the component's event dispatcher, creating it if needed.

func (*Base) GetID

func (b *Base) GetID() string

GetID returns the component's instance ID.

func (*Base) GetKind added in v0.17.0

func (b *Base) GetKind() string

GetKind returns the component's kind.

func (*Base) IsDirty added in v0.15.0

func (b *Base) IsDirty(selector string) bool

IsDirty checks if a specific target has been marked dirty.

func (*Base) MarkTargetDirty added in v0.15.0

func (b *Base) MarkTargetDirty(selector string)

MarkTargetDirty marks a specific DOM target as needing an update. This is used in conjunction with TargetRenderer to track which fragments changed. Usage: component.MarkTargetDirty("#cart-total")

func (*Base) Redirect

func (b *Base) Redirect(url string, delaySeconds ...int)

Redirect requests a client-side redirect with an optional delay in seconds. If delaySeconds is not provided, 0 is used (immediate).

func (*Base) Root

func (b *Base) Root(content hb.TagInterface) hb.TagInterface

Root returns the standard Liveflux component root element with required attributes and hidden fields, and appends the provided content as a child. This avoids repeating boilerplate in every component's Render method.

func (*Base) SetID

func (b *Base) SetID(id string)

SetID sets the component's instance ID.

func (*Base) SetKind added in v0.17.0

func (b *Base) SetKind(kind string)

SetKind sets the component's kind only once (no-op if already set or empty input).

func (*Base) SetRedirect

func (b *Base) SetRedirect(url string)

SetRedirect requests an immediate client-side redirect to the given URL on next response.

func (*Base) SetRedirectDelaySeconds

func (b *Base) SetRedirectDelaySeconds(seconds int)

SetRedirectDelay sets an optional delay (seconds) for a previously-set redirect. Negative values are treated as zero.

func (*Base) TakeRedirect

func (b *Base) TakeRedirect() string

TakeRedirect returns the pending redirect URL (if any) and clears it.

func (*Base) TakeRedirectDelaySeconds

func (b *Base) TakeRedirectDelaySeconds() int

TakeRedirectDelaySeconds returns the pending redirect delay seconds (if any) and resets it.

type ClientOptions

type ClientOptions struct {
	Endpoint    string            `json:"endpoint,omitempty"`
	Headers     map[string]string `json:"headers,omitempty"`
	Credentials string            `json:"credentials,omitempty"` // e.g., "same-origin", "include"
	TimeoutMs   int               `json:"timeoutMs,omitempty"`   // request timeout; 0 = no timeout
	// Names of response headers used for client-side redirects
	RedirectHeader      string `json:"redirectHeader,omitempty"`
	RedirectAfterHeader string `json:"redirectAfterHeader,omitempty"`

	// WebSocket integration
	UseWebSocket bool   `json:"useWebSocket,omitempty"`
	WebSocketURL string `json:"wsEndpoint,omitempty"`
}

ClientOptions configures the embedded client. All fields are optional; zero values are ignored.

type ComponentInterface

type ComponentInterface interface {
	// GetKind returns the stable routing key (TYPE identifier) used by the client
	// and registry to select which component to construct/route to.
	// Component authors MUST implement this.
	GetKind() string

	// SetKind sets the component's kind (TYPE identifier). The framework sets this
	// once during construction in the registry. Implementations should treat kind
	// as immutable; Base enforces set-once semantics.
	SetKind(kind string)

	// GetID returns the instance ID (per-mount INSTANCE identifier).
	GetID() string

	// SetID sets the instance ID (per-mount INSTANCE identifier). This is called by
	// the framework during mount (see handler.go).
	SetID(id string)

	Mount(ctx context.Context, params map[string]string) error
	Handle(ctx context.Context, action string, data url.Values) error
	Render(ctx context.Context) hb.TagInterface
}

ComponentInterface defines the contract for a server-driven UI component.

Lifecycle: - New(kind) via registry (framework sets the component's kind via SetKind(kind)) - SetID(...) during first mount (framework assigns a per-instance ID) - Mount(ctx, params) on first initialization - Handle(ctx, action, form) on user actions - Render(ctx) returns the current HTML (hb.Tag)

Kind is assigned by the framework when the instance is created from the registry. ID and SetID are used by the framework to track component instances and are assigned on mount. Mount should initialize default state. Handle should mutate state based on actions. Render must be deterministic based on current state.

Example usage:

type Counter struct { liveflux.Base; Count int }
func (c *Counter) Mount(ctx context.Context, params map[string]string) error { c.Count = 0; return nil }
func (c *Counter) Handle(ctx context.Context, action string, data url.Values) error { if action=="inc" { c.Count++ }; return nil }
func (c *Counter) Render(ctx context.Context) hb.TagInterface { return hb.Div().Textf("%d", c.Count) }
liveflux.RegisterByKind("counter", func() liveflux.ComponentInterface { return &Counter{} })

See handler.go for the HTTP entry point.

func New

New creates a new component instance by using the type of the provided example. The example is not used beyond its type information. The registry is consulted via KindOf(example) and, if empty, DefaultKindFromType(example). This avoids passing string kinds at call sites.

type Event added in v0.9.0

type Event struct {
	Name string                 `json:"name"`
	Data map[string]interface{} `json:"data,omitempty"`
}

Event represents a dispatched event with a name and optional data payload.

type EventAware added in v0.9.0

type EventAware interface {
	GetEventDispatcher() *EventDispatcher
}

EventAware is an interface for components that support event dispatching.

type EventDispatcher added in v0.9.0

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

EventDispatcher manages event dispatching and listening within components.

func NewEventDispatcher added in v0.9.0

func NewEventDispatcher() *EventDispatcher

NewEventDispatcher creates a new event dispatcher.

func (*EventDispatcher) Dispatch added in v0.9.0

func (ed *EventDispatcher) Dispatch(name string, data ...map[string]interface{})

Dispatch queues an event to be sent to the client and other components. Usage: dispatcher.Dispatch("post-created", map[string]interface{}{"title": "My Post"})

func (*EventDispatcher) DispatchToKind added in v0.17.0

func (ed *EventDispatcher) DispatchToKind(componentKind string, eventName string, data ...map[string]any)

DispatchToKind queues an event to be sent to a specific component kind. This is handled by the client-side runtime which filters events by kind.

func (*EventDispatcher) DispatchToKindAndID added in v0.17.0

func (ed *EventDispatcher) DispatchToKindAndID(componentKind string, componentID string, eventName string, data ...map[string]any)

DispatchToKindAndID queues an event to be sent to a specific component kind and ID. The client-side runtime filters events by both kind and component ID.

func (*EventDispatcher) EventsJSON added in v0.9.0

func (ed *EventDispatcher) EventsJSON() string

EventsJSON returns the queued events as a JSON string.

func (*EventDispatcher) HasEvents added in v0.9.0

func (ed *EventDispatcher) HasEvents() bool

HasEvents returns true if there are queued events.

func (*EventDispatcher) On added in v0.9.0

func (ed *EventDispatcher) On(name string, handler EventListener)

On registers an event listener for the given event name. Multiple listeners can be registered for the same event.

func (*EventDispatcher) TakeEvents added in v0.9.0

func (ed *EventDispatcher) TakeEvents() []Event

TakeEvents returns all queued events and clears the queue.

func (*EventDispatcher) TriggerLocal added in v0.9.0

func (ed *EventDispatcher) TriggerLocal(ctx context.Context, event Event) error

TriggerLocal triggers event listeners registered on this dispatcher (server-side only). This allows components to respond to events during the same request cycle.

type EventListener added in v0.9.0

type EventListener func(ctx context.Context, event Event) error

EventListener is a function that handles an event.

type Handler

type Handler struct {
	Store Store
}

Handler is an http.Handler that mounts/handles components and returns HTML.

Usage patterns (client-side): - To mount: POST with form field `liveflux_component_kind` (kind) (and optional params) -> returns initial HTML - To act: POST with `liveflux_component_kind` (kind), `liveflux_component_id`, `liveflux_action` (+ any user fields) -> returns updated HTML

State is stored via the configured Store (default: in-memory). For production, wire a session-backed implementation.

func NewHandler

func NewHandler(store Store) *Handler

NewHandler creates a Handler using the provided store. If store is nil, StoreDefault is used.

func (*Handler) ServeHTTP

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP handles Liveflux HTTP traffic.

  • GET requests return the bundled client script so the runtime can be loaded via URL.
  • POST requests mount components (when no ID is provided) or dispatch actions to existing instances.

type MemoryStore

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

MemoryStore is a simple in-memory implementation suitable for development and single-instance deployments. Replace with a session or DB-backed implementation for multi-instance deployments.

func NewMemoryStore

func NewMemoryStore() *MemoryStore

NewMemoryStore creates a MemoryStore.

func (*MemoryStore) Delete

func (s *MemoryStore) Delete(id string)

Delete removes a component by id.

func (*MemoryStore) Get

func (s *MemoryStore) Get(id string) (ComponentInterface, bool)

Get returns a component by id.

func (*MemoryStore) LockComponent added in v0.12.0

func (s *MemoryStore) LockComponent(id string) *sync.Mutex

LockComponent acquires a per-component lock to prevent concurrent modifications. Returns the lock that must be unlocked after the operation completes.

func (*MemoryStore) Set

func (s *MemoryStore) Set(c ComponentInterface)

Set stores a component by its ID.

func (*MemoryStore) UnlockComponent added in v0.12.0

func (s *MemoryStore) UnlockComponent(mu *sync.Mutex)

UnlockComponent releases the per-component lock.

type OnAttribute added in v0.9.0

type OnAttribute struct {
	EventName string
	Method    string
}

OnAttribute represents the #[On] attribute pattern from Livewire. Components can use struct tags or method naming conventions to declare event listeners.

func ParseOnAttributes added in v0.9.0

func ParseOnAttributes(component ComponentInterface) []OnAttribute

ParseOnAttributes scans a component for methods with "On" prefix and registers them. Convention: OnEventName(ctx context.Context, event Event) error Example: OnPostCreated handles "post-created" event

type Store

type Store interface {
	Get(id string) (ComponentInterface, bool)
	Set(c ComponentInterface)
	Delete(id string)
}

Store defines how component instances are persisted between requests.

var StoreDefault Store = NewMemoryStore()

StoreDefault is the default process-local store used by the handler.

type TargetFragment added in v0.15.0

type TargetFragment struct {
	// Selector is the CSS selector identifying the target element
	Selector string
	// Content is the HTML content to apply
	Content hb.TagInterface
	// SwapMode determines how the content is merged with the target
	// Valid values: "replace", "inner", "beforebegin", "afterbegin", "beforeend", "afterend"
	SwapMode string
	// NoComponentMetadata omits data-flux-component-kind and data-flux-component-id attributes.
	// When true, the client treats the fragment as document-scoped instead of component-scoped.
	NoComponentMetadata bool
}

TargetFragment represents a fragment of HTML to be applied to a specific DOM selector.

type TargetRenderer added in v0.15.0

type TargetRenderer interface {
	// RenderTargets returns a list of fragments to update specific DOM regions.
	// The handler will check for this interface and, if the client supports targets,
	// will send only these fragments instead of the full component render.
	RenderTargets(ctx context.Context) []TargetFragment
}

TargetRenderer is an optional interface that components can implement to support targeted fragment updates instead of full component re-renders.

type WebSocketComponent added in v0.6.0

type WebSocketComponent interface {
	ComponentInterface
	// HandleWS handles WebSocket messages for this component.
	// It should return a response message or an error.
	HandleWS(ctx context.Context, message *WebSocketMessage) (any, error)
}

WebSocketComponent is the interface that components can implement to handle WebSocket messages.

type WebSocketHandler added in v0.6.0

type WebSocketHandler struct {
	*Handler
	// contains filtered or unexported fields
}

WebSocketHandler handles WebSocket connections for LiveFlux.

func NewWebSocketHandler added in v0.6.0

func NewWebSocketHandler(store Store, optFns ...WebSocketOption) *WebSocketHandler

NewWebSocketHandler creates a new WebSocketHandler.

func (*WebSocketHandler) Broadcast added in v0.6.0

func (h *WebSocketHandler) Broadcast(componentID string, message interface{}) error

Broadcast sends a message to all connected clients for a component.

func (*WebSocketHandler) Handle added in v0.6.0

func (h *WebSocketHandler) Handle(kind string, constructor func() ComponentInterface)

Handle registers a component constructor for the given kind.

func (*WebSocketHandler) ServeHTTP added in v0.6.0

func (h *WebSocketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements http.Handler.

type WebSocketMessage added in v0.6.0

type WebSocketMessage struct {
	Type        string          `json:"type"`             // message type (e.g., "action", "update", "error")
	ComponentID string          `json:"componentID"`      // ID of the target component
	Action      string          `json:"action,omitempty"` // action name (for action messages)
	Data        json.RawMessage `json:"data,omitempty"`   // message payload
}

WebSocketMessage represents a message sent over WebSocket.

type WebSocketOption added in v0.7.0

type WebSocketOption func(*websocketOptions)

WebSocketOption configures optional behaviour for the WebSocket handler.

func WithWebSocketAllowedOrigins added in v0.7.0

func WithWebSocketAllowedOrigins(origins ...string) WebSocketOption

WithWebSocketAllowedOrigins restricts allowed WebSocket upgrade origins to the provided list. Comparisons are case-insensitive and expect fully qualified origin strings (scheme://host[:port]). When no origins are specified the handler falls back to the default upgrader behaviour (allow all).

func WithWebSocketCSRFCheck added in v0.7.0

func WithWebSocketCSRFCheck(check func(*http.Request) error) WebSocketOption

WithWebSocketCSRFCheck configures a custom CSRF validation function that is executed before upgrading the HTTP connection to a WebSocket. Returning a non-nil error will reject the upgrade with HTTP 403.

func WithWebSocketMessageValidator added in v0.7.0

func WithWebSocketMessageValidator(validator func(*WebSocketMessage) error) WebSocketOption

WithWebSocketMessageValidator sets a callback invoked for every WebSocket message before it is dispatched to the component. Returning an error sends a 400 response/error frame to the client and skips processing.

func WithWebSocketRateLimit added in v0.7.0

func WithWebSocketRateLimit(max int, window time.Duration) WebSocketOption

WithWebSocketRateLimit configures a simple per-client connection rate limit for WebSocket upgrades. A max value <= 0 disables limiting. The window defines the period for counting attempts; if zero, one minute is used.

func WithWebSocketRequireTLS added in v0.7.0

func WithWebSocketRequireTLS(require bool) WebSocketOption

WithWebSocketRequireTLS enforces that WebSocket upgrades occur over HTTPS/WSS. When enabled, plaintext HTTP upgrade attempts are rejected with HTTP 403.

Directories

Path Synopsis
examples
counter command
crud command
events command
formless command
target-basic command
tree command
triggers command
websocket command
js
tests command

Jump to

Keyboard shortcuts

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