Documentation
¶
Overview ¶
Package state provides stores, signals, computed values and watchers.
Concurrency contract: Store and Signal are safe for concurrent use, so background goroutines (tickers, feeds, host pushes) may call Set/Get directly. Listeners, watchers and dependent effects run synchronously on the goroutine that performed the Set, outside internal locks, so they may call back into the store or signal. Two things are deliberately not parallel-safe: computed functions run under the store lock and must only read the state map they receive, and signal dependency tracking (Effect) assumes effects never execute in parallel; effects are registered on the render goroutine and re-run on whichever goroutine calls Set.
Index ¶
- Variables
- func Batch(fn func())
- func ClearResourceCache(key string)
- func Dispatch(ctx Context, a Action) error
- func Effect(fn func() func()) func()
- func Map[T, R any](s *Store, key, dep string, compute func(T) R)
- func Map2[A, B, R any](s *Store, key, depA, depB string, compute func(A, B) R)
- func SetLogger(l Logger)
- func Untracked[T any](fn func() T) T
- func UseAction(ctx Context, a Action) func() error
- type Action
- type Computed
- type Context
- type Logger
- type MemoValue
- type ReactiveString
- type ReactiveVar
- type Resource
- func (r *Resource[T]) Close()
- func (r *Resource[T]) Error() error
- func (r *Resource[T]) Invalidate()
- func (r *Resource[T]) Load(ctx context.Context)
- func (r *Resource[T]) Loading() bool
- func (r *Resource[T]) Mutate(value T)
- func (r *Resource[T]) Read() (T, error)
- func (r *Resource[T]) Reload(ctx context.Context)
- func (r *Resource[T]) Status() ResourceStatus
- func (r *Resource[T]) Value() T
- type ResourceOption
- type ResourceStatus
- type Signal
- type Store
- func (s *Store) Get(key string) any
- func (s *Store) Module() string
- func (s *Store) Name() string
- func (s *Store) OnChange(key string, listener func(any)) func()
- func (s *Store) Redo()
- func (s *Store) RegisterComputed(c *Computed)
- func (s *Store) RegisterWatcher(w *Watcher) func()
- func (s *Store) Set(key string, value any)
- func (s *Store) Snapshot() map[string]any
- func (s *Store) Undo()
- type StoreManager
- func (sm *StoreManager) DumpState()
- func (sm *StoreManager) GetStore(module, name string) *Store
- func (sm *StoreManager) NewStore(name string, opts ...StoreOption) *Store
- func (sm *StoreManager) RegisterStore(module, name string, store *Store)
- func (sm *StoreManager) Snapshot() map[string]map[string]map[string]any
- func (sm *StoreManager) UnregisterStore(module, name string)
- type StoreOption
- type Subscription
- type Watcher
- type WatcherOption
Constants ¶
This section is empty.
Variables ¶
var ( // ErrResourcePending is returned by Read while a resource is loading. ErrResourcePending = errors.New("state: resource pending") // ErrNilResource is returned when Read is called on a nil resource. ErrNilResource = errors.New("state: nil resource") )
var GlobalStoreManager = &StoreManager{ modules: make(map[string]map[string]*Store), }
GlobalStoreManager is the process-wide store registry.
var OnCallbackPanic func(recovered any, context string, stack []byte)
OnCallbackPanic receives panics recovered at state callback boundaries. Core installs the browser error pipeline here; packages that use state on their own still get a log entry instead of a process-ending panic.
var StoreHook func(module, store, key string, value any)
StoreHook is invoked on every mutation when non-nil, allowing external observers (e.g. plugins) to react to state changes without creating an import cycle with core.
Functions ¶
func Batch ¶
func Batch(fn func())
Batch defers dependent effects until fn completes and runs each effect once.
func ClearResourceCache ¶
func ClearResourceCache(key string)
ClearResourceCache removes a shared resource cache entry.
func Dispatch ¶
Dispatch executes the given Action with the provided context. If the action is nil it is a no-op and nil is returned.
func Effect ¶
func Effect(fn func() func()) func()
Effect registers a reactive computation that automatically re-runs when its dependent signals change. The provided function may return a cleanup function that will run before the next execution and when the effect is stopped.
func Map ¶
Map registers a computed value derived from a single dependency using a strongly typed mapping function. The mapping function receives the current value of the dependency and its result is stored under the provided key. If the dependency cannot be asserted to the expected type, the zero value of the return type is used instead.
func Map2 ¶
Map2 registers a computed value derived from two dependencies. The mapping function receives the current values of both dependencies and its result is stored under the provided key. If any dependency fails type assertion the zero value of the return type is used.
Types ¶
type Action ¶
Action represents a unit of work executed with a Context. It returns an error if the action fails.
type Computed ¶
type Computed struct {
// contains filtered or unexported fields
}
Computed represents a derived state value based on other store keys. It holds the target key for the computed value, the list of dependencies and the function used to calculate the value.
func NewComputed ¶
NewComputed creates a new Computed value.
type Context ¶
Context is an alias of context.Context used by Actions. This allows the API to remain stable if a custom context is needed later.
type MemoValue ¶
type MemoValue[T any] struct { // contains filtered or unexported fields }
MemoValue is a read-only signal derived from other signals.
func (*MemoValue[T]) Get ¶
func (m *MemoValue[T]) Get() T
Get returns the current memoized value and tracks the caller.
func (*MemoValue[T]) OnChange ¶
func (m *MemoValue[T]) OnChange(fn func(T)) *Subscription
OnChange subscribes to memo changes.
type ReactiveString ¶
type ReactiveString = ReactiveVar[string]
ReactiveString is a convenience alias for ReactiveVar[string].
type ReactiveVar ¶
type ReactiveVar[T any] struct { // contains filtered or unexported fields }
ReactiveVar stores a value and notifies listeners when it changes.
func NewReactiveVar ¶
func NewReactiveVar[T any](initial T) *ReactiveVar[T]
NewReactiveVar creates a reactive value.
func (*ReactiveVar[T]) OnChange ¶
func (rv *ReactiveVar[T]) OnChange(listener func(T))
OnChange registers a listener.
func (*ReactiveVar[T]) Set ¶
func (rv *ReactiveVar[T]) Set(newValue T)
Set updates the value and notifies listeners.
type Resource ¶
type Resource[T any] struct { // contains filtered or unexported fields }
Resource wraps cancellable asynchronous data in reactive signals.
func NewResource ¶
func NewResource[T any](loader func(context.Context) (T, error), opts ...ResourceOption) *Resource[T]
NewResource creates a resource and starts loading by default.
func (*Resource[T]) Close ¶
func (r *Resource[T]) Close()
Close cancels pending work and prevents future loads.
func (*Resource[T]) Invalidate ¶
func (r *Resource[T]) Invalidate()
Invalidate clears the cache and returns the resource to idle.
func (*Resource[T]) Mutate ¶
func (r *Resource[T]) Mutate(value T)
Mutate replaces the value without loading.
func (*Resource[T]) Status ¶
func (r *Resource[T]) Status() ResourceStatus
Status returns the current reactive status.
type ResourceOption ¶
type ResourceOption func(*resourceConfig)
ResourceOption configures a Resource.
func WithResourceKey ¶
func WithResourceKey(key string) ResourceOption
WithResourceKey enables request deduplication and caching for key.
func WithResourceTTL ¶
func WithResourceTTL(ttl time.Duration) ResourceOption
WithResourceTTL expires a keyed cache entry after ttl.
func WithoutImmediateLoad ¶
func WithoutImmediateLoad() ResourceOption
WithoutImmediateLoad leaves a resource idle until Load is called.
type ResourceStatus ¶
type ResourceStatus string
ResourceStatus describes the current resource state.
const ( // ResourceIdle indicates that loading has not started. ResourceIdle ResourceStatus = "idle" // ResourceLoading indicates that a load is in progress. ResourceLoading ResourceStatus = "loading" // ResourceReady indicates that a value is available. ResourceReady ResourceStatus = "ready" // ResourceError indicates that loading failed. ResourceError ResourceStatus = "error" )
type Signal ¶
type Signal[T any] struct { // contains filtered or unexported fields }
Signal holds a value of type T and tracks which effects depend on it. Get/Set are safe for concurrent use, so background goroutines may feed a signal; dependent effects run synchronously on the goroutine calling Set.
func (*Signal[T]) Channel ¶
func (s *Signal[T]) Channel() <-chan T
Channel returns a read-only channel that receives the new value on each Set. The channel is created lazily on first call and shared across all listeners. It is closed automatically when all OnChange listeners are removed.
func (*Signal[T]) Get ¶
func (s *Signal[T]) Get() T
Get returns the current value of the signal and registers the calling effect.
func (*Signal[T]) OnChange ¶
func (s *Signal[T]) OnChange(fn func(T)) *Subscription
OnChange registers a callback that fires whenever the signal's value changes. Returns a Subscription that can be stopped to remove the listener.
func (*Signal[T]) Set ¶
func (s *Signal[T]) Set(v T)
Set updates the signal's value and notifies dependent effects. Effects run synchronously on the calling goroutine, outside the signal's lock.
func (*Signal[T]) SetFromHost ¶
SetFromHost sets the signal value from an untyped host payload. JSON decodes numbers as float64 and composites as []any/map[string]any, so payloads that do not assert directly to T are converted through a JSON round-trip into T. Payloads that cannot represent T are ignored.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store holds keyed state with listeners, computed values, watchers and optional history. All methods are safe for concurrent use: internal state is mutex-protected, and listeners/watchers are invoked outside the lock (on the goroutine that called Set), so they may call back into the store. Computed functions run under the lock and must only read the state map they receive, never call store methods.
func NewStore ¶
func NewStore(name string, opts ...StoreOption) *Store
NewStore creates a new store with the given name and optional configuration. By default stores are registered under the "default" module.
func (*Store) RegisterComputed ¶
RegisterComputed registers a computed value on the store. The computed value is evaluated immediately and whenever one of its dependencies changes. The compute function runs under the store lock: it must only read the state map it receives and never call store methods.
func (*Store) RegisterWatcher ¶
RegisterWatcher registers a watcher that triggers when any of its dependencies change. If the dependency list is empty the watcher is triggered on every state update. It returns a function that removes the watcher.
type StoreManager ¶
type StoreManager struct {
// contains filtered or unexported fields
}
StoreManager groups stores by module and name.
func NewStoreManager ¶
func NewStoreManager() *StoreManager
NewStoreManager creates a standalone manager for isolating store instances.
func (*StoreManager) DumpState ¶
func (sm *StoreManager) DumpState()
DumpState writes every registered store to the debug logger.
func (*StoreManager) GetStore ¶
func (sm *StoreManager) GetStore(module, name string) *Store
GetStore returns a registered store or nil.
func (*StoreManager) NewStore ¶
func (sm *StoreManager) NewStore(name string, opts ...StoreOption) *Store
NewStore creates and registers a store in this manager.
func (*StoreManager) RegisterStore ¶
func (sm *StoreManager) RegisterStore(module, name string, store *Store)
RegisterStore registers a store by module and name.
func (*StoreManager) Snapshot ¶
func (sm *StoreManager) Snapshot() map[string]map[string]map[string]any
Snapshot returns a deep copy of all registered stores and their states.
func (*StoreManager) UnregisterStore ¶
func (sm *StoreManager) UnregisterStore(module, name string)
UnregisterStore removes the store identified by module and name. If the store or module does not exist, it is a no-op.
type StoreOption ¶
type StoreOption func(*Store)
StoreOption configures optional behaviour for a Store during creation.
func WithDevTools ¶
func WithDevTools() StoreOption
WithDevTools enables logging of state mutations for development.
func WithHistory ¶
func WithHistory(limit int) StoreOption
WithHistory enables mutation history with the provided limit. The limit controls how many past mutations are retained for undo/redo.
func WithModule ¶
func WithModule(module string) StoreOption
WithModule namespaces a store under the provided module.
func WithPersistence ¶
func WithPersistence() StoreOption
WithPersistence enables localStorage persistence for the store.
type Subscription ¶
type Subscription struct {
// contains filtered or unexported fields
}
Subscription represents a cancellable listener returned by OnChange.
func (*Subscription) Stop ¶
func (s *Subscription) Stop()
Stop removes the listener and releases the associated channel.
type Watcher ¶
type Watcher struct {
// contains filtered or unexported fields
}
Watcher represents a callback that reacts to changes on specific store keys. When any of the dependencies change, the associated function is triggered.
func NewWatcher ¶
func NewWatcher(deps []string, run func(map[string]any), opts ...WatcherOption) *Watcher
NewWatcher creates a new Watcher.
type WatcherOption ¶
type WatcherOption func(*Watcher)
WatcherOption configures optional watcher behaviour.
func WatcherDeep ¶
func WatcherDeep() WatcherOption
WatcherDeep enables deep watching of nested keys.
func WatcherImmediate ¶
func WatcherImmediate() WatcherOption
WatcherImmediate triggers the watcher immediately after registration.