@vielzeug/sourcerer 1.0.5 → 1.1.0

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.
Files changed (89) hide show
  1. package/dist/_dev.cjs +2 -0
  2. package/dist/_dev.cjs.map +1 -0
  3. package/dist/_dev.d.ts +2 -0
  4. package/dist/_dev.d.ts.map +1 -0
  5. package/dist/_dev.js +12 -0
  6. package/dist/_dev.js.map +1 -0
  7. package/dist/_utils.cjs +1 -1
  8. package/dist/_utils.cjs.map +1 -1
  9. package/dist/_utils.d.ts +20 -0
  10. package/dist/_utils.d.ts.map +1 -1
  11. package/dist/_utils.js +16 -3
  12. package/dist/_utils.js.map +1 -1
  13. package/dist/codecs.cjs +1 -1
  14. package/dist/codecs.cjs.map +1 -1
  15. package/dist/codecs.d.ts +1 -1
  16. package/dist/codecs.d.ts.map +1 -1
  17. package/dist/codecs.js +21 -19
  18. package/dist/codecs.js.map +1 -1
  19. package/dist/core.cjs +1 -1
  20. package/dist/core.cjs.map +1 -1
  21. package/dist/core.d.ts +25 -1
  22. package/dist/core.d.ts.map +1 -1
  23. package/dist/core.js +1 -1
  24. package/dist/core.js.map +1 -1
  25. package/dist/cursorSource.cjs +1 -1
  26. package/dist/cursorSource.cjs.map +1 -1
  27. package/dist/cursorSource.js +69 -69
  28. package/dist/cursorSource.js.map +1 -1
  29. package/dist/derive.cjs +1 -1
  30. package/dist/derive.cjs.map +1 -1
  31. package/dist/derive.d.ts +1 -0
  32. package/dist/derive.d.ts.map +1 -1
  33. package/dist/derive.js +2 -4
  34. package/dist/derive.js.map +1 -1
  35. package/dist/devtools.cjs +2 -0
  36. package/dist/devtools.cjs.map +1 -0
  37. package/dist/devtools.d.ts +52 -0
  38. package/dist/devtools.d.ts.map +1 -0
  39. package/dist/devtools.js +20 -0
  40. package/dist/devtools.js.map +1 -0
  41. package/dist/errors.cjs +1 -1
  42. package/dist/errors.cjs.map +1 -1
  43. package/dist/errors.d.ts +2 -2
  44. package/dist/errors.d.ts.map +1 -1
  45. package/dist/errors.js +1 -1
  46. package/dist/errors.js.map +1 -1
  47. package/dist/fetchManager.cjs.map +1 -1
  48. package/dist/fetchManager.d.ts +13 -0
  49. package/dist/fetchManager.d.ts.map +1 -1
  50. package/dist/fetchManager.js.map +1 -1
  51. package/dist/index.cjs +1 -1
  52. package/dist/index.d.ts +1 -2
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +13 -14
  55. package/dist/infiniteSource.cjs +1 -1
  56. package/dist/infiniteSource.cjs.map +1 -1
  57. package/dist/infiniteSource.js +62 -62
  58. package/dist/infiniteSource.js.map +1 -1
  59. package/dist/localSource.cjs +1 -1
  60. package/dist/localSource.cjs.map +1 -1
  61. package/dist/localSource.d.ts.map +1 -1
  62. package/dist/localSource.js +69 -79
  63. package/dist/localSource.js.map +1 -1
  64. package/dist/merge.cjs +1 -1
  65. package/dist/merge.cjs.map +1 -1
  66. package/dist/merge.d.ts +6 -1
  67. package/dist/merge.d.ts.map +1 -1
  68. package/dist/merge.js +8 -1
  69. package/dist/merge.js.map +1 -1
  70. package/dist/remoteSource.cjs +1 -1
  71. package/dist/remoteSource.cjs.map +1 -1
  72. package/dist/remoteSource.d.ts.map +1 -1
  73. package/dist/remoteSource.js +94 -94
  74. package/dist/remoteSource.js.map +1 -1
  75. package/dist/sourcerer.cjs +1 -1
  76. package/dist/sourcerer.cjs.map +1 -1
  77. package/dist/sourcerer.iife.js +1 -1
  78. package/dist/sourcerer.iife.js.map +1 -1
  79. package/dist/sourcerer.js +1 -1
  80. package/dist/sourcerer.js.map +1 -1
  81. package/dist/types.d.ts +14 -4
  82. package/dist/types.d.ts.map +1 -1
  83. package/package.json +9 -3
  84. package/dist/applyQuery.cjs +0 -2
  85. package/dist/applyQuery.cjs.map +0 -1
  86. package/dist/applyQuery.d.ts +0 -20
  87. package/dist/applyQuery.d.ts.map +0 -1
  88. package/dist/applyQuery.js +0 -8
  89. package/dist/applyQuery.js.map +0 -1
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- export { applyQuery } from './applyQuery';
2
1
  export { decodeQuery, encodeQuery } from './codecs';
3
2
  export type { DecodeQueryOptions } from './codecs';
4
3
  export { createCursorSource } from './cursorSource';
@@ -11,6 +10,6 @@ export { prefetchSource, prefetchSourceAndKeep } from './prefetch';
11
10
  export { filterContains, filterEquals, filterRange, searchBy, sortBy } from './presets';
12
11
  export { createRemoteSource } from './remoteSource';
13
12
  export { sourceState } from './state';
14
- export { SourceDisposedError, SourcererError, SourceTimeoutError } from './errors';
13
+ export { SourcererDisposedError, SourcererError, SourcererTimeoutError } from './errors';
15
14
  export type { CursorConfig, CursorMeta, CursorSource, CursorSourceQuery, DerivedSource, FetchEvent, InfiniteConfig, InfiniteMeta, InfiniteSource, InfiniteSourceQuery, LocalSource, LocalSourceConfig, LocalSourceQuery, MergedSource, PageNavigator, Predicate, QueryParams, QueryParamsInput, ReactiveSource, RemoteConfig, RemoteSource, RemoteSourceQuery, RetryConfig, SearchOptions, Sorter, SourcererErrorContext, SourceMeta, SourceQuery, SourceSnapshot, SourceState, } from './types';
16
15
  //# sourceMappingURL=index.d.ts.map
@@ -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,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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,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,sBAAsB,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACzF,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
@@ -1,14 +1,13 @@
1
- import { applyQuery as e } from "./applyQuery.js";
2
- import { SourceDisposedError as t, SourceTimeoutError as n, SourcererError as r } from "./errors.js";
3
- import { decodeQuery as i, encodeQuery as a } from "./codecs.js";
4
- import { createCursorSource as o } from "./cursorSource.js";
5
- import { deriveSource as s } from "./derive.js";
6
- import { createInfiniteSource as c } from "./infiniteSource.js";
7
- import { itemRange as l } from "./pagination.js";
8
- import { createLocalSource as u } from "./localSource.js";
9
- import { mergeSource as d } from "./merge.js";
10
- import { createRemoteSource as f } from "./remoteSource.js";
11
- import { prefetchSource as p, prefetchSourceAndKeep as m } from "./prefetch.js";
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 };
1
+ import { SourcererDisposedError as e, SourcererError as t, SourcererTimeoutError as n } from "./errors.js";
2
+ import { decodeQuery as r, encodeQuery as i } from "./codecs.js";
3
+ import { createCursorSource as a } from "./cursorSource.js";
4
+ import { deriveSource as o } from "./derive.js";
5
+ import { createInfiniteSource as s } from "./infiniteSource.js";
6
+ import { itemRange as c } from "./pagination.js";
7
+ import { createLocalSource as l } from "./localSource.js";
8
+ import { mergeSource as u } from "./merge.js";
9
+ import { createRemoteSource as d } from "./remoteSource.js";
10
+ import { prefetchSource as f, prefetchSourceAndKeep as p } from "./prefetch.js";
11
+ import { filterContains as m, filterEquals as h, filterRange as g, searchBy as _, sortBy as v } from "./presets.js";
12
+ import { sourceState as y } from "./state.js";
13
+ export { e as SourcererDisposedError, t as SourcererError, n as SourcererTimeoutError, a as createCursorSource, s as createInfiniteSource, l as createLocalSource, d as createRemoteSource, r as decodeQuery, o as deriveSource, i as encodeQuery, m as filterContains, h as filterEquals, g as filterRange, c as itemRange, u as mergeSource, f as prefetchSource, p as prefetchSourceAndKeep, _ as searchBy, v as sortBy, y as sourceState };
@@ -1,2 +1,2 @@
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;
1
+ const e=require("./_utils.cjs"),t=require("./errors.cjs"),n=require("./asyncSearch.cjs"),r=require("./asyncSource.cjs");let i=require("@vielzeug/arsenal");function a(a){let o=a.queryKey??e.defaultKeyOf,s=e.clampPositiveInt(a.limit??20,`createInfiniteSource`,`limit`),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 t.SourcererError(e.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(t){let n=!1;if(t.limit!==void 0){let r=e.clampPositiveInt(t.limit,`source.patch`,`limit`);r!==s&&(s=r,n=!0)}return`search`in t&&(t.search!==c||v.core.isScheduled)&&(c=t.search??``,n=!0),n?(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 { 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
+ {"version":3,"file":"infiniteSource.cjs","names":[],"sources":["../src/infiniteSource.ts"],"sourcesContent":["import type { InfiniteConfig, InfiniteMeta, InfiniteSource, InfiniteSourceQuery, SearchOptions } from './types';\n\nimport { clampPositiveInt, 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 = clampPositiveInt(cfg.limit ?? 20, 'createInfiniteSource', 'limit');\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 = clampPositiveInt(changes.limit, 'source.patch', '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,125 +1,125 @@
1
- import { SourcererError as e } from "./errors.js";
2
- import { defaultKeyOf as t, extractError as n, retry as r } from "./_utils.js";
3
- import { createAsyncSearchCoordinator as i } from "./asyncSearch.js";
4
- import { createAsyncSource as a } from "./asyncSource.js";
1
+ import { clampPositiveInt as e, defaultKeyOf as t, extractError as n, retry as r } from "./_utils.js";
2
+ import { SourcererError as i } from "./errors.js";
3
+ import { createAsyncSearchCoordinator as a } from "./asyncSearch.js";
4
+ import { createAsyncSource as o } from "./asyncSource.js";
5
5
  //#region src/infiniteSource.ts
6
- function o(o) {
7
- let s = o.queryKey ?? t, c = Math.max(1, Math.trunc(o.limit ?? 20)), l = "", u = 1, d = 0, f = [], p = 0, m = null, h = !1, g = [], _ = {
6
+ function s(s) {
7
+ let c = s.queryKey ?? t, l = e(s.limit ?? 20, "createInfiniteSource", "limit"), u = "", d = 1, f = 0, p = [], m = 0, h = null, g = !1, _ = [], v = {
8
8
  error: null,
9
9
  hasMore: !1,
10
10
  isLoading: !1,
11
11
  isLoadingMore: !1,
12
12
  isSearchPending: !1,
13
13
  loadedPages: 0,
14
- pageSize: c,
14
+ pageSize: l,
15
15
  totalItems: 0
16
- }, v = () => {
17
- g = f, _ = {
18
- error: m,
19
- hasMore: f.length < p,
20
- isLoading: y.pendingCount() > 0 && !h,
21
- isLoadingMore: h,
22
- isSearchPending: y.core.isScheduled,
23
- loadedPages: d,
24
- pageSize: c,
25
- totalItems: p
16
+ }, y = () => {
17
+ _ = p, v = {
18
+ error: h,
19
+ hasMore: p.length < m,
20
+ isLoading: b.pendingCount() > 0 && !g,
21
+ isLoadingMore: g,
22
+ isSearchPending: b.core.isScheduled,
23
+ loadedPages: f,
24
+ pageSize: l,
25
+ totalItems: m
26
26
  };
27
- }, y = a(o, s, v), { autoFetch: b, debounceMs: x, retryAttempts: S, retryDelay: C } = y;
28
- v();
29
- let w = () => {
30
- y.disposed || y.core.notify();
31
- }, T = i(y.core, w), E = (t, i) => {
27
+ }, b = o(s, c, y), { autoFetch: x, debounceMs: S, retryAttempts: C, retryDelay: w } = b;
28
+ y();
29
+ let T = () => {
30
+ b.disposed || b.core.notify();
31
+ }, E = a(b.core, T), D = (e, t) => {
32
32
  let a = {
33
- ...l && { search: l },
34
- limit: c,
35
- page: t
33
+ ...u && { search: u },
34
+ limit: l,
35
+ page: e
36
36
  };
37
- return m = null, y.fetch(a, async (a, s, c) => {
37
+ return h = null, b.fetch(a, async (a, o, c) => {
38
38
  let l = Date.now();
39
39
  try {
40
- let e = await r((e) => o.fetch(a, e), {
41
- delay: C,
42
- signal: s,
43
- times: S + 1
40
+ let n = await r((e) => s.fetch(a, e), {
41
+ delay: w,
42
+ signal: o,
43
+ times: C + 1
44
44
  });
45
- c() && (f = i ? [...f, ...e.items] : e.items, p = e.total, u = t, d = i ? d + 1 : 1, m = null, o.onFetch?.({
45
+ c() && (p = t ? [...p, ...n.items] : n.items, m = n.total, d = e, f = t ? f + 1 : 1, h = null, s.onFetch?.({
46
46
  durationMs: Date.now() - l,
47
47
  query: a,
48
48
  status: "success"
49
49
  }));
50
- } catch (t) {
51
- if (s.aborted) return;
52
- c() && (i || (f = []), p = i ? p : 0, m = new e(n(t), {
53
- cause: t,
50
+ } catch (e) {
51
+ if (o.aborted) return;
52
+ c() && (t || (p = []), m = t ? m : 0, h = new i(n(e), {
53
+ cause: e,
54
54
  context: {
55
55
  kind: "infinite",
56
56
  limit: a.limit,
57
57
  page: a.page,
58
58
  ...a.search && { search: a.search }
59
59
  }
60
- }), o.onFetch?.({
60
+ }), s.onFetch?.({
61
61
  durationMs: Date.now() - l,
62
- error: m,
62
+ error: h,
63
63
  query: a,
64
64
  status: "error"
65
65
  }));
66
66
  } finally {
67
- h = !1;
67
+ g = !1;
68
68
  }
69
69
  }, () => {
70
- w(), T.settleIfIdle(y.pendingCount());
70
+ T(), E.settleIfIdle(b.pendingCount());
71
71
  });
72
- }, D = () => E(1, !1);
73
- return b && D(), y.startRefreshInterval(() => void D()), {
72
+ }, O = () => D(1, !1);
73
+ return x && O(), b.startRefreshInterval(() => void O()), {
74
74
  get current() {
75
- return g;
75
+ return _;
76
76
  },
77
77
  get disposalSignal() {
78
- return y.disposalSignal;
78
+ return b.disposalSignal;
79
79
  },
80
80
  dispose: () => {
81
- T.cancel(), T.dispose(), y.dispose();
81
+ E.cancel(), E.dispose(), b.dispose();
82
82
  },
83
83
  get disposed() {
84
- return y.disposed;
84
+ return b.disposed;
85
85
  },
86
86
  loadMore() {
87
- return !_.hasMore || y.pendingCount() > 0 || h ? Promise.resolve() : (h = !0, v(), E(u + 1, !0));
87
+ return !v.hasMore || b.pendingCount() > 0 || g ? Promise.resolve() : (g = !0, y(), D(d + 1, !0));
88
88
  },
89
89
  get meta() {
90
- return _;
90
+ return v;
91
91
  },
92
- patch(e) {
93
- let t = !1;
94
- if (e.limit !== void 0) {
95
- let n = Math.max(1, Math.trunc(e.limit));
96
- n !== c && (c = n, t = !0);
92
+ patch(t) {
93
+ let n = !1;
94
+ if (t.limit !== void 0) {
95
+ let r = e(t.limit, "source.patch", "limit");
96
+ r !== l && (l = r, n = !0);
97
97
  }
98
- return "search" in e && (e.search !== l || y.core.isScheduled) && (l = e.search ?? "", t = !0), t ? (T.cancel(), f = [], p = 0, u = 1, d = 0, D()) : Promise.resolve();
98
+ return "search" in t && (t.search !== u || b.core.isScheduled) && (u = t.search ?? "", n = !0), n ? (E.cancel(), p = [], m = 0, d = 1, f = 0, O()) : Promise.resolve();
99
99
  },
100
100
  get query() {
101
101
  return {
102
- ...l && { search: l },
103
- limit: c,
104
- page: u
102
+ ...u && { search: u },
103
+ limit: l,
104
+ page: d
105
105
  };
106
106
  },
107
107
  ready(e) {
108
- return y.ready(e);
108
+ return b.ready(e);
109
109
  },
110
110
  reset() {
111
- return T.cancel(), u = 1, d = 0, f = [], p = 0, l = "", D();
111
+ return E.cancel(), d = 1, f = 0, p = [], m = 0, u = "", O();
112
112
  },
113
113
  search(e, t) {
114
- return t?.immediate ? e === l && !y.core.isScheduled ? Promise.resolve() : (T.cancel(), l = e, f = [], p = 0, d = 0, u = 1, D()) : e === l ? Promise.resolve() : (l = e, f = [], p = 0, d = 0, u = 1, T.schedule(() => void D(), x));
114
+ return t?.immediate ? e === u && !b.core.isScheduled ? Promise.resolve() : (E.cancel(), u = e, p = [], m = 0, f = 0, d = 1, O()) : e === u ? Promise.resolve() : (u = e, p = [], m = 0, f = 0, d = 1, E.schedule(() => void O(), S));
115
115
  },
116
- subscribe: (e) => y.core.subscribe(e),
116
+ subscribe: (e) => b.core.subscribe(e),
117
117
  [Symbol.dispose]: () => {
118
- T.cancel(), T.dispose(), y.dispose();
118
+ E.cancel(), E.dispose(), b.dispose();
119
119
  }
120
120
  };
121
121
  }
122
122
  //#endregion
123
- export { o as createInfiniteSource };
123
+ export { s as createInfiniteSource };
124
124
 
125
125
  //# sourceMappingURL=infiniteSource.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"infiniteSource.js","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
+ {"version":3,"file":"infiniteSource.js","names":[],"sources":["../src/infiniteSource.ts"],"sourcesContent":["import type { InfiniteConfig, InfiniteMeta, InfiniteSource, InfiniteSourceQuery, SearchOptions } from './types';\n\nimport { clampPositiveInt, 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 = clampPositiveInt(cfg.limit ?? 20, 'createInfiniteSource', 'limit');\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 = clampPositiveInt(changes.limit, 'source.patch', '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,2 +1,2 @@
1
- const e=require("./errors.cjs"),t=require("./_utils.cjs"),n=require("./core.cjs"),r=require("./pagination.cjs");var i=20,a=300;function o(e,t){let n=t.toLowerCase();return e.filter(e=>JSON.stringify(e).toLowerCase().includes(n))}function s(s,c={}){let l=n.createSourceCore(),u=c.filterAsync!==void 0||c.sortAsync!==void 0,d=c.debounceMs??a,f=c.initialData??s,p=``,m=c.filter,h=c.sort,g=c.limit??i,_=1,v=[],y=!1,b=!1,x=null,S=null,C=null,w=()=>l.notify(),T=()=>{C&&=(C.resolve(),null)},E=()=>{let e=f;return p&&(e=(c.searchFn??o)(e,p)),m&&(e=e.filter(m)),h&&(e=[...e].sort(h)),e},D=()=>{v=E();let e=r.pageCount(v.length,g);_=r.clampPage(_,e)},O=async()=>{S?.abort();let n=new AbortController;S=n,y=!0,x=null,w();try{let e=f;if(p&&(e=(c.searchFn??o)(e,p)),m&&(e=e.filter(m)),c.filterAsync&&!n.signal.aborted&&(e=await c.filterAsync(e,n.signal)),h&&(e=[...e].sort(h)),c.sortAsync&&!n.signal.aborted&&(e=await c.sortAsync(e,n.signal)),n.signal.aborted)return;v=e,y=!1,b=!1;let t=r.pageCount(v.length,g);_=r.clampPage(_,t)}catch(r){n.signal.aborted||(y=!1,b=!1,x=new e.SourcererError(t.extractError(r),{cause:r}))}finally{S===n&&(S=null)}w(),T()},k=()=>u?O():(b=!1,D(),w(),T(),Promise.resolve());u?(v=E(),O()):D();let A={get current(){let e=(_-1)*g;return v.slice(e,e+g)},get disposalSignal(){return l.disposalSignal},dispose(){l.isDisposed||(l.cancelTimer(),S?.abort(),S=null,T(),l.dispose())},get disposed(){return l.isDisposed},goTo(e){let t=r.clampPage(e,r.pageCount(v.length,g));return t===_?Promise.resolve():(_=t,w(),Promise.resolve())},goToLast(){return A.goTo(r.pageCount(v.length,g))},get meta(){return r.createMeta({error:x,isLoading:y,isSearchPending:b,pageNumber:_,pageSize:g,totalItems:v.length})},next(){return A.goTo(_+1)},patch(e){let t=!1;if(e.limit!==void 0){let n=Math.max(1,Math.trunc(e.limit));n!==g&&(g=n,t=!0)}if(`filter`in e&&(m=e.filter,t=!0),`sort`in e&&(h=e.sort,t=!0),`search`in e&&(e.search!==p||l.isScheduled)&&(p=e.search??``,t=!0),e.page!==void 0){let n=r.clampPage(e.page,r.pageCount(v.length,g));n!==_&&(_=n,t=!0)}return t?(l.cancelTimer(),T(),(e.limit!==void 0||`filter`in e||`sort`in e||`search`in e)&&e.page===void 0&&(_=1),k()):Promise.resolve()},prev(){return A.goTo(_-1)},get query(){return{limit:g,page:_,...p&&{search:p}}},ready(e){return l.ready(()=>!y&&!l.isScheduled,e)},reset(){return l.cancelTimer(),b=!1,p=``,m=c.filter,h=c.sort,_=1,T(),k()},search(e,t){if(t?.immediate)return e===p&&!l.isScheduled?Promise.resolve():(l.cancelTimer(),b=!1,p=e,_=1,T(),k());if(e===p)return Promise.resolve();T(),p=e,_=1,b=!0,w();let n,r=new Promise(e=>{n=e});return C={promise:r,resolve:n},l.schedule(()=>{b=!1,k()},d),r},setData(e){return f=e,_=1,k()},subscribe(e){return l.subscribe(e)},[Symbol.dispose](){A.dispose()}};return A}exports.createLocalSource=s;
1
+ const e=require("./_utils.cjs"),t=require("./errors.cjs"),n=require("./asyncSearch.cjs"),r=require("./core.cjs"),i=require("./pagination.cjs");var a=20,o=300;function s(e,t){let n=t.toLowerCase();return e.filter(e=>JSON.stringify(e).toLowerCase().includes(n))}function c(c,l={}){let u=r.createSourceCore(),d=l.filterAsync!==void 0||l.sortAsync!==void 0,f=l.debounceMs??o,p=l.initialData??c,m=``,h=l.filter,g=l.sort,_=e.clampPositiveInt(l.limit??a,`createLocalSource`,`limit`),v=1,y=[],b=!1,x=!1,S=null,C=null,w=()=>u.notify(),T=n.createAsyncSearchCoordinator(u,w),E=()=>{let e=p;return m&&(e=(l.searchFn??s)(e,m)),h&&(e=e.filter(h)),g&&(e=[...e].sort(g)),e},D=()=>{y=E();let e=i.pageCount(y.length,_);v=i.clampPage(v,e)},O=async()=>{C?.abort();let n=new AbortController;C=n,b=!0,S=null,w();try{let e=p;if(m&&(e=(l.searchFn??s)(e,m)),h&&(e=e.filter(h)),l.filterAsync&&!n.signal.aborted&&(e=await l.filterAsync(e,n.signal)),g&&(e=[...e].sort(g)),l.sortAsync&&!n.signal.aborted&&(e=await l.sortAsync(e,n.signal)),n.signal.aborted)return;y=e,b=!1,x=!1;let t=i.pageCount(y.length,_);v=i.clampPage(v,t)}catch(r){n.signal.aborted||(b=!1,x=!1,S=new t.SourcererError(e.extractError(r),{cause:r}))}finally{C===n&&(C=null)}w(),T.settleIfIdle(0)},k=()=>d?O():(x=!1,D(),w(),T.settleIfIdle(0),Promise.resolve());d?(y=E(),O()):D();let A={get current(){let e=(v-1)*_;return y.slice(e,e+_)},get disposalSignal(){return u.disposalSignal},dispose(){u.isDisposed||(C?.abort(),C=null,T.cancel(),T.dispose(),u.dispose())},get disposed(){return u.isDisposed},goTo(e){let t=i.clampPage(e,i.pageCount(y.length,_));return t===v?Promise.resolve():(v=t,w(),Promise.resolve())},goToLast(){return A.goTo(i.pageCount(y.length,_))},get meta(){return i.createMeta({error:S,isLoading:b,isSearchPending:x,pageNumber:v,pageSize:_,totalItems:y.length})},next(){return A.goTo(v+1)},patch(t){let n=!1;if(t.limit!==void 0){let r=e.clampPositiveInt(t.limit,`source.patch`,`limit`);r!==_&&(_=r,n=!0)}if(`filter`in t&&(h=t.filter,n=!0),`sort`in t&&(g=t.sort,n=!0),`search`in t&&(t.search!==m||u.isScheduled)&&(m=t.search??``,n=!0),t.page!==void 0){let e=i.clampPage(t.page,i.pageCount(y.length,_));e!==v&&(v=e,n=!0)}return n?(T.cancel(),(t.limit!==void 0||`filter`in t||`sort`in t||`search`in t)&&t.page===void 0&&(v=1),k()):Promise.resolve()},prev(){return A.goTo(v-1)},get query(){return{limit:_,page:v,...m&&{search:m}}},ready(e){return u.ready(()=>!b&&!u.isScheduled,e)},reset(){return T.cancel(),x=!1,m=``,h=l.filter,g=l.sort,v=1,k()},search(e,t){return t?.immediate?e===m&&!u.isScheduled?Promise.resolve():(T.cancel(),x=!1,m=e,v=1,k()):e===m?Promise.resolve():(m=e,v=1,x=!0,T.schedule(()=>{x=!1,k()},f))},setData(e){return p=e,v=1,k()},subscribe(e){return u.subscribe(e)},[Symbol.dispose](){A.dispose()}};return A}exports.createLocalSource=c;
2
2
  //# sourceMappingURL=localSource.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"localSource.cjs","names":[],"sources":["../src/localSource.ts"],"sourcesContent":["import type { LocalSource, LocalSourceConfig, LocalSourceQuery, SearchOptions, SourceQuery } from './types';\n\nimport { extractError } from './_utils';\nimport { createSourceCore } from './core';\nimport { SourcererError } from './errors';\nimport { clampPage, createMeta, pageCount } from './pagination';\n\ntype PendingSearch = { promise: Promise<void>; resolve: () => void };\n\nconst DEFAULT_LIMIT = 20;\nconst DEFAULT_DEBOUNCE_MS = 300;\n\nfunction defaultSearch<T>(items: readonly T[], query: string): readonly T[] {\n const q = query.toLowerCase();\n\n return items.filter((item) => JSON.stringify(item).toLowerCase().includes(q));\n}\n\n/**\n * Creates an in-memory paginated source with optional async filter/sort pipelines.\n *\n * When neither `filterAsync` nor `sortAsync` are configured, all operations\n * complete synchronously — there is no loading state and `ready()` resolves immediately.\n * Provide async ops to offload heavy computation (e.g. to a Web Worker).\n *\n * @example\n * ```ts\n * // Synchronous (common case)\n * const source = createLocalSource([1, 2, 3, 4, 5], { limit: 2 });\n * await source.goTo(2);\n * console.log(source.current); // [3, 4]\n *\n * // Async pipeline (Web Worker offloading)\n * const source = createLocalSource(users, {\n * filterAsync: (items, signal) => myWorker.filter(items, signal),\n * sortAsync: (items, signal) => myWorker.sort(items, signal),\n * });\n * ```\n */\nexport function createLocalSource<T>(data: readonly T[], cfg: LocalSourceConfig<T> = {}): LocalSource<T> {\n const core = createSourceCore();\n const isAsync = cfg.filterAsync !== undefined || cfg.sortAsync !== undefined;\n const debounceMs = cfg.debounceMs ?? DEFAULT_DEBOUNCE_MS;\n\n let allData: readonly T[] = cfg.initialData ?? data;\n let search = '';\n let filter = cfg.filter;\n let sort = cfg.sort;\n let limit = cfg.limit ?? DEFAULT_LIMIT;\n let page = 1;\n let processed: readonly T[] = [];\n let isLoading = false;\n let isSearchPending = false;\n let error: SourcererError | null = null;\n let asyncController: AbortController | null = null;\n let pendingSearch: PendingSearch | null = null;\n\n const commit = () => core.notify();\n\n const resolvePendingSearch = () => {\n if (pendingSearch) {\n pendingSearch.resolve();\n pendingSearch = null;\n }\n };\n\n // ── Sync pipeline (used when no async ops) ──────────────────────────────────\n const runSyncPipeline = (): readonly T[] => {\n let result: readonly T[] = allData;\n\n if (search) result = (cfg.searchFn ?? defaultSearch)(result, search);\n\n if (filter) result = result.filter(filter);\n\n if (sort) result = [...result].sort(sort);\n\n return result;\n };\n\n const recompute = () => {\n processed = runSyncPipeline();\n\n const pages = pageCount(processed.length, limit);\n\n page = clampPage(page, pages);\n };\n\n // ── Async pipeline ──────────────────────────────────────────────────────────\n const runAsyncPipeline = async (): Promise<void> => {\n asyncController?.abort();\n\n const controller = new AbortController();\n\n asyncController = controller;\n isLoading = true;\n error = null;\n commit();\n\n try {\n let result: readonly T[] = allData;\n\n if (search) result = (cfg.searchFn ?? defaultSearch)(result, search);\n\n if (filter) result = result.filter(filter);\n\n if (cfg.filterAsync && !controller.signal.aborted) {\n result = await cfg.filterAsync(result, controller.signal);\n }\n\n if (sort) result = [...result].sort(sort);\n\n if (cfg.sortAsync && !controller.signal.aborted) {\n result = await cfg.sortAsync(result, controller.signal);\n }\n\n if (controller.signal.aborted) return;\n\n processed = result;\n isLoading = false;\n isSearchPending = false;\n\n const pages = pageCount(processed.length, limit);\n\n page = clampPage(page, pages);\n } catch (reason: unknown) {\n if (!controller.signal.aborted) {\n isLoading = false;\n isSearchPending = false;\n error = new SourcererError(extractError(reason), { cause: reason });\n }\n } finally {\n if (asyncController === controller) asyncController = null;\n }\n\n commit();\n resolvePendingSearch();\n };\n\n // Internal flush — not part of public API\n const flushInternal = (): Promise<void> => {\n if (isAsync) return runAsyncPipeline();\n\n isSearchPending = false;\n recompute();\n commit();\n resolvePendingSearch();\n\n return Promise.resolve();\n };\n\n // ── Initial state ───────────────────────────────────────────────────────────\n if (isAsync) {\n // Async: seed with a sync pass so `current` isn't empty while the async pass runs.\n processed = runSyncPipeline();\n void runAsyncPipeline();\n } else {\n recompute();\n }\n\n const source: LocalSource<T> = {\n get current() {\n const start = (page - 1) * limit;\n\n return processed.slice(start, start + limit);\n },\n\n get disposalSignal() {\n return core.disposalSignal;\n },\n\n dispose() {\n if (core.isDisposed) return;\n\n core.cancelTimer();\n asyncController?.abort();\n asyncController = null;\n resolvePendingSearch();\n core.dispose();\n },\n\n get disposed() {\n return core.isDisposed;\n },\n\n goTo(n) {\n const pages = pageCount(processed.length, limit);\n const clamped = clampPage(n, pages);\n\n if (clamped === page) return Promise.resolve();\n\n page = clamped;\n commit();\n\n return Promise.resolve();\n },\n\n goToLast() {\n return source.goTo(pageCount(processed.length, limit));\n },\n\n get meta() {\n return createMeta({\n error,\n isLoading,\n isSearchPending,\n pageNumber: page,\n pageSize: limit,\n totalItems: processed.length,\n });\n },\n\n next() {\n return source.goTo(page + 1);\n },\n\n patch(changes: LocalSourceQuery<T>) {\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 if ('filter' in changes) {\n filter = changes.filter;\n changed = true;\n }\n\n if ('sort' in changes) {\n sort = changes.sort;\n changed = true;\n }\n\n // `|| 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 || core.isScheduled)) {\n search = changes.search ?? '';\n changed = true;\n }\n\n if (changes.page !== undefined) {\n const next = clampPage(changes.page, pageCount(processed.length, limit));\n\n if (next !== page) {\n page = next;\n changed = true;\n }\n }\n\n if (!changed) return Promise.resolve();\n\n // patch() is documented as a single atomic recompute — cancel any debounced search()\n // still pending so it doesn't fire a second, redundant recompute afterwards.\n core.cancelTimer();\n resolvePendingSearch();\n\n // Reset page only when non-page query fields changed without an explicit page\n if (\n (changes.limit !== undefined || 'filter' in changes || 'sort' in changes || 'search' in changes) &&\n changes.page === undefined\n ) {\n page = 1;\n }\n\n return flushInternal();\n },\n\n prev() {\n return source.goTo(page - 1);\n },\n\n get query(): SourceQuery {\n return {\n limit,\n page,\n ...(search && { search }),\n };\n },\n\n ready(timeout?: number) {\n return core.ready(() => !isLoading && !core.isScheduled, timeout);\n },\n\n reset() {\n core.cancelTimer();\n isSearchPending = false;\n search = '';\n filter = cfg.filter;\n sort = cfg.sort;\n page = 1;\n resolvePendingSearch();\n\n return flushInternal();\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 recompute already happened.\n if (q === search && !core.isScheduled) return Promise.resolve();\n\n core.cancelTimer();\n isSearchPending = false;\n search = q;\n page = 1;\n resolvePendingSearch();\n\n return flushInternal();\n }\n\n if (q === search) return Promise.resolve();\n\n // Cancel any previous pending search promise\n resolvePendingSearch();\n\n search = q;\n page = 1;\n isSearchPending = true;\n commit();\n\n let resolveSearch!: () => void;\n const promise = new Promise<void>((res) => {\n resolveSearch = res;\n });\n\n pendingSearch = { promise, resolve: resolveSearch };\n\n core.schedule(() => {\n isSearchPending = false;\n void flushInternal();\n }, debounceMs);\n\n return promise;\n },\n\n setData(d) {\n allData = d;\n page = 1;\n\n return flushInternal();\n },\n\n subscribe(listener) {\n return core.subscribe(listener);\n },\n\n [Symbol.dispose]() {\n source.dispose();\n },\n };\n\n return source;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"localSource.cjs","names":[],"sources":["../src/localSource.ts"],"sourcesContent":["import type { LocalSource, LocalSourceConfig, LocalSourceQuery, SearchOptions, SourceQuery } from './types';\n\nimport { clampPositiveInt, extractError } from './_utils';\nimport { createAsyncSearchCoordinator } from './asyncSearch';\nimport { createSourceCore } from './core';\nimport { SourcererError } from './errors';\nimport { clampPage, createMeta, pageCount } from './pagination';\n\nconst DEFAULT_LIMIT = 20;\nconst DEFAULT_DEBOUNCE_MS = 300;\n\nfunction defaultSearch<T>(items: readonly T[], query: string): readonly T[] {\n const q = query.toLowerCase();\n\n return items.filter((item) => JSON.stringify(item).toLowerCase().includes(q));\n}\n\n/**\n * Creates an in-memory paginated source with optional async filter/sort pipelines.\n *\n * When neither `filterAsync` nor `sortAsync` are configured, all operations\n * complete synchronously — there is no loading state and `ready()` resolves immediately.\n * Provide async ops to offload heavy computation (e.g. to a Web Worker).\n *\n * @example\n * ```ts\n * // Synchronous (common case)\n * const source = createLocalSource([1, 2, 3, 4, 5], { limit: 2 });\n * await source.goTo(2);\n * console.log(source.current); // [3, 4]\n *\n * // Async pipeline (Web Worker offloading)\n * const source = createLocalSource(users, {\n * filterAsync: (items, signal) => myWorker.filter(items, signal),\n * sortAsync: (items, signal) => myWorker.sort(items, signal),\n * });\n * ```\n */\nexport function createLocalSource<T>(data: readonly T[], cfg: LocalSourceConfig<T> = {}): LocalSource<T> {\n const core = createSourceCore();\n const isAsync = cfg.filterAsync !== undefined || cfg.sortAsync !== undefined;\n const debounceMs = cfg.debounceMs ?? DEFAULT_DEBOUNCE_MS;\n\n let allData: readonly T[] = cfg.initialData ?? data;\n let search = '';\n let filter = cfg.filter;\n let sort = cfg.sort;\n let limit = clampPositiveInt(cfg.limit ?? DEFAULT_LIMIT, 'createLocalSource', 'limit');\n let page = 1;\n let processed: readonly T[] = [];\n let isLoading = false;\n let isSearchPending = false;\n let error: SourcererError | null = null;\n let asyncController: AbortController | null = null;\n\n const commit = () => core.notify();\n // Shared debounced-search promise coordinator — the same one remote/cursor/infinite use,\n // instead of a fourth hand-rolled copy of \"pendingSearch/resolvePendingSearch\" bookkeeping.\n const searchCoordinator = createAsyncSearchCoordinator(core, commit);\n\n // ── Sync pipeline (used when no async ops) ──────────────────────────────────\n const runSyncPipeline = (): readonly T[] => {\n let result: readonly T[] = allData;\n\n if (search) result = (cfg.searchFn ?? defaultSearch)(result, search);\n\n if (filter) result = result.filter(filter);\n\n if (sort) result = [...result].sort(sort);\n\n return result;\n };\n\n const recompute = () => {\n processed = runSyncPipeline();\n\n const pages = pageCount(processed.length, limit);\n\n page = clampPage(page, pages);\n };\n\n // ── Async pipeline ──────────────────────────────────────────────────────────\n const runAsyncPipeline = async (): Promise<void> => {\n asyncController?.abort();\n\n const controller = new AbortController();\n\n asyncController = controller;\n isLoading = true;\n error = null;\n commit();\n\n try {\n let result: readonly T[] = allData;\n\n if (search) result = (cfg.searchFn ?? defaultSearch)(result, search);\n\n if (filter) result = result.filter(filter);\n\n if (cfg.filterAsync && !controller.signal.aborted) {\n result = await cfg.filterAsync(result, controller.signal);\n }\n\n if (sort) result = [...result].sort(sort);\n\n if (cfg.sortAsync && !controller.signal.aborted) {\n result = await cfg.sortAsync(result, controller.signal);\n }\n\n if (controller.signal.aborted) return;\n\n processed = result;\n isLoading = false;\n isSearchPending = false;\n\n const pages = pageCount(processed.length, limit);\n\n page = clampPage(page, pages);\n } catch (reason: unknown) {\n if (!controller.signal.aborted) {\n isLoading = false;\n isSearchPending = false;\n error = new SourcererError(extractError(reason), { cause: reason });\n }\n } finally {\n if (asyncController === controller) asyncController = null;\n }\n\n commit();\n // Local source never has more than one pipeline run in flight — settling always means idle.\n searchCoordinator.settleIfIdle(0);\n };\n\n // Internal flush — not part of public API\n const flushInternal = (): Promise<void> => {\n if (isAsync) return runAsyncPipeline();\n\n isSearchPending = false;\n recompute();\n commit();\n searchCoordinator.settleIfIdle(0);\n\n return Promise.resolve();\n };\n\n // ── Initial state ───────────────────────────────────────────────────────────\n if (isAsync) {\n // Async: seed with a sync pass so `current` isn't empty while the async pass runs.\n processed = runSyncPipeline();\n void runAsyncPipeline();\n } else {\n recompute();\n }\n\n const source: LocalSource<T> = {\n get current() {\n const start = (page - 1) * limit;\n\n return processed.slice(start, start + limit);\n },\n\n get disposalSignal() {\n return core.disposalSignal;\n },\n\n dispose() {\n if (core.isDisposed) return;\n\n asyncController?.abort();\n asyncController = null;\n searchCoordinator.cancel();\n searchCoordinator.dispose();\n core.dispose();\n },\n\n get disposed() {\n return core.isDisposed;\n },\n\n goTo(n) {\n const pages = pageCount(processed.length, limit);\n const clamped = clampPage(n, pages);\n\n if (clamped === page) return Promise.resolve();\n\n page = clamped;\n commit();\n\n return Promise.resolve();\n },\n\n goToLast() {\n return source.goTo(pageCount(processed.length, limit));\n },\n\n get meta() {\n return createMeta({\n error,\n isLoading,\n isSearchPending,\n pageNumber: page,\n pageSize: limit,\n totalItems: processed.length,\n });\n },\n\n next() {\n return source.goTo(page + 1);\n },\n\n patch(changes: LocalSourceQuery<T>) {\n let changed = false;\n\n if (changes.limit !== undefined) {\n const next = clampPositiveInt(changes.limit, 'source.patch', 'limit');\n\n if (next !== limit) {\n limit = next;\n changed = true;\n }\n }\n\n if ('filter' in changes) {\n filter = changes.filter;\n changed = true;\n }\n\n if ('sort' in changes) {\n sort = changes.sort;\n changed = true;\n }\n\n // `|| 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 || core.isScheduled)) {\n search = changes.search ?? '';\n changed = true;\n }\n\n if (changes.page !== undefined) {\n const next = clampPage(changes.page, pageCount(processed.length, limit));\n\n if (next !== page) {\n page = next;\n changed = true;\n }\n }\n\n if (!changed) return Promise.resolve();\n\n // patch() is documented as a single atomic recompute — cancel any debounced search()\n // still pending so it doesn't fire a second, redundant recompute afterwards.\n searchCoordinator.cancel();\n\n // Reset page only when non-page query fields changed without an explicit page\n if (\n (changes.limit !== undefined || 'filter' in changes || 'sort' in changes || 'search' in changes) &&\n changes.page === undefined\n ) {\n page = 1;\n }\n\n return flushInternal();\n },\n\n prev() {\n return source.goTo(page - 1);\n },\n\n get query(): SourceQuery {\n return {\n limit,\n page,\n ...(search && { search }),\n };\n },\n\n ready(timeout?: number) {\n return core.ready(() => !isLoading && !core.isScheduled, timeout);\n },\n\n reset() {\n searchCoordinator.cancel();\n isSearchPending = false;\n search = '';\n filter = cfg.filter;\n sort = cfg.sort;\n page = 1;\n\n return flushInternal();\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 recompute already happened.\n if (q === search && !core.isScheduled) return Promise.resolve();\n\n searchCoordinator.cancel();\n isSearchPending = false;\n search = q;\n page = 1;\n\n return flushInternal();\n }\n\n if (q === search) return Promise.resolve();\n\n search = q;\n page = 1;\n isSearchPending = true;\n\n return searchCoordinator.schedule(() => {\n isSearchPending = false;\n void flushInternal();\n }, debounceMs);\n },\n\n setData(d) {\n allData = d;\n page = 1;\n\n return flushInternal();\n },\n\n subscribe(listener) {\n return core.subscribe(listener);\n },\n\n [Symbol.dispose]() {\n source.dispose();\n },\n };\n\n return source;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"localSource.d.ts","sourceRoot":"","sources":["../src/localSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAgD,MAAM,SAAS,CAAC;AAkB5G;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE,EAAE,GAAG,GAAE,iBAAiB,CAAC,CAAC,CAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CA6TvG"}
1
+ {"version":3,"file":"localSource.d.ts","sourceRoot":"","sources":["../src/localSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAgD,MAAM,SAAS,CAAC;AAiB5G;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE,EAAE,GAAG,GAAE,iBAAiB,CAAC,CAAC,CAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAySvG"}