@peerbit/document 13.1.0 → 13.1.2

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": "13.1.0",
3
+ "version": "13.1.2",
4
4
  "description": "Document store implementation",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -61,21 +61,21 @@
61
61
  "uint8arrays": "^5.1.0",
62
62
  "@peerbit/cache": "3.1.0",
63
63
  "@peerbit/crypto": "3.1.2",
64
- "@peerbit/document-interface": "3.2.43",
65
64
  "@peerbit/indexer-cache": "0.2.8",
65
+ "@peerbit/document-interface": "3.2.45",
66
66
  "@peerbit/indexer-interface": "3.0.5",
67
- "@peerbit/indexer-sqlite3": "3.0.8",
68
67
  "@peerbit/indexer-simple": "1.2.8",
69
- "@peerbit/log": "6.2.0",
68
+ "@peerbit/indexer-sqlite3": "3.0.8",
69
+ "@peerbit/log": "6.2.2",
70
70
  "@peerbit/logger": "2.0.1",
71
71
  "@peerbit/program": "6.0.32",
72
- "@peerbit/rpc": "6.1.0",
73
72
  "@peerbit/pubsub": "5.3.0",
73
+ "@peerbit/rpc": "6.1.0",
74
74
  "@peerbit/stream-interface": "6.0.11",
75
- "@peerbit/shared-log": "13.2.0"
75
+ "@peerbit/shared-log": "13.2.2"
76
76
  },
77
77
  "optionalDependencies": {
78
- "@peerbit/document-rust": "0.1.0"
78
+ "@peerbit/document-rust": "0.1.1"
79
79
  },
80
80
  "devDependencies": {
81
81
  "@chainsafe/libp2p-noise": "^17.0.0",
@@ -83,11 +83,11 @@
83
83
  "@types/pidusage": "^2.0.5",
84
84
  "pidusage": "^4.0.1",
85
85
  "uuid": "^10.0.0",
86
- "@peerbit/native-backbone": "0.1.0",
86
+ "@peerbit/log-rust": "1.1.2",
87
+ "@peerbit/native-backbone": "0.1.2",
88
+ "@peerbit/test-utils": "3.1.2",
87
89
  "@peerbit/time": "3.0.0",
88
- "@peerbit/log-rust": "1.1.0",
89
- "@peerbit/test-utils": "3.1.0",
90
- "peerbit": "5.3.0"
90
+ "peerbit": "5.3.2"
91
91
  },
92
92
  "repository": {
93
93
  "type": "git",
package/src/program.ts CHANGED
@@ -2300,6 +2300,7 @@ export class Documents<
2300
2300
  maybeOpen: this.maybeSubprogramOpen.bind(this),
2301
2301
  prefetch: options.index?.prefetch,
2302
2302
  includeIndexed: options.index?.includeIndexed,
2303
+ immutable: this.immutable,
2303
2304
  });
2304
2305
  this._documentInternalChangeListenerCount = Math.max(
2305
2306
  0,
package/src/search.ts CHANGED
@@ -859,6 +859,7 @@ export type OpenOptions<
859
859
  maybeOpen: (value: T & Program) => Promise<T & Program>;
860
860
  prefetch?: boolean | Partial<PrefetchOptions>;
861
861
  includeIndexed?: boolean; // if true, indexed representations will always be included in the search results
862
+ immutable?: boolean; // conflict rule of the owning store: oldest version wins when true (mirrors Documents "immutable")
862
863
  };
863
864
 
864
865
  type IndexableClass<I> = new (
@@ -1093,6 +1094,7 @@ export class DocumentIndex<
1093
1094
  private _resumableIterators: ResumableIterators<WithContext<I>>;
1094
1095
  private _prefetch?: PrefetchOptions | undefined;
1095
1096
  private includeIndexed: boolean | undefined = undefined;
1097
+ private immutable: boolean = false;
1096
1098
 
1097
1099
  compatibility: 6 | 7 | 8 | 9 | undefined;
1098
1100
 
@@ -1427,6 +1429,7 @@ export class DocumentIndex<
1427
1429
  this.canRead = properties.canRead;
1428
1430
  this.canSearch = properties.canSearch;
1429
1431
  this.includeIndexed = properties.includeIndexed;
1432
+ this.immutable = properties.immutable ?? false;
1430
1433
 
1431
1434
  @variant(0)
1432
1435
  class IndexedClassWithContext {
@@ -4663,6 +4666,53 @@ export class DocumentIndex<
4663
4666
  return indexedPlaceholders;
4664
4667
  };
4665
4668
 
4669
+ // The `visited` set prevents re-emitting the same document across pages
4670
+ // and sources, but different sources can return different versions of the
4671
+ // same document (e.g. a stale local head merged before a newer remote
4672
+ // head arrives). Plain id-based dedupe would let the first-seen, stale
4673
+ // version permanently shadow the newer one. If the id is still buffered
4674
+ // (not yet handed to the consumer) and the incoming result is strictly
4675
+ // preferred by the store's conflict rule, evict the stale buffered entry
4676
+ // so the caller can buffer the preferred result in its place. Returns
4677
+ // true when the caller should proceed to buffer the incoming result.
4678
+ // Results that were already emitted to the consumer cannot be retracted
4679
+ // here; those are only corrected via live updates/replication.
4680
+ // The preference direction mirrors the index merge rule in program.ts:
4681
+ // newest wins for mutable stores, oldest wins for immutable stores.
4682
+ const isPreferredContext = (
4683
+ incoming: types.Context,
4684
+ existing: types.Context,
4685
+ ): boolean =>
4686
+ incoming.head !== existing.head &&
4687
+ (this.immutable
4688
+ ? incoming.modified < existing.modified
4689
+ : incoming.modified > existing.modified);
4690
+
4691
+ const evictStaleBuffered = (
4692
+ indexKey: indexerTypes.IdPrimitive,
4693
+ incomingContext: types.Context,
4694
+ ): boolean => {
4695
+ for (const peerBuffer of peerBufferMap.values()) {
4696
+ for (let i = 0; i < peerBuffer.buffer.length; i++) {
4697
+ const existing = peerBuffer.buffer[i];
4698
+ const existingKey = indexerTypes.toId(
4699
+ this.indexByResolver(existing.indexed),
4700
+ ).primitive;
4701
+ if (existingKey !== indexKey) {
4702
+ continue;
4703
+ }
4704
+ if (!isPreferredContext(incomingContext, existing.context)) {
4705
+ // same or non-preferred version: keep normal dedupe behavior
4706
+ return false;
4707
+ }
4708
+ peerBuffer.buffer.splice(i, 1);
4709
+ indexedPlaceholders?.delete(indexKey);
4710
+ return true;
4711
+ }
4712
+ }
4713
+ return false; // not buffered (already emitted): skip incoming
4714
+ };
4715
+
4666
4716
  let done = false;
4667
4717
  let drain = false; // if true, close on empty once (overrides manual)
4668
4718
  let first = false;
@@ -4921,7 +4971,10 @@ export class DocumentIndex<
4921
4971
  indexedPlaceholders?.delete(indexKey);
4922
4972
  continue;
4923
4973
  }
4924
- if (visited.has(indexKey)) {
4974
+ if (
4975
+ visited.has(indexKey) &&
4976
+ !evictStaleBuffered(indexKey, result.context)
4977
+ ) {
4925
4978
  continue;
4926
4979
  }
4927
4980
  visited.add(indexKey);
@@ -4940,7 +4993,8 @@ export class DocumentIndex<
4940
4993
  result as unknown as types.ResultIndexedValue<I>;
4941
4994
  if (
4942
4995
  visited.has(indexKey) &&
4943
- !indexedPlaceholders?.has(indexKey)
4996
+ !indexedPlaceholders?.has(indexKey) &&
4997
+ !evictStaleBuffered(indexKey, indexedResult.context)
4944
4998
  ) {
4945
4999
  continue;
4946
5000
  }
@@ -5127,7 +5181,10 @@ export class DocumentIndex<
5127
5181
  indexedPlaceholders?.delete(keyPrimitive);
5128
5182
  continue;
5129
5183
  }
5130
- if (visited.has(keyPrimitive)) {
5184
+ if (
5185
+ visited.has(keyPrimitive) &&
5186
+ !evictStaleBuffered(keyPrimitive, result.context)
5187
+ ) {
5131
5188
  continue;
5132
5189
  }
5133
5190
  visited.add(keyPrimitive);
@@ -5154,7 +5211,11 @@ export class DocumentIndex<
5154
5211
  result as unknown as types.ResultIndexedValue<I>;
5155
5212
  if (
5156
5213
  visited.has(keyPrimitive) &&
5157
- !indexedPlaceholders?.has(keyPrimitive)
5214
+ !indexedPlaceholders?.has(keyPrimitive) &&
5215
+ !evictStaleBuffered(
5216
+ keyPrimitive,
5217
+ indexedResult.context,
5218
+ )
5158
5219
  ) {
5159
5220
  continue;
5160
5221
  }
@@ -5279,7 +5340,10 @@ export class DocumentIndex<
5279
5340
  indexedPlaceholders?.delete(indexKey);
5280
5341
  continue;
5281
5342
  }
5282
- if (visited.has(indexKey)) {
5343
+ if (
5344
+ visited.has(indexKey) &&
5345
+ !evictStaleBuffered(indexKey, result.context)
5346
+ ) {
5283
5347
  continue;
5284
5348
  }
5285
5349
  visited.add(indexKey);
@@ -5309,7 +5373,11 @@ export class DocumentIndex<
5309
5373
  result as unknown as types.ResultIndexedValue<I>;
5310
5374
  if (
5311
5375
  visited.has(indexKey) &&
5312
- !indexedPlaceholders?.has(indexKey)
5376
+ !indexedPlaceholders?.has(indexKey) &&
5377
+ !evictStaleBuffered(
5378
+ indexKey,
5379
+ indexedResult.context,
5380
+ )
5313
5381
  ) {
5314
5382
  continue;
5315
5383
  }