Skip to content
sourcerer logoSourcererData
Typed reactive data sources for pagination, filtering, sorting, search, and infinite scroll.
v0.0.15.2 KB gzip Browser · Node.js · SSR · Deno
createLocalSourcecreateRemoteSourcecreateCursorSourcecreateInfiniteSourcederiveSourcemergeSourceapplyQueryapplyLocalQuery +19 more →

Why Sourcerer?

Managing paginated lists across local and remote data usually means writing different state models for each case, wiring separate loading flags, and duplicating URL serialization logic. Sourcerer provides one typed contract — current, meta, and subscribe — that works the same whether data lives in memory or comes from a server.

ts
// Without Sourcerer — manual local list state
const [items, setItems] = useState(allUsers);
const [page, setPage] = useState(1);
const [search, setSearch] = useState('');
const pageSize = 10;
const filtered = items.filter((u) => u.name.includes(search));
const paginated = filtered.slice((page - 1) * pageSize, page * pageSize);
const totalPages = Math.ceil(filtered.length / pageSize);
// ... repeat for remote with loading/error/abort logic ...

// With Sourcerer — same API for both
const source = createLocalSource(allUsers, { limit: 10 }); // or createRemoteSource(...)
await source.search(search, { immediate: true });
// source.current, source.meta.pageCount — both cases handled
FeatureSourcererTanStack QuerySWR
Bundle size5.2 KB~16 kB~6 kB
In-memory source primitive
Remote source primitive
Cursor-based paginationPartialPartial
Infinite scroll source
Typed page/filter/sort/search modelPartialPartial
Optimistic updates
URL query encode/decode helpersPartialPartial
Framework agnostic React-first

Use Sourcerer when you want one typed source abstraction for both local collections and server-backed lists, with built-in support for pagination, search, filters, and optimistic mutation.

Consider TanStack Query when your data layer is already built around query keys, cache invalidation across many components, and React-first DevTools integration.

Installation

sh
pnpm add @vielzeug/sourcerer
sh
npm install @vielzeug/sourcerer
sh
yarn add @vielzeug/sourcerer

Quick Start

ts
import { createLocalSource } from '@vielzeug/sourcerer';

const source = createLocalSource(
  [
    { id: 1, name: 'Ada' },
    { id: 2, name: 'Grace' },
    { id: 3, name: 'Linus' },
  ],
  { limit: 2 },
);

await source.search('ada', { immediate: true });
console.log(source.current); // [{ id: 1, name: 'Ada' }]
console.log(source.meta.pageNumber); // 1
ts
import { createRemoteSource } from '@vielzeug/sourcerer';

const source = createRemoteSource({
  fetch: async ({ filter, limit, page, search, sort }, signal) => {
    const res = await fetch(`/api/users?page=${page}&limit=${limit}`, { signal });
    return res.json(); // { items: User[], total: number }
  },
  limit: 20,
});

// autoFetch is true by default — initial data loads immediately
await source.ready();
console.log(source.current, source.meta.totalItems);

Features

FactoryData modelNavigationKey extras
createLocalSource()In-memory arrayPage numberfilterAsync, sortAsync, patch(), custom searchFn, ready()
createRemoteSource()Server fetchPage numberstaleTime, optimisticUpdate, patch(), ready(), queryKey
createCursorSource()Server fetchCursor tokenspatch(), ready(), queryKey
createInfiniteSource()Server fetchAppend (loadMore)patch(), loadedPages, ready(), queryKey

Documentation

See Also

  • Ripple — reactive signals; Sourcerer's loading, error, and data state are exposed as signals for framework-agnostic UI binding
  • Arsenal — utility functions used inside Sourcerer's fetch and transform pipelines
  • Wayfinder — client-side router; sync Sourcerer's pagination and filter state with URL search params