fetch

package
v4.1.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: 20 Imported by: 0

README

GWC | Fetch Library

GoWebComponents (GWC)

High-Level Overview

The fetch library handles async data loading, typed resources, shared cache behavior, uploads, bounded realtime browser streams, and offline mutation queue flows in GWC applications.

Public APIs

github.com/monstercameron/GoWebComponents/fetch (package fetch)
  • Functions: ApplyOptimisticUpdate, AsMutationConflictError, Cancel, Clear, Close, ConfigurePersistentCache, DecodeJSON, Dispose, DisposeQueryTag, DisposeResource, Done, Enqueue, Error, Fetch, Get, GetMutationConflict, InspectCachedResources, Invalidate, InvalidateQueryTag, InvalidateQueryTags, InvalidateResource, IsMutationConflict, List, LoadCached, LoadQuery, NewMutationConflict, Open, OpenMutationQueue, QueryKeysForTag, QueryTagsForKey, Refetch, Reload, Remove, Replay, ReplayWithOptions, RestoreCacheBootstrap, ReturnChannel, Send, Set, SweepCachedResources, Text, Unwrap, Update, Upload, UseCachedResource, UseEventSource, UseFetch, UseInfiniteQuery, UseQuery, UseResource, UseWebSocket
  • Types: AsyncResource, CacheBootstrap, CacheBootstrapEntry, CacheOptions, CacheResumePolicy, CachedResource, CachedResourceInspection, CachedResourceState, EventSource, EventSourceOptions, HTTPError, InfiniteQuery, InfiniteQueryData, InfiniteQueryOptions, InfiniteQueryState, MultipartBody, MultipartFile, MutationConflict, MutationConflictError, MutationConflictHandler, MutationConflictResolution, MutationDraft, MutationExecutor, MutationQueue, MutationQueueOptions, MutationReplayOptions, MutationReplayReport, MutationResolutionAction, MutationState, OptimisticUpdate, Options, PersistentCacheOptions, Query, QueryOptions, QueryPage, QueryPageRequest, QueuedMutation, RealtimeError, RealtimeMessage, RealtimeState, RealtimeStatus, Resource, ResourceState, Result, State, UploadUpdate, WebSocket, WebSocketOptions
  • Variables: none
  • Constants: CacheBootstrapDataKey, CacheResumeAlwaysRefetch, CacheResumeStaleWhileRevalidate, CacheResumeTrustOnce, MutationDead, MutationQueued, MutationResolutionDead, MutationResolutionRemove, MutationResolutionReplace, MutationResolutionRetry, MutationRetrying, RealtimeClosed, RealtimeConnecting, RealtimeIdle, RealtimeOpen, RealtimeReconnecting, RealtimeUnsupported

Subfiles And Purpose

  • cache.go - Core implementation for cache
  • doc.go - Package-level Go documentation
  • example_test.go - Tests for example behavior
  • fetch.go - Core implementation for fetch
  • fetch_wasm_test.go - Tests for fetch_wasm behavior
  • mutation_queue.go - Core implementation for mutation_queue
  • mutation_queue_wasm_test.go - Tests for mutation_queue_wasm behavior
  • query_cache.go - Tag-aware query, pagination, and optimistic rollback helpers
  • realtime.go - Shared bounded WebSocket and EventSource hook state
  • realtime_native.go - Native unsupported realtime stubs
  • realtime_wasm.go - Browser WebSocket and EventSource transports
  • README.md - Folder-level documentation

Realtime Hooks

UseWebSocket and UseEventSource are browser hooks for small realtime surfaces that need bounded in-memory state. Both hooks keep only the newest MaxMessages and MaxErrors, reconnect with capped exponential backoff, and expose a RealtimeState snapshot through Get().

On non-browser builds the hooks compile and return RealtimeUnsupported with a descriptive error. This keeps SSR, native tests, and tooling builds safe without pretending a browser transport exists.

socket := fetch.UseWebSocket("wss://example.test/live", fetch.WebSocketOptions{
    MaxMessages:       16,
    MaxReconnects:     3,
    HeartbeatInterval: 30 * time.Second,
})

state := socket.Get()
if state.Open {
    _ = socket.Send("ping")
}

Query Cache

UseQuery is the higher-level cache wrapper for application data. It uses the same shared cache as UseCachedResource, adds tags for invalidating related keys together, and returns rollback handles for optimistic mutation flows. UseInfiniteQuery stores pages under one cache key and appends additional pages with LoadNext.

users := fetch.UseQuery("users:list", loadUsers, fetch.QueryOptions{
    Tags: []string{"users"},
})

rollback := users.OptimisticUpdate(func(prev []User) []User {
    return append(prev, User{Name: "Ada"})
})
if err := saveUser(); err != nil {
    rollback.Rollback()
}

fetch.InvalidateQueryTag("users")

File Map

fetch/
|-- cache.go
|-- doc.go
|-- example_test.go
|-- fetch.go
|-- fetch_wasm_test.go
|-- mutation_queue.go
|-- mutation_queue_wasm_test.go
|-- query_cache.go
|-- realtime.go
|-- realtime_native.go
|-- realtime_wasm.go
\-- README.md

Documentation

Overview

Package fetch provides data loading utilities for GoWebComponents.

The package exposes these public hook styles:

  • UseResource for typed, context-aware async loading in non-trivial components
  • UseCachedResource for shared cached async state with deduplication and invalidation
  • UseQuery and UseInfiniteQuery for tag-aware cache invalidation, paginated data, and optimistic rollback helpers
  • UseWebSocket and UseEventSource for bounded browser realtime streams
  • OpenMutationQueue for durable offline write replay in browser storage
  • UseFetch (deprecated) for low-level raw fetch state around a URL

UseResource is the preferred choice in nearly all cases: it gives typed results, cancellation, dependency-driven reloads, and loader logic beyond a single raw fetch call. UseFetch is deprecated — prefer UseResource (or ui.UseQuery for cached, tag-invalidated data); it remains only for legacy callers.

Basic usage:

import (
    "context"

    "github.com/monstercameron/GoWebComponents/v4/fetch"
)

func UserList() ui.Node {
    resource := fetch.UseResource(func(ctx context.Context) (string, error) {
        return fetchUsers(ctx) // your typed loader
    })
    state := resource.Get()

    if state.Loading {
        return html.Div(html.Props{}, html.P(html.Props{}, html.Text("Loading...")))
    }

    if state.Err != nil {
        return html.Div(html.Props{}, html.P(html.Props{}, html.Text("Error: "+state.Err.Error())))
    }

    refresh := ui.UseEvent(func() {
        resource.Reload()
    })
    return html.Div(html.Props{},
        html.H1(html.Props{}, html.Text("Users")),
        html.Pre(html.Props{}, html.Text(state.Data)),
        html.Button(html.Props{OnClick: refresh}, html.Text("Refresh")),
    )
}

Available functions:

  • UseResource: Typed async resource hook for context-aware loaders
  • UseCachedResource: Shared typed cache hook with stale-while-revalidate behavior
  • UseQuery: Tag-aware cached query hook with optimistic rollback helpers
  • UseInfiniteQuery: Cached paginated query hook for load-more and infinite-scroll views
  • InvalidateQueryTag / InvalidateQueryTags: Mark related cached queries stale by tag
  • UseWebSocket: Bounded WebSocket hook with reconnect, backoff, and optional heartbeat
  • UseEventSource: Bounded EventSource hook with reconnect, backoff, and heartbeat timeout tracking
  • OpenMutationQueue: Durable queued write storage plus replay helpers for offline workflows
  • Fetch: Low-level fetch function returning a channel for manual control
  • UseFetch (deprecated): Raw fetch state hook — prefer UseResource

The UseFetch hook (deprecated — prefer UseResource):

  • Manages loading, error, and raw response data states
  • Returns a handle with Get and Refetch methods
  • Leaves response parsing and higher-level orchestration under caller control

The UseResource hook:

  • Accepts a loader of type func(context.Context) (T, error)
  • Returns a typed handle with Get, Reload, and Cancel methods
  • Cancels in-flight work when the component unmounts or dependencies change

The UseCachedResource hook:

  • Accepts a stable cache key plus a loader of type func(context.Context) (T, error)
  • Returns a typed handle with Get, Reload, Cancel, Invalidate, Set, and Update methods
  • Reuses cached values across components, deduplicates in-flight reloads, and keeps ready data visible during background refreshes

UseQuery is the higher-level cache API for application data. It keeps the same typed state shape as UseCachedResource, adds normalized tags for invalidating related queries together, and exposes OptimisticUpdate rollback handles for mutation flows. UseInfiniteQuery stores pages under one cache key and appends additional pages with LoadNext while preserving the same tag and optimistic-update behavior.

The realtime hooks:

  • Return handles with bounded RealtimeState snapshots
  • Keep only the newest MaxMessages and MaxErrors entries
  • Reconnect with capped exponential backoff
  • Compile on non-browser targets with RealtimeUnsupported state

For more control, use the Fetch function directly:

ch := fetch.Fetch("/api/data", fetch.Options{
    Method: "POST",
    Headers: map[string]interface{}{"Content-Type": "application/json"},
    Body: `{"key": "value"}`,
})
result := <-ch
if result.Err != nil {
    // Handle error
}
// Use result.Data

Index

Constants

View Source
const CacheBootstrapDataKey = "fetchCache"

Variables

View Source
var ErrCircuitOpen = errors.New("fetch: circuit breaker is open")

ErrCircuitOpen is returned by ExecuteWithPolicy when the circuit breaker is in the open state and is not yet eligible to transition to half-open.

Functions

func BuildFetchService

func BuildFetchService() pluginruntime.FetchService

BuildFetchService returns one fetch-cache interposer service.

func ConfigurePersistentCache

func ConfigurePersistentCache(parseOptions PersistentCacheOptions)

ConfigurePersistentCache sets the options for the persistent cache store, closing any existing store.

func DisposeQueryTag

func DisposeQueryTag(parseTag string) int

DisposeQueryTag clears all live cache entries registered for tag.

func DisposeResource

func DisposeResource(parseKey string)

DisposeResource clears the named cached resource and drops its registry entry.

func ExecuteWithPolicy

func ExecuteWithPolicy[T any](parseCtx context.Context, parsePolicy ResiliencePolicy, parseOp func(context.Context) (T, error)) (T, error)

ExecuteWithPolicy runs parseOp under the retry and circuit-breaker rules described by parsePolicy. It is generic so the caller keeps type safety without casting the result.

Execution order:

  1. If the circuit breaker is open, return immediately with ErrCircuitOpen.
  2. Call parseOp. On success, record success and return.
  3. On error, consult RetryIf; if it returns false, record failure and return.
  4. Record the failure, then sleep (respecting context cancellation).
  5. Repeat up to RetryPolicy.MaxAttempts times, then return the last error.

func Fetch

func Fetch(parseUrl string, parseOptions Options) <-chan Result

Fetch performs an asynchronous HTTP fetch operation on non-browser builds.

func InvalidateQueryTag

func InvalidateQueryTag(parseTag string) int

InvalidateQueryTag marks all live queries with tag stale.

func InvalidateQueryTags

func InvalidateQueryTags(parseTags ...string) int

InvalidateQueryTags marks all live queries with any supplied tag stale.

func InvalidateResource

func InvalidateResource(parseKey string)

InvalidateResource marks the named cached resource stale.

func IsMutationConflict

func IsMutationConflict(parseErr error) bool

IsMutationConflict reports whether err unwraps to a MutationConflictError.

func LoadCached

func LoadCached[T any](parseCtx context.Context, parseKey string, parseLoader func(context.Context) (T, error), parseOptions ...CacheOptions) (T, error)

LoadCached reuses the shared cache from imperative code such as route loaders.

func LoadQuery

func LoadQuery[T any](parseCtx context.Context, parseKey string, parseLoader func(context.Context) (T, error), parseOptions ...QueryOptions) (T, error)

LoadQuery reuses the shared cache from imperative code and registers query tags.

func NewMutationConflict

func NewMutationConflict(parseErr error, parseConflict MutationConflict) error

NewMutationConflict wraps err with structured conflict metadata, returning a *MutationConflictError.

func QueryKeysForTag

func QueryKeysForTag(parseTag string) []string

QueryKeysForTag returns sorted cache keys registered for a tag.

func QueryTagsForKey

func QueryTagsForKey(parseKey string) []string

QueryTagsForKey returns sorted tags registered for one cache key.

func RestoreCacheBootstrap

func RestoreCacheBootstrap(parsePayload ui.SSRBootstrap) error

RestoreCacheBootstrap seeds shared cached resources from a UI bootstrap payload.

func ReturnChannel deprecated

func ReturnChannel(parseCh <-chan Result)

ReturnChannel returns a fetch result channel to the pool for reuse. With the new implementation channels are one-shot, so this is a no-op kept for API compatibility.

Deprecated: channels are now one-shot and do not need to be returned. This function is a no-op and will be removed in a future release.

func ScopeCacheKey

func ScopeCacheKey(parseSegments ...string) string

ScopeCacheKey builds a cache key namespaced under a module or feature prefix, the recommended convention for avoiding accidental cross-component sharing in the app-global cache namespace (see UseCachedResource). Empty segments are dropped, so ScopeCacheKey("billing", "invoices") returns "billing:invoices".

res := fetch.UseCachedResource(fetch.ScopeCacheKey("billing", "invoices"), loadInvoices)

Two unrelated components that both pick the bare key "list" would share one cache entry; scoping each under its own module prefix keeps them independent.

func SweepCachedResources

func SweepCachedResources() int

SweepCachedResources clears expired or idle cache entries and returns the number removed.

func Upload

func Upload(parseCtx context.Context, parseUrl string, parseOptions Options) <-chan UploadUpdate

Upload performs an upload operation on non-browser builds.

Types

type AsyncResource

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

AsyncResource exposes the current typed resource state and lifecycle controls.

func UseResource

func UseResource[T any](parseLoader func(context.Context) (T, error), parseDeps ...any) AsyncResource[T]

UseResource provides a typed async resource hook driven by a Go loader.

The loader runs on mount and whenever deps or the reload token change. It receives a context that is cancelled when the component unmounts, the dependency list changes, or Cancel is called on the returned handle.

func (AsyncResource[T]) Cancel

func (parseR AsyncResource[T]) Cancel()

Cancel cancels the active resource load, if any.

func (AsyncResource[T]) Get

func (parseR AsyncResource[T]) Get() ResourceState[T]

Get returns the current typed resource state.

func (AsyncResource[T]) Reload

func (parseR AsyncResource[T]) Reload()

Reload starts a new resource load.

type BreakerConfig

type BreakerConfig struct {
	// FailureThreshold is the consecutive-failure count that trips the breaker.
	FailureThreshold int

	// OpenDuration is how long the breaker stays open before probing with
	// half-open calls.
	OpenDuration time.Duration

	// HalfOpenMaxCalls is the maximum number of calls allowed in the half-open
	// state before the breaker re-opens (if all half-open calls succeed, it
	// instead resets to closed). Zero or negative values allow unlimited
	// half-open probes until a probe records success or failure.
	HalfOpenMaxCalls int
}

BreakerConfig holds the tuning parameters for a CircuitBreaker.

type BreakerState

type BreakerState int

BreakerState represents the operational state of a CircuitBreaker.

const (
	// StateClosed means the circuit breaker is healthy and allows all calls.
	StateClosed BreakerState = iota

	// StateOpen means the circuit breaker has tripped and fast-fails all calls.
	StateOpen

	// StateHalfOpen means the circuit breaker is probing whether the downstream
	// is healthy again, allowing a limited number of calls through.
	StateHalfOpen
)

func (BreakerState) String

func (parseState BreakerState) String() string

String returns the breaker state name ("closed", "open", "half-open") so the state reads cleanly in logs and %v formatting instead of as a bare integer.

type CacheBootstrap

type CacheBootstrap struct {
	Entries []CacheBootstrapEntry `json:"entries,omitempty"`
}

type CacheBootstrapEntry

type CacheBootstrapEntry struct {
	Key          string            `json:"key,omitempty"`
	Value        any               `json:"value,omitempty"`
	UpdatedAt    time.Time         `json:"updatedAt"`
	ResumePolicy CacheResumePolicy `json:"resumePolicy,omitempty"`
	StaleAfter   time.Duration     `json:"staleAfter,omitempty"`
}

type CacheOptions

type CacheOptions struct {
	StaleAfter   time.Duration
	MaxAge       time.Duration
	DisposeAfter time.Duration
	Persist      bool
}

type CacheResumePolicy

type CacheResumePolicy string
const (
	CacheResumeTrustOnce            CacheResumePolicy = "trust-once"
	CacheResumeStaleWhileRevalidate CacheResumePolicy = "stale-while-revalidate"
	CacheResumeAlwaysRefetch        CacheResumePolicy = "always-refetch"
)

type CachedResource

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

CachedResource exposes shared cached resource state and mutation helpers.

func UseCachedResource

func UseCachedResource[T any](parseKey string, parseLoader func(context.Context) (T, error), parseOptions ...CacheOptions) CachedResource[T]

UseCachedResource binds a component to an app-global cached resource keyed by parseKey, loading it through parseLoader on first use and sharing the result across every caller of the same key.

Global-namespace contract: cache keys live in one process-wide registry, not a per-component or per-module scope. Two unrelated components that choose the same key string therefore share the same cache entry, loader lifecycle, and value. This is intentional - it is how distant components share one fetch - but it means key strings are effectively global identifiers. Requesting one key with two different value types is reported as a diagnostic warning rather than silently corrupting state, so a type mismatch is visible.

Recommended convention: prefix keys with a stable module or feature name so unrelated features cannot collide. Use ScopeCacheKey to build them, for example ScopeCacheKey("billing", "invoices") instead of a bare "invoices".

func (CachedResource[T]) Cancel

func (parseR CachedResource[T]) Cancel()

Cancel cancels the active cached resource load, if any.

func (CachedResource[T]) Dispose

func (parseR CachedResource[T]) Dispose()

Dispose clears the cached value and removes the keyed entry from the shared registry.

func (CachedResource[T]) Get

func (parseR CachedResource[T]) Get() CachedResourceState[T]

Get returns the current cached resource state.

func (CachedResource[T]) Invalidate

func (parseR CachedResource[T]) Invalidate()

Invalidate marks the cached value stale and eligible for revalidation.

func (CachedResource[T]) OptimisticUpdate

func (parseR CachedResource[T]) OptimisticUpdate(parseFn func(T) T) OptimisticUpdate[T]

OptimisticUpdate applies an optimistic resource update and returns a rollback handle.

func (CachedResource[T]) Reload

func (parseR CachedResource[T]) Reload()

Reload starts a new cached resource load.

func (CachedResource[T]) Set

func (parseR CachedResource[T]) Set(parseValue T)

Set replaces the cached value optimistically.

func (CachedResource[T]) Update

func (parseR CachedResource[T]) Update(parseFn func(T) T)

Update replaces the cached value using the previous value.

type CachedResourceInspection

type CachedResourceInspection struct {
	Key             string
	Tags            []string
	Loading         bool
	Ready           bool
	Stale           bool
	LastError       string
	UpdatedAt       time.Time
	LastLoaded      time.Time
	SubscriberCount int
	OwnerPaths      []string
	ResumePolicy    CacheResumePolicy
}

func InspectCachedResources

func InspectCachedResources() []CachedResourceInspection

InspectCachedResources returns a stable snapshot of shared cache state for diagnostics and devtools.

type CachedResourceState

type CachedResourceState[T any] struct {
	Value     T
	Loading   bool
	Error     error
	Ready     bool
	Stale     bool
	UpdatedAt time.Time
}

CachedResourceState describes the current state of a shared cached resource.

type CircuitBreaker

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

CircuitBreaker protects a downstream dependency by tracking consecutive failures and temporarily refusing calls once a failure threshold is crossed. The zero value is not valid; use NewCircuitBreaker.

func NewCircuitBreaker

func NewCircuitBreaker(parseConfig BreakerConfig) *CircuitBreaker

NewCircuitBreaker constructs a CircuitBreaker with the supplied configuration and a real wall-clock source. Inject a synthetic clock via setNow for tests.

func (*CircuitBreaker) State

func (parseB *CircuitBreaker) State() BreakerState

State returns the current BreakerState without modifying any internal fields.

type DurableMutationRunner

type DurableMutationRunner[T any] func(parseOptimistic T, parseDraft MutationDraft, parseCommit func(context.Context, QueuedMutation) (T, error)) (QueuedMutation, error)

DurableMutationRunner applies a mutation that is BOTH optimistic and durable: it updates the query cache immediately (so the UI reacts now) and enqueues the write to the persistent MutationQueue (so it survives a reload or offline gap). It returns the queued entry and any enqueue error.

func UseDurableMutation

func UseDurableMutation[T any](parseCache *query.Cache, parseKey string, parseQueue MutationQueue) DurableMutationRunner[T]

UseDurableMutation bridges the optimistic query cache and the durable offline MutationQueue, which previously lived in separate packages with no link (the audit's FA2 gap). The returned runner: (1) durably enqueues the draft so the write is never lost; (2) applies the optimistic value to the cache and re-renders; (3) runs commit in the background — on success it clears the queue entry and commits the authoritative value, on failure it rolls the cache back and LEAVES the entry queued for later replay via MutationQueue.Replay. One call gives you optimistic UI, offline durability, and automatic reconciliation.

run := fetch.UseDurableMutation[int](appCache, "post/"+id+"/likes", queue)
onClick := func() {
    run(current+1, fetch.MutationDraft{Method: "POST", URL: "/api/like", Body: id},
        func(ctx context.Context, m fetch.QueuedMutation) (int, error) { return serverfn.Call(...) })
}

type EventSource

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

EventSource exposes a UseEventSource connection handle.

func UseEventSource

func UseEventSource(parseURL string, parseOptions ...EventSourceOptions) EventSource

UseEventSource opens a bounded browser EventSource connection for a component.

func (EventSource) Close

func (parseE EventSource) Close()

Close closes the EventSource connection and suppresses reconnects.

func (EventSource) Get

func (parseE EventSource) Get() RealtimeState

Get returns the current EventSource state snapshot.

func (EventSource) Open

func (parseE EventSource) Open()

Open starts or restarts the EventSource connection.

type EventSourceOptions

type EventSourceOptions struct {
	WithCredentials   bool
	Manual            bool
	DisableReconnect  bool
	MaxReconnects     int
	InitialBackoff    time.Duration
	MaxBackoff        time.Duration
	BackoffFactor     float64
	HeartbeatInterval time.Duration
	HeartbeatTimeout  time.Duration
	MaxMessages       int
	MaxErrors         int
	Now               func() time.Time
}

EventSourceOptions configures UseEventSource.

type HTTPError

type HTTPError struct {
	Status     int
	StatusText string
	Body       string
	Headers    map[string]string
}

HTTPError reports a non-success HTTP status while preserving the response metadata on Result.

func (HTTPError) Error

func (parseE HTTPError) Error() string

Error is a core package helper.

type InfiniteQuery

type InfiniteQuery[T any, C any] struct {
	// contains filtered or unexported fields
}

InfiniteQuery wraps cached paginated data and page-loading helpers.

func UseInfiniteQuery

func UseInfiniteQuery[T any, C any](parseKey string, parseLoader func(context.Context, QueryPageRequest[C]) (QueryPage[T, C], error), parseOptions ...InfiniteQueryOptions[C]) InfiniteQuery[T, C]

UseInfiniteQuery caches the first page and exposes LoadNext for pagination.

func (InfiniteQuery[T, C]) CacheKey

func (parseQ InfiniteQuery[T, C]) CacheKey() string

CacheKey returns the stable cache key behind this infinite query.

func (InfiniteQuery[T, C]) Cancel

func (parseQ InfiniteQuery[T, C]) Cancel()

Cancel cancels the active first-page query load, if any.

func (InfiniteQuery[T, C]) Dispose

func (parseQ InfiniteQuery[T, C]) Dispose()

Dispose clears the infinite query cache entry.

func (InfiniteQuery[T, C]) Get

func (parseQ InfiniteQuery[T, C]) Get() InfiniteQueryState[T, C]

Get returns the current infinite query state.

func (InfiniteQuery[T, C]) Invalidate

func (parseQ InfiniteQuery[T, C]) Invalidate()

Invalidate marks the infinite query stale and eligible for first-page revalidation.

func (InfiniteQuery[T, C]) LoadNext

func (parseQ InfiniteQuery[T, C]) LoadNext()

LoadNext loads and appends the next page when HasNext is true.

func (InfiniteQuery[T, C]) OptimisticUpdate

func (parseQ InfiniteQuery[T, C]) OptimisticUpdate(parseFn func(InfiniteQueryData[T, C]) InfiniteQueryData[T, C]) OptimisticUpdate[InfiniteQueryData[T, C]]

OptimisticUpdate applies an optimistic infinite-query update and returns a rollback handle.

func (InfiniteQuery[T, C]) Reload

func (parseQ InfiniteQuery[T, C]) Reload()

Reload reloads the first page and replaces currently cached pages.

func (InfiniteQuery[T, C]) Set

func (parseQ InfiniteQuery[T, C]) Set(parseValue InfiniteQueryData[T, C])

Set replaces the complete infinite query data optimistically.

func (InfiniteQuery[T, C]) Tags

func (parseQ InfiniteQuery[T, C]) Tags() []string

Tags returns the normalized tags registered for this infinite query.

func (InfiniteQuery[T, C]) Update

func (parseQ InfiniteQuery[T, C]) Update(parseFn func(InfiniteQueryData[T, C]) InfiniteQueryData[T, C])

Update replaces the complete infinite query data using the previous value.

type InfiniteQueryData

type InfiniteQueryData[T any, C any] struct {
	Pages      []QueryPage[T, C]
	Items      []T
	NextCursor C
	HasNext    bool
}

InfiniteQueryData is the cached value stored for an infinite query.

type InfiniteQueryOptions

type InfiniteQueryOptions[C any] struct {
	Cache         CacheOptions
	Tags          []string
	InitialCursor C
}

InfiniteQueryOptions configures UseInfiniteQuery.

type InfiniteQueryState

type InfiniteQueryState[T any, C any] struct {
	InfiniteQueryData[T, C]
	Loading   bool
	Error     error
	Ready     bool
	Stale     bool
	UpdatedAt time.Time
}

InfiniteQueryState describes the current state of a paginated query.

type MultipartBody

type MultipartBody struct {
	Fields map[string]string
	Files  []MultipartFile
}

MultipartBody describes a multipart form-data payload with text fields and browser files.

type MultipartFile

type MultipartFile struct {
	FieldName string
	File      ui.File
	Filename  string
}

MultipartFile describes one browser file to append to a multipart form-data body.

type MutationConflict

type MutationConflict struct {
	Code          string            `json:"code,omitempty"`
	Message       string            `json:"message,omitempty"`
	LocalVersion  string            `json:"localVersion,omitempty"`
	RemoteVersion string            `json:"remoteVersion,omitempty"`
	Fields        map[string]string `json:"fields,omitempty"`
}

func GetMutationConflict

func GetMutationConflict(parseErr error) (MutationConflict, bool)

GetMutationConflict returns the structured conflict details carried by err.

type MutationConflictError

type MutationConflictError struct {
	Conflict MutationConflict
	Err      error
}

func AsMutationConflictError

func AsMutationConflictError(parseErr error) (*MutationConflictError, bool)

AsMutationConflictError unwraps err into the structured MutationConflictError form.

func (*MutationConflictError) Error

func (parseE *MutationConflictError) Error() string

Error is a core package helper.

func (*MutationConflictError) Unwrap

func (parseE *MutationConflictError) Unwrap() error

Unwrap is a core package helper.

type MutationConflictResolution

type MutationConflictResolution struct {
	Action  MutationResolutionAction
	Draft   MutationDraft
	Message string
}

type MutationDraft

type MutationDraft struct {
	ID       string            `json:"id,omitempty"`
	Kind     string            `json:"kind,omitempty"`
	DedupKey string            `json:"dedupKey,omitempty"`
	Method   string            `json:"method,omitempty"`
	URL      string            `json:"url,omitempty"`
	Headers  map[string]string `json:"headers,omitempty"`
	Body     any               `json:"body,omitempty"`
	Metadata map[string]string `json:"metadata,omitempty"`
}

MutationDraft describes one app-owned write to persist for later replay.

type MutationExecutor

type MutationExecutor func(context.Context, QueuedMutation) error

MutationExecutor performs the authoritative replay for one queued mutation.

type MutationQueue

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

MutationQueue persists writes locally and replays them later through an app-owned executor.

func OpenMutationQueue

func OpenMutationQueue(parseOptions ...MutationQueueOptions) (MutationQueue, error)

OpenMutationQueue opens the persistent mutation queue backed by browser storage.

func (MutationQueue) Clear

func (parseQ MutationQueue) Clear() error

Clear removes every persisted queue entry.

func (MutationQueue) Enqueue

func (parseQ MutationQueue) Enqueue(parseDraft MutationDraft) (QueuedMutation, error)

Enqueue stores a write for later replay, suppressing duplicates that share the same dedup key.

func (MutationQueue) List

func (parseQ MutationQueue) List() ([]QueuedMutation, error)

List returns all currently persisted queue entries in creation order.

func (MutationQueue) Remove

func (parseQ MutationQueue) Remove(parseId string) error

Remove deletes one queue entry by id.

func (MutationQueue) Replay

func (parseQ MutationQueue) Replay(parseCtx context.Context, parseExecutor MutationExecutor) (MutationReplayReport, error)

Replay replays due entries through the provided executor and persists the updated queue state.

func (MutationQueue) ReplayWithOptions

func (parseQ MutationQueue) ReplayWithOptions(parseCtx context.Context, parseExecutor MutationExecutor, parseOptions ...MutationReplayOptions) (MutationReplayReport, error)

ReplayWithOptions replays due entries and applies optional conflict-resolution policy.

type MutationQueueOptions

type MutationQueueOptions struct {
	StorageKey         string
	MaxAttempts        int
	BaseDelay          time.Duration
	MaxDelay           time.Duration
	DeleteOnCorruption bool
	StoreResolver      func(context.Context) (interop.PersistentStore, error)
	StorageResolver    func() (interop.Storage, error)
	Now                func() time.Time
}

MutationQueueOptions configures persistent queue behavior.

type MutationReplayOptions

type MutationReplayOptions struct {
	ConflictHandler MutationConflictHandler
}

type MutationReplayReport

type MutationReplayReport struct {
	Succeeded   int
	Deferred    int
	Retried     int
	DeadLetters int
	Conflicts   int
	Resolved    int
	Remaining   int
}

MutationReplayReport summarizes one replay pass across queued entries.

type MutationResolutionAction

type MutationResolutionAction string
const (
	MutationResolutionRetry   MutationResolutionAction = "retry"
	MutationResolutionDead    MutationResolutionAction = "dead"
	MutationResolutionRemove  MutationResolutionAction = "remove"
	MutationResolutionReplace MutationResolutionAction = "replace"
)

type MutationState

type MutationState string
const (
	MutationQueued   MutationState = "queued"
	MutationRetrying MutationState = "retrying"
	MutationDead     MutationState = "dead"
)

type OptimisticUpdate

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

OptimisticUpdate can roll back one optimistic cache write.

func ApplyOptimisticUpdate

func ApplyOptimisticUpdate[T any](parseKey string, parseFn func(T) T) OptimisticUpdate[T]

ApplyOptimisticUpdate updates a cache entry and returns a rollback handle.

func (OptimisticUpdate[T]) Active

func (parseU OptimisticUpdate[T]) Active() bool

Active reports whether the optimistic update can still be committed or rolled back.

func (*OptimisticUpdate[T]) Commit

func (parseU *OptimisticUpdate[T]) Commit()

Commit makes the optimistic update final and disables rollback.

func (*OptimisticUpdate[T]) Rollback

func (parseU *OptimisticUpdate[T]) Rollback()

Rollback restores the cache snapshot captured before the optimistic update.

type Options

type Options struct {
	Method string
	// Headers are request headers. Values are typed any (not string) so callers can pass
	// non-string values that are stringified at send time; response headers in Result are
	// always plain strings.
	Headers map[string]any
	Body    any
}

Options represents configuration for HTTP fetch operations.

type PersistentCacheOptions

type PersistentCacheOptions struct {
	DatabaseName     string
	StoreName        string
	FallbackResolver func() (interop.Storage, error)
	FallbackBackend  string
	StoreResolver    func(context.Context) (interop.PersistentStore, error)
}

type Query

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

Query wraps a cached resource with query metadata such as tags.

func UseQuery

func UseQuery[T any](parseKey string, parseLoader func(context.Context) (T, error), parseOptions ...QueryOptions) Query[T]

UseQuery is a tag-aware wrapper around UseCachedResource.

func (Query[T]) CacheKey

func (parseQ Query[T]) CacheKey() string

CacheKey returns the stable cache key behind this query.

func (Query[T]) Cancel

func (parseQ Query[T]) Cancel()

Cancel cancels the active query load, if any.

func (Query[T]) Dispose

func (parseQ Query[T]) Dispose()

Dispose clears the query cache entry.

func (Query[T]) Get

func (parseQ Query[T]) Get() CachedResourceState[T]

Get returns the current query state.

func (Query[T]) Invalidate

func (parseQ Query[T]) Invalidate()

Invalidate marks the query stale and eligible for revalidation.

func (Query[T]) OptimisticUpdate

func (parseQ Query[T]) OptimisticUpdate(parseFn func(T) T) OptimisticUpdate[T]

OptimisticUpdate applies an optimistic query update and returns a rollback handle.

func (Query[T]) Reload

func (parseQ Query[T]) Reload()

Reload starts a new query load.

func (Query[T]) Set

func (parseQ Query[T]) Set(parseValue T)

Set replaces the query value optimistically.

func (Query[T]) Tags

func (parseQ Query[T]) Tags() []string

Tags returns the normalized tags registered for this query.

func (Query[T]) Update

func (parseQ Query[T]) Update(parseFn func(T) T)

Update replaces the query value using the previous value.

type QueryOptions

type QueryOptions struct {
	Cache CacheOptions
	Tags  []string
}

QueryOptions configures the ergonomic query wrapper around UseCachedResource.

type QueryPage

type QueryPage[T any, C any] struct {
	Items      []T
	NextCursor C
	HasNext    bool
}

QueryPage is one page of an infinite query result.

type QueryPageRequest

type QueryPageRequest[C any] struct {
	Cursor    C
	PageIndex int
}

QueryPageRequest describes one page load for UseInfiniteQuery.

type QueuedMutation

type QueuedMutation struct {
	ID            string            `json:"id,omitempty"`
	Kind          string            `json:"kind,omitempty"`
	DedupKey      string            `json:"dedupKey,omitempty"`
	Method        string            `json:"method,omitempty"`
	URL           string            `json:"url,omitempty"`
	Headers       map[string]string `json:"headers,omitempty"`
	Body          any               `json:"body,omitempty"`
	Metadata      map[string]string `json:"metadata,omitempty"`
	State         MutationState     `json:"state,omitempty"`
	Attempts      int               `json:"attempts,omitempty"`
	MaxAttempts   int               `json:"maxAttempts,omitempty"`
	CreatedAt     time.Time         `json:"createdAt"`
	UpdatedAt     time.Time         `json:"updatedAt"`
	NextAttemptAt time.Time         `json:"nextAttemptAt"`
	LastError     string            `json:"lastError,omitempty"`
}

QueuedMutation is the persisted replay record stored in the mutation queue.

type RealtimeError

type RealtimeError struct {
	Message string
	At      time.Time
}

RealtimeError stores one recent realtime transport error.

type RealtimeMessage

type RealtimeMessage struct {
	Data        string
	Type        string
	LastEventID string
	ReceivedAt  time.Time
}

RealtimeMessage stores one received WebSocket or EventSource message.

type RealtimeState

type RealtimeState struct {
	Status            RealtimeStatus
	Supported         bool
	Connecting        bool
	Open              bool
	Closed            bool
	Messages          []RealtimeMessage
	LastMessage       RealtimeMessage
	Errors            []RealtimeError
	Error             error
	ConnectAttempts   int
	ReconnectAttempts int
	Reconnects        int
	NextReconnectAt   time.Time
	LastOpenAt        time.Time
	LastCloseAt       time.Time
	LastHeartbeatAt   time.Time
	HeartbeatMisses   int
}

RealtimeState is the bounded state snapshot returned by realtime hooks.

type RealtimeStatus

type RealtimeStatus string

RealtimeStatus describes the current lifecycle phase for a realtime hook.

const (
	// RealtimeIdle means the hook has not opened a browser transport yet.
	RealtimeIdle RealtimeStatus = "idle"
	// RealtimeConnecting means a browser transport is being opened.
	RealtimeConnecting RealtimeStatus = "connecting"
	// RealtimeOpen means the browser transport is currently open.
	RealtimeOpen RealtimeStatus = "open"
	// RealtimeReconnecting means the hook is waiting for a bounded reconnect attempt.
	RealtimeReconnecting RealtimeStatus = "reconnecting"
	// RealtimeClosed means the transport is closed and no reconnect is pending.
	RealtimeClosed RealtimeStatus = "closed"
	// RealtimeUnsupported means the browser API is unavailable on this target.
	RealtimeUnsupported RealtimeStatus = "unsupported"
)

type ResiliencePolicy

type ResiliencePolicy struct {
	// Retry controls backoff and attempt limits.
	Retry RetryPolicy

	// Breaker, when non-nil, gates every call through circuit-breaker logic.
	Breaker *CircuitBreaker
	// contains filtered or unexported fields
}

ResiliencePolicy bundles a RetryPolicy and an optional CircuitBreaker into a single unit that ExecuteWithPolicy uses to drive resilient operation calls. Construct one with NewResiliencePolicy.

func NewResiliencePolicy

func NewResiliencePolicy(parseRetry RetryPolicy, parseBreaker *CircuitBreaker) ResiliencePolicy

NewResiliencePolicy constructs a ResiliencePolicy wired to real-time sleep and real random jitter. Pass the result to ExecuteWithPolicy.

type Resource

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

Resource exposes the current low-level fetch state and a refetch helper.

func UseFetch deprecated

func UseFetch(parseUrl string, parseOptions ...Options) Resource

UseFetch is a hook that simplifies data fetching within a component. It uses the runtime fetch hook directly.

Deprecated: prefer the typed UseResource[T] (a Go loader returning a typed value) or ui.UseQuery (cache + dedupe + stale-while-revalidate). UseFetch remains for a quick untyped URL GET.

func (Resource) Get

func (parseR Resource) Get() State

Get returns the current low-level fetch state.

func (Resource) Refetch

func (parseR Resource) Refetch()

Refetch restarts the underlying fetch request.

type ResourceState

type ResourceState[T any] struct {
	Value   T
	Loading bool
	Error   error
	Ready   bool
}

ResourceState describes the state of a typed async resource.

type Result

type Result struct {
	Data   any
	Status int
	// Headers are response headers, always plain strings (unlike Options.Headers, whose
	// values are typed any for request-side flexibility).
	Headers map[string]string
	Err     error
}

Result represents the result of a manual Fetch operation.

func (Result) DecodeJSON

func (parseR Result) DecodeJSON(parseTarget any) error

DecodeJSON decodes a string-backed response body into target.

func (Result) Text

func (parseR Result) Text() string

Text returns the response body when it is string-backed.

type RetryPolicy

type RetryPolicy struct {
	// MaxAttempts is the total number of times the operation may be called,
	// including the first attempt. Zero or negative values disable retries.
	MaxAttempts int

	// BaseDelay is the wait time before the second attempt.
	BaseDelay time.Duration

	// MaxDelay caps the computed backoff delay so it never grows unboundedly.
	MaxDelay time.Duration

	// Multiplier scales the delay between successive retries. A value of 2.0
	// doubles the delay after each failure. A zero multiplier is honored as
	// zero, so attempts after the second compute a zero delay; prefer
	// DefaultRetryPolicy or an explicit positive multiplier for real backoff.
	Multiplier float64

	// Jitter is a fractional spread added to each delay to prevent thundering
	// herds. A value of 0.1 allows a ±10 % random spread around the base delay.
	Jitter float64

	// RetryIf, when non-nil, is called with each error to decide whether the
	// operation should be retried. Returning false stops retrying immediately
	// and surfaces the error to the caller. When nil, all errors are retried.
	RetryIf func(error) bool
}

RetryPolicy describes how ExecuteWithPolicy retries a failing operation, using exponential backoff with optional jitter.

func DefaultRetryPolicy

func DefaultRetryPolicy() RetryPolicy

DefaultRetryPolicy returns a RetryPolicy suitable for most HTTP operations: three attempts, 100 ms base delay doubling up to 5 s, with 10 % jitter and no error filter (all errors are retried).

type State

type State = runtime.FetchState

State represents the state of a fetch operation managed by UseFetch.

type UploadUpdate

type UploadUpdate struct {
	Loaded           int64
	Total            int64
	LengthComputable bool
	Done             bool
	Result           Result
}

UploadUpdate reports upload progress and the final upload result.

type WebSocket

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

WebSocket exposes a UseWebSocket connection handle.

func UseWebSocket

func UseWebSocket(parseURL string, parseOptions ...WebSocketOptions) WebSocket

UseWebSocket opens a bounded browser WebSocket connection for a component.

func (WebSocket) Close

func (parseW WebSocket) Close()

Close closes the WebSocket connection and suppresses reconnects.

func (WebSocket) Get

func (parseW WebSocket) Get() RealtimeState

Get returns the current WebSocket state snapshot.

func (WebSocket) Open

func (parseW WebSocket) Open()

Open starts or restarts the WebSocket connection.

func (WebSocket) Send

func (parseW WebSocket) Send(parseMessage string) error

Send sends one text message through the active WebSocket connection.

type WebSocketOptions

type WebSocketOptions struct {
	Protocols         []string
	Manual            bool
	DisableReconnect  bool
	MaxReconnects     int
	InitialBackoff    time.Duration
	MaxBackoff        time.Duration
	BackoffFactor     float64
	HeartbeatInterval time.Duration
	HeartbeatTimeout  time.Duration
	HeartbeatMessage  string
	MaxMessages       int
	MaxErrors         int
	Now               func() time.Time
}

WebSocketOptions configures UseWebSocket.

Jump to

Keyboard shortcuts

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