@vielzeug/sourcerer 1.0.4 → 1.0.6
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/README.md +12 -0
- package/dist/asyncSearch.cjs +2 -0
- package/dist/asyncSearch.cjs.map +1 -0
- package/dist/asyncSearch.d.ts +13 -0
- package/dist/asyncSearch.d.ts.map +1 -0
- package/dist/asyncSearch.js +28 -0
- package/dist/asyncSearch.js.map +1 -0
- package/dist/cursorSource.cjs +1 -1
- package/dist/cursorSource.cjs.map +1 -1
- package/dist/cursorSource.d.ts.map +1 -1
- package/dist/cursorSource.js +37 -47
- package/dist/cursorSource.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/infiniteSource.cjs +1 -1
- package/dist/infiniteSource.cjs.map +1 -1
- package/dist/infiniteSource.d.ts.map +1 -1
- package/dist/infiniteSource.js +45 -55
- package/dist/infiniteSource.js.map +1 -1
- package/dist/presets.cjs +1 -1
- package/dist/presets.cjs.map +1 -1
- package/dist/presets.d.ts +5 -0
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js +23 -4
- package/dist/presets.js.map +1 -1
- package/dist/remoteSource.cjs +1 -1
- package/dist/remoteSource.cjs.map +1 -1
- package/dist/remoteSource.d.ts.map +1 -1
- package/dist/remoteSource.js +55 -65
- package/dist/remoteSource.js.map +1 -1
- package/dist/sourcerer.cjs +1 -1
- package/dist/sourcerer.cjs.map +1 -1
- package/dist/sourcerer.iife.js +1 -1
- package/dist/sourcerer.iife.js.map +1 -1
- package/dist/sourcerer.js +1 -1
- package/dist/sourcerer.js.map +1 -1
- package/package.json +3 -3
- package/dist/_dev.d.ts +0 -2
- package/dist/_dev.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -49,6 +49,18 @@ await source.ready();
|
|
|
49
49
|
console.log(source.current, source.meta.totalItems);
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
## Local Search Presets
|
|
53
|
+
|
|
54
|
+
For large in-memory lists, prefer `searchBy(...)` over the default JSON-stringify search:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import { createLocalSource, searchBy } from '@vielzeug/sourcerer';
|
|
58
|
+
|
|
59
|
+
const source = createLocalSource(users, {
|
|
60
|
+
searchFn: searchBy([(u) => u.name, (u) => u.email]),
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
52
64
|
## Sources Overview
|
|
53
65
|
|
|
54
66
|
| Factory | Data model | Navigation |
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function e(e,t){let n=null,r=()=>{n&&=(n(),null)};return{cancel(){e.cancelTimer(),r()},dispose(){r()},schedule(i,a){r();let o=new Promise(e=>{n=e});return e.schedule(i,a),t(),o},settleIfIdle(e){e===0&&r()}}}exports.createAsyncSearchCoordinator=e;
|
|
2
|
+
//# sourceMappingURL=asyncSearch.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asyncSearch.cjs","names":[],"sources":["../src/asyncSearch.ts"],"sourcesContent":["import type { SourceCore } from './core';\n\nexport type AsyncSearchCoordinator = Readonly<{\n cancel(): void;\n dispose(): void;\n schedule(run: () => void, delayMs: number): Promise<void>;\n settleIfIdle(pendingCount: number): void;\n}>;\n\n/**\n * Shared debounced-search promise orchestration for async sources.\n * Keeps search() promise lifecycles consistent across remote/cursor/infinite sources.\n */\nexport function createAsyncSearchCoordinator(core: SourceCore, notify: () => void): AsyncSearchCoordinator {\n let pendingResolve: (() => void) | null = null;\n\n const resolvePending = () => {\n if (pendingResolve) {\n pendingResolve();\n pendingResolve = null;\n }\n };\n\n return {\n cancel() {\n core.cancelTimer();\n resolvePending();\n },\n\n dispose() {\n resolvePending();\n },\n\n schedule(run, delayMs) {\n resolvePending();\n\n const promise = new Promise<void>((resolve) => {\n pendingResolve = resolve;\n });\n\n core.schedule(run, delayMs);\n notify();\n\n return promise;\n },\n\n settleIfIdle(pendingCount) {\n if (pendingCount === 0) resolvePending();\n },\n };\n}\n"],"mappings":"AAaA,SAAgB,EAA6B,EAAkB,EAA4C,CACzG,IAAI,EAAsC,KAEpC,MAAuB,CAC3B,AAEE,KADA,EAAe,EACE,KAErB,EAEA,MAAO,CACL,QAAS,CACP,EAAK,YAAY,EACjB,EAAe,CACjB,EAEA,SAAU,CACR,EAAe,CACjB,EAEA,SAAS,EAAK,EAAS,CACrB,EAAe,EAEf,IAAM,EAAU,IAAI,QAAe,GAAY,CAC7C,EAAiB,CACnB,CAAC,EAKD,OAHA,EAAK,SAAS,EAAK,CAAO,EAC1B,EAAO,EAEA,CACT,EAEA,aAAa,EAAc,CACrB,IAAiB,GAAG,EAAe,CACzC,CACF,CACF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SourceCore } from './core';
|
|
2
|
+
export type AsyncSearchCoordinator = Readonly<{
|
|
3
|
+
cancel(): void;
|
|
4
|
+
dispose(): void;
|
|
5
|
+
schedule(run: () => void, delayMs: number): Promise<void>;
|
|
6
|
+
settleIfIdle(pendingCount: number): void;
|
|
7
|
+
}>;
|
|
8
|
+
/**
|
|
9
|
+
* Shared debounced-search promise orchestration for async sources.
|
|
10
|
+
* Keeps search() promise lifecycles consistent across remote/cursor/infinite sources.
|
|
11
|
+
*/
|
|
12
|
+
export declare function createAsyncSearchCoordinator(core: SourceCore, notify: () => void): AsyncSearchCoordinator;
|
|
13
|
+
//# sourceMappingURL=asyncSearch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asyncSearch.d.ts","sourceRoot":"","sources":["../src/asyncSearch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEzC,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC;IAC5C,MAAM,IAAI,IAAI,CAAC;IACf,OAAO,IAAI,IAAI,CAAC;IAChB,QAAQ,CAAC,GAAG,EAAE,MAAM,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1C,CAAC,CAAC;AAEH;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,IAAI,GAAG,sBAAsB,CAqCzG"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//#region src/asyncSearch.ts
|
|
2
|
+
function e(e, t) {
|
|
3
|
+
let n = null, r = () => {
|
|
4
|
+
n &&= (n(), null);
|
|
5
|
+
};
|
|
6
|
+
return {
|
|
7
|
+
cancel() {
|
|
8
|
+
e.cancelTimer(), r();
|
|
9
|
+
},
|
|
10
|
+
dispose() {
|
|
11
|
+
r();
|
|
12
|
+
},
|
|
13
|
+
schedule(i, a) {
|
|
14
|
+
r();
|
|
15
|
+
let o = new Promise((e) => {
|
|
16
|
+
n = e;
|
|
17
|
+
});
|
|
18
|
+
return e.schedule(i, a), t(), o;
|
|
19
|
+
},
|
|
20
|
+
settleIfIdle(e) {
|
|
21
|
+
e === 0 && r();
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { e as createAsyncSearchCoordinator };
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=asyncSearch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asyncSearch.js","names":[],"sources":["../src/asyncSearch.ts"],"sourcesContent":["import type { SourceCore } from './core';\n\nexport type AsyncSearchCoordinator = Readonly<{\n cancel(): void;\n dispose(): void;\n schedule(run: () => void, delayMs: number): Promise<void>;\n settleIfIdle(pendingCount: number): void;\n}>;\n\n/**\n * Shared debounced-search promise orchestration for async sources.\n * Keeps search() promise lifecycles consistent across remote/cursor/infinite sources.\n */\nexport function createAsyncSearchCoordinator(core: SourceCore, notify: () => void): AsyncSearchCoordinator {\n let pendingResolve: (() => void) | null = null;\n\n const resolvePending = () => {\n if (pendingResolve) {\n pendingResolve();\n pendingResolve = null;\n }\n };\n\n return {\n cancel() {\n core.cancelTimer();\n resolvePending();\n },\n\n dispose() {\n resolvePending();\n },\n\n schedule(run, delayMs) {\n resolvePending();\n\n const promise = new Promise<void>((resolve) => {\n pendingResolve = resolve;\n });\n\n core.schedule(run, delayMs);\n notify();\n\n return promise;\n },\n\n settleIfIdle(pendingCount) {\n if (pendingCount === 0) resolvePending();\n },\n };\n}\n"],"mappings":";AAaA,SAAgB,EAA6B,GAAkB,GAA4C;CACzG,IAAI,IAAsC,MAEpC,UAAuB;EAC3B,AAEE,OADA,EAAe,GACE;CAErB;CAEA,OAAO;EACL,SAAS;GAEP,AADA,EAAK,YAAY,GACjB,EAAe;EACjB;EAEA,UAAU;GACR,EAAe;EACjB;EAEA,SAAS,GAAK,GAAS;GACrB,EAAe;GAEf,IAAM,IAAU,IAAI,SAAe,MAAY;IAC7C,IAAiB;GACnB,CAAC;GAKD,OAHA,EAAK,SAAS,GAAK,CAAO,GAC1B,EAAO,GAEA;EACT;EAEA,aAAa,GAAc;GACzB,AAAI,MAAiB,KAAG,EAAe;EACzC;CACF;AACF"}
|
package/dist/cursorSource.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./errors.cjs"),t=require("./_utils.cjs"),n=require("./asyncSource.cjs");let
|
|
1
|
+
const e=require("./errors.cjs"),t=require("./_utils.cjs"),n=require("./asyncSearch.cjs"),r=require("./asyncSource.cjs");let i=require("@vielzeug/arsenal");function a(a){let o=a.queryKey??t.defaultKeyOf,s=Math.max(1,Math.trunc(a.limit??20)),c=``,l,u,d,f,p=[],m=0,h=null,g=[],_={error:null,hasNextPage:!1,hasPrevPage:!1,isLoading:!1,isSearchPending:!1,pageSize:s,totalItems:0},v=()=>{g=p,_={error:h,hasNextPage:d!==void 0,hasPrevPage:f!==void 0,isLoading:y.pendingCount()>0,isSearchPending:y.core.isScheduled,pageSize:s,totalItems:m}},y=r.createAsyncSource(a,o,v),{autoFetch:b,debounceMs:x,retryAttempts:S,retryDelay:C}=y;v();let w=()=>{y.disposed||y.core.notify()},T=n.createAsyncSearchCoordinator(y.core,w),E=()=>({...l!==void 0&&{after:l},...u!==void 0&&{before:u},...c&&{search:c},limit:s}),D=n=>(h=null,y.fetch(n,async(n,r,o)=>{let s=Date.now();try{let e=await(0,i.retry)(e=>a.fetch(n,e),{delay:C,signal:r,times:S+1});o()&&(p=e.items,m=e.total??e.items.length,d=e.nextCursor,f=e.prevCursor,h=null,a.onFetch?.({durationMs:Date.now()-s,query:n,status:`success`}))}catch(i){if(r.aborted)return;o()&&(p=[],m=0,d=void 0,f=void 0,h=new e.SourcererError(t.extractError(i),{cause:i,context:{kind:`cursor`,limit:n.limit,...n.search&&{search:n.search}}}),a.onFetch?.({durationMs:Date.now()-s,error:h,query:n,status:`error`}))}},()=>{w(),T.settleIfIdle(y.pendingCount())})),O=()=>D(E());return b&&O(),y.startRefreshInterval(()=>void O()),{get current(){return g},get disposalSignal(){return y.disposalSignal},dispose:()=>{T.cancel(),T.dispose(),y.dispose()},get disposed(){return y.disposed},get meta(){return _},next(){return d?(l=d,u=void 0,O()):Promise.resolve()},patch(e){let t=!1;if(e.limit!==void 0){let n=Math.max(1,Math.trunc(e.limit));n!==s&&(s=n,l=void 0,u=void 0,t=!0)}return`search`in e&&(e.search!==c||y.core.isScheduled)&&(c=e.search??``,l=void 0,u=void 0,t=!0),t?(T.cancel(),O()):Promise.resolve()},prev(){return f?(u=f,l=void 0,O()):Promise.resolve()},get query(){return{...l!==void 0&&{after:l},...u!==void 0&&{before:u},...c&&{search:c},limit:s}},ready(e){return y.ready(e)},refresh(){return O()},reset(){return T.cancel(),c=``,l=void 0,u=void 0,O()},search(e,t){return t?.immediate?e===c&&!y.core.isScheduled?Promise.resolve():(T.cancel(),c=e,l=void 0,u=void 0,O()):e===c?Promise.resolve():(c=e,l=void 0,u=void 0,T.schedule(()=>void O(),x))},subscribe:e=>y.core.subscribe(e),[Symbol.dispose]:()=>{T.cancel(),T.dispose(),y.dispose()}}}exports.createCursorSource=a;
|
|
2
2
|
//# sourceMappingURL=cursorSource.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursorSource.cjs","names":[],"sources":["../src/cursorSource.ts"],"sourcesContent":["import type { CursorConfig, CursorMeta, CursorSource, CursorSourceQuery, SearchOptions } from './types';\n\nimport { defaultKeyOf, extractError, retry } from './_utils';\nimport { createAsyncSource } from './asyncSource';\nimport { SourcererError } from './errors';\n\ntype PendingSearch = { promise: Promise<void>; resolve: () => void };\n\n/** Creates a cursor-based (keyset-pagination) source that fetches data from a network endpoint. */\nexport function createCursorSource<T, TCursor = string>(cfg: CursorConfig<T, TCursor>): CursorSource<T, TCursor> {\n const keyOf = cfg.queryKey ?? defaultKeyOf;\n\n // ── Mutable state ───────────────────────────────────────────────────────────\n let limit = Math.max(1, Math.trunc(cfg.limit ?? 20));\n let search = '';\n let afterCursor: TCursor | undefined;\n let beforeCursor: TCursor | undefined;\n let nextCursor: TCursor | undefined;\n let prevCursor: TCursor | undefined;\n let items: readonly T[] = [];\n let total = 0;\n let error: SourcererError | null = null;\n let pendingSearch: PendingSearch | null = null;\n\n // ── Cached accessors ────────────────────────────────────────────────────────\n let cachedCurrent: readonly T[] = [];\n let cachedMeta: CursorMeta = {\n error: null,\n hasNextPage: false,\n hasPrevPage: false,\n isLoading: false,\n isSearchPending: false,\n pageSize: limit,\n totalItems: 0,\n };\n\n const refreshMeta = () => {\n cachedCurrent = items;\n cachedMeta = {\n error,\n hasNextPage: nextCursor !== undefined,\n hasPrevPage: prevCursor !== undefined,\n isLoading: base.pendingCount() > 0,\n isSearchPending: base.core.isScheduled,\n pageSize: limit,\n totalItems: total,\n };\n };\n\n // onBeforeNotify ensures refreshMeta() runs before any subscriber observes the new state,\n // eliminating the need for a parallel listeners Set.\n const base = createAsyncSource<CursorSourceQuery<TCursor>>(cfg, keyOf, refreshMeta);\n const { autoFetch, debounceMs, retryAttempts, retryDelay } = base;\n\n refreshMeta();\n\n const notifyListeners = () => {\n if (base.disposed) return;\n\n base.core.notify();\n };\n\n const resolvePendingSearch = () => {\n if (pendingSearch) {\n pendingSearch.resolve();\n pendingSearch = null;\n }\n };\n\n // ── Core fetch ──────────────────────────────────────────────────────────────\n const toRemoteQuery = (): CursorSourceQuery<TCursor> => ({\n ...(afterCursor !== undefined && { after: afterCursor }),\n ...(beforeCursor !== undefined && { before: beforeCursor }),\n ...(search && { search }),\n limit,\n });\n\n const fetchQuery = (q: CursorSourceQuery<TCursor>): Promise<void> => {\n error = null;\n\n return base.fetch(\n q,\n async (q, signal, isLatest) => {\n const startTime = Date.now();\n\n try {\n const result = await retry((sig) => cfg.fetch(q, sig!), {\n delay: retryDelay,\n signal,\n times: retryAttempts + 1,\n });\n\n if (isLatest()) {\n items = result.items;\n total = result.total ?? result.items.length;\n nextCursor = result.nextCursor;\n prevCursor = result.prevCursor;\n error = null;\n cfg.onFetch?.({ durationMs: Date.now() - startTime, query: q, status: 'success' });\n }\n } catch (reason: unknown) {\n if (signal.aborted) return;\n\n if (isLatest()) {\n items = [];\n total = 0;\n nextCursor = undefined;\n prevCursor = undefined;\n error = new SourcererError(extractError(reason), {\n cause: reason,\n context: { kind: 'cursor', limit: q.limit, ...(q.search && { search: q.search }) },\n });\n cfg.onFetch?.({ durationMs: Date.now() - startTime, error, query: q, status: 'error' });\n }\n }\n },\n () => {\n notifyListeners();\n\n if (base.pendingCount() === 0) resolvePendingSearch();\n },\n );\n };\n\n const doUpdate = () => fetchQuery(toRemoteQuery());\n\n // ── Auto-fetch + refresh interval ───────────────────────────────────────────\n if (autoFetch) void doUpdate();\n\n base.startRefreshInterval(() => void doUpdate());\n\n // ── Public API ──────────────────────────────────────────────────────────────\n return {\n get current() {\n return cachedCurrent;\n },\n\n get disposalSignal() {\n return base.disposalSignal;\n },\n\n dispose: () => {\n resolvePendingSearch();\n base.dispose();\n },\n\n get disposed() {\n return base.disposed;\n },\n\n get meta() {\n return cachedMeta;\n },\n\n next() {\n if (!nextCursor) return Promise.resolve();\n\n afterCursor = nextCursor;\n beforeCursor = undefined;\n\n return doUpdate();\n },\n\n patch(changes) {\n let changed = false;\n\n if (changes.limit !== undefined) {\n const next = Math.max(1, Math.trunc(changes.limit));\n\n if (next !== limit) {\n limit = next;\n afterCursor = undefined;\n beforeCursor = undefined;\n changed = true;\n }\n }\n\n // `|| base.core.isScheduled` also catches patching in the same search text as an already-pending\n // debounced search() call — that still needs flushing, not silently dropping as a no-op.\n if ('search' in changes && (changes.search !== search || base.core.isScheduled)) {\n search = changes.search ?? '';\n afterCursor = undefined;\n beforeCursor = undefined;\n changed = true;\n }\n\n if (!changed) return Promise.resolve();\n\n // patch() is documented as a single atomic fetch — cancel any debounced search()\n // still pending so it doesn't fire a second, redundant fetch afterwards.\n base.core.cancelTimer();\n resolvePendingSearch();\n\n return doUpdate();\n },\n\n prev() {\n if (!prevCursor) return Promise.resolve();\n\n beforeCursor = prevCursor;\n afterCursor = undefined;\n\n return doUpdate();\n },\n\n get query() {\n return {\n ...(afterCursor !== undefined && { after: afterCursor }),\n ...(beforeCursor !== undefined && { before: beforeCursor }),\n ...(search && { search }),\n limit,\n };\n },\n\n ready(timeout) {\n return base.ready(timeout);\n },\n\n refresh() {\n return doUpdate();\n },\n\n reset() {\n base.core.cancelTimer();\n resolvePendingSearch();\n search = '';\n afterCursor = undefined;\n beforeCursor = undefined;\n\n return doUpdate();\n },\n\n search(q, opts?: SearchOptions): Promise<void> {\n if (opts?.immediate) {\n // A pending debounced search for this same text still needs flushing —\n // `q === search` alone doesn't mean the fetch already happened.\n if (q === search && !base.core.isScheduled) return Promise.resolve();\n\n base.core.cancelTimer();\n resolvePendingSearch();\n search = q;\n afterCursor = undefined;\n beforeCursor = undefined;\n\n return doUpdate();\n }\n\n if (q === search) return Promise.resolve();\n\n resolvePendingSearch();\n\n search = q;\n afterCursor = undefined;\n beforeCursor = undefined;\n\n let resolveSearch!: () => void;\n const promise = new Promise<void>((res) => {\n resolveSearch = res;\n });\n\n pendingSearch = { promise, resolve: resolveSearch };\n\n base.core.schedule(() => void doUpdate(), debounceMs);\n notifyListeners();\n\n return promise;\n },\n\n subscribe: (listener) => base.core.subscribe(listener),\n\n [Symbol.dispose]: () => {\n resolvePendingSearch();\n base.dispose();\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cursorSource.cjs","names":[],"sources":["../src/cursorSource.ts"],"sourcesContent":["import type { CursorConfig, CursorMeta, CursorSource, CursorSourceQuery, SearchOptions } from './types';\n\nimport { defaultKeyOf, extractError, retry } from './_utils';\nimport { createAsyncSearchCoordinator } from './asyncSearch';\nimport { createAsyncSource } from './asyncSource';\nimport { SourcererError } from './errors';\n\n/** Creates a cursor-based (keyset-pagination) source that fetches data from a network endpoint. */\nexport function createCursorSource<T, TCursor = string>(cfg: CursorConfig<T, TCursor>): CursorSource<T, TCursor> {\n const keyOf = cfg.queryKey ?? defaultKeyOf;\n\n // ── Mutable state ───────────────────────────────────────────────────────────\n let limit = Math.max(1, Math.trunc(cfg.limit ?? 20));\n let search = '';\n let afterCursor: TCursor | undefined;\n let beforeCursor: TCursor | undefined;\n let nextCursor: TCursor | undefined;\n let prevCursor: TCursor | undefined;\n let items: readonly T[] = [];\n let total = 0;\n let error: SourcererError | null = null;\n\n // ── Cached accessors ────────────────────────────────────────────────────────\n let cachedCurrent: readonly T[] = [];\n let cachedMeta: CursorMeta = {\n error: null,\n hasNextPage: false,\n hasPrevPage: false,\n isLoading: false,\n isSearchPending: false,\n pageSize: limit,\n totalItems: 0,\n };\n\n const refreshMeta = () => {\n cachedCurrent = items;\n cachedMeta = {\n error,\n hasNextPage: nextCursor !== undefined,\n hasPrevPage: prevCursor !== undefined,\n isLoading: base.pendingCount() > 0,\n isSearchPending: base.core.isScheduled,\n pageSize: limit,\n totalItems: total,\n };\n };\n\n // onBeforeNotify ensures refreshMeta() runs before any subscriber observes the new state,\n // eliminating the need for a parallel listeners Set.\n const base = createAsyncSource<CursorSourceQuery<TCursor>>(cfg, keyOf, refreshMeta);\n const { autoFetch, debounceMs, retryAttempts, retryDelay } = base;\n\n refreshMeta();\n\n const notifyListeners = () => {\n if (base.disposed) return;\n\n base.core.notify();\n };\n const searchCoordinator = createAsyncSearchCoordinator(base.core, notifyListeners);\n\n // ── Core fetch ──────────────────────────────────────────────────────────────\n const toRemoteQuery = (): CursorSourceQuery<TCursor> => ({\n ...(afterCursor !== undefined && { after: afterCursor }),\n ...(beforeCursor !== undefined && { before: beforeCursor }),\n ...(search && { search }),\n limit,\n });\n\n const fetchQuery = (q: CursorSourceQuery<TCursor>): Promise<void> => {\n error = null;\n\n return base.fetch(\n q,\n async (q, signal, isLatest) => {\n const startTime = Date.now();\n\n try {\n const result = await retry((sig) => cfg.fetch(q, sig!), {\n delay: retryDelay,\n signal,\n times: retryAttempts + 1,\n });\n\n if (isLatest()) {\n items = result.items;\n total = result.total ?? result.items.length;\n nextCursor = result.nextCursor;\n prevCursor = result.prevCursor;\n error = null;\n cfg.onFetch?.({ durationMs: Date.now() - startTime, query: q, status: 'success' });\n }\n } catch (reason: unknown) {\n if (signal.aborted) return;\n\n if (isLatest()) {\n items = [];\n total = 0;\n nextCursor = undefined;\n prevCursor = undefined;\n error = new SourcererError(extractError(reason), {\n cause: reason,\n context: { kind: 'cursor', limit: q.limit, ...(q.search && { search: q.search }) },\n });\n cfg.onFetch?.({ durationMs: Date.now() - startTime, error, query: q, status: 'error' });\n }\n }\n },\n () => {\n notifyListeners();\n\n searchCoordinator.settleIfIdle(base.pendingCount());\n },\n );\n };\n\n const doUpdate = () => fetchQuery(toRemoteQuery());\n\n // ── Auto-fetch + refresh interval ───────────────────────────────────────────\n if (autoFetch) void doUpdate();\n\n base.startRefreshInterval(() => void doUpdate());\n\n // ── Public API ──────────────────────────────────────────────────────────────\n return {\n get current() {\n return cachedCurrent;\n },\n\n get disposalSignal() {\n return base.disposalSignal;\n },\n\n dispose: () => {\n searchCoordinator.cancel();\n searchCoordinator.dispose();\n base.dispose();\n },\n\n get disposed() {\n return base.disposed;\n },\n\n get meta() {\n return cachedMeta;\n },\n\n next() {\n if (!nextCursor) return Promise.resolve();\n\n afterCursor = nextCursor;\n beforeCursor = undefined;\n\n return doUpdate();\n },\n\n patch(changes) {\n let changed = false;\n\n if (changes.limit !== undefined) {\n const next = Math.max(1, Math.trunc(changes.limit));\n\n if (next !== limit) {\n limit = next;\n afterCursor = undefined;\n beforeCursor = undefined;\n changed = true;\n }\n }\n\n // `|| base.core.isScheduled` also catches patching in the same search text as an already-pending\n // debounced search() call — that still needs flushing, not silently dropping as a no-op.\n if ('search' in changes && (changes.search !== search || base.core.isScheduled)) {\n search = changes.search ?? '';\n afterCursor = undefined;\n beforeCursor = undefined;\n changed = true;\n }\n\n if (!changed) return Promise.resolve();\n\n // patch() is documented as a single atomic fetch — cancel any debounced search()\n // still pending so it doesn't fire a second, redundant fetch afterwards.\n searchCoordinator.cancel();\n\n return doUpdate();\n },\n\n prev() {\n if (!prevCursor) return Promise.resolve();\n\n beforeCursor = prevCursor;\n afterCursor = undefined;\n\n return doUpdate();\n },\n\n get query() {\n return {\n ...(afterCursor !== undefined && { after: afterCursor }),\n ...(beforeCursor !== undefined && { before: beforeCursor }),\n ...(search && { search }),\n limit,\n };\n },\n\n ready(timeout) {\n return base.ready(timeout);\n },\n\n refresh() {\n return doUpdate();\n },\n\n reset() {\n searchCoordinator.cancel();\n search = '';\n afterCursor = undefined;\n beforeCursor = undefined;\n\n return doUpdate();\n },\n\n search(q, opts?: SearchOptions): Promise<void> {\n if (opts?.immediate) {\n // A pending debounced search for this same text still needs flushing —\n // `q === search` alone doesn't mean the fetch already happened.\n if (q === search && !base.core.isScheduled) return Promise.resolve();\n\n searchCoordinator.cancel();\n search = q;\n afterCursor = undefined;\n beforeCursor = undefined;\n\n return doUpdate();\n }\n\n if (q === search) return Promise.resolve();\n\n search = q;\n afterCursor = undefined;\n beforeCursor = undefined;\n\n return searchCoordinator.schedule(() => void doUpdate(), debounceMs);\n },\n\n subscribe: (listener) => base.core.subscribe(listener),\n\n [Symbol.dispose]: () => {\n searchCoordinator.cancel();\n searchCoordinator.dispose();\n base.dispose();\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursorSource.d.ts","sourceRoot":"","sources":["../src/cursorSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAc,YAAY,EAAoC,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"cursorSource.d.ts","sourceRoot":"","sources":["../src/cursorSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAc,YAAY,EAAoC,MAAM,SAAS,CAAC;AAOxG,mGAAmG;AACnG,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAsP/G"}
|
package/dist/cursorSource.js
CHANGED
|
@@ -1,68 +1,67 @@
|
|
|
1
1
|
import { SourcererError as e } from "./errors.js";
|
|
2
2
|
import { defaultKeyOf as t, extractError as n, retry as r } from "./_utils.js";
|
|
3
|
-
import {
|
|
3
|
+
import { createAsyncSearchCoordinator as i } from "./asyncSearch.js";
|
|
4
|
+
import { createAsyncSource as a } from "./asyncSource.js";
|
|
4
5
|
//#region src/cursorSource.ts
|
|
5
|
-
function
|
|
6
|
-
let
|
|
6
|
+
function o(o) {
|
|
7
|
+
let s = o.queryKey ?? t, c = Math.max(1, Math.trunc(o.limit ?? 20)), l = "", u, d, f, p, m = [], h = 0, g = null, _ = [], v = {
|
|
7
8
|
error: null,
|
|
8
9
|
hasNextPage: !1,
|
|
9
10
|
hasPrevPage: !1,
|
|
10
11
|
isLoading: !1,
|
|
11
12
|
isSearchPending: !1,
|
|
12
|
-
pageSize:
|
|
13
|
+
pageSize: c,
|
|
13
14
|
totalItems: 0
|
|
14
15
|
}, y = () => {
|
|
15
|
-
_ =
|
|
16
|
-
error:
|
|
17
|
-
hasNextPage:
|
|
18
|
-
hasPrevPage:
|
|
16
|
+
_ = m, v = {
|
|
17
|
+
error: g,
|
|
18
|
+
hasNextPage: f !== void 0,
|
|
19
|
+
hasPrevPage: p !== void 0,
|
|
19
20
|
isLoading: b.pendingCount() > 0,
|
|
20
21
|
isSearchPending: b.core.isScheduled,
|
|
21
|
-
pageSize:
|
|
22
|
-
totalItems:
|
|
22
|
+
pageSize: c,
|
|
23
|
+
totalItems: h
|
|
23
24
|
};
|
|
24
|
-
}, b =
|
|
25
|
+
}, b = a(o, s, y), { autoFetch: x, debounceMs: S, retryAttempts: C, retryDelay: w } = b;
|
|
25
26
|
y();
|
|
26
27
|
let T = () => {
|
|
27
28
|
b.disposed || b.core.notify();
|
|
28
|
-
}, E = () => {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
...l
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
limit: s
|
|
35
|
-
}), O = (t) => (h = null, b.fetch(t, async (t, i, o) => {
|
|
29
|
+
}, E = i(b.core, T), D = () => ({
|
|
30
|
+
...u !== void 0 && { after: u },
|
|
31
|
+
...d !== void 0 && { before: d },
|
|
32
|
+
...l && { search: l },
|
|
33
|
+
limit: c
|
|
34
|
+
}), O = (t) => (g = null, b.fetch(t, async (t, i, a) => {
|
|
36
35
|
let s = Date.now();
|
|
37
36
|
try {
|
|
38
|
-
let e = await r((e) =>
|
|
37
|
+
let e = await r((e) => o.fetch(t, e), {
|
|
39
38
|
delay: w,
|
|
40
39
|
signal: i,
|
|
41
40
|
times: C + 1
|
|
42
41
|
});
|
|
43
|
-
|
|
42
|
+
a() && (m = e.items, h = e.total ?? e.items.length, f = e.nextCursor, p = e.prevCursor, g = null, o.onFetch?.({
|
|
44
43
|
durationMs: Date.now() - s,
|
|
45
44
|
query: t,
|
|
46
45
|
status: "success"
|
|
47
46
|
}));
|
|
48
47
|
} catch (r) {
|
|
49
48
|
if (i.aborted) return;
|
|
50
|
-
|
|
49
|
+
a() && (m = [], h = 0, f = void 0, p = void 0, g = new e(n(r), {
|
|
51
50
|
cause: r,
|
|
52
51
|
context: {
|
|
53
52
|
kind: "cursor",
|
|
54
53
|
limit: t.limit,
|
|
55
54
|
...t.search && { search: t.search }
|
|
56
55
|
}
|
|
57
|
-
}),
|
|
56
|
+
}), o.onFetch?.({
|
|
58
57
|
durationMs: Date.now() - s,
|
|
59
|
-
error:
|
|
58
|
+
error: g,
|
|
60
59
|
query: t,
|
|
61
60
|
status: "error"
|
|
62
61
|
}));
|
|
63
62
|
}
|
|
64
63
|
}, () => {
|
|
65
|
-
T(), b.pendingCount()
|
|
64
|
+
T(), E.settleIfIdle(b.pendingCount());
|
|
66
65
|
})), k = () => O(D());
|
|
67
66
|
return x && k(), b.startRefreshInterval(() => void k()), {
|
|
68
67
|
get current() {
|
|
@@ -72,7 +71,7 @@ function a(a) {
|
|
|
72
71
|
return b.disposalSignal;
|
|
73
72
|
},
|
|
74
73
|
dispose: () => {
|
|
75
|
-
E(), b.dispose();
|
|
74
|
+
E.cancel(), E.dispose(), b.dispose();
|
|
76
75
|
},
|
|
77
76
|
get disposed() {
|
|
78
77
|
return b.disposed;
|
|
@@ -81,25 +80,25 @@ function a(a) {
|
|
|
81
80
|
return v;
|
|
82
81
|
},
|
|
83
82
|
next() {
|
|
84
|
-
return
|
|
83
|
+
return f ? (u = f, d = void 0, k()) : Promise.resolve();
|
|
85
84
|
},
|
|
86
85
|
patch(e) {
|
|
87
86
|
let t = !1;
|
|
88
87
|
if (e.limit !== void 0) {
|
|
89
88
|
let n = Math.max(1, Math.trunc(e.limit));
|
|
90
|
-
n !==
|
|
89
|
+
n !== c && (c = n, u = void 0, d = void 0, t = !0);
|
|
91
90
|
}
|
|
92
|
-
return "search" in e && (e.search !==
|
|
91
|
+
return "search" in e && (e.search !== l || b.core.isScheduled) && (l = e.search ?? "", u = void 0, d = void 0, t = !0), t ? (E.cancel(), k()) : Promise.resolve();
|
|
93
92
|
},
|
|
94
93
|
prev() {
|
|
95
|
-
return
|
|
94
|
+
return p ? (d = p, u = void 0, k()) : Promise.resolve();
|
|
96
95
|
},
|
|
97
96
|
get query() {
|
|
98
97
|
return {
|
|
99
|
-
...
|
|
100
|
-
...
|
|
101
|
-
...
|
|
102
|
-
limit:
|
|
98
|
+
...u !== void 0 && { after: u },
|
|
99
|
+
...d !== void 0 && { before: d },
|
|
100
|
+
...l && { search: l },
|
|
101
|
+
limit: c
|
|
103
102
|
};
|
|
104
103
|
},
|
|
105
104
|
ready(e) {
|
|
@@ -109,27 +108,18 @@ function a(a) {
|
|
|
109
108
|
return k();
|
|
110
109
|
},
|
|
111
110
|
reset() {
|
|
112
|
-
return
|
|
111
|
+
return E.cancel(), l = "", u = void 0, d = void 0, k();
|
|
113
112
|
},
|
|
114
113
|
search(e, t) {
|
|
115
|
-
|
|
116
|
-
if (e === c) return Promise.resolve();
|
|
117
|
-
E(), c = e, l = void 0, u = void 0;
|
|
118
|
-
let n, r = new Promise((e) => {
|
|
119
|
-
n = e;
|
|
120
|
-
});
|
|
121
|
-
return g = {
|
|
122
|
-
promise: r,
|
|
123
|
-
resolve: n
|
|
124
|
-
}, b.core.schedule(() => void k(), S), T(), r;
|
|
114
|
+
return t?.immediate ? e === l && !b.core.isScheduled ? Promise.resolve() : (E.cancel(), l = e, u = void 0, d = void 0, k()) : e === l ? Promise.resolve() : (l = e, u = void 0, d = void 0, E.schedule(() => void k(), S));
|
|
125
115
|
},
|
|
126
116
|
subscribe: (e) => b.core.subscribe(e),
|
|
127
117
|
[Symbol.dispose]: () => {
|
|
128
|
-
E(), b.dispose();
|
|
118
|
+
E.cancel(), E.dispose(), b.dispose();
|
|
129
119
|
}
|
|
130
120
|
};
|
|
131
121
|
}
|
|
132
122
|
//#endregion
|
|
133
|
-
export {
|
|
123
|
+
export { o as createCursorSource };
|
|
134
124
|
|
|
135
125
|
//# sourceMappingURL=cursorSource.js.map
|
package/dist/cursorSource.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursorSource.js","names":[],"sources":["../src/cursorSource.ts"],"sourcesContent":["import type { CursorConfig, CursorMeta, CursorSource, CursorSourceQuery, SearchOptions } from './types';\n\nimport { defaultKeyOf, extractError, retry } from './_utils';\nimport { createAsyncSource } from './asyncSource';\nimport { SourcererError } from './errors';\n\ntype PendingSearch = { promise: Promise<void>; resolve: () => void };\n\n/** Creates a cursor-based (keyset-pagination) source that fetches data from a network endpoint. */\nexport function createCursorSource<T, TCursor = string>(cfg: CursorConfig<T, TCursor>): CursorSource<T, TCursor> {\n const keyOf = cfg.queryKey ?? defaultKeyOf;\n\n // ── Mutable state ───────────────────────────────────────────────────────────\n let limit = Math.max(1, Math.trunc(cfg.limit ?? 20));\n let search = '';\n let afterCursor: TCursor | undefined;\n let beforeCursor: TCursor | undefined;\n let nextCursor: TCursor | undefined;\n let prevCursor: TCursor | undefined;\n let items: readonly T[] = [];\n let total = 0;\n let error: SourcererError | null = null;\n let pendingSearch: PendingSearch | null = null;\n\n // ── Cached accessors ────────────────────────────────────────────────────────\n let cachedCurrent: readonly T[] = [];\n let cachedMeta: CursorMeta = {\n error: null,\n hasNextPage: false,\n hasPrevPage: false,\n isLoading: false,\n isSearchPending: false,\n pageSize: limit,\n totalItems: 0,\n };\n\n const refreshMeta = () => {\n cachedCurrent = items;\n cachedMeta = {\n error,\n hasNextPage: nextCursor !== undefined,\n hasPrevPage: prevCursor !== undefined,\n isLoading: base.pendingCount() > 0,\n isSearchPending: base.core.isScheduled,\n pageSize: limit,\n totalItems: total,\n };\n };\n\n // onBeforeNotify ensures refreshMeta() runs before any subscriber observes the new state,\n // eliminating the need for a parallel listeners Set.\n const base = createAsyncSource<CursorSourceQuery<TCursor>>(cfg, keyOf, refreshMeta);\n const { autoFetch, debounceMs, retryAttempts, retryDelay } = base;\n\n refreshMeta();\n\n const notifyListeners = () => {\n if (base.disposed) return;\n\n base.core.notify();\n };\n\n const resolvePendingSearch = () => {\n if (pendingSearch) {\n pendingSearch.resolve();\n pendingSearch = null;\n }\n };\n\n // ── Core fetch ──────────────────────────────────────────────────────────────\n const toRemoteQuery = (): CursorSourceQuery<TCursor> => ({\n ...(afterCursor !== undefined && { after: afterCursor }),\n ...(beforeCursor !== undefined && { before: beforeCursor }),\n ...(search && { search }),\n limit,\n });\n\n const fetchQuery = (q: CursorSourceQuery<TCursor>): Promise<void> => {\n error = null;\n\n return base.fetch(\n q,\n async (q, signal, isLatest) => {\n const startTime = Date.now();\n\n try {\n const result = await retry((sig) => cfg.fetch(q, sig!), {\n delay: retryDelay,\n signal,\n times: retryAttempts + 1,\n });\n\n if (isLatest()) {\n items = result.items;\n total = result.total ?? result.items.length;\n nextCursor = result.nextCursor;\n prevCursor = result.prevCursor;\n error = null;\n cfg.onFetch?.({ durationMs: Date.now() - startTime, query: q, status: 'success' });\n }\n } catch (reason: unknown) {\n if (signal.aborted) return;\n\n if (isLatest()) {\n items = [];\n total = 0;\n nextCursor = undefined;\n prevCursor = undefined;\n error = new SourcererError(extractError(reason), {\n cause: reason,\n context: { kind: 'cursor', limit: q.limit, ...(q.search && { search: q.search }) },\n });\n cfg.onFetch?.({ durationMs: Date.now() - startTime, error, query: q, status: 'error' });\n }\n }\n },\n () => {\n notifyListeners();\n\n if (base.pendingCount() === 0) resolvePendingSearch();\n },\n );\n };\n\n const doUpdate = () => fetchQuery(toRemoteQuery());\n\n // ── Auto-fetch + refresh interval ───────────────────────────────────────────\n if (autoFetch) void doUpdate();\n\n base.startRefreshInterval(() => void doUpdate());\n\n // ── Public API ──────────────────────────────────────────────────────────────\n return {\n get current() {\n return cachedCurrent;\n },\n\n get disposalSignal() {\n return base.disposalSignal;\n },\n\n dispose: () => {\n resolvePendingSearch();\n base.dispose();\n },\n\n get disposed() {\n return base.disposed;\n },\n\n get meta() {\n return cachedMeta;\n },\n\n next() {\n if (!nextCursor) return Promise.resolve();\n\n afterCursor = nextCursor;\n beforeCursor = undefined;\n\n return doUpdate();\n },\n\n patch(changes) {\n let changed = false;\n\n if (changes.limit !== undefined) {\n const next = Math.max(1, Math.trunc(changes.limit));\n\n if (next !== limit) {\n limit = next;\n afterCursor = undefined;\n beforeCursor = undefined;\n changed = true;\n }\n }\n\n // `|| base.core.isScheduled` also catches patching in the same search text as an already-pending\n // debounced search() call — that still needs flushing, not silently dropping as a no-op.\n if ('search' in changes && (changes.search !== search || base.core.isScheduled)) {\n search = changes.search ?? '';\n afterCursor = undefined;\n beforeCursor = undefined;\n changed = true;\n }\n\n if (!changed) return Promise.resolve();\n\n // patch() is documented as a single atomic fetch — cancel any debounced search()\n // still pending so it doesn't fire a second, redundant fetch afterwards.\n base.core.cancelTimer();\n resolvePendingSearch();\n\n return doUpdate();\n },\n\n prev() {\n if (!prevCursor) return Promise.resolve();\n\n beforeCursor = prevCursor;\n afterCursor = undefined;\n\n return doUpdate();\n },\n\n get query() {\n return {\n ...(afterCursor !== undefined && { after: afterCursor }),\n ...(beforeCursor !== undefined && { before: beforeCursor }),\n ...(search && { search }),\n limit,\n };\n },\n\n ready(timeout) {\n return base.ready(timeout);\n },\n\n refresh() {\n return doUpdate();\n },\n\n reset() {\n base.core.cancelTimer();\n resolvePendingSearch();\n search = '';\n afterCursor = undefined;\n beforeCursor = undefined;\n\n return doUpdate();\n },\n\n search(q, opts?: SearchOptions): Promise<void> {\n if (opts?.immediate) {\n // A pending debounced search for this same text still needs flushing —\n // `q === search` alone doesn't mean the fetch already happened.\n if (q === search && !base.core.isScheduled) return Promise.resolve();\n\n base.core.cancelTimer();\n resolvePendingSearch();\n search = q;\n afterCursor = undefined;\n beforeCursor = undefined;\n\n return doUpdate();\n }\n\n if (q === search) return Promise.resolve();\n\n resolvePendingSearch();\n\n search = q;\n afterCursor = undefined;\n beforeCursor = undefined;\n\n let resolveSearch!: () => void;\n const promise = new Promise<void>((res) => {\n resolveSearch = res;\n });\n\n pendingSearch = { promise, resolve: resolveSearch };\n\n base.core.schedule(() => void doUpdate(), debounceMs);\n notifyListeners();\n\n return promise;\n },\n\n subscribe: (listener) => base.core.subscribe(listener),\n\n [Symbol.dispose]: () => {\n resolvePendingSearch();\n base.dispose();\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cursorSource.js","names":[],"sources":["../src/cursorSource.ts"],"sourcesContent":["import type { CursorConfig, CursorMeta, CursorSource, CursorSourceQuery, SearchOptions } from './types';\n\nimport { defaultKeyOf, extractError, retry } from './_utils';\nimport { createAsyncSearchCoordinator } from './asyncSearch';\nimport { createAsyncSource } from './asyncSource';\nimport { SourcererError } from './errors';\n\n/** Creates a cursor-based (keyset-pagination) source that fetches data from a network endpoint. */\nexport function createCursorSource<T, TCursor = string>(cfg: CursorConfig<T, TCursor>): CursorSource<T, TCursor> {\n const keyOf = cfg.queryKey ?? defaultKeyOf;\n\n // ── Mutable state ───────────────────────────────────────────────────────────\n let limit = Math.max(1, Math.trunc(cfg.limit ?? 20));\n let search = '';\n let afterCursor: TCursor | undefined;\n let beforeCursor: TCursor | undefined;\n let nextCursor: TCursor | undefined;\n let prevCursor: TCursor | undefined;\n let items: readonly T[] = [];\n let total = 0;\n let error: SourcererError | null = null;\n\n // ── Cached accessors ────────────────────────────────────────────────────────\n let cachedCurrent: readonly T[] = [];\n let cachedMeta: CursorMeta = {\n error: null,\n hasNextPage: false,\n hasPrevPage: false,\n isLoading: false,\n isSearchPending: false,\n pageSize: limit,\n totalItems: 0,\n };\n\n const refreshMeta = () => {\n cachedCurrent = items;\n cachedMeta = {\n error,\n hasNextPage: nextCursor !== undefined,\n hasPrevPage: prevCursor !== undefined,\n isLoading: base.pendingCount() > 0,\n isSearchPending: base.core.isScheduled,\n pageSize: limit,\n totalItems: total,\n };\n };\n\n // onBeforeNotify ensures refreshMeta() runs before any subscriber observes the new state,\n // eliminating the need for a parallel listeners Set.\n const base = createAsyncSource<CursorSourceQuery<TCursor>>(cfg, keyOf, refreshMeta);\n const { autoFetch, debounceMs, retryAttempts, retryDelay } = base;\n\n refreshMeta();\n\n const notifyListeners = () => {\n if (base.disposed) return;\n\n base.core.notify();\n };\n const searchCoordinator = createAsyncSearchCoordinator(base.core, notifyListeners);\n\n // ── Core fetch ──────────────────────────────────────────────────────────────\n const toRemoteQuery = (): CursorSourceQuery<TCursor> => ({\n ...(afterCursor !== undefined && { after: afterCursor }),\n ...(beforeCursor !== undefined && { before: beforeCursor }),\n ...(search && { search }),\n limit,\n });\n\n const fetchQuery = (q: CursorSourceQuery<TCursor>): Promise<void> => {\n error = null;\n\n return base.fetch(\n q,\n async (q, signal, isLatest) => {\n const startTime = Date.now();\n\n try {\n const result = await retry((sig) => cfg.fetch(q, sig!), {\n delay: retryDelay,\n signal,\n times: retryAttempts + 1,\n });\n\n if (isLatest()) {\n items = result.items;\n total = result.total ?? result.items.length;\n nextCursor = result.nextCursor;\n prevCursor = result.prevCursor;\n error = null;\n cfg.onFetch?.({ durationMs: Date.now() - startTime, query: q, status: 'success' });\n }\n } catch (reason: unknown) {\n if (signal.aborted) return;\n\n if (isLatest()) {\n items = [];\n total = 0;\n nextCursor = undefined;\n prevCursor = undefined;\n error = new SourcererError(extractError(reason), {\n cause: reason,\n context: { kind: 'cursor', limit: q.limit, ...(q.search && { search: q.search }) },\n });\n cfg.onFetch?.({ durationMs: Date.now() - startTime, error, query: q, status: 'error' });\n }\n }\n },\n () => {\n notifyListeners();\n\n searchCoordinator.settleIfIdle(base.pendingCount());\n },\n );\n };\n\n const doUpdate = () => fetchQuery(toRemoteQuery());\n\n // ── Auto-fetch + refresh interval ───────────────────────────────────────────\n if (autoFetch) void doUpdate();\n\n base.startRefreshInterval(() => void doUpdate());\n\n // ── Public API ──────────────────────────────────────────────────────────────\n return {\n get current() {\n return cachedCurrent;\n },\n\n get disposalSignal() {\n return base.disposalSignal;\n },\n\n dispose: () => {\n searchCoordinator.cancel();\n searchCoordinator.dispose();\n base.dispose();\n },\n\n get disposed() {\n return base.disposed;\n },\n\n get meta() {\n return cachedMeta;\n },\n\n next() {\n if (!nextCursor) return Promise.resolve();\n\n afterCursor = nextCursor;\n beforeCursor = undefined;\n\n return doUpdate();\n },\n\n patch(changes) {\n let changed = false;\n\n if (changes.limit !== undefined) {\n const next = Math.max(1, Math.trunc(changes.limit));\n\n if (next !== limit) {\n limit = next;\n afterCursor = undefined;\n beforeCursor = undefined;\n changed = true;\n }\n }\n\n // `|| base.core.isScheduled` also catches patching in the same search text as an already-pending\n // debounced search() call — that still needs flushing, not silently dropping as a no-op.\n if ('search' in changes && (changes.search !== search || base.core.isScheduled)) {\n search = changes.search ?? '';\n afterCursor = undefined;\n beforeCursor = undefined;\n changed = true;\n }\n\n if (!changed) return Promise.resolve();\n\n // patch() is documented as a single atomic fetch — cancel any debounced search()\n // still pending so it doesn't fire a second, redundant fetch afterwards.\n searchCoordinator.cancel();\n\n return doUpdate();\n },\n\n prev() {\n if (!prevCursor) return Promise.resolve();\n\n beforeCursor = prevCursor;\n afterCursor = undefined;\n\n return doUpdate();\n },\n\n get query() {\n return {\n ...(afterCursor !== undefined && { after: afterCursor }),\n ...(beforeCursor !== undefined && { before: beforeCursor }),\n ...(search && { search }),\n limit,\n };\n },\n\n ready(timeout) {\n return base.ready(timeout);\n },\n\n refresh() {\n return doUpdate();\n },\n\n reset() {\n searchCoordinator.cancel();\n search = '';\n afterCursor = undefined;\n beforeCursor = undefined;\n\n return doUpdate();\n },\n\n search(q, opts?: SearchOptions): Promise<void> {\n if (opts?.immediate) {\n // A pending debounced search for this same text still needs flushing —\n // `q === search` alone doesn't mean the fetch already happened.\n if (q === search && !base.core.isScheduled) return Promise.resolve();\n\n searchCoordinator.cancel();\n search = q;\n afterCursor = undefined;\n beforeCursor = undefined;\n\n return doUpdate();\n }\n\n if (q === search) return Promise.resolve();\n\n search = q;\n afterCursor = undefined;\n beforeCursor = undefined;\n\n return searchCoordinator.schedule(() => void doUpdate(), debounceMs);\n },\n\n subscribe: (listener) => base.core.subscribe(listener),\n\n [Symbol.dispose]: () => {\n searchCoordinator.cancel();\n searchCoordinator.dispose();\n base.dispose();\n },\n };\n}\n"],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./applyQuery.cjs"),t=require("./errors.cjs"),n=require("./codecs.cjs"),r=require("./cursorSource.cjs"),i=require("./derive.cjs"),a=require("./infiniteSource.cjs"),o=require("./pagination.cjs"),s=require("./localSource.cjs"),c=require("./merge.cjs"),l=require("./remoteSource.cjs"),u=require("./prefetch.cjs"),d=require("./presets.cjs"),f=require("./state.cjs");exports.SourceDisposedError=t.SourceDisposedError,exports.SourceTimeoutError=t.SourceTimeoutError,exports.SourcererError=t.SourcererError,exports.applyQuery=e.applyQuery,exports.createCursorSource=r.createCursorSource,exports.createInfiniteSource=a.createInfiniteSource,exports.createLocalSource=s.createLocalSource,exports.createRemoteSource=l.createRemoteSource,exports.decodeQuery=n.decodeQuery,exports.deriveSource=i.deriveSource,exports.encodeQuery=n.encodeQuery,exports.filterContains=d.filterContains,exports.filterEquals=d.filterEquals,exports.filterRange=d.filterRange,exports.itemRange=o.itemRange,exports.mergeSource=c.mergeSource,exports.prefetchSource=u.prefetchSource,exports.prefetchSourceAndKeep=u.prefetchSourceAndKeep,exports.sortBy=d.sortBy,exports.sourceState=f.sourceState;
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./applyQuery.cjs"),t=require("./errors.cjs"),n=require("./codecs.cjs"),r=require("./cursorSource.cjs"),i=require("./derive.cjs"),a=require("./infiniteSource.cjs"),o=require("./pagination.cjs"),s=require("./localSource.cjs"),c=require("./merge.cjs"),l=require("./remoteSource.cjs"),u=require("./prefetch.cjs"),d=require("./presets.cjs"),f=require("./state.cjs");exports.SourceDisposedError=t.SourceDisposedError,exports.SourceTimeoutError=t.SourceTimeoutError,exports.SourcererError=t.SourcererError,exports.applyQuery=e.applyQuery,exports.createCursorSource=r.createCursorSource,exports.createInfiniteSource=a.createInfiniteSource,exports.createLocalSource=s.createLocalSource,exports.createRemoteSource=l.createRemoteSource,exports.decodeQuery=n.decodeQuery,exports.deriveSource=i.deriveSource,exports.encodeQuery=n.encodeQuery,exports.filterContains=d.filterContains,exports.filterEquals=d.filterEquals,exports.filterRange=d.filterRange,exports.itemRange=o.itemRange,exports.mergeSource=c.mergeSource,exports.prefetchSource=u.prefetchSource,exports.prefetchSourceAndKeep=u.prefetchSourceAndKeep,exports.searchBy=d.searchBy,exports.sortBy=d.sortBy,exports.sourceState=f.sourceState;
|
package/dist/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export { createLocalSource } from './localSource';
|
|
|
8
8
|
export { mergeSource } from './merge';
|
|
9
9
|
export { itemRange } from './pagination';
|
|
10
10
|
export { prefetchSource, prefetchSourceAndKeep } from './prefetch';
|
|
11
|
-
export { filterContains, filterEquals, filterRange, sortBy } from './presets';
|
|
11
|
+
export { filterContains, filterEquals, filterRange, searchBy, sortBy } from './presets';
|
|
12
12
|
export { createRemoteSource } from './remoteSource';
|
|
13
13
|
export { sourceState } from './state';
|
|
14
14
|
export { SourceDisposedError, SourcererError, SourceTimeoutError } from './errors';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACpD,YAAY,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACpD,YAAY,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACxF,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AACnF,YAAY,EACV,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,iBAAiB,EACjB,aAAa,EACb,UAAU,EACV,cAAc,EACd,YAAY,EACZ,cAAc,EACd,mBAAmB,EACnB,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,SAAS,EACT,WAAW,EACX,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,WAAW,EACX,aAAa,EACb,MAAM,EACN,qBAAqB,EACrB,UAAU,EACV,WAAW,EACX,cAAc,EACd,WAAW,GACZ,MAAM,SAAS,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,6 @@ import { createLocalSource as u } from "./localSource.js";
|
|
|
9
9
|
import { mergeSource as d } from "./merge.js";
|
|
10
10
|
import { createRemoteSource as f } from "./remoteSource.js";
|
|
11
11
|
import { prefetchSource as p, prefetchSourceAndKeep as m } from "./prefetch.js";
|
|
12
|
-
import { filterContains as h, filterEquals as g, filterRange as _,
|
|
13
|
-
import { sourceState as
|
|
14
|
-
export { t as SourceDisposedError, n as SourceTimeoutError, r as SourcererError, e as applyQuery, o as createCursorSource, c as createInfiniteSource, u as createLocalSource, f as createRemoteSource, i as decodeQuery, s as deriveSource, a as encodeQuery, h as filterContains, g as filterEquals, _ as filterRange, l as itemRange, d as mergeSource, p as prefetchSource, m as prefetchSourceAndKeep, v as
|
|
12
|
+
import { filterContains as h, filterEquals as g, filterRange as _, searchBy as v, sortBy as y } from "./presets.js";
|
|
13
|
+
import { sourceState as b } from "./state.js";
|
|
14
|
+
export { t as SourceDisposedError, n as SourceTimeoutError, r as SourcererError, e as applyQuery, o as createCursorSource, c as createInfiniteSource, u as createLocalSource, f as createRemoteSource, i as decodeQuery, s as deriveSource, a as encodeQuery, h as filterContains, g as filterEquals, _ as filterRange, l as itemRange, d as mergeSource, p as prefetchSource, m as prefetchSourceAndKeep, v as searchBy, y as sortBy, b as sourceState };
|
package/dist/infiniteSource.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./errors.cjs"),t=require("./_utils.cjs"),n=require("./asyncSource.cjs");let
|
|
1
|
+
const e=require("./errors.cjs"),t=require("./_utils.cjs"),n=require("./asyncSearch.cjs"),r=require("./asyncSource.cjs");let i=require("@vielzeug/arsenal");function a(a){let o=a.queryKey??t.defaultKeyOf,s=Math.max(1,Math.trunc(a.limit??20)),c=``,l=1,u=0,d=[],f=0,p=null,m=!1,h=[],g={error:null,hasMore:!1,isLoading:!1,isLoadingMore:!1,isSearchPending:!1,loadedPages:0,pageSize:s,totalItems:0},_=()=>{h=d,g={error:p,hasMore:d.length<f,isLoading:v.pendingCount()>0&&!m,isLoadingMore:m,isSearchPending:v.core.isScheduled,loadedPages:u,pageSize:s,totalItems:f}},v=r.createAsyncSource(a,o,_),{autoFetch:y,debounceMs:b,retryAttempts:x,retryDelay:S}=v;_();let C=()=>{v.disposed||v.core.notify()},w=n.createAsyncSearchCoordinator(v.core,C),T=(n,r)=>{let o={...c&&{search:c},limit:s,page:n};return p=null,v.fetch(o,async(o,s,c)=>{let h=Date.now();try{let e=await(0,i.retry)(e=>a.fetch(o,e),{delay:S,signal:s,times:x+1});c()&&(d=r?[...d,...e.items]:e.items,f=e.total,l=n,u=r?u+1:1,p=null,a.onFetch?.({durationMs:Date.now()-h,query:o,status:`success`}))}catch(n){if(s.aborted)return;c()&&(r||(d=[]),f=r?f:0,p=new e.SourcererError(t.extractError(n),{cause:n,context:{kind:`infinite`,limit:o.limit,page:o.page,...o.search&&{search:o.search}}}),a.onFetch?.({durationMs:Date.now()-h,error:p,query:o,status:`error`}))}finally{m=!1}},()=>{C(),w.settleIfIdle(v.pendingCount())})},E=()=>T(1,!1);return y&&E(),v.startRefreshInterval(()=>void E()),{get current(){return h},get disposalSignal(){return v.disposalSignal},dispose:()=>{w.cancel(),w.dispose(),v.dispose()},get disposed(){return v.disposed},loadMore(){return!g.hasMore||v.pendingCount()>0||m?Promise.resolve():(m=!0,_(),T(l+1,!0))},get meta(){return g},patch(e){let t=!1;if(e.limit!==void 0){let n=Math.max(1,Math.trunc(e.limit));n!==s&&(s=n,t=!0)}return`search`in e&&(e.search!==c||v.core.isScheduled)&&(c=e.search??``,t=!0),t?(w.cancel(),d=[],f=0,l=1,u=0,E()):Promise.resolve()},get query(){return{...c&&{search:c},limit:s,page:l}},ready(e){return v.ready(e)},reset(){return w.cancel(),l=1,u=0,d=[],f=0,c=``,E()},search(e,t){return t?.immediate?e===c&&!v.core.isScheduled?Promise.resolve():(w.cancel(),c=e,d=[],f=0,u=0,l=1,E()):e===c?Promise.resolve():(c=e,d=[],f=0,u=0,l=1,w.schedule(()=>void E(),b))},subscribe:e=>v.core.subscribe(e),[Symbol.dispose]:()=>{w.cancel(),w.dispose(),v.dispose()}}}exports.createInfiniteSource=a;
|
|
2
2
|
//# sourceMappingURL=infiniteSource.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"infiniteSource.cjs","names":[],"sources":["../src/infiniteSource.ts"],"sourcesContent":["import type { InfiniteConfig, InfiniteMeta, InfiniteSource, InfiniteSourceQuery, SearchOptions } from './types';\n\nimport { defaultKeyOf, extractError, retry } from './_utils';\nimport { createAsyncSource } from './asyncSource';\nimport { SourcererError } from './errors';\n\ntype PendingSearch = { promise: Promise<void>; resolve: () => void };\n\n/** Creates an infinite-scroll source that appends pages on `loadMore()`. */\nexport function createInfiniteSource<T>(cfg: InfiniteConfig<T>): InfiniteSource<T> {\n const keyOf = cfg.queryKey ?? defaultKeyOf;\n\n // ── Mutable state ───────────────────────────────────────────────────────────\n let limit = Math.max(1, Math.trunc(cfg.limit ?? 20));\n let search = '';\n let currentPage = 1;\n let loadedPages = 0;\n let items: readonly T[] = [];\n let total = 0;\n let error: SourcererError | null = null;\n let isLoadingMore = false;\n let pendingSearch: PendingSearch | null = null;\n\n // ── Cached accessors ─────────────────────────────────────────────────────────\n let cachedCurrent: readonly T[] = [];\n let cachedMeta: InfiniteMeta = {\n error: null,\n hasMore: false,\n isLoading: false,\n isLoadingMore: false,\n isSearchPending: false,\n loadedPages: 0,\n pageSize: limit,\n totalItems: 0,\n };\n\n const refreshMeta = () => {\n cachedCurrent = items;\n cachedMeta = {\n error,\n hasMore: items.length < total,\n isLoading: base.pendingCount() > 0 && !isLoadingMore,\n isLoadingMore,\n isSearchPending: base.core.isScheduled,\n loadedPages,\n pageSize: limit,\n totalItems: total,\n };\n };\n\n // onBeforeNotify ensures refreshMeta() runs before any subscriber observes the new state,\n // eliminating the need for a parallel listeners Set.\n const base = createAsyncSource<InfiniteSourceQuery>(cfg, keyOf, refreshMeta);\n const { autoFetch, debounceMs, retryAttempts, retryDelay } = base;\n\n refreshMeta();\n\n const notifyListeners = () => {\n if (base.disposed) return;\n\n base.core.notify();\n };\n\n const resolvePendingSearch = () => {\n if (pendingSearch) {\n pendingSearch.resolve();\n pendingSearch = null;\n }\n };\n\n // ── Core fetch ──────────────────────────────────────────────────────────────\n const fetchPage = (targetPage: number, append: boolean): Promise<void> => {\n const q: InfiniteSourceQuery = {\n ...(search && { search }),\n limit,\n page: targetPage,\n };\n\n error = null;\n\n return base.fetch(\n q,\n async (q, signal, isLatest) => {\n const startTime = Date.now();\n\n try {\n const result = await retry((sig) => cfg.fetch(q, sig!), {\n delay: retryDelay,\n signal,\n times: retryAttempts + 1,\n });\n\n if (isLatest()) {\n if (append) {\n items = [...items, ...result.items];\n } else {\n items = result.items;\n }\n\n total = result.total;\n currentPage = targetPage;\n loadedPages = append ? loadedPages + 1 : 1;\n error = null;\n cfg.onFetch?.({ durationMs: Date.now() - startTime, query: q, status: 'success' });\n }\n } catch (reason: unknown) {\n if (signal.aborted) return;\n\n if (isLatest()) {\n if (!append) items = [];\n\n total = append ? total : 0;\n error = new SourcererError(extractError(reason), {\n cause: reason,\n context: { kind: 'infinite', limit: q.limit, page: q.page, ...(q.search && { search: q.search }) },\n });\n cfg.onFetch?.({ durationMs: Date.now() - startTime, error, query: q, status: 'error' });\n }\n } finally {\n isLoadingMore = false;\n }\n },\n () => {\n notifyListeners();\n\n if (base.pendingCount() === 0) resolvePendingSearch();\n },\n );\n };\n\n const doFetch = () => fetchPage(1, false);\n\n // ── Auto-fetch + refresh interval ───────────────────────────────────────────\n if (autoFetch) void doFetch();\n\n base.startRefreshInterval(() => void doFetch());\n\n // ── Public API ──────────────────────────────────────────────────────────────\n return {\n get current() {\n return cachedCurrent;\n },\n\n get disposalSignal() {\n return base.disposalSignal;\n },\n\n dispose: () => {\n resolvePendingSearch();\n base.dispose();\n },\n\n get disposed() {\n return base.disposed;\n },\n\n loadMore() {\n if (!cachedMeta.hasMore || base.pendingCount() > 0 || isLoadingMore) return Promise.resolve();\n\n isLoadingMore = true;\n refreshMeta();\n\n return fetchPage(currentPage + 1, true);\n },\n\n get meta() {\n return cachedMeta;\n },\n\n patch(changes) {\n let changed = false;\n\n if (changes.limit !== undefined) {\n const next = Math.max(1, Math.trunc(changes.limit));\n\n if (next !== limit) {\n limit = next;\n changed = true;\n }\n }\n\n // `|| base.core.isScheduled` also catches patching in the same search text as an already-pending\n // debounced search() call — that still needs flushing, not silently dropping as a no-op.\n if ('search' in changes && (changes.search !== search || base.core.isScheduled)) {\n search = changes.search ?? '';\n changed = true;\n }\n\n if (!changed) return Promise.resolve();\n\n // patch() is documented as a single atomic fetch — cancel any debounced search()\n // still pending so it doesn't fire a second, redundant fetch afterwards.\n base.core.cancelTimer();\n resolvePendingSearch();\n\n items = [];\n total = 0;\n currentPage = 1;\n loadedPages = 0;\n\n return doFetch();\n },\n\n get query() {\n return {\n ...(search && { search }),\n limit,\n page: currentPage,\n };\n },\n\n ready(timeout) {\n return base.ready(timeout);\n },\n\n reset() {\n base.core.cancelTimer();\n resolvePendingSearch();\n currentPage = 1;\n loadedPages = 0;\n items = [];\n total = 0;\n search = '';\n\n return doFetch();\n },\n\n search(q, opts?: SearchOptions): Promise<void> {\n if (opts?.immediate) {\n // A pending debounced search for this same text still needs flushing —\n // `q === search` alone doesn't mean the fetch already happened.\n if (q === search && !base.core.isScheduled) return Promise.resolve();\n\n base.core.cancelTimer();\n resolvePendingSearch();\n search = q;\n items = [];\n total = 0;\n loadedPages = 0;\n currentPage = 1;\n\n return doFetch();\n }\n\n if (q === search) return Promise.resolve();\n\n resolvePendingSearch();\n\n search = q;\n items = [];\n total = 0;\n loadedPages = 0;\n currentPage = 1;\n\n let resolveSearch!: () => void;\n const promise = new Promise<void>((res) => {\n resolveSearch = res;\n });\n\n pendingSearch = { promise, resolve: resolveSearch };\n\n base.core.schedule(() => void doFetch(), debounceMs);\n notifyListeners();\n\n return promise;\n },\n\n subscribe: (listener) => base.core.subscribe(listener),\n\n [Symbol.dispose]: () => {\n resolvePendingSearch();\n base.dispose();\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"infiniteSource.cjs","names":[],"sources":["../src/infiniteSource.ts"],"sourcesContent":["import type { InfiniteConfig, InfiniteMeta, InfiniteSource, InfiniteSourceQuery, SearchOptions } from './types';\n\nimport { defaultKeyOf, extractError, retry } from './_utils';\nimport { createAsyncSearchCoordinator } from './asyncSearch';\nimport { createAsyncSource } from './asyncSource';\nimport { SourcererError } from './errors';\n\n/** Creates an infinite-scroll source that appends pages on `loadMore()`. */\nexport function createInfiniteSource<T>(cfg: InfiniteConfig<T>): InfiniteSource<T> {\n const keyOf = cfg.queryKey ?? defaultKeyOf;\n\n // ── Mutable state ───────────────────────────────────────────────────────────\n let limit = Math.max(1, Math.trunc(cfg.limit ?? 20));\n let search = '';\n let currentPage = 1;\n let loadedPages = 0;\n let items: readonly T[] = [];\n let total = 0;\n let error: SourcererError | null = null;\n let isLoadingMore = false;\n\n // ── Cached accessors ─────────────────────────────────────────────────────────\n let cachedCurrent: readonly T[] = [];\n let cachedMeta: InfiniteMeta = {\n error: null,\n hasMore: false,\n isLoading: false,\n isLoadingMore: false,\n isSearchPending: false,\n loadedPages: 0,\n pageSize: limit,\n totalItems: 0,\n };\n\n const refreshMeta = () => {\n cachedCurrent = items;\n cachedMeta = {\n error,\n hasMore: items.length < total,\n isLoading: base.pendingCount() > 0 && !isLoadingMore,\n isLoadingMore,\n isSearchPending: base.core.isScheduled,\n loadedPages,\n pageSize: limit,\n totalItems: total,\n };\n };\n\n // onBeforeNotify ensures refreshMeta() runs before any subscriber observes the new state,\n // eliminating the need for a parallel listeners Set.\n const base = createAsyncSource<InfiniteSourceQuery>(cfg, keyOf, refreshMeta);\n const { autoFetch, debounceMs, retryAttempts, retryDelay } = base;\n\n refreshMeta();\n\n const notifyListeners = () => {\n if (base.disposed) return;\n\n base.core.notify();\n };\n const searchCoordinator = createAsyncSearchCoordinator(base.core, notifyListeners);\n\n // ── Core fetch ──────────────────────────────────────────────────────────────\n const fetchPage = (targetPage: number, append: boolean): Promise<void> => {\n const q: InfiniteSourceQuery = {\n ...(search && { search }),\n limit,\n page: targetPage,\n };\n\n error = null;\n\n return base.fetch(\n q,\n async (q, signal, isLatest) => {\n const startTime = Date.now();\n\n try {\n const result = await retry((sig) => cfg.fetch(q, sig!), {\n delay: retryDelay,\n signal,\n times: retryAttempts + 1,\n });\n\n if (isLatest()) {\n if (append) {\n items = [...items, ...result.items];\n } else {\n items = result.items;\n }\n\n total = result.total;\n currentPage = targetPage;\n loadedPages = append ? loadedPages + 1 : 1;\n error = null;\n cfg.onFetch?.({ durationMs: Date.now() - startTime, query: q, status: 'success' });\n }\n } catch (reason: unknown) {\n if (signal.aborted) return;\n\n if (isLatest()) {\n if (!append) items = [];\n\n total = append ? total : 0;\n error = new SourcererError(extractError(reason), {\n cause: reason,\n context: { kind: 'infinite', limit: q.limit, page: q.page, ...(q.search && { search: q.search }) },\n });\n cfg.onFetch?.({ durationMs: Date.now() - startTime, error, query: q, status: 'error' });\n }\n } finally {\n isLoadingMore = false;\n }\n },\n () => {\n notifyListeners();\n\n searchCoordinator.settleIfIdle(base.pendingCount());\n },\n );\n };\n\n const doFetch = () => fetchPage(1, false);\n\n // ── Auto-fetch + refresh interval ───────────────────────────────────────────\n if (autoFetch) void doFetch();\n\n base.startRefreshInterval(() => void doFetch());\n\n // ── Public API ──────────────────────────────────────────────────────────────\n return {\n get current() {\n return cachedCurrent;\n },\n\n get disposalSignal() {\n return base.disposalSignal;\n },\n\n dispose: () => {\n searchCoordinator.cancel();\n searchCoordinator.dispose();\n base.dispose();\n },\n\n get disposed() {\n return base.disposed;\n },\n\n loadMore() {\n if (!cachedMeta.hasMore || base.pendingCount() > 0 || isLoadingMore) return Promise.resolve();\n\n isLoadingMore = true;\n refreshMeta();\n\n return fetchPage(currentPage + 1, true);\n },\n\n get meta() {\n return cachedMeta;\n },\n\n patch(changes) {\n let changed = false;\n\n if (changes.limit !== undefined) {\n const next = Math.max(1, Math.trunc(changes.limit));\n\n if (next !== limit) {\n limit = next;\n changed = true;\n }\n }\n\n // `|| base.core.isScheduled` also catches patching in the same search text as an already-pending\n // debounced search() call — that still needs flushing, not silently dropping as a no-op.\n if ('search' in changes && (changes.search !== search || base.core.isScheduled)) {\n search = changes.search ?? '';\n changed = true;\n }\n\n if (!changed) return Promise.resolve();\n\n // patch() is documented as a single atomic fetch — cancel any debounced search()\n // still pending so it doesn't fire a second, redundant fetch afterwards.\n searchCoordinator.cancel();\n\n items = [];\n total = 0;\n currentPage = 1;\n loadedPages = 0;\n\n return doFetch();\n },\n\n get query() {\n return {\n ...(search && { search }),\n limit,\n page: currentPage,\n };\n },\n\n ready(timeout) {\n return base.ready(timeout);\n },\n\n reset() {\n searchCoordinator.cancel();\n currentPage = 1;\n loadedPages = 0;\n items = [];\n total = 0;\n search = '';\n\n return doFetch();\n },\n\n search(q, opts?: SearchOptions): Promise<void> {\n if (opts?.immediate) {\n // A pending debounced search for this same text still needs flushing —\n // `q === search` alone doesn't mean the fetch already happened.\n if (q === search && !base.core.isScheduled) return Promise.resolve();\n\n searchCoordinator.cancel();\n search = q;\n items = [];\n total = 0;\n loadedPages = 0;\n currentPage = 1;\n\n return doFetch();\n }\n\n if (q === search) return Promise.resolve();\n\n search = q;\n items = [];\n total = 0;\n loadedPages = 0;\n currentPage = 1;\n\n return searchCoordinator.schedule(() => void doFetch(), debounceMs);\n },\n\n subscribe: (listener) => base.core.subscribe(listener),\n\n [Symbol.dispose]: () => {\n searchCoordinator.cancel();\n searchCoordinator.dispose();\n base.dispose();\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"infiniteSource.d.ts","sourceRoot":"","sources":["../src/infiniteSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAgB,cAAc,EAAsC,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"infiniteSource.d.ts","sourceRoot":"","sources":["../src/infiniteSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAgB,cAAc,EAAsC,MAAM,SAAS,CAAC;AAOhH,4EAA4E;AAC5E,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAqPjF"}
|