@marianmeres/fetch-store
v3.1.0
Published
[](https://jsr.io/@marianmeres/fetch-store) [](https://www.npmjs.com/package/@marianmeres/fetch-store) [. Svelte-compatible but framework-agnostic.
Installation
deno add jsr:@marianmeres/fetch-storenpm install @marianmeres/fetch-storeUsage
import { createFetchStore } from "@marianmeres/fetch-store";
const userStore = createFetchStore(async (userId: string) => {
const res = await fetch(`/api/users/${userId}`);
if (!res.ok) throw new Error("Failed to fetch user");
return (await res.json()) as User;
});
userStore.subscribe(({ data, isFetching, lastFetchError }) => {
// react to state changes
});
await userStore.fetch("123");Svelte
<script lang="ts">
import { userStore } from "./user-store.ts";
userStore.fetch(userId);
</script>
{#if $userStore.isFetching}
<Spinner />
{:else if $userStore.lastFetchError}
<Error error={$userStore.lastFetchError} />
{:else if $userStore.data}
<UserCard user={$userStore.data} />
{/if}Abortable
const searchStore = createFetchStore(
async (q: string, signal: AbortSignal) => {
const r = await fetch(`/api/search?q=${q}`, { signal });
return (await r.json()) as Result[];
},
null,
{ abortable: true }
);
searchStore.fetch("h"); // aborted
searchStore.fetch("he"); // aborted
searchStore.fetch("hello"); // completesDeduplication
const store = createFetchStore(worker, null, { dedupeInflight: true });
const a = store.fetch("x");
const b = store.fetch("x");
a === b; // true — one network callCached / polled reads
// fire only if no successful fetch yet, or more than 60s old
await store.fetchOnce("123", 60_000);
// poll every 5s, silent (no isFetching flicker)
const stop = store.fetchRecursive("123", 5_000);
// ...later
stop();Streaming (SSE)
import { createFetchStreamStore } from "@marianmeres/fetch-store";
const feed = createFetchStreamStore<Message>((emit, url: string) => {
const es = new EventSource(url);
es.onmessage = (e) => emit("data", JSON.parse(e.data));
es.onerror = (e) => emit("error", e);
return () => { es.close(); emit("end"); };
});
const stop = feed.fetchStream(["/api/events"]);Features
- Reactive state:
data,isFetching,lastFetchError,successCounter, timestamps fetchSilent— background refresh without loading indicatorfetchOnce— TTL-cached fetch that joins any in-flight requestfetchRecursive— polling with cancelabortable— automaticAbortControllerper calldedupeInflight— concurrent calls share one promisedataFactory— custom merge/transform strategiescreateFetchStreamStore— push-based sources (SSE, WebSocket, generators)
API
See API.md for the complete API reference.
Changelog
See CHANGELOG.md.
