@peerbit/document 15.0.13 → 15.0.14

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.
@@ -32,7 +32,7 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
32
32
  }
33
33
  return useValue ? value : void 0;
34
34
  };
35
- import { BorshError, field, serialize, variant, } from "@dao-xyz/borsh";
35
+ import { BorshError, deserialize, field, serialize, variant, } from "@dao-xyz/borsh";
36
36
  import { AccessError } from "@peerbit/crypto";
37
37
  import { Context, NotFoundError, } from "@peerbit/document-interface";
38
38
  import { extractDocumentFieldSimple, initializeDocumentRust, planDocumentContext, planDocumentContextBatch, tryPlanDocumentContext, tryPlanDocumentContextBatch, } from "./native-rust.js";
@@ -41,6 +41,7 @@ import { Entry, EntryType, LamportClock, ShallowEntry, ShallowMeta, Timestamp, e
41
41
  import { logger as loggerFn } from "@peerbit/logger";
42
42
  import { Program } from "@peerbit/program";
43
43
  import { SharedLog, } from "@peerbit/shared-log";
44
+ import { detachCanPerformCallbackProperties, detachEntryPayloadForCallback, } from "./callback-detachment.js";
44
45
  import { MAX_BATCH_SIZE } from "./constants.js";
45
46
  import { BORSH_ENCODING_OPERATION, DeleteOperation, PutOperation, PutWithKeyOperation, coerceDeleteOperation, isDeleteOperation, isPutOperation, } from "./operation.js";
46
47
  import { createCanPerformPolicyEvaluator, createCanPerformDeletePolicyEvaluator, getCanPerformPolicyDescriptor, canPerformPolicyDeleteFieldPaths, canPerformPolicyNeedsDeleteValue, canPerformPolicyNeedsPreviousEntries, canPerformPolicyPutNeedsEntryPublicKeys, canPerformPolicySignedByFieldPaths, } from "./policy.js";
@@ -392,9 +393,16 @@ let Documents = (() => {
392
393
  _documentChangeListenerTrackingInitialized = false;
393
394
  _documentBackend;
394
395
  _canAppendDecodedDocuments = new WeakMap();
396
+ acceptPutOperation(operation, document, hasDocument) {
397
+ if (hasDocument) {
398
+ this._canAppendDecodedDocuments.set(operation, document);
399
+ }
400
+ return operation;
401
+ }
395
402
  _nativeDocumentIdExtractionPlan;
396
403
  _nativeDocumentFieldExtractionPlans;
397
404
  _hasLogTrim = false;
405
+ _hasCustomIdResolver = false;
398
406
  idResolver;
399
407
  domain;
400
408
  strictHistory;
@@ -418,6 +426,70 @@ let Documents = (() => {
418
426
  ? new NativeDocumentBackend(this.createNativeDocumentBackendContext())
419
427
  : new CompatDocumentBackend(this.putCompatDocumentBackend.bind(this), this.putManyCompatDocumentBackend.bind(this), this.delCompatDocumentBackend.bind(this));
420
428
  }
429
+ detachDomainEntryCallback(domain) {
430
+ const boundMethods = new Map();
431
+ const detachedFromEntry = (entry) => {
432
+ const fromEntry = Reflect.get(domain, "fromEntry", domain);
433
+ return Reflect.apply(fromEntry, domain, [
434
+ entry instanceof Entry
435
+ ? detachEntryPayloadForCallback(entry)
436
+ : entry,
437
+ ]);
438
+ };
439
+ const facade = Object.create(Object.getPrototypeOf(domain));
440
+ let callbackDomain;
441
+ callbackDomain = new Proxy(facade, {
442
+ get(_target, property) {
443
+ if (property === "fromEntry") {
444
+ return detachedFromEntry;
445
+ }
446
+ if (property === "valueOf") {
447
+ return () => callbackDomain;
448
+ }
449
+ const value = Reflect.get(domain, property, domain);
450
+ if (property === "constructor" || typeof value !== "function") {
451
+ return value;
452
+ }
453
+ const existing = boundMethods.get(property);
454
+ if (existing && existing.source === value) {
455
+ return existing.bound;
456
+ }
457
+ const bound = value.bind(domain);
458
+ boundMethods.set(property, { source: value, bound });
459
+ return bound;
460
+ },
461
+ set(_target, property, value) {
462
+ return Reflect.set(domain, property, value, domain);
463
+ },
464
+ has(_target, property) {
465
+ return Reflect.has(domain, property);
466
+ },
467
+ ownKeys() {
468
+ return Reflect.ownKeys(domain);
469
+ },
470
+ getOwnPropertyDescriptor(_target, property) {
471
+ const descriptor = Reflect.getOwnPropertyDescriptor(domain, property);
472
+ if (!descriptor) {
473
+ return undefined;
474
+ }
475
+ if (property === "fromEntry") {
476
+ return "value" in descriptor
477
+ ? {
478
+ ...descriptor,
479
+ value: detachedFromEntry,
480
+ configurable: true,
481
+ }
482
+ : {
483
+ ...descriptor,
484
+ get: () => detachedFromEntry,
485
+ configurable: true,
486
+ };
487
+ }
488
+ return { ...descriptor, configurable: true };
489
+ },
490
+ });
491
+ return callbackDomain;
492
+ }
421
493
  createNativeDocumentBackendContext() {
422
494
  return {
423
495
  assertPlainPutSupported: (doc, options) => {
@@ -1216,6 +1288,7 @@ let Documents = (() => {
1216
1288
  (typeof idProperty === "string"
1217
1289
  ? (obj) => obj[idProperty]
1218
1290
  : (obj) => indexerTypes.extractFieldValue(obj, idProperty));
1291
+ this._hasCustomIdResolver = options.id != null;
1219
1292
  this.idResolver = idResolver;
1220
1293
  this.strictHistory = options.strictHistory ?? false;
1221
1294
  this._hasLogTrim = options.log?.trim != null;
@@ -1252,7 +1325,9 @@ let Documents = (() => {
1252
1325
  // B12: the historical document->log compatibility mapping (6 -> log v8,
1253
1326
  // 7 -> log v9) is retired; the rejection at the top of open() fires for
1254
1327
  // any defined value before this point.
1255
- this.domain = options.domain?.(this);
1328
+ this.domain = options.domain
1329
+ ? this.detachDomainEntryCallback(options.domain(this))
1330
+ : undefined;
1256
1331
  let keepFunction;
1257
1332
  if (options?.keep === "self") {
1258
1333
  this.keepCache = new Set();
@@ -1293,7 +1368,16 @@ let Documents = (() => {
1293
1368
  };
1294
1369
  }
1295
1370
  else {
1296
- keepFunction = options?.keep;
1371
+ const keep = options?.keep;
1372
+ keepFunction = keep
1373
+ ? function (entry) {
1374
+ return Reflect.apply(keep, this, [
1375
+ entry instanceof Entry
1376
+ ? detachEntryPayloadForCallback(entry)
1377
+ : entry,
1378
+ ]);
1379
+ }
1380
+ : undefined;
1297
1381
  }
1298
1382
  await this.log.open({
1299
1383
  encoding: BORSH_ENCODING_OPERATION,
@@ -1316,7 +1400,7 @@ let Documents = (() => {
1316
1400
  distributionDebounceTime: options?.distributionDebounceTime,
1317
1401
  strictFullReplicaFallback: false,
1318
1402
  domain: options?.domain
1319
- ? () => options.domain(this)
1403
+ ? () => this.detachDomainEntryCallback(options.domain(this))
1320
1404
  : undefined,
1321
1405
  eagerBlocks: options?.eagerBlocks,
1322
1406
  fanout: options?.fanout,
@@ -1375,41 +1459,41 @@ let Documents = (() => {
1375
1459
  return false;
1376
1460
  }
1377
1461
  try {
1378
- let operation = l0;
1462
+ const operation = l0;
1379
1463
  if (this._optionCanPerform) {
1380
1464
  if (this._optionCanPerformNativePolicy && this.isNativeMode()) {
1381
1465
  return this.nativeCanPerformAllowsAppend(this._optionCanPerformNativePolicy, operation, entry, reference?.document);
1382
1466
  }
1383
- let document = reference?.document;
1384
- if (!document) {
1385
- if (isPutOperation(l0)) {
1386
- document =
1387
- this._canAppendDecodedDocuments.get(l0) ??
1388
- this._index.valueEncoding.decoder(l0.data);
1389
- if (!document) {
1390
- return false;
1391
- }
1392
- }
1393
- else if (isDeleteOperation(l0)) {
1394
- // Nothing to do here by default.
1395
- // Checking if the document exists is not necessary since it
1396
- // might already be deleted.
1397
- }
1398
- else {
1399
- throw new Error("Unsupported operation");
1467
+ let document;
1468
+ if (isPutOperation(l0)) {
1469
+ const cachedDocument = this._canAppendDecodedDocuments.get(l0);
1470
+ this._canAppendDecodedDocuments.delete(l0);
1471
+ document =
1472
+ cachedDocument ??
1473
+ this._index.valueEncoding.decoder(new Uint8Array(l0.data));
1474
+ if (!document) {
1475
+ return false;
1400
1476
  }
1401
1477
  }
1478
+ else if (isDeleteOperation(l0)) {
1479
+ // Nothing to do here by default.
1480
+ // Checking if the document exists is not necessary since it
1481
+ // might already be deleted.
1482
+ }
1483
+ else {
1484
+ throw new Error("Unsupported operation");
1485
+ }
1402
1486
  const previousEntries = this._optionCanPerformNativePolicy &&
1403
1487
  isPutOperation(operation) &&
1404
1488
  canPerformPolicyNeedsPreviousEntries(this._optionCanPerformNativePolicy)
1405
- ? await this.resolveCanPerformPreviousEntries(entry)
1489
+ ? (await this.resolveCanPerformPreviousEntries(entry)).map(detachEntryPayloadForCallback)
1406
1490
  : undefined;
1407
1491
  const deleteValue = this._optionCanPerformNativePolicy &&
1408
1492
  isDeleteOperation(operation) &&
1409
1493
  canPerformPolicyNeedsDeleteValue(this._optionCanPerformNativePolicy)
1410
1494
  ? await this.resolveCanPerformDeleteValue(operation)
1411
1495
  : undefined;
1412
- if (!(await this._optionCanPerform(isPutOperation(operation)
1496
+ if (!(await this._optionCanPerform(detachCanPerformCallbackProperties(isPutOperation(operation)
1413
1497
  ? {
1414
1498
  type: "put",
1415
1499
  value: document,
@@ -1422,7 +1506,7 @@ let Documents = (() => {
1422
1506
  value: deleteValue,
1423
1507
  operation,
1424
1508
  entry: entry,
1425
- }))) {
1509
+ })))) {
1426
1510
  return false;
1427
1511
  }
1428
1512
  }
@@ -1485,6 +1569,9 @@ let Documents = (() => {
1485
1569
  }
1486
1570
  return entries;
1487
1571
  }
1572
+ detachDocumentValueForCallback(document) {
1573
+ return this._index.valueEncoding.decoder(this._index.valueEncoding.encoder(document));
1574
+ }
1488
1575
  async resolveCanPerformDeleteValue(operation, options) {
1489
1576
  const key = operation.key instanceof indexerTypes.IdKey
1490
1577
  ? operation.key
@@ -1496,11 +1583,11 @@ let Documents = (() => {
1496
1583
  }
1497
1584
  const indexedDocument = await this.getLocalIdentityDocumentByHead(existingHead);
1498
1585
  if (indexedDocument) {
1499
- return indexedDocument;
1586
+ return this.detachDocumentValueForCallback(indexedDocument);
1500
1587
  }
1501
1588
  const indexedPolicyDocument = await this.getLocalIndexedDocumentForNativeDeletePolicy(key);
1502
1589
  if (indexedPolicyDocument) {
1503
- return indexedPolicyDocument;
1590
+ return deserialize(serialize(indexedPolicyDocument), this._index.indexedType);
1504
1591
  }
1505
1592
  if (options?.allowEntryFallback === false) {
1506
1593
  return;
@@ -1512,7 +1599,7 @@ let Documents = (() => {
1512
1599
  if (!isPutOperation(existingOperation)) {
1513
1600
  return;
1514
1601
  }
1515
- return this._index.valueEncoding.decoder(existingOperation.data);
1602
+ return this._index.valueEncoding.decoder(new Uint8Array(existingOperation.data));
1516
1603
  }
1517
1604
  async _canAppend(entry, reference) {
1518
1605
  const resolve = async (history) => {
@@ -1554,9 +1641,13 @@ let Documents = (() => {
1554
1641
  if (isPutOperation(operation)) {
1555
1642
  // check nexts
1556
1643
  const putOperation = operation;
1644
+ let decodedDocumentForCanPerform;
1645
+ let hasDecodedDocumentForCanPerform = false;
1557
1646
  let keyValue;
1558
1647
  if (reference?.document) {
1559
- keyValue = this.idResolver(reference.document);
1648
+ keyValue = this.idResolver(this._hasCustomIdResolver
1649
+ ? this.index.valueEncoding.decoder(new Uint8Array(putOperation.data))
1650
+ : reference.document);
1560
1651
  }
1561
1652
  else {
1562
1653
  keyValue = await this.getNativeDocumentIdFromPutOperation(putOperation);
@@ -1564,8 +1655,13 @@ let Documents = (() => {
1564
1655
  if (this.isNativeMode()) {
1565
1656
  return false;
1566
1657
  }
1567
- const value = this.index.valueEncoding.decoder(putOperation.data);
1568
- this._canAppendDecodedDocuments.set(putOperation, value);
1658
+ const value = this.index.valueEncoding.decoder(this._hasCustomIdResolver || this._optionCanPerform
1659
+ ? new Uint8Array(putOperation.data)
1660
+ : putOperation.data);
1661
+ if (this._optionCanPerform && !this._hasCustomIdResolver) {
1662
+ decodedDocumentForCanPerform = value;
1663
+ hasDecodedDocumentForCanPerform = true;
1664
+ }
1569
1665
  keyValue = this.idResolver(value);
1570
1666
  }
1571
1667
  }
@@ -1596,7 +1692,7 @@ let Documents = (() => {
1596
1692
  if (entry.meta.next.length > 0) {
1597
1693
  return false; // can not append to immutable document
1598
1694
  }
1599
- return putOperation;
1695
+ return this.acceptPutOperation(putOperation, decodedDocumentForCanPerform, hasDecodedDocumentForCanPerform);
1600
1696
  }
1601
1697
  else {
1602
1698
  if (this.strictHistory) {
@@ -1605,7 +1701,7 @@ let Documents = (() => {
1605
1701
  return false;
1606
1702
  }
1607
1703
  if (entry.meta.next[0] === existingContext.head) {
1608
- return putOperation;
1704
+ return this.acceptPutOperation(putOperation, decodedDocumentForCanPerform, hasDecodedDocumentForCanPerform);
1609
1705
  }
1610
1706
  const prevEntry = await this.log.log.entryIndex.get(existingContext.head);
1611
1707
  if (!prevEntry) {
@@ -1614,16 +1710,19 @@ let Documents = (() => {
1614
1710
  return false;
1615
1711
  }
1616
1712
  const referenceHistoryCorrectly = await pointsToHistory(prevEntry);
1617
- return referenceHistoryCorrectly ? putOperation : false;
1713
+ return referenceHistoryCorrectly
1714
+ ? this.acceptPutOperation(putOperation, decodedDocumentForCanPerform, hasDecodedDocumentForCanPerform)
1715
+ : false;
1618
1716
  }
1619
1717
  else {
1620
- return putOperation;
1718
+ return this.acceptPutOperation(putOperation, decodedDocumentForCanPerform, hasDecodedDocumentForCanPerform);
1621
1719
  }
1622
1720
  }
1623
1721
  }
1624
1722
  else {
1625
1723
  // Keep existing behavior: next pointers may express document dependencies.
1626
1724
  }
1725
+ return this.acceptPutOperation(putOperation, decodedDocumentForCanPerform, hasDecodedDocumentForCanPerform);
1627
1726
  }
1628
1727
  else if (isDeleteOperation(operation)) {
1629
1728
  if (entry.meta.next.length !== 1) {
@@ -1671,7 +1770,6 @@ let Documents = (() => {
1671
1770
  else {
1672
1771
  throw new Error("Unsupported operation");
1673
1772
  }
1674
- return operation;
1675
1773
  }
1676
1774
  catch (error) {
1677
1775
  if (error instanceof AccessError) {
@@ -3404,12 +3502,15 @@ let Documents = (() => {
3404
3502
  }
3405
3503
  }
3406
3504
  }
3407
- let value = (isReferencedAppendEntry && reference?.document) ||
3408
- this.index.valueEncoding.decoder(payload.data);
3505
+ let value = isReferencedAppendEntry && reference?.document
3506
+ ? reference.document
3507
+ : this.index.valueEncoding.decoder(new Uint8Array(payload.data));
3409
3508
  // get index key from value
3410
3509
  const key = isReferencedAppendEntry && reference?.key
3411
3510
  ? reference.key
3412
- : indexerTypes.toId(this.idResolver(value));
3511
+ : indexerTypes.toId(this.idResolver(this._hasCustomIdResolver
3512
+ ? this.index.valueEncoding.decoder(new Uint8Array(payload.data))
3513
+ : value));
3413
3514
  // document is already updated with more recent entry
3414
3515
  if (modified.has(key.primitive)) {
3415
3516
  // Duplicate ids deliberately retain the scalar boundary until