@vielzeug/codex 2.2.8 → 2.2.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.
- package/data/catalog.json +171 -22
- package/data/llms-full.txt +14178 -11054
- package/data/llms.txt +6 -2
- package/data/manifest.json +1 -1
- package/data/packages/courier.json +2 -2
- package/data/packages/dnd.json +2 -2
- package/data/packages/focus.json +37 -0
- package/data/packages/forge.json +9 -10
- package/data/packages/gesture.json +25 -0
- package/data/packages/illusionist.json +132 -0
- package/data/packages/lingua.json +4 -3
- package/data/packages/ore.json +4 -9
- package/data/packages/ripple.json +1 -1
- package/data/packages/sentinel.json +35 -0
- package/data/packages/sourcerer.json +30 -29
- package/data/refine.json +3921 -3960
- package/data/search.json +148 -24
- package/package.json +1 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"apiSource": "export { createElementSize } from './element-size.ts';\nexport { SentinelError, SentinelUnavailableError } from './errors.ts';\nexport type { CreateIntersectionOptions } from './intersection.ts';\nexport { createIntersection } from './intersection.ts';\nexport { createMediaQuery } from './media-query.ts';\nexport { createNetwork } from './network.ts';\nexport type {\n ElementSizeState,\n IntersectionState,\n MediaQueryState,\n NetworkConnectionSnapshot,\n NetworkState,\n Sentinel,\n SentinelOptions,\n ViewportState,\n WindowSentinelOptions,\n} from './types.ts';\nexport { createViewport } from './viewport.ts';\n",
|
|
3
|
+
"docs": {
|
|
4
|
+
"index": "---\ntitle: Sentinel — Reactive environment state\ndescription: Reactive browser and DOM observations for viewport, network, media query, element size, and intersection state.\npackage: sentinel\ncategory: Environment\nkeywords: [reactive, browser, viewport, network, media-query, resize-observer, intersection-observer]\nrelated: [ripple, ore, focus, gesture]\nexports: [createViewport, createNetwork, createMediaQuery, createElementSize, createIntersection, SentinelError, SentinelUnavailableError, Sentinel]\nenvironments: [browser]\n---\n\n<!-- markdownlint-disable MD025 MD033 MD060 -->\n\n<PackageHero package=\"sentinel\" />\n\n## Why Sentinel?\n\nBrowser environment APIs use different events, observer callbacks, initial states, and cleanup methods. Sentinel gives them one explicit handle shape and exposes current values as Ripple `Readable<T>` signals.\n\n```ts\n// Before\n{\n const panel = document.querySelector<HTMLElement>('[data-panel]');\n if (!panel) throw new Error('Panel not found');\n\n const observer = new ResizeObserver(([entry]) => {\n console.log(entry?.contentRect.width);\n });\n observer.observe(panel);\n\n // Later\n observer.disconnect();\n}\n\n// After\nimport { createElementSize } from '@vielzeug/sentinel';\n\n{\n const panel = document.querySelector<HTMLElement>('[data-panel]');\n if (!panel) throw new Error('Panel not found');\n\n const size = createElementSize(panel);\n const unsubscribe = size.subscribe(() => {\n console.log(size.value?.width);\n });\n\n // Later\n unsubscribe();\n size.dispose();\n}\n```\n\n| Feature | Sentinel | Native observer APIs | Ad hoc event listeners |\n| --- | --- | --- | --- |\n| Bundle size | <PackageInfo package=\"sentinel\" type=\"size\" /> | Built in | Application-defined |\n| Zero dependencies | <ore-icon name=\"x\" size=\"16\"></ore-icon> | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"check\" size=\"16\"></ore-icon> |\n| Reactive current state | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> |\n| Consistent disposable handle | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"triangle-alert\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> |\n| Shared abort ownership | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> | <ore-icon name=\"triangle-alert\" size=\"16\"></ore-icon> |\n| Ripple composition | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> |\n\n<div class=\"decision-callout\">\n\n**Use Sentinel when** browser or DOM observations need reactive state, consistent ownership, and composition with Ripple.\n\n**Consider native APIs when** one isolated observer is sufficient and adding Ripple as a peer dependency is not justified.\n\n</div>\n\n## Installation\n\n::: code-group\n\n```sh [pnpm]\npnpm add @vielzeug/sentinel @vielzeug/ripple\n```\n\n```sh [npm]\nnpm install @vielzeug/sentinel @vielzeug/ripple\n```\n\n```sh [yarn]\nyarn add @vielzeug/sentinel @vielzeug/ripple\n```\n\n:::\n\n## Quick Start\n\nCreate a viewport Sentinel, render its initial state, then react to changes until the page lifetime ends.\n\n```ts\nimport { createViewport } from '@vielzeug/sentinel';\n\nfunction observeViewport(): () => void {\n const viewport = createViewport();\n const render = () => {\n const { dpr, height, width } = viewport.value;\n console.log(`${width}×${height} at ${dpr}dpr`);\n };\n\n render();\n const unsubscribe = viewport.subscribe(render);\n\n return () => {\n unsubscribe();\n viewport.dispose();\n };\n}\n\nconst stopObserving = observeViewport();\n// Call stopObserving() when the owning view unmounts.\n```\n\n<div class=\"features-grid\">\n\n## Features\n\n- `createViewport()` — Observe viewport dimensions and device pixel ratio.\n- `createNetwork()` — Track online status and optional connection details.\n- `createMediaQuery()` — Observe one media query.\n- `createElementSize()` — Read content-box dimensions from `ResizeObserver`.\n- `createIntersection()` — Track normalized intersection state.\n- `dispose()` — Release owned browser observers and listeners.\n- `SentinelOptions.signal` — Abort several Sentinels through one external lifetime.\n\n</div>\n\n<div class=\"doc-links\">\n\n## Documentation\n\n- [**Usage Guide**](./usage.md) — Apply Sentinel lifecycles, framework bindings, and Ripple composition.\n- [**API Reference**](./api.md) — Review factory signatures, options, state types, and errors.\n- [**Examples**](./examples.md) — Follow focused browser observation examples.\n\n</div>\n\n<div class=\"see-also\">\n\n## See Also\n\n- [@vielzeug/ripple](../ripple/) — Derive and watch values from Sentinel state.\n- [@vielzeug/ore](../ore/) — Bind Sentinels to web-component mount and cleanup lifecycles.\n- [@vielzeug/focus](../focus/) — Manage keyboard focus alongside observed UI state.\n- [@vielzeug/gesture](../gesture/) — Handle pointer gestures alongside environmental observations.\n\n</div>\n\n<!-- markdownlint-enable MD025 MD033 MD060 -->\n",
|
|
5
|
+
"api": "---\ntitle: Sentinel — API Reference\ndescription: Factory signatures, options, state types, lifecycle handles, and errors for Sentinel.\n---\n\n[[toc]]\n\n## API Overview\n\n| Symbol | Purpose | Execution mode | Common gotcha |\n| --- | --- | --- | --- |\n| `createViewport()` | Observe layout viewport dimensions and device pixel ratio | Sync | Requires a browser Window |\n| `createNetwork()` | Observe online status and optional connection information | Sync | `connection` is often `null` |\n| `createMediaQuery()` | Observe one media query | Sync | Throws when `matchMedia` is unavailable |\n| `createElementSize()` | Observe element content-box dimensions | Sync | Value is `null` before the first delivery |\n| `createIntersection()` | Observe element intersection state | Sync | Value is `null` before the first delivery |\n| `Sentinel<T>` | Combine a Ripple readable with explicit browser-resource ownership | Sync | Subscriptions and the Sentinel have separate cleanup |\n| `SentinelError` | Base class for package-defined errors | Sync | Catch a subtype when recovery is specific |\n| `SentinelUnavailableError` | Report an unavailable browser API | Sync | Invalid observer inputs retain their native errors |\n\n## Package Entry Point\n\n| Import | Purpose |\n| --- | --- |\n| `@vielzeug/sentinel` | All factories, state types, option types, and error classes |\n\n## Factories\n\n### `createViewport()`\n\n```ts\nfunction createViewport(options?: WindowSentinelOptions): Sentinel<ViewportState>;\n```\n\nReturns a Sentinel initialized from the layout viewport's `innerWidth`, `innerHeight`, and `devicePixelRatio`.\n\n| Parameter | Type | Description |\n| --- | --- | --- |\n| `options.target` | `Window` | Window to observe instead of the global browser window |\n| `options.runtime` | `Pick<Ripple, 'signal'>` | Ripple runtime that owns the internal signal |\n| `options.signal` | `AbortSignal` | External signal that disposes the Sentinel |\n\n**Returns:** `Sentinel<ViewportState>`.\n\n**Example**\n\n```ts\nimport { createViewport } from '@vielzeug/sentinel';\n\nconst viewport = createViewport();\nconsole.log(viewport.value.width);\nviewport.dispose();\n```\n\n---\n\n### `createNetwork()`\n\n```ts\nfunction createNetwork(options?: WindowSentinelOptions): Sentinel<NetworkState>;\n```\n\nReturns a Sentinel initialized from `navigator.onLine` and the optional Network Information API.\n\n| Parameter | Type | Description |\n| --- | --- | --- |\n| `options.target` | `Window` | Window whose navigator and events are observed |\n| `options.runtime` | `Pick<Ripple, 'signal'>` | Ripple runtime that owns the internal signal |\n| `options.signal` | `AbortSignal` | External signal that disposes the Sentinel |\n\n**Returns:** `Sentinel<NetworkState>`.\n\n**Example**\n\n```ts\nimport { createNetwork } from '@vielzeug/sentinel';\n\nconst network = createNetwork();\nconsole.log(network.value.online);\nnetwork.dispose();\n```\n\n---\n\n### `createMediaQuery()`\n\n```ts\nfunction createMediaQuery(query: string, options?: WindowSentinelOptions): Sentinel<MediaQueryState>;\n```\n\nReturns a Sentinel initialized from `matchMedia(query).matches`.\n\n| Parameter | Type | Description |\n| --- | --- | --- |\n| `query` | `string` | CSS media query to observe |\n| `options.target` | `Window` | Window whose `matchMedia` method is used |\n| `options.runtime` | `Pick<Ripple, 'signal'>` | Ripple runtime that owns the internal signal |\n| `options.signal` | `AbortSignal` | External signal that disposes the Sentinel |\n\n**Returns:** `Sentinel<MediaQueryState>`.\n\n**Example**\n\n```ts\nimport { createMediaQuery } from '@vielzeug/sentinel';\n\nconst darkMode = createMediaQuery('(prefers-color-scheme: dark)');\nconsole.log(darkMode.value.matches);\ndarkMode.dispose();\n```\n\n---\n\n### `createElementSize()`\n\n```ts\nfunction createElementSize(element: Element, options?: SentinelOptions): Sentinel<ElementSizeState | null>;\n```\n\nReturns a Sentinel containing the latest `ResizeObserverEntry.contentRect` dimensions.\n\n| Parameter | Type | Description |\n| --- | --- | --- |\n| `element` | `Element` | Element to observe |\n| `options.runtime` | `Pick<Ripple, 'signal'>` | Ripple runtime that owns the internal signal |\n| `options.signal` | `AbortSignal` | External signal that disposes the Sentinel |\n\n**Returns:** `Sentinel<ElementSizeState | null>`. The initial value is `null`.\n\n**Example**\n\n```ts\nimport { createElementSize } from '@vielzeug/sentinel';\n\nconst size = createElementSize(document.body);\nconst unsubscribe = size.subscribe(() => {\n console.log(size.value?.width);\n});\n\nunsubscribe();\nsize.dispose();\n```\n\n---\n\n### `createIntersection()`\n\n```ts\nfunction createIntersection(\n element: Element,\n options?: CreateIntersectionOptions,\n): Sentinel<IntersectionState | null>;\n```\n\nReturns a Sentinel containing normalized fields from the latest IntersectionObserver entry.\n\n| Parameter | Type | Description |\n| --- | --- | --- |\n| `element` | `Element` | Element to observe |\n| `options.root` | `Element \\| Document \\| null` | Intersection root |\n| `options.rootMargin` | `string` | Margin applied to the root |\n| `options.scrollMargin` | `string` | Margin applied to nested scroll containers |\n| `options.threshold` | `number \\| number[]` | Intersection ratio threshold or thresholds |\n| `options.runtime` | `Pick<Ripple, 'signal'>` | Ripple runtime that owns the internal signal |\n| `options.signal` | `AbortSignal` | External signal that disposes the Sentinel |\n\n**Returns:** `Sentinel<IntersectionState | null>`. The initial value is `null`.\n\n**Example**\n\n```ts\nimport { createIntersection } from '@vielzeug/sentinel';\n\nconst intersection = createIntersection(document.body, { threshold: 0.5 });\nconst unsubscribe = intersection.subscribe(() => {\n console.log(intersection.value?.isIntersecting);\n});\n\nunsubscribe();\nintersection.dispose();\n```\n\n## Types\n\n### `Sentinel<T>`\n\n```ts\ninterface Sentinel<T> extends Readable<T> {\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n [Symbol.dispose](): void;\n}\n```\n\n`value`, `peek()`, and `subscribe()` follow Ripple's `Readable<T>` contract. `dispose()` stops the underlying browser observation. A subscription's returned function remains independently owned by the subscriber.\n\n| Member | Type | Description |\n| --- | --- | --- |\n| `value` | `T` | Current reactive snapshot |\n| `peek()` | `() => T` | Read the snapshot without reactive tracking |\n| `subscribe(listener)` | `(listener: () => void) => () => void` | Subscribe to invalidations and return an independent unsubscribe function |\n| `disposed` | `boolean` | Whether observation has ended |\n| `disposalSignal` | `AbortSignal` | Aborts when observation ends |\n| `dispose()` | `() => void` | Stop observation and release owned browser resources |\n| `[Symbol.dispose]()` | `() => void` | Dispose through the explicit resource-management protocol |\n\n---\n\n### `SentinelOptions`\n\n```ts\ninterface SentinelOptions {\n readonly runtime?: Pick<Ripple, 'signal'>;\n readonly signal?: AbortSignal;\n}\n```\n\n---\n\n### `WindowSentinelOptions`\n\n```ts\ninterface WindowSentinelOptions extends SentinelOptions {\n readonly target?: Window;\n}\n```\n\n---\n\n### `CreateIntersectionOptions`\n\n```ts\ninterface CreateIntersectionOptions extends SentinelOptions {\n readonly root?: Element | Document | null;\n readonly rootMargin?: string;\n readonly scrollMargin?: string;\n readonly threshold?: number | number[];\n}\n```\n\n---\n\n### `ViewportState`\n\n```ts\ninterface ViewportState {\n readonly dpr: number;\n readonly height: number;\n readonly width: number;\n}\n```\n\n---\n\n### `NetworkConnectionSnapshot`\n\n```ts\ninterface NetworkConnectionSnapshot {\n readonly downlink?: number;\n readonly effectiveType?: 'slow-2g' | '2g' | '3g' | '4g';\n readonly rtt?: number;\n readonly saveData?: boolean;\n}\n```\n\n---\n\n### `NetworkState`\n\n```ts\ninterface NetworkState {\n readonly connection: NetworkConnectionSnapshot | null;\n readonly online: boolean;\n}\n```\n\n---\n\n### `MediaQueryState`\n\n```ts\ninterface MediaQueryState {\n readonly matches: boolean;\n}\n```\n\n---\n\n### `ElementSizeState`\n\n```ts\ninterface ElementSizeState {\n readonly height: number;\n readonly width: number;\n}\n```\n\n---\n\n### `IntersectionState`\n\n```ts\ninterface IntersectionState {\n readonly intersectionRatio: number;\n readonly isIntersecting: boolean;\n}\n```\n\n## Errors\n\n### `SentinelError`\n\n```ts\nclass SentinelError extends Error {\n constructor(message: string, options?: ErrorOptions);\n}\n```\n\nBase class for package-defined errors.\n\n---\n\n### `SentinelUnavailableError`\n\n```ts\nclass SentinelUnavailableError extends SentinelError {}\n```\n\nThrown when a required browser API or Window is unavailable:\n\n- `createViewport()` and `createNetwork()` when no browser Window is available.\n- `createMediaQuery()` when `matchMedia` is unavailable.\n- `createElementSize()` when the element has no Window or `ResizeObserver` is unavailable.\n- `createIntersection()` when the element has no Window or `IntersectionObserver` is unavailable.\n\nNative setup errors remain unchanged, including invalid observer options or targets.\n",
|
|
6
|
+
"usage": "---\ntitle: Sentinel — Usage Guide\ndescription: Observe browser and DOM state with explicit reactive lifecycles.\n---\n\n[[toc]]\n\n## Basic Usage\n\nCreate a Sentinel, read its current state, subscribe to invalidations, and release both resources when the owner ends.\n\n```ts\nimport { createViewport } from '@vielzeug/sentinel';\n\nfunction observeViewport(): () => void {\n const viewport = createViewport();\n\n const render = () => {\n const { dpr, height, width } = viewport.value;\n console.log(`${width}×${height} at ${dpr}dpr`);\n };\n\n render();\n const unsubscribe = viewport.subscribe(render);\n\n return () => {\n unsubscribe();\n viewport.dispose();\n };\n}\n\nconst stopObserving = observeViewport();\n// Call stopObserving() when the owning view unmounts.\n```\n\n`subscribe()` notifies you that the value changed; read the new snapshot from `.value` inside the listener. Disposing a Sentinel stops its browser observer or event listeners. It does not unsubscribe consumers from the Ripple readable.\n\n## Observe Window State\n\nUse `createViewport()` for viewport dimensions and device pixel ratio.\n\n```ts\nimport { createViewport } from '@vielzeug/sentinel';\n\nconst viewport = createViewport();\nconsole.log(viewport.value.width);\nconsole.log(viewport.value.height);\nconsole.log(viewport.value.dpr);\n```\n\nUse `createNetwork()` for online status and the optional Network Information API snapshot.\n\n```ts\nimport { createNetwork } from '@vielzeug/sentinel';\n\nconst network = createNetwork();\nconsole.log(network.value.online);\nconsole.log(network.value.connection);\n```\n\n`connection` is `null` when `navigator.connection` is unavailable.\n\n## Observe Media Queries\n\nUse `createMediaQuery()` to react to a browser media query.\n\n```ts\nimport { createMediaQuery, SentinelUnavailableError } from '@vielzeug/sentinel';\n\nfunction observeReducedMotion(): () => void {\n try {\n const reducedMotion = createMediaQuery('(prefers-reduced-motion: reduce)');\n\n const applyPreference = () => {\n document.documentElement.classList.toggle('reduce-motion', reducedMotion.value.matches);\n };\n\n applyPreference();\n const unsubscribe = reducedMotion.subscribe(applyPreference);\n\n return () => {\n unsubscribe();\n reducedMotion.dispose();\n };\n } catch (error) {\n if (!(error instanceof SentinelUnavailableError)) throw error;\n return () => {};\n }\n}\n\nconst stopObserving = observeReducedMotion();\n// Call stopObserving() when the owning view unmounts.\n```\n\n`createMediaQuery()` throws `SentinelUnavailableError` when `matchMedia` is unavailable.\n\n## Observe Elements\n\n### Element Size\n\nUse `createElementSize()` after the target element exists.\n\n```ts\nimport { createElementSize } from '@vielzeug/sentinel';\n\nconst panel = document.querySelector<HTMLElement>('[data-panel]');\nif (!panel) throw new Error('Panel not found');\n\nconst size = createElementSize(panel);\nconst unsubscribe = size.subscribe(() => {\n const current = size.value;\n if (current) panel.dataset.width = String(current.width);\n});\n```\n\nThe initial state is `null` until `ResizeObserver` reports its first measurement.\n\n### Intersection\n\nUse `createIntersection()` to observe visibility relative to the viewport or a custom root.\n\n```ts\nimport { createIntersection } from '@vielzeug/sentinel';\n\nconst target = document.querySelector<HTMLElement>('[data-lazy-section]');\nif (!target) throw new Error('Section not found');\n\nconst intersection = createIntersection(target, {\n rootMargin: '100px',\n threshold: [0, 0.5, 1],\n});\n\nconst unsubscribe = intersection.subscribe(() => {\n target.hidden = !intersection.value?.isIntersecting;\n});\n```\n\nThe initial state is `null` until `IntersectionObserver` reports its first entry.\n\n## Control Ownership\n\nCall `dispose()` to stop observation. Disposal is idempotent.\n\n```ts\nconst viewport = createViewport();\n\nviewport.dispose();\nviewport.dispose();\n```\n\nPass an `AbortSignal` when several Sentinels share one lifetime.\n\n```ts\nconst controller = new AbortController();\nconst viewport = createViewport({ signal: controller.signal });\nconst network = createNetwork({ signal: controller.signal });\n\ncontroller.abort();\n```\n\nAn injected Ripple runtime creates the state signal. Runtime disposal and Sentinel disposal remain separate responsibilities.\n\n```ts\nimport { createRipple } from '@vielzeug/ripple';\nimport { createViewport } from '@vielzeug/sentinel';\n\nconst ripple = createRipple();\nconst viewport = createViewport({ runtime: ripple });\n\nviewport.dispose();\nripple.dispose();\n```\n\n## Handle Unavailable APIs\n\n`createMediaQuery()`, `createElementSize()`, and `createIntersection()` report unavailable platform APIs with `SentinelUnavailableError`.\n\n```ts\nimport { createElementSize, SentinelUnavailableError } from '@vielzeug/sentinel';\n\ntry {\n const size = createElementSize(document.body);\n size.dispose();\n} catch (error) {\n if (error instanceof SentinelUnavailableError) {\n console.warn(error.message);\n } else {\n throw error;\n }\n}\n```\n\nInvoke all factories only in a browser client lifecycle. Package imports are safe during SSR, but factories require browser or DOM APIs.\n\n## Framework Integration\n\nCreate the Sentinel after the component mounts, mirror its current value into framework state, and unsubscribe and dispose on unmount.\n\n::: code-group\n\n```tsx [React]\nimport { createViewport, type ViewportState } from '@vielzeug/sentinel';\nimport { useEffect, useState } from 'react';\n\nexport function ViewportSize() {\n const [viewportState, setViewportState] = useState<ViewportState | null>(null);\n\n useEffect(() => {\n const viewport = createViewport();\n const update = () => setViewportState(viewport.value);\n\n update();\n const unsubscribe = viewport.subscribe(update);\n\n return () => {\n unsubscribe();\n viewport.dispose();\n };\n }, []);\n\n return <output>{viewportState ? `${viewportState.width}×${viewportState.height}` : 'Measuring…'}</output>;\n}\n```\n\n```vue [Vue 3]\n<script setup lang=\"ts\">\nimport { createViewport, type Sentinel, type ViewportState } from '@vielzeug/sentinel';\nimport { onMounted, onUnmounted, ref } from 'vue';\n\nconst viewportState = ref<ViewportState | null>(null);\nlet viewport: Sentinel<ViewportState> | undefined;\nlet unsubscribe: (() => void) | undefined;\n\nonMounted(() => {\n viewport = createViewport();\n const update = () => {\n viewportState.value = viewport?.value ?? null;\n };\n\n update();\n unsubscribe = viewport.subscribe(update);\n});\n\nonUnmounted(() => {\n unsubscribe?.();\n viewport?.dispose();\n});\n</script>\n\n<template>\n <output>\n {{ viewportState ? `${viewportState.width}×${viewportState.height}` : 'Measuring…' }}\n </output>\n</template>\n```\n\n```svelte [Svelte]\n<script lang=\"ts\">\n import { createViewport, type ViewportState } from '@vielzeug/sentinel';\n import { onMount } from 'svelte';\n\n let viewportState: ViewportState | null = null;\n\n onMount(() => {\n const viewport = createViewport();\n const update = () => {\n viewportState = viewport.value;\n };\n\n update();\n const unsubscribe = viewport.subscribe(update);\n\n return () => {\n unsubscribe();\n viewport.dispose();\n };\n });\n</script>\n\n<output>\n {viewportState ? `${viewportState.width}×${viewportState.height}` : 'Measuring…'}\n</output>\n```\n\n:::\n\n## Working with Other Vielzeug Libraries\n\n### Sentinel + Ripple\n\nUse Ripple to derive values from one or more Sentinel states. Dispose the watcher separately from the Sentinels.\n\n```ts\nimport { computed, watch } from '@vielzeug/ripple';\nimport { createMediaQuery, createViewport } from '@vielzeug/sentinel';\n\nconst viewport = createViewport();\nconst mobileQuery = createMediaQuery('(max-width: 768px)');\nconst compact = computed(() => mobileQuery.value.matches || viewport.value.width < 400);\nconst compactWatcher = watch(compact, (value) => console.log('Compact layout:', value), { immediate: true });\n\ncompactWatcher.dispose();\nmobileQuery.dispose();\nviewport.dispose();\n```\n\n### Sentinel + Ore\n\nCreate DOM-dependent Sentinels in `onMounted()` and register both subscription and Sentinel cleanup with the component.\n\n```ts\nimport { define, html, onCleanup, onMounted, ref } from '@vielzeug/ore';\nimport { createElementSize } from '@vielzeug/sentinel';\n\ndefine('measured-panel', {\n setup() {\n const panel = ref<HTMLElement>();\n\n onMounted(() => {\n const element = panel.value;\n if (!element) return;\n\n const size = createElementSize(element);\n const update = () => {\n element.dataset.width = String(size.value?.width ?? 0);\n };\n const unsubscribe = size.subscribe(update);\n\n onCleanup(() => {\n unsubscribe();\n size.dispose();\n });\n });\n\n return html`<section ref=${panel}>Measured panel</section>`;\n },\n});\n```\n\n## Best Practices\n\n- **Create** DOM-dependent Sentinels only after their target elements exist.\n- **Read** the latest snapshot from `.value` inside subscription listeners.\n- **Unsubscribe** Ripple listeners when their owner ends.\n- **Dispose** every Sentinel to release browser observers and event listeners.\n- **Share** an `AbortSignal` when multiple Sentinels have the same lifetime.\n- **Guard** APIs that can throw `SentinelUnavailableError`.\n- **Treat** `NetworkState.connection` as optional browser enhancement data.\n- **Invoke** factories only in browser client lifecycles.\n",
|
|
7
|
+
"examples": "---\ntitle: Sentinel — Examples\ndescription: Focused browser and DOM observation examples for Sentinel.\n---\n\n## Examples\n\n- [Responsive Viewport Tracking](./examples/responsive-viewport-tracking.md)\n- [Monitor Network Condition](./examples/monitor-network-condition.md)\n- [Respect Reduced Motion Preference](./examples/respect-reduced-motion-preference.md)\n- [Responsive Column Layout](./examples/responsive-column-layout.md)\n- [Lazy Load Images on Intersection](./examples/lazy-load-images-on-intersection.md)\n"
|
|
8
|
+
},
|
|
9
|
+
"examples": [
|
|
10
|
+
{
|
|
11
|
+
"id": "viewport-basic",
|
|
12
|
+
"code": "import { createViewport } from '@vielzeug/sentinel'\n\nconst viewport = createViewport()\nconst logViewport = () => {\n const { dpr, height, width } = viewport.value\n console.log(`${width}x${height} at ${dpr}dpr`)\n}\n\nlogViewport()\nconst unsubscribe = viewport.subscribe(logViewport)\nwindow.dispatchEvent(new Event('resize'))\n\nunsubscribe()\nviewport.dispose()\nconsole.log('disposed:', viewport.disposed)",
|
|
13
|
+
"name": "createViewport - Basic"
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"typeSignatures": {
|
|
17
|
+
"createElementSize": "export { createElementSize } from './element-size.ts';",
|
|
18
|
+
"SentinelError": "export { SentinelError, SentinelUnavailableError } from './errors.ts';",
|
|
19
|
+
"SentinelUnavailableError": "export { SentinelError, SentinelUnavailableError } from './errors.ts';",
|
|
20
|
+
"CreateIntersectionOptions": "export type { CreateIntersectionOptions } from './intersection.ts';",
|
|
21
|
+
"createIntersection": "export { createIntersection } from './intersection.ts';",
|
|
22
|
+
"createMediaQuery": "export { createMediaQuery } from './media-query.ts';",
|
|
23
|
+
"createNetwork": "export { createNetwork } from './network.ts';",
|
|
24
|
+
"ElementSizeState": "export type {\n ElementSizeState,\n IntersectionState,\n MediaQueryState,\n NetworkConnectionSnapshot,\n NetworkState,\n Sentinel,\n SentinelOptions,\n ViewportState,\n WindowSentinelOptions,\n} from './types.ts';",
|
|
25
|
+
"IntersectionState": "export type {\n ElementSizeState,\n IntersectionState,\n MediaQueryState,\n NetworkConnectionSnapshot,\n NetworkState,\n Sentinel,\n SentinelOptions,\n ViewportState,\n WindowSentinelOptions,\n} from './types.ts';",
|
|
26
|
+
"MediaQueryState": "export type {\n ElementSizeState,\n IntersectionState,\n MediaQueryState,\n NetworkConnectionSnapshot,\n NetworkState,\n Sentinel,\n SentinelOptions,\n ViewportState,\n WindowSentinelOptions,\n} from './types.ts';",
|
|
27
|
+
"NetworkConnectionSnapshot": "export type {\n ElementSizeState,\n IntersectionState,\n MediaQueryState,\n NetworkConnectionSnapshot,\n NetworkState,\n Sentinel,\n SentinelOptions,\n ViewportState,\n WindowSentinelOptions,\n} from './types.ts';",
|
|
28
|
+
"NetworkState": "export type {\n ElementSizeState,\n IntersectionState,\n MediaQueryState,\n NetworkConnectionSnapshot,\n NetworkState,\n Sentinel,\n SentinelOptions,\n ViewportState,\n WindowSentinelOptions,\n} from './types.ts';",
|
|
29
|
+
"Sentinel": "export type {\n ElementSizeState,\n IntersectionState,\n MediaQueryState,\n NetworkConnectionSnapshot,\n NetworkState,\n Sentinel,\n SentinelOptions,\n ViewportState,\n WindowSentinelOptions,\n} from './types.ts';",
|
|
30
|
+
"SentinelOptions": "export type {\n ElementSizeState,\n IntersectionState,\n MediaQueryState,\n NetworkConnectionSnapshot,\n NetworkState,\n Sentinel,\n SentinelOptions,\n ViewportState,\n WindowSentinelOptions,\n} from './types.ts';",
|
|
31
|
+
"ViewportState": "export type {\n ElementSizeState,\n IntersectionState,\n MediaQueryState,\n NetworkConnectionSnapshot,\n NetworkState,\n Sentinel,\n SentinelOptions,\n ViewportState,\n WindowSentinelOptions,\n} from './types.ts';",
|
|
32
|
+
"WindowSentinelOptions": "export type {\n ElementSizeState,\n IntersectionState,\n MediaQueryState,\n NetworkConnectionSnapshot,\n NetworkState,\n Sentinel,\n SentinelOptions,\n ViewportState,\n WindowSentinelOptions,\n} from './types.ts';",
|
|
33
|
+
"createViewport": "export { createViewport } from './viewport.ts';"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"apiSource": "export { createCursorSource } from './cursorSource';\nexport { createInfiniteSource } from './infiniteSource';\nexport { createLocalSource } from './localSource';\nexport { createPageSource } from './pageSource';\nexport type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';\n",
|
|
2
|
+
"apiSource": "export { createCursorSource } from './cursorSource';\nexport { createInfiniteSource } from './infiniteSource';\nexport { createLocalSource } from './localSource';\nexport { createPageSource } from './pageSource';\nexport type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';\n",
|
|
3
3
|
"docs": {
|
|
4
|
-
"index": "---\ntitle: Sourcerer — Reactive Query Sources\ndescription: Framework-agnostic collection sources for local, page, cursor, and infinite pagination.\npackage: sourcerer\ncategory: data\nkeywords: [pagination, data-source, cursor, infinite-scroll, search]\nrelated: [courier, ripple, scout, wayfinder]\nexports:\n [\n createCursorSource,\n createInfiniteSource,\n createLocalSource,\n createPageSource,\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n LoadContext,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n ]\nenvironments: [browser, node, ssr, deno]\n---\n\n<!-- markdownlint-disable MD025 MD033 MD060 -->\n\n<PackageHero package=\"sourcerer\" />\n\n## Why Sourcerer?\n\nLists often combine pagination, search, request cancellation, and render state. Sourcerer gives local arrays and remote loaders one snapshot contract while leaving caching, retries, and transport policy to your application.\n\n```ts\nimport { createPageSource } from '@vielzeug/sourcerer';\n\ntype User = { id: number; name: string };\n\n// Before: query changes can mix old items with new loading and page state.\nlet items: User[] = [];\nlet page = 1;\nlet isLoading = false;\n\n// After: one source publishes internally consistent loaded state.\nconst source = createPageSource<User>({\n autoStart: false,\n load: async () => ({ data: [{ id: 1, name: 'Ada' }], total: 1 }),\n});\nsource.subscribe((snapshot) => console.log(snapshot.data));\nsource.dispose();\n```\n\n| Feature | Sourcerer | Manual list state | Courier query cache |\n| --- | --- | --- | --- |\n| Bundle size | <PackageInfo package=\"sourcerer\" type=\"size\" /> | Application-defined | <PackageInfo package=\"courier\" type=\"size\" /> |\n| Zero runtime dependencies | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> |\n| Local and remote collections | <ore-icon name=\"check\" size=\"16\"></ore-icon> | Application-defined | <ore-icon name=\"triangle-alert\" size=\"16\"></ore-icon> |\n| Cursor and infinite pagination | <ore-icon name=\"check\" size=\"16\"></ore-icon> | Application-defined | <ore-icon name=\"triangle-alert\" size=\"16\"></ore-icon> |\n| Latest-request cancellation | <ore-icon name=\"check\" size=\"16\"></ore-icon> | Application-defined | Transport-level |\n\n<div class=\"decision-callout\">\n\n**Use Sourcerer when** one UI collection needs local or remote pagination with an explicit, framework-independent snapshot contract.\n\n**Consider Courier alone when** you only need cached HTTP queries and pagination state belongs elsewhere.\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, then dispose it with its owner.\n\n```ts\nimport { createPageSource } from '@vielzeug/sourcerer';\n\ntype User = { id: number; name: string };\n\nconst source = createPageSource<User>({\n autoStart: false,\n load: async ({ query }) => {\n const users = [\n { id: 1, name: 'Ada' },\n { id: 2, name: 'Grace' },\n { id: 3, name: 'Linus' },\n ];\n const start = (query.page - 1) * query.pageSize;\n\n return { data: users.slice(start, start + query.pageSize), total: users.length };\n },\n});\n\ntry {\n await source.reload();\n console.log(source.snapshot.data);\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()` — synchronous search and numbered pagination over an array\n- `createPageSource()` — numbered remote pages with latest-request cancellation\n- `createCursorSource()` — sequential opaque-cursor navigation\n- `createInfiniteSource()` — append-only page loading\n- `SourceSnapshot` — loaded `query`, `data`, and `pagination` plus optional `pendingQuery`\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/) — use as transport, caching, and retry policy inside a page loader\n- [Scout](/scout/) — adapt an indexed search matcher for local sources\n- [Ripple](/ripple/) — project source snapshots into reactive application state\n- [Wayfinder](/wayfinder/) — validate and synchronize page query fields 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 | Common gotcha |\n| --- | --- | --- | --- |\n| `createLocalSource()` | In-memory search and pagination | Sync | Prepare filtering and ranking before `setData()` |\n| `createPageSource()` | Numbered async pages | Async | `query` remains loaded state while `pendingQuery` is active |\n| `createCursorSource()` | Cursor-based async pages | Async | `after` and `before` cannot coexist |\n| `createInfiniteSource()` | Appended async pages | Async | `loadMore()` does nothing while fetching or exhausted |\n| `SourceSnapshot` | Atomic loaded state plus pending request | Type | Read `pendingQuery` for newer in-flight state |\n\n## Package Entry Point\n\n| Import | Purpose |\n| --- | --- |\n| `@vielzeug/sourcerer` | Factories and public types |\n\n## Factories\n\n### `createLocalSource()`\n\n```ts\nfunction createLocalSource<T>(data: readonly T[], config?: LocalSourceConfig<T>): LocalSource<T>\n```\n\nCreates a synchronous source over an in-memory collection.\n\n| Option | Type | Description |\n| --- | --- | --- |\n| `initialQuery` | `LocalQueryPatch` | Initial page, page size, or search value |\n| `match` | `(item, search) => boolean` | Explicit search predicate |\n\n**Returns:** `LocalSource<T>`.\n\n```ts\nimport { createLocalSource } from '@vielzeug/sourcerer';\n\nconst users = createLocalSource(\n [{ id: 1, name: 'Ada' }],\n {\n initialQuery: { pageSize: 20 },\n match: (user, search) => user.name.toLowerCase().includes(search.toLowerCase()),\n },\n);\n\nusers.setQuery({ search: 'ada' });\n```\n\n---\n\n### `createPageSource()`\n\n```ts\nfunction createPageSource<T, TFilter = unknown, TSort = unknown>(\n config: PageSourceConfig<T, TFilter, TSort>,\n): PageSource<T, TFilter, TSort>\n```\n\nCreates a numbered source. New queries abort older work. Loaded state stays in `snapshot`; newer work appears in `snapshot.pendingQuery`.\n\n| Option | Type | Description |\n| --- | --- | --- |\n| `autoStart` | `boolean` | Start initial request; default `true` |\n| `initialQuery` | `PageQueryPatch<TFilter, TSort>` | Initial query values |\n| `load` | `(context) => Promise<PageResult<T>>` | Transport callback |\n\n**Returns:** `PageSource<T, TFilter, TSort>`.\n\n```ts\nimport { createPageSource } from '@vielzeug/sourcerer';\n\nconst users = createPageSource({\n autoStart: false,\n load: async () => ({ data: [{ id: 1, name: 'Ada' }], total: 1 }),\n});\n\nawait users.setQuery({ page: 1 });\nusers.dispose();\n```\n\n---\n\n### `createCursorSource()`\n\n```ts\nfunction createCursorSource<T, TCursor = string>(\n config: CursorSourceConfig<T, TCursor>,\n): CursorSource<T, TCursor>\n```\n\nCreates a sequential cursor source. Search and page-size changes reset cursors.\n\n**Returns:** `CursorSource<T, TCursor>`.\n\n```ts\nimport { createCursorSource } from '@vielzeug/sourcerer';\n\nconst orders = createCursorSource({\n autoStart: false,\n load: async () => ({ data: ['order-1'] }),\n});\n\nawait orders.reload();\nawait orders.page.next();\norders.dispose();\n```\n\n---\n\n### `createInfiniteSource()`\n\n```ts\nfunction createInfiniteSource<T>(config: InfiniteSourceConfig<T>): InfiniteSource<T>\n```\n\nCreates an append-only source. Query changes replace loaded collection after successful first-page load.\n\n**Returns:** `InfiniteSource<T>`.\n\n```ts\nimport { createInfiniteSource } from '@vielzeug/sourcerer';\n\nconst feed = createInfiniteSource({\n autoStart: false,\n load: async () => ({ data: ['post-1'], total: 1 }),\n});\n\nawait feed.loadMore();\nfeed.dispose();\n```\n\n## Types\n\n### Source primitives\n\n```ts\ntype Disposable = {\n [Symbol.dispose](): void;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n};\n\ntype SourceSnapshot<T, TQuery, TPagination extends AnyPagination = AnyPagination> = Readonly<{\n data: readonly T[];\n error: Error | null;\n isFetching: boolean;\n pagination: TPagination;\n pendingQuery?: TQuery;\n query: TQuery;\n}>;\n\ntype Source<T, TQuery, TPagination extends AnyPagination = AnyPagination> = Disposable & {\n readonly snapshot: SourceSnapshot<T, TQuery, TPagination>;\n subscribe(listener: (snapshot: SourceSnapshot<T, TQuery, TPagination>) => void): () => void;\n};\n```\n\n### Numbered pages\n\n```ts\ntype PagePagination = Readonly<{\n count: number;\n hasNext: boolean;\n hasPrevious: boolean;\n index: number;\n kind: 'page';\n size: number;\n total: number;\n}>;\n\ntype PageQuery<TFilter = unknown, TSort = unknown> = Readonly<{\n filter?: TFilter;\n page: number;\n pageSize: number;\n search: string;\n sort?: TSort;\n}>;\n\ntype PageQueryPatch<TFilter = unknown, TSort = unknown> = Readonly<{\n filter?: TFilter | undefined;\n page?: number;\n pageSize?: number;\n search?: string;\n sort?: TSort | undefined;\n}>;\n\ntype PageResult<T> = Readonly<{ data: readonly T[]; total: number }>;\ntype LoadContext<TQuery> = Readonly<{ query: TQuery; signal: AbortSignal }>;\n\ntype PageSourceConfig<T, TFilter = unknown, TSort = unknown> = Readonly<{\n autoStart?: boolean;\n initialQuery?: PageQueryPatch<TFilter, TSort>;\n load(context: LoadContext<PageQuery<TFilter, TSort>>): Promise<PageResult<T>>;\n}>;\n\ntype PageSource<T, TFilter = unknown, TSort = unknown> = Source<T, PageQuery<TFilter, TSort>, PagePagination> & {\n readonly page: Readonly<{\n go(index: number): Promise<void>;\n last(): Promise<void>;\n next(): Promise<void>;\n previous(): Promise<void>;\n }>;\n reload(): Promise<void>;\n setQuery(changes: PageQueryPatch<TFilter, TSort>): Promise<void>;\n};\n```\n\n### Local sources\n\n```ts\ntype LocalQuery = Readonly<{ page: number; pageSize: number; search: string }>;\ntype LocalQueryPatch = Readonly<{ page?: number; pageSize?: number; search?: string }>;\ntype LocalSourceConfig<T> = Readonly<{\n initialQuery?: LocalQueryPatch;\n match?: (item: T, search: string) => boolean;\n}>;\n\ntype LocalSource<T> = Source<T, LocalQuery, PagePagination> & {\n readonly page: Readonly<{\n go(index: number): void;\n last(): void;\n next(): void;\n previous(): void;\n }>;\n setData(data: readonly T[]): void;\n setQuery(changes: LocalQueryPatch): void;\n};\n```\n\n### Cursor and infinite sources\n\n```ts\ntype CursorPagination<TCursor = string> = Readonly<{\n hasNext: boolean;\n hasPrevious: boolean;\n kind: 'cursor';\n nextCursor?: TCursor;\n previousCursor?: TCursor;\n total?: number;\n}>;\n\ntype CursorQuery<TCursor = string> = Readonly<{\n after?: TCursor;\n before?: TCursor;\n pageSize: number;\n search: string;\n}>;\n\ntype CursorQueryPatch<TCursor = string> = Readonly<{\n after?: TCursor | undefined;\n before?: TCursor | undefined;\n pageSize?: number;\n search?: string;\n}>;\n\ntype CursorResult<T, TCursor = string> = Readonly<{\n data: readonly T[];\n nextCursor?: TCursor;\n previousCursor?: TCursor;\n total?: number;\n}>;\n\ntype CursorSourceConfig<T, TCursor = string> = Readonly<{\n autoStart?: boolean;\n initialQuery?: CursorQueryPatch<TCursor>;\n load(context: LoadContext<CursorQuery<TCursor>>): Promise<CursorResult<T, TCursor>>;\n}>;\n\ntype CursorSource<T, TCursor = string> = Source<T, CursorQuery<TCursor>, CursorPagination<TCursor>> & {\n readonly page: Readonly<{ next(): Promise<void>; previous(): Promise<void> }>;\n reload(): Promise<void>;\n setQuery(changes: CursorQueryPatch<TCursor>): Promise<void>;\n};\n\ntype InfinitePagination = Readonly<{\n hasMore: boolean;\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\nUse a local source when data already exists in memory.\n\n```ts\nimport { createLocalSource } from '@vielzeug/sourcerer';\n\nconst source = createLocalSource(\n [\n { id: 1, name: 'Ada' },\n { id: 2, name: 'Grace' },\n { id: 3, name: 'Linus' },\n ],\n {\n initialQuery: { pageSize: 2 },\n match: (user, search) => user.name.toLowerCase().includes(search.toLowerCase()),\n },\n);\n\nsource.setQuery({ search: 'a' });\nconsole.log(source.snapshot.data);\nsource.dispose();\n```\n\nRead `snapshot.query`, `snapshot.data`, and `snapshot.pagination` together. They always describe one loaded result.\n\n## Handle Pending Remote Queries\n\nUse `pendingQuery` to distinguish loaded data from newer work.\n\n```ts\nimport { createPageSource } from '@vielzeug/sourcerer';\n\nconst source = createPageSource<string>({\n autoStart: false,\n load: async ({ query }) => {\n const data = ['Ada', 'Grace', 'Linus'];\n const start = (query.page - 1) * query.pageSize;\n\n return { data: data.slice(start, start + query.pageSize), total: data.length };\n },\n});\n\nsource.subscribe((snapshot) => {\n if (snapshot.pendingQuery) console.log('Loading:', snapshot.pendingQuery);\n console.log('Loaded:', snapshot.query, snapshot.data);\n});\n\nawait source.setQuery({ page: 2 });\nsource.dispose();\n```\n\nNew `setQuery()` calls abort older requests. A failed current request preserves prior loaded data, records `snapshot.error`, and rejects the returned promise.\n\n## Use Cursor Pagination\n\nUse cursors when an API cannot provide stable page numbers.\n\n```ts\nimport { createCursorSource } from '@vielzeug/sourcerer';\n\nconst rows = ['A', 'B', 'C', 'D'];\nconst source = createCursorSource<string, number>({\n autoStart: false,\n initialQuery: { pageSize: 2 },\n load: async ({ query }) => {\n const start = query.after ?? 0;\n const data = rows.slice(start, start + query.pageSize);\n const nextCursor = start + data.length;\n\n return {\n data,\n nextCursor: nextCursor < rows.length ? nextCursor : undefined,\n previousCursor: start > 0 ? Math.max(0, start - query.pageSize) : undefined,\n };\n },\n});\n\nawait source.reload();\nawait source.page.next();\nconsole.log(source.snapshot.data);\nsource.dispose();\n```\n\n`after` and `before` cannot coexist. Search or page-size changes reset cursor state.\n\n## Build an Infinite Feed\n\nUse an infinite source when each page should append.\n\n```ts\nimport { createInfiniteSource } from '@vielzeug/sourcerer';\n\nconst source = createInfiniteSource<number>({\n autoStart: false,\n initialQuery: { pageSize: 2 },\n load: async ({ query }) => {\n const values = [1, 2, 3, 4, 5];\n const start = (query.page - 1) * query.pageSize;\n\n return { data: values.slice(start, start + query.pageSize), total: values.length };\n },\n});\n\nawait source.loadMore();\nawait source.loadMore();\nconsole.log(source.snapshot.data);\nsource.dispose();\n```\n\n`loadMore()` is a no-op while fetching or after `pagination.hasMore` becomes false.\n\n## Testing and Debugging\n\nInject deterministic loaders in unit tests. Await source commands before reading final state.\n\n```ts\nimport { expect, it } from 'vitest';\nimport { createPageSource } from '@vielzeug/sourcerer';\n\nit('loads first page', async () => {\n const source = createPageSource({\n autoStart: false,\n load: async () => ({ data: ['Ada'], total: 1 }),\n });\n\n await source.reload();\n expect(source.snapshot.data).toEqual(['Ada']);\n source.dispose();\n});\n```\n\n## Framework Integration\n\nSubscribe through each framework’s lifecycle. Keep source creation stable across renders.\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 () => ({ data: [{ id: 1, name: 'Ada' }], total: 1 }) }),\n [],\n );\n const snapshot = useSyncExternalStore(source.subscribe, () => source.snapshot);\n\n useEffect(() => () => source.dispose(), [source]);\n\n return <p>{snapshot.isFetching ? 'Loading' : snapshot.data.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 () => ({ data: [{ id: 1, name: 'Ada' }], total: 1 }) });\nconst snapshot = shallowRef(source.snapshot);\nconst stop = source.subscribe((next) => (snapshot.value = next));\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 () => ({ data: [{ id: 1, name: 'Ada' }], total: 1 }) });\n let snapshot = source.snapshot;\n const stop = source.subscribe((next) => (snapshot = next));\n\n onDestroy(() => {\n stop();\n source.dispose();\n });\n</script>\n\n{#if snapshot.isFetching}Loading{/if}\n{#each snapshot.data as user}{user.name}{/each}\n```\n\n:::\n\n## Working with Other Vielzeug Libraries\n\nUse Courier for transport policy. Sourcerer owns request succession; Courier owns HTTP behavior.\n\n```ts\nimport { createCourier } from '@vielzeug/courier';\nimport { createPageSource } from '@vielzeug/sourcerer';\n\nconst courier = createCourier({ baseUrl: '/api' });\nconst source = createPageSource({\n load: ({ query, signal }) => courier.get('/users', { query, signal }),\n});\n```\n\nUse Scout’s matcher when local search needs an index.\n\n```ts\nimport { createIndex, toSearchMatcher } from '@vielzeug/scout';\nimport { createLocalSource } from '@vielzeug/sourcerer';\n\nconst users = [{ name: 'Ada' }, { name: 'Grace' }];\nconst index = createIndex(users, { fields: ['name'] });\nconst source = createLocalSource(users, { match: toSearchMatcher(index) });\n```\n\n## Best Practices\n\n- Dispose each source with its owning view, request, or scope.\n- Read one snapshot object per render instead of mixing source fields across updates.\n- Inspect `pendingQuery` before rendering controls for in-flight work.\n- Validate URL query values before passing them to `setQuery()`.\n- Keep caching, retries, polling, and optimistic writes in your transport layer.\n- Use `setData()` with prepared local collections; keep ranking and filtering explicit.\n- Debounce text inputs before updating remote source queries.\n",
|
|
4
|
+
"index": "---\ntitle: Sourcerer — Reactive Query Sources\ndescription: Framework-agnostic collection sources for local, page, cursor, and infinite pagination.\npackage: sourcerer\ncategory: data\nkeywords: [pagination, data-source, cursor, infinite-scroll, search]\nrelated: [courier, ripple, scout, wayfinder]\nexports:\n [\n createCursorSource,\n createInfiniteSource,\n createLocalSource,\n createPageSource,\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfinitePagination,\n InfiniteLoadQuery,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n LoadContext,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n ]\nenvironments: [browser, node, ssr, deno]\n---\n\n<!-- markdownlint-disable MD025 MD033 MD060 -->\n\n<PackageHero package=\"sourcerer\" />\n\n## Why Sourcerer?\n\nLists often combine pagination, search, request cancellation, and render state. Sourcerer gives local arrays and remote loaders one snapshot contract while leaving caching, retries, and transport policy to your application.\n\n```ts\nimport { createPageSource } from '@vielzeug/sourcerer';\n\ntype User = { id: number; name: string };\n\n// Before: query changes can mix old items with new loading and page state.\nlet items: User[] = [];\nlet page = 1;\nlet isLoading = false;\n\n// After: one source publishes internally consistent loaded state.\nconst source = createPageSource<User>({\n autoStart: false,\n load: async () => ({ data: [{ id: 1, name: 'Ada' }], total: 1 }),\n});\nsource.subscribe((snapshot) => console.log(snapshot.data));\nsource.dispose();\n```\n\n| Feature | Sourcerer | Manual list state | Courier query cache |\n| --- | --- | --- | --- |\n| Bundle size | <PackageInfo package=\"sourcerer\" type=\"size\" /> | Application-defined | <PackageInfo package=\"courier\" type=\"size\" /> |\n| Zero runtime dependencies | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> |\n| Local and remote collections | <ore-icon name=\"check\" size=\"16\"></ore-icon> | Application-defined | <ore-icon name=\"triangle-alert\" size=\"16\"></ore-icon> |\n| Cursor and infinite pagination | <ore-icon name=\"check\" size=\"16\"></ore-icon> | Application-defined | <ore-icon name=\"triangle-alert\" size=\"16\"></ore-icon> |\n| Latest-request cancellation | <ore-icon name=\"check\" size=\"16\"></ore-icon> | Application-defined | Transport-level |\n\n<div class=\"decision-callout\">\n\n**Use Sourcerer when** one UI collection needs local or remote pagination with an explicit, framework-independent snapshot contract.\n\n**Consider Courier alone when** you only need cached HTTP queries and pagination state belongs elsewhere.\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, then dispose it with its owner.\n\n```ts\nimport { createPageSource } from '@vielzeug/sourcerer';\n\ntype User = { id: number; name: string };\n\nconst source = createPageSource<User>({\n autoStart: false,\n load: async ({ query }) => {\n const users = [\n { id: 1, name: 'Ada' },\n { id: 2, name: 'Grace' },\n { id: 3, name: 'Linus' },\n ];\n const start = (query.page - 1) * query.pageSize;\n\n return { data: users.slice(start, start + query.pageSize), total: users.length };\n },\n});\n\ntry {\n await source.reload();\n console.log(source.snapshot.data);\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()` — synchronous search and numbered pagination over an array\n- `createPageSource()` — numbered remote pages with latest-request cancellation\n- `createCursorSource()` — sequential opaque-cursor navigation\n- `createInfiniteSource()` — append-only page loading\n- `SourceSnapshot` — loaded `query`, `data`, and `pagination` plus optional `pendingQuery`\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/) — use as transport, caching, and retry policy inside a page loader\n- [Scout](/scout/) — adapt an indexed search matcher for local sources\n- [Ripple](/ripple/) — project source snapshots into reactive application state\n- [Wayfinder](/wayfinder/) — validate and synchronize page query fields 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 | Common gotcha |\n| --- | --- | --- | --- |\n| `createLocalSource()` | In-memory search and pagination | Sync | Prepare filtering and ranking before `setData()` |\n| `createPageSource()` | Numbered async pages | Async | `query` remains loaded state while `pendingQuery` is active |\n| `createCursorSource()` | Cursor-based async pages | Async | `after` and `before` cannot coexist |\n| `createInfiniteSource()` | Appended async pages | Async | `loadMore()` does nothing while fetching or exhausted; `pendingQuery` set only on query replace, not append |\n| `SourceSnapshot` | Atomic loaded state plus pending request | Type | Read `pendingQuery` for newer in-flight state |\n\n## Package Entry Point\n\n| Import | Purpose |\n| --- | --- |\n| `@vielzeug/sourcerer` | Factories and public types |\n\n## Factories\n\n### `createLocalSource()`\n\n```ts\nfunction createLocalSource<T>(data: readonly T[], config?: LocalSourceConfig<T>): LocalSource<T>\n```\n\nCreates a synchronous source over an in-memory collection.\n\n| Option | Type | Description |\n| --- | --- | --- |\n| `initialQuery` | `LocalQueryPatch` | Initial page, page size, or search value |\n| `match` | `(item, search) => boolean` | Explicit search predicate |\n\n**Returns:** `LocalSource<T>`.\n\n```ts\nimport { createLocalSource } from '@vielzeug/sourcerer';\n\nconst users = createLocalSource(\n [{ id: 1, name: 'Ada' }],\n {\n initialQuery: { pageSize: 20 },\n match: (user, search) => user.name.toLowerCase().includes(search.toLowerCase()),\n },\n);\n\nusers.setQuery({ search: 'ada' });\n```\n\n---\n\n### `createPageSource()`\n\n```ts\nfunction createPageSource<T, TFilter = unknown, TSort = unknown>(\n config: PageSourceConfig<T, TFilter, TSort>,\n): PageSource<T, TFilter, TSort>\n```\n\nCreates a numbered source. New queries abort older work. Loaded state stays in `snapshot`; newer work appears in `snapshot.pendingQuery`.\n\n| Option | Type | Description |\n| --- | --- | --- |\n| `autoStart` | `boolean` | Start initial request; default `true` |\n| `initialQuery` | `PageQueryPatch<TFilter, TSort>` | Initial query values |\n| `load` | `(context) => Promise<PageResult<T>>` | Transport callback |\n\n**Returns:** `PageSource<T, TFilter, TSort>`.\n\n```ts\nimport { createPageSource } from '@vielzeug/sourcerer';\n\nconst users = createPageSource({\n autoStart: false,\n load: async () => ({ data: [{ id: 1, name: 'Ada' }], total: 1 }),\n});\n\nawait users.setQuery({ page: 1 });\nusers.dispose();\n```\n\n---\n\n### `createCursorSource()`\n\n```ts\nfunction createCursorSource<T, TCursor = string>(\n config: CursorSourceConfig<T, TCursor>,\n): CursorSource<T, TCursor>\n```\n\nCreates a sequential cursor source. Search and page-size changes reset cursors.\n\n**Returns:** `CursorSource<T, TCursor>`.\n\n```ts\nimport { createCursorSource } from '@vielzeug/sourcerer';\n\nconst orders = createCursorSource({\n autoStart: false,\n load: async () => ({ data: ['order-1'] }),\n});\n\nawait orders.reload();\nawait orders.page.next();\norders.dispose();\n```\n\n---\n\n### `createInfiniteSource()`\n\n```ts\nfunction createInfiniteSource<T>(config: InfiniteSourceConfig<T>): InfiniteSource<T>\n```\n\nCreates an append-only source. Query changes replace loaded collection after successful first-page load.\n\n**Returns:** `InfiniteSource<T>`.\n\n```ts\nimport { createInfiniteSource } from '@vielzeug/sourcerer';\n\nconst feed = createInfiniteSource({\n autoStart: false,\n load: async () => ({ data: ['post-1'], total: 1 }),\n});\n\nawait feed.loadMore();\nfeed.dispose();\n```\n\n## Types\n\n### Source primitives\n\n```ts\ntype Disposable = {\n [Symbol.dispose](): void;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n};\n\ntype SourceSnapshot<T, TQuery, TPagination extends AnyPagination = AnyPagination> = Readonly<{\n data: readonly T[];\n error: Error | null;\n isFetching: boolean;\n pagination: TPagination;\n pendingQuery?: TQuery;\n query: TQuery;\n}>;\n\ntype Source<T, TQuery, TPagination extends AnyPagination = AnyPagination> = Disposable & {\n readonly snapshot: SourceSnapshot<T, TQuery, TPagination>;\n subscribe(listener: (snapshot: SourceSnapshot<T, TQuery, TPagination>) => void): () => void;\n};\n```\n\n### Numbered pages\n\n```ts\ntype PagePagination = Readonly<{\n count: number;\n hasNext: boolean;\n hasPrevious: boolean;\n index: number;\n kind: 'page';\n size: number;\n total: number;\n}>;\n\ntype PageQuery<TFilter = unknown, TSort = unknown> = Readonly<{\n filter?: TFilter;\n page: number;\n pageSize: number;\n search: string;\n sort?: TSort;\n}>;\n\ntype PageQueryPatch<TFilter = unknown, TSort = unknown> = Readonly<{\n filter?: TFilter | undefined;\n page?: number;\n pageSize?: number;\n search?: string;\n sort?: TSort | undefined;\n}>;\n\ntype PageResult<T> = Readonly<{ data: readonly T[]; total: number }>;\ntype LoadContext<TQuery> = Readonly<{ query: TQuery; signal: AbortSignal }>;\n\ntype PageSourceConfig<T, TFilter = unknown, TSort = unknown> = Readonly<{\n autoStart?: boolean;\n initialQuery?: PageQueryPatch<TFilter, TSort>;\n load(context: LoadContext<PageQuery<TFilter, TSort>>): Promise<PageResult<T>>;\n}>;\n\ntype PageSource<T, TFilter = unknown, TSort = unknown> = Source<T, PageQuery<TFilter, TSort>, PagePagination> & {\n readonly page: Readonly<{\n go(index: number): Promise<void>;\n last(): Promise<void>;\n next(): Promise<void>;\n previous(): Promise<void>;\n }>;\n reload(): Promise<void>;\n setQuery(changes: PageQueryPatch<TFilter, TSort>): Promise<void>;\n};\n```\n\n### Local sources\n\n```ts\ntype LocalQuery = Readonly<{ page: number; pageSize: number; search: string }>;\ntype LocalQueryPatch = Readonly<{ page?: number; pageSize?: number; search?: string }>;\ntype LocalSourceConfig<T> = Readonly<{\n initialQuery?: LocalQueryPatch;\n match?: (item: T, search: string) => boolean;\n}>;\n\ntype LocalSource<T> = Source<T, LocalQuery, PagePagination> & {\n readonly page: Readonly<{\n go(index: number): void;\n last(): void;\n next(): void;\n previous(): void;\n }>;\n setData(data: readonly T[]): void;\n setQuery(changes: LocalQueryPatch): void;\n};\n```\n\n### Cursor and infinite sources\n\n```ts\ntype CursorPagination<TCursor = string> = Readonly<{\n hasNext: boolean;\n hasPrevious: boolean;\n kind: 'cursor';\n nextCursor?: TCursor;\n previousCursor?: TCursor;\n total?: number;\n}>;\n\ntype CursorQuery<TCursor = string> = Readonly<{\n after?: TCursor;\n before?: TCursor;\n pageSize: number;\n search: string;\n}>;\n\ntype CursorQueryPatch<TCursor = string> = Readonly<{\n after?: TCursor | undefined;\n before?: TCursor | undefined;\n pageSize?: number;\n search?: string;\n}>;\n\ntype CursorResult<T, TCursor = string> = Readonly<{\n data: readonly T[];\n nextCursor?: TCursor;\n previousCursor?: TCursor;\n total?: number;\n}>;\n\ntype CursorSourceConfig<T, TCursor = string> = Readonly<{\n autoStart?: boolean;\n initialQuery?: CursorQueryPatch<TCursor>;\n load(context: LoadContext<CursorQuery<TCursor>>): Promise<CursorResult<T, TCursor>>;\n}>;\n\ntype CursorSource<T, TCursor = string> = Source<T, CursorQuery<TCursor>, CursorPagination<TCursor>> & {\n readonly page: Readonly<{ next(): Promise<void>; previous(): Promise<void> }>;\n reload(): Promise<void>;\n setQuery(changes: CursorQueryPatch<TCursor>): Promise<void>;\n};\n\ntype InfinitePagination = Readonly<{\n hasMore: boolean;\n kind: 'infinite';\n loaded: number;\n total: number;\n}>;\n\ntype InfiniteQuery = Readonly<{ pageSize: number; search: string }>;\ntype InfiniteQueryPatch = Readonly<{ pageSize?: number; search?: string }>;\ntype InfiniteLoadQuery = Readonly<{ page: number; pageSize: number; search: string }>;\n\ntype InfiniteSourceConfig<T> = Readonly<{\n autoStart?: boolean;\n initialQuery?: InfiniteQueryPatch;\n load(context: LoadContext<InfiniteLoadQuery>): Promise<PageResult<T>>;\n}>;\n\ntype InfiniteSource<T> = Source<T, InfiniteQuery, InfinitePagination> & {\n loadMore(): Promise<void>;\n reload(): Promise<void>;\n setQuery(changes: InfiniteQueryPatch): Promise<void>;\n};\n```\n\n### Shared helpers\n\n```ts\ntype AnyPagination = CursorPagination<unknown> | InfinitePagination | PagePagination;\n```\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\nUse a local source when data already exists in memory.\n\n```ts\nimport { createLocalSource } from '@vielzeug/sourcerer';\n\nconst source = createLocalSource(\n [\n { id: 1, name: 'Ada' },\n { id: 2, name: 'Grace' },\n { id: 3, name: 'Linus' },\n ],\n {\n initialQuery: { pageSize: 2 },\n match: (user, search) => user.name.toLowerCase().includes(search.toLowerCase()),\n },\n);\n\nsource.setQuery({ search: 'a' });\nconsole.log(source.snapshot.data);\nsource.dispose();\n```\n\nRead `snapshot.query`, `snapshot.data`, and `snapshot.pagination` together. They always describe one loaded result.\n\n## Handle Pending Remote Queries\n\nUse `pendingQuery` to distinguish loaded data from newer work.\n\n```ts\nimport { createPageSource } from '@vielzeug/sourcerer';\n\nconst source = createPageSource<string>({\n autoStart: false,\n load: async ({ query }) => {\n const data = ['Ada', 'Grace', 'Linus'];\n const start = (query.page - 1) * query.pageSize;\n\n return { data: data.slice(start, start + query.pageSize), total: data.length };\n },\n});\n\nsource.subscribe((snapshot) => {\n if (snapshot.pendingQuery) console.log('Loading:', snapshot.pendingQuery);\n console.log('Loaded:', snapshot.query, snapshot.data);\n});\n\nawait source.setQuery({ page: 2 });\nsource.dispose();\n```\n\nNew `setQuery()` calls abort older requests. A failed current request preserves prior loaded data, records `snapshot.error`, and rejects the returned promise.\n\n## Use Cursor Pagination\n\nUse cursors when an API cannot provide stable page numbers.\n\n```ts\nimport { createCursorSource } from '@vielzeug/sourcerer';\n\nconst rows = ['A', 'B', 'C', 'D'];\nconst source = createCursorSource<string, number>({\n autoStart: false,\n initialQuery: { pageSize: 2 },\n load: async ({ query }) => {\n const start = query.after ?? 0;\n const data = rows.slice(start, start + query.pageSize);\n const nextCursor = start + data.length;\n\n return {\n data,\n nextCursor: nextCursor < rows.length ? nextCursor : undefined,\n previousCursor: start > 0 ? Math.max(0, start - query.pageSize) : undefined,\n };\n },\n});\n\nawait source.reload();\nawait source.page.next();\nconsole.log(source.snapshot.data);\nsource.dispose();\n```\n\n`after` and `before` cannot coexist. Search or page-size changes reset cursor state.\n\n## Build an Infinite Feed\n\nUse an infinite source when each page should append.\n\n```ts\nimport { createInfiniteSource } from '@vielzeug/sourcerer';\n\nconst source = createInfiniteSource<number>({\n autoStart: false,\n initialQuery: { pageSize: 2 },\n load: async ({ query }) => {\n const values = [1, 2, 3, 4, 5];\n const start = (query.page - 1) * query.pageSize;\n\n return { data: values.slice(start, start + query.pageSize), total: values.length };\n },\n});\n\nawait source.loadMore();\nawait source.loadMore();\nconsole.log(source.snapshot.data);\nsource.dispose();\n```\n\n`loadMore()` is a no-op while fetching or after `pagination.hasMore` becomes false.\n\n## Testing and Debugging\n\nInject deterministic loaders in unit tests. Await source commands before reading final state.\n\n```ts\nimport { expect, it } from 'vitest';\nimport { createPageSource } from '@vielzeug/sourcerer';\n\nit('loads first page', async () => {\n const source = createPageSource({\n autoStart: false,\n load: async () => ({ data: ['Ada'], total: 1 }),\n });\n\n await source.reload();\n expect(source.snapshot.data).toEqual(['Ada']);\n source.dispose();\n});\n```\n\n## Framework Integration\n\nSubscribe through each framework’s lifecycle. Keep source creation stable across renders.\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 () => ({ data: [{ id: 1, name: 'Ada' }], total: 1 }) }),\n [],\n );\n const snapshot = useSyncExternalStore(source.subscribe, () => source.snapshot);\n\n useEffect(() => () => source.dispose(), [source]);\n\n return <p>{snapshot.isFetching ? 'Loading' : snapshot.data.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 () => ({ data: [{ id: 1, name: 'Ada' }], total: 1 }) });\nconst snapshot = shallowRef(source.snapshot);\nconst stop = source.subscribe((next) => (snapshot.value = next));\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 () => ({ data: [{ id: 1, name: 'Ada' }], total: 1 }) });\n let snapshot = source.snapshot;\n const stop = source.subscribe((next) => (snapshot = next));\n\n onDestroy(() => {\n stop();\n source.dispose();\n });\n</script>\n\n{#if snapshot.isFetching}Loading{/if}\n{#each snapshot.data as user}{user.name}{/each}\n```\n\n:::\n\n## Working with Other Vielzeug Libraries\n\nUse Courier for transport policy. Sourcerer owns request succession; Courier owns HTTP behavior.\n\n```ts\nimport { createCourier } from '@vielzeug/courier';\nimport { createPageSource } from '@vielzeug/sourcerer';\n\nconst courier = createCourier({ baseUrl: '/api' });\nconst source = createPageSource({\n load: ({ query, signal }) => courier.get('/users', { query, signal }),\n});\n```\n\nUse Scout’s matcher when local search needs an index.\n\n```ts\nimport { createIndex, toSearchMatcher } from '@vielzeug/scout';\nimport { createLocalSource } from '@vielzeug/sourcerer';\n\nconst users = [{ name: 'Ada' }, { name: 'Grace' }];\nconst index = createIndex(users, { fields: ['name'] });\nconst source = createLocalSource(users, { match: toSearchMatcher(index) });\n```\n\n## Gotchas\n\n### Navigation methods are no-ops while fetching\n\n`page.go()`, `page.next()`, `page.previous()`, `page.last()` (page and cursor sources) and `loadMore()` (infinite source) return a resolved promise and change nothing while a request is in flight. This prevents queued navigation from racing with abort logic. If a user clicks \"next\" during a fetch, the click is lost — debounce or disable navigation controls while `snapshot.isFetching` is true.\n\n### `pendingQuery` means a different query is in flight\n\nFor page and cursor sources, `pendingQuery` is always set when a new query is loading. For infinite sources, `pendingQuery` is set only when `setQuery()` or `reload()` replaces the query — not during `loadMore()` append fetches. To detect an append in progress on an infinite source, read `snapshot.isFetching` with `pendingQuery` absent.\n\n### `sameQuery` uses reference equality\n\n`setQuery()` compares the new query against the current one using `Object.is` per field. For `filter` and `sort` (opaque `TFilter`/`TSort` types), a new object with the same content triggers a refetch. Memoize filter/sort objects in your application layer if you want to avoid redundant requests.\n\n### Clear optional query fields by passing `undefined` explicitly\n\nIn `PageQueryPatch`, omitting `filter` preserves the current value; passing `filter: undefined` clears it. The same applies to `sort`. In `CursorQueryPatch`, omitting `after`/`before` preserves the current cursor; passing `after: undefined` or `before: undefined` clears it. This distinction is runtime-only — TypeScript's optional-field syntax does not distinguish \"absent\" from \"explicitly `undefined`.\"\n\n```ts\n// Page source: keep current filter, change page:\nsource.setQuery({ page: 2 });\n\n// Page source: clear filter, reset to page 1:\nsource.setQuery({ filter: undefined });\n\n// Cursor source: clear after cursor:\nsource.setQuery({ after: undefined });\n```\n\n## Best Practices\n\n- Dispose each source with its owning view, request, or scope.\n- Read one snapshot object per render instead of mixing source fields across updates.\n- Inspect `pendingQuery` before rendering controls for in-flight work.\n- Validate URL query values before passing them to `setQuery()`.\n- Keep caching, retries, polling, and optimistic writes in your transport layer.\n- Use `setData()` with prepared local collections; keep ranking and filtering explicit.\n- Debounce text inputs before updating remote source queries.\n",
|
|
7
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 Search](./examples/local-pagination-and-filtering.md)\n- [Page Query 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"
|
|
8
8
|
},
|
|
9
9
|
"examples": [
|
|
@@ -43,30 +43,31 @@
|
|
|
43
43
|
"createInfiniteSource": "export { createInfiniteSource } from './infiniteSource';",
|
|
44
44
|
"createLocalSource": "export { createLocalSource } from './localSource';",
|
|
45
45
|
"createPageSource": "export { createPageSource } from './pageSource';",
|
|
46
|
-
"AnyPagination": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
47
|
-
"CursorPagination": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
48
|
-
"CursorQuery": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
49
|
-
"CursorQueryPatch": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
50
|
-
"CursorResult": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
51
|
-
"CursorSource": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
52
|
-
"CursorSourceConfig": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
46
|
+
"AnyPagination": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
47
|
+
"CursorPagination": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
48
|
+
"CursorQuery": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
49
|
+
"CursorQueryPatch": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
50
|
+
"CursorResult": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
51
|
+
"CursorSource": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
52
|
+
"CursorSourceConfig": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
53
|
+
"InfiniteLoadQuery": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
54
|
+
"InfinitePagination": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
55
|
+
"InfiniteQuery": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
56
|
+
"InfiniteQueryPatch": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
57
|
+
"InfiniteSource": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
58
|
+
"InfiniteSourceConfig": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
59
|
+
"LoadContext": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
60
|
+
"LocalQuery": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
61
|
+
"LocalQueryPatch": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
62
|
+
"LocalSource": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
63
|
+
"LocalSourceConfig": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
64
|
+
"PagePagination": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
65
|
+
"PageQuery": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
66
|
+
"PageQueryPatch": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
67
|
+
"PageResult": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
68
|
+
"PageSource": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
69
|
+
"PageSourceConfig": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
70
|
+
"Source": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';",
|
|
71
|
+
"SourceSnapshot": "export type {\n AnyPagination,\n CursorPagination,\n CursorQuery,\n CursorQueryPatch,\n CursorResult,\n CursorSource,\n CursorSourceConfig,\n InfiniteLoadQuery,\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n LoadContext,\n LocalQuery,\n LocalQueryPatch,\n LocalSource,\n LocalSourceConfig,\n PagePagination,\n PageQuery,\n PageQueryPatch,\n PageResult,\n PageSource,\n PageSourceConfig,\n Source,\n SourceSnapshot,\n} from './types';"
|
|
71
72
|
}
|
|
72
73
|
}
|