API reference/fetchium

fetchium

fetchium

API reference for the main fetchium package — a data-fetching and query layer built on Signalium's reactive primitives.

ts
import {
  Query,
  QueryAdapter,
  fetchQuery,
  queryKeyForClass,
  Mutation,
  getMutation,
  mutationKeyForClass,
  Entity,
  QueryClient,
  NetworkManager,
  NoOpNetworkManager,
  GcManager,
  NoOpGcManager,
  t,
  registerFormat,
  draft,
  QueryClientContext,
  NetworkManagerContext,
} from 'fetchium';

// REST adapter (JSON REST APIs)
import { RESTQuery, RESTMutation, RESTQueryAdapter } from 'fetchium/rest';

Classes

Query (abstract)

Base class for all query definitions. Extend this to define custom data-fetching logic.

Static properties

PropertyTypeDescription
cacheQueryCacheOptions | undefinedClass-level persistent cache settings (maxCount, cacheTime).

Static properties

PropertyTypeDescription
cacheQueryCacheOptions | undefinedClass-level persistent cache settings (maxCount, cacheTime).
adaptertypeof QueryAdapter(required) The adapter class responsible for sending requests. Set automatically on RESTQuery. Custom query types must set this to their own adapter class.

Instance properties

PropertyTypeDescription
paramsRecord<string, TypeDef> | undefinedShape definition for query parameters.
resultTypeDefShape(abstract) Shape definition for the query result.
configQueryConfigOptions | undefinedInstance-level configuration (gcTime, staleTime, retry, etc.).
contextQueryContextThe query context provided by the QueryClient. Available in getConfig() and other methods.

Methods

MethodSignatureDescription
getIdentityKey(): unknown(abstract) Returns a value used to compute the cache/identity key for this query class.
refetch(): voidTriggers a refetch of this query, bypassing staleTime.
getConfig(): QueryConfigOptions | undefinedOptional. Dynamically compute config at execution time.

RESTQuery extends Query

Convenience base class for REST/JSON queries. Handles URL construction, search params, body serialization, and pagination.

Instance properties

PropertyTypeDefaultDescription
method'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH''GET'HTTP method.
pathstring | undefinedURL path. Use template literal interpolation with this.params references.
searchParamsRecord<string, unknown> | undefinedQuery string parameters.
bodyRecord<string, unknown> | undefinedRequest body (JSON-serialized).
headersHeadersInit | undefinedCustom HTTP headers.
requestOptionsQueryRequestOptions | undefinedAdditional fetch options (credentials, mode, baseUrl, etc.).
fetchNextFetchNextConfig | undefinedStatic pagination config. Values can be FieldRefs (e.g. this.result.nextCursor).
responseResponse | undefinedThe raw HTTP Response from the last fetch. Set by RESTQueryAdapter after each request completes. Available in getConfig().

getIdentityKey() default

Returns "${method}:${path}".

Optional method overrides

MethodSignatureDescription
getPath(): string | undefinedDynamically compute the URL path.
getMethod(): stringDynamically compute the HTTP method.
getSearchParams(): Record<string, unknown> | undefinedDynamically compute search params.
getBody(): Record<string, unknown> | undefinedDynamically compute the request body.
getRequestOptions(): QueryRequestOptions | undefinedDynamically compute fetch options.
getFetchNext(): FetchNextConfig | undefinedDynamically compute pagination config. Takes priority over the static fetchNext field.

Example

ts
class GetUser extends RESTQuery {
  params = { id: t.string };

  path = `/api/users/${this.params.id}`;

  result = {
    id: t.id,
    name: t.string,
    email: t.string,
  };
}

Entity

Base class for entity definitions. Entities are normalized, identity-stable proxy objects managed by the QueryClient.

Static properties

PropertyTypeDescription
cache{ gcTime?: number } | undefinedIn-memory GC time in minutes. 0 = next-tick eviction, Infinity = never GC.

Optional instance methods

MethodSignatureDescription
__subscribe(onEvent: (event: MutationEvent) => void) => (() => void) | undefinedSubscribe to external mutation events for this entity (e.g. WebSocket push). Return a cleanup function.

Example

ts
class User extends Entity {
  static cache = { gcTime: 10 };

  __typename = t.typename('User');
  id = t.id;

  name = t.string;
  email = t.optional(t.string);
}

Mutation (abstract)

Base class for mutation definitions.

Static properties

PropertyTypeDescription
adaptertypeof QueryAdapter(required) The adapter class that handles sending this mutation. Set automatically on RESTMutation. Custom mutation types must set this to their own adapter class.

Instance properties

PropertyTypeDescription
paramsTypeDefShape | undefinedShape definition for mutation input parameters.
resultTypeDefShape | undefinedShape definition for the mutation response.
optimisticUpdatesboolean | undefinedWhen true, applies effects optimistically before the server responds.
configMutationConfigOptions | undefinedMutation configuration (retry settings).
effectsMutationEffects | undefinedStatic entity effects (creates, updates, deletes) and query invalidation.
contextQueryContextThe query context provided by the QueryClient.

Methods

MethodSignatureDescription
getIdentityKey(): unknown(abstract) Returns a value used to compute the mutation identity key.
getEffects(): MutationEffectsOptional. Dynamically compute entity effects at execution time.

RESTMutation extends Mutation

Convenience base class for REST/JSON mutations.

Instance properties

PropertyTypeDefaultDescription
pathstring | undefinedURL path.
method'POST' | 'PUT' | 'DELETE' | 'PATCH''POST'HTTP method.
bodyRecord<string, unknown> | undefinedRequest body shape. No body is sent if omitted.
headersHeadersInit | undefinedCustom HTTP headers.
requestOptionsQueryRequestOptions | undefinedAdditional fetch options.

getIdentityKey() default

Returns "${method}:${path}".

Optional method overrides

MethodSignatureDescription
getPath(): string | undefinedDynamically compute the URL path.
getMethod(): stringDynamically compute the HTTP method.
getBody(): Record<string, unknown> | undefinedDynamically compute the request body.
getRequestOptions(): QueryRequestOptions | undefinedDynamically compute fetch options.

QueryClient

Central coordinator for queries, mutations, entity storage, caching, and garbage collection.

Constructor

ts
new QueryClient(config: QueryClientConfig)
FieldTypeDefaultDescription
storeQueryStoreIn-memoryPersistent storage backend. Defaults to SyncQueryStore(MemoryPersistentStore).
adaptersQueryAdapter[][]Transport adapters (e.g. new RESTQueryAdapter({ fetch, baseUrl })).
logLogContext | undefinedconsoleLogger with error, warn, info, debug methods.
evictionMultipliernumber | undefined1Scales all GC times for testing. Set to 0.001 to make timers fire in milliseconds.
networkManagerNetworkManagernew NetworkManager()Tracks network connectivity.
gcManagerGcManager | NoOpGcManagerAuto-detectedGC manager. Uses NoOpGcManager on the server.

Methods

MethodSignatureDescription
getContext(): QueryContextReturns the QueryContext passed at construction.
applyMutationEvent(event: MutationEvent): voidApplies an external mutation event (create/update/delete) to the entity store.
invalidateQueries(targets: ReadonlyArray<InvalidateTarget>): voidMarks matching query instances as stale. Accepts query classes and optional param subsets for filtering.
destroy(): voidTears down the GC manager, network manager, and all caches.

QueryAdapter (abstract)

Base class for transport adapters. An adapter handles sending queries and mutations for all query/mutation classes that declare it via static adapter. Register adapters with QueryClient at construction time.

Methods

MethodSignatureDescription
register(queryClient: IQueryClientForAdapter): voidCalled once when the adapter is registered with a QueryClient. Override to do setup (e.g. open a WebSocket connection).
send(ctx: Query, signal: AbortSignal): Promise<unknown>(abstract) Send a query and return the raw response data.
sendNext(ctx: Query, signal: AbortSignal): Promise<unknown>Optional. Send the next-page request for a paginated query.
hasNext(ctx: Query): booleanOptional. Return true if more pages are available for the current result.
sendMutation(ctx: Mutation, signal: AbortSignal): Promise<unknown>Optional. Send a mutation and return the raw response data.
onNetworkStatusChange(isOnline: boolean): voidOptional. Called when the network comes online or goes offline.
destroy(): voidOptional. Called when the QueryClient is destroyed. Clean up connections or timers.

Protected properties

PropertyTypeDescription
queryClientIQueryClientForAdapter | undefinedSet by register(). Use to access the shared query context via this.queryClient.getContext().

Example

ts
import { QueryAdapter } from 'fetchium';
import type { Query } from 'fetchium';

class GraphQLAdapter extends QueryAdapter {
  async send(ctx: Query, signal: AbortSignal): Promise<unknown> {
    const q = ctx as GraphQLQuery;
    const response = await fetch('/graphql', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ query: q.query, variables: q.variables }),
      signal,
    });
    const json = await response.json();
    if (json.errors?.length) throw new Error(json.errors[0].message);
    return json.data;
  }
}

new QueryClient({
  store,
  adapters: [new GraphQLAdapter()],
});

RESTQueryAdapter extends QueryAdapter

Transport adapter for RESTQuery and RESTMutation. Handles URL construction, JSON serialization, search params, pagination, and baseUrl resolution.

Import from fetchium/rest.

Constructor

ts
new RESTQueryAdapter(options?: RESTQueryAdapterOptions)
OptionTypeDescription
fetch(url: string, init?: RequestInit) => Promise<Response>The fetch implementation to use. Defaults to globalThis.fetch.
baseUrlstring | Signal<string> | (() => string) | undefinedBase URL prepended to all request paths.

NetworkManager

Signal-based network connectivity tracker. Automatically detects browser online/offline events.

Constructor

ts
new NetworkManager(initialStatus?: boolean)
ParameterTypeDefaultDescription
initialStatusbooleanAuto-detectedInitial online status. If omitted, uses navigator.onLine.

Properties and methods

MemberType / SignatureDescription
isOnlineboolean (getter)Returns true if the network is currently online. Manual override takes precedence.
setNetworkStatus(online: boolean): voidManually set the network status.
clearManualOverride(): voidClear any manual override and return to automatic detection.
getOnlineSignal(): Signal<boolean>Returns the underlying reactive Signal for online status.
destroy(): voidRemoves event listeners and cleans up resources.

NoOpNetworkManager

SSR-safe no-op implementation of NetworkManager. Always reports isOnline = true.

MemberType / SignatureDescription
isOnlineboolean (getter)Always returns true.
setNetworkStatus(online: boolean): voidNo-op.
clearManualOverride(): voidNo-op.
getOnlineSignal(): Signal<boolean>Returns a static Signal(true).
destroy(): voidNo-op.

GcManager

Bucket-based in-memory garbage collection. Each unique gcTime gets its own interval with two rotating sets. Minimum eviction delay is approximately gcTime; maximum is approximately 2 * gcTime.

Constructor

ts
new GcManager(
  onEvict: (key: number, type: GcKeyType) => void,
  multiplier?: number,
)
ParameterTypeDefaultDescription
onEvict(key: number, type: GcKeyType) => voidCallback invoked when a key is evicted.
multipliernumber1Multiplier applied to gcTime intervals (useful for testing).

Methods

MethodSignatureDescription
schedule(key: number, gcTime: number, type: GcKeyType): voidSchedule a key for eviction. gcTime = 0 evicts on next microtask. gcTime = Infinity never evicts.
cancel(key: number, gcTime: number): voidCancel a pending eviction.
destroy(): voidClears all intervals and pending entries.

NoOpGcManager

No-op garbage collection manager. All methods are no-ops.

MethodSignature
schedule(key: number, gcTime: number, type: GcKeyType): void
cancel(key: number, gcTime: number): void
destroy(): void

Functions

fetchQuery

ts
function fetchQuery<T extends Query>(
  QueryClass: new () => T,
  params?: ExtractQueryParams<T>,
): QueryPromise<T>;

Fetches a query reactively. Must be called within a reactive context where QueryClientContext is provided. Returns a QueryPromise (a DiscriminatedReactivePromise) that resolves to the query result.

ParameterTypeDescription
QueryClassnew () => TThe query class to instantiate and execute.
paramsExtractQueryParams<T>Parameters matching the query's params shape. Optional if the query has no required params. Values can be Signalium Signals for reactive parameter changes.

Returns: QueryPromise<T> — a reactive promise with .value, .isPending, .isResolved, .isRejected, .error.


getMutation

ts
function getMutation<T extends Mutation>(
  MutationClass: new () => T,
): ReactiveTask<ExtractType<T['result']>, [ExtractType<T['params']>]>;

Returns a ReactiveTask for executing a mutation. Must be called within a reactive context where QueryClientContext is provided.

ParameterTypeDescription
MutationClassnew () => TThe mutation class to instantiate.

Returns: ReactiveTask — call .run(params) to execute the mutation.


queryKeyForClass

ts
function queryKeyForClass(cls: new () => Query, params: unknown): number;

Computes the numeric cache key for a query class and params combination. Useful for cache invalidation or inspection.


mutationKeyForClass

ts
function mutationKeyForClass(cls: new () => Mutation): string;

Returns the string identity key for a mutation class. Derived from the mutation's getIdentityKey().


registerFormat

ts
function registerFormat<Input extends Mask.STRING | Mask.NUMBER, T>(
  name: string,
  type: Input,
  parse: (value: Input extends Mask.STRING ? string : number) => T,
  serialize: (value: T) => Input extends Mask.STRING ? string : number,
  options?: { eager?: boolean },
): void;

Registers a custom format for use with t.format(name). Built-in formats include 'date' and 'date-time'.

ParameterTypeDescription
namestringFormat name. Use with t.format(name).
typeMask.STRING | Mask.NUMBERThe underlying wire type (string or number).
parse(value) => TConverts the raw wire value into the formatted type.
serialize(value) => wireConverts the formatted type back to the wire value.
options.eagerbooleanIf true (default), parsing runs eagerly during entity construction. If false, parsing is lazy.

To add TypeScript types for custom formats, use module augmentation:

ts
declare global {
  namespace SignaliumQuery {
    interface FormatRegistry {
      'my-format': MyType;
    }
  }
}

draft

ts
function draft<T>(value: T): Draft<T>;

Deep clones an entity or object, returning a plain mutable copy. The draft is not an entity proxy and can be freely modified before being passed to a mutation.

ParameterTypeDescription
valueTThe entity or object to clone.

Returns: Draft<T> — a recursively mutable deep clone.


The t Type DSL

The t object provides a declarative type definition DSL for describing query parameters, results, and entity shapes.

Primitive types

PropertyTypeDescription
t.stringTypeDef<string>String type.
t.numberTypeDef<number>Number type.
t.booleanTypeDef<boolean>Boolean type.
t.nullTypeDef<null>Null literal type.
t.undefinedTypeDef<undefined>Undefined literal type.
t.idTypeDef<string | number>Identity field marker. Marks the field as the entity's unique ID. Accepts string or number.

Composite types

MethodSignatureDescription
t.array(type: TypeDef<T>) => TypeDef<T[]>Array of the given element type.
t.object(shape: Record<string, TypeDef>) => TypeDef<...>Object with the given field shapes.
t.record(type: TypeDef<T>) => TypeDef<Record<string, T>>Record (dictionary) with string keys and values of the given type.
t.union(...types: TypeDef[]) => TypeDef<...>Discriminated union. Object types must have a typename field for discrimination.
t.entity(cls: new () => Entity) => TypeDef<Entity>Reference to a normalized entity type.

Modifiers

MethodSignatureDescription
t.optional(type: TypeDef<T>) => TypeDef<T | undefined>Makes a type optional (allows undefined).
t.nullable(type: TypeDef<T>) => TypeDef<T | null>Makes a type nullable (allows null).
t.nullish(type: TypeDef<T>) => TypeDef<T | undefined | null>Makes a type nullish (allows both undefined and null).

Constants and enums

MethodSignatureDescription
t.const(value: T) => TypeDef<T>Constant literal value.
t.enum(...values: T[]) => TypeDef<T[number]>Enum of allowed values (strings, numbers, or booleans).
t.enum.caseInsensitive(...values: T[]) => TypeDef<T[number]>Case-insensitive enum. String values match case-insensitively but return canonical casing.

Formats

MethodSignatureDescription
t.format(name: string) => TypeDef<FormatRegistry[name]>A formatted value. Built-in: 'date' (YYYY-MM-DD to Date), 'date-time' (ISO 8601 to Date).

Result parsing

MethodSignatureDescription
t.result(type: TypeDef<T>) => TypeDef<ParseResult<T>>Wraps a type in a ParseResult<T> ({ success: true, value: T } | { success: false, error: Error }). Individual fields that fail validation produce an error result instead of throwing.

Live data

MethodSignatureDescription
t.liveArray(entity: EntityClass | EntityClass[], opts?: LiveArrayOptions) => TypeDef<E[]>A live array that automatically updates when matching entities are created, updated, or deleted via mutation events.
t.liveValue(type: TypeDef<V>, entity: EntityClass | EntityClass[], opts: LiveValueOptions) => TypeDef<V>A live derived value that recomputes when matching entities change. Requires onCreate, onUpdate, and onDelete callbacks.

LiveArrayOptions<E>

PropertyTypeDescription
constraintsConstraintDef<E>Filter which entities are included. Can be a Record<string, unknown> or an array of [EntityClass, constraintMap] tuples. Constraint values can be FieldRefs.
sort(a: E, b: E) => numberSort comparator for the array.

LiveValueOptions<V, E>

PropertyTypeDescription
constraintsConstraintDef<E>Filter which entities trigger recomputation.
onCreate(value: V, entity: E) => VCalled when a matching entity is created. Returns the new value.
onUpdate(value: V, entity: E) => VCalled when a matching entity is updated. Returns the new value.
onDelete(value: V, entity: E) => VCalled when a matching entity is deleted. Returns the new value.

Contexts

ContextTypeDefaultDescription
QueryClientContextContext<QueryClient | undefined>undefinedSignalium context for the QueryClient. Must be provided for fetchQuery and getMutation to work.
NetworkManagerContextContext<NetworkManager>defaultNetworkManagerSignalium context for the NetworkManager.

Types

Query types

TypeDefinitionDescription
QueryPromise<T extends Query>DiscriminatedReactivePromise<QueryResult<T>>The return type of fetchQuery. A reactive promise.
QueryResult<T extends Query>ExtractType<T['result']> & { __refetch(), __fetchNext(), __hasNext, __isFetchingNext }The resolved value of a query. Includes pagination helpers.
QueryCacheOptions{ maxCount?: number; cacheTime?: number }Persistent storage cache settings. cacheTime is in minutes (default: 1440 / 24 hours). maxCount is the LRU queue size.
QueryConfigOptions{ gcTime?, staleTime?, debounce?, networkMode?, retry?, refreshStaleOnReconnect?, subscribe? }Instance-level query configuration. See property table below.
QueryRequestOptions{ baseUrl?, credentials?, mode?, cache?, redirect?, referrer?, referrerPolicy?, integrity?, keepalive?, signal? }Extended fetch options for individual queries.
QueryContext{ log?, evictionMultiplier? }Context object provided to the QueryClient.
QueryParamsRecord<string, string | number | boolean | undefined | null | Signal<...> | unknown[] | Record<string, unknown>>The shape of query parameters at runtime.
FetchNextConfig{ url?: unknown; searchParams?: Record<string, unknown> }Pagination configuration. Values can be FieldRefs.

QueryConfigOptions properties

PropertyTypeDefaultDescription
gcTimenumber5In-memory eviction time in minutes. 0 = next-tick, Infinity = never.
staleTimenumber0Milliseconds data is considered fresh. 0 = always stale.
debouncenumber0Milliseconds to debounce param-change refetches.
networkModeNetworkModeNetworkMode.OnlineWhen to allow fetching.
retryRetryConfig | number | boolean3 (client) / 0 (server)Retry configuration.
refreshStaleOnReconnectbooleantrueWhether to refetch stale queries when network reconnects.
subscribe(onEvent) => () => voidSubscribe to external events that should trigger refetches.

Mutation types

TypeDefinitionDescription
MutationConfigOptions{ retry?: RetryConfig | number | false }Mutation retry configuration.
MutationEffects{ creates?, updates?, deletes?, invalidates? }Mutation side effects. Entity effects are ReadonlyArray<readonly [EntityClassOrTypename, unknown]>. invalidates is ReadonlyArray<InvalidateTarget>.
InvalidateTargetQueryClass | readonly [QueryClass, Record<string, unknown>]Target for query invalidation. Class alone matches all instances; tuple with param subset matches only instances whose params contain those values.
MutationEventCreateEvent | UpdateEvent | DeleteEventUnion of mutation event types.
CreateEvent{ type: 'create'; typename: string; data: Record<string, unknown>; id?: unknown }Entity creation event.
UpdateEvent{ type: 'update'; typename: string; data: Record<string, unknown>; id?: unknown }Entity update event.
DeleteEvent{ type: 'delete'; typename: string; data: string | number | Record<string, unknown>; id?: unknown }Entity deletion event. data can be just the ID.

Network types

TypeDefinitionDescription
NetworkModeenum { Always, Online, OfflineFirst }Controls when queries are allowed to fetch.

NetworkMode values

ValueDescription
NetworkMode.AlwaysAlways fetch regardless of network status.
NetworkMode.OnlineOnly fetch when online (default).
NetworkMode.OfflineFirstFetch if cached data exists, even when offline.

Retry types

TypeDefinitionDescription
RetryConfig{ retries: number; retryDelay?: (attemptIndex: number) => number }Retry configuration. Default delay: exponential backoff (1000ms * 2^attempt).

Utility types

TypeDefinitionDescription
TypeDef<T>Branded phantom typeRepresents a type definition in the public API.
TypeDefShapeRecord<string, TypeDef> | TypeDefA shape for query results or mutation params.
ExtractType<T>Conditional typeExtracts the TypeScript type from a TypeDef<T>.
ExtractQueryParams<T>Conditional typeExtracts the params type from a Query subclass.
Draft<T>Recursive mapped typeRecursively removes readonly from all properties. Return type of draft().
ParseResult<T>ParseSuccess<T> | ParseErrorResult of t.result() parsing.
ParseSuccess<T>{ success: true; value: T }Successful parse.
ParseError{ success: false; error: Error }Failed parse.

Store types

TypeDefinitionDescription
QueryStoreInterfaceStorage backend interface. See stores/sync and stores/async.
CachedQuery{ value: unknown; refIds: Set<number> | undefined; updatedAt: number; preloadedEntities?: PreloadedEntityMap }Cached query data returned by QueryStore.loadQuery().
PreloadedEntityMapMap<number, Record<string, unknown>>Pre-loaded entity data for hydration.