@vielzeug/codex 26.10.6 → 26.10.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,17 @@
1
1
  {
2
- "apiSource": "export { createCursorSource } from './cursorSource';\nexport { SourcererConfigurationError, SourcererDisposedError, SourcererError } from './errors';\nexport { createInfiniteSource } from './infiniteSource';\nexport { createLocalSource } from './localSource';\nexport { createPageSource } from './pageSource';\nexport type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n} from './types';\n",
2
+ "apiSource": "export { createCursorSource } from './cursorSource';\nexport { SourcererConfigurationError, SourcererDisposedError, SourcererError } from './errors';\nexport { createInfiniteSource } from './infiniteSource';\nexport { createLocalSource } from './localSource';\nexport { createPageSource } from './pageSource';\nexport { createResource } from './resourceSource';\nexport type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';\n",
3
3
  "docs": {
4
- "index": "---\ntitle: 'Sourcerer: Reactive collection sources'\ndescription: Framework-agnostic local and remote collection state with page, cursor, and infinite pagination.\npackage: sourcerer\ncategory: data\nkeywords: [pagination, data-source, cursor, infinite-scroll, collection]\nrelated: [courier, ripple, scout, wayfinder]\nexports:\n [\n createCursorSource,\n createInfiniteSource,\n createLocalSource,\n createPageSource,\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n SourcererError,\n SourcererConfigurationError,\n SourcererDisposedError,\n ]\nenvironments: [browser, node, ssr, deno]\n---\n\n<!-- markdownlint-disable MD025 MD033 MD060 -->\n\n<PackageHero package=\"sourcerer\" />\n\n## Why Sourcerer?\n\nPaginated views need collection data, loading state, errors, parameters, and navigation to change coherently. Sourcerer owns that state and request succession without coupling it to a framework or transport client.\n\n```ts\n// Before\nlet items = [];\nlet loading = false;\nlet page = 1;\n\n// After\nconst source = createPageSource({\n load: async ({ page, pageSize }) => ({ items: await loadUsers(page, pageSize), totalItems: 100 }),\n});\nsource.subscribe((state) => render(state));\n```\n\n| Feature | Sourcerer | Manual store | General query cache |\n| --- | --- | --- | --- |\n| Bundle size | <PackageInfo package=\"sourcerer\" type=\"size\" /> | Application-defined | Package-defined |\n| Zero runtime dependencies | <ore-icon name=\"x\" size=\"16\"></ore-icon> | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"triangle-alert\" size=\"16\"></ore-icon> |\n| Page, cursor, and infinite navigation | <ore-icon name=\"check\" size=\"16\"></ore-icon> | Application-defined | Application-defined |\n| Framework-neutral subscriptions | <ore-icon name=\"check\" size=\"16\"></ore-icon> | Application-defined | <ore-icon name=\"triangle-alert\" size=\"16\"></ore-icon> |\n| HTTP transport policy | Loader-defined | Application-defined | Loader-defined |\n\n<div class=\"decision-callout\">\n\n**Use Sourcerer when** a collection view needs explicit pagination, observable state, cancellation, and lifecycle ownership.\n\n**Consider a general query cache when** your primary requirement is shared keyed caching, invalidation, mutations, or server-state normalization rather than collection navigation.\n\n</div>\n\n## Installation\n\n::: code-group\n\n```sh [pnpm]\npnpm add @vielzeug/sourcerer\n```\n\n```sh [npm]\nnpm install @vielzeug/sourcerer\n```\n\n```sh [yarn]\nyarn add @vielzeug/sourcerer\n```\n\n:::\n\n## Quick Start\n\nCreate a page source, load it, read its state, and dispose it with its owner.\n\n```ts\nimport { createPageSource } from '@vielzeug/sourcerer';\n\ntype User = { id: number; name: string };\nconst users: User[] = [\n { id: 1, name: 'Ada' },\n { id: 2, name: 'Grace' },\n];\nconst source = createPageSource({\n load: async ({ page, pageSize }) => {\n const start = (page - 1) * pageSize;\n return { items: users.slice(start, start + pageSize), totalItems: users.length };\n },\n pageSize: 1,\n});\n\ntry {\n await source.reload();\n console.log(source.state.items);\n} catch (error) {\n console.error(error);\n} finally {\n source.dispose();\n}\n```\n\n## Features\n\n<div class=\"features-grid\">\n\n- `createLocalSource()`: filters and paginates an in-memory collection synchronously\n- `createPageSource()`: loads numbered pages and exposes direct navigation commands\n- `createCursorSource()`: follows opaque cursors returned by the loader\n- `createInfiniteSource()`: appends pages while preserving loaded items\n- `setParams()`: replaces consumer-owned loader parameters and resets pagination\n- `subscribe()`: publishes complete immutable state replacements\n\n</div>\n\n## Documentation\n\n<div class=\"doc-links\">\n\n- [Usage Guide](./usage.md)\n- [API Reference](./api.md)\n- [Examples](./examples.md)\n- [Migration Guide](./migration.md)\n\n</div>\n\n## See Also\n\n<div class=\"see-also\">\n\n- [Courier](/courier/): provide HTTP transport, middleware, and structured transport errors inside loaders\n- [Scout](/scout/): index larger in-memory collections before passing matches to a local source\n- [Ripple](/ripple/): project source state into reactive computations\n- [Wayfinder](/wayfinder/): validate and synchronize source parameters with route state\n\n</div>\n\n<!-- markdownlint-enable MD025 MD033 MD060 -->\n",
5
- "api": "---\ntitle: 'Sourcerer: API Reference'\ndescription: Public API for @vielzeug/sourcerer.\n---\n\n[[toc]]\n\n## API Overview\n\n| Symbol | Purpose | Execution mode | Common gotcha |\n| --- | --- | --- | --- |\n| `createLocalSource()` | Filter and paginate in-memory items | Sync | `params` replacement uses `Object.is` |\n| `createPageSource()` | Load numbered pages | Async | Construction is inert |\n| `createCursorSource()` | Load server-issued cursor pages | Async | `after` and `before` cannot coexist initially |\n| `createInfiniteSource()` | Append numbered pages | Async | `loadMore()` is a no-op while loading or exhausted |\n| `SourcererError` | Base package error | Sync | Loader errors retain their original type |\n\n## Package Entry Point\n\n| Import | Purpose |\n| --- | --- |\n| `@vielzeug/sourcerer` | All factories, states, pagination types, loader contexts, and errors |\n\n## Source Factories\n\n### `createLocalSource()`\n\n```ts\nfunction createLocalSource<T>(items: readonly T[]): LocalSource<T>\nfunction createLocalSource<T, TParams = undefined>(\n items: readonly T[],\n config: LocalSourceConfig<T, TParams>,\n): LocalSource<T, TParams>\n```\n\nReturns a synchronous in-memory source.\n\n| Parameter | Type | Description |\n| --- | --- | --- |\n| `items` | `readonly T[]` | Initial collection |\n| `config.filter` | `(item: T, params: TParams) => boolean` | Optional inclusion predicate |\n| `config.pageSize` | `number` | Positive page size; defaults to `20` |\n| `config.params` | `TParams` | Initial params; required when `TParams` excludes `undefined` |\n\n**Returns:** `LocalSource<T, TParams>`.\n\n```ts\nimport { createLocalSource } from '@vielzeug/sourcerer';\n\nconst source = createLocalSource(['Ada', 'Grace'], {\n filter: (name, search: string) => name.includes(search),\n params: '',\n});\nsource.setParams('Ada');\n```\n\n| Method | Returns | Description |\n| --- | --- | --- |\n| `first()` | `void` | Move to page one |\n| `goTo(page)` | `void` | Move to a positive page, clamped to the known range |\n| `last()` | `void` | Move to the final page |\n| `next()` | `void` | Move forward when available |\n| `previous()` | `void` | Move backward when available |\n| `setItems(items)` | `void` | Replace the collection and recompute state |\n| `setPageSize(pageSize)` | `void` | Replace page size and reset to page one |\n| `setParams(params)` | `void` | Replace params and reset to page one |\n| `subscribe(listener)` | `() => void` | Register a state listener and return its unsubscribe function |\n| `dispose()` | `void` | Stop notifications and reject later mutations |\n\n---\n\n### `createPageSource()`\n\n```ts\nfunction createPageSource<T, TParams = undefined>(\n config: PageSourceConfig<T, TParams>,\n): PageSource<T, TParams>\n```\n\nReturns an inert numbered-page source.\n\n| Parameter | Type | Description |\n| --- | --- | --- |\n| `config.load` | `(context: PageLoadContext<TParams>) => Promise<PageResult<T>>` | Page loader |\n| `config.pageSize` | `number` | Positive page size; defaults to `20` |\n| `config.params` | `TParams` | Initial params; required when `TParams` excludes `undefined` |\n\n**Returns:** `PageSource<T, TParams>`.\n\n```ts\nimport { createPageSource } from '@vielzeug/sourcerer';\n\nconst source = createPageSource({\n load: async ({ page }) => ({ items: [page], totalItems: 10 }),\n});\nawait source.reload();\n```\n\n| Method | Returns | Description |\n| --- | --- | --- |\n| `first()` | `Promise<void>` | Load page one |\n| `goTo(page)` | `Promise<void>` | Load a positive page |\n| `last()` | `Promise<void>` | Load the last known page |\n| `next()` | `Promise<void>` | Load the next known page |\n| `previous()` | `Promise<void>` | Load the previous page |\n| `reload()` | `Promise<void>` | Reload the requested page and params |\n| `setPageSize(pageSize)` | `Promise<void>` | Reset to page one and load with a new size |\n| `setParams(params)` | `Promise<void>` | Reset to page one and load replacement params |\n| `subscribe(listener)` | `() => void` | Register a state listener and return its unsubscribe function |\n| `dispose()` | `void` | Abort work and stop notifications |\n\n---\n\n### `createCursorSource()`\n\n```ts\nfunction createCursorSource<T, TParams = undefined, TCursor = string>(\n config: CursorSourceConfig<T, TParams, TCursor>,\n): CursorSource<T, TParams, TCursor>\n```\n\nReturns an inert cursor source.\n\n| Parameter | Type | Description |\n| --- | --- | --- |\n| `config.after` | `TCursor` | Optional initial forward cursor |\n| `config.before` | `TCursor` | Optional initial backward cursor |\n| `config.load` | `(context: CursorLoadContext<TParams, TCursor>) => Promise<CursorResult<T, TCursor>>` | Cursor loader |\n| `config.pageSize` | `number` | Positive page size; defaults to `20` |\n| `config.params` | `TParams` | Initial params; required when `TParams` excludes `undefined` |\n\n**Returns:** `CursorSource<T, TParams, TCursor>`.\n\n```ts\nimport { createCursorSource } from '@vielzeug/sourcerer';\n\nconst source = createCursorSource({ load: async () => ({ items: ['first'], nextCursor: 'next' }) });\nawait source.reload();\nawait source.next();\n```\n\n| Method | Returns | Description |\n| --- | --- | --- |\n| `next()` | `Promise<void>` | Load `state.pagination.nextCursor` when available |\n| `previous()` | `Promise<void>` | Load `state.pagination.previousCursor` when available |\n| `reload()` | `Promise<void>` | Reload the requested cursor and params |\n| `setPageSize(pageSize)` | `Promise<void>` | Clear cursors and reload with a new size |\n| `setParams(params)` | `Promise<void>` | Clear cursors and load replacement params |\n| `subscribe(listener)` | `() => void` | Register a state listener and return its unsubscribe function |\n| `dispose()` | `void` | Abort work and stop notifications |\n\n---\n\n### `createInfiniteSource()`\n\n```ts\nfunction createInfiniteSource<T, TParams = undefined>(\n config: InfiniteSourceConfig<T, TParams>,\n): InfiniteSource<T, TParams>\n```\n\nReturns an inert source that appends numbered pages.\n\n| Parameter | Type | Description |\n| --- | --- | --- |\n| `config.load` | `(context: InfiniteLoadContext<TParams>) => Promise<PageResult<T>>` | Page loader |\n| `config.pageSize` | `number` | Positive page size; defaults to `20` |\n| `config.params` | `TParams` | Initial params; required when `TParams` excludes `undefined` |\n\n**Returns:** `InfiniteSource<T, TParams>`.\n\n```ts\nimport { createInfiniteSource } from '@vielzeug/sourcerer';\n\nconst source = createInfiniteSource({ load: async () => ({ items: ['post'], totalItems: 1 }) });\nawait source.reload();\nawait source.loadMore();\n```\n\n| Method | Returns | Description |\n| --- | --- | --- |\n| `loadMore()` | `Promise<void>` | Append the next page when available |\n| `reload()` | `Promise<void>` | Replace items from page one |\n| `setPageSize(pageSize)` | `Promise<void>` | Replace items from page one with a new size |\n| `setParams(params)` | `Promise<void>` | Replace items from page one with new params |\n| `subscribe(listener)` | `() => void` | Register a state listener and return its unsubscribe function |\n| `dispose()` | `void` | Abort work and stop notifications |\n\n## Types\n\n### Page source types\n\n```ts\ntype PagePagination = Readonly<{\n hasNext: boolean;\n hasPrevious: boolean;\n page: number;\n pageCount: number;\n pageSize: number;\n totalItems: number;\n}>;\n\ntype PageSourceState<T, TParams = undefined> = Readonly<{\n error: Error | null;\n items: readonly T[];\n loading: boolean;\n pagination: PagePagination;\n params: TParams;\n pendingParams?: TParams;\n}>;\n\ntype PageLoadContext<TParams = undefined> = Readonly<{\n page: number;\n pageSize: number;\n params: TParams;\n signal: AbortSignal;\n}>;\n\ntype PageResult<T> = Readonly<{\n items: readonly T[];\n totalItems: number;\n}>;\n\ntype PageSourceConfig<T, TParams = undefined> = Readonly<{\n load(context: PageLoadContext<TParams>): Promise<PageResult<T>>;\n pageSize?: number;\n } & (undefined extends TParams ? { params?: TParams } : { params: TParams })\n>;\n\ntype PageSource<T, TParams = undefined> = {\n [Symbol.dispose](): void;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n first(): Promise<void>;\n goTo(page: number): Promise<void>;\n last(): Promise<void>;\n next(): Promise<void>;\n previous(): Promise<void>;\n reload(): Promise<void>;\n setPageSize(pageSize: number): Promise<void>;\n setParams(params: TParams): Promise<void>;\n readonly state: PageSourceState<T, TParams>;\n subscribe(listener: (state: PageSourceState<T, TParams>) => void): () => void;\n};\n```\n\nThe conditional config field makes `params` optional only when `TParams` includes `undefined`.\n\n### Local source types\n\n```ts\ntype LocalSourceState<T, TParams = undefined> = Readonly<{\n error: null;\n items: readonly T[];\n loading: false;\n pagination: PagePagination;\n params: TParams;\n}>;\n\ntype LocalSourceConfig<T, TParams = undefined> = Readonly<{\n filter?: (item: T, params: TParams) => boolean;\n pageSize?: number;\n } & (undefined extends TParams ? { params?: TParams } : { params: TParams })\n>;\n\ntype LocalSource<T, TParams = undefined> = {\n [Symbol.dispose](): void;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n first(): void;\n goTo(page: number): void;\n last(): void;\n next(): void;\n previous(): void;\n setItems(items: readonly T[]): void;\n setPageSize(pageSize: number): void;\n setParams(params: TParams): void;\n readonly state: LocalSourceState<T, TParams>;\n subscribe(listener: (state: LocalSourceState<T, TParams>) => void): () => void;\n};\n```\n\n### Cursor source types\n\n```ts\ntype CursorPagination<TCursor = string> = Readonly<{\n nextCursor?: TCursor;\n pageSize: number;\n previousCursor?: TCursor;\n totalItems?: number;\n}>;\n\ntype CursorLoadContext<TParams = undefined, TCursor = string> = Readonly<{\n after?: TCursor;\n before?: TCursor;\n pageSize: number;\n params: TParams;\n signal: AbortSignal;\n}>;\n\ntype CursorResult<T, TCursor = string> = Readonly<{\n items: readonly T[];\n nextCursor?: TCursor;\n previousCursor?: TCursor;\n totalItems?: number;\n}>;\n\ntype CursorSourceState<T, TParams = undefined, TCursor = string> = Readonly<{\n error: Error | null;\n items: readonly T[];\n loading: boolean;\n pagination: CursorPagination<TCursor>;\n params: TParams;\n pendingParams?: TParams;\n}>;\n\ntype CursorSourceConfig<T, TParams = undefined, TCursor = string> = Readonly<{\n after?: TCursor;\n before?: TCursor;\n load(context: CursorLoadContext<TParams, TCursor>): Promise<CursorResult<T, TCursor>>;\n pageSize?: number;\n } & (undefined extends TParams ? { params?: TParams } : { params: TParams })\n>;\n\ntype CursorSource<T, TParams = undefined, TCursor = string> = {\n [Symbol.dispose](): void;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n next(): Promise<void>;\n previous(): Promise<void>;\n reload(): Promise<void>;\n setPageSize(pageSize: number): Promise<void>;\n setParams(params: TParams): Promise<void>;\n readonly state: CursorSourceState<T, TParams, TCursor>;\n subscribe(listener: (state: CursorSourceState<T, TParams, TCursor>) => void): () => void;\n};\n```\n\n### Infinite source types\n\n```ts\ntype InfinitePagination = Readonly<{\n hasMore: boolean;\n loadedItems: number;\n pageSize: number;\n totalItems: number;\n}>;\n\ntype InfiniteLoadContext<TParams = undefined> = Readonly<{\n page: number;\n pageSize: number;\n params: TParams;\n signal: AbortSignal;\n}>;\n\ntype InfiniteSourceState<T, TParams = undefined> = Readonly<{\n error: Error | null;\n items: readonly T[];\n loading: boolean;\n pagination: InfinitePagination;\n params: TParams;\n pendingParams?: TParams;\n}>;\n\ntype InfiniteSourceConfig<T, TParams = undefined> = Readonly<{\n load(context: InfiniteLoadContext<TParams>): Promise<PageResult<T>>;\n pageSize?: number;\n } & (undefined extends TParams ? { params?: TParams } : { params: TParams })\n>;\n\ntype InfiniteSource<T, TParams = undefined> = {\n [Symbol.dispose](): void;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n loadMore(): Promise<void>;\n reload(): Promise<void>;\n setPageSize(pageSize: number): Promise<void>;\n setParams(params: TParams): Promise<void>;\n readonly state: InfiniteSourceState<T, TParams>;\n subscribe(listener: (state: InfiniteSourceState<T, TParams>) => void): () => void;\n};\n```\n\n## Errors\n\n| Error | Trigger | Notable properties |\n| --- | --- | --- |\n| `SourcererError` | Base class for package-originated configuration and lifecycle errors | `instanceof SourcererError` narrows the hierarchy |\n| `SourcererConfigurationError` | Invalid page, page size, total, or initial cursor direction | Extends `SourcererError` |\n| `SourcererDisposedError` | A source command runs after disposal | Extends `SourcererError` |\n\nLoader failures are preserved when they are `Error` instances. Non-Error rejections become `Error` objects whose `cause` contains the original value.\n",
6
- "usage": "---\ntitle: 'Sourcerer: Usage Guide'\ndescription: Build local, page, cursor, and infinite collection sources.\n---\n\n[[toc]]\n\n## Basic Usage\n\nCreate a page source and call `reload()` to start the first request. Construction performs no I/O.\n\n```ts\nimport { createPageSource } from '@vielzeug/sourcerer';\n\nconst names = ['Ada', 'Grace', 'Linus'];\nconst source = createPageSource({\n load: async ({ page, pageSize }) => {\n const start = (page - 1) * pageSize;\n return { items: names.slice(start, start + pageSize), totalItems: names.length };\n },\n pageSize: 2,\n});\n\nawait source.reload();\nconsole.log(source.state.items);\nsource.dispose();\n```\n\nRead one `state` object per render. It contains `items`, `loading`, `error`, `params`, and pagination metadata from one committed result. Commands return `Promise<void>`; read `source.state` after awaiting them.\n\n## Pass Loader Parameters\n\nUse `params` for application-owned filters, search terms, sort state, or request options. `setParams()` replaces the entire value and resets pagination.\n\n```ts\nimport { createPageSource } from '@vielzeug/sourcerer';\n\ntype UserParams = { role: 'admin' | 'user'; search: string };\nconst users = ['Ada', 'Grace', 'Linus'];\nconst source = createPageSource<string, UserParams>({\n load: async ({ page, pageSize, params }) => {\n const matching = users.filter((name) => name.toLowerCase().includes(params.search.toLowerCase()));\n const start = (page - 1) * pageSize;\n return { items: matching.slice(start, start + pageSize), totalItems: matching.length };\n },\n params: { role: 'admin', search: '' },\n});\n\nawait source.setParams({ role: 'admin', search: 'ada' });\nconsole.log(source.state.params);\nsource.dispose();\n```\n\nA non-optional parameter type requires an initial `params` value. Sourcerer compares parameter values with `Object.is`; reuse a value when setting it again should be a no-op.\n\nWhile replacement parameters load, `state.params` continues to describe the committed items and `state.pendingParams` contains the requested value. Page-only navigation does not set `pendingParams`.\n\n## Navigate Numbered Pages\n\nUse direct commands for numbered-page navigation. `setPageSize()` resets to page one.\n\n```ts\nawait source.reload();\nawait source.next();\nawait source.goTo(4);\nawait source.previous();\nawait source.first();\nawait source.last();\nawait source.setPageSize(50);\n```\n\nAfter the first successful load, navigation is clamped to the known `pageCount`. Before that load, `goTo()` accepts any positive page because the total is unknown.\n\n## Filter Local Collections\n\nUse a local source when data is already in memory. Its commands are synchronous.\n\n```ts\nimport { createLocalSource } from '@vielzeug/sourcerer';\n\nconst source = createLocalSource(['Ada', 'Grace', 'Linus'], {\n filter: (name, search: string) => name.toLowerCase().includes(search.toLowerCase()),\n pageSize: 2,\n params: '',\n});\n\nsource.setParams('a');\nsource.next();\nsource.setItems(['Ada', 'Grace']);\nconsole.log(source.state.items);\nsource.dispose();\n```\n\nUse ordinary arrays for one-off transformations. A local source is useful when pagination, subscriptions, and lifecycle ownership are also required.\n\n## Use Cursor Pagination\n\nReturn opaque cursors from the loader. `next()` and `previous()` use only cursors from the committed state.\n\n```ts\nimport { createCursorSource } from '@vielzeug/sourcerer';\n\nconst rows = ['A', 'B', 'C', 'D'];\nconst source = createCursorSource({\n load: async ({ after, pageSize }) => {\n const start = after ? Number(after) : 0;\n const items = rows.slice(start, start + pageSize);\n const next = start + items.length;\n return {\n items,\n nextCursor: next < rows.length ? String(next) : undefined,\n previousCursor: start > 0 ? String(Math.max(0, start - pageSize)) : undefined,\n };\n },\n pageSize: 2,\n});\n\nawait source.reload();\nawait source.next();\nconsole.log(source.state.items);\nsource.dispose();\n```\n\nChanging params or page size clears current cursor direction. A source cannot start with both `after` and `before`.\n\n## Build an Infinite Feed\n\nUse an infinite source when later pages should append to committed items.\n\n```ts\nimport { createInfiniteSource } from '@vielzeug/sourcerer';\n\nconst values = [1, 2, 3, 4, 5];\nconst source = createInfiniteSource({\n load: async ({ page, pageSize }) => {\n const start = (page - 1) * pageSize;\n return { items: values.slice(start, start + pageSize), totalItems: values.length };\n },\n pageSize: 2,\n});\n\nawait source.reload();\nawait source.loadMore();\nconsole.log(source.state.items);\nsource.dispose();\n```\n\n`loadMore()` is a no-op while another request is active or after `pagination.hasMore` becomes false. `setParams()` and `setPageSize()` replace the feed from page one.\n\n## Handle Requests and Errors\n\nA new remote command aborts older work. Superseded or disposed work settles without committing. A current loader failure preserves committed items, writes the error to state, and rejects the command.\n\n```ts\ntry {\n await source.reload();\n} catch (error) {\n console.error(error);\n console.log(source.state.error);\n}\n```\n\nLoader result arrays are copied before publication. Commands after disposal throw or reject `SourcererDisposedError`.\n\n## Testing\n\nInject deterministic loaders and await commands before asserting final state.\n\n```ts\nimport { expect, it } from 'vitest';\nimport { createPageSource } from '@vielzeug/sourcerer';\n\nit('loads a page', async () => {\n const source = createPageSource({ load: async () => ({ items: ['Ada'], totalItems: 1 }) });\n\n await source.reload();\n\n expect(source.state.items).toEqual(['Ada']);\n source.dispose();\n});\n```\n\n## Framework Integration\n\nCreate one source per component lifetime and bridge `subscribe()` to the framework lifecycle.\n\n::: code-group\n\n```tsx [React]\nimport { createPageSource } from '@vielzeug/sourcerer';\nimport { useEffect, useMemo, useSyncExternalStore } from 'react';\n\nexport function Users() {\n const source = useMemo(\n () => createPageSource({ load: async () => ({ items: [{ id: 1, name: 'Ada' }], totalItems: 1 }) }),\n [],\n );\n const state = useSyncExternalStore(source.subscribe, () => source.state);\n\n useEffect(() => {\n void source.reload().catch(() => undefined);\n return () => source.dispose();\n }, [source]);\n\n return <p>{state.loading ? 'Loading' : state.items.length}</p>;\n}\n```\n\n```ts [Vue 3]\nimport { onUnmounted, shallowRef } from 'vue';\nimport { createPageSource } from '@vielzeug/sourcerer';\n\nconst source = createPageSource({ load: async () => ({ items: [{ id: 1, name: 'Ada' }], totalItems: 1 }) });\nconst state = shallowRef(source.state);\nconst stop = source.subscribe((next) => (state.value = next));\nvoid source.reload().catch(() => undefined);\n\nonUnmounted(() => {\n stop();\n source.dispose();\n});\n```\n\n```svelte [Svelte]\n<script lang=\"ts\">\n import { onDestroy } from 'svelte';\n import { createPageSource } from '@vielzeug/sourcerer';\n\n const source = createPageSource({ load: async () => ({ items: [{ id: 1, name: 'Ada' }], totalItems: 1 }) });\n let state = source.state;\n const stop = source.subscribe((next) => (state = next));\n void source.reload().catch(() => undefined);\n\n onDestroy(() => {\n stop();\n source.dispose();\n });\n</script>\n\n{#if state.loading}Loading{/if}\n{#each state.items as user}{user.name}{/each}\n```\n\n:::\n\n## Working with Other Vielzeug Libraries\n\nUse Courier for transport policy and pass the source-owned cancellation signal through.\n\n```ts\nimport { createCourier } from '@vielzeug/courier';\nimport { createPageSource } from '@vielzeug/sourcerer';\n\ntype User = { id: number; name: string };\ntype Response = { data: User[]; total: number };\nconst courier = createCourier({ baseUrl: '/api' });\nconst source = createPageSource({\n load: async ({ page, pageSize, params: search, signal }) => {\n const result = await courier.get<Response>('/users', { query: { page, pageSize, search }, signal });\n return { items: result.data, totalItems: result.total };\n },\n params: '',\n});\n```\n\nUse Scout to compute indexed local matches, Ripple to project state into reactive computations, and Wayfinder to validate and synchronize params with the URL.\n\n## Best Practices\n\n- Dispose each source with its owning view, request, or service scope.\n- Read one `state` object per render.\n- Await direct commands or handle rejected current-request failures.\n- Keep transport, caching, and persistence policy outside Sourcerer.\n- Treat `params` as an immutable value and replace it atomically.\n- Debounce text input before calling `setParams()` on a remote source.\n- Validate route and form values before constructing params or page numbers.\n- Keep rendering committed items while `loading` is true.\n",
7
- "examples": "---\ntitle: 'Sourcerer: Examples'\ndescription: Recipes for local, page, cursor, infinite, and framework source usage.\n---\n\n## Examples\n\n- [Local Pagination and Filtering](./examples/local-pagination-and-filtering.md)\n- [Page Params with URL State](./examples/remote-search-with-url-state.md)\n- [Cursor-Based Pagination](./examples/cursor-based-pagination.md)\n- [Infinite Scroll](./examples/infinite-scroll.md)\n- [Framework Integration](./examples/framework-integration.md)\n- [Remote Data with Courier](./examples/sourcerer-with-courier.md)\n- [Reactive Controls with Ripple](./examples/sourcerer-with-ripple.md)\n- [URL-Synced List with Wayfinder](./examples/sourcerer-with-wayfinder.md)\n"
4
+ "index": "---\ntitle: 'Sourcerer: Reactive collection sources'\ndescription: Framework-agnostic collection pagination and observable single-value resources.\npackage: sourcerer\ncategory: data\nkeywords: [pagination, data-source, cursor, infinite-scroll, collection, resource]\nrelated: [courier, ripple, scout, wayfinder]\nexports: [createLocalSource, createPageSource, createCursorSource, createInfiniteSource, createResource]\nenvironments: [browser, node, ssr, deno]\n---\n\n<!-- markdownlint-disable MD025 MD033 MD060 -->\n\n<PackageHero package=\"sourcerer\" />\n\n## Why Sourcerer?\n\nPaginated views need collection data, loading state, errors, parameters, and navigation to change coherently. Sourcerer owns that state and request succession without coupling it to a framework or transport client.\n\n```ts\n// Before\nlet items = [];\nlet loading = false;\nlet page = 1;\n\n// After\nconst source = createPageSource({\n load: async ({ page, pageSize }) => ({ items: await loadUsers(page, pageSize), totalItems: 100 }),\n});\nsource.subscribe((state) => render(state));\n```\n\n| Feature | Sourcerer | Manual store | General query cache |\n| --- | --- | --- | --- |\n| Bundle size | <PackageInfo package=\"sourcerer\" type=\"size\" /> | Application-defined | Package-defined |\n| Zero runtime dependencies | <ore-icon name=\"x\" size=\"16\"></ore-icon> | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"triangle-alert\" size=\"16\"></ore-icon> |\n| Page, cursor, and infinite navigation | <ore-icon name=\"check\" size=\"16\"></ore-icon> | Application-defined | Application-defined |\n| Framework-neutral subscriptions | <ore-icon name=\"check\" size=\"16\"></ore-icon> | Application-defined | <ore-icon name=\"triangle-alert\" size=\"16\"></ore-icon> |\n| HTTP transport policy | Loader-defined | Application-defined | Loader-defined |\n\n<div class=\"decision-callout\">\n\n**Use Sourcerer when** a collection view needs explicit pagination, observable state, cancellation, and lifecycle ownership.\n\n**Consider a general query cache when** your primary requirement is shared keyed caching, invalidation, mutations, or server-state normalization rather than collection navigation.\n\n</div>\n\n## Installation\n\n::: code-group\n\n```sh [pnpm]\npnpm add @vielzeug/sourcerer\n```\n\n```sh [npm]\nnpm install @vielzeug/sourcerer\n```\n\n```sh [yarn]\nyarn add @vielzeug/sourcerer\n```\n\n:::\n\n## Quick Start\n\nCreate a page source, load it, read its state, and dispose it with its owner.\n\n```ts\nimport { createPageSource } from '@vielzeug/sourcerer';\n\ntype User = { id: number; name: string };\nconst users: User[] = [\n { id: 1, name: 'Ada' },\n { id: 2, name: 'Grace' },\n];\nconst source = createPageSource({\n load: async ({ page, pageSize }) => {\n const start = (page - 1) * pageSize;\n return { items: users.slice(start, start + pageSize), totalItems: users.length };\n },\n pageSize: 1,\n});\n\ntry {\n await source.reload();\n console.log(source.state.items);\n} catch (error) {\n console.error(error);\n} finally {\n source.dispose();\n}\n```\n\n## Features\n\n<div class=\"features-grid\">\n\n- `createLocalSource()`: filters and paginates an in-memory collection synchronously\n- `createPageSource()`: loads numbered pages and exposes direct navigation commands\n- `createCursorSource()`: follows opaque cursors returned by the loader\n- `createInfiniteSource()`: appends pages while preserving loaded items\n- `createResource()`: starts loading one value immediately, or awaits `reload()` with `start: false`\n- `setParams()`: replaces consumer-owned loader parameters and resets pagination\n- `PageSource.apply()`: reconciles page and structurally compared params in at most one request\n- `subscribe()`: publishes complete immutable state replacements\n\n</div>\n\n## Documentation\n\n<div class=\"doc-links\">\n\n- [Usage Guide](./usage.md)\n- [API Reference](./api.md)\n- [Examples](./examples.md)\n- [Migration Guide](./migration.md)\n\n</div>\n\n## See Also\n\n<div class=\"see-also\">\n\n- [Courier](/courier/): provide HTTP transport, middleware, and structured transport errors inside loaders\n- [Scout](/scout/): index larger in-memory collections before passing matches to a local source\n- [Ripple](/ripple/): project source state into reactive computations\n- [Wayfinder](/wayfinder/): validate and synchronize source parameters with route state\n\n</div>\n\n<!-- markdownlint-enable MD025 MD033 MD060 -->\n",
5
+ "api": "---\ntitle: 'Sourcerer: API Reference'\ndescription: Public API for @vielzeug/sourcerer.\n---\n\n[[toc]]\n\n## API Overview\n\n| Symbol | Purpose | Execution mode | Common gotcha |\n| --- | --- | --- | --- |\n| `createLocalSource()` | Filter and paginate in-memory items | Sync | `params` replacement uses `Object.is` |\n| `createPageSource()` | Load numbered pages | Async | Construction is inert |\n| `createCursorSource()` | Load server-issued cursor pages | Async | `after` and `before` cannot coexist initially |\n| `createInfiniteSource()` | Append numbered pages | Async | `loadMore()` is a no-op while loading or exhausted |\n| `createResource()` | Load one reactive value | Async | Starts loading during construction; `start: false` opts out |\n| `SourcererError` | Base package error | Sync | Loader errors retain their original type |\n| `SourcererConfigurationError` | Invalid pagination configuration | Sync | Pages and page sizes must be positive integers |\n| `SourcererDisposedError` | Command after source disposal | Sync | In-flight work instead settles without committing |\n\n## Package Entry Point\n\n| Import | Purpose |\n| --- | --- |\n| `@vielzeug/sourcerer` | All factories, states, pagination types, loader contexts, and errors |\n\n## Source Factories\n\n### `createLocalSource()`\n\n```ts\nfunction createLocalSource<T>(items: readonly T[]): LocalSource<T>\nfunction createLocalSource<T, TParams = undefined>(\n items: readonly T[],\n config: LocalSourceConfig<T, TParams>,\n): LocalSource<T, TParams>\n```\n\nReturns a synchronous in-memory source.\n\n| Parameter | Type | Description |\n| --- | --- | --- |\n| `items` | `readonly T[]` | Initial collection |\n| `config.filter` | `(item: T, params: TParams) => boolean` | Optional inclusion predicate |\n| `config.pageSize` | `number` | Positive page size; defaults to `20` |\n| `config.params` | `TParams` | Initial params; required when `TParams` excludes `undefined` |\n\n**Returns:** `LocalSource<T, TParams>`.\n\n```ts\nimport { createLocalSource } from '@vielzeug/sourcerer';\n\nconst source = createLocalSource(['Ada', 'Grace'], {\n filter: (name, search: string) => name.includes(search),\n params: '',\n});\nsource.setParams('Ada');\n```\n\n| Method | Returns | Description |\n| --- | --- | --- |\n| `first()` | `void` | Move to page one |\n| `goTo(page)` | `void` | Move to a positive page, clamped to the known range |\n| `last()` | `void` | Move to the final page |\n| `next()` | `void` | Move forward when available |\n| `previous()` | `void` | Move backward when available |\n| `setItems(items)` | `void` | Replace the collection and recompute state |\n| `setPageSize(pageSize)` | `void` | Replace page size and reset to page one |\n| `setParams(params)` | `void` | Replace params and reset to page one |\n| `subscribe(listener)` | `() => void` | Register a state listener and return its unsubscribe function |\n| `dispose()` | `void` | Stop notifications and reject later mutations |\n\n---\n\n### `createPageSource()`\n\n```ts\nfunction createPageSource<T, TParams = undefined>(\n config: PageSourceConfig<T, TParams>,\n): PageSource<T, TParams>\n```\n\nReturns an inert numbered-page source.\n\n| Parameter | Type | Description |\n| --- | --- | --- |\n| `config.load` | `(context: PageLoadContext<TParams>) => Promise<PageResult<T>>` | Page loader |\n| `config.pageSize` | `number` | Positive page size; defaults to `20` |\n| `config.params` | `TParams` | Initial params; required when `TParams` excludes `undefined` |\n\n**Returns:** `PageSource<T, TParams>`.\n\n```ts\nimport { createPageSource } from '@vielzeug/sourcerer';\n\nconst source = createPageSource({\n load: async ({ page }) => ({ items: [page], totalItems: 10 }),\n});\nawait source.reload();\n```\n\n| Method | Returns | Description |\n| --- | --- | --- |\n| `apply(update)` | `Promise<void>` | Reconcile `{ params, page }` in at most one load; params compare structurally |\n| `first()` | `Promise<void>` | Load page one |\n| `goTo(page)` | `Promise<void>` | Load a positive page |\n| `last()` | `Promise<void>` | Load the last known page |\n| `next()` | `Promise<void>` | Load the next known page |\n| `previous()` | `Promise<void>` | Load the previous page |\n| `reload()` | `Promise<void>` | Reload the requested page and params |\n| `setPageSize(pageSize)` | `Promise<void>` | Reset to page one and load with a new size |\n| `setParams(params)` | `Promise<void>` | Reset to page one and load replacement params |\n| `subscribe(listener)` | `() => void` | Register a state listener and return its unsubscribe function |\n| `dispose()` | `void` | Abort work and stop notifications |\n\n`apply(update: PageSourceUpdate<TParams>): Promise<void>` compares params structurally with\n`isEqual`. Changed params use the supplied positive page without clamping, or page one when omitted.\nUnchanged params with a page use `goTo()` and clamp after the first successful load.\nAn unchanged request does not refetch a committed result or duplicate an active request; it loads\nan inert source or retries an uncommitted request after failure. Omitted or `undefined` params\npreserve the requested value; use `setParams(undefined)` when `undefined` is a valid replacement.\nThe update does not include page size; use `setPageSize()` separately.\n\n---\n\n### `createCursorSource()`\n\n```ts\nfunction createCursorSource<T, TParams = undefined, TCursor = string>(\n config: CursorSourceConfig<T, TParams, TCursor>,\n): CursorSource<T, TParams, TCursor>\n```\n\nReturns an inert cursor source.\n\n| Parameter | Type | Description |\n| --- | --- | --- |\n| `config.after` | `TCursor` | Optional initial forward cursor |\n| `config.before` | `TCursor` | Optional initial backward cursor |\n| `config.load` | `(context: CursorLoadContext<TParams, TCursor>) => Promise<CursorResult<T, TCursor>>` | Cursor loader |\n| `config.pageSize` | `number` | Positive page size; defaults to `20` |\n| `config.params` | `TParams` | Initial params; required when `TParams` excludes `undefined` |\n\n**Returns:** `CursorSource<T, TParams, TCursor>`.\n\n```ts\nimport { createCursorSource } from '@vielzeug/sourcerer';\n\nconst source = createCursorSource({ load: async () => ({ items: ['first'], nextCursor: 'next' }) });\nawait source.reload();\nawait source.next();\n```\n\n| Method | Returns | Description |\n| --- | --- | --- |\n| `next()` | `Promise<void>` | Load `state.pagination.nextCursor` when available |\n| `previous()` | `Promise<void>` | Load `state.pagination.previousCursor` when available |\n| `reload()` | `Promise<void>` | Reload the requested cursor and params |\n| `setPageSize(pageSize)` | `Promise<void>` | Clear cursors and reload with a new size |\n| `setParams(params)` | `Promise<void>` | Clear cursors and load replacement params |\n| `subscribe(listener)` | `() => void` | Register a state listener and return its unsubscribe function |\n| `dispose()` | `void` | Abort work and stop notifications |\n\n---\n\n### `createInfiniteSource()`\n\n```ts\nfunction createInfiniteSource<T, TParams = undefined>(\n config: InfiniteSourceConfig<T, TParams>,\n): InfiniteSource<T, TParams>\n```\n\nReturns an inert source that appends numbered pages.\n\n| Parameter | Type | Description |\n| --- | --- | --- |\n| `config.load` | `(context: InfiniteLoadContext<TParams>) => Promise<PageResult<T>>` | Page loader |\n| `config.pageSize` | `number` | Positive page size; defaults to `20` |\n| `config.params` | `TParams` | Initial params; required when `TParams` excludes `undefined` |\n\n**Returns:** `InfiniteSource<T, TParams>`.\n\n```ts\nimport { createInfiniteSource } from '@vielzeug/sourcerer';\n\nconst source = createInfiniteSource({ load: async () => ({ items: ['post'], totalItems: 1 }) });\nawait source.reload();\nawait source.loadMore();\n```\n\n| Method | Returns | Description |\n| --- | --- | --- |\n| `loadMore()` | `Promise<void>` | Append the next page when available |\n| `reload()` | `Promise<void>` | Replace items from page one |\n| `setPageSize(pageSize)` | `Promise<void>` | Replace items from page one with a new size |\n| `setParams(params)` | `Promise<void>` | Replace items from page one with new params |\n| `subscribe(listener)` | `() => void` | Register a state listener and return its unsubscribe function |\n| `dispose()` | `void` | Abort work and stop notifications |\n\n---\n\n### `createResource()`\n\n```ts\nfunction createResource<T>(config: ResourceConfig<T>): Resource<T>\n```\n\nReturns observable state for one asynchronously loaded value. It does not suspend rendering,\ncache by key, or track external reactive inputs.\n\n| Parameter | Type | Description |\n| --- | --- | --- |\n| `config.load` | `(context: ResourceLoadContext) => Promise<T>` | Loader; receives a signal aborted on disposal and on the next `reload()` |\n| `config.start` | `boolean` | Start the initial load during construction; defaults to `true` |\n\n**Returns:** `Resource<T>`.\n\n```ts\nimport { createResource } from '@vielzeug/sourcerer';\n\nconst profile = createResource({\n load: ({ signal }) => fetch('/me', { signal }).then((response) => response.json()),\n start: false,\n});\n\nconst stop = profile.subscribe((state) => console.log(state.data, state.loading, state.error));\nconsole.log(profile.state);\ntry {\n await profile.reload();\n} finally {\n stop();\n profile.dispose();\n}\n```\n\n| Method | Returns | Description |\n| --- | --- | --- |\n| `reload()` | `Promise<void>` | Refetch with a fresh signal; rejects so callers can await it |\n| `subscribe(listener)` | `() => void` | Register a state listener and return its unsubscribe function |\n| `dispose()` | `void` | Abort the in-flight load and stop notifications |\n\nConstruction starts the initial load unless `start: false`. Its failure surfaces through\n`state.error`; a later `reload()` rejects and retains the previous `data` on failure.\nA superseded or disposed request settles without touching state. Subscriptions are change-only:\nread `state` for the current snapshot, including the initial loading state. `dispose()` is idempotent,\naborts `disposalSignal`, and leaves the last snapshot readable; subscriptions after disposal are inert.\n\n## Types\n\n### Page source types\n\n```ts\ntype PagePagination = Readonly<{\n hasNext: boolean;\n hasPrevious: boolean;\n page: number;\n pageCount: number;\n pageSize: number;\n totalItems: number;\n}>;\n\ntype PageSourceState<T, TParams = undefined> = Readonly<{\n error: Error | null;\n items: readonly T[];\n loading: boolean;\n pagination: PagePagination;\n params: TParams;\n pendingParams?: TParams;\n}>;\n\ntype PageLoadContext<TParams = undefined> = Readonly<{\n page: number;\n pageSize: number;\n params: TParams;\n signal: AbortSignal;\n}>;\n\ntype PageResult<T> = Readonly<{\n items: readonly T[];\n totalItems: number;\n}>;\n\ntype PageSourceConfig<T, TParams = undefined> = Readonly<{\n load(context: PageLoadContext<TParams>): Promise<PageResult<T>>;\n pageSize?: number;\n } & (undefined extends TParams ? { params?: TParams } : { params: TParams })\n>;\n\ntype PageSourceUpdate<TParams = undefined> = Readonly<{\n page?: number;\n params?: TParams;\n}>;\n\ntype PageSource<T, TParams = undefined> = {\n [Symbol.dispose](): void;\n apply(update: PageSourceUpdate<TParams>): Promise<void>;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n first(): Promise<void>;\n goTo(page: number): Promise<void>;\n last(): Promise<void>;\n next(): Promise<void>;\n previous(): Promise<void>;\n reload(): Promise<void>;\n setPageSize(pageSize: number): Promise<void>;\n setParams(params: TParams): Promise<void>;\n readonly state: PageSourceState<T, TParams>;\n subscribe(listener: (state: PageSourceState<T, TParams>) => void): () => void;\n};\n```\n\nThe conditional config field makes `params` optional only when `TParams` includes `undefined`.\n\n### Resource types\n\n```ts\ntype ResourceLoadContext = Readonly<{\n signal: AbortSignal;\n}>;\n\ntype ResourceState<T> = Readonly<{\n data: T | undefined;\n error: Error | null;\n loading: boolean;\n}>;\n\ntype ResourceConfig<T> = Readonly<{\n load(context: ResourceLoadContext): Promise<T>;\n start?: boolean;\n}>;\n\ntype Resource<T> = {\n [Symbol.dispose](): void;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n reload(): Promise<void>;\n readonly state: ResourceState<T>;\n subscribe(listener: (state: ResourceState<T>) => void): () => void;\n};\n```\n\n### Local source types\n\n```ts\ntype LocalSourceState<T, TParams = undefined> = Readonly<{\n error: null;\n items: readonly T[];\n loading: false;\n pagination: PagePagination;\n params: TParams;\n}>;\n\ntype LocalSourceConfig<T, TParams = undefined> = Readonly<{\n filter?: (item: T, params: TParams) => boolean;\n pageSize?: number;\n } & (undefined extends TParams ? { params?: TParams } : { params: TParams })\n>;\n\ntype LocalSource<T, TParams = undefined> = {\n [Symbol.dispose](): void;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n first(): void;\n goTo(page: number): void;\n last(): void;\n next(): void;\n previous(): void;\n setItems(items: readonly T[]): void;\n setPageSize(pageSize: number): void;\n setParams(params: TParams): void;\n readonly state: LocalSourceState<T, TParams>;\n subscribe(listener: (state: LocalSourceState<T, TParams>) => void): () => void;\n};\n```\n\n### Cursor source types\n\n```ts\ntype CursorPagination<TCursor = string> = Readonly<{\n nextCursor?: TCursor;\n pageSize: number;\n previousCursor?: TCursor;\n totalItems?: number;\n}>;\n\ntype CursorLoadContext<TParams = undefined, TCursor = string> = Readonly<{\n after?: TCursor;\n before?: TCursor;\n pageSize: number;\n params: TParams;\n signal: AbortSignal;\n}>;\n\ntype CursorResult<T, TCursor = string> = Readonly<{\n items: readonly T[];\n nextCursor?: TCursor;\n previousCursor?: TCursor;\n totalItems?: number;\n}>;\n\ntype CursorSourceState<T, TParams = undefined, TCursor = string> = Readonly<{\n error: Error | null;\n items: readonly T[];\n loading: boolean;\n pagination: CursorPagination<TCursor>;\n params: TParams;\n pendingParams?: TParams;\n}>;\n\ntype CursorSourceConfig<T, TParams = undefined, TCursor = string> = Readonly<{\n after?: TCursor;\n before?: TCursor;\n load(context: CursorLoadContext<TParams, TCursor>): Promise<CursorResult<T, TCursor>>;\n pageSize?: number;\n } & (undefined extends TParams ? { params?: TParams } : { params: TParams })\n>;\n\ntype CursorSource<T, TParams = undefined, TCursor = string> = {\n [Symbol.dispose](): void;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n next(): Promise<void>;\n previous(): Promise<void>;\n reload(): Promise<void>;\n setPageSize(pageSize: number): Promise<void>;\n setParams(params: TParams): Promise<void>;\n readonly state: CursorSourceState<T, TParams, TCursor>;\n subscribe(listener: (state: CursorSourceState<T, TParams, TCursor>) => void): () => void;\n};\n```\n\n### Infinite source types\n\n```ts\ntype InfinitePagination = Readonly<{\n hasMore: boolean;\n loadedItems: number;\n pageSize: number;\n totalItems: number;\n}>;\n\ntype InfiniteLoadContext<TParams = undefined> = Readonly<{\n page: number;\n pageSize: number;\n params: TParams;\n signal: AbortSignal;\n}>;\n\ntype InfiniteSourceState<T, TParams = undefined> = Readonly<{\n error: Error | null;\n items: readonly T[];\n loading: boolean;\n pagination: InfinitePagination;\n params: TParams;\n pendingParams?: TParams;\n}>;\n\ntype InfiniteSourceConfig<T, TParams = undefined> = Readonly<{\n load(context: InfiniteLoadContext<TParams>): Promise<PageResult<T>>;\n pageSize?: number;\n } & (undefined extends TParams ? { params?: TParams } : { params: TParams })\n>;\n\ntype InfiniteSource<T, TParams = undefined> = {\n [Symbol.dispose](): void;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n loadMore(): Promise<void>;\n reload(): Promise<void>;\n setPageSize(pageSize: number): Promise<void>;\n setParams(params: TParams): Promise<void>;\n readonly state: InfiniteSourceState<T, TParams>;\n subscribe(listener: (state: InfiniteSourceState<T, TParams>) => void): () => void;\n};\n```\n\n## Errors\n\n| Error | Trigger | Notable properties |\n| --- | --- | --- |\n| `SourcererError` | Base class for package-originated configuration and lifecycle errors | `instanceof SourcererError` narrows the hierarchy |\n| `SourcererConfigurationError` | Invalid page, page size, total, or initial cursor direction | Extends `SourcererError` |\n| `SourcererDisposedError` | A source command runs after disposal | Extends `SourcererError` |\n\nLoader failures are preserved when they are `Error` instances. Non-Error rejections become `Error` objects whose `cause` contains the original value.\n",
6
+ "usage": "---\ntitle: 'Sourcerer: Usage Guide'\ndescription: Build collection sources, reconcile page and params, and load single-value resources.\n---\n\n[[toc]]\n\n## Basic Usage\n\nCreate a page source and call `reload()` to start the first request. Construction performs no I/O.\n\n```ts\nimport { createPageSource } from '@vielzeug/sourcerer';\n\nconst names = ['Ada', 'Grace', 'Linus'];\nconst source = createPageSource({\n load: async ({ page, pageSize }) => {\n const start = (page - 1) * pageSize;\n return { items: names.slice(start, start + pageSize), totalItems: names.length };\n },\n pageSize: 2,\n});\n\nawait source.reload();\nconsole.log(source.state.items);\nsource.dispose();\n```\n\nRead one `state` object per render. It contains `items`, `loading`, `error`, `params`, and pagination metadata from one committed result. Commands return `Promise<void>`; read `source.state` after awaiting them.\n\n## Pass Loader Parameters\n\nUse `params` for application-owned filters, search terms, sort state, or request options. `setParams()` replaces the entire value and resets pagination.\n\n```ts\nimport { createPageSource } from '@vielzeug/sourcerer';\n\ntype UserParams = { role: 'admin' | 'user'; search: string };\nconst users = ['Ada', 'Grace', 'Linus'];\nconst source = createPageSource<string, UserParams>({\n load: async ({ page, pageSize, params }) => {\n const matching = users.filter((name) => name.toLowerCase().includes(params.search.toLowerCase()));\n const start = (page - 1) * pageSize;\n return { items: matching.slice(start, start + pageSize), totalItems: matching.length };\n },\n params: { role: 'admin', search: '' },\n});\n\nawait source.setParams({ role: 'admin', search: 'ada' });\nconsole.log(source.state.params);\nsource.dispose();\n```\n\nA non-optional parameter type requires an initial `params` value. `setParams()` compares values with `Object.is`; `apply()` compares structurally, avoiding redundant requests from a router or reactive effect. Both can load an inert source or retry an uncommitted request. See [Apply Page and Filter Together](#apply-page-and-filter-together).\n\nWhile replacement parameters load, `state.params` continues to describe the committed items and `state.pendingParams` contains the requested value. Page-only navigation does not set `pendingParams`.\n\n## Navigate Numbered Pages\n\nUse direct commands for numbered-page navigation. `setPageSize()` resets to page one.\n\n```ts\nawait source.reload();\nawait source.next();\nawait source.goTo(4);\nawait source.previous();\nawait source.first();\nawait source.last();\nawait source.setPageSize(50);\n```\n\nAfter the first successful load, navigation is clamped to the known `pageCount`. Before that load, `goTo()` accepts any positive page because the total is unknown.\n\n## Apply Page and Filter Together\n\nA URL query, a filter form, or a router state usually carries the page and the filters at once. `apply()` accepts both in one call and issues at most one request.\n\n```ts\nimport { createPageSource } from '@vielzeug/sourcerer';\n\nconst names = ['Ada', 'Grace', 'Linus', 'Ada Byron'];\nconst source = createPageSource({\n load: async ({ page, pageSize, params }) => {\n const matching = names.filter((name) => name.includes(params.search));\n const start = (page - 1) * pageSize;\n return { items: matching.slice(start, start + pageSize), totalItems: matching.length };\n },\n pageSize: 1,\n params: { search: '' },\n});\n\ntry {\n await source.apply({ page: 2, params: { search: 'Ada' } });\n console.log(source.state.items); // ['Ada Byron']\n await source.apply({ params: { search: 'Ada' } });\n console.log(source.state.pagination.page); // 2; no extra request\n await source.apply({ params: { search: 'Grace' } });\n console.log(source.state.pagination.page); // 1\n} finally {\n source.dispose();\n}\n```\n\nParameters are compared structurally, so a freshly built object with the same contents does not\nrefetch a committed result or duplicate active work. An inert source still loads, and an unchanged\nrequest can retry after failure. When parameters change,\n`page` is validated but never clamped: the page count still describes the previous filter set, so\nclamping against it would silently move the reader elsewhere. Omit `page` in that case and the\nsource returns to page one. When parameters are unchanged, `apply()` routes through `goTo()` and\nclamps to the known page count.\n\nOmitted or `undefined` params keep the requested value. Use `setParams(undefined)` when\nyour parameter type allows `undefined` and you want to replace the value with it.\n\n## Filter Local Collections\n\nUse a local source when data is already in memory. Its commands are synchronous.\n\n```ts\nimport { createLocalSource } from '@vielzeug/sourcerer';\n\nconst source = createLocalSource(['Ada', 'Grace', 'Linus'], {\n filter: (name, search: string) => name.toLowerCase().includes(search.toLowerCase()),\n pageSize: 2,\n params: '',\n});\n\nsource.setParams('a');\nsource.next();\nsource.setItems(['Ada', 'Grace']);\nconsole.log(source.state.items);\nsource.dispose();\n```\n\nUse ordinary arrays for one-off transformations. A local source is useful when pagination, subscriptions, and lifecycle ownership are also required.\n\n## Use Cursor Pagination\n\nReturn opaque cursors from the loader. `next()` and `previous()` use only cursors from the committed state.\n\n```ts\nimport { createCursorSource } from '@vielzeug/sourcerer';\n\nconst rows = ['A', 'B', 'C', 'D'];\nconst source = createCursorSource({\n load: async ({ after, pageSize }) => {\n const start = after ? Number(after) : 0;\n const items = rows.slice(start, start + pageSize);\n const next = start + items.length;\n return {\n items,\n nextCursor: next < rows.length ? String(next) : undefined,\n previousCursor: start > 0 ? String(Math.max(0, start - pageSize)) : undefined,\n };\n },\n pageSize: 2,\n});\n\nawait source.reload();\nawait source.next();\nconsole.log(source.state.items);\nsource.dispose();\n```\n\nChanging params or page size clears current cursor direction. A source cannot start with both `after` and `before`.\n\n## Build an Infinite Feed\n\nUse an infinite source when later pages should append to committed items.\n\n```ts\nimport { createInfiniteSource } from '@vielzeug/sourcerer';\n\nconst values = [1, 2, 3, 4, 5];\nconst source = createInfiniteSource({\n load: async ({ page, pageSize }) => {\n const start = (page - 1) * pageSize;\n return { items: values.slice(start, start + pageSize), totalItems: values.length };\n },\n pageSize: 2,\n});\n\nawait source.reload();\nawait source.loadMore();\nconsole.log(source.state.items);\nsource.dispose();\n```\n\n`loadMore()` is a no-op while another request is active or after `pagination.hasMore` becomes false. `setParams()` and `setPageSize()` replace the feed from page one.\n\n## Load a Single Value\n\nUse a resource for one reactive value: a profile, a settings document, a pricing summary. It loads once and refetches on demand.\n\n```ts\nimport { createResource } from '@vielzeug/sourcerer';\n\ntype Profile = { name: string };\nconst profile = createResource<Profile>({\n load: async ({ signal }) => {\n const response = await fetch('/me', { signal });\n if (!response.ok) throw new Error(`Profile request failed: ${response.status}`);\n return response.json();\n },\n start: false,\n});\n\nconst stop = profile.subscribe((state) => console.log(state.data, state.loading, state.error));\nconsole.log(profile.state);\ntry {\n await profile.reload();\n} catch (error) {\n console.error(error);\n} finally {\n stop();\n profile.dispose();\n}\n```\n\nA resource starts loading during construction by default; the example uses `start: false` to await\nthe first load explicitly. Automatic initial-load failures land in `state.error` without an\nunhandled rejection. Explicit `reload()` calls reject current failures and preserve previous `data`.\nReloading aborts older work, whose promise settles without committing.\n\nRead `state` before subscribing when you need the initial snapshot: subscriptions notify only\nchanges. A resource does not track Ripple signals or cache values by key; call `reload()` when\nexternal inputs change. Disposal aborts work and retains the last readable snapshot.\n\n## Handle Requests and Errors\n\nA new remote command aborts older work. Superseded or disposed work settles without committing. A current loader failure preserves committed items, writes the error to state, and rejects the command.\n\n```ts\ntry {\n await source.reload();\n} catch (error) {\n console.error(error);\n console.log(source.state.error);\n}\n```\n\nLoader result arrays are copied before publication. Commands after disposal throw or reject `SourcererDisposedError`.\n\n## Testing\n\nInject deterministic loaders and await commands before asserting final state.\n\n```ts\nimport { expect, it } from 'vitest';\nimport { createPageSource } from '@vielzeug/sourcerer';\n\nit('loads a page', async () => {\n const source = createPageSource({ load: async () => ({ items: ['Ada'], totalItems: 1 }) });\n\n await source.reload();\n\n expect(source.state.items).toEqual(['Ada']);\n source.dispose();\n});\n```\n\n## Framework Integration\n\nCreate one source per component lifetime and bridge `subscribe()` to the framework lifecycle.\n\n::: code-group\n\n```tsx [React]\nimport { createPageSource } from '@vielzeug/sourcerer';\nimport { useEffect, useMemo, useSyncExternalStore } from 'react';\n\nexport function Users() {\n const source = useMemo(\n () => createPageSource({ load: async () => ({ items: [{ id: 1, name: 'Ada' }], totalItems: 1 }) }),\n [],\n );\n const state = useSyncExternalStore(source.subscribe, () => source.state);\n\n useEffect(() => {\n void source.reload().catch(() => undefined);\n return () => source.dispose();\n }, [source]);\n\n return <p>{state.loading ? 'Loading' : state.items.length}</p>;\n}\n```\n\n```ts [Vue 3]\nimport { onUnmounted, shallowRef } from 'vue';\nimport { createPageSource } from '@vielzeug/sourcerer';\n\nconst source = createPageSource({ load: async () => ({ items: [{ id: 1, name: 'Ada' }], totalItems: 1 }) });\nconst state = shallowRef(source.state);\nconst stop = source.subscribe((next) => (state.value = next));\nvoid source.reload().catch(() => undefined);\n\nonUnmounted(() => {\n stop();\n source.dispose();\n});\n```\n\n```svelte [Svelte]\n<script lang=\"ts\">\n import { onDestroy } from 'svelte';\n import { createPageSource } from '@vielzeug/sourcerer';\n\n const source = createPageSource({ load: async () => ({ items: [{ id: 1, name: 'Ada' }], totalItems: 1 }) });\n let state = source.state;\n const stop = source.subscribe((next) => (state = next));\n void source.reload().catch(() => undefined);\n\n onDestroy(() => {\n stop();\n source.dispose();\n });\n</script>\n\n{#if state.loading}Loading{/if}\n{#each state.items as user}{user.name}{/each}\n```\n\n:::\n\n## Working with Other Vielzeug Libraries\n\nUse Courier for transport policy and pass the source-owned cancellation signal through.\n\n```ts\nimport { createCourier } from '@vielzeug/courier';\nimport { createPageSource } from '@vielzeug/sourcerer';\n\ntype User = { id: number; name: string };\ntype Response = { data: User[]; total: number };\nconst courier = createCourier({ baseUrl: '/api' });\nconst source = createPageSource({\n load: async ({ page, pageSize, params: search, signal }) => {\n const result = await courier.get<Response>('/users', { query: { page, pageSize, search }, signal });\n return { items: result.data, totalItems: result.total };\n },\n params: '',\n});\n```\n\nUse Scout to compute indexed local matches, Ripple to project state into reactive computations, and Wayfinder to validate and synchronize params with the URL.\n\n## Best Practices\n\n- Dispose each source with its owning view, request, or service scope.\n- Read one `state` object per render.\n- Await direct commands or handle rejected current-request failures.\n- Keep transport, caching, and persistence policy outside Sourcerer.\n- Treat `params` as an immutable value and replace it atomically.\n- Debounce text input before calling `setParams()` on a remote source.\n- Validate route and form values before constructing params or page numbers.\n- Keep rendering committed items while `loading` is true.\n",
7
+ "examples": "---\ntitle: 'Sourcerer: Examples'\ndescription: Recipes for local, page, cursor, infinite, resource, and framework source use.\n---\n\n## Examples\n\n- [Local Pagination and Filtering](./examples/local-pagination-and-filtering.md)\n- [Page Params with URL State](./examples/remote-search-with-url-state.md)\n- [Cursor-Based Pagination](./examples/cursor-based-pagination.md)\n- [Infinite Scroll](./examples/infinite-scroll.md)\n- [Load a Single Value](./examples/single-value-resource.md)\n- [Framework Integration](./examples/framework-integration.md)\n- [Remote Data with Courier](./examples/sourcerer-with-courier.md)\n- [Reactive Controls with Ripple](./examples/sourcerer-with-ripple.md)\n- [URL-Synced List with Wayfinder](./examples/sourcerer-with-wayfinder.md)\n"
8
8
  },
9
9
  "examples": [
10
+ {
11
+ "id": "apply",
12
+ "code": "import { createPageSource } from '@vielzeug/sourcerer'\n\nconst allUsers = ['Ada Lovelace', 'Grace Hopper', 'Linus Torvalds', 'Ada Byron']\n\nconst source = createPageSource({\n load: async ({ page, pageSize, params: { search } }) => {\n const matching = search ? allUsers.filter((name) => name.includes(search)) : allUsers\n const start = (page - 1) * pageSize\n return { items: matching.slice(start, start + pageSize), totalItems: matching.length }\n },\n pageSize: 2,\n params: { search: '' },\n})\n\nawait source.reload()\n\n// One call, one request: page and filters arrive together\nawait source.apply({ page: 2, params: { search: '' } })\nconsole.log('Page 2:', source.state.items)\n\n// A structurally identical params object is a no-op, so a re-render cannot refetch\nawait source.apply({ params: { search: '' } })\nconsole.log('Still page 2:', source.state.pagination.page)\n\n// New params reset to page 1 unless a page is given\nawait source.apply({ params: { search: 'Ada' } })\nconsole.log('Filtered:', source.state.items, 'page', source.state.pagination.page)\n\nsource.dispose()",
13
+ "name": "apply - Page and params in one call"
14
+ },
10
15
  {
11
16
  "id": "cursor-source",
12
17
  "code": "import { createCursorSource } from '@vielzeug/sourcerer'\n\nconst items = Array.from({ length: 30 }, (_, index) => ({ id: index + 1, label: `Item ${index + 1}` }))\n\nconst source = createCursorSource({\n load: async ({ after, pageSize }) => {\n const start = after ? Number(after) : 0\n const pageItems = items.slice(start, start + pageSize)\n const next = start + pageItems.length\n return { items: pageItems, nextCursor: next < items.length ? String(next) : undefined, previousCursor: start ? String(Math.max(0, start - pageSize)) : undefined }\n },\n pageSize: 10,\n})\n\nawait source.reload()\nawait source.next()\nconsole.log(source.state.items.map((item) => item.label))\nconsole.log(source.state.pagination)\n\nsource.dispose()",
@@ -14,7 +19,7 @@
14
19
  },
15
20
  {
16
21
  "id": "error-handling",
17
- "code": "import { createPageSource } from '@vielzeug/sourcerer'\n\nconst source = createPageSource({\n load: async () => { throw new Error('network down') },\n})\n\ntry {\n await source.reload()\n} catch (error) {\n console.log((error as Error).message)\n}\n\nconsole.log(source.state.error?.message)\nsource.dispose()",
22
+ "code": "import { createPageSource } from '@vielzeug/sourcerer'\n\nconst source = createPageSource({\n load: async () => { throw new Error('network down') },\n})\n\ntry {\n await source.reload()\n} catch (error) {\n console.log(error.message)\n}\n\nconsole.log(source.state.error?.message)\nsource.dispose()",
18
23
  "name": "Error Handling"
19
24
  },
20
25
  {
@@ -36,6 +41,11 @@
36
41
  "id": "page-source",
37
42
  "code": "import { createPageSource } from '@vielzeug/sourcerer'\n\nconst allItems = Array.from({ length: 47 }, (_, index) => ({ id: index + 1, name: `Item ${index + 1}` }))\n\nconst source = createPageSource({\n load: async ({ page, pageSize, params: search }) => {\n const filtered = search ? allItems.filter((item) => item.name.includes(search)) : allItems\n const start = (page - 1) * pageSize\n return { items: filtered.slice(start, start + pageSize), totalItems: filtered.length }\n },\n pageSize: 10,\n params: '',\n})\n\nawait source.reload()\nawait source.setParams('Item 4')\nconsole.log(source.state.items.map((item) => item.name))\nconsole.log(source.state.pagination)\n\nsource.dispose()",
38
43
  "name": "Page Source"
44
+ },
45
+ {
46
+ "id": "resource",
47
+ "code": "import { createResource } from '@vielzeug/sourcerer'\n\nlet revision = 0\n\nconst profile = createResource({\n load: async ({ signal }) => {\n if (signal.aborted) throw new Error('request aborted')\n revision += 1\n return { name: 'Ada Lovelace', revision }\n },\n start: false,\n})\n\nconsole.log('Initial:', profile.state)\nprofile.subscribe((state) => console.log('Notify:', state.data, 'loading:', state.loading))\n\nawait profile.reload()\nconsole.log('Data:', profile.state.data, 'error:', profile.state.error)\n\nprofile.dispose()\nconsole.log('✓ Disposed')",
48
+ "name": "createResource - One reactive value"
39
49
  }
40
50
  ],
41
51
  "typeSignatures": {
@@ -46,25 +56,31 @@
46
56
  "createInfiniteSource": "export { createInfiniteSource } from './infiniteSource';",
47
57
  "createLocalSource": "export { createLocalSource } from './localSource';",
48
58
  "createPageSource": "export { createPageSource } from './pageSource';",
49
- "CursorLoadContext": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n} from './types';",
50
- "CursorPagination": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n} from './types';",
51
- "CursorResult": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n} from './types';",
52
- "CursorSource": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n} from './types';",
53
- "CursorSourceConfig": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n} from './types';",
54
- "CursorSourceState": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n} from './types';",
55
- "InfiniteLoadContext": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n} from './types';",
56
- "InfinitePagination": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n} from './types';",
57
- "InfiniteSource": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n} from './types';",
58
- "InfiniteSourceConfig": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n} from './types';",
59
- "InfiniteSourceState": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n} from './types';",
60
- "LocalSource": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n} from './types';",
61
- "LocalSourceConfig": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n} from './types';",
62
- "LocalSourceState": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n} from './types';",
63
- "PageLoadContext": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n} from './types';",
64
- "PagePagination": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n} from './types';",
65
- "PageResult": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n} from './types';",
66
- "PageSource": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n} from './types';",
67
- "PageSourceConfig": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n} from './types';",
68
- "PageSourceState": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n} from './types';"
59
+ "createResource": "export { createResource } from './resourceSource';",
60
+ "CursorLoadContext": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';",
61
+ "CursorPagination": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';",
62
+ "CursorResult": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';",
63
+ "CursorSource": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';",
64
+ "CursorSourceConfig": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';",
65
+ "CursorSourceState": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';",
66
+ "InfiniteLoadContext": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';",
67
+ "InfinitePagination": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';",
68
+ "InfiniteSource": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';",
69
+ "InfiniteSourceConfig": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';",
70
+ "InfiniteSourceState": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';",
71
+ "LocalSource": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';",
72
+ "LocalSourceConfig": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';",
73
+ "LocalSourceState": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';",
74
+ "PageLoadContext": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';",
75
+ "PagePagination": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';",
76
+ "PageResult": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';",
77
+ "PageSource": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';",
78
+ "PageSourceConfig": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';",
79
+ "PageSourceState": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';",
80
+ "PageSourceUpdate": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';",
81
+ "Resource": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';",
82
+ "ResourceConfig": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';",
83
+ "ResourceLoadContext": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';",
84
+ "ResourceState": "export type {\n CursorLoadContext,\n CursorPagination,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n CursorSourceState,\n InfiniteLoadContext,\n InfinitePagination,\n InfiniteSource,\n InfiniteSourceConfig,\n InfiniteSourceState,\n LocalSource,\n LocalSourceConfig,\n LocalSourceState,\n PageLoadContext,\n PagePagination,\n PageResult,\n PageSource,\n PageSourceConfig,\n PageSourceState,\n PageSourceUpdate,\n Resource,\n ResourceConfig,\n ResourceLoadContext,\n ResourceState,\n} from './types';"
69
85
  }
70
86
  }