@vielzeug/sourcerer 1.0.6 → 2.0.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 (152) hide show
  1. package/README.md +19 -74
  2. package/dist/_dev.cjs +2 -0
  3. package/dist/_dev.cjs.map +1 -0
  4. package/dist/_dev.d.ts +2 -0
  5. package/dist/_dev.d.ts.map +1 -0
  6. package/dist/_dev.js +6 -0
  7. package/dist/_dev.js.map +1 -0
  8. package/dist/asyncSource.cjs +1 -1
  9. package/dist/asyncSource.cjs.map +1 -1
  10. package/dist/asyncSource.d.ts +14 -58
  11. package/dist/asyncSource.d.ts.map +1 -1
  12. package/dist/asyncSource.js +28 -27
  13. package/dist/asyncSource.js.map +1 -1
  14. package/dist/cursorSource.cjs +1 -1
  15. package/dist/cursorSource.cjs.map +1 -1
  16. package/dist/cursorSource.d.ts +3 -3
  17. package/dist/cursorSource.d.ts.map +1 -1
  18. package/dist/cursorSource.js +77 -110
  19. package/dist/cursorSource.js.map +1 -1
  20. package/dist/devtools.cjs +2 -0
  21. package/dist/devtools.cjs.map +1 -0
  22. package/dist/devtools.d.ts +6 -0
  23. package/dist/devtools.d.ts.map +1 -0
  24. package/dist/devtools.js +8 -0
  25. package/dist/devtools.js.map +1 -0
  26. package/dist/index.cjs +1 -1
  27. package/dist/index.d.ts +2 -12
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +5 -14
  30. package/dist/infiniteSource.cjs +1 -1
  31. package/dist/infiniteSource.cjs.map +1 -1
  32. package/dist/infiniteSource.d.ts +3 -3
  33. package/dist/infiniteSource.d.ts.map +1 -1
  34. package/dist/infiniteSource.js +72 -107
  35. package/dist/infiniteSource.js.map +1 -1
  36. package/dist/localSource.cjs +1 -1
  37. package/dist/localSource.cjs.map +1 -1
  38. package/dist/localSource.d.ts +2 -22
  39. package/dist/localSource.d.ts.map +1 -1
  40. package/dist/localSource.js +58 -114
  41. package/dist/localSource.js.map +1 -1
  42. package/dist/pageSource.cjs +2 -0
  43. package/dist/pageSource.cjs.map +1 -0
  44. package/dist/pageSource.d.ts +4 -0
  45. package/dist/pageSource.d.ts.map +1 -0
  46. package/dist/pageSource.js +96 -0
  47. package/dist/pageSource.js.map +1 -0
  48. package/dist/pagination.cjs +1 -1
  49. package/dist/pagination.cjs.map +1 -1
  50. package/dist/pagination.d.ts +5 -30
  51. package/dist/pagination.d.ts.map +1 -1
  52. package/dist/pagination.js +21 -27
  53. package/dist/pagination.js.map +1 -1
  54. package/dist/requestController.cjs +2 -0
  55. package/dist/requestController.cjs.map +1 -0
  56. package/dist/requestController.d.ts +13 -0
  57. package/dist/requestController.d.ts.map +1 -0
  58. package/dist/requestController.js +29 -0
  59. package/dist/requestController.js.map +1 -0
  60. package/dist/sourceStore.cjs +2 -0
  61. package/dist/sourceStore.cjs.map +1 -0
  62. package/dist/sourceStore.d.ts +10 -0
  63. package/dist/sourceStore.d.ts.map +1 -0
  64. package/dist/sourceStore.js +38 -0
  65. package/dist/sourceStore.js.map +1 -0
  66. package/dist/sourcerer.cjs +1 -1
  67. package/dist/sourcerer.cjs.map +1 -1
  68. package/dist/sourcerer.iife.js +1 -1
  69. package/dist/sourcerer.iife.js.map +1 -1
  70. package/dist/sourcerer.js +1 -1
  71. package/dist/sourcerer.js.map +1 -1
  72. package/dist/types.d.ts +128 -345
  73. package/dist/types.d.ts.map +1 -1
  74. package/package.json +10 -7
  75. package/dist/_utils.cjs +0 -2
  76. package/dist/_utils.cjs.map +0 -1
  77. package/dist/_utils.d.ts +0 -8
  78. package/dist/_utils.d.ts.map +0 -1
  79. package/dist/_utils.js +0 -7
  80. package/dist/_utils.js.map +0 -1
  81. package/dist/applyQuery.cjs +0 -2
  82. package/dist/applyQuery.cjs.map +0 -1
  83. package/dist/applyQuery.d.ts +0 -20
  84. package/dist/applyQuery.d.ts.map +0 -1
  85. package/dist/applyQuery.js +0 -8
  86. package/dist/applyQuery.js.map +0 -1
  87. package/dist/asyncSearch.cjs +0 -2
  88. package/dist/asyncSearch.cjs.map +0 -1
  89. package/dist/asyncSearch.d.ts +0 -13
  90. package/dist/asyncSearch.d.ts.map +0 -1
  91. package/dist/asyncSearch.js +0 -28
  92. package/dist/asyncSearch.js.map +0 -1
  93. package/dist/codecs.cjs +0 -2
  94. package/dist/codecs.cjs.map +0 -1
  95. package/dist/codecs.d.ts +0 -30
  96. package/dist/codecs.d.ts.map +0 -1
  97. package/dist/codecs.js +0 -36
  98. package/dist/codecs.js.map +0 -1
  99. package/dist/core.cjs +0 -2
  100. package/dist/core.cjs.map +0 -1
  101. package/dist/core.d.ts +0 -47
  102. package/dist/core.d.ts.map +0 -1
  103. package/dist/core.js +0 -59
  104. package/dist/core.js.map +0 -1
  105. package/dist/derive.cjs +0 -2
  106. package/dist/derive.cjs.map +0 -1
  107. package/dist/derive.d.ts +0 -28
  108. package/dist/derive.d.ts.map +0 -1
  109. package/dist/derive.js +0 -40
  110. package/dist/derive.js.map +0 -1
  111. package/dist/errors.cjs +0 -2
  112. package/dist/errors.cjs.map +0 -1
  113. package/dist/errors.d.ts +0 -62
  114. package/dist/errors.d.ts.map +0 -1
  115. package/dist/errors.js +0 -29
  116. package/dist/errors.js.map +0 -1
  117. package/dist/fetchManager.cjs +0 -2
  118. package/dist/fetchManager.cjs.map +0 -1
  119. package/dist/fetchManager.d.ts +0 -27
  120. package/dist/fetchManager.d.ts.map +0 -1
  121. package/dist/fetchManager.js +0 -41
  122. package/dist/fetchManager.js.map +0 -1
  123. package/dist/merge.cjs +0 -2
  124. package/dist/merge.cjs.map +0 -1
  125. package/dist/merge.d.ts +0 -30
  126. package/dist/merge.d.ts.map +0 -1
  127. package/dist/merge.js +0 -34
  128. package/dist/merge.js.map +0 -1
  129. package/dist/prefetch.cjs +0 -2
  130. package/dist/prefetch.cjs.map +0 -1
  131. package/dist/prefetch.d.ts +0 -32
  132. package/dist/prefetch.d.ts.map +0 -1
  133. package/dist/prefetch.js +0 -38
  134. package/dist/prefetch.js.map +0 -1
  135. package/dist/presets.cjs +0 -2
  136. package/dist/presets.cjs.map +0 -1
  137. package/dist/presets.d.ts +0 -17
  138. package/dist/presets.d.ts.map +0 -1
  139. package/dist/presets.js +0 -43
  140. package/dist/presets.js.map +0 -1
  141. package/dist/remoteSource.cjs +0 -2
  142. package/dist/remoteSource.cjs.map +0 -1
  143. package/dist/remoteSource.d.ts +0 -4
  144. package/dist/remoteSource.d.ts.map +0 -1
  145. package/dist/remoteSource.js +0 -165
  146. package/dist/remoteSource.js.map +0 -1
  147. package/dist/state.cjs +0 -2
  148. package/dist/state.cjs.map +0 -1
  149. package/dist/state.d.ts +0 -23
  150. package/dist/state.d.ts.map +0 -1
  151. package/dist/state.js +0 -14
  152. package/dist/state.js.map +0 -1
@@ -1,125 +1,92 @@
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 { warn as e } from "./_dev.js";
2
+ import { createAsyncSource as t } from "./asyncSource.js";
3
+ import { positiveInteger as n, sameQuery as r, totalItems as i } from "./pagination.js";
5
4
  //#region src/cursorSource.ts
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 = {
5
+ var a = (e) => ({
6
+ hasNext: e?.nextCursor !== void 0,
7
+ hasPrevious: e?.previousCursor !== void 0,
8
+ kind: "cursor",
9
+ ...e?.nextCursor !== void 0 && { nextCursor: e.nextCursor },
10
+ ...e?.previousCursor !== void 0 && { previousCursor: e.previousCursor },
11
+ ...e?.total !== void 0 && { total: i(e.total) }
12
+ }), o = (e, t = {}) => {
13
+ if (t.after !== void 0 && t.before !== void 0) throw RangeError("Cursor query cannot include both after and before");
14
+ let r = t.pageSize !== void 0 || t.search !== void 0, i = r || "before" in t ? void 0 : "after" in t ? t.after : e.after, a = r || "after" in t ? void 0 : "before" in t ? t.before : e.before;
15
+ return {
16
+ ...i !== void 0 && { after: i },
17
+ ...a !== void 0 && { before: a },
18
+ pageSize: n(t.pageSize ?? e.pageSize, "pageSize"),
19
+ search: t.search ?? e.search
20
+ };
21
+ };
22
+ function s(n) {
23
+ let i = o({
24
+ pageSize: 20,
25
+ search: ""
26
+ }, n.initialQuery), s = t({
27
+ data: [],
8
28
  error: null,
9
- hasNextPage: !1,
10
- hasPrevPage: !1,
11
- isLoading: !1,
12
- isSearchPending: !1,
13
- pageSize: c,
14
- totalItems: 0
15
- }, y = () => {
16
- _ = m, v = {
17
- error: g,
18
- hasNextPage: f !== void 0,
19
- hasPrevPage: p !== void 0,
20
- isLoading: b.pendingCount() > 0,
21
- isSearchPending: b.core.isScheduled,
22
- pageSize: c,
23
- totalItems: h
24
- };
25
- }, b = a(o, s, y), { autoFetch: x, debounceMs: S, retryAttempts: C, retryDelay: w } = b;
26
- y();
27
- let T = () => {
28
- b.disposed || b.core.notify();
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) => {
35
- let s = Date.now();
36
- try {
37
- let e = await r((e) => o.fetch(t, e), {
38
- delay: w,
39
- signal: i,
40
- times: C + 1
41
- });
42
- a() && (m = e.items, h = e.total ?? e.items.length, f = e.nextCursor, p = e.prevCursor, g = null, o.onFetch?.({
43
- durationMs: Date.now() - s,
44
- query: t,
45
- status: "success"
46
- }));
47
- } catch (r) {
48
- if (i.aborted) return;
49
- a() && (m = [], h = 0, f = void 0, p = void 0, g = new e(n(r), {
50
- cause: r,
51
- context: {
52
- kind: "cursor",
53
- limit: t.limit,
54
- ...t.search && { search: t.search }
55
- }
56
- }), o.onFetch?.({
57
- durationMs: Date.now() - s,
58
- error: g,
59
- query: t,
60
- status: "error"
61
- }));
62
- }
63
- }, () => {
64
- T(), E.settleIfIdle(b.pendingCount());
65
- })), k = () => O(D());
66
- return x && k(), b.startRefreshInterval(() => void k()), {
67
- get current() {
68
- return _;
69
- },
29
+ isFetching: !1,
30
+ pagination: a(),
31
+ query: i
32
+ }), c = (e) => s.fetch({
33
+ failure: (e, t) => ({
34
+ ...e,
35
+ error: t,
36
+ isFetching: !1,
37
+ pendingQuery: void 0
38
+ }),
39
+ load: (t) => n.load({
40
+ query: e,
41
+ signal: t
42
+ }),
43
+ pending: (t) => ({
44
+ ...t,
45
+ error: null,
46
+ isFetching: !0,
47
+ pendingQuery: e
48
+ }),
49
+ success: (t) => ({
50
+ data: t.data,
51
+ error: null,
52
+ isFetching: !1,
53
+ pagination: a(t),
54
+ query: e
55
+ })
56
+ }), l = () => c(i), u = async (e) => {
57
+ let t = o(s.snapshot.pendingQuery ?? s.snapshot.query, e);
58
+ r(t, i) || (i = t, await c(t));
59
+ }, d = {
70
60
  get disposalSignal() {
71
- return b.disposalSignal;
72
- },
73
- dispose: () => {
74
- E.cancel(), E.dispose(), b.dispose();
61
+ return s.disposalSignal;
75
62
  },
63
+ dispose: s.dispose,
76
64
  get disposed() {
77
- return b.disposed;
78
- },
79
- get meta() {
80
- return v;
81
- },
82
- next() {
83
- return f ? (u = f, d = void 0, k()) : Promise.resolve();
65
+ return s.disposed;
84
66
  },
85
- patch(e) {
86
- let t = !1;
87
- if (e.limit !== void 0) {
88
- let n = Math.max(1, Math.trunc(e.limit));
89
- n !== c && (c = n, u = void 0, d = void 0, t = !0);
67
+ page: {
68
+ next() {
69
+ let e = s.snapshot.pagination.nextCursor;
70
+ return s.snapshot.isFetching || e === void 0 ? Promise.resolve() : u({ after: e });
71
+ },
72
+ previous() {
73
+ let e = s.snapshot.pagination.previousCursor;
74
+ return s.snapshot.isFetching || e === void 0 ? Promise.resolve() : u({ before: e });
90
75
  }
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();
92
- },
93
- prev() {
94
- return p ? (d = p, u = void 0, k()) : Promise.resolve();
95
- },
96
- get query() {
97
- return {
98
- ...u !== void 0 && { after: u },
99
- ...d !== void 0 && { before: d },
100
- ...l && { search: l },
101
- limit: c
102
- };
103
- },
104
- ready(e) {
105
- return b.ready(e);
106
- },
107
- refresh() {
108
- return k();
109
- },
110
- reset() {
111
- return E.cancel(), l = "", u = void 0, d = void 0, k();
112
76
  },
113
- search(e, t) {
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));
77
+ reload: l,
78
+ setQuery: u,
79
+ get snapshot() {
80
+ return s.snapshot;
115
81
  },
116
- subscribe: (e) => b.core.subscribe(e),
117
- [Symbol.dispose]: () => {
118
- E.cancel(), E.dispose(), b.dispose();
82
+ subscribe: s.subscribe,
83
+ [Symbol.dispose]() {
84
+ d.dispose();
119
85
  }
120
86
  };
87
+ return n.autoStart !== !1 && l().catch(() => /* @__PURE__ */ e("Initial load failed. Inspect source.snapshot.error.")), d;
121
88
  }
122
89
  //#endregion
123
- export { o as createCursorSource };
90
+ export { s as createCursorSource };
124
91
 
125
92
  //# sourceMappingURL=cursorSource.js.map
@@ -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 { 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
+ {"version":3,"file":"cursorSource.js","names":[],"sources":["../src/cursorSource.ts"],"sourcesContent":["import type { CursorPagination, CursorQuery, CursorQueryPatch, CursorSource, CursorSourceConfig } from './types';\n\nimport { warn } from './_dev';\nimport { createAsyncSource } from './asyncSource';\nimport { positiveInteger, sameQuery, totalItems } from './pagination';\n\nconst createPagination = <TCursor>(result?: {\n nextCursor?: TCursor;\n previousCursor?: TCursor;\n total?: number;\n}): CursorPagination<TCursor> => ({\n hasNext: result?.nextCursor !== undefined,\n hasPrevious: result?.previousCursor !== undefined,\n kind: 'cursor',\n ...(result?.nextCursor !== undefined && { nextCursor: result.nextCursor }),\n ...(result?.previousCursor !== undefined && { previousCursor: result.previousCursor }),\n ...(result?.total !== undefined && { total: totalItems(result.total) }),\n});\n\nconst normalizeQuery = <TCursor>(\n current: CursorQuery<TCursor>,\n patch: CursorQueryPatch<TCursor> = {},\n): CursorQuery<TCursor> => {\n if (patch.after !== undefined && patch.before !== undefined) {\n throw new RangeError('Cursor query cannot include both after and before');\n }\n\n const resetsCursor = patch.pageSize !== undefined || patch.search !== undefined;\n const after = resetsCursor || 'before' in patch ? undefined : 'after' in patch ? patch.after : current.after;\n const before = resetsCursor || 'after' in patch ? undefined : 'before' in patch ? patch.before : current.before;\n\n return {\n ...(after !== undefined && { after }),\n ...(before !== undefined && { before }),\n pageSize: positiveInteger(patch.pageSize ?? current.pageSize, 'pageSize'),\n search: patch.search ?? current.search,\n };\n};\n\n/** Cursor sources retain loaded cursors while pendingQuery records newer navigation. */\nexport function createCursorSource<T, TCursor = string>(\n config: CursorSourceConfig<T, TCursor>,\n): CursorSource<T, TCursor> {\n const initialQuery: CursorQuery<TCursor> = { pageSize: 20, search: '' };\n let requestedQuery = normalizeQuery(initialQuery, config.initialQuery);\n const asyncSource = createAsyncSource<T, CursorQuery<TCursor>, CursorPagination<TCursor>>({\n data: [],\n error: null,\n isFetching: false,\n pagination: createPagination(),\n query: requestedQuery,\n });\n\n const fetch = (query: CursorQuery<TCursor>): Promise<void> =>\n asyncSource.fetch({\n failure: (previous, error) => ({ ...previous, error, isFetching: false, pendingQuery: undefined }),\n load: (signal) => config.load({ query, signal }),\n pending: (previous) => ({ ...previous, error: null, isFetching: true, pendingQuery: query }),\n success: (result) => ({\n data: result.data,\n error: null,\n isFetching: false,\n pagination: createPagination(result),\n query,\n }),\n });\n\n const reload = (): Promise<void> => fetch(requestedQuery);\n\n const setQuery = async (patch: CursorQueryPatch<TCursor>): Promise<void> => {\n const current = asyncSource.snapshot.pendingQuery ?? asyncSource.snapshot.query;\n const next = normalizeQuery(current, patch);\n\n if (sameQuery(next, requestedQuery)) return;\n\n requestedQuery = next;\n await fetch(next);\n };\n\n const source: CursorSource<T, TCursor> = {\n get disposalSignal() {\n return asyncSource.disposalSignal;\n },\n\n dispose: asyncSource.dispose,\n\n get disposed() {\n return asyncSource.disposed;\n },\n\n page: {\n next() {\n const cursor = asyncSource.snapshot.pagination.nextCursor;\n\n return asyncSource.snapshot.isFetching || cursor === undefined\n ? Promise.resolve()\n : setQuery({ after: cursor });\n },\n\n previous() {\n const cursor = asyncSource.snapshot.pagination.previousCursor;\n\n return asyncSource.snapshot.isFetching || cursor === undefined\n ? Promise.resolve()\n : setQuery({ before: cursor });\n },\n },\n\n reload,\n setQuery,\n\n get snapshot() {\n return asyncSource.snapshot;\n },\n\n subscribe: asyncSource.subscribe,\n\n [Symbol.dispose]() {\n source.dispose();\n },\n };\n\n if (config.autoStart !== false)\n void reload().catch(() => warn('Initial load failed. Inspect source.snapshot.error.'));\n\n return source;\n}\n"],"mappings":";;;;AAMA,IAAM,KAA6B,OAID;CAChC,SAAS,GAAQ,eAAe,KAAA;CAChC,aAAa,GAAQ,mBAAmB,KAAA;CACxC,MAAM;CACN,GAAI,GAAQ,eAAe,KAAA,KAAa,EAAE,YAAY,EAAO,WAAW;CACxE,GAAI,GAAQ,mBAAmB,KAAA,KAAa,EAAE,gBAAgB,EAAO,eAAe;CACpF,GAAI,GAAQ,UAAU,KAAA,KAAa,EAAE,OAAO,EAAW,EAAO,KAAK,EAAE;AACvE,IAEM,KACJ,GACA,IAAmC,CAAC,MACX;CACzB,IAAI,EAAM,UAAU,KAAA,KAAa,EAAM,WAAW,KAAA,GAChD,MAAU,WAAW,mDAAmD;CAG1E,IAAM,IAAe,EAAM,aAAa,KAAA,KAAa,EAAM,WAAW,KAAA,GAChE,IAAQ,KAAgB,YAAY,IAAQ,KAAA,IAAY,WAAW,IAAQ,EAAM,QAAQ,EAAQ,OACjG,IAAS,KAAgB,WAAW,IAAQ,KAAA,IAAY,YAAY,IAAQ,EAAM,SAAS,EAAQ;CAEzG,OAAO;EACL,GAAI,MAAU,KAAA,KAAa,EAAE,SAAM;EACnC,GAAI,MAAW,KAAA,KAAa,EAAE,UAAO;EACrC,UAAU,EAAgB,EAAM,YAAY,EAAQ,UAAU,UAAU;EACxE,QAAQ,EAAM,UAAU,EAAQ;CAClC;AACF;AAGA,SAAgB,EACd,GAC0B;CAE1B,IAAI,IAAiB,EAAe;EADS,UAAU;EAAI,QAAQ;CAC/B,GAAc,EAAO,YAAY,GAC/D,IAAc,EAAsE;EACxF,MAAM,CAAC;EACP,OAAO;EACP,YAAY;EACZ,YAAY,EAAiB;EAC7B,OAAO;CACT,CAAC,GAEK,KAAS,MACb,EAAY,MAAM;EAChB,UAAU,GAAU,OAAW;GAAE,GAAG;GAAU;GAAO,YAAY;GAAO,cAAc,KAAA;EAAU;EAChG,OAAO,MAAW,EAAO,KAAK;GAAE;GAAO;EAAO,CAAC;EAC/C,UAAU,OAAc;GAAE,GAAG;GAAU,OAAO;GAAM,YAAY;GAAM,cAAc;EAAM;EAC1F,UAAU,OAAY;GACpB,MAAM,EAAO;GACb,OAAO;GACP,YAAY;GACZ,YAAY,EAAiB,CAAM;GACnC;EACF;CACF,CAAC,GAEG,UAA8B,EAAM,CAAc,GAElD,IAAW,OAAO,MAAoD;EAE1E,IAAM,IAAO,EADG,EAAY,SAAS,gBAAgB,EAAY,SAAS,OACrC,CAAK;EAEtC,EAAU,GAAM,CAAc,MAElC,IAAiB,GACjB,MAAM,EAAM,CAAI;CAClB,GAEM,IAAmC;EACvC,IAAI,iBAAiB;GACnB,OAAO,EAAY;EACrB;EAEA,SAAS,EAAY;EAErB,IAAI,WAAW;GACb,OAAO,EAAY;EACrB;EAEA,MAAM;GACJ,OAAO;IACL,IAAM,IAAS,EAAY,SAAS,WAAW;IAE/C,OAAO,EAAY,SAAS,cAAc,MAAW,KAAA,IACjD,QAAQ,QAAQ,IAChB,EAAS,EAAE,OAAO,EAAO,CAAC;GAChC;GAEA,WAAW;IACT,IAAM,IAAS,EAAY,SAAS,WAAW;IAE/C,OAAO,EAAY,SAAS,cAAc,MAAW,KAAA,IACjD,QAAQ,QAAQ,IAChB,EAAS,EAAE,QAAQ,EAAO,CAAC;GACjC;EACF;EAEA;EACA;EAEA,IAAI,WAAW;GACb,OAAO,EAAY;EACrB;EAEA,WAAW,EAAY;EAEvB,CAAC,OAAO,WAAW;GACjB,EAAO,QAAQ;EACjB;CACF;CAKA,OAHI,EAAO,cAAc,MACvB,EAAY,CAAC,CAAC,YAAY,kBAAK,qDAAqD,CAAC,GAEhF;AACT"}
@@ -0,0 +1,2 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(e,t={}){return()=>{}}exports.debugSource=e;
2
+ //# sourceMappingURL=devtools.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devtools.cjs","names":[],"sources":["../src/devtools.ts"],"sourcesContent":["import type { AnyPagination, Source } from './types';\n\nconst isDev = !(globalThis as { __SOURCERER_PROD__?: boolean }).__SOURCERER_PROD__;\n\nexport type SourcererDevtoolsOptions = Readonly<{\n label?: string;\n}>;\n\nexport function debugSource<T, TQuery, TPagination extends AnyPagination>(\n source: Source<T, TQuery, TPagination>,\n options: SourcererDevtoolsOptions = {},\n): () => void {\n if (!isDev) return () => {};\n\n const prefix = `[@vielzeug/sourcerer:${options.label ?? 'source'}]`;\n let previous = source.snapshot;\n\n return source.subscribe((next) => {\n if (previous.isFetching !== next.isFetching)\n console.debug(`${prefix} isFetching:`, previous.isFetching, '→', next.isFetching);\n\n if (previous.data.length !== next.data.length) {\n console.debug(`${prefix} data:`, previous.data.length, '→', next.data.length, 'items');\n }\n\n if (previous.error !== next.error) console.debug(`${prefix} error:`, next.error);\n\n previous = next;\n });\n}\n"],"mappings":"mEAQA,SAAgB,EACd,EACA,EAAoC,CAAC,EACzB,CACA,UAAa,CAAC,CAiB5B"}
@@ -0,0 +1,6 @@
1
+ import type { AnyPagination, Source } from './types';
2
+ export type SourcererDevtoolsOptions = Readonly<{
3
+ label?: string;
4
+ }>;
5
+ export declare function debugSource<T, TQuery, TPagination extends AnyPagination>(source: Source<T, TQuery, TPagination>, options?: SourcererDevtoolsOptions): () => void;
6
+ //# sourceMappingURL=devtools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devtools.d.ts","sourceRoot":"","sources":["../src/devtools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAIrD,MAAM,MAAM,wBAAwB,GAAG,QAAQ,CAAC;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CAAC;AAEH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,SAAS,aAAa,EACtE,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EACtC,OAAO,GAAE,wBAA6B,GACrC,MAAM,IAAI,CAkBZ"}
@@ -0,0 +1,8 @@
1
+ //#region src/devtools.ts
2
+ function e(e, t = {}) {
3
+ return () => {};
4
+ }
5
+ //#endregion
6
+ export { e as debugSource };
7
+
8
+ //# sourceMappingURL=devtools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devtools.js","names":[],"sources":["../src/devtools.ts"],"sourcesContent":["import type { AnyPagination, Source } from './types';\n\nconst isDev = !(globalThis as { __SOURCERER_PROD__?: boolean }).__SOURCERER_PROD__;\n\nexport type SourcererDevtoolsOptions = Readonly<{\n label?: string;\n}>;\n\nexport function debugSource<T, TQuery, TPagination extends AnyPagination>(\n source: Source<T, TQuery, TPagination>,\n options: SourcererDevtoolsOptions = {},\n): () => void {\n if (!isDev) return () => {};\n\n const prefix = `[@vielzeug/sourcerer:${options.label ?? 'source'}]`;\n let previous = source.snapshot;\n\n return source.subscribe((next) => {\n if (previous.isFetching !== next.isFetching)\n console.debug(`${prefix} isFetching:`, previous.isFetching, '→', next.isFetching);\n\n if (previous.data.length !== next.data.length) {\n console.debug(`${prefix} data:`, previous.data.length, '→', next.data.length, 'items');\n }\n\n if (previous.error !== next.error) console.debug(`${prefix} error:`, next.error);\n\n previous = next;\n });\n}\n"],"mappings":";AAQA,SAAgB,EACd,GACA,IAAoC,CAAC,GACzB;CACA,aAAa,CAAC;AAiB5B"}
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.searchBy=d.searchBy,exports.sortBy=d.sortBy,exports.sourceState=f.sourceState;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./cursorSource.cjs"),t=require("./infiniteSource.cjs"),n=require("./localSource.cjs"),r=require("./pageSource.cjs");exports.createCursorSource=e.createCursorSource,exports.createInfiniteSource=t.createInfiniteSource,exports.createLocalSource=n.createLocalSource,exports.createPageSource=r.createPageSource;
package/dist/index.d.ts CHANGED
@@ -1,16 +1,6 @@
1
- export { applyQuery } from './applyQuery';
2
- export { decodeQuery, encodeQuery } from './codecs';
3
- export type { DecodeQueryOptions } from './codecs';
4
1
  export { createCursorSource } from './cursorSource';
5
- export { deriveSource } from './derive';
6
2
  export { createInfiniteSource } from './infiniteSource';
7
3
  export { createLocalSource } from './localSource';
8
- export { mergeSource } from './merge';
9
- export { itemRange } from './pagination';
10
- export { prefetchSource, prefetchSourceAndKeep } from './prefetch';
11
- export { filterContains, filterEquals, filterRange, searchBy, sortBy } from './presets';
12
- export { createRemoteSource } from './remoteSource';
13
- export { sourceState } from './state';
14
- export { SourceDisposedError, SourcererError, SourceTimeoutError } from './errors';
15
- 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';
4
+ export { createPageSource } from './pageSource';
5
+ export type { CursorPagination, CursorQuery, CursorQueryPatch, CursorResult, CursorSource, CursorSourceConfig, InfinitePagination, InfiniteQuery, InfiniteQueryPatch, InfiniteSource, InfiniteSourceConfig, LocalQuery, LocalQueryPatch, LocalSource, LocalSourceConfig, PageLoadContext, PagePagination, PageQuery, PageQueryPatch, PageResult, PageSource, PageSourceConfig, AnyPagination, Predicate, Sorter, Source, SourceSnapshot, } from './types';
16
6
  //# 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,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,YAAY,EACV,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACb,kBAAkB,EAClB,cAAc,EACd,oBAAoB,EACpB,UAAU,EACV,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,SAAS,EACT,cAAc,EACd,UAAU,EACV,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,SAAS,EACT,MAAM,EACN,MAAM,EACN,cAAc,GACf,MAAM,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -1,14 +1,5 @@
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 { createCursorSource as e } from "./cursorSource.js";
2
+ import { createInfiniteSource as t } from "./infiniteSource.js";
3
+ import { createLocalSource as n } from "./localSource.js";
4
+ import { createPageSource as r } from "./pageSource.js";
5
+ export { e as createCursorSource, t as createInfiniteSource, n as createLocalSource, r as createPageSource };
@@ -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("./_dev.cjs"),t=require("./asyncSource.cjs"),n=require("./pagination.cjs");var r=(e,t,n)=>({hasMore:e<t,isLoadingMore:n,kind:`infinite`,loaded:e,total:t}),i=(e,t={})=>({pageSize:n.positiveInteger(t.pageSize??e.pageSize,`pageSize`),search:t.search??e.search});function a(a){let o=i({pageSize:20,search:``},a.initialQuery),s=1,c=t.createAsyncSource({data:[],error:null,isFetching:!1,pagination:r(0,0,!1),query:o}),l=(e,t,i)=>{let o=c.snapshot.data;return c.fetch({failure:(e,t)=>({...e,error:t,isFetching:!1,pendingQuery:void 0}),load:n=>a.load({query:{...e,page:t,pageSize:e.pageSize},signal:n}),pending:t=>({...t,error:null,isFetching:!0,pagination:r(t.data.length,t.pagination.total,i),pendingQuery:e}),success:a=>{let c=n.totalItems(a.total),l=i?[...o,...a.data]:a.data;return s=t+1,{data:l,error:null,isFetching:!1,pagination:r(l.length,c,!1),query:e}}})},u=()=>(s=1,l(o,1,!1)),d={get disposalSignal(){return c.disposalSignal},dispose:c.dispose,get disposed(){return c.disposed},loadMore(){let{isFetching:e,pagination:t}=c.snapshot;return e||c.snapshot.data.length>0&&!t.hasMore?Promise.resolve():l(o,s,!0)},reload:u,setQuery:async e=>{let t=i(c.snapshot.pendingQuery??c.snapshot.query,e);n.sameQuery(t,o)||(o=t,s=1,await l(t,1,!1))},get snapshot(){return c.snapshot},subscribe:c.subscribe,[Symbol.dispose](){d.dispose()}};return a.autoStart!==!1&&u().catch(()=>e.warn(`Initial load failed. Inspect source.snapshot.error.`)),d}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 {\n InfinitePagination,\n InfiniteQuery,\n InfiniteQueryPatch,\n InfiniteSource,\n InfiniteSourceConfig,\n} from './types';\n\nimport { warn } from './_dev';\nimport { createAsyncSource } from './asyncSource';\nimport { positiveInteger, sameQuery, totalItems } from './pagination';\n\nconst createPagination = (loaded: number, total: number, isLoadingMore: boolean): InfinitePagination => ({\n hasMore: loaded < total,\n isLoadingMore,\n kind: 'infinite',\n loaded,\n total,\n});\n\nconst normalizeQuery = (current: InfiniteQuery, patch: InfiniteQueryPatch = {}): InfiniteQuery => ({\n pageSize: positiveInteger(patch.pageSize ?? current.pageSize, 'pageSize'),\n search: patch.search ?? current.search,\n});\n\n/** Infinite sources preserve loaded collection state while a pending query replaces it. */\nexport function createInfiniteSource<T>(config: InfiniteSourceConfig<T>): InfiniteSource<T> {\n const initialQuery: InfiniteQuery = { pageSize: 20, search: '' };\n let requestedQuery = normalizeQuery(initialQuery, config.initialQuery);\n let nextPage = 1;\n const asyncSource = createAsyncSource<T, InfiniteQuery, InfinitePagination>({\n data: [],\n error: null,\n isFetching: false,\n pagination: createPagination(0, 0, false),\n query: requestedQuery,\n });\n\n const fetch = (query: InfiniteQuery, page: number, append: boolean): Promise<void> => {\n const loadedData = asyncSource.snapshot.data;\n\n return asyncSource.fetch({\n failure: (previous, error) => ({ ...previous, error, isFetching: false, pendingQuery: undefined }),\n load: (signal) => config.load({ query: { ...query, page, pageSize: query.pageSize }, signal }),\n pending: (previous) => ({\n ...previous,\n error: null,\n isFetching: true,\n pagination: createPagination(previous.data.length, previous.pagination.total, append),\n pendingQuery: query,\n }),\n success: (result) => {\n const total = totalItems(result.total);\n const data = append ? [...loadedData, ...result.data] : result.data;\n\n nextPage = page + 1;\n\n return {\n data,\n error: null,\n isFetching: false,\n pagination: createPagination(data.length, total, false),\n query,\n };\n },\n });\n };\n\n const reload = (): Promise<void> => {\n nextPage = 1;\n\n return fetch(requestedQuery, 1, false);\n };\n\n const setQuery = async (patch: InfiniteQueryPatch): Promise<void> => {\n const current = asyncSource.snapshot.pendingQuery ?? asyncSource.snapshot.query;\n const next = normalizeQuery(current, patch);\n\n if (sameQuery(next, requestedQuery)) return;\n\n requestedQuery = next;\n nextPage = 1;\n await fetch(next, 1, false);\n };\n\n const source: InfiniteSource<T> = {\n get disposalSignal() {\n return asyncSource.disposalSignal;\n },\n\n dispose: asyncSource.dispose,\n\n get disposed() {\n return asyncSource.disposed;\n },\n\n loadMore() {\n const { isFetching, pagination } = asyncSource.snapshot;\n\n return isFetching || (asyncSource.snapshot.data.length > 0 && !pagination.hasMore)\n ? Promise.resolve()\n : fetch(requestedQuery, nextPage, true);\n },\n\n reload,\n setQuery,\n\n get snapshot() {\n return asyncSource.snapshot;\n },\n\n subscribe: asyncSource.subscribe,\n\n [Symbol.dispose]() {\n source.dispose();\n },\n };\n\n if (config.autoStart !== false)\n void reload().catch(() => warn('Initial load failed. Inspect source.snapshot.error.'));\n\n return source;\n}\n"],"mappings":"2FAYA,IAAM,GAAoB,EAAgB,EAAe,KAAgD,CACvG,QAAS,EAAS,EAClB,gBACA,KAAM,WACN,SACA,OACF,GAEM,GAAkB,EAAwB,EAA4B,CAAC,KAAsB,CACjG,SAAU,EAAA,gBAAgB,EAAM,UAAY,EAAQ,SAAU,UAAU,EACxE,OAAQ,EAAM,QAAU,EAAQ,MAClC,GAGA,SAAgB,EAAwB,EAAoD,CAE1F,IAAI,EAAiB,EAAe,CADE,SAAU,GAAI,OAAQ,EACxB,EAAc,EAAO,YAAY,EACjE,EAAW,EACT,EAAc,EAAA,kBAAwD,CAC1E,KAAM,CAAC,EACP,MAAO,KACP,WAAY,GACZ,WAAY,EAAiB,EAAG,EAAG,EAAK,EACxC,MAAO,CACT,CAAC,EAEK,GAAS,EAAsB,EAAc,IAAmC,CACpF,IAAM,EAAa,EAAY,SAAS,KAExC,OAAO,EAAY,MAAM,CACvB,SAAU,EAAU,KAAW,CAAE,GAAG,EAAU,QAAO,WAAY,GAAO,aAAc,IAAA,EAAU,GAChG,KAAO,GAAW,EAAO,KAAK,CAAE,MAAO,CAAE,GAAG,EAAO,OAAM,SAAU,EAAM,QAAS,EAAG,QAAO,CAAC,EAC7F,QAAU,IAAc,CACtB,GAAG,EACH,MAAO,KACP,WAAY,GACZ,WAAY,EAAiB,EAAS,KAAK,OAAQ,EAAS,WAAW,MAAO,CAAM,EACpF,aAAc,CAChB,GACA,QAAU,GAAW,CACnB,IAAM,EAAQ,EAAA,WAAW,EAAO,KAAK,EAC/B,EAAO,EAAS,CAAC,GAAG,EAAY,GAAG,EAAO,IAAI,EAAI,EAAO,KAI/D,MAFA,GAAW,EAAO,EAEX,CACL,OACA,MAAO,KACP,WAAY,GACZ,WAAY,EAAiB,EAAK,OAAQ,EAAO,EAAK,EACtD,OACF,CACF,CACF,CAAC,CACH,EAEM,OACJ,EAAW,EAEJ,EAAM,EAAgB,EAAG,EAAK,GAcjC,EAA4B,CAChC,IAAI,gBAAiB,CACnB,OAAO,EAAY,cACrB,EAEA,QAAS,EAAY,QAErB,IAAI,UAAW,CACb,OAAO,EAAY,QACrB,EAEA,UAAW,CACT,GAAM,CAAE,aAAY,cAAe,EAAY,SAE/C,OAAO,GAAe,EAAY,SAAS,KAAK,OAAS,GAAK,CAAC,EAAW,QACtE,QAAQ,QAAQ,EAChB,EAAM,EAAgB,EAAU,EAAI,CAC1C,EAEA,SACA,cA/BsB,IAA6C,CAEnE,IAAM,EAAO,EADG,EAAY,SAAS,cAAgB,EAAY,SAAS,MACrC,CAAK,EAEtC,EAAA,UAAU,EAAM,CAAc,IAElC,EAAiB,EACjB,EAAW,EACX,MAAM,EAAM,EAAM,EAAG,EAAK,EAC5B,EAwBE,IAAI,UAAW,CACb,OAAO,EAAY,QACrB,EAEA,UAAW,EAAY,UAEvB,CAAC,OAAO,UAAW,CACjB,EAAO,QAAQ,CACjB,CACF,EAKA,OAHI,EAAO,YAAc,IACvB,EAAY,CAAC,CAAC,UAAY,EAAA,KAAK,qDAAqD,CAAC,EAEhF,CACT"}
@@ -1,4 +1,4 @@
1
- import type { InfiniteConfig, InfiniteSource } from './types';
2
- /** Creates an infinite-scroll source that appends pages on `loadMore()`. */
3
- export declare function createInfiniteSource<T>(cfg: InfiniteConfig<T>): InfiniteSource<T>;
1
+ import type { InfiniteSource, InfiniteSourceConfig } from './types';
2
+ /** Infinite sources preserve loaded collection state while a pending query replaces it. */
3
+ export declare function createInfiniteSource<T>(config: InfiniteSourceConfig<T>): InfiniteSource<T>;
4
4
  //# sourceMappingURL=infiniteSource.d.ts.map
@@ -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;AAOhH,4EAA4E;AAC5E,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAqPjF"}
1
+ {"version":3,"file":"infiniteSource.d.ts","sourceRoot":"","sources":["../src/infiniteSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAIV,cAAc,EACd,oBAAoB,EACrB,MAAM,SAAS,CAAC;AAmBjB,2FAA2F;AAC3F,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAgG1F"}
@@ -1,125 +1,90 @@
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 { warn as e } from "./_dev.js";
2
+ import { createAsyncSource as t } from "./asyncSource.js";
3
+ import { positiveInteger as n, sameQuery as r, totalItems as i } from "./pagination.js";
5
4
  //#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 = [], _ = {
5
+ var a = (e, t, n) => ({
6
+ hasMore: e < t,
7
+ isLoadingMore: n,
8
+ kind: "infinite",
9
+ loaded: e,
10
+ total: t
11
+ }), o = (e, t = {}) => ({
12
+ pageSize: n(t.pageSize ?? e.pageSize, "pageSize"),
13
+ search: t.search ?? e.search
14
+ });
15
+ function s(n) {
16
+ let s = o({
17
+ pageSize: 20,
18
+ search: ""
19
+ }, n.initialQuery), c = 1, l = t({
20
+ data: [],
8
21
  error: null,
9
- hasMore: !1,
10
- isLoading: !1,
11
- isLoadingMore: !1,
12
- isSearchPending: !1,
13
- loadedPages: 0,
14
- pageSize: c,
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
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) => {
32
- let a = {
33
- ...l && { search: l },
34
- limit: c,
35
- page: t
36
- };
37
- return m = null, y.fetch(a, async (a, s, c) => {
38
- let l = Date.now();
39
- try {
40
- let e = await r((e) => o.fetch(a, e), {
41
- delay: C,
42
- signal: s,
43
- times: S + 1
44
- });
45
- c() && (f = i ? [...f, ...e.items] : e.items, p = e.total, u = t, d = i ? d + 1 : 1, m = null, o.onFetch?.({
46
- durationMs: Date.now() - l,
47
- query: a,
48
- status: "success"
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,
54
- context: {
55
- kind: "infinite",
56
- limit: a.limit,
57
- page: a.page,
58
- ...a.search && { search: a.search }
59
- }
60
- }), o.onFetch?.({
61
- durationMs: Date.now() - l,
62
- error: m,
63
- query: a,
64
- status: "error"
65
- }));
66
- } finally {
67
- h = !1;
22
+ isFetching: !1,
23
+ pagination: a(0, 0, !1),
24
+ query: s
25
+ }), u = (e, t, r) => {
26
+ let o = l.snapshot.data;
27
+ return l.fetch({
28
+ failure: (e, t) => ({
29
+ ...e,
30
+ error: t,
31
+ isFetching: !1,
32
+ pendingQuery: void 0
33
+ }),
34
+ load: (r) => n.load({
35
+ query: {
36
+ ...e,
37
+ page: t,
38
+ pageSize: e.pageSize
39
+ },
40
+ signal: r
41
+ }),
42
+ pending: (t) => ({
43
+ ...t,
44
+ error: null,
45
+ isFetching: !0,
46
+ pagination: a(t.data.length, t.pagination.total, r),
47
+ pendingQuery: e
48
+ }),
49
+ success: (n) => {
50
+ let s = i(n.total), l = r ? [...o, ...n.data] : n.data;
51
+ return c = t + 1, {
52
+ data: l,
53
+ error: null,
54
+ isFetching: !1,
55
+ pagination: a(l.length, s, !1),
56
+ query: e
57
+ };
68
58
  }
69
- }, () => {
70
- w(), T.settleIfIdle(y.pendingCount());
71
59
  });
72
- }, D = () => E(1, !1);
73
- return b && D(), y.startRefreshInterval(() => void D()), {
74
- get current() {
75
- return g;
76
- },
60
+ }, d = () => (c = 1, u(s, 1, !1)), f = {
77
61
  get disposalSignal() {
78
- return y.disposalSignal;
79
- },
80
- dispose: () => {
81
- T.cancel(), T.dispose(), y.dispose();
62
+ return l.disposalSignal;
82
63
  },
64
+ dispose: l.dispose,
83
65
  get disposed() {
84
- return y.disposed;
66
+ return l.disposed;
85
67
  },
86
68
  loadMore() {
87
- return !_.hasMore || y.pendingCount() > 0 || h ? Promise.resolve() : (h = !0, v(), E(u + 1, !0));
88
- },
89
- get meta() {
90
- return _;
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);
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();
99
- },
100
- get query() {
101
- return {
102
- ...l && { search: l },
103
- limit: c,
104
- page: u
105
- };
106
- },
107
- ready(e) {
108
- return y.ready(e);
69
+ let { isFetching: e, pagination: t } = l.snapshot;
70
+ return e || l.snapshot.data.length > 0 && !t.hasMore ? Promise.resolve() : u(s, c, !0);
109
71
  },
110
- reset() {
111
- return T.cancel(), u = 1, d = 0, f = [], p = 0, l = "", D();
72
+ reload: d,
73
+ setQuery: async (e) => {
74
+ let t = o(l.snapshot.pendingQuery ?? l.snapshot.query, e);
75
+ r(t, s) || (s = t, c = 1, await u(t, 1, !1));
112
76
  },
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));
77
+ get snapshot() {
78
+ return l.snapshot;
115
79
  },
116
- subscribe: (e) => y.core.subscribe(e),
117
- [Symbol.dispose]: () => {
118
- T.cancel(), T.dispose(), y.dispose();
80
+ subscribe: l.subscribe,
81
+ [Symbol.dispose]() {
82
+ f.dispose();
119
83
  }
120
84
  };
85
+ return n.autoStart !== !1 && d().catch(() => /* @__PURE__ */ e("Initial load failed. Inspect source.snapshot.error.")), f;
121
86
  }
122
87
  //#endregion
123
- export { o as createInfiniteSource };
88
+ export { s as createInfiniteSource };
124
89
 
125
90
  //# sourceMappingURL=infiniteSource.js.map