state

package
v4.2.0 Latest Latest
Warning

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

Go to latest
Published: Jul 5, 2026 License: MIT Imports: 13 Imported by: 0

README

GWC | State Library

GoWebComponents (GWC)

High-Level Overview

The state library provides shared state primitives and hook-based integration for component-level and app-level state management.

Snapshot Versions

SaveSnapshot and SavePersistentSnapshot emit versioned envelopes. RegisterSnapshotMigration installs migrations for restoring older envelopes; future versions are rejected, legacy unversioned payloads are treated as version 0, and failed migrations leave the existing atom values untouched.

Public APIs

github.com/monstercameron/GoWebComponents/state (package state)
  • Functions: ApplySnapshot, ExportSnapshot, Get, GetSnapshot, ImportSnapshot, LoadPersistentSnapshot, LoadSnapshot, MarshalSnapshotJSON, ReactiveRegionSourceIDs, RestorePersistentSnapshot, RestoreSnapshot, SavePersistentSnapshot, SaveSnapshot, Select, Set, Text, UnmarshalSnapshotJSON, Update, UseAtom, UseComputed, UseDerived
  • Types: Atom, Computed, Derived, Element, PersistentSnapshotOptions, Snapshot, StorageArea
  • Variables: none
  • Constants: LocalStorage, SessionStorage

Subfiles And Purpose

  • doc.go - Package-level Go documentation
  • example_test.go - Tests for example behavior
  • README.md - Folder-level documentation
  • state.go - Core implementation for state
  • state_wasm_test.go - Tests for state_wasm behavior

File Map

state/
|-- doc.go
|-- example_test.go
|-- README.md
|-- state.go
\-- state_wasm_test.go

Documentation

Overview

Package state provides shared atom-based state management for GoWebComponents.

This package implements atom-based state management inspired by SolidJS and Jotai, allowing components to subscribe to global state that persists across the entire application and automatically triggers re-renders when values change.

Basic usage:

import "github.com/monstercameron/GoWebComponents/v4/state"

// In any component
func UserProfile() ui.Node {
    username := state.UseAtom("currentUser", "Guest")
    login := ui.UseEvent(func() {
        username.Set("John Doe")
    })

    return html.Div(html.Props{},
        html.H1(html.Props{}, html.Text(fmt.Sprintf("Welcome, %s", username.Get()))),
        html.Button(html.Props{OnClick: login}, html.Text("Login")),
    )
}

// In a different component - shares the same state!
func NavBar() ui.Node {
    username := state.UseAtom("currentUser", "Guest")
    return html.Nav(html.Props{}, html.Span(html.Props{}, html.Text(username.Get())))
}

Key features:

  • Global state accessible from any component by ID
  • Automatic subscription and re-rendering when state changes
  • Type-safe with Go generics
  • Thread-safe for concurrent access
  • Subscription-scoped updates - only subscribed components re-render
  • UseComputed for typed derived values inside components
  • UseDerived for read-only shared derived atoms with explicit source dependencies
  • Snapshot export/import for in-memory restore and optional browser persistence helpers

Atoms vs Component State:

  • Use state.UseAtom for data that needs to be shared across components
  • Use state.UseComputed for memoized derived values based on atoms, props, or local state
  • Use state.UseDerived for shared read-only derived atoms keyed by ID and explicit source atom dependencies
  • Use ui.UseState for local component state
  • Atoms persist across component unmounts
  • Atoms trigger updates in all subscribed components

Snapshot persistence notes:

  • GetSnapshot and ApplySnapshot preserve exact Go values for same-process restore.
  • SaveSnapshot and LoadSnapshot encode snapshots as JSON for browser storage.
  • SavePersistentSnapshot and LoadPersistentSnapshot use IndexedDB-first durable storage with explicit fallback behavior.
  • JSON persistence is only stable for JSON-compatible atom values; numeric and struct-heavy atoms may need caller-owned codecs if exact round-tripping is required.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func ApplySnapshot

func ApplySnapshot(parseSnapshot Snapshot) error

ApplySnapshot merges atom values from snapshot into the global runtime and schedules subscribed components for updates.

func ImportSnapshot deprecated

func ImportSnapshot(parseSnapshot Snapshot) error

ImportSnapshot merges atom values from snapshot into the global runtime and schedules subscribed components for updates.

Deprecated: use ApplySnapshot. ImportSnapshot is the older export/import-terminology name and is kept only for source compatibility.

func MarshalSnapshotJSON

func MarshalSnapshotJSON(parseSnapshot Snapshot) ([]byte, error)

MarshalSnapshotJSON serializes snapshot for browser storage or transport.

Persisted snapshots should only contain JSON-compatible values if stable round-tripping is required. Composite Go structs restore as generic JSON objects unless callers provide their own typed serialization layer.

func RegisterSnapshotMigration

func RegisterSnapshotMigration(parseFromVersion int, parseMigration SnapshotMigration) error

RegisterSnapshotMigration registers one adjacent snapshot schema migration from parseFromVersion to parseFromVersion+1. Register migrations at app boot before loading stored snapshots. Passing nil removes the migration.

func RestorePersistentSnapshot

func RestorePersistentSnapshot(parseCtx context.Context, parseKey string, parseOptions ...PersistentSnapshotOptions) (bool, error)

RestorePersistentSnapshot loads a durable snapshot and imports it into the current runtime.

If parseCtx is nil it is replaced with context.Background(). If parseCtx is already cancelled the underlying store resolver will receive a cancelled context and is expected to return an error, which is propagated to the caller.

func RestoreSnapshot

func RestoreSnapshot(parseKey string, parseArea StorageArea) (bool, error)

RestoreSnapshot loads a snapshot from browser storage and imports it.

func SavePersistentSnapshot

func SavePersistentSnapshot(parseCtx context.Context, parseKey string, parseSnapshot Snapshot, parseOptions ...PersistentSnapshotOptions) error

SavePersistentSnapshot stores a JSON-encoded snapshot in IndexedDB-first durable browser storage.

If parseCtx is nil it is replaced with context.Background(). If parseCtx is already cancelled the underlying store resolver will receive a cancelled context and is expected to return an error, which is propagated to the caller.

func SaveSnapshot

func SaveSnapshot(parseKey string, parseSnapshot Snapshot, parseArea StorageArea) error

SaveSnapshot stores a JSON-encoded snapshot in browser storage.

Types

type Atom

type Atom[T any] struct {
	// contains filtered or unexported fields
}

Atom exposes shared read/write state keyed by ID.

func UseAtom

func UseAtom[T any](parseId string, parseInitialValue T) Atom[T]

UseAtom provides shared global atoms with subscription-scoped rerenders. Atoms are accessible from anywhere in the component tree by ID and automatically trigger re-renders in all subscribed components when updated.

The first component to call UseAtom with a specific ID initializes the atom with the provided initial value. Subsequent calls from other components will use the existing value and subscribe to updates.

Type parameter T can be any Go type. The hook uses generic type parameters for type safety.

Returns an Atom[T] handle with Get, Set, and Update methods.

Example - Theme Management:

// In a theme-switcher component
theme := state.UseAtom("appTheme", "light")

toggle := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
    if theme.Get() == "light" {
        theme.Set("dark")
    } else {
        theme.Set("light")
    }
    return nil
})

// In a header component — re-renders automatically when theme changes
theme := state.UseAtom("appTheme", "light")
bgColor := "white"
if theme.Get() == "dark" {
    bgColor = "#333"
}

Example - User Authentication:

type User struct {
    ID       int
    Username string
    Email    string
}

user := state.UseAtom("currentUser", User{})

login := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
    user.Set(User{ID: 1, Username: "johndoe", Email: "john@example.com"})
    return nil
})

if user.Get().ID == 0 {
    // render login button
} else {
    // render welcome message using user.Get().Username
}

Thread Safety: UseAtom is thread-safe and can be safely called from multiple goroutines. The internal atom registry uses mutex-based synchronization.

Cleanup: When a component unmounts, it is automatically unsubscribed from all atoms to prevent memory leaks and unnecessary updates.

Best Practices:

  • Use descriptive atom IDs (e.g., "currentUser", "appTheme", "shoppingCart")
  • Initialize atoms with appropriate default values
  • Use structured types (structs) for complex state
  • Avoid storing large amounts of data in atoms (use for coordination, not caching)
Example

ExampleUseAtom shows shared atom state: components that bind the same atom id observe one value, and a Computed derives from it.

package main

import (
	"github.com/monstercameron/GoWebComponents/v4/state"
)

func main() {
	parseCount := state.UseAtom("counter", 0)
	parseDoubled := state.UseComputed(func() int { return parseCount.Get() * 2 })
	// Both update together when the atom changes.
	_ = parseDoubled
}

func UseAtomKey

func UseAtomKey[T any](parseKey AtomKey[T]) Atom[T]

UseAtomKey subscribes the current component to a typed atom key — the typed sibling of UseAtom. Prefer it over UseAtom for any atom shared across components or packages, so the id, type, and default are declared once and can't drift between call sites.

func (Atom[T]) Get

func (parseA Atom[T]) Get() T

Get returns the current atom value.

func (Atom[T]) ReactiveRegionSourceIDs

func (parseA Atom[T]) ReactiveRegionSourceIDs() []string

ReactiveRegionSourceIDs is a core package helper.

func (Atom[T]) Set

func (parseA Atom[T]) Set(parseValue T)

Set replaces the atom value.

func (Atom[T]) Text

func (parseA Atom[T]) Text(render func(T) string) *Element

Text renders an atom-backed reactive text node that can update without rerendering the owning component.

func (Atom[T]) Update

func (parseA Atom[T]) Update(parseFn func(T) T)

Update replaces the atom value using the previous value.

type AtomKey

type AtomKey[T any] struct {
	// contains filtered or unexported fields
}

AtomKey is a typed, declared-once handle to a shared atom. Declaring the id, value type, and default in ONE package-level var —

var ThemeAtom = state.NewAtomKey("app.theme", "light")

and passing that key to UseAtomKey / ThemeAtom.Global() everywhere the atom is read or written gives three things the stringly UseAtom(id, default) form cannot:

  • Type + default consistency: a UseAtom("app.theme", "light") and a NewGlobalAtom("app.theme", 0) elsewhere silently disagree on type and default; with a key they share the one declaration.
  • A compile-checked name: a typo in the key var is a compile error, whereas a typo'd id string silently creates a brand-new, empty atom.
  • A stringless call site: you pass ThemeAtom, not "app.theme" + "light" repeated everywhere.

Two keys that nonetheless choose the same id string still address the same atom — AtomKey centralizes the contract, it does not namespace ids. Share one key var for one logical atom. (Corollary: an AtomKey[string] and an AtomKey[int] declared with the SAME id hit one registry slot; whichever seeds first wins and the other's reads fall back to its default — exactly the raw-UseAtom type-mismatch footgun, not a new one. For a pointer/slice/map T, Default() hands every caller the same reference, so mutating it aliases; keep defaults immutable.)

func NewAtomKey

func NewAtomKey[T any](parseID string, parseInitial T) AtomKey[T]

NewAtomKey declares a typed atom key. Call it once at package scope and reuse the returned value.

func (AtomKey[T]) Default

func (parseKey AtomKey[T]) Default() T

Default returns the key's seeded default value.

func (AtomKey[T]) Global

func (parseKey AtomKey[T]) Global() GlobalAtom[T]

Global returns the out-of-render handle for this key — the typed sibling of NewGlobalAtom — so code outside a component can read or write the atom: ThemeAtom.Global().Set("dark"). The default is seeded only if the atom has no value yet (it never clobbers an existing write).

func (AtomKey[T]) ID

func (parseKey AtomKey[T]) ID() string

ID returns the underlying atom id this key maps to.

type Computed

type Computed[T any] struct {
	// contains filtered or unexported fields
}

Computed exposes a memoized derived value local to the current component.

func UseComputed deprecated

func UseComputed[T any](parseCompute func() T, parseDeps ...any) Computed[T]

UseComputed derives a typed value from other state used by the current component.

It is intended for render-time derived values, especially when a component is already reading one or more atoms and wants a typed handle instead of using ui.UseMemo directly in every call site.

The computed value is memoized according to the provided dependency list. Callers should pass the values that should trigger recomputation.

Deprecated: prefer ui.UseMemo, which returns the value directly (UseComputed only wraps it in a Computed handle). For a shared, cross-component derived value use state.UseDerived instead.

func (Computed[T]) Get

func (parseC Computed[T]) Get() T

Get returns the current computed value.

type ComputedSignal

type ComputedSignal[T any] struct {
	// contains filtered or unexported fields
}

ComputedSignal is a read-only value derived from one or more reactive sources.

Its dependencies are EXPLICIT — passed to NewComputed — so recomputation is predictable and never depends on a hidden tracking graph. ComputedSignal.Get is lazy (it recomputes from the live sources on read); pass the computed to ui.ReactiveRegion to render a subtree that updates fine-grained when any named source changes.

Multi-source note: Get, Text, and ReactiveRegionSourceIDs honor ALL declared sources. The one exception is using a ComputedSignal as an explicit source of ANOTHER computed (via the reactiveSource interface): only its primary (first) source id is propagated, so chain a computed off its underlying atoms — not off another multi-source computed — if you need every transitive dependency tracked.

func NewAutoComputed

func NewAutoComputed[T any](parseCompute func() T) ComputedSignal[T]

NewAutoComputed derives a value from compute, AUTO-DISCOVERING its reactive sources by running compute once with read-tracking on and recording which signals it read (Solid-style auto-tracking). It is the opt-in sibling of NewComputed; explicit dependency declaration (NewComputed) remains the default and recommended path per GWC's no-hidden-graph design, so auto-tracking is a convenience, not a replacement.

a := state.NewSignal(2)
b := state.NewSignal(3)
sum := state.NewAutoComputed(func() int { return a.Get() + b.Get() }) // a, b discovered

func NewComputed

func NewComputed[T any](parseCompute func() T, parseSources ...reactiveSource) ComputedSignal[T]

NewComputed derives a value from compute, declaring the reactive sources it depends on. Dependencies are explicit by design: only changes to the named sources are guaranteed to refresh consumers bound through ui.ReactiveRegion.

first := state.NewSignal("Ada")
last := state.NewSignal("Lovelace")
full := state.NewComputed(func() string { return first.Get() + " " + last.Get() }, first, last)

func (ComputedSignal[T]) Get

func (parseC ComputedSignal[T]) Get() T

Get recomputes and returns the derived value from the live sources.

func (ComputedSignal[T]) Peek

func (parseC ComputedSignal[T]) Peek() T

Peek returns the derived value; identical to ComputedSignal.Get, named for parity with Signal.Peek.

func (ComputedSignal[T]) ReactiveRegionSourceIDs

func (parseC ComputedSignal[T]) ReactiveRegionSourceIDs() []string

ReactiveRegionSourceIDs returns every declared source id, so ui.ReactiveRegion re-renders the region when ANY dependency of the computed changes.

func (ComputedSignal[T]) Text

func (parseC ComputedSignal[T]) Text(render func(T) string) *Element

Text renders a fine-grained reactive text node for the computed value. It subscribes to EVERY declared source, so the text flushes when any dependency changes — a multi-source computed is no longer a silent missed-update footgun (it previously bound only the first source). The node recomputes the full computed value on each flush.

func (ComputedSignal[T]) TextValue

func (parseC ComputedSignal[T]) TextValue() *Element

TextValue is the zero-argument form of Text for a computed signal: it renders the computed value with default fmt formatting (see Signal.TextValue).

type Derived

type Derived[T any] struct {
	// contains filtered or unexported fields
}

Derived exposes a shared read-only derived atom keyed by ID.

func Select deprecated

func Select[T any, U any](parseId string, parseSource selectorSource[T], parseProject func(T) U) Derived[U]

Select is a compatibility wrapper around UseSelector.

Deprecated: Use UseSelector.

func UseDerived

func UseDerived[T any](parseId string, parseCompute func() T, parseDeps ...string) Derived[T]

UseDerived registers and subscribes to a read-only derived atom.

Derived atoms are shared state values keyed by id. They recompute when one of the named source atom IDs changes and expose a typed read-only handle to the current derived value. Dependency tracking is explicit through atom IDs so recomputation remains predictable and avoids hidden runtime graph discovery.

The id is GLOBAL and shared — this is intentional and is the whole point: two components that pass the same id share one derived atom (the same model as UseAtom). That deliberately differs from UseSelector, whose id is auto-scoped to the calling component because a selector is a component-local projection, not shared state. So: pick a unique, descriptive id for a UseDerived you intend to share, exactly as you would for a UseAtom; reach for UseSelector when you want a local, collision-free projection instead.

func UseSelector

func UseSelector[T any, U any](parseId string, parseSource selectorSource[T], parseProject func(T) U) Derived[U]

UseSelector creates a read-only projected shared value from an atom or derived source.

The selector remains explicit: callers provide the derived ID to register and the source handle to project from. When the projected value is unchanged, subscribers are not notified, which makes it suitable for fine-grained hot-value paths.

func (Derived[T]) Get

func (parseD Derived[T]) Get() T

Get returns the current derived value.

func (Derived[T]) ReactiveRegionSourceIDs

func (parseD Derived[T]) ReactiveRegionSourceIDs() []string

ReactiveRegionSourceIDs is a core package helper.

func (Derived[T]) Text

func (parseD Derived[T]) Text(render func(T) string) *Element

Text renders a derived-value-backed reactive text node that can update without rerendering the owning component.

type Element

type Element = runtime.Element

Element aliases the runtime element type for state package examples and helpers.

type GlobalAtom

type GlobalAtom[T any] struct {
	// contains filtered or unexported fields
}

GlobalAtom is a non-hook handle to a shared atom, readable and writable from ANY context — crucially from OUTSIDE a render: global keyboard handlers, undo/redo, post-decrypt hydration, network/event callbacks, or any goroutine.

It targets the same atom registry as UseAtom, keyed by the same id, so a component that reads the id via UseAtom(id, default) re-renders automatically when a GlobalAtom write changes the value. This is the answer to G39: it retires the render-phase "capture variable + captured bool" triad and removes the pre-render-write silent-drop bug — a value written through GlobalAtom before the first render persists (UseAtom seeds its default only when the atom is absent) and is observed by the first UseAtom read.

Contract: a GlobalAtom and any UseAtom sharing an id MUST agree on the default value. Construct a GlobalAtom once (e.g. a package var) and share it.

func NewGlobalAtom

func NewGlobalAtom[T any](parseID string, parseDefault T) GlobalAtom[T]

NewGlobalAtom returns a handle for the atom identified by id and seeds the registry with defaultValue if (and only if) the atom has no value yet. Seeding never notifies subscribers and never clobbers an existing value, so it is safe to construct at package-init time or after an external write.

func (GlobalAtom[T]) Get

func (parseAtom GlobalAtom[T]) Get() T

Get returns the current value, or the handle's default when the runtime is unavailable or the stored value is not of type T.

func (GlobalAtom[T]) ID

func (parseAtom GlobalAtom[T]) ID() string

ID returns the atom's identifier (the key shared with UseAtom).

func (GlobalAtom[T]) Set

func (parseAtom GlobalAtom[T]) Set(parseValue T)

Set writes a new value and schedules a re-render of every component subscribed to this id via UseAtom. Safe to call from any goroutine or callback. A no-op when the runtime is unavailable (e.g. native SSR with no global runtime).

Writing a value equal to the current one is a no-op (no re-render), matching UseState's behavior. Equality is a fast == with a structural reflect.DeepEqual fallback for non-comparable types (slice/map), so an equal slice/map is also a no-op.

func (GlobalAtom[T]) Update

func (parseAtom GlobalAtom[T]) Update(parseFn func(T) T)

Update applies fn to the current value and stores the result.

type PersistentSnapshotOptions

type PersistentSnapshotOptions struct {
	// DatabaseName is the IndexedDB database to open (default used when empty).
	DatabaseName string
	// StoreName is the object store within the database (default used when empty).
	StoreName string
	// DeleteOnCorruption drops and recreates the store if it fails to open, trading data
	// loss for availability instead of surfacing a hard error.
	DeleteOnCorruption bool
	// FallbackResolver supplies a synchronous Storage when IndexedDB is unavailable.
	FallbackResolver func() (interop.Storage, error)
	// FallbackBackend names the fallback for diagnostics (e.g. "localStorage").
	FallbackBackend string
	// StoreResolver overrides how the durable store is opened; when nil the default
	// IndexedDB resolver is used.
	StoreResolver func(context.Context) (interop.PersistentStore, error)
}

PersistentSnapshotOptions configures durable IndexedDB-first snapshot storage used by SavePersistentSnapshot / LoadPersistentSnapshot. The zero value is valid: it uses the default database and store names with no fallback. Set fields only to override defaults.

type Signal

type Signal[T any] struct {
	// contains filtered or unexported fields
}

Signal is a fine-grained reactive value: a terse, ergonomic handle over the shared atom registry that updates exactly the DOM nodes bound to it (via Signal.Text) and the regions/components subscribed to it — without forcing a re-render of the component that owns it.

It is the recommended fine-grained primitive. Compared to its neighbors:

  • vs UseAtom: a Signal needs no caller-managed string id (one is minted), and it is created with NewSignal outside the hook/render lifecycle, so it can live in a package var, an event handler, or a goroutine.
  • vs Solid/Svelte signals: GWC tracks derivation dependencies EXPLICITLY (NewComputed names its sources) rather than discovering them through a hidden runtime graph. That is a deliberate design choice — predictable, auditable reactivity over implicit magic.

A Signal is a small value (an id + default); copy it freely. Reads and writes go through the global atom registry and are safe from any goroutine.

func NewKeyedSignal

func NewKeyedSignal[T any](parseID string, parseInitial T) Signal[T]

NewKeyedSignal creates a signal with an explicit, shared id, so independent call sites can address the same reactive value (the way UseAtom does). Prefer NewSignal unless the shared identity is the point. Call sites sharing an id must agree on the initial value.

func NewSignal

func NewSignal[T any](parseInitial T) Signal[T]

NewSignal creates a fine-grained reactive value seeded with initial.

It may be called anywhere — including outside a component render (package init, event handlers, goroutines) — because, unlike a hook, it does not depend on call order within a render. Each call mints a fresh, process-unique identity; use NewKeyedSignal when several call sites must address the same signal.

func (Signal[T]) Get

func (parseS Signal[T]) Get() T

Get returns the current value of the signal. When called inside a NewAutoComputed compute function, it also records this signal as a discovered dependency (auto-tracking); outside one, the read-tracking check is a single cheap atomic load.

func (Signal[T]) ID

func (parseS Signal[T]) ID() string

ID returns the underlying atom id — the source key used by reactive regions and selectors, and the key a UseAtom reader would share.

func (Signal[T]) Peek

func (parseS Signal[T]) Peek() T

Peek returns the current value without implying a reactive subscription. It is identical to Signal.Get today, named for parity with signal libraries and to document intent at call sites that must read a value without binding to it.

func (Signal[T]) ReactiveRegionSourceIDs

func (parseS Signal[T]) ReactiveRegionSourceIDs() []string

ReactiveRegionSourceIDs lets a Signal drive a ui.ReactiveRegion, so a subtree can re-render on signal changes without rerunning its owner.

func (Signal[T]) Set

func (parseS Signal[T]) Set(parseValue T)

Set writes a new value and notifies bound text nodes, reactive regions, and UseAtom subscribers of the same id. Writing a value equal to the current one is a no-op (no notification), matching UseState semantics. Safe from any goroutine; a no-op when the runtime is unavailable (e.g. native SSR).

func (Signal[T]) Text

func (parseS Signal[T]) Text(render func(T) string) *Element

Text renders a fine-grained reactive text node bound to this signal: it updates in place when the signal changes, WITHOUT re-rendering the component that returned it. This is the primary fine-grained authoring path.

count := state.NewSignal(0)
// ...
h.Span(count.Text(func(n int) string { return fmt.Sprintf("%d", n) }))

func (Signal[T]) TextValue

func (parseS Signal[T]) TextValue() *Element

TextValue is the zero-argument form of Text: it binds a reactive text node that renders the signal's value with default fmt formatting — the common case (a string signal, or any value whose fmt form is what you want) where no custom formatter is needed.

name := state.NewSignal("Ada")
h.Span(name.TextValue()) // no render func

func (Signal[T]) Update

func (parseS Signal[T]) Update(parseFn func(T) T)

Update applies fn to the current value and stores the result.

type Snapshot

type Snapshot map[string]any

Snapshot stores exported atom values by atom ID.

func ExportSnapshot deprecated

func ExportSnapshot() (Snapshot, error)

ExportSnapshot returns a copy of all atoms currently registered in the global runtime.

Deprecated: use GetSnapshot. ExportSnapshot is the older export/import-terminology name and is kept only for source compatibility.

func GetSnapshot

func GetSnapshot() (Snapshot, error)

GetSnapshot returns a copy of all atoms currently registered in the global runtime.

The returned snapshot preserves in-memory Go values exactly for same-process restore via ApplySnapshot. When serializing to JSON or browser storage, only JSON-compatible atom values should be relied on as stable persisted data.

func LoadPersistentSnapshot

func LoadPersistentSnapshot(parseCtx context.Context, parseKey string, parseOptions ...PersistentSnapshotOptions) (Snapshot, bool, error)

LoadPersistentSnapshot reads and decodes a snapshot from IndexedDB-first durable browser storage.

If parseCtx is nil it is replaced with context.Background(). If parseCtx is already cancelled the underlying store resolver will receive a cancelled context and is expected to return an error, which is propagated to the caller.

func LoadSnapshot

func LoadSnapshot(parseKey string, parseArea StorageArea) (Snapshot, bool, error)

LoadSnapshot reads and decodes a snapshot from browser storage.

func UnmarshalSnapshotJSON

func UnmarshalSnapshotJSON(parseData []byte) (Snapshot, error)

UnmarshalSnapshotJSON decodes a JSON snapshot produced by MarshalSnapshotJSON.

func (Snapshot) Select

func (parseS Snapshot) Select(parseKeys ...string) Snapshot

Select returns a filtered snapshot containing only the requested atom keys.

type SnapshotMigration

type SnapshotMigration func(Snapshot) (Snapshot, error)

SnapshotMigration upgrades one snapshot payload between adjacent schema versions. Implementations must return a fresh snapshot or an error; errors abort the restore before any atom state is changed.

type StorageArea

type StorageArea string

StorageArea names a browser storage backend.

const (
	// LocalStorage stores snapshots in window.localStorage.
	LocalStorage StorageArea = "localStorage"
	// SessionStorage stores snapshots in window.sessionStorage.
	SessionStorage StorageArea = "sessionStorage"
)

Jump to

Keyboard shortcuts

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