Reactive data loaders and resource primitives for aihu.
createResourcefunction createResource<T>( key: Signal<string | null | undefined>, fetcher: (key: string) => Promise<T>, options?: ResourceOptions<T>, ): Resource<T>Create a reactive data resource.
createResourceSerializerfunction createResourceSerializer(store: ResourceStore): () => Record<string, unknown>Returns a serializer function compatible with SsrOptions.serializer.
createResourceStorefunction createResourceStore(): ResourceStoreWithMetaCreate a new in-memory ResourceStore backed by a plain Map.
datafunction data(_config?: Record<string, never>): PluginPlugin factory for `@aihu-plugin/data`.
ResourceStoreTokenconst ResourceStoreTokenContext token for the ResourceStore.
Resourceinterface Resource<T> {
readonly state: Signal<DataState<T>>
/** Immediately trigger a new fetch for the current key, bypassing cache. */
refetch(): void
/**
* Mark the cached entry stale. Does NOT trigger an immediate fetch.
* The next refetch() call or key-signal change will perform a fresh fetch.
*/
invalidate(): void
}The object returned by createResource.
ResourceOptionsinterface ResourceOptions<T> {
/**
* Initial value surfaced as { status: 'ready', data: initialData } before
* the first fetch completes. If omitted, the resource starts as { status: 'idle' }.
*/
initialData?: T
/**
* When true, this resource is included in the SSR dehydration payload
* emitted by createResourceSerializer(). Default: false.
*/
dehydrate?: boolean
/**
* Cache store to use. When omitted, createResource attempts to inject
* ResourceStoreToken from @aihu/context; if that also yields undefined,
* the module-level default singleton store is used.
*/
store?: ResourceStore
}ResourceStoreinterface ResourceStore {
/** Get the cached state for a key, or undefined if not cached. */
get(key: string): DataState<unknown> | undefined
/** Write a state entry into the cache. */
set(key: string, state: DataState<unknown>): void
/** Delete a cache entry (used by refetch() to force a fresh load). */
delete(key: string): void
/** Iterate all entries (used by createResourceSerializer). */
entries(): IterableIterator<[string, DataState<unknown>]>
}Cache store interface for
ResourceStoreWithMetainterface ResourceStoreWithMeta extends ResourceStore {
/** Keys whose ready state should be included in SSR dehydration. */
readonly dehydratableKeys: Set<string>
/**
* Register a key as dehydration-eligible. Called by createResource when
* dehydrate: true on a successful fetch.
*/
markDehydratable(key: string): void
}Extended internal store type that includes dehydration tracking.
DataStatetype DataState<T> =
| { readonly status: 'idle' }
| { readonly status: 'loading' }
| { readonly status: 'ready'; readonly data: T }
| { readonly status: 'error'; readonly error: unknown }
| { readonly status: 'streaming'; readonly data: T; readonly done: false }All possible states of a reactive resource.