@peerbit/document 12.1.2 → 12.2.0-3333888

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peerbit/document",
3
- "version": "12.1.2",
3
+ "version": "12.2.0-3333888",
4
4
  "description": "Document store implementation",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -57,32 +57,32 @@
57
57
  "@libp2p/interface": "^3.1.0",
58
58
  "@libp2p/tcp": "^11.0.2",
59
59
  "@multiformats/multiaddr": "^13.0.1",
60
+ "@peerbit/cache": "2.2.0-3333888",
61
+ "@peerbit/crypto": "2.4.1-3333888",
62
+ "@peerbit/logger": "2.0.0-3333888",
63
+ "@peerbit/log": "5.0.6-3333888",
64
+ "@peerbit/pubsub": "4.1.3-3333888",
65
+ "@peerbit/program": "5.6.0-3333888",
66
+ "@peerbit/rpc": "5.4.15-3333888",
67
+ "@peerbit/shared-log": "12.2.0-3333888",
68
+ "@peerbit/indexer-interface": "2.1.1-3333888",
69
+ "@peerbit/indexer-simple": "1.2.2-3333888",
70
+ "@peerbit/indexer-sqlite3": "2.1.0-3333888",
71
+ "@peerbit/document-interface": "3.2.0-3333888",
72
+ "@peerbit/indexer-cache": "0.2.2-3333888",
73
+ "@peerbit/stream-interface": "5.3.1-3333888",
60
74
  "p-defer": "^4.0.0",
61
- "uint8arrays": "^5.1.0",
62
- "@peerbit/cache": "2.2.0",
63
- "@peerbit/crypto": "2.4.1",
64
- "@peerbit/logger": "2.0.0",
65
- "@peerbit/log": "5.0.5",
66
- "@peerbit/pubsub": "4.1.3",
67
- "@peerbit/program": "5.5.2",
68
- "@peerbit/rpc": "5.4.14",
69
- "@peerbit/shared-log": "12.1.3",
70
- "@peerbit/indexer-interface": "2.1.1",
71
- "@peerbit/indexer-simple": "1.2.2",
72
- "@peerbit/indexer-sqlite3": "2.0.2",
73
- "@peerbit/indexer-cache": "0.2.2",
74
- "@peerbit/stream-interface": "5.3.1",
75
- "@peerbit/document-interface": "3.1.14"
75
+ "uint8arrays": "^5.1.0"
76
76
  },
77
77
  "devDependencies": {
78
+ "@peerbit/test-utils": "2.3.15-3333888",
79
+ "@peerbit/time": "2.3.0-3333888",
80
+ "peerbit": "4.4.15-3333888",
78
81
  "@types/pidusage": "^2.0.5",
79
82
  "pidusage": "^4.0.1",
80
83
  "uuid": "^10.0.0",
81
84
  "@libp2p/websockets": "^10.1.0",
82
- "@chainsafe/libp2p-noise": "^17.0.0",
83
- "@peerbit/test-utils": "2.3.14",
84
- "peerbit": "4.4.14",
85
- "@peerbit/time": "2.3.0"
85
+ "@chainsafe/libp2p-noise": "^17.0.0"
86
86
  },
87
87
  "scripts": {
88
88
  "clean": "aegir clean",
package/src/index.ts CHANGED
@@ -9,6 +9,7 @@ export type {
9
9
  WithIndexedContext,
10
10
  WithIndexed,
11
11
  OpenOptions,
12
+ GetOptions,
12
13
  QueryOptions,
13
14
  RemoteQueryOptions,
14
15
  ResultsIterator,
@@ -40,3 +41,10 @@ export {
40
41
  createDocumentDomainFromProperty,
41
42
  } from "./domain.js";
42
43
  export * from "./events.js";
44
+ export type {
45
+ DocumentsLike,
46
+ DocumentsLikeCountOptions,
47
+ DocumentsLikeIndex,
48
+ DocumentsLikeQuery,
49
+ DocumentsLikeWaitForOptions,
50
+ } from "./like.js";
package/src/like.ts ADDED
@@ -0,0 +1,132 @@
1
+ import type {
2
+ Context,
3
+ IterationRequest,
4
+ ResultIndexedValue,
5
+ ResultValue,
6
+ Results,
7
+ SearchRequest,
8
+ SearchRequestIndexed,
9
+ } from "@peerbit/document-interface";
10
+ import type * as indexerTypes from "@peerbit/indexer-interface";
11
+ import type { Program } from "@peerbit/program";
12
+ import type { SharedLogLike } from "@peerbit/shared-log";
13
+ import type { PeerRefs } from "@peerbit/stream-interface";
14
+ import type {
15
+ GetOptions,
16
+ QueryOptions,
17
+ ReachScope,
18
+ ResultsIterator,
19
+ SearchOptions,
20
+ ValueTypeFromRequest,
21
+ WithContext,
22
+ WithIndexedContext,
23
+ } from "./search.js";
24
+ import type { CountEstimate } from "./program.js";
25
+
26
+ export type DocumentsLikeQuery =
27
+ | SearchRequest
28
+ | SearchRequestIndexed
29
+ | IterationRequest
30
+ | {
31
+ query?: indexerTypes.QueryLike | indexerTypes.Query[];
32
+ sort?: indexerTypes.SortLike | indexerTypes.Sort | indexerTypes.Sort[];
33
+ };
34
+
35
+ export type DocumentsLikeWaitForOptions = {
36
+ seek?: "any" | "present";
37
+ signal?: AbortSignal;
38
+ timeout?: number;
39
+ };
40
+
41
+ export type DocumentsLikeExactCountOptions = {
42
+ query?: indexerTypes.Query | indexerTypes.QueryLike;
43
+ approximate?: false | undefined;
44
+ };
45
+
46
+ export type DocumentsLikeApproximateCountOptions = {
47
+ query?: indexerTypes.Query | indexerTypes.QueryLike;
48
+ approximate: true | { scope?: ReachScope };
49
+ };
50
+
51
+ export type DocumentsLikeCountOptions =
52
+ | DocumentsLikeExactCountOptions
53
+ | DocumentsLikeApproximateCountOptions;
54
+
55
+ export type DocumentsLikeIndex<T, I, D = any> = {
56
+ get: <Resolve extends boolean | undefined = true>(
57
+ id: indexerTypes.Ideable | indexerTypes.IdKey,
58
+ options?: GetOptions<T, I, D, Resolve>,
59
+ ) => Promise<ValueTypeFromRequest<Resolve, T, I> | undefined>;
60
+ getDetailed: <Resolve extends boolean | undefined = true>(
61
+ id: indexerTypes.IdKey | indexerTypes.IdPrimitive,
62
+ options?: QueryOptions<T, I, D, Resolve>,
63
+ ) => Promise<
64
+ | Results<
65
+ Resolve extends false
66
+ ? ResultIndexedValue<WithContext<I>>
67
+ : ResultValue<WithIndexedContext<T, I>>
68
+ >[]
69
+ | undefined
70
+ >;
71
+ resolveId: (value: any) => indexerTypes.IdKey;
72
+ iterate: <Resolve extends boolean | undefined = true>(
73
+ query?: DocumentsLikeQuery,
74
+ options?: QueryOptions<T, I, D, Resolve>,
75
+ ) => ResultsIterator<ValueTypeFromRequest<Resolve, T, I>>;
76
+ search: <Resolve extends boolean | undefined = true>(
77
+ query: DocumentsLikeQuery,
78
+ options?: SearchOptions<T, I, D, Resolve>,
79
+ ) => Promise<ValueTypeFromRequest<Resolve, T, I>[]>;
80
+ getSize: () => Promise<number> | number;
81
+ waitFor: (
82
+ peers: PeerRefs,
83
+ options?: DocumentsLikeWaitForOptions,
84
+ ) => Promise<string[]>;
85
+ wrappedIndexedType?: new (value: I, context: Context) => WithContext<I>;
86
+ index?: {
87
+ count?: (options?: indexerTypes.CountOptions) => Promise<number> | number;
88
+ getSize?: () => Promise<number> | number;
89
+ get?: (
90
+ id: indexerTypes.IdKey,
91
+ options?: { shape: indexerTypes.Shape },
92
+ ) =>
93
+ | Promise<indexerTypes.IndexedResult<WithContext<I>> | undefined>
94
+ | indexerTypes.IndexedResult<WithContext<I>>
95
+ | undefined;
96
+ iterate?: (
97
+ request?: indexerTypes.IterateOptions,
98
+ options?: { shape?: indexerTypes.Shape; reference?: boolean },
99
+ ) => indexerTypes.IndexIterator<
100
+ WithContext<I>,
101
+ indexerTypes.Shape | undefined
102
+ >;
103
+ put?: (value: WithContext<I>) => Promise<void> | void;
104
+ };
105
+ };
106
+
107
+ export type DocumentsLike<T, I, D = any> = {
108
+ closed?: boolean;
109
+ events: EventTarget;
110
+ changes: EventTarget;
111
+ index: DocumentsLikeIndex<T, I, D>;
112
+ log: SharedLogLike<any>;
113
+ put(doc: T, options?: unknown): Promise<unknown>;
114
+ get: (
115
+ id: indexerTypes.Ideable | indexerTypes.IdKey,
116
+ options?: Omit<GetOptions<T, I, D, true | undefined>, "resolve">,
117
+ ) => Promise<T | undefined>;
118
+ del(
119
+ id: indexerTypes.Ideable | indexerTypes.IdKey,
120
+ options?: unknown,
121
+ ): Promise<unknown>;
122
+ count: {
123
+ (options?: DocumentsLikeExactCountOptions): Promise<number>;
124
+ (options: DocumentsLikeApproximateCountOptions): Promise<CountEstimate>;
125
+ };
126
+ waitFor: (
127
+ peers: PeerRefs,
128
+ options?: DocumentsLikeWaitForOptions,
129
+ ) => Promise<string[]>;
130
+ recover: () => Promise<void>;
131
+ close: (from?: Program<any, any>) => Promise<boolean | void>;
132
+ };
package/src/program.ts CHANGED
@@ -42,6 +42,7 @@ import {
42
42
  type CanRead,
43
43
  type CanSearch,
44
44
  DocumentIndex,
45
+ type GetOptions,
45
46
  type PrefetchOptions,
46
47
  type ReachScope,
47
48
  type TransformOptions,
@@ -175,6 +176,10 @@ export class Documents<
175
176
  return this._index;
176
177
  }
177
178
 
179
+ get changes() {
180
+ return this.events;
181
+ }
182
+
178
183
  private async maybeSubprogramOpen(value: T & Program): Promise<T & Program> {
179
184
  if (await this.canOpen!(value)) {
180
185
  return (await this.node.open(value, {
@@ -300,10 +305,18 @@ export class Documents<
300
305
  trim: options?.log?.trim,
301
306
  replicate: options?.replicate,
302
307
  replicas: options?.replicas,
308
+ respondToIHaveTimeout: options?.respondToIHaveTimeout,
309
+ sync: options?.sync,
310
+ syncronizer: options?.syncronizer,
311
+ timeUntilRoleMaturity: options?.timeUntilRoleMaturity,
312
+ waitForReplicatorTimeout: options?.waitForReplicatorTimeout,
313
+ waitForPruneDelay: options?.waitForPruneDelay,
314
+ distributionDebounceTime: options?.distributionDebounceTime,
303
315
  domain: (options?.domain
304
316
  ? (log: any) => options.domain!(this)
305
317
  : undefined) as any, /// TODO types,
306
318
  compatibility: logCompatiblity,
319
+ eagerBlocks: options?.eagerBlocks,
307
320
  keep: keepFunction,
308
321
  });
309
322
  }
@@ -333,7 +346,7 @@ export class Documents<
333
346
  : history;
334
347
  }
335
348
 
336
- async canAppend(
349
+ protected async canAppend(
337
350
  entry: Entry<Operation>,
338
351
  reference?: { document: T; operation: PutOperation },
339
352
  ): Promise<boolean> {
@@ -391,7 +404,7 @@ export class Documents<
391
404
  return true;
392
405
  }
393
406
 
394
- async _canAppend(
407
+ protected async _canAppend(
395
408
  entry: Entry<Operation>,
396
409
  reference?: { document: T; operation: PutOperation },
397
410
  ): Promise<PutOperation | DeleteOperation | false> {
@@ -604,11 +617,22 @@ export class Documents<
604
617
  return appended;
605
618
  }
606
619
 
620
+ public async get(
621
+ id: indexerTypes.Ideable | indexerTypes.IdKey,
622
+ options?: Omit<GetOptions<T, I, D, true | undefined>, "resolve">,
623
+ ): Promise<T | undefined> {
624
+ const resolved = await this.index.get(id, {
625
+ ...(options ?? {}),
626
+ resolve: true,
627
+ } as GetOptions<T, I, D, true>);
628
+ return resolved ? (resolved as T) : undefined;
629
+ }
630
+
607
631
  async del(
608
- id: indexerTypes.Ideable,
632
+ id: indexerTypes.Ideable | indexerTypes.IdKey,
609
633
  options?: SharedAppendOptions<Operation>,
610
634
  ) {
611
- const key = indexerTypes.toId(id);
635
+ const key = id instanceof indexerTypes.IdKey ? id : indexerTypes.toId(id);
612
636
  const existing = (
613
637
  await this._index.getDetailed(key, {
614
638
  resolve: false,
package/src/search.ts CHANGED
@@ -2235,7 +2235,7 @@ export class DocumentIndex<
2235
2235
  // give queries higher priority than other "normal" data activities
2236
2236
  // without this, we might have a scenario that a peer joina network with large amount of data to be synced, but can not query anything before that is done
2237
2237
  // this will lead to bad UX as you usually want to list/expore whats going on before doing any replication work
2238
- remote.priority = 1;
2238
+ remote.priority = 2;
2239
2239
  }
2240
2240
 
2241
2241
  if (!local && !remote) {
@@ -3728,9 +3728,13 @@ export class DocumentIndex<
3728
3728
  const keepRemoteAlive = keepOpen && remoteOptions !== false;
3729
3729
 
3730
3730
  if (queryRequestCoerced instanceof types.IterationRequest) {
3731
- queryRequestCoerced.resolve = resolve;
3731
+ // If replication is requested, prefer fetching indexed results (with `entries`)
3732
+ // even when the caller wants resolved documents. This allows `replicate(...)` to
3733
+ // join using the provided `Entry` objects instead of doing per-head block fetches.
3734
+ const requestResolve = resolve && !replicate;
3735
+ queryRequestCoerced.resolve = requestResolve;
3732
3736
  queryRequestCoerced.fetch = queryRequestCoerced.fetch ?? 10;
3733
- const replicateFlag = !resolve && replicate ? true : false;
3737
+ const replicateFlag = !requestResolve && replicate ? true : false;
3734
3738
  queryRequestCoerced.replicate = replicateFlag;
3735
3739
  const ttlSource =
3736
3740
  typeof remoteOptions === "object" &&
@@ -4251,19 +4255,26 @@ export class DocumentIndex<
4251
4255
  }
4252
4256
  };
4253
4257
 
4254
- return {
4255
- close,
4256
- next,
4257
- done: doneFn,
4258
- pending: async () => {
4259
- try {
4260
- await fetchPromise;
4261
- if (!done && keepRemoteAlive) {
4262
- await fetchAtLeast(1);
4258
+ return {
4259
+ close,
4260
+ next,
4261
+ done: doneFn,
4262
+ pending: async () => {
4263
+ try {
4264
+ await fetchPromise;
4265
+ // In push-update mode, remotes will stream new results proactively.
4266
+ // After the iterator has been primed (`first === true`), calling
4267
+ // `fetchAtLeast(1)` from `pending()` can double-count by pulling from
4268
+ // the remote iterator while we also have pushed results buffered locally.
4269
+ //
4270
+ // We still need to prime the iterator at least once so `pending()` is meaningful
4271
+ // even before the first `next(...)` call.
4272
+ if (!done && keepRemoteAlive && (!pushUpdates || !first)) {
4273
+ await fetchAtLeast(1);
4274
+ }
4275
+ } catch (error) {
4276
+ warn("Failed to refresh iterator pending state", error);
4263
4277
  }
4264
- } catch (error) {
4265
- warn("Failed to refresh iterator pending state", error);
4266
- }
4267
4278
 
4268
4279
  let total = 0;
4269
4280
  for (const buffer of peerBufferMap.values()) {
@@ -4273,10 +4284,11 @@ export class DocumentIndex<
4273
4284
  },
4274
4285
  all: async () => {
4275
4286
  drain = true;
4287
+ const drainBatchSize = replicate ? 1000 : 100;
4276
4288
  let result: ValueTypeFromRequest<Resolve, T, I>[] = [];
4277
4289
  let c = 0;
4278
4290
  while (doneFn() !== true) {
4279
- let batch = await next(100);
4291
+ let batch = await next(drainBatchSize);
4280
4292
  c += batch.length;
4281
4293
  if (c > WARNING_WHEN_ITERATING_FOR_MORE_THAN) {
4282
4294
  warn(
@@ -4304,9 +4316,10 @@ export class DocumentIndex<
4304
4316
  },
4305
4317
  [Symbol.asyncIterator]: async function* () {
4306
4318
  drain = true;
4319
+ const drainBatchSize = replicate ? 1000 : 100;
4307
4320
  let c = 0;
4308
4321
  while (doneFn() !== true) {
4309
- const batch = await next(100);
4322
+ const batch = await next(drainBatchSize);
4310
4323
  c += batch.length;
4311
4324
  if (c > WARNING_WHEN_ITERATING_FOR_MORE_THAN) {
4312
4325
  warn(