@peerbit/react 0.0.21 → 0.0.22

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.
@@ -2,7 +2,7 @@ import { Documents } from "@peerbit/document";
2
2
  import * as indexerTypes from "@peerbit/indexer-interface";
3
3
  type QueryOptons = {
4
4
  query: indexerTypes.Query[] | indexerTypes.QueryLike;
5
- id: string;
5
+ id?: string;
6
6
  };
7
7
  export declare const useCount: <T extends Record<string, any>>(db?: Documents<T, any, any>, options?: {
8
8
  debounce?: number;
@@ -34,7 +34,10 @@ export const useCount = (db, options) => {
34
34
  db.events.removeEventListener("change", handleChange);
35
35
  debounced.cancel();
36
36
  };
37
- }, [db?.closed ? undefined : db?.rootAddress, options?.id]);
37
+ }, [
38
+ db?.closed ? undefined : db?.rootAddress,
39
+ options?.id ?? options?.query,
40
+ ]);
38
41
  return count;
39
42
  };
40
43
  //# sourceMappingURL=useCount.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useCount.js","sourceRoot":"","sources":["../../src/useCount.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA0B,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAMlD,MAAM,CAAC,MAAM,QAAQ,GAAG,CACpB,EAA2B,EAC3B,OAGe,EACjB,EAAE;IACA,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAS,CAAC,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,MAAM,CAAS,CAAC,CAAC,CAAC;IAEnC,SAAS,CAAC,GAAG,EAAE;QACX,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;YACnB,OAAO;QACX,CAAC;QAED,MAAM,EAAE,GAAG,KAAK,EAAE,IAAU,EAAE,EAAE;YAC5B,IAAI,CAAC;gBACD,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC;oBACzB,KAAK,EAAE,OAAO,EAAE,KAAK;oBACrB,WAAW,EAAE,IAAI;iBACpB,CAAC,CAAC;gBACH,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAC;gBACzB,QAAQ,CAAC,KAAK,CAAC,CAAC;YACpB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACb,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;oBAC/B,OAAO;gBACX,CAAC;gBACD,MAAM,KAAK,CAAC;YAChB,CAAC;QACL,CAAC,CAAC;QAEF,MAAM,SAAS,GAAG,uBAAuB,CACrC,EAAE,EACF,OAAO,EAAE,QAAQ,IAAI,IAAI,CAC5B,CAAC;QAEF,MAAM,YAAY,GAAG,GAAG,EAAE;YACtB,SAAS,EAAE,CAAC;QAChB,CAAC,CAAC;QAEF,SAAS,EAAE,CAAC;QACZ,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QAEnD,OAAO,GAAG,EAAE;YACR,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;YACtD,SAAS,CAAC,MAAM,EAAE,CAAC;QACvB,CAAC,CAAC;IACN,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;IAE5D,OAAO,KAAK,CAAC;AACjB,CAAC,CAAC"}
1
+ {"version":3,"file":"useCount.js","sourceRoot":"","sources":["../../src/useCount.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA0B,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAMlD,MAAM,CAAC,MAAM,QAAQ,GAAG,CACpB,EAA2B,EAC3B,OAGe,EACjB,EAAE;IACA,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAS,CAAC,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,MAAM,CAAS,CAAC,CAAC,CAAC;IAEnC,SAAS,CAAC,GAAG,EAAE;QACX,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;YACnB,OAAO;QACX,CAAC;QAED,MAAM,EAAE,GAAG,KAAK,EAAE,IAAU,EAAE,EAAE;YAC5B,IAAI,CAAC;gBACD,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC;oBACzB,KAAK,EAAE,OAAO,EAAE,KAAK;oBACrB,WAAW,EAAE,IAAI;iBACpB,CAAC,CAAC;gBACH,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAC;gBACzB,QAAQ,CAAC,KAAK,CAAC,CAAC;YACpB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACb,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;oBAC/B,OAAO;gBACX,CAAC;gBACD,MAAM,KAAK,CAAC;YAChB,CAAC;QACL,CAAC,CAAC;QAEF,MAAM,SAAS,GAAG,uBAAuB,CACrC,EAAE,EACF,OAAO,EAAE,QAAQ,IAAI,IAAI,CAC5B,CAAC;QAEF,MAAM,YAAY,GAAG,GAAG,EAAE;YACtB,SAAS,EAAE,CAAC;QAChB,CAAC,CAAC;QAEF,SAAS,EAAE,CAAC;QACZ,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QAEnD,OAAO,GAAG,EAAE;YACR,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;YACtD,SAAS,CAAC,MAAM,EAAE,CAAC;QACvB,CAAC,CAAC;IACN,CAAC,EAAE;QACC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,WAAW;QACxC,OAAO,EAAE,EAAE,IAAI,OAAO,EAAE,KAAK;KAChC,CAAC,CAAC;IAEH,OAAO,KAAK,CAAC;AACjB,CAAC,CAAC"}
@@ -6,32 +6,33 @@ type QueryLike = {
6
6
  };
7
7
  type QueryOptions = {
8
8
  query: QueryLike;
9
- id: string;
9
+ id?: string;
10
+ };
11
+ type WaitForReplicatorsOption = {
12
+ warmup?: number;
13
+ eager?: boolean;
10
14
  };
11
15
  export declare const useQuery: <T extends Record<string, any>, I extends Record<string, any>, R extends boolean | undefined = true, RT = R extends false ? WithContext<I> : WithContext<T>>(db?: Documents<T, I>, options?: {
12
16
  resolve?: R;
13
- waitForReplicators?: boolean | {
14
- timeout?: number;
15
- };
16
- transform?: (result: WithContext<RT>) => Promise<WithContext<RT>>;
17
+ transform?: (r: RT) => Promise<RT>;
17
18
  debounce?: number;
18
19
  debug?: boolean | {
19
20
  id: string;
20
21
  };
21
22
  reverse?: boolean;
22
23
  batchSize?: number;
24
+ prefetch?: boolean;
23
25
  onChange?: {
24
- merge?: boolean | ((change: DocumentsChange<T>) => DocumentsChange<T> | Promise<DocumentsChange<T>> | undefined);
25
- update?: (prev: WithContext<RT>[], change: DocumentsChange<T>) => WithContext<RT>[];
26
+ merge?: boolean | ((c: DocumentsChange<T>) => DocumentsChange<T> | Promise<DocumentsChange<T>> | undefined);
27
+ update?: (prev: RT[], change: DocumentsChange<T>) => RT[];
26
28
  };
27
29
  local?: boolean;
28
- remote?: boolean | {
29
- eager?: boolean;
30
- };
30
+ remote?: boolean | WaitForReplicatorsOption;
31
31
  } & QueryOptions) => {
32
- items: WithContext<RT>[];
33
- loadMore: () => Promise<void>;
32
+ items: RT[];
33
+ loadMore: () => Promise<boolean | undefined>;
34
34
  isLoading: boolean;
35
- empty: boolean;
35
+ empty: () => boolean;
36
+ id: string | undefined;
36
37
  };
37
38
  export {};
@@ -1,17 +1,11 @@
1
- import { useState, useEffect, useRef } from "react";
1
+ import { useState, useEffect, useRef, useReducer } from "react";
2
2
  import { ClosedError, } from "@peerbit/document";
3
3
  import { AbortError } from "@peerbit/time";
4
- const logWithId = (options, ...args) => {
5
- if (!options?.debug)
6
- return;
7
- if (typeof options.debug === "boolean") {
8
- console.log(...args);
9
- }
10
- else if (typeof options.debug.id === "string") {
11
- console.log(options.debug.id, ...args);
12
- }
13
- };
4
+ import { NoPeersError } from "@peerbit/shared-log";
5
+ import { v4 as uuid } from "uuid";
6
+ /* ────────────── main hook ────────────── */
14
7
  export const useQuery = (db, options) => {
8
+ /* ────────────── state & refs ────────────── */
15
9
  const [all, setAll] = useState([]);
16
10
  const allRef = useRef([]);
17
11
  const [isLoading, setIsLoading] = useState(false);
@@ -19,103 +13,113 @@ export const useQuery = (db, options) => {
19
13
  const iteratorRef = useRef(null);
20
14
  const emptyResultsRef = useRef(false);
21
15
  const closeControllerRef = useRef(null);
22
- const updateAll = (combined, fromChange) => {
23
- logWithId(options, "Loading more items, new combined length", combined.length, "from change", fromChange);
16
+ const waitedOnceRef = useRef(false);
17
+ const resetResultsOnReset = useRef(true);
18
+ const [id, setId] = useState(undefined);
19
+ const [resetCounter, invokeReset] = useReducer((n) => n + 1, 0);
20
+ const reverseRef = useRef(options?.reverse);
21
+ useEffect(() => {
22
+ reverseRef.current = options?.reverse;
23
+ }, [options?.reverse]);
24
+ /* ────────────── util ────────────── */
25
+ const log = (...a) => {
26
+ if (!options?.debug)
27
+ return;
28
+ if (typeof options.debug === "boolean")
29
+ console.log(...a);
30
+ else
31
+ console.log(options.debug.id, ...a);
32
+ };
33
+ const updateAll = (combined) => {
24
34
  allRef.current = combined;
25
35
  setAll(combined);
26
36
  };
27
37
  const reset = (fromRef) => {
28
- if (iteratorRef.current != null && iteratorRef.current !== fromRef) {
38
+ const toClose = iteratorRef.current;
39
+ if (toClose && fromRef && toClose !== fromRef) {
29
40
  return;
30
41
  }
42
+ iteratorRef.current = null;
31
43
  closeControllerRef.current?.abort();
32
44
  closeControllerRef.current = new AbortController();
33
45
  emptyResultsRef.current = false;
34
- logWithId(options, "reset", {
35
- id: iteratorRef.current?.id,
36
- size: allRef.current.length,
37
- });
38
- !iteratorRef.current?.iterator.done() &&
39
- iteratorRef.current?.iterator?.close();
40
- iteratorRef.current = null;
41
- setAll([]);
46
+ toClose?.iterator.close();
47
+ if (resetResultsOnReset.current) {
48
+ allRef.current = [];
49
+ setAll([]);
50
+ }
42
51
  setIsLoading(false);
43
52
  loadingMoreRef.current = false;
44
- allRef.current = [];
53
+ log(options, "Iterator reset", toClose?.id, fromRef?.id);
54
+ setId(undefined);
45
55
  };
46
- // Initialize the iterator only once or when query changes
47
56
  useEffect(() => {
48
- if (!db || db.closed || options?.query === null) {
57
+ resetResultsOnReset.current = true;
58
+ waitedOnceRef.current = false;
59
+ }, [db, options?.id ?? options?.query, options?.resolve, options?.reverse]);
60
+ /* ────────────── effect: (re)create iterator ────────────── */
61
+ useEffect(() => {
62
+ if (!db || db.closed || options?.query == null) {
49
63
  reset(null);
50
64
  return;
51
65
  }
52
66
  const initIterator = () => {
53
- // Don't make this async, it will cause issues with the iterator refs
54
- try {
55
- // Initialize the iterator and load initial batch.
56
- const ref = {
57
- id: options?.id,
58
- iterator: db.index.iterate(options?.query ?? {}, {
59
- local: options?.local ?? true,
60
- remote: options?.remote ?? true,
61
- resolve: options?.resolve,
62
- }),
63
- };
64
- iteratorRef.current = ref;
65
- logWithId(options, "Initializing iterator", {
66
- id: options?.id,
67
- options: options,
68
- });
69
- loadMore(); // initial load
70
- return ref;
71
- }
72
- catch (error) {
73
- console.error("Error initializing iterator", error);
74
- return null;
67
+ let id = options?.id ?? uuid();
68
+ const ref = {
69
+ id,
70
+ iterator: db.index.iterate(options.query ?? {}, {
71
+ local: options?.local ?? true,
72
+ remote: options.remote == null || options.remote === false
73
+ ? false
74
+ : typeof options.remote === "object"
75
+ ? options.remote
76
+ : true,
77
+ resolve: options?.resolve,
78
+ }),
79
+ itemsConsumed: 0,
80
+ };
81
+ iteratorRef.current = ref;
82
+ if (options?.prefetch) {
83
+ loadMore();
75
84
  }
85
+ setId(id);
86
+ log("Iterator initialised", ref.id);
87
+ return ref;
76
88
  };
77
- // Reset state when the db or query changes.
78
89
  reset(iteratorRef.current);
79
90
  const newIteratorRef = initIterator();
80
- let handleChange = undefined;
81
- if (options?.onChange && options?.onChange?.merge !== false) {
82
- let mergeFunction = typeof options.onChange.merge === "function"
91
+ /* live-merge listener (optional) */
92
+ let handleChange;
93
+ if (options?.onChange && options.onChange.merge !== false) {
94
+ const mergeFn = typeof options.onChange.merge === "function"
83
95
  ? options.onChange.merge
84
- : (change) => change;
96
+ : (c) => c;
85
97
  handleChange = async (e) => {
86
- // while we are iterating, we might get new documents.. so this method inserts them where they should be
87
- let filteredChange = await mergeFunction(e.detail);
88
- if (!filteredChange ||
89
- (filteredChange.added.length === 0 &&
90
- filteredChange.removed.length === 0)) {
98
+ log(options, "Merge change", e.detail, "iterator", newIteratorRef.id);
99
+ const filtered = await mergeFn(e.detail);
100
+ if (!filtered ||
101
+ (filtered.added.length === 0 &&
102
+ filtered.removed.length === 0))
91
103
  return;
92
- }
93
- let merged = [];
104
+ let merged;
94
105
  if (options.onChange?.update) {
95
106
  merged = [
96
- ...options.onChange.update(allRef.current, filteredChange),
107
+ ...options.onChange?.update(allRef.current, filtered),
97
108
  ];
98
109
  }
99
110
  else {
100
- merged = await db.index.updateResults(allRef.current, filteredChange, options?.query || {}, options?.resolve ?? true);
101
- logWithId(options, "After update", allRef.current, merged);
102
- const expectedDiff = filteredChange.added.length -
103
- filteredChange.removed.length;
111
+ merged = await db.index.updateResults(allRef.current, filtered, options.query || {}, options.resolve ?? true);
112
+ log(options, "After update", allRef.current, merged);
113
+ const expectedDiff = filtered.added.length - filtered.removed.length;
104
114
  if (merged === allRef.current ||
105
115
  (expectedDiff !== 0 &&
106
116
  merged.length === allRef.current.length)) {
107
117
  // no change
108
- logWithId(options, "no change after merge");
118
+ log(options, "no change after merge");
109
119
  return;
110
120
  }
111
121
  }
112
- logWithId(options, "handleChange", {
113
- added: e.detail.added.length,
114
- removed: e.detail.removed.length,
115
- merged: merged.length,
116
- allRef: allRef.current.length,
117
- });
118
- updateAll(options?.reverse ? merged.reverse() : merged, e.detail);
122
+ updateAll(options?.reverse ? merged.reverse() : merged);
119
123
  };
120
124
  db.events.addEventListener("change", handleChange);
121
125
  }
@@ -126,99 +130,130 @@ export const useQuery = (db, options) => {
126
130
  };
127
131
  }, [
128
132
  db?.closed ? undefined : db?.address,
129
- options?.id != null ? options?.id : options?.query,
133
+ options?.id ?? options?.query,
130
134
  options?.resolve,
135
+ options?.reverse,
136
+ resetCounter,
131
137
  ]);
132
- // Define the loadMore function
138
+ /* ────────────── loadMore (once-wait aware) ────────────── */
133
139
  const batchSize = options?.batchSize ?? 10;
140
+ const shouldWait = () => {
141
+ if (waitedOnceRef.current) {
142
+ return false;
143
+ }
144
+ if (options?.remote === false)
145
+ return false;
146
+ if (options?.remote === true)
147
+ return true;
148
+ if (options?.remote == null)
149
+ return true;
150
+ if (typeof options?.remote === "object") {
151
+ return true;
152
+ }
153
+ return true;
154
+ };
155
+ const reloadAfterTime = () => {
156
+ if (typeof options?.remote === "object" && options.remote.eager) {
157
+ return options.remote.warmup ?? db?.log.timeUntilRoleMaturity;
158
+ }
159
+ return undefined;
160
+ };
161
+ const markWaited = () => {
162
+ waitedOnceRef.current = true;
163
+ };
134
164
  const loadMore = async () => {
135
- if (!iteratorRef.current ||
165
+ const iterator = iteratorRef.current;
166
+ if (!iterator ||
136
167
  emptyResultsRef.current ||
137
- iteratorRef.current.iterator.done() ||
168
+ iterator.iterator.done() ||
138
169
  loadingMoreRef.current) {
139
- logWithId(options, "loadMore: already loading or no more items", {
140
- isLoading,
141
- emptyResultsRef: emptyResultsRef.current,
142
- iteratorRef: !iteratorRef.current,
143
- });
144
- return;
170
+ return false;
145
171
  }
146
- const iterator = iteratorRef.current;
147
172
  setIsLoading(true);
148
173
  loadingMoreRef.current = true;
149
174
  try {
150
- // Fetch next batchSize number of items:
151
- logWithId(options, "wait for replicators for iterator " + iterator.id);
152
- if (options?.waitForReplicators !== false) {
153
- let timeout = 5e3;
154
- if (typeof options?.waitForReplicators === "object") {
155
- timeout = options.waitForReplicators.timeout ?? 1e4;
156
- }
157
- await db?.log
175
+ /* ── optional replicate-wait ── */
176
+ if (shouldWait()) {
177
+ log(options, "Wait for replicators", iterator.id);
178
+ let isEager = typeof options?.remote === "object" && options.remote.eager;
179
+ const waitTimeout = typeof options?.remote === "object" &&
180
+ typeof options?.remote.warmup === "number"
181
+ ? options?.remote.warmup
182
+ : 5_000;
183
+ let shouldResetAfterMaturity = isEager && !waitedOnceRef.current;
184
+ let promise = db?.log
158
185
  .waitForReplicators({
159
- timeout,
186
+ timeout: waitTimeout,
160
187
  signal: closeControllerRef.current?.signal,
161
188
  })
162
189
  .catch((e) => {
163
- if (e instanceof AbortError) {
164
- // Ignore abort error
190
+ if (e instanceof AbortError ||
191
+ e instanceof NoPeersError)
165
192
  return;
166
- }
167
193
  console.warn("Remote replicators not ready", e);
194
+ })
195
+ .finally(() => {
196
+ markWaited();
197
+ if (shouldResetAfterMaturity) {
198
+ resetResultsOnReset.current = false; // don't reset results, because we expect to get same or more results
199
+ invokeReset();
200
+ }
168
201
  });
202
+ if (!shouldResetAfterMaturity) {
203
+ await promise;
204
+ }
169
205
  }
170
- logWithId(options, "loadMore: loading more items for iterator " +
171
- iteratorRef.current?.id, "should resolve?: " + options?.resolve, "query local?: " + options?.local, "query remote?: " + options?.remote, "isReplicating: " + (await db?.log.isReplicating()));
206
+ else {
207
+ log(options, "Skip wait for replicators", iterator.id);
208
+ }
209
+ /* ── fetch next batch ── */
210
+ log(options, "Retrieve next batch", iterator.id);
172
211
  let newItems = await iterator.iterator.next(batchSize);
173
212
  if (options?.transform) {
174
- newItems = await Promise.all(newItems.map((item) => options.transform(item)));
213
+ log(options, "Transform start", iterator.id);
214
+ newItems = await Promise.all(newItems.map(options.transform));
215
+ log(options, "Transform end", iterator.id);
175
216
  }
217
+ /* iterator might have been reset while we were async… */
176
218
  if (iteratorRef.current !== iterator) {
177
- // If the iterator has changed, we should not update the state
178
- // This can happen if the iterator was closed and a new one was created
179
- logWithId(options, "Iterator ref changed, not updating state", {
180
- refBefore: iterator.id,
181
- currentRef: iteratorRef.current?.id,
182
- ignoredItems: newItems.length,
183
- });
184
- return;
219
+ log(options, "Iterator reset while loading more");
220
+ return false;
185
221
  }
186
- logWithId(options, "loadMore: loaded more items for iterator " +
187
- iteratorRef.current?.id, "new items length", newItems.length, "all items length", allRef.current.length);
222
+ iterator.itemsConsumed += newItems.length;
188
223
  emptyResultsRef.current = newItems.length === 0;
189
- if (newItems.length > 0) {
190
- let prev = allRef.current;
191
- let prevHash = new Set(prev.map((x) => x.__context.head));
192
- let newItemsNoHash = newItems.filter((x) => !prevHash.has(x.__context.head));
193
- if (newItemsNoHash.length === 0) {
194
- logWithId(options, "no new items after dedup, not updating state. Prev length", prev.length);
224
+ if (newItems.length) {
225
+ log("Loaded more items for iterator", iterator.id, "current id", iteratorRef.current?.id, "new items", newItems.length, "previous results", allRef.current.length, "batchSize", batchSize, "items consumed", iterator.itemsConsumed);
226
+ const prev = allRef.current;
227
+ const dedup = new Set(prev.map((x) => x.__context.head));
228
+ const unique = newItems.filter((x) => !dedup.has(x.__context.head));
229
+ if (!unique.length)
195
230
  return;
196
- }
197
- const combined = options?.reverse
198
- ? [...newItemsNoHash.reverse(), ...prev]
199
- : [...prev, ...newItemsNoHash];
200
- updateAll(combined, null);
231
+ const combined = reverseRef.current
232
+ ? [...unique.reverse(), ...prev]
233
+ : [...prev, ...unique];
234
+ updateAll(combined);
201
235
  }
202
236
  else {
203
- logWithId(options, "no new items, not updating state for iterator " +
204
- iteratorRef.current?.id +
205
- " existing results length", allRef.current.length);
237
+ log(options, "No new items", iterator.id);
206
238
  }
239
+ return !iterator.iterator.done();
207
240
  }
208
- catch (error) {
209
- if (error instanceof ClosedError) {
210
- // Handle closed database gracefully
211
- logWithId(options, "Database closed error");
212
- }
213
- else {
214
- throw error;
215
- }
241
+ catch (e) {
242
+ if (!(e instanceof ClosedError))
243
+ throw e;
216
244
  }
217
245
  finally {
218
246
  setIsLoading(false);
219
247
  loadingMoreRef.current = false;
220
248
  }
221
249
  };
222
- return { items: all, loadMore, isLoading, empty: emptyResultsRef.current };
250
+ /* ────────────── public API ────────────── */
251
+ return {
252
+ items: all,
253
+ loadMore,
254
+ isLoading,
255
+ empty: () => emptyResultsRef.current,
256
+ id: id,
257
+ };
223
258
  };
224
259
  //# sourceMappingURL=useQuery.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useQuery.js","sourceRoot":"","sources":["../../src/useQuery.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useQuery.js","sourceRoot":"","sources":["../../src/useQuery.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAChE,OAAO,EACH,WAAW,GAKd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,EAAE,IAAI,IAAI,EAAE,MAAM,MAAM,CAAC;AAWlC,6CAA6C;AAC7C,MAAM,CAAC,MAAM,QAAQ,GAAG,CAMpB,EAAoB,EACpB,OAqBgB,EAClB,EAAE;IAIA,gDAAgD;IAChD,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAS,EAAE,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,MAAM,CAAS,EAAE,CAAC,CAAC;IAClC,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClD,MAAM,cAAc,GAAG,MAAM,CAAU,KAAK,CAAC,CAAC;IAC9C,MAAM,WAAW,GAAG,MAAM,CAIhB,IAAI,CAAC,CAAC;IAChB,MAAM,eAAe,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACtC,MAAM,kBAAkB,GAAG,MAAM,CAAyB,IAAI,CAAC,CAAC;IAChE,MAAM,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACpC,MAAM,mBAAmB,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAEzC,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,QAAQ,CAAqB,SAAS,CAAC,CAAC;IAC5D,MAAM,CAAC,YAAY,EAAE,WAAW,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAEhE,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC5C,SAAS,CAAC,GAAG,EAAE;QACX,UAAU,CAAC,OAAO,GAAG,OAAO,EAAE,OAAO,CAAC;IAC1C,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IAEvB,wCAAwC;IACxC,MAAM,GAAG,GAAG,CAAC,GAAG,CAAQ,EAAE,EAAE;QACxB,IAAI,CAAC,OAAO,EAAE,KAAK;YAAE,OAAO;QAC5B,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,SAAS;YAAE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;;YACrD,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;IAC7C,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,CAAC,QAAgB,EAAE,EAAE;QACnC,MAAM,CAAC,OAAO,GAAG,QAAQ,CAAC;QAC1B,MAAM,CAAC,QAAQ,CAAC,CAAC;IACrB,CAAC,CAAC;IAEF,MAAM,KAAK,GAAG,CACV,OAGQ,EACV,EAAE;QACA,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC;QACpC,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;YAC5C,OAAO;QACX,CAAC;QAED,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC;QAE3B,kBAAkB,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;QACpC,kBAAkB,CAAC,OAAO,GAAG,IAAI,eAAe,EAAE,CAAC;QACnD,eAAe,CAAC,OAAO,GAAG,KAAK,CAAC;QAEhC,OAAO,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC;QAE1B,IAAI,mBAAmB,CAAC,OAAO,EAAE,CAAC;YAC9B,MAAM,CAAC,OAAO,GAAG,EAAE,CAAC;YACpB,MAAM,CAAC,EAAE,CAAC,CAAC;QACf,CAAC;QAED,YAAY,CAAC,KAAK,CAAC,CAAC;QACpB,cAAc,CAAC,OAAO,GAAG,KAAK,CAAC;QAC/B,GAAG,CAAC,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;QACzD,KAAK,CAAC,SAAS,CAAC,CAAC;IACrB,CAAC,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE;QACX,mBAAmB,CAAC,OAAO,GAAG,IAAI,CAAC;QACnC,aAAa,CAAC,OAAO,GAAG,KAAK,CAAC;IAClC,CAAC,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IAE5E,+DAA+D;IAC/D,SAAS,CAAC,GAAG,EAAE;QACX,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,MAAM,IAAI,OAAO,EAAE,KAAK,IAAI,IAAI,EAAE,CAAC;YAC7C,KAAK,CAAC,IAAI,CAAC,CAAC;YACZ,OAAO;QACX,CAAC;QAED,MAAM,YAAY,GAAG,GAAG,EAAE;YACtB,IAAI,EAAE,GAAG,OAAO,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC;YAC/B,MAAM,GAAG,GAAG;gBACR,EAAE;gBACF,QAAQ,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,EAAE;oBAC5C,KAAK,EAAE,OAAO,EAAE,KAAK,IAAI,IAAI;oBAC7B,MAAM,EACF,OAAO,CAAC,MAAM,IAAI,IAAI,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK;wBAC9C,CAAC,CAAC,KAAK;wBACP,CAAC,CAAC,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ;4BACpC,CAAC,CAAC,OAAO,CAAC,MAAM;4BAChB,CAAC,CAAC,IAAI;oBACd,OAAO,EAAE,OAAO,EAAE,OAAO;iBAC5B,CAA0B;gBAC3B,aAAa,EAAE,CAAC;aACnB,CAAC;YACF,WAAW,CAAC,OAAO,GAAG,GAAG,CAAC;YAC1B,IAAI,OAAO,EAAE,QAAQ,EAAE,CAAC;gBACpB,QAAQ,EAAE,CAAC;YACf,CAAC;YACD,KAAK,CAAC,EAAE,CAAC,CAAC;YAEV,GAAG,CAAC,sBAAsB,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;YACpC,OAAO,GAAG,CAAC;QACf,CAAC,CAAC;QAEF,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAC3B,MAAM,cAAc,GAAG,YAAY,EAAE,CAAC;QAEtC,oCAAoC;QACpC,IAAI,YAEW,CAAC;QAEhB,IAAI,OAAO,EAAE,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;YACxD,MAAM,OAAO,GACT,OAAO,OAAO,CAAC,QAAQ,CAAC,KAAK,KAAK,UAAU;gBACxC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK;gBACxB,CAAC,CAAC,CAAC,CAAqB,EAAE,EAAE,CAAC,CAAC,CAAC;YAEvC,YAAY,GAAG,KAAK,EAAE,CAAkC,EAAE,EAAE;gBACxD,GAAG,CACC,OAAO,EACP,cAAc,EACd,CAAC,CAAC,MAAM,EACR,UAAU,EACV,cAAc,CAAC,EAAE,CACpB,CAAC;gBACF,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;gBACzC,IACI,CAAC,QAAQ;oBACT,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;wBACxB,QAAQ,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC;oBAElC,OAAO;gBAEX,IAAI,MAAc,CAAC;gBACnB,IAAI,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;oBAC3B,MAAM,GAAG;wBACL,GAAG,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC;qBACxD,CAAC;gBACN,CAAC;qBAAM,CAAC;oBACJ,MAAM,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,aAAa,CACjC,MAAM,CAAC,OAA4B,EACnC,QAAQ,EACR,OAAO,CAAC,KAAK,IAAI,EAAE,EACnB,OAAO,CAAC,OAAO,IAAI,IAAI,CAC1B,CAAC;oBAEF,GAAG,CAAC,OAAO,EAAE,cAAc,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;oBACrD,MAAM,YAAY,GACd,QAAQ,CAAC,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC;oBAEpD,IACI,MAAM,KAAK,MAAM,CAAC,OAAO;wBACzB,CAAC,YAAY,KAAK,CAAC;4BACf,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAC9C,CAAC;wBACC,YAAY;wBACZ,GAAG,CAAC,OAAO,EAAE,uBAAuB,CAAC,CAAC;wBACtC,OAAO;oBACX,CAAC;gBACL,CAAC;gBAED,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YAC5D,CAAC,CAAC;YAEF,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QACvD,CAAC;QAED,OAAO,GAAG,EAAE;YACR,YAAY;gBACR,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;YAC1D,KAAK,CAAC,cAAc,CAAC,CAAC;QAC1B,CAAC,CAAC;IACN,CAAC,EAAE;QACC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,OAAO;QACpC,OAAO,EAAE,EAAE,IAAI,OAAO,EAAE,KAAK;QAC7B,OAAO,EAAE,OAAO;QAChB,OAAO,EAAE,OAAO;QAChB,YAAY;KACf,CAAC,CAAC;IAEH,8DAA8D;IAC9D,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,EAAE,CAAC;IAE3C,MAAM,UAAU,GAAG,GAAY,EAAE;QAC7B,IAAI,aAAa,CAAC,OAAO,EAAE,CAAC;YACxB,OAAO,KAAK,CAAC;QACjB,CAAC;QACD,IAAI,OAAO,EAAE,MAAM,KAAK,KAAK;YAAE,OAAO,KAAK,CAAC;QAC5C,IAAI,OAAO,EAAE,MAAM,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QAC1C,IAAI,OAAO,EAAE,MAAM,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC;QACzC,IAAI,OAAO,OAAO,EAAE,MAAM,KAAK,QAAQ,EAAE,CAAC;YACtC,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC,CAAC;IAEF,MAAM,eAAe,GAAG,GAAuB,EAAE;QAC7C,IAAI,OAAO,OAAO,EAAE,MAAM,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAC9D,OAAO,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,EAAE,GAAG,CAAC,qBAAqB,CAAC;QAClE,CAAC;QACD,OAAO,SAAS,CAAC;IACrB,CAAC,CAAC;IAEF,MAAM,UAAU,GAAG,GAAG,EAAE;QACpB,aAAa,CAAC,OAAO,GAAG,IAAI,CAAC;IACjC,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;QACxB,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC;QACrC,IACI,CAAC,QAAQ;YACT,eAAe,CAAC,OAAO;YACvB,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE;YACxB,cAAc,CAAC,OAAO,EACxB,CAAC;YACC,OAAO,KAAK,CAAC;QACjB,CAAC;QAED,YAAY,CAAC,IAAI,CAAC,CAAC;QACnB,cAAc,CAAC,OAAO,GAAG,IAAI,CAAC;QAE9B,IAAI,CAAC;YACD,mCAAmC;YACnC,IAAI,UAAU,EAAE,EAAE,CAAC;gBACf,GAAG,CAAC,OAAO,EAAE,sBAAsB,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;gBAElD,IAAI,OAAO,GACP,OAAO,OAAO,EAAE,MAAM,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;gBAChE,MAAM,WAAW,GACb,OAAO,OAAO,EAAE,MAAM,KAAK,QAAQ;oBACnC,OAAO,OAAO,EAAE,MAAM,CAAC,MAAM,KAAK,QAAQ;oBACtC,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM;oBACxB,CAAC,CAAC,KAAK,CAAC;gBAEhB,IAAI,wBAAwB,GACxB,OAAO,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;gBACtC,IAAI,OAAO,GAAG,EAAE,EAAE,GAAG;qBAChB,kBAAkB,CAAC;oBAChB,OAAO,EAAE,WAAW;oBACpB,MAAM,EAAE,kBAAkB,CAAC,OAAO,EAAE,MAAM;iBAC7C,CAAC;qBACD,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;oBACT,IACI,CAAC,YAAY,UAAU;wBACvB,CAAC,YAAY,YAAY;wBAEzB,OAAO;oBACX,OAAO,CAAC,IAAI,CAAC,8BAA8B,EAAE,CAAC,CAAC,CAAC;gBACpD,CAAC,CAAC;qBACD,OAAO,CAAC,GAAG,EAAE;oBACV,UAAU,EAAE,CAAC;oBACb,IAAI,wBAAwB,EAAE,CAAC;wBAC3B,mBAAmB,CAAC,OAAO,GAAG,KAAK,CAAC,CAAC,qEAAqE;wBAC1G,WAAW,EAAE,CAAC;oBAClB,CAAC;gBACL,CAAC,CAAC,CAAC;gBACP,IAAI,CAAC,wBAAwB,EAAE,CAAC;oBAC5B,MAAM,OAAO,CAAC;gBAClB,CAAC;YACL,CAAC;iBAAM,CAAC;gBACJ,GAAG,CAAC,OAAO,EAAE,2BAA2B,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;YAC3D,CAAC;YAED,4BAA4B;YAC5B,GAAG,CAAC,OAAO,EAAE,qBAAqB,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;YACjD,IAAI,QAAQ,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACvD,IAAI,OAAO,EAAE,SAAS,EAAE,CAAC;gBACrB,GAAG,CAAC,OAAO,EAAE,iBAAiB,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;gBAE7C,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;gBAC9D,GAAG,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;YAC/C,CAAC;YAED,yDAAyD;YAEzD,IAAI,WAAW,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;gBACnC,GAAG,CAAC,OAAO,EAAE,mCAAmC,CAAC,CAAC;gBAClD,OAAO,KAAK,CAAC;YACjB,CAAC;YAED,QAAQ,CAAC,aAAa,IAAI,QAAQ,CAAC,MAAM,CAAC;YAE1C,eAAe,CAAC,OAAO,GAAG,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC;YAEhD,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;gBAClB,GAAG,CACC,gCAAgC,EAChC,QAAQ,CAAC,EAAE,EACX,YAAY,EACZ,WAAW,CAAC,OAAO,EAAE,EAAE,EACvB,WAAW,EACX,QAAQ,CAAC,MAAM,EACf,kBAAkB,EAClB,MAAM,CAAC,OAAO,CAAC,MAAM,EACrB,WAAW,EACX,SAAS,EACT,gBAAgB,EAChB,QAAQ,CAAC,aAAa,CACzB,CAAC;gBACF,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC;gBAC5B,MAAM,KAAK,GAAG,IAAI,GAAG,CACjB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAE,CAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAC7C,CAAC;gBACF,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAC1B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAE,CAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAC/C,CAAC;gBACF,IAAI,CAAC,MAAM,CAAC,MAAM;oBAAE,OAAO;gBAE3B,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO;oBAC/B,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC;oBAChC,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,MAAM,CAAC,CAAC;gBAC3B,SAAS,CAAC,QAAQ,CAAC,CAAC;YACxB,CAAC;iBAAM,CAAC;gBACJ,GAAG,CAAC,OAAO,EAAE,cAAc,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;YAC9C,CAAC;YACD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QACrC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACT,IAAI,CAAC,CAAC,CAAC,YAAY,WAAW,CAAC;gBAAE,MAAM,CAAC,CAAC;QAC7C,CAAC;gBAAS,CAAC;YACP,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,cAAc,CAAC,OAAO,GAAG,KAAK,CAAC;QACnC,CAAC;IACL,CAAC,CAAC;IAEF,8CAA8C;IAC9C,OAAO;QACH,KAAK,EAAE,GAAG;QACV,QAAQ;QACR,SAAS;QACT,KAAK,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,OAAO;QACpC,EAAE,EAAE,EAAE;KACT,CAAC;AACN,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peerbit/react",
3
- "version": "0.0.21",
3
+ "version": "0.0.22",
4
4
  "homepage": "https://dao-xyz.github.io/peerbit-examples",
5
5
  "type": "module",
6
6
  "module": "lib/esm/index.js",
@@ -70,5 +70,5 @@
70
70
  "last 1 safari version"
71
71
  ]
72
72
  },
73
- "gitHead": "6e2a023d63cd34b6058da13820562d64b8101253"
73
+ "gitHead": "0aeb9e6d47a916b922efd66f4b14ac982664a9bd"
74
74
  }
package/src/useCount.tsx CHANGED
@@ -5,7 +5,7 @@ import { debounceLeadingTrailing } from "./utils";
5
5
 
6
6
  type QueryOptons = {
7
7
  query: indexerTypes.Query[] | indexerTypes.QueryLike;
8
- id: string;
8
+ id?: string;
9
9
  };
10
10
  export const useCount = <T extends Record<string, any>>(
11
11
  db?: Documents<T, any, any>,
@@ -54,7 +54,10 @@ export const useCount = <T extends Record<string, any>>(
54
54
  db.events.removeEventListener("change", handleChange);
55
55
  debounced.cancel();
56
56
  };
57
- }, [db?.closed ? undefined : db?.rootAddress, options?.id]);
57
+ }, [
58
+ db?.closed ? undefined : db?.rootAddress,
59
+ options?.id ?? options?.query,
60
+ ]);
58
61
 
59
62
  return count;
60
63
  };
package/src/useQuery.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import { useState, useEffect, useRef } from "react";
1
+ import { useState, useEffect, useRef, useReducer } from "react";
2
2
  import {
3
3
  ClosedError,
4
4
  Documents,
@@ -8,26 +8,19 @@ import {
8
8
  } from "@peerbit/document";
9
9
  import * as indexerTypes from "@peerbit/indexer-interface";
10
10
  import { AbortError } from "@peerbit/time";
11
+ import { NoPeersError } from "@peerbit/shared-log";
12
+ import { v4 as uuid } from "uuid";
11
13
 
14
+ /* ────────────── helper types ────────────── */
12
15
  type QueryLike = {
13
16
  query?: indexerTypes.Query[] | indexerTypes.QueryLike;
14
17
  sort?: indexerTypes.Sort[] | indexerTypes.Sort | indexerTypes.SortLike;
15
18
  };
16
- type QueryOptions = { query: QueryLike; id: string };
19
+ type QueryOptions = { query: QueryLike; id?: string };
17
20
 
18
- const logWithId = (
19
- options: { debug?: boolean | { id: string } } | undefined,
20
- ...args: any[]
21
- ) => {
22
- if (!options?.debug) return;
23
-
24
- if (typeof options.debug === "boolean") {
25
- console.log(...args);
26
- } else if (typeof options.debug.id === "string") {
27
- console.log(options.debug.id, ...args);
28
- }
29
- };
21
+ type WaitForReplicatorsOption = { warmup?: number; eager?: boolean };
30
22
 
23
+ /* ────────────── main hook ────────────── */
31
24
  export const useQuery = <
32
25
  T extends Record<string, any>,
33
26
  I extends Record<string, any>,
@@ -37,167 +30,179 @@ export const useQuery = <
37
30
  db?: Documents<T, I>,
38
31
  options?: {
39
32
  resolve?: R;
40
- waitForReplicators?: boolean | { timeout?: number };
41
- transform?: (result: WithContext<RT>) => Promise<WithContext<RT>>;
33
+ transform?: (r: RT) => Promise<RT>;
42
34
  debounce?: number;
43
35
  debug?: boolean | { id: string };
44
36
  reverse?: boolean;
45
- batchSize?: number; // You can set a default batch size here
37
+ batchSize?: number;
38
+ prefetch?: boolean;
46
39
  onChange?: {
47
40
  merge?:
48
41
  | boolean
49
42
  | ((
50
- change: DocumentsChange<T>
43
+ c: DocumentsChange<T>
51
44
  ) =>
52
45
  | DocumentsChange<T>
53
46
  | Promise<DocumentsChange<T>>
54
- | undefined); // if true, the iterator will be updated with new documents
55
- update?: (
56
- prev: WithContext<RT>[],
57
- change: DocumentsChange<T>
58
- ) => WithContext<RT>[];
47
+ | undefined);
48
+ update?: (prev: RT[], change: DocumentsChange<T>) => RT[];
59
49
  };
60
- local?: boolean; // if true, (default is true) the iterator will only return local documents
61
- remote?:
62
- | boolean
63
- | {
64
- eager?: boolean;
65
- };
50
+ local?: boolean;
51
+ remote?: boolean | WaitForReplicatorsOption;
66
52
  } & QueryOptions
67
53
  ) => {
68
- const [all, setAll] = useState<WithContext<RT>[]>([]);
69
- const allRef = useRef<WithContext<RT>[]>([]);
54
+ /* ── «Item» is the concrete element type flowing through the hook ── */
55
+ type Item = RT;
56
+
57
+ /* ────────────── state & refs ────────────── */
58
+ const [all, setAll] = useState<Item[]>([]);
59
+ const allRef = useRef<Item[]>([]);
70
60
  const [isLoading, setIsLoading] = useState(false);
71
- const loadingMoreRef = useRef(false);
61
+ const loadingMoreRef = useRef<boolean>(false);
72
62
  const iteratorRef = useRef<{
73
63
  id?: string;
74
- iterator: ResultsIterator<WithContext<RT>>;
64
+ iterator: ResultsIterator<Item>;
65
+ itemsConsumed: number;
75
66
  } | null>(null);
76
67
  const emptyResultsRef = useRef(false);
77
68
  const closeControllerRef = useRef<AbortController | null>(null);
69
+ const waitedOnceRef = useRef(false);
70
+ const resetResultsOnReset = useRef(true);
78
71
 
79
- const updateAll = (
80
- combined: WithContext<RT>[],
81
- fromChange?: DocumentsChange<any> | null
82
- ) => {
83
- logWithId(
84
- options,
85
- "Loading more items, new combined length",
86
- combined.length,
87
- "from change",
88
- fromChange
89
- );
72
+ const [id, setId] = useState<string | undefined>(undefined);
73
+ const [resetCounter, invokeReset] = useReducer((n) => n + 1, 0);
90
74
 
91
- allRef.current = combined;
75
+ const reverseRef = useRef(options?.reverse);
76
+ useEffect(() => {
77
+ reverseRef.current = options?.reverse;
78
+ }, [options?.reverse]);
79
+
80
+ /* ────────────── util ────────────── */
81
+ const log = (...a: any[]) => {
82
+ if (!options?.debug) return;
83
+ if (typeof options.debug === "boolean") console.log(...a);
84
+ else console.log(options.debug.id, ...a);
85
+ };
92
86
 
87
+ const updateAll = (combined: Item[]) => {
88
+ allRef.current = combined;
93
89
  setAll(combined);
94
90
  };
95
91
 
96
92
  const reset = (
97
93
  fromRef: {
98
94
  id?: string;
99
- iterator: ResultsIterator<WithContext<RT>>;
95
+ iterator: ResultsIterator<Item>;
100
96
  } | null
101
97
  ) => {
102
- if (iteratorRef.current != null && iteratorRef.current !== fromRef) {
98
+ const toClose = iteratorRef.current;
99
+ if (toClose && fromRef && toClose !== fromRef) {
103
100
  return;
104
101
  }
102
+
103
+ iteratorRef.current = null;
104
+
105
105
  closeControllerRef.current?.abort();
106
106
  closeControllerRef.current = new AbortController();
107
-
108
107
  emptyResultsRef.current = false;
109
- logWithId(options, "reset", {
110
- id: iteratorRef.current?.id,
111
- size: allRef.current.length,
112
- });
113
108
 
114
- !iteratorRef.current?.iterator.done() &&
115
- iteratorRef.current?.iterator?.close();
116
- iteratorRef.current = null;
117
- setAll([]);
109
+ toClose?.iterator.close();
110
+
111
+ if (resetResultsOnReset.current) {
112
+ allRef.current = [];
113
+ setAll([]);
114
+ }
115
+
118
116
  setIsLoading(false);
119
117
  loadingMoreRef.current = false;
120
- allRef.current = [];
118
+ log(options, "Iterator reset", toClose?.id, fromRef?.id);
119
+ setId(undefined);
121
120
  };
122
121
 
123
- // Initialize the iterator only once or when query changes
124
122
  useEffect(() => {
125
- if (!db || db.closed || options?.query === null) {
123
+ resetResultsOnReset.current = true;
124
+ waitedOnceRef.current = false;
125
+ }, [db, options?.id ?? options?.query, options?.resolve, options?.reverse]);
126
+
127
+ /* ────────────── effect: (re)create iterator ────────────── */
128
+ useEffect(() => {
129
+ if (!db || db.closed || options?.query == null) {
126
130
  reset(null);
127
131
  return;
128
132
  }
129
133
 
130
134
  const initIterator = () => {
131
- // Don't make this async, it will cause issues with the iterator refs
132
- try {
133
- // Initialize the iterator and load initial batch.
134
-
135
- const ref = {
136
- id: options?.id,
137
- iterator: db.index.iterate(options?.query ?? {}, {
138
- local: options?.local ?? true,
139
- remote: options?.remote ?? true,
140
- resolve: options?.resolve as any,
141
- }) as any as ResultsIterator<WithContext<RT>>,
142
- };
143
- iteratorRef.current = ref;
144
-
145
- logWithId(options, "Initializing iterator", {
146
- id: options?.id,
147
- options: options,
148
- });
149
-
150
- loadMore(); // initial load
151
- return ref;
152
- } catch (error) {
153
- console.error("Error initializing iterator", error);
154
- return null;
135
+ let id = options?.id ?? uuid();
136
+ const ref = {
137
+ id,
138
+ iterator: db.index.iterate(options.query ?? {}, {
139
+ local: options?.local ?? true,
140
+ remote:
141
+ options.remote == null || options.remote === false
142
+ ? false
143
+ : typeof options.remote === "object"
144
+ ? options.remote
145
+ : true,
146
+ resolve: options?.resolve,
147
+ }) as ResultsIterator<Item>,
148
+ itemsConsumed: 0,
149
+ };
150
+ iteratorRef.current = ref;
151
+ if (options?.prefetch) {
152
+ loadMore();
155
153
  }
154
+ setId(id);
155
+
156
+ log("Iterator initialised", ref.id);
157
+ return ref;
156
158
  };
157
159
 
158
- // Reset state when the db or query changes.
159
160
  reset(iteratorRef.current);
160
-
161
161
  const newIteratorRef = initIterator();
162
162
 
163
+ /* live-merge listener (optional) */
163
164
  let handleChange:
164
- | undefined
165
- | ((e: CustomEvent<DocumentsChange<T>>) => void | Promise<void>) =
166
- undefined;
167
- if (options?.onChange && options?.onChange?.merge !== false) {
168
- let mergeFunction =
165
+ | ((e: CustomEvent<DocumentsChange<T>>) => void | Promise<void>)
166
+ | undefined;
167
+
168
+ if (options?.onChange && options.onChange.merge !== false) {
169
+ const mergeFn =
169
170
  typeof options.onChange.merge === "function"
170
171
  ? options.onChange.merge
171
- : (change: DocumentsChange<T>) => change;
172
+ : (c: DocumentsChange<T>) => c;
173
+
172
174
  handleChange = async (e: CustomEvent<DocumentsChange<T>>) => {
173
- // while we are iterating, we might get new documents.. so this method inserts them where they should be
174
- let filteredChange = await mergeFunction(e.detail);
175
+ log(
176
+ options,
177
+ "Merge change",
178
+ e.detail,
179
+ "iterator",
180
+ newIteratorRef.id
181
+ );
182
+ const filtered = await mergeFn(e.detail);
175
183
  if (
176
- !filteredChange ||
177
- (filteredChange.added.length === 0 &&
178
- filteredChange.removed.length === 0)
179
- ) {
184
+ !filtered ||
185
+ (filtered.added.length === 0 &&
186
+ filtered.removed.length === 0)
187
+ )
180
188
  return;
181
- }
182
- let merged: WithContext<RT>[] = [];
189
+
190
+ let merged: Item[];
183
191
  if (options.onChange?.update) {
184
192
  merged = [
185
- ...options.onChange.update(
186
- allRef.current,
187
- filteredChange
188
- ),
193
+ ...options.onChange?.update(allRef.current, filtered),
189
194
  ];
190
195
  } else {
191
196
  merged = await db.index.updateResults(
192
- allRef.current,
193
- filteredChange,
194
- options?.query || {},
195
- options?.resolve ?? true
197
+ allRef.current as WithContext<RT>[],
198
+ filtered,
199
+ options.query || {},
200
+ options.resolve ?? true
196
201
  );
197
- logWithId(options, "After update", allRef.current, merged);
202
+
203
+ log(options, "After update", allRef.current, merged);
198
204
  const expectedDiff =
199
- filteredChange.added.length -
200
- filteredChange.removed.length;
205
+ filtered.added.length - filtered.removed.length;
201
206
 
202
207
  if (
203
208
  merged === allRef.current ||
@@ -205,23 +210,14 @@ export const useQuery = <
205
210
  merged.length === allRef.current.length)
206
211
  ) {
207
212
  // no change
208
- logWithId(options, "no change after merge");
213
+ log(options, "no change after merge");
209
214
  return;
210
215
  }
211
216
  }
212
217
 
213
- logWithId(options, "handleChange", {
214
- added: e.detail.added.length,
215
- removed: e.detail.removed.length,
216
- merged: merged.length,
217
- allRef: allRef.current.length,
218
- });
219
-
220
- updateAll(
221
- options?.reverse ? merged.reverse() : merged,
222
- e.detail
223
- );
218
+ updateAll(options?.reverse ? merged.reverse() : merged);
224
219
  };
220
+
225
221
  db.events.addEventListener("change", handleChange);
226
222
  }
227
223
 
@@ -232,137 +228,162 @@ export const useQuery = <
232
228
  };
233
229
  }, [
234
230
  db?.closed ? undefined : db?.address,
235
- options?.id != null ? options?.id : options?.query,
231
+ options?.id ?? options?.query,
236
232
  options?.resolve,
233
+ options?.reverse,
234
+ resetCounter,
237
235
  ]);
238
236
 
239
- // Define the loadMore function
237
+ /* ────────────── loadMore (once-wait aware) ────────────── */
240
238
  const batchSize = options?.batchSize ?? 10;
239
+
240
+ const shouldWait = (): boolean => {
241
+ if (waitedOnceRef.current) {
242
+ return false;
243
+ }
244
+ if (options?.remote === false) return false;
245
+ if (options?.remote === true) return true;
246
+ if (options?.remote == null) return true;
247
+ if (typeof options?.remote === "object") {
248
+ return true;
249
+ }
250
+ return true;
251
+ };
252
+
253
+ const reloadAfterTime = (): number | undefined => {
254
+ if (typeof options?.remote === "object" && options.remote.eager) {
255
+ return options.remote.warmup ?? db?.log.timeUntilRoleMaturity;
256
+ }
257
+ return undefined;
258
+ };
259
+
260
+ const markWaited = () => {
261
+ waitedOnceRef.current = true;
262
+ };
263
+
241
264
  const loadMore = async () => {
265
+ const iterator = iteratorRef.current;
242
266
  if (
243
- !iteratorRef.current ||
267
+ !iterator ||
244
268
  emptyResultsRef.current ||
245
- iteratorRef.current.iterator.done() ||
269
+ iterator.iterator.done() ||
246
270
  loadingMoreRef.current
247
271
  ) {
248
- logWithId(options, "loadMore: already loading or no more items", {
249
- isLoading,
250
- emptyResultsRef: emptyResultsRef.current,
251
- iteratorRef: !iteratorRef.current,
252
- });
253
- return;
272
+ return false;
254
273
  }
255
- const iterator = iteratorRef.current;
256
274
 
257
275
  setIsLoading(true);
258
276
  loadingMoreRef.current = true;
277
+
259
278
  try {
260
- // Fetch next batchSize number of items:
261
- logWithId(
262
- options,
263
- "wait for replicators for iterator " + iterator.id
264
- );
265
- if (options?.waitForReplicators !== false) {
266
- let timeout = 5e3;
267
- if (typeof options?.waitForReplicators === "object") {
268
- timeout = options.waitForReplicators.timeout ?? 1e4;
269
- }
270
- await db?.log
279
+ /* ── optional replicate-wait ── */
280
+ if (shouldWait()) {
281
+ log(options, "Wait for replicators", iterator.id);
282
+
283
+ let isEager =
284
+ typeof options?.remote === "object" && options.remote.eager;
285
+ const waitTimeout =
286
+ typeof options?.remote === "object" &&
287
+ typeof options?.remote.warmup === "number"
288
+ ? options?.remote.warmup
289
+ : 5_000;
290
+
291
+ let shouldResetAfterMaturity =
292
+ isEager && !waitedOnceRef.current;
293
+ let promise = db?.log
271
294
  .waitForReplicators({
272
- timeout,
295
+ timeout: waitTimeout,
273
296
  signal: closeControllerRef.current?.signal,
274
297
  })
275
298
  .catch((e) => {
276
- if (e instanceof AbortError) {
277
- // Ignore abort error
299
+ if (
300
+ e instanceof AbortError ||
301
+ e instanceof NoPeersError
302
+ )
278
303
  return;
279
- }
280
304
  console.warn("Remote replicators not ready", e);
305
+ })
306
+ .finally(() => {
307
+ markWaited();
308
+ if (shouldResetAfterMaturity) {
309
+ resetResultsOnReset.current = false; // don't reset results, because we expect to get same or more results
310
+ invokeReset();
311
+ }
281
312
  });
313
+ if (!shouldResetAfterMaturity) {
314
+ await promise;
315
+ }
316
+ } else {
317
+ log(options, "Skip wait for replicators", iterator.id);
282
318
  }
283
319
 
284
- logWithId(
285
- options,
286
- "loadMore: loading more items for iterator " +
287
- iteratorRef.current?.id,
288
- "should resolve?: " + options?.resolve,
289
- "query local?: " + options?.local,
290
- "query remote?: " + options?.remote,
291
- "isReplicating: " + (await db?.log.isReplicating())
292
- );
293
-
294
- let newItems: WithContext<RT>[] = await iterator.iterator.next(
295
- batchSize
296
- );
297
-
320
+ /* ── fetch next batch ── */
321
+ log(options, "Retrieve next batch", iterator.id);
322
+ let newItems = await iterator.iterator.next(batchSize);
298
323
  if (options?.transform) {
299
- newItems = await Promise.all(
300
- newItems.map((item) => options.transform!(item))
301
- );
324
+ log(options, "Transform start", iterator.id);
325
+
326
+ newItems = await Promise.all(newItems.map(options.transform));
327
+ log(options, "Transform end", iterator.id);
302
328
  }
303
329
 
330
+ /* iterator might have been reset while we were async… */
331
+
304
332
  if (iteratorRef.current !== iterator) {
305
- // If the iterator has changed, we should not update the state
306
- // This can happen if the iterator was closed and a new one was created
307
- logWithId(options, "Iterator ref changed, not updating state", {
308
- refBefore: iterator.id,
309
- currentRef: iteratorRef.current?.id,
310
- ignoredItems: newItems.length,
311
- });
312
- return;
333
+ log(options, "Iterator reset while loading more");
334
+ return false;
313
335
  }
314
336
 
315
- logWithId(
316
- options,
317
- "loadMore: loaded more items for iterator " +
318
- iteratorRef.current?.id,
319
- "new items length",
320
- newItems.length,
321
- "all items length",
322
- allRef.current.length
323
- );
337
+ iterator.itemsConsumed += newItems.length;
324
338
 
325
339
  emptyResultsRef.current = newItems.length === 0;
326
340
 
327
- if (newItems.length > 0) {
328
- let prev = allRef.current;
329
- let prevHash = new Set(prev.map((x) => x.__context.head));
330
- let newItemsNoHash = newItems.filter(
331
- (x) => !prevHash.has(x.__context.head)
341
+ if (newItems.length) {
342
+ log(
343
+ "Loaded more items for iterator",
344
+ iterator.id,
345
+ "current id",
346
+ iteratorRef.current?.id,
347
+ "new items",
348
+ newItems.length,
349
+ "previous results",
350
+ allRef.current.length,
351
+ "batchSize",
352
+ batchSize,
353
+ "items consumed",
354
+ iterator.itemsConsumed
332
355
  );
333
- if (newItemsNoHash.length === 0) {
334
- logWithId(
335
- options,
336
- "no new items after dedup, not updating state. Prev length",
337
- prev.length
338
- );
339
- return;
340
- }
341
- const combined = options?.reverse
342
- ? [...newItemsNoHash.reverse(), ...prev]
343
- : [...prev, ...newItemsNoHash];
344
- updateAll(combined, null);
345
- } else {
346
- logWithId(
347
- options,
348
- "no new items, not updating state for iterator " +
349
- iteratorRef.current?.id +
350
- " existing results length",
351
- allRef.current.length
356
+ const prev = allRef.current;
357
+ const dedup = new Set(
358
+ prev.map((x) => (x as any).__context.head)
352
359
  );
353
- }
354
- } catch (error) {
355
- if (error instanceof ClosedError) {
356
- // Handle closed database gracefully
357
- logWithId(options, "Database closed error");
360
+ const unique = newItems.filter(
361
+ (x) => !dedup.has((x as any).__context.head)
362
+ );
363
+ if (!unique.length) return;
364
+
365
+ const combined = reverseRef.current
366
+ ? [...unique.reverse(), ...prev]
367
+ : [...prev, ...unique];
368
+ updateAll(combined);
358
369
  } else {
359
- throw error;
370
+ log(options, "No new items", iterator.id);
360
371
  }
372
+ return !iterator.iterator.done();
373
+ } catch (e) {
374
+ if (!(e instanceof ClosedError)) throw e;
361
375
  } finally {
362
376
  setIsLoading(false);
363
377
  loadingMoreRef.current = false;
364
378
  }
365
379
  };
366
380
 
367
- return { items: all, loadMore, isLoading, empty: emptyResultsRef.current };
381
+ /* ────────────── public API ────────────── */
382
+ return {
383
+ items: all,
384
+ loadMore,
385
+ isLoading,
386
+ empty: () => emptyResultsRef.current,
387
+ id: id,
388
+ };
368
389
  };