@peerbit/document 9.13.10 → 10.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.
- package/dist/src/program.js +1 -1
- package/dist/src/program.js.map +1 -1
- package/dist/src/resumable-iterator.d.ts +11 -8
- package/dist/src/resumable-iterator.d.ts.map +1 -1
- package/dist/src/resumable-iterator.js +33 -17
- package/dist/src/resumable-iterator.js.map +1 -1
- package/dist/src/search.d.ts +13 -7
- package/dist/src/search.d.ts.map +1 -1
- package/dist/src/search.js +491 -69
- package/dist/src/search.js.map +1 -1
- package/package.json +2 -2
- package/src/program.ts +1 -1
- package/src/resumable-iterator.ts +48 -23
- package/src/search.ts +725 -139
package/dist/src/search.js
CHANGED
|
@@ -25,34 +25,65 @@ import pDefer, {} from "p-defer";
|
|
|
25
25
|
import { concat, fromString } from "uint8arrays";
|
|
26
26
|
import { copySerialization } from "./borsh.js";
|
|
27
27
|
import { MAX_BATCH_SIZE } from "./constants.js";
|
|
28
|
-
import MostCommonQueryPredictor from "./most-common-query-predictor.js";
|
|
28
|
+
import MostCommonQueryPredictor, { idAgnosticQueryKey, } from "./most-common-query-predictor.js";
|
|
29
29
|
import { isPutOperation } from "./operation.js";
|
|
30
30
|
import { Prefetch } from "./prefetch.js";
|
|
31
31
|
import { ResumableIterators } from "./resumable-iterator.js";
|
|
32
32
|
const WARNING_WHEN_ITERATING_FOR_MORE_THAN = 1e5;
|
|
33
33
|
const logger = loggerFn({ module: "document-index" });
|
|
34
|
-
const coerceQuery = (query, options) => {
|
|
35
|
-
|
|
34
|
+
const coerceQuery = (query, options, compatibility) => {
|
|
35
|
+
const replicate = typeof options?.remote !== "boolean" ? options?.remote?.replicate : false;
|
|
36
|
+
const shouldResolve = options?.resolve !== false;
|
|
37
|
+
const useLegacyRequests = compatibility != null && compatibility <= 9;
|
|
36
38
|
if (query instanceof types.SearchRequestIndexed &&
|
|
37
39
|
query.replicate === false &&
|
|
38
40
|
replicate) {
|
|
39
41
|
query.replicate = true;
|
|
40
42
|
return query;
|
|
41
43
|
}
|
|
42
|
-
if (query instanceof types.SearchRequest
|
|
44
|
+
if (query instanceof types.SearchRequest ||
|
|
45
|
+
query instanceof types.SearchRequestIndexed) {
|
|
46
|
+
return query;
|
|
47
|
+
}
|
|
48
|
+
if (query instanceof types.IterationRequest) {
|
|
49
|
+
if (useLegacyRequests) {
|
|
50
|
+
if (query.resolve === false) {
|
|
51
|
+
return new types.SearchRequestIndexed({
|
|
52
|
+
query: query.query,
|
|
53
|
+
sort: query.sort,
|
|
54
|
+
fetch: query.fetch,
|
|
55
|
+
replicate: query.replicate ?? replicate,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return new types.SearchRequest({
|
|
59
|
+
query: query.query,
|
|
60
|
+
sort: query.sort,
|
|
61
|
+
fetch: query.fetch,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
43
64
|
return query;
|
|
44
65
|
}
|
|
45
66
|
const queryObject = query;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
67
|
+
if (useLegacyRequests) {
|
|
68
|
+
if (shouldResolve) {
|
|
69
|
+
return new types.SearchRequest({
|
|
70
|
+
query: indexerTypes.toQuery(queryObject.query),
|
|
71
|
+
sort: indexerTypes.toSort(queryObject.sort),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return new types.SearchRequestIndexed({
|
|
52
75
|
query: indexerTypes.toQuery(queryObject.query),
|
|
53
|
-
sort: indexerTypes.toSort(
|
|
76
|
+
sort: indexerTypes.toSort(queryObject.sort),
|
|
54
77
|
replicate,
|
|
55
78
|
});
|
|
79
|
+
}
|
|
80
|
+
return new types.IterationRequest({
|
|
81
|
+
query: indexerTypes.toQuery(queryObject.query),
|
|
82
|
+
sort: indexerTypes.toSort(queryObject.sort),
|
|
83
|
+
fetch: 10,
|
|
84
|
+
resolve: shouldResolve,
|
|
85
|
+
replicate: shouldResolve ? false : replicate,
|
|
86
|
+
});
|
|
56
87
|
};
|
|
57
88
|
const introduceEntries = async (queryRequest, responses, documentType, indexedType, sync, options) => {
|
|
58
89
|
const results = [];
|
|
@@ -94,6 +125,30 @@ const dedup = (allResult, dedupBy) => {
|
|
|
94
125
|
}
|
|
95
126
|
return dedup;
|
|
96
127
|
};
|
|
128
|
+
const resolvesDocuments = (req) => {
|
|
129
|
+
if (!req) {
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
if (req instanceof types.SearchRequestIndexed) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
if (req instanceof types.IterationRequest) {
|
|
136
|
+
return req.resolve !== false;
|
|
137
|
+
}
|
|
138
|
+
return true;
|
|
139
|
+
};
|
|
140
|
+
const replicatesIndex = (req) => {
|
|
141
|
+
if (!req) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
if (req instanceof types.SearchRequestIndexed) {
|
|
145
|
+
return req.replicate === true;
|
|
146
|
+
}
|
|
147
|
+
if (req instanceof types.IterationRequest) {
|
|
148
|
+
return req.replicate === true;
|
|
149
|
+
}
|
|
150
|
+
return false;
|
|
151
|
+
};
|
|
97
152
|
function isSubclassOf(SubClass, SuperClass) {
|
|
98
153
|
// Start with the immediate parent of SubClass
|
|
99
154
|
let proto = Object.getPrototypeOf(SubClass);
|
|
@@ -106,6 +161,7 @@ function isSubclassOf(SubClass, SuperClass) {
|
|
|
106
161
|
return false;
|
|
107
162
|
}
|
|
108
163
|
const DEFAULT_TIMEOUT = 1e4;
|
|
164
|
+
const DISCOVER_TIMEOUT_FALLBACK = 500;
|
|
109
165
|
const DEFAULT_INDEX_BY = "id";
|
|
110
166
|
const isTransformerWithFunction = (options) => {
|
|
111
167
|
return options.transform != null;
|
|
@@ -154,9 +210,11 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
154
210
|
documentEvents;
|
|
155
211
|
_joinListener;
|
|
156
212
|
_resultQueue;
|
|
213
|
+
iteratorKeepAliveTimers;
|
|
157
214
|
constructor(properties) {
|
|
158
215
|
super();
|
|
159
216
|
this._query = properties?.query || new RPC();
|
|
217
|
+
this.iteratorKeepAliveTimers = new Map();
|
|
160
218
|
}
|
|
161
219
|
get valueEncoding() {
|
|
162
220
|
return this._valueEncoding;
|
|
@@ -317,7 +375,8 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
317
375
|
}
|
|
318
376
|
if (this.prefetch?.predictor &&
|
|
319
377
|
(query instanceof types.SearchRequest ||
|
|
320
|
-
query instanceof types.SearchRequestIndexed
|
|
378
|
+
query instanceof types.SearchRequestIndexed ||
|
|
379
|
+
query instanceof types.IterationRequest)) {
|
|
321
380
|
const { ignore } = this.prefetch.predictor.onRequest(query, {
|
|
322
381
|
from: ctx.from,
|
|
323
382
|
});
|
|
@@ -334,6 +393,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
334
393
|
async handleSearchRequest(query, ctx) {
|
|
335
394
|
if (this.canSearch &&
|
|
336
395
|
(query instanceof types.SearchRequest ||
|
|
396
|
+
query instanceof types.IterationRequest ||
|
|
337
397
|
query instanceof types.CollectNextRequest) &&
|
|
338
398
|
!(await this.canSearch(query, ctx.from))) {
|
|
339
399
|
return new types.NoAccess();
|
|
@@ -342,11 +402,13 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
342
402
|
this.processCloseIteratorRequest(query, ctx.from);
|
|
343
403
|
}
|
|
344
404
|
else {
|
|
345
|
-
const
|
|
346
|
-
(query
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
405
|
+
const fromQueued = query instanceof types.CollectNextRequest
|
|
406
|
+
? this._resultQueue.get(query.idString)?.fromQuery
|
|
407
|
+
: undefined;
|
|
408
|
+
const queryResolvesDocuments = query instanceof types.CollectNextRequest
|
|
409
|
+
? resolvesDocuments(fromQueued)
|
|
410
|
+
: resolvesDocuments(query);
|
|
411
|
+
const shouldIncludedIndexedResults = this.includeIndexed && queryResolvesDocuments;
|
|
350
412
|
const results = await this.processQuery(query, ctx.from, false, {
|
|
351
413
|
canRead: this.canRead,
|
|
352
414
|
});
|
|
@@ -585,22 +647,29 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
585
647
|
};
|
|
586
648
|
}
|
|
587
649
|
let results;
|
|
650
|
+
const runAndClose = async (req) => {
|
|
651
|
+
const response = await this.queryCommence(req, coercedOptions);
|
|
652
|
+
this._resumableIterators.close({ idString: req.idString });
|
|
653
|
+
this.cancelIteratorKeepAlive(req.idString);
|
|
654
|
+
return response;
|
|
655
|
+
};
|
|
588
656
|
const resolve = coercedOptions?.resolve || coercedOptions?.resolve == null;
|
|
589
657
|
let requestClazz = resolve
|
|
590
658
|
? types.SearchRequest
|
|
591
659
|
: types.SearchRequestIndexed;
|
|
592
660
|
if (key instanceof Uint8Array) {
|
|
593
|
-
|
|
661
|
+
const request = new requestClazz({
|
|
594
662
|
query: [
|
|
595
663
|
new indexerTypes.ByteMatchQuery({ key: this.indexBy, value: key }),
|
|
596
664
|
],
|
|
597
|
-
})
|
|
665
|
+
});
|
|
666
|
+
results = await runAndClose(request);
|
|
598
667
|
}
|
|
599
668
|
else {
|
|
600
669
|
const indexableKey = indexerTypes.toIdeable(key);
|
|
601
670
|
if (typeof indexableKey === "number" ||
|
|
602
671
|
typeof indexableKey === "bigint") {
|
|
603
|
-
|
|
672
|
+
const request = new requestClazz({
|
|
604
673
|
query: [
|
|
605
674
|
new indexerTypes.IntegerCompare({
|
|
606
675
|
key: this.indexBy,
|
|
@@ -608,27 +677,44 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
608
677
|
value: indexableKey,
|
|
609
678
|
}),
|
|
610
679
|
],
|
|
611
|
-
})
|
|
680
|
+
});
|
|
681
|
+
results = await runAndClose(request);
|
|
612
682
|
}
|
|
613
683
|
else if (typeof indexableKey === "string") {
|
|
614
|
-
|
|
684
|
+
const request = new requestClazz({
|
|
615
685
|
query: [
|
|
616
686
|
new indexerTypes.StringMatch({
|
|
617
687
|
key: this.indexBy,
|
|
618
688
|
value: indexableKey,
|
|
619
689
|
}),
|
|
620
690
|
],
|
|
621
|
-
})
|
|
691
|
+
});
|
|
692
|
+
results = await runAndClose(request);
|
|
622
693
|
}
|
|
623
694
|
else if (indexableKey instanceof Uint8Array) {
|
|
624
|
-
|
|
695
|
+
const request = new requestClazz({
|
|
625
696
|
query: [
|
|
626
697
|
new indexerTypes.ByteMatchQuery({
|
|
627
698
|
key: this.indexBy,
|
|
628
699
|
value: indexableKey,
|
|
629
700
|
}),
|
|
630
701
|
],
|
|
631
|
-
})
|
|
702
|
+
});
|
|
703
|
+
results = await runAndClose(request);
|
|
704
|
+
}
|
|
705
|
+
else if (indexableKey instanceof ArrayBuffer) {
|
|
706
|
+
const request = new requestClazz({
|
|
707
|
+
query: [
|
|
708
|
+
new indexerTypes.ByteMatchQuery({
|
|
709
|
+
key: this.indexBy,
|
|
710
|
+
value: new Uint8Array(indexableKey),
|
|
711
|
+
}),
|
|
712
|
+
],
|
|
713
|
+
});
|
|
714
|
+
results = await runAndClose(request);
|
|
715
|
+
}
|
|
716
|
+
else {
|
|
717
|
+
throw new Error("Unsupported key type");
|
|
632
718
|
}
|
|
633
719
|
}
|
|
634
720
|
// if we are to resolve the document we need to go through all results and replace the results with the resolved values
|
|
@@ -711,23 +797,42 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
711
797
|
}
|
|
712
798
|
let indexedResult = undefined;
|
|
713
799
|
let fromQuery;
|
|
800
|
+
let keepAliveRequest;
|
|
714
801
|
if (query instanceof types.SearchRequest ||
|
|
715
|
-
query instanceof types.SearchRequestIndexed
|
|
802
|
+
query instanceof types.SearchRequestIndexed ||
|
|
803
|
+
query instanceof types.IterationRequest) {
|
|
716
804
|
fromQuery = query;
|
|
717
|
-
|
|
805
|
+
if (!isLocal &&
|
|
806
|
+
query instanceof types.IterationRequest &&
|
|
807
|
+
query.keepAliveTtl != null) {
|
|
808
|
+
keepAliveRequest = query;
|
|
809
|
+
}
|
|
810
|
+
indexedResult = await this._resumableIterators.iterateAndFetch(query, {
|
|
811
|
+
keepAlive: keepAliveRequest !== undefined,
|
|
812
|
+
});
|
|
718
813
|
}
|
|
719
814
|
else if (query instanceof types.CollectNextRequest) {
|
|
720
|
-
fromQuery
|
|
721
|
-
|
|
722
|
-
|
|
815
|
+
const cachedRequest = prevQueued?.fromQuery ||
|
|
816
|
+
this._resumableIterators.queues.get(query.idString)?.request;
|
|
817
|
+
fromQuery = cachedRequest;
|
|
818
|
+
if (!isLocal &&
|
|
819
|
+
cachedRequest instanceof types.IterationRequest &&
|
|
820
|
+
cachedRequest.keepAliveTtl != null) {
|
|
821
|
+
keepAliveRequest = cachedRequest;
|
|
822
|
+
}
|
|
723
823
|
indexedResult =
|
|
724
824
|
prevQueued?.keptInIndex === 0
|
|
725
825
|
? []
|
|
726
|
-
: await this._resumableIterators.next(query
|
|
826
|
+
: await this._resumableIterators.next(query, {
|
|
827
|
+
keepAlive: keepAliveRequest !== undefined,
|
|
828
|
+
});
|
|
727
829
|
}
|
|
728
830
|
else {
|
|
729
831
|
throw new Error("Unsupported");
|
|
730
832
|
}
|
|
833
|
+
if (!isLocal && keepAliveRequest) {
|
|
834
|
+
this.scheduleIteratorKeepAlive(query.idString, keepAliveRequest.keepAliveTtl);
|
|
835
|
+
}
|
|
731
836
|
let resultSize = 0;
|
|
732
837
|
let toIterate = prevQueued
|
|
733
838
|
? [...prevQueued.queue, ...indexedResult]
|
|
@@ -751,6 +856,8 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
751
856
|
this._resultQueue.set(query.idString, prevQueued);
|
|
752
857
|
}
|
|
753
858
|
const filteredResults = [];
|
|
859
|
+
const resolveDocumentsFlag = resolvesDocuments(fromQuery);
|
|
860
|
+
const replicateIndexFlag = replicatesIndex(fromQuery);
|
|
754
861
|
for (const result of toIterate) {
|
|
755
862
|
if (!isLocal) {
|
|
756
863
|
resultSize += result.value.__context.size;
|
|
@@ -764,7 +871,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
764
871
|
!(await options.canRead(indexedUnwrapped, from))) {
|
|
765
872
|
continue;
|
|
766
873
|
}
|
|
767
|
-
if (
|
|
874
|
+
if (resolveDocumentsFlag) {
|
|
768
875
|
const value = await this.resolveDocument({
|
|
769
876
|
indexed: result.value,
|
|
770
877
|
head: result.value.__context.head,
|
|
@@ -779,11 +886,11 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
779
886
|
indexed: indexedUnwrapped,
|
|
780
887
|
}));
|
|
781
888
|
}
|
|
782
|
-
else
|
|
889
|
+
else {
|
|
783
890
|
const context = result.value.__context;
|
|
784
891
|
const head = await this._log.log.get(context.head);
|
|
785
892
|
// assume remote peer will start to replicate (TODO is this ideal?)
|
|
786
|
-
if (
|
|
893
|
+
if (replicateIndexFlag) {
|
|
787
894
|
this._log.addPeersToGidPeerHistory(context.gid, [from.hashcode()]);
|
|
788
895
|
}
|
|
789
896
|
filteredResults.push(new types.ResultIndexedValue({
|
|
@@ -798,11 +905,53 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
798
905
|
results: filteredResults,
|
|
799
906
|
kept: BigInt(kept + (prevQueued?.queue.length || 0)),
|
|
800
907
|
});
|
|
908
|
+
/* console.debug("[DocumentIndex] processQuery", {
|
|
909
|
+
id: query.idString,
|
|
910
|
+
isLocal,
|
|
911
|
+
batchLength: filteredResults.length,
|
|
912
|
+
kept: results.kept,
|
|
913
|
+
source: from.hashcode(),
|
|
914
|
+
}); */
|
|
801
915
|
if (!isLocal && results.kept === 0n) {
|
|
802
916
|
this.clearResultsQueue(query);
|
|
803
917
|
}
|
|
804
918
|
return results;
|
|
805
919
|
}
|
|
920
|
+
scheduleIteratorKeepAlive(idString, ttl) {
|
|
921
|
+
if (ttl == null) {
|
|
922
|
+
return;
|
|
923
|
+
}
|
|
924
|
+
const ttlNumber = Number(ttl);
|
|
925
|
+
if (!Number.isFinite(ttlNumber) || ttlNumber <= 0) {
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
928
|
+
// Cap max timeout to 1 day (TODO make configurable?)
|
|
929
|
+
const delay = Math.max(1, Math.min(ttlNumber, 86400000));
|
|
930
|
+
this.cancelIteratorKeepAlive(idString);
|
|
931
|
+
const timers = this.iteratorKeepAliveTimers ??
|
|
932
|
+
(this.iteratorKeepAliveTimers = new Map());
|
|
933
|
+
const timer = setTimeout(() => {
|
|
934
|
+
timers.delete(idString);
|
|
935
|
+
const queued = this._resultQueue.get(idString);
|
|
936
|
+
if (queued) {
|
|
937
|
+
clearTimeout(queued.timeout);
|
|
938
|
+
this._resultQueue.delete(idString);
|
|
939
|
+
}
|
|
940
|
+
this._resumableIterators.close({ idString });
|
|
941
|
+
}, delay);
|
|
942
|
+
timers.set(idString, timer);
|
|
943
|
+
}
|
|
944
|
+
cancelIteratorKeepAlive(idString) {
|
|
945
|
+
const timers = this.iteratorKeepAliveTimers;
|
|
946
|
+
if (!timers) {
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
const timer = timers.get(idString);
|
|
950
|
+
if (timer) {
|
|
951
|
+
clearTimeout(timer);
|
|
952
|
+
timers.delete(idString);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
806
955
|
clearResultsQueue(query) {
|
|
807
956
|
const queue = this._resultQueue.get(query.idString);
|
|
808
957
|
if (queue) {
|
|
@@ -817,6 +966,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
817
966
|
for (const [key, queue] of this._resultQueue) {
|
|
818
967
|
clearTimeout(queue.timeout);
|
|
819
968
|
this._resultQueue.delete(key);
|
|
969
|
+
this.cancelIteratorKeepAlive(key);
|
|
820
970
|
this._resumableIterators.close({ idString: key });
|
|
821
971
|
}
|
|
822
972
|
}
|
|
@@ -950,6 +1100,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
950
1100
|
logger.info("Ignoring close iterator request from different peer");
|
|
951
1101
|
return;
|
|
952
1102
|
}
|
|
1103
|
+
this.cancelIteratorKeepAlive(query.idString);
|
|
953
1104
|
this.clearResultsQueue(query);
|
|
954
1105
|
return this._resumableIterators.close(query);
|
|
955
1106
|
}
|
|
@@ -1126,7 +1277,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
1126
1277
|
*/
|
|
1127
1278
|
async search(queryRequest, options) {
|
|
1128
1279
|
// Set fetch to search size, or max value (default to max u32 (4294967295))
|
|
1129
|
-
const coercedRequest = coerceQuery(queryRequest, options);
|
|
1280
|
+
const coercedRequest = coerceQuery(queryRequest, options, this.compatibility);
|
|
1130
1281
|
coercedRequest.fetch = coercedRequest.fetch ?? 0xffffffff;
|
|
1131
1282
|
// So that the iterator is pre-fetching the right amount of entries
|
|
1132
1283
|
const iterator = this.iterate(coercedRequest, options);
|
|
@@ -1168,19 +1319,42 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
1168
1319
|
/**
|
|
1169
1320
|
* Query and retrieve documents in a iterator
|
|
1170
1321
|
* @param queryRequest
|
|
1171
|
-
* @param
|
|
1322
|
+
* @param optionsArg
|
|
1172
1323
|
* @returns
|
|
1173
1324
|
*/
|
|
1174
|
-
iterate(queryRequest,
|
|
1325
|
+
iterate(queryRequest, optionsArg) {
|
|
1326
|
+
let options = optionsArg;
|
|
1175
1327
|
if (queryRequest instanceof types.SearchRequest &&
|
|
1176
1328
|
options?.resolve === false) {
|
|
1177
1329
|
throw new Error("Cannot use resolve=false with SearchRequest"); // TODO make this work
|
|
1178
1330
|
}
|
|
1179
|
-
let queryRequestCoerced = coerceQuery(queryRequest ?? {}, options);
|
|
1331
|
+
let queryRequestCoerced = coerceQuery(queryRequest ?? {}, options, this.compatibility);
|
|
1332
|
+
const { mergePolicy, push: pushUpdates, callbacks: updateCallbacksRaw, } = normalizeUpdatesOption(options?.updates);
|
|
1333
|
+
const hasLiveUpdates = mergePolicy !== undefined;
|
|
1334
|
+
const originalRemote = options?.remote;
|
|
1335
|
+
let remoteOptions = typeof originalRemote === "boolean"
|
|
1336
|
+
? originalRemote
|
|
1337
|
+
: originalRemote
|
|
1338
|
+
? { ...originalRemote }
|
|
1339
|
+
: undefined;
|
|
1340
|
+
if (pushUpdates && remoteOptions !== false) {
|
|
1341
|
+
if (typeof remoteOptions === "object") {
|
|
1342
|
+
if (remoteOptions.replicate !== true) {
|
|
1343
|
+
remoteOptions.replicate = true;
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
else if (remoteOptions === undefined || remoteOptions === true) {
|
|
1347
|
+
remoteOptions = { replicate: true };
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
if (remoteOptions !== originalRemote) {
|
|
1351
|
+
options = Object.assign({}, options, { remote: remoteOptions });
|
|
1352
|
+
}
|
|
1180
1353
|
let resolve = options?.resolve !== false;
|
|
1181
|
-
if (
|
|
1354
|
+
if (!(queryRequestCoerced instanceof types.IterationRequest) &&
|
|
1355
|
+
options?.remote &&
|
|
1182
1356
|
typeof options.remote !== "boolean" &&
|
|
1183
|
-
options.remote.replicate &&
|
|
1357
|
+
(options.remote.replicate || pushUpdates) &&
|
|
1184
1358
|
options?.resolve !== false) {
|
|
1185
1359
|
if ((queryRequest instanceof types.SearchRequestIndexed === false &&
|
|
1186
1360
|
this.compatibility == null) ||
|
|
@@ -1195,7 +1369,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
1195
1369
|
}
|
|
1196
1370
|
let replicate = options?.remote &&
|
|
1197
1371
|
typeof options.remote !== "boolean" &&
|
|
1198
|
-
options.remote.replicate;
|
|
1372
|
+
(options.remote.replicate || pushUpdates);
|
|
1199
1373
|
if (replicate &&
|
|
1200
1374
|
queryRequestCoerced instanceof types.SearchRequestIndexed) {
|
|
1201
1375
|
queryRequestCoerced.replicate = true;
|
|
@@ -1237,6 +1411,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
1237
1411
|
this.clearResultsQueue(queryRequestCoerced);
|
|
1238
1412
|
};
|
|
1239
1413
|
let warmupPromise = undefined;
|
|
1414
|
+
let discoveredTargetHashes;
|
|
1240
1415
|
if (typeof options?.remote === "object") {
|
|
1241
1416
|
let waitForTime = undefined;
|
|
1242
1417
|
if (options.remote.wait) {
|
|
@@ -1271,11 +1446,25 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
1271
1446
|
};
|
|
1272
1447
|
}
|
|
1273
1448
|
if (options.remote.reach?.discover) {
|
|
1274
|
-
|
|
1449
|
+
const discoverTimeout = waitForTime ??
|
|
1450
|
+
(options.remote.wait ? DEFAULT_TIMEOUT : DISCOVER_TIMEOUT_FALLBACK);
|
|
1451
|
+
const discoverPromise = this.waitFor(options.remote.reach.discover, {
|
|
1275
1452
|
signal: ensureController().signal,
|
|
1276
1453
|
seek: "present",
|
|
1277
|
-
timeout:
|
|
1454
|
+
timeout: discoverTimeout,
|
|
1455
|
+
})
|
|
1456
|
+
.then((hashes) => {
|
|
1457
|
+
discoveredTargetHashes = hashes;
|
|
1458
|
+
})
|
|
1459
|
+
.catch((error) => {
|
|
1460
|
+
if (error instanceof TimeoutError || error instanceof AbortError) {
|
|
1461
|
+
discoveredTargetHashes = [];
|
|
1462
|
+
return;
|
|
1463
|
+
}
|
|
1464
|
+
throw error;
|
|
1278
1465
|
});
|
|
1466
|
+
const prior = warmupPromise ?? Promise.resolve();
|
|
1467
|
+
warmupPromise = prior.then(() => discoverPromise);
|
|
1279
1468
|
options.remote.reach.eager = true; // include the results from the discovered peer even if it is not mature
|
|
1280
1469
|
}
|
|
1281
1470
|
const waitPolicy = typeof options.remote.wait === "object"
|
|
@@ -1299,15 +1488,24 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
1299
1488
|
const fetchFirst = async (n, fetchOptions) => {
|
|
1300
1489
|
await warmupPromise;
|
|
1301
1490
|
let hasMore = false;
|
|
1491
|
+
const discoverTargets = typeof options?.remote === "object"
|
|
1492
|
+
? options.remote.reach?.discover
|
|
1493
|
+
: undefined;
|
|
1494
|
+
const initialRemoteTargets = discoveredTargetHashes !== undefined
|
|
1495
|
+
? discoveredTargetHashes
|
|
1496
|
+
: discoverTargets?.map((pk) => pk.hashcode().toString());
|
|
1497
|
+
const skipRemoteDueToDiscovery = typeof options?.remote === "object" &&
|
|
1498
|
+
options.remote.reach?.discover &&
|
|
1499
|
+
discoveredTargetHashes?.length === 0;
|
|
1302
1500
|
queryRequestCoerced.fetch = n;
|
|
1303
1501
|
await this.queryCommence(queryRequestCoerced, {
|
|
1304
1502
|
local: fetchOptions?.from != null ? false : options?.local,
|
|
1305
|
-
remote: options?.remote !== false
|
|
1503
|
+
remote: options?.remote !== false && !skipRemoteDueToDiscovery
|
|
1306
1504
|
? {
|
|
1307
1505
|
...(typeof options?.remote === "object"
|
|
1308
1506
|
? options.remote
|
|
1309
1507
|
: {}),
|
|
1310
|
-
from: fetchOptions?.from,
|
|
1508
|
+
from: fetchOptions?.from ?? initialRemoteTargets,
|
|
1311
1509
|
}
|
|
1312
1510
|
: false,
|
|
1313
1511
|
resolve,
|
|
@@ -1322,13 +1520,20 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
1322
1520
|
}
|
|
1323
1521
|
else if (response instanceof types.Results) {
|
|
1324
1522
|
const results = response;
|
|
1523
|
+
const existingBuffer = peerBufferMap.get(from.hashcode());
|
|
1524
|
+
const buffer = existingBuffer?.buffer || [];
|
|
1325
1525
|
if (results.kept === 0n && results.results.length === 0) {
|
|
1526
|
+
if (keepRemoteAlive) {
|
|
1527
|
+
peerBufferMap.set(from.hashcode(), {
|
|
1528
|
+
buffer,
|
|
1529
|
+
kept: Number(response.kept),
|
|
1530
|
+
});
|
|
1531
|
+
}
|
|
1326
1532
|
return;
|
|
1327
1533
|
}
|
|
1328
1534
|
if (results.kept > 0n) {
|
|
1329
1535
|
hasMore = true;
|
|
1330
1536
|
}
|
|
1331
|
-
const buffer = peerBufferMap.get(from.hashcode())?.buffer || [];
|
|
1332
1537
|
for (const result of results.results) {
|
|
1333
1538
|
const indexKey = indexerTypes.toId(this.indexByResolver(result.value)).primitive;
|
|
1334
1539
|
if (result instanceof types.ResultValue) {
|
|
@@ -1380,6 +1585,15 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
1380
1585
|
}
|
|
1381
1586
|
},
|
|
1382
1587
|
}, fetchOptions?.fetchedFirstForRemote);
|
|
1588
|
+
/* console.debug(
|
|
1589
|
+
"[DocumentIndex] fetchFirst",
|
|
1590
|
+
{
|
|
1591
|
+
id: queryRequestCoerced.idString,
|
|
1592
|
+
requestedFrom: fetchOptions?.from,
|
|
1593
|
+
initialRemoteTargets,
|
|
1594
|
+
keepRemoteAlive,
|
|
1595
|
+
},
|
|
1596
|
+
); */
|
|
1383
1597
|
if (!hasMore) {
|
|
1384
1598
|
maybeSetDone();
|
|
1385
1599
|
}
|
|
@@ -1403,7 +1617,8 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
1403
1617
|
let resultsLeft = 0;
|
|
1404
1618
|
for (const [peer, buffer] of peerBufferMap) {
|
|
1405
1619
|
if (buffer.buffer.length < n) {
|
|
1406
|
-
|
|
1620
|
+
const hasExistingRemoteResults = buffer.kept > 0;
|
|
1621
|
+
if (!hasExistingRemoteResults && !keepRemoteAlive) {
|
|
1407
1622
|
if (peerBufferMap.get(peer)?.buffer.length === 0) {
|
|
1408
1623
|
peerBufferMap.delete(peer); // No more results
|
|
1409
1624
|
}
|
|
@@ -1411,9 +1626,21 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
1411
1626
|
}
|
|
1412
1627
|
// TODO buffer more than deleted?
|
|
1413
1628
|
// TODO batch to multiple 'to's
|
|
1629
|
+
const lacking = n - buffer.buffer.length;
|
|
1630
|
+
const amount = lacking > 0 ? lacking : keepRemoteAlive ? 1 : 0;
|
|
1631
|
+
/* console.debug("[DocumentIndex] fetchAtLeast loop", {
|
|
1632
|
+
peer,
|
|
1633
|
+
bufferLength: buffer.buffer.length,
|
|
1634
|
+
bufferKept: buffer.kept,
|
|
1635
|
+
amount,
|
|
1636
|
+
keepRemoteAlive,
|
|
1637
|
+
}); */
|
|
1638
|
+
if (amount <= 0) {
|
|
1639
|
+
continue;
|
|
1640
|
+
}
|
|
1414
1641
|
const collectRequest = new types.CollectNextRequest({
|
|
1415
1642
|
id: queryRequestCoerced.id,
|
|
1416
|
-
amount
|
|
1643
|
+
amount,
|
|
1417
1644
|
});
|
|
1418
1645
|
// Fetch locally?
|
|
1419
1646
|
if (peer === this.node.identity.publicKey.hashcode()) {
|
|
@@ -1424,7 +1651,8 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
1424
1651
|
.then(async (results) => {
|
|
1425
1652
|
resultsLeft += Number(results.kept);
|
|
1426
1653
|
if (results.results.length === 0) {
|
|
1427
|
-
if (
|
|
1654
|
+
if (!keepRemoteAlive &&
|
|
1655
|
+
peerBufferMap.get(peer)?.buffer.length === 0) {
|
|
1428
1656
|
peerBufferMap.delete(peer); // No more results
|
|
1429
1657
|
}
|
|
1430
1658
|
}
|
|
@@ -1516,7 +1744,8 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
1516
1744
|
return;
|
|
1517
1745
|
}
|
|
1518
1746
|
if (response.response.results.length === 0) {
|
|
1519
|
-
if (
|
|
1747
|
+
if (!keepRemoteAlive &&
|
|
1748
|
+
peerBufferMap.get(peer)?.buffer.length === 0) {
|
|
1520
1749
|
peerBufferMap.delete(peer); // No more results
|
|
1521
1750
|
}
|
|
1522
1751
|
}
|
|
@@ -1684,32 +1913,75 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
1684
1913
|
let joinListener;
|
|
1685
1914
|
let fetchedFirstForRemote = undefined;
|
|
1686
1915
|
let updateDeferred;
|
|
1687
|
-
const signalUpdate = () =>
|
|
1916
|
+
const signalUpdate = (reason) => {
|
|
1917
|
+
if (reason) {
|
|
1918
|
+
/* console.debug("[DocumentIndex] signalUpdate", {
|
|
1919
|
+
id: queryRequestCoerced.idString,
|
|
1920
|
+
reason,
|
|
1921
|
+
}); */
|
|
1922
|
+
}
|
|
1923
|
+
updateDeferred?.resolve();
|
|
1924
|
+
};
|
|
1688
1925
|
const _waitForUpdate = () => updateDeferred ? updateDeferred.promise : Promise.resolve();
|
|
1689
1926
|
// ---------------- Live updates wiring (sorted-only with optional filter) ----------------
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1927
|
+
function normalizeUpdatesOption(u) {
|
|
1928
|
+
const identityFilter = (evt) => evt;
|
|
1929
|
+
const buildMergePolicy = (merge, defaultEnabled) => {
|
|
1930
|
+
const effective = merge === undefined ? (defaultEnabled ? true : undefined) : merge;
|
|
1931
|
+
if (effective === undefined || effective === false) {
|
|
1932
|
+
return undefined;
|
|
1933
|
+
}
|
|
1934
|
+
if (effective === true) {
|
|
1935
|
+
return {
|
|
1936
|
+
merge: {
|
|
1937
|
+
filter: identityFilter,
|
|
1938
|
+
},
|
|
1939
|
+
};
|
|
1940
|
+
}
|
|
1694
1941
|
return {
|
|
1695
1942
|
merge: {
|
|
1696
|
-
filter:
|
|
1943
|
+
filter: effective.filter ?? identityFilter,
|
|
1697
1944
|
},
|
|
1698
1945
|
};
|
|
1946
|
+
};
|
|
1947
|
+
if (u == null || u === false) {
|
|
1948
|
+
return { push: false };
|
|
1949
|
+
}
|
|
1950
|
+
if (u === true) {
|
|
1951
|
+
return {
|
|
1952
|
+
mergePolicy: buildMergePolicy(true, true),
|
|
1953
|
+
push: false,
|
|
1954
|
+
};
|
|
1955
|
+
}
|
|
1956
|
+
if (typeof u === "string") {
|
|
1957
|
+
if (u === "remote") {
|
|
1958
|
+
return { push: true };
|
|
1959
|
+
}
|
|
1960
|
+
if (u === "local") {
|
|
1961
|
+
return {
|
|
1962
|
+
mergePolicy: buildMergePolicy(true, true),
|
|
1963
|
+
push: false,
|
|
1964
|
+
};
|
|
1965
|
+
}
|
|
1966
|
+
if (u === "all") {
|
|
1967
|
+
return {
|
|
1968
|
+
mergePolicy: buildMergePolicy(true, true),
|
|
1969
|
+
push: true,
|
|
1970
|
+
};
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1699
1973
|
if (typeof u === "object") {
|
|
1974
|
+
const hasMergeProp = Object.prototype.hasOwnProperty.call(u, "merge");
|
|
1975
|
+
const mergeValue = hasMergeProp ? u.merge : undefined;
|
|
1700
1976
|
return {
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
}
|
|
1705
|
-
: {},
|
|
1977
|
+
mergePolicy: buildMergePolicy(mergeValue, !hasMergeProp || mergeValue === undefined),
|
|
1978
|
+
push: Boolean(u.push),
|
|
1979
|
+
callbacks: u,
|
|
1706
1980
|
};
|
|
1707
1981
|
}
|
|
1708
|
-
return
|
|
1709
|
-
}
|
|
1710
|
-
const updateCallbacks =
|
|
1711
|
-
const mergePolicy = normalizeUpdatesOption(options?.updates);
|
|
1712
|
-
const hasLiveUpdates = mergePolicy !== undefined;
|
|
1982
|
+
return { push: false };
|
|
1983
|
+
}
|
|
1984
|
+
const updateCallbacks = updateCallbacksRaw;
|
|
1713
1985
|
let pendingResultsReason;
|
|
1714
1986
|
let hasDeliveredResults = false;
|
|
1715
1987
|
const emitOnResults = async (batch, defaultReason) => {
|
|
@@ -1735,6 +2007,130 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
1735
2007
|
if (hasLiveUpdates && !updateDeferred) {
|
|
1736
2008
|
updateDeferred = pDefer();
|
|
1737
2009
|
}
|
|
2010
|
+
const keepRemoteAlive = (options?.closePolicy === "manual" || hasLiveUpdates || pushUpdates) &&
|
|
2011
|
+
remoteOptions !== false;
|
|
2012
|
+
if (queryRequestCoerced instanceof types.IterationRequest) {
|
|
2013
|
+
queryRequestCoerced.resolve = resolve;
|
|
2014
|
+
queryRequestCoerced.fetch = queryRequestCoerced.fetch ?? 10;
|
|
2015
|
+
const replicateFlag = !resolve && replicate ? true : false;
|
|
2016
|
+
queryRequestCoerced.replicate = replicateFlag;
|
|
2017
|
+
const ttlSource = typeof remoteOptions === "object" &&
|
|
2018
|
+
typeof remoteOptions?.wait === "object"
|
|
2019
|
+
? (remoteOptions.wait.timeout ?? DEFAULT_TIMEOUT)
|
|
2020
|
+
: DEFAULT_TIMEOUT;
|
|
2021
|
+
queryRequestCoerced.keepAliveTtl = keepRemoteAlive
|
|
2022
|
+
? BigInt(ttlSource)
|
|
2023
|
+
: undefined;
|
|
2024
|
+
queryRequestCoerced.pushUpdates = pushUpdates ? true : undefined;
|
|
2025
|
+
queryRequestCoerced.mergeUpdates = mergePolicy?.merge ? true : undefined;
|
|
2026
|
+
}
|
|
2027
|
+
if (pushUpdates && this.prefetch?.accumulator) {
|
|
2028
|
+
const targetPrefetchKey = idAgnosticQueryKey(queryRequestCoerced);
|
|
2029
|
+
const mergePrefetchedResults = async (from, results) => {
|
|
2030
|
+
const peerHash = from.hashcode();
|
|
2031
|
+
const existingBuffer = peerBufferMap.get(peerHash);
|
|
2032
|
+
const buffer = existingBuffer?.buffer || [];
|
|
2033
|
+
if (results.kept === 0n && results.results.length === 0) {
|
|
2034
|
+
peerBufferMap.set(peerHash, {
|
|
2035
|
+
buffer,
|
|
2036
|
+
kept: Number(results.kept),
|
|
2037
|
+
});
|
|
2038
|
+
return;
|
|
2039
|
+
}
|
|
2040
|
+
for (const result of results.results) {
|
|
2041
|
+
const indexKey = indexerTypes.toId(this.indexByResolver(result.value)).primitive;
|
|
2042
|
+
if (result instanceof types.ResultValue) {
|
|
2043
|
+
const existingIndexed = indexedPlaceholders?.get(indexKey);
|
|
2044
|
+
if (existingIndexed) {
|
|
2045
|
+
existingIndexed.value =
|
|
2046
|
+
result.value;
|
|
2047
|
+
existingIndexed.context = result.context;
|
|
2048
|
+
existingIndexed.from = from;
|
|
2049
|
+
existingIndexed.indexed = await this.resolveIndexed(result, results.results);
|
|
2050
|
+
indexedPlaceholders?.delete(indexKey);
|
|
2051
|
+
continue;
|
|
2052
|
+
}
|
|
2053
|
+
if (visited.has(indexKey)) {
|
|
2054
|
+
continue;
|
|
2055
|
+
}
|
|
2056
|
+
visited.add(indexKey);
|
|
2057
|
+
buffer.push({
|
|
2058
|
+
value: result.value,
|
|
2059
|
+
context: result.context,
|
|
2060
|
+
from,
|
|
2061
|
+
indexed: await this.resolveIndexed(result, results.results),
|
|
2062
|
+
});
|
|
2063
|
+
}
|
|
2064
|
+
else {
|
|
2065
|
+
if (visited.has(indexKey) && !indexedPlaceholders?.has(indexKey)) {
|
|
2066
|
+
continue;
|
|
2067
|
+
}
|
|
2068
|
+
visited.add(indexKey);
|
|
2069
|
+
const indexed = coerceWithContext(result.indexed || result.value, result.context);
|
|
2070
|
+
const placeholder = {
|
|
2071
|
+
value: result.value,
|
|
2072
|
+
context: result.context,
|
|
2073
|
+
from,
|
|
2074
|
+
indexed,
|
|
2075
|
+
};
|
|
2076
|
+
buffer.push(placeholder);
|
|
2077
|
+
ensureIndexedPlaceholders().set(indexKey, placeholder);
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
peerBufferMap.set(peerHash, {
|
|
2081
|
+
buffer,
|
|
2082
|
+
kept: Number(results.kept),
|
|
2083
|
+
});
|
|
2084
|
+
};
|
|
2085
|
+
const consumePrefetch = async (consumable) => {
|
|
2086
|
+
const request = consumable.response?.request;
|
|
2087
|
+
if (!request) {
|
|
2088
|
+
return;
|
|
2089
|
+
}
|
|
2090
|
+
if (idAgnosticQueryKey(request) !== targetPrefetchKey) {
|
|
2091
|
+
return;
|
|
2092
|
+
}
|
|
2093
|
+
/* console.debug("[DocumentIndex] prefetch match", {
|
|
2094
|
+
iterator: queryRequestCoerced.idString,
|
|
2095
|
+
source: consumable.from?.hashcode(),
|
|
2096
|
+
});
|
|
2097
|
+
*/
|
|
2098
|
+
try {
|
|
2099
|
+
const prepared = await introduceEntries(queryRequestCoerced, [
|
|
2100
|
+
{
|
|
2101
|
+
response: consumable.response.results,
|
|
2102
|
+
from: consumable.from,
|
|
2103
|
+
},
|
|
2104
|
+
], this.documentType, this.indexedType, this._sync, options);
|
|
2105
|
+
for (const response of prepared) {
|
|
2106
|
+
if (!response.from) {
|
|
2107
|
+
continue;
|
|
2108
|
+
}
|
|
2109
|
+
const payload = response.response;
|
|
2110
|
+
if (!(payload instanceof types.Results)) {
|
|
2111
|
+
continue;
|
|
2112
|
+
}
|
|
2113
|
+
await mergePrefetchedResults(response.from, payload);
|
|
2114
|
+
}
|
|
2115
|
+
if (!pendingResultsReason) {
|
|
2116
|
+
pendingResultsReason = "change";
|
|
2117
|
+
}
|
|
2118
|
+
signalUpdate("prefetch-add");
|
|
2119
|
+
}
|
|
2120
|
+
catch (error) {
|
|
2121
|
+
logger.warn("Failed to merge prefetched results", error);
|
|
2122
|
+
}
|
|
2123
|
+
};
|
|
2124
|
+
const onPrefetchAdd = (evt) => {
|
|
2125
|
+
void consumePrefetch(evt.detail.consumable);
|
|
2126
|
+
};
|
|
2127
|
+
this.prefetch.accumulator.addEventListener("add", onPrefetchAdd);
|
|
2128
|
+
const cleanupDefault = cleanup;
|
|
2129
|
+
cleanup = () => {
|
|
2130
|
+
this.prefetch?.accumulator.removeEventListener("add", onPrefetchAdd);
|
|
2131
|
+
return cleanupDefault();
|
|
2132
|
+
};
|
|
2133
|
+
}
|
|
1738
2134
|
let updatesCleanup;
|
|
1739
2135
|
if (hasLiveUpdates) {
|
|
1740
2136
|
const localHash = this.node.identity.publicKey.hashcode();
|
|
@@ -1767,6 +2163,11 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
1767
2163
|
return value;
|
|
1768
2164
|
};
|
|
1769
2165
|
const onChange = async (evt) => {
|
|
2166
|
+
/* console.debug("[DocumentIndex] onChange event", {
|
|
2167
|
+
id: queryRequestCoerced.idString,
|
|
2168
|
+
added: evt.detail.added?.length,
|
|
2169
|
+
removed: evt.detail.removed?.length,
|
|
2170
|
+
}); */
|
|
1770
2171
|
// Optional filter to mutate/suppress change events
|
|
1771
2172
|
let filtered = evt.detail;
|
|
1772
2173
|
if (mergePolicy?.merge?.filter) {
|
|
@@ -1862,6 +2263,12 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
1862
2263
|
indexed: indexedCandidate,
|
|
1863
2264
|
};
|
|
1864
2265
|
buf.buffer.push(placeholder);
|
|
2266
|
+
/* console.debug("[DocumentIndex] buffered change", {
|
|
2267
|
+
id: queryRequestCoerced.idString,
|
|
2268
|
+
placeholderId: (valueForBuffer as any)?.id,
|
|
2269
|
+
peer: localHash,
|
|
2270
|
+
bufferSize: buf.buffer.length,
|
|
2271
|
+
}); */
|
|
1865
2272
|
if (!resolve) {
|
|
1866
2273
|
ensureIndexedPlaceholders().set(id, placeholder);
|
|
1867
2274
|
}
|
|
@@ -1875,7 +2282,13 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
1875
2282
|
}
|
|
1876
2283
|
if (changeForCallback.added.length > 0 ||
|
|
1877
2284
|
changeForCallback.removed.length > 0) {
|
|
2285
|
+
/* console.debug("[DocumentIndex] changeForCallback", {
|
|
2286
|
+
id: queryRequestCoerced.idString,
|
|
2287
|
+
added: changeForCallback.added.map((x) => (x as any)?.id),
|
|
2288
|
+
removed: changeForCallback.removed.map((x) => (x as any)?.id),
|
|
2289
|
+
}); */
|
|
1878
2290
|
updateCallbacks?.onChange?.(changeForCallback);
|
|
2291
|
+
signalUpdate("change");
|
|
1879
2292
|
}
|
|
1880
2293
|
}
|
|
1881
2294
|
}
|
|
@@ -1962,8 +2375,8 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
1962
2375
|
return cleanupDefault();
|
|
1963
2376
|
};
|
|
1964
2377
|
}
|
|
1965
|
-
if (
|
|
1966
|
-
|
|
2378
|
+
if (keepRemoteAlive) {
|
|
2379
|
+
const prevMaybeSetDone = maybeSetDone;
|
|
1967
2380
|
maybeSetDone = () => {
|
|
1968
2381
|
if (drain) {
|
|
1969
2382
|
prevMaybeSetDone();
|
|
@@ -1985,7 +2398,16 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
1985
2398
|
close,
|
|
1986
2399
|
next,
|
|
1987
2400
|
done: doneFn,
|
|
1988
|
-
pending: () => {
|
|
2401
|
+
pending: async () => {
|
|
2402
|
+
try {
|
|
2403
|
+
await fetchPromise;
|
|
2404
|
+
if (!done && keepRemoteAlive) {
|
|
2405
|
+
await fetchAtLeast(1);
|
|
2406
|
+
}
|
|
2407
|
+
}
|
|
2408
|
+
catch (error) {
|
|
2409
|
+
logger.warn("Failed to refresh iterator pending state", error);
|
|
2410
|
+
}
|
|
1989
2411
|
let pendingCount = 0;
|
|
1990
2412
|
for (const buffer of peerBufferMap.values()) {
|
|
1991
2413
|
pendingCount += buffer.kept + buffer.buffer.length;
|