@peerbit/document 9.11.7 → 9.11.8-863fe8e
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/events.d.ts +9 -0
- package/dist/src/events.d.ts.map +1 -0
- package/dist/src/events.js +2 -0
- package/dist/src/events.js.map +1 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/program.d.ts +2 -8
- package/dist/src/program.d.ts.map +1 -1
- package/dist/src/program.js +1 -0
- package/dist/src/program.js.map +1 -1
- package/dist/src/search.d.ts +15 -4
- package/dist/src/search.d.ts.map +1 -1
- package/dist/src/search.js +105 -13
- package/dist/src/search.js.map +1 -1
- package/package.json +75 -75
- package/src/events.ts +9 -0
- package/src/index.ts +1 -0
- package/src/program.ts +2 -7
- package/src/search.ts +152 -28
package/src/search.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type AbstractType, field, serialize, variant } from "@dao-xyz/borsh";
|
|
2
|
-
import type { PeerId } from "@libp2p/interface";
|
|
2
|
+
import type { PeerId, TypedEventTarget } from "@libp2p/interface";
|
|
3
3
|
import { Cache } from "@peerbit/cache";
|
|
4
4
|
import {
|
|
5
5
|
type MaybePromise,
|
|
@@ -28,9 +28,11 @@ import {
|
|
|
28
28
|
} from "@peerbit/shared-log";
|
|
29
29
|
import { DataMessage, SilentDelivery } from "@peerbit/stream-interface";
|
|
30
30
|
import { AbortError, waitFor } from "@peerbit/time";
|
|
31
|
+
import pDefer from "p-defer";
|
|
31
32
|
import { concat, fromString } from "uint8arrays";
|
|
32
33
|
import { copySerialization } from "./borsh.js";
|
|
33
34
|
import { MAX_BATCH_SIZE } from "./constants.js";
|
|
35
|
+
import type { DocumentEvents, DocumentsChange } from "./events.js";
|
|
34
36
|
import type { QueryPredictor } from "./most-common-query-predictor.js";
|
|
35
37
|
import MostCommonQueryPredictor from "./most-common-query-predictor.js";
|
|
36
38
|
import { type Operation, isPutOperation } from "./operation.js";
|
|
@@ -76,6 +78,21 @@ export type QueryOptions<R, D, Resolve extends boolean | undefined> = {
|
|
|
76
78
|
resolve?: Resolve;
|
|
77
79
|
signal?: AbortSignal;
|
|
78
80
|
};
|
|
81
|
+
|
|
82
|
+
export type GetOptions<R, D, Resolve extends boolean | undefined> = {
|
|
83
|
+
remote?:
|
|
84
|
+
| boolean
|
|
85
|
+
| RemoteQueryOptions<
|
|
86
|
+
types.AbstractSearchRequest,
|
|
87
|
+
types.AbstractSearchResult,
|
|
88
|
+
D
|
|
89
|
+
>;
|
|
90
|
+
local?: boolean;
|
|
91
|
+
resolve?: Resolve;
|
|
92
|
+
signal?: AbortSignal;
|
|
93
|
+
waitFor?: number; // how long to wait for a non-empty result set
|
|
94
|
+
};
|
|
95
|
+
|
|
79
96
|
export type SearchOptions<
|
|
80
97
|
R,
|
|
81
98
|
D,
|
|
@@ -228,6 +245,8 @@ function isSubclassOf(
|
|
|
228
245
|
return false;
|
|
229
246
|
}
|
|
230
247
|
|
|
248
|
+
const DEFAULT_TIMEOUT = 1e4;
|
|
249
|
+
|
|
231
250
|
const DEFAULT_INDEX_BY = "id";
|
|
232
251
|
|
|
233
252
|
export type CanSearch = (
|
|
@@ -298,6 +317,7 @@ export type OpenOptions<
|
|
|
298
317
|
I,
|
|
299
318
|
D extends ReplicationDomain<any, Operation, any>,
|
|
300
319
|
> = {
|
|
320
|
+
documentEvents: TypedEventTarget<DocumentEvents<T, I>>;
|
|
301
321
|
documentType: AbstractType<T>;
|
|
302
322
|
dbType: AbstractType<types.IDocumentStore<T>>;
|
|
303
323
|
log: SharedLog<Operation, D, any>;
|
|
@@ -399,6 +419,9 @@ export class DocumentIndex<
|
|
|
399
419
|
private _maybeOpen: (value: T & Program) => Promise<T & Program>;
|
|
400
420
|
private canSearch?: CanSearch;
|
|
401
421
|
private canRead?: CanRead<I>;
|
|
422
|
+
|
|
423
|
+
private documentEvents: TypedEventTarget<DocumentEvents<T, I>>;
|
|
424
|
+
|
|
402
425
|
private _joinListener?: (e: { detail: PublicSignKey }) => Promise<void>;
|
|
403
426
|
|
|
404
427
|
private _resultQueue: Map<
|
|
@@ -455,7 +478,7 @@ export class DocumentIndex<
|
|
|
455
478
|
this.indexedTypeIsDocumentType =
|
|
456
479
|
!properties.transform?.type ||
|
|
457
480
|
properties.transform?.type === properties.documentType;
|
|
458
|
-
|
|
481
|
+
this.documentEvents = properties.documentEvents;
|
|
459
482
|
this.compatibility = properties.compatibility;
|
|
460
483
|
this.canRead = properties.canRead;
|
|
461
484
|
this.canSearch = properties.canSearch;
|
|
@@ -791,26 +814,58 @@ export class DocumentIndex<
|
|
|
791
814
|
return dropped;
|
|
792
815
|
}
|
|
793
816
|
|
|
794
|
-
public async get<Options extends
|
|
817
|
+
public async get<Options extends GetOptions<T, D, true | undefined>>(
|
|
795
818
|
key: indexerTypes.Ideable | indexerTypes.IdKey,
|
|
796
819
|
options?: Options,
|
|
797
820
|
): Promise<WithIndexedContext<T, I>>;
|
|
798
821
|
|
|
799
|
-
public async get<Options extends
|
|
822
|
+
public async get<Options extends GetOptions<T, D, false>>(
|
|
800
823
|
key: indexerTypes.Ideable | indexerTypes.IdKey,
|
|
801
824
|
options?: Options,
|
|
802
825
|
): Promise<WithContext<I>>;
|
|
803
826
|
|
|
804
827
|
public async get<
|
|
805
|
-
Options extends
|
|
828
|
+
Options extends GetOptions<T, D, Resolve>,
|
|
806
829
|
Resolve extends boolean | undefined = ExtractResolveFromOptions<Options>,
|
|
807
830
|
>(key: indexerTypes.Ideable | indexerTypes.IdKey, options?: Options) {
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
)
|
|
831
|
+
let idKey =
|
|
832
|
+
key instanceof indexerTypes.IdKey ? key : indexerTypes.toId(key);
|
|
833
|
+
const result = (await this.getDetailed(idKey, options))?.[0]?.results[0];
|
|
834
|
+
|
|
835
|
+
// if no results, and we have remote joining options, we wait for the timout and if there are joining peers we re-query
|
|
836
|
+
if (!result) {
|
|
837
|
+
if (options?.waitFor) {
|
|
838
|
+
let deferred = pDefer<WithIndexedContext<T, I> | WithContext<I>>();
|
|
839
|
+
|
|
840
|
+
const listener = (evt: CustomEvent<DocumentsChange<T, I>>) => {
|
|
841
|
+
for (const added of evt.detail.added) {
|
|
842
|
+
const id = this.indexByResolver(added.__indexed);
|
|
843
|
+
if (id === idKey.primitive) {
|
|
844
|
+
deferred.resolve(added);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
};
|
|
848
|
+
|
|
849
|
+
this.documentEvents.addEventListener("change", listener);
|
|
850
|
+
|
|
851
|
+
let cleanup = () => {
|
|
852
|
+
this.documentEvents.removeEventListener("change", listener);
|
|
853
|
+
clearTimeout(timeout);
|
|
854
|
+
this.events.removeEventListener("close", resolveUndefined);
|
|
855
|
+
};
|
|
856
|
+
|
|
857
|
+
let resolveUndefined = () => {
|
|
858
|
+
cleanup();
|
|
859
|
+
deferred.resolve(undefined);
|
|
860
|
+
};
|
|
861
|
+
|
|
862
|
+
let timeout = setTimeout(resolveUndefined, options.waitFor);
|
|
863
|
+
this.events.addEventListener("close", resolveUndefined);
|
|
864
|
+
|
|
865
|
+
return deferred.promise;
|
|
866
|
+
}
|
|
867
|
+
return undefined;
|
|
868
|
+
}
|
|
814
869
|
return result?.value;
|
|
815
870
|
}
|
|
816
871
|
|
|
@@ -820,6 +875,13 @@ export class DocumentIndex<
|
|
|
820
875
|
await iterator.close();
|
|
821
876
|
return one[0];
|
|
822
877
|
}
|
|
878
|
+
|
|
879
|
+
public async getFromHash(hash: string) {
|
|
880
|
+
const iterator = this.index.iterate({ query: { hash } });
|
|
881
|
+
const one = await iterator.next(1);
|
|
882
|
+
await iterator.close();
|
|
883
|
+
return one[0];
|
|
884
|
+
}
|
|
823
885
|
public async put(
|
|
824
886
|
value: T,
|
|
825
887
|
id: indexerTypes.IdKey,
|
|
@@ -1243,10 +1305,10 @@ export class DocumentIndex<
|
|
|
1243
1305
|
}
|
|
1244
1306
|
}
|
|
1245
1307
|
|
|
1246
|
-
|
|
1308
|
+
processCloseIteratorRequest(
|
|
1247
1309
|
query: types.CloseIteratorRequest,
|
|
1248
1310
|
publicKey: PublicSignKey,
|
|
1249
|
-
):
|
|
1311
|
+
): void {
|
|
1250
1312
|
const queueData = this._resultQueue.get(query.idString);
|
|
1251
1313
|
if (queueData && !queueData.from.equals(publicKey)) {
|
|
1252
1314
|
logger.info("Ignoring close iterator request from different peer");
|
|
@@ -1326,6 +1388,7 @@ export class DocumentIndex<
|
|
|
1326
1388
|
: await this._log.getCover(remote.domain ?? { args: undefined }, {
|
|
1327
1389
|
roleAge: remote.minAge,
|
|
1328
1390
|
eager: remote.eager,
|
|
1391
|
+
reachableOnly: !!remote.joining, // when we want to merge joining we can ignore pending to be online peers and instead consider them once they become online
|
|
1329
1392
|
});
|
|
1330
1393
|
|
|
1331
1394
|
if (replicatorGroups) {
|
|
@@ -1682,8 +1745,8 @@ export class DocumentIndex<
|
|
|
1682
1745
|
let t0 = +new Date();
|
|
1683
1746
|
let waitForTime =
|
|
1684
1747
|
typeof options.remote.joining === "boolean"
|
|
1685
|
-
?
|
|
1686
|
-
: (options.remote.joining.waitFor ??
|
|
1748
|
+
? DEFAULT_TIMEOUT
|
|
1749
|
+
: (options.remote.joining.waitFor ?? DEFAULT_TIMEOUT);
|
|
1687
1750
|
let setDoneIfTimeout = false;
|
|
1688
1751
|
maybeSetDone = () => {
|
|
1689
1752
|
if (t0 + waitForTime < +new Date()) {
|
|
@@ -2128,15 +2191,24 @@ export class DocumentIndex<
|
|
|
2128
2191
|
return dedup(coercedBatch, this.indexByResolver);
|
|
2129
2192
|
};
|
|
2130
2193
|
|
|
2131
|
-
let
|
|
2194
|
+
let cleanupAndDone = () => {
|
|
2132
2195
|
cleanup();
|
|
2133
|
-
done = true;
|
|
2134
2196
|
controller.abort(new AbortError("Iterator closed"));
|
|
2197
|
+
this.prefetch?.accumulator.clear(queryRequestCoerced);
|
|
2198
|
+
this.processCloseIteratorRequest(
|
|
2199
|
+
queryRequestCoerced,
|
|
2200
|
+
this.node.identity.publicKey,
|
|
2201
|
+
);
|
|
2202
|
+
done = true;
|
|
2203
|
+
};
|
|
2135
2204
|
|
|
2205
|
+
let close = async () => {
|
|
2206
|
+
cleanupAndDone();
|
|
2207
|
+
|
|
2208
|
+
// send close to remote
|
|
2136
2209
|
const closeRequest = new types.CloseIteratorRequest({
|
|
2137
2210
|
id: queryRequestCoerced.id,
|
|
2138
2211
|
});
|
|
2139
|
-
this.prefetch?.accumulator.clear(queryRequestCoerced);
|
|
2140
2212
|
const promises: Promise<any>[] = [];
|
|
2141
2213
|
|
|
2142
2214
|
for (const [peer, buffer] of peerBufferMap) {
|
|
@@ -2144,15 +2216,7 @@ export class DocumentIndex<
|
|
|
2144
2216
|
peerBufferMap.delete(peer);
|
|
2145
2217
|
continue;
|
|
2146
2218
|
}
|
|
2147
|
-
|
|
2148
|
-
if (peer === this.node.identity.publicKey.hashcode()) {
|
|
2149
|
-
promises.push(
|
|
2150
|
-
this.processCloseIteratorRequest(
|
|
2151
|
-
closeRequest,
|
|
2152
|
-
this.node.identity.publicKey,
|
|
2153
|
-
),
|
|
2154
|
-
);
|
|
2155
|
-
} else {
|
|
2219
|
+
if (peer !== this.node.identity.publicKey.hashcode()) {
|
|
2156
2220
|
// Close remote
|
|
2157
2221
|
promises.push(
|
|
2158
2222
|
this._query.send(closeRequest, {
|
|
@@ -2172,6 +2236,11 @@ export class DocumentIndex<
|
|
|
2172
2236
|
|
|
2173
2237
|
let joinListener: ((e: { detail: PublicSignKey }) => void) | undefined;
|
|
2174
2238
|
|
|
2239
|
+
let updateDeferred: ReturnType<typeof pDefer> | undefined;
|
|
2240
|
+
const signalUpdate = () => updateDeferred?.resolve();
|
|
2241
|
+
const waitForUpdate = () =>
|
|
2242
|
+
updateDeferred ? updateDeferred.promise : Promise.resolve();
|
|
2243
|
+
|
|
2175
2244
|
if (typeof options?.remote === "object" && options?.remote.joining) {
|
|
2176
2245
|
let onMissedResults =
|
|
2177
2246
|
typeof options?.remote?.joining === "object" &&
|
|
@@ -2179,7 +2248,38 @@ export class DocumentIndex<
|
|
|
2179
2248
|
? options.remote.joining.onMissedResults
|
|
2180
2249
|
: undefined;
|
|
2181
2250
|
|
|
2251
|
+
updateDeferred = pDefer<void>();
|
|
2252
|
+
|
|
2253
|
+
const waitForTime =
|
|
2254
|
+
typeof options.remote.joining === "object" &&
|
|
2255
|
+
options.remote.joining.waitFor;
|
|
2256
|
+
|
|
2257
|
+
const prevMaybeSetDone = maybeSetDone;
|
|
2258
|
+
maybeSetDone = () => {
|
|
2259
|
+
prevMaybeSetDone();
|
|
2260
|
+
if (done) signalUpdate(); // break deferred waits
|
|
2261
|
+
};
|
|
2262
|
+
|
|
2263
|
+
let joinTimeoutId =
|
|
2264
|
+
waitForTime &&
|
|
2265
|
+
setTimeout(() => {
|
|
2266
|
+
signalUpdate();
|
|
2267
|
+
}, waitForTime);
|
|
2268
|
+
controller.signal.addEventListener("abort", () => signalUpdate());
|
|
2269
|
+
|
|
2270
|
+
let activeJoins = new Set<string>();
|
|
2271
|
+
|
|
2182
2272
|
joinListener = async (e: { detail: PublicSignKey }) => {
|
|
2273
|
+
if (done) return;
|
|
2274
|
+
const pk = e.detail;
|
|
2275
|
+
const hash = pk.hashcode();
|
|
2276
|
+
|
|
2277
|
+
if (hash === this.node.identity.publicKey.hashcode()) return;
|
|
2278
|
+
if (peerBufferMap.has(hash)) return;
|
|
2279
|
+
if (activeJoins.has(hash)) return;
|
|
2280
|
+
|
|
2281
|
+
activeJoins.add(hash);
|
|
2282
|
+
|
|
2183
2283
|
if (totalFetchedCounter > 0) {
|
|
2184
2284
|
// wait for the node to become a replicator, then so query
|
|
2185
2285
|
await this._log
|
|
@@ -2237,9 +2337,13 @@ export class DocumentIndex<
|
|
|
2237
2337
|
}
|
|
2238
2338
|
}
|
|
2239
2339
|
}
|
|
2340
|
+
signalUpdate();
|
|
2240
2341
|
})
|
|
2241
2342
|
.catch(() => {
|
|
2242
2343
|
/* TODO error handling */
|
|
2344
|
+
})
|
|
2345
|
+
.finally(() => {
|
|
2346
|
+
activeJoins.delete(hash);
|
|
2243
2347
|
});
|
|
2244
2348
|
}
|
|
2245
2349
|
};
|
|
@@ -2247,6 +2351,9 @@ export class DocumentIndex<
|
|
|
2247
2351
|
const cleanupDefault = cleanup;
|
|
2248
2352
|
cleanup = () => {
|
|
2249
2353
|
this._query.events.removeEventListener("join", joinListener!);
|
|
2354
|
+
joinTimeoutId && clearTimeout(joinTimeoutId);
|
|
2355
|
+
updateDeferred?.resolve();
|
|
2356
|
+
updateDeferred = undefined;
|
|
2250
2357
|
return cleanupDefault();
|
|
2251
2358
|
};
|
|
2252
2359
|
}
|
|
@@ -2264,10 +2371,27 @@ export class DocumentIndex<
|
|
|
2264
2371
|
},
|
|
2265
2372
|
all: async () => {
|
|
2266
2373
|
let result: ValueTypeFromRequest<Resolve, T, I>[] = [];
|
|
2374
|
+
let c = 0;
|
|
2267
2375
|
while (doneFn() !== true) {
|
|
2376
|
+
c++;
|
|
2268
2377
|
let batch = await next(100);
|
|
2269
|
-
|
|
2378
|
+
if (c > 100) {
|
|
2379
|
+
break;
|
|
2380
|
+
}
|
|
2381
|
+
if (batch.length > 0) {
|
|
2382
|
+
result.push(...batch);
|
|
2383
|
+
continue;
|
|
2384
|
+
}
|
|
2385
|
+
|
|
2386
|
+
// wait until: join fetch adds results, cleanup runs, or the join-wait times out
|
|
2387
|
+
await waitForUpdate();
|
|
2388
|
+
|
|
2389
|
+
// re-arm the deferred for the next cycle (only if joining is enabled and we’re not done)
|
|
2390
|
+
if (updateDeferred && !doneFn()) {
|
|
2391
|
+
updateDeferred = pDefer<void>();
|
|
2392
|
+
}
|
|
2270
2393
|
}
|
|
2394
|
+
cleanupAndDone();
|
|
2271
2395
|
return result;
|
|
2272
2396
|
},
|
|
2273
2397
|
};
|