@peerbit/native-backbone 0.1.4 → 0.2.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.
Files changed (44) hide show
  1. package/README.md +31 -0
  2. package/dist/src/durability/codec.d.ts +86 -0
  3. package/dist/src/durability/codec.d.ts.map +1 -0
  4. package/dist/src/durability/codec.js +365 -0
  5. package/dist/src/durability/codec.js.map +1 -0
  6. package/dist/src/durability/lease.d.ts +59 -0
  7. package/dist/src/durability/lease.d.ts.map +1 -0
  8. package/dist/src/durability/lease.js +48 -0
  9. package/dist/src/durability/lease.js.map +1 -0
  10. package/dist/src/durability/memory-storage.d.ts +37 -0
  11. package/dist/src/durability/memory-storage.d.ts.map +1 -0
  12. package/dist/src/durability/memory-storage.js +436 -0
  13. package/dist/src/durability/memory-storage.js.map +1 -0
  14. package/dist/src/durability/node-lease.d.ts +14 -0
  15. package/dist/src/durability/node-lease.d.ts.map +1 -0
  16. package/dist/src/durability/node-lease.js +214 -0
  17. package/dist/src/durability/node-lease.js.map +1 -0
  18. package/dist/src/durability/node-storage.d.ts +76 -0
  19. package/dist/src/durability/node-storage.d.ts.map +1 -0
  20. package/dist/src/durability/node-storage.js +1813 -0
  21. package/dist/src/durability/node-storage.js.map +1 -0
  22. package/dist/src/durability/storage.d.ts +224 -0
  23. package/dist/src/durability/storage.d.ts.map +1 -0
  24. package/dist/src/durability/storage.js +343 -0
  25. package/dist/src/durability/storage.js.map +1 -0
  26. package/dist/src/index.d.ts +93 -15
  27. package/dist/src/index.d.ts.map +1 -1
  28. package/dist/src/index.js +717 -199
  29. package/dist/src/index.js.map +1 -1
  30. package/dist/wasm/README.md +31 -0
  31. package/dist/wasm/native_backbone.d.ts +131 -115
  32. package/dist/wasm/native_backbone.js +96 -0
  33. package/dist/wasm/native_backbone_bg.wasm +0 -0
  34. package/dist/wasm/native_backbone_bg.wasm.d.ts +119 -115
  35. package/package.json +4 -3
  36. package/src/durability/codec.ts +683 -0
  37. package/src/durability/lease.ts +87 -0
  38. package/src/durability/memory-storage.ts +593 -0
  39. package/src/durability/node-lease.ts +293 -0
  40. package/src/durability/node-storage.ts +2798 -0
  41. package/src/durability/storage.ts +682 -0
  42. package/src/durability.rs +1872 -0
  43. package/src/index.ts +1392 -735
  44. package/src/lib.rs +1 -0
package/src/index.ts CHANGED
@@ -1,5 +1,12 @@
1
1
  import { calculateRawCid, cidifyString } from "@peerbit/blocks-interface";
2
2
 
3
+ export * from "./durability/codec.js";
4
+ export * from "./durability/lease.js";
5
+ export * from "./durability/memory-storage.js";
6
+ export * from "./durability/node-lease.js";
7
+ export * from "./durability/node-storage.js";
8
+ export * from "./durability/storage.js";
9
+
3
10
  export type RangeResolution = "u32" | "u64";
4
11
 
5
12
  type NativePeerbitBackboneHandle = {
@@ -1274,10 +1281,10 @@ type NativePeerbitBackboneHandle = {
1274
1281
  documentProjectionEncodedDocument: Uint8Array,
1275
1282
  documentProjectionSigner: Uint8Array | undefined,
1276
1283
  ) => unknown[];
1277
- prepare_plain_committed_no_next_storage_append_document_index_compact_transaction: (
1278
- wallTime: bigint,
1279
- logical: number,
1280
- gid: string,
1284
+ prepare_plain_committed_no_next_storage_append_document_index_compact_transaction: (
1285
+ wallTime: bigint,
1286
+ logical: number,
1287
+ gid: string,
1281
1288
  type: number,
1282
1289
  metaData: Uint8Array | undefined,
1283
1290
  payloadData: Uint8Array,
@@ -1290,31 +1297,31 @@ type NativePeerbitBackboneHandle = {
1290
1297
  documentValuePrefixBytes: Uint8Array,
1291
1298
  documentExistingCreated: string,
1292
1299
  documentByteElementIndexLimit: number,
1293
- documentDeleteTrimmedHeads: boolean,
1294
- trimLengthTo: number | undefined,
1295
- ) => unknown[];
1296
- prepare_plain_committed_no_next_storage_append_document_index_compact_plain_put_payload_transaction?: (
1297
- wallTime: bigint,
1298
- logical: number,
1299
- gid: string,
1300
- type: number,
1301
- metaData: Uint8Array | undefined,
1302
- payloadData: Uint8Array,
1303
- replicas: number,
1304
- roleAgeMs: number,
1305
- now: string,
1306
- selfHash: string,
1307
- selfReplicating: boolean,
1308
- documentKey: string,
1309
- documentExistingCreated: string,
1310
- documentByteElementIndexLimit: number,
1311
- documentDeleteTrimmedHeads: boolean,
1312
- trimLengthTo: number | undefined,
1313
- ) => unknown[];
1314
- prepare_plain_committed_no_next_storage_append_document_index_compact_batch_transaction?: (
1315
- wallTimes: BigUint64Array,
1316
- logicals: Uint32Array,
1317
- gids: string[],
1300
+ documentDeleteTrimmedHeads: boolean,
1301
+ trimLengthTo: number | undefined,
1302
+ ) => unknown[];
1303
+ prepare_plain_committed_no_next_storage_append_document_index_compact_plain_put_payload_transaction?: (
1304
+ wallTime: bigint,
1305
+ logical: number,
1306
+ gid: string,
1307
+ type: number,
1308
+ metaData: Uint8Array | undefined,
1309
+ payloadData: Uint8Array,
1310
+ replicas: number,
1311
+ roleAgeMs: number,
1312
+ now: string,
1313
+ selfHash: string,
1314
+ selfReplicating: boolean,
1315
+ documentKey: string,
1316
+ documentExistingCreated: string,
1317
+ documentByteElementIndexLimit: number,
1318
+ documentDeleteTrimmedHeads: boolean,
1319
+ trimLengthTo: number | undefined,
1320
+ ) => unknown[];
1321
+ prepare_plain_committed_no_next_storage_append_document_index_compact_batch_transaction?: (
1322
+ wallTimes: BigUint64Array,
1323
+ logicals: Uint32Array,
1324
+ gids: string[],
1318
1325
  type: number,
1319
1326
  metaDatas: Array<Uint8Array | undefined>,
1320
1327
  payloadDatas: Uint8Array[],
@@ -1327,27 +1334,27 @@ type NativePeerbitBackboneHandle = {
1327
1334
  documentValuePrefixBytes: Uint8Array[],
1328
1335
  documentExistingCreated: string[],
1329
1336
  documentByteElementIndexLimit: number,
1330
- documentDeleteTrimmedHeads: boolean,
1331
- trimLengthTo: number | undefined,
1332
- ) => unknown[][];
1333
- prepare_plain_committed_no_next_storage_append_document_index_compact_plain_put_payload_batch_transaction?: (
1334
- wallTimes: BigUint64Array,
1335
- logicals: Uint32Array,
1336
- gids: string[],
1337
- type: number,
1338
- metaDatas: Array<Uint8Array | undefined>,
1339
- payloadDatas: Uint8Array[],
1340
- replicas: number,
1341
- roleAgeMs: number,
1342
- now: string,
1343
- selfHash: string,
1344
- selfReplicating: boolean,
1345
- documentKeys: string[],
1346
- documentExistingCreated: string[],
1347
- documentByteElementIndexLimit: number,
1348
- documentDeleteTrimmedHeads: boolean,
1349
- trimLengthTo: number | undefined,
1350
- ) => unknown[][];
1337
+ documentDeleteTrimmedHeads: boolean,
1338
+ trimLengthTo: number | undefined,
1339
+ ) => unknown[][];
1340
+ prepare_plain_committed_no_next_storage_append_document_index_compact_plain_put_payload_batch_transaction?: (
1341
+ wallTimes: BigUint64Array,
1342
+ logicals: Uint32Array,
1343
+ gids: string[],
1344
+ type: number,
1345
+ metaDatas: Array<Uint8Array | undefined>,
1346
+ payloadDatas: Uint8Array[],
1347
+ replicas: number,
1348
+ roleAgeMs: number,
1349
+ now: string,
1350
+ selfHash: string,
1351
+ selfReplicating: boolean,
1352
+ documentKeys: string[],
1353
+ documentExistingCreated: string[],
1354
+ documentByteElementIndexLimit: number,
1355
+ documentDeleteTrimmedHeads: boolean,
1356
+ trimLengthTo: number | undefined,
1357
+ ) => unknown[][];
1351
1358
  prepare_plain_committed_no_next_storage_append_document_index_cached_plan_compact_batch_transaction?: (
1352
1359
  wallTimes: BigUint64Array,
1353
1360
  logicals: Uint32Array,
@@ -1584,8 +1591,23 @@ type NativePeerbitBackboneHandle = {
1584
1591
  documentProjectionSigner: Uint8Array | undefined,
1585
1592
  trimLengthTo: number,
1586
1593
  ) => unknown[];
1587
- prepare_plain_committed_storage_append_transaction: (
1588
- wallTime: bigint,
1594
+ prepare_plain_committed_storage_append_transaction: (
1595
+ wallTime: bigint,
1596
+ logical: number,
1597
+ gid: string,
1598
+ next: string[],
1599
+ type: number,
1600
+ metaData: Uint8Array | undefined,
1601
+ payloadData: Uint8Array,
1602
+ replicas: number,
1603
+ roleAgeMs: number,
1604
+ now: string,
1605
+ selfHash: string,
1606
+ selfReplicating: boolean,
1607
+ resolveTrimmedEntries: boolean,
1608
+ ) => unknown[];
1609
+ prepare_plain_committed_storage_append_document_delete_transaction: (
1610
+ wallTime: bigint,
1589
1611
  logical: number,
1590
1612
  gid: string,
1591
1613
  next: string[],
@@ -1596,25 +1618,10 @@ type NativePeerbitBackboneHandle = {
1596
1618
  roleAgeMs: number,
1597
1619
  now: string,
1598
1620
  selfHash: string,
1599
- selfReplicating: boolean,
1600
- resolveTrimmedEntries: boolean,
1601
- ) => unknown[];
1602
- prepare_plain_committed_storage_append_document_delete_transaction: (
1603
- wallTime: bigint,
1604
- logical: number,
1605
- gid: string,
1606
- next: string[],
1607
- type: number,
1608
- metaData: Uint8Array | undefined,
1609
- payloadData: Uint8Array,
1610
- replicas: number,
1611
- roleAgeMs: number,
1612
- now: string,
1613
- selfHash: string,
1614
- selfReplicating: boolean,
1615
- resolveTrimmedEntries: boolean,
1616
- documentKey: string,
1617
- ) => unknown[];
1621
+ selfReplicating: boolean,
1622
+ resolveTrimmedEntries: boolean,
1623
+ documentKey: string,
1624
+ ) => unknown[];
1618
1625
  prepare_plain_committed_storage_append_document_index_transaction: (
1619
1626
  wallTime: bigint,
1620
1627
  logical: number,
@@ -1664,10 +1671,10 @@ type NativePeerbitBackboneHandle = {
1664
1671
  documentProjectionSigner: Uint8Array | undefined,
1665
1672
  trimLengthTo: number | undefined,
1666
1673
  ) => unknown[];
1667
- prepare_plain_committed_storage_append_document_index_latest_required_previous_signer_transaction?: (
1668
- wallTime: bigint,
1669
- logical: number,
1670
- gid: string,
1674
+ prepare_plain_committed_storage_append_document_index_latest_required_previous_signer_transaction?: (
1675
+ wallTime: bigint,
1676
+ logical: number,
1677
+ gid: string,
1671
1678
  type: number,
1672
1679
  metaData: Uint8Array | undefined,
1673
1680
  payloadData: Uint8Array,
@@ -1686,116 +1693,116 @@ type NativePeerbitBackboneHandle = {
1686
1693
  | undefined,
1687
1694
  documentProjectionEncodedDocument: Uint8Array | undefined,
1688
1695
  documentProjectionSigner: Uint8Array | undefined,
1689
- requiredPreviousSignerPublicKey: Uint8Array,
1690
- trimLengthTo: number | undefined,
1691
- ) => unknown[];
1692
- prepare_plain_committed_storage_append_document_index_latest_compact_transaction?: (
1693
- wallTime: bigint,
1694
- logical: number,
1695
- gid: string,
1696
- type: number,
1697
- metaData: Uint8Array | undefined,
1698
- payloadData: Uint8Array,
1699
- replicas: number,
1700
- roleAgeMs: number,
1701
- now: string,
1702
- selfHash: string,
1703
- selfReplicating: boolean,
1704
- documentKey: string,
1705
- documentValuePrefixBytes: Uint8Array,
1706
- documentByteElementIndexLimit: number,
1707
- documentDeleteTrimmedHeads: boolean,
1708
- documentProjectionPlan:
1709
- | NativeBackboneSimpleDocumentProjectionPlan
1710
- | undefined,
1711
- documentProjectionEncodedDocument: Uint8Array | undefined,
1712
- documentProjectionSigner: Uint8Array | undefined,
1713
- trimLengthTo: number | undefined,
1714
- ) => unknown[];
1715
- prepare_plain_committed_storage_append_document_index_latest_compact_plain_put_payload_transaction?: (
1716
- wallTime: bigint,
1717
- logical: number,
1718
- gid: string,
1719
- type: number,
1720
- metaData: Uint8Array | undefined,
1721
- payloadData: Uint8Array,
1722
- replicas: number,
1723
- roleAgeMs: number,
1724
- now: string,
1725
- selfHash: string,
1726
- selfReplicating: boolean,
1727
- documentKey: string,
1728
- documentByteElementIndexLimit: number,
1729
- documentDeleteTrimmedHeads: boolean,
1730
- trimLengthTo: number | undefined,
1731
- ) => unknown[];
1732
- prepare_plain_committed_storage_append_document_index_latest_required_previous_signer_compact_transaction?: (
1733
- wallTime: bigint,
1734
- logical: number,
1735
- gid: string,
1736
- type: number,
1737
- metaData: Uint8Array | undefined,
1738
- payloadData: Uint8Array,
1739
- replicas: number,
1740
- roleAgeMs: number,
1741
- now: string,
1742
- selfHash: string,
1743
- selfReplicating: boolean,
1744
- documentKey: string,
1745
- documentValuePrefixBytes: Uint8Array,
1746
- documentByteElementIndexLimit: number,
1747
- documentDeleteTrimmedHeads: boolean,
1748
- documentProjectionPlan:
1749
- | NativeBackboneSimpleDocumentProjectionPlan
1750
- | undefined,
1751
- documentProjectionEncodedDocument: Uint8Array | undefined,
1752
- documentProjectionSigner: Uint8Array | undefined,
1753
- requiredPreviousSignerPublicKey: Uint8Array,
1754
- trimLengthTo: number | undefined,
1755
- ) => unknown[];
1756
- prepare_plain_committed_storage_append_document_index_latest_cached_plan_compact_transaction?: (
1757
- wallTime: bigint,
1758
- logical: number,
1759
- gid: string,
1760
- type: number,
1761
- metaData: Uint8Array | undefined,
1762
- payloadData: Uint8Array,
1763
- replicas: number,
1764
- roleAgeMs: number,
1765
- now: string,
1766
- selfHash: string,
1767
- selfReplicating: boolean,
1768
- documentKey: string,
1769
- documentByteElementIndexLimit: number,
1770
- documentDeleteTrimmedHeads: boolean,
1771
- documentProjectionPlanId: number,
1772
- documentProjectionEncodedDocument: Uint8Array,
1773
- documentProjectionSigner: Uint8Array | undefined,
1774
- trimLengthTo: number | undefined,
1775
- ) => unknown[];
1776
- prepare_plain_committed_storage_append_document_index_latest_cached_plan_compact_plain_put_payload_transaction?: (
1777
- wallTime: bigint,
1778
- logical: number,
1779
- gid: string,
1780
- type: number,
1781
- metaData: Uint8Array | undefined,
1782
- payloadData: Uint8Array,
1783
- replicas: number,
1784
- roleAgeMs: number,
1785
- now: string,
1786
- selfHash: string,
1787
- selfReplicating: boolean,
1788
- documentKey: string,
1789
- documentByteElementIndexLimit: number,
1790
- documentDeleteTrimmedHeads: boolean,
1791
- documentProjectionPlanId: number,
1792
- documentProjectionSigner: Uint8Array | undefined,
1793
- trimLengthTo: number | undefined,
1794
- ) => unknown[];
1795
- prepare_plain_committed_storage_append_document_index_latest_cached_plan_transaction: (
1796
- wallTime: bigint,
1797
- logical: number,
1798
- gid: string,
1696
+ requiredPreviousSignerPublicKey: Uint8Array,
1697
+ trimLengthTo: number | undefined,
1698
+ ) => unknown[];
1699
+ prepare_plain_committed_storage_append_document_index_latest_compact_transaction?: (
1700
+ wallTime: bigint,
1701
+ logical: number,
1702
+ gid: string,
1703
+ type: number,
1704
+ metaData: Uint8Array | undefined,
1705
+ payloadData: Uint8Array,
1706
+ replicas: number,
1707
+ roleAgeMs: number,
1708
+ now: string,
1709
+ selfHash: string,
1710
+ selfReplicating: boolean,
1711
+ documentKey: string,
1712
+ documentValuePrefixBytes: Uint8Array,
1713
+ documentByteElementIndexLimit: number,
1714
+ documentDeleteTrimmedHeads: boolean,
1715
+ documentProjectionPlan:
1716
+ | NativeBackboneSimpleDocumentProjectionPlan
1717
+ | undefined,
1718
+ documentProjectionEncodedDocument: Uint8Array | undefined,
1719
+ documentProjectionSigner: Uint8Array | undefined,
1720
+ trimLengthTo: number | undefined,
1721
+ ) => unknown[];
1722
+ prepare_plain_committed_storage_append_document_index_latest_compact_plain_put_payload_transaction?: (
1723
+ wallTime: bigint,
1724
+ logical: number,
1725
+ gid: string,
1726
+ type: number,
1727
+ metaData: Uint8Array | undefined,
1728
+ payloadData: Uint8Array,
1729
+ replicas: number,
1730
+ roleAgeMs: number,
1731
+ now: string,
1732
+ selfHash: string,
1733
+ selfReplicating: boolean,
1734
+ documentKey: string,
1735
+ documentByteElementIndexLimit: number,
1736
+ documentDeleteTrimmedHeads: boolean,
1737
+ trimLengthTo: number | undefined,
1738
+ ) => unknown[];
1739
+ prepare_plain_committed_storage_append_document_index_latest_required_previous_signer_compact_transaction?: (
1740
+ wallTime: bigint,
1741
+ logical: number,
1742
+ gid: string,
1743
+ type: number,
1744
+ metaData: Uint8Array | undefined,
1745
+ payloadData: Uint8Array,
1746
+ replicas: number,
1747
+ roleAgeMs: number,
1748
+ now: string,
1749
+ selfHash: string,
1750
+ selfReplicating: boolean,
1751
+ documentKey: string,
1752
+ documentValuePrefixBytes: Uint8Array,
1753
+ documentByteElementIndexLimit: number,
1754
+ documentDeleteTrimmedHeads: boolean,
1755
+ documentProjectionPlan:
1756
+ | NativeBackboneSimpleDocumentProjectionPlan
1757
+ | undefined,
1758
+ documentProjectionEncodedDocument: Uint8Array | undefined,
1759
+ documentProjectionSigner: Uint8Array | undefined,
1760
+ requiredPreviousSignerPublicKey: Uint8Array,
1761
+ trimLengthTo: number | undefined,
1762
+ ) => unknown[];
1763
+ prepare_plain_committed_storage_append_document_index_latest_cached_plan_compact_transaction?: (
1764
+ wallTime: bigint,
1765
+ logical: number,
1766
+ gid: string,
1767
+ type: number,
1768
+ metaData: Uint8Array | undefined,
1769
+ payloadData: Uint8Array,
1770
+ replicas: number,
1771
+ roleAgeMs: number,
1772
+ now: string,
1773
+ selfHash: string,
1774
+ selfReplicating: boolean,
1775
+ documentKey: string,
1776
+ documentByteElementIndexLimit: number,
1777
+ documentDeleteTrimmedHeads: boolean,
1778
+ documentProjectionPlanId: number,
1779
+ documentProjectionEncodedDocument: Uint8Array,
1780
+ documentProjectionSigner: Uint8Array | undefined,
1781
+ trimLengthTo: number | undefined,
1782
+ ) => unknown[];
1783
+ prepare_plain_committed_storage_append_document_index_latest_cached_plan_compact_plain_put_payload_transaction?: (
1784
+ wallTime: bigint,
1785
+ logical: number,
1786
+ gid: string,
1787
+ type: number,
1788
+ metaData: Uint8Array | undefined,
1789
+ payloadData: Uint8Array,
1790
+ replicas: number,
1791
+ roleAgeMs: number,
1792
+ now: string,
1793
+ selfHash: string,
1794
+ selfReplicating: boolean,
1795
+ documentKey: string,
1796
+ documentByteElementIndexLimit: number,
1797
+ documentDeleteTrimmedHeads: boolean,
1798
+ documentProjectionPlanId: number,
1799
+ documentProjectionSigner: Uint8Array | undefined,
1800
+ trimLengthTo: number | undefined,
1801
+ ) => unknown[];
1802
+ prepare_plain_committed_storage_append_document_index_latest_cached_plan_transaction: (
1803
+ wallTime: bigint,
1804
+ logical: number,
1805
+ gid: string,
1799
1806
  type: number,
1800
1807
  metaData: Uint8Array | undefined,
1801
1808
  payloadData: Uint8Array,
@@ -1852,10 +1859,10 @@ type NativePeerbitBackboneHandle = {
1852
1859
  requiredPreviousSignerPublicKey: Uint8Array,
1853
1860
  trimLengthTo: number | undefined,
1854
1861
  ) => unknown[][];
1855
- prepare_plain_committed_storage_append_document_index_latest_compact_batch_transaction?: (
1856
- wallTimes: BigUint64Array,
1857
- logicals: Uint32Array,
1858
- gids: string[],
1862
+ prepare_plain_committed_storage_append_document_index_latest_compact_batch_transaction?: (
1863
+ wallTimes: BigUint64Array,
1864
+ logicals: Uint32Array,
1865
+ gids: string[],
1859
1866
  type: number,
1860
1867
  metaDatas: Array<Uint8Array | undefined>,
1861
1868
  payloadDatas: Uint8Array[],
@@ -1867,26 +1874,26 @@ type NativePeerbitBackboneHandle = {
1867
1874
  documentKeys: string[],
1868
1875
  documentValuePrefixBytes: Uint8Array[],
1869
1876
  documentByteElementIndexLimit: number,
1870
- documentDeleteTrimmedHeads: boolean,
1871
- trimLengthTo: number | undefined,
1872
- ) => unknown[][];
1873
- prepare_plain_committed_storage_append_document_index_latest_compact_plain_put_payload_batch_transaction?: (
1874
- wallTimes: BigUint64Array,
1875
- logicals: Uint32Array,
1876
- gids: string[],
1877
- type: number,
1878
- metaDatas: Array<Uint8Array | undefined>,
1879
- payloadDatas: Uint8Array[],
1880
- replicas: number,
1881
- roleAgeMs: number,
1882
- now: string,
1883
- selfHash: string,
1884
- selfReplicating: boolean,
1885
- documentKeys: string[],
1886
- documentByteElementIndexLimit: number,
1887
- documentDeleteTrimmedHeads: boolean,
1888
- trimLengthTo: number | undefined,
1889
- ) => unknown[][];
1877
+ documentDeleteTrimmedHeads: boolean,
1878
+ trimLengthTo: number | undefined,
1879
+ ) => unknown[][];
1880
+ prepare_plain_committed_storage_append_document_index_latest_compact_plain_put_payload_batch_transaction?: (
1881
+ wallTimes: BigUint64Array,
1882
+ logicals: Uint32Array,
1883
+ gids: string[],
1884
+ type: number,
1885
+ metaDatas: Array<Uint8Array | undefined>,
1886
+ payloadDatas: Uint8Array[],
1887
+ replicas: number,
1888
+ roleAgeMs: number,
1889
+ now: string,
1890
+ selfHash: string,
1891
+ selfReplicating: boolean,
1892
+ documentKeys: string[],
1893
+ documentByteElementIndexLimit: number,
1894
+ documentDeleteTrimmedHeads: boolean,
1895
+ trimLengthTo: number | undefined,
1896
+ ) => unknown[][];
1890
1897
  prepare_plain_committed_storage_append_document_index_latest_required_previous_signer_compact_batch_transaction?: (
1891
1898
  wallTimes: BigUint64Array,
1892
1899
  logicals: Uint32Array,
@@ -1906,9 +1913,30 @@ type NativePeerbitBackboneHandle = {
1906
1913
  requiredPreviousSignerPublicKey: Uint8Array,
1907
1914
  trimLengthTo: number | undefined,
1908
1915
  ) => unknown[][];
1909
- prepare_plain_committed_storage_append_document_index_latest_cached_plan_batch_transaction?: (
1910
- wallTimes: BigUint64Array,
1911
- logicals: Uint32Array,
1916
+ prepare_plain_committed_storage_append_document_index_latest_cached_plan_batch_transaction?: (
1917
+ wallTimes: BigUint64Array,
1918
+ logicals: Uint32Array,
1919
+ gids: string[],
1920
+ type: number,
1921
+ metaDatas: Array<Uint8Array | undefined>,
1922
+ payloadDatas: Uint8Array[],
1923
+ replicas: number,
1924
+ roleAgeMs: number,
1925
+ now: string,
1926
+ selfHash: string,
1927
+ selfReplicating: boolean,
1928
+ resolveTrimmedEntries: boolean,
1929
+ documentKeys: string[],
1930
+ documentByteElementIndexLimit: number,
1931
+ documentDeleteTrimmedHeads: boolean,
1932
+ documentProjectionPlanIds: Uint32Array,
1933
+ documentProjectionEncodedDocuments: Uint8Array[],
1934
+ documentProjectionSigners: Array<Uint8Array | undefined>,
1935
+ trimLengthTo: number | undefined,
1936
+ ) => unknown[][];
1937
+ prepare_plain_committed_storage_append_document_index_latest_required_previous_signer_cached_plan_batch_transaction?: (
1938
+ wallTimes: BigUint64Array,
1939
+ logicals: Uint32Array,
1912
1940
  gids: string[],
1913
1941
  type: number,
1914
1942
  metaDatas: Array<Uint8Array | undefined>,
@@ -1924,34 +1952,33 @@ type NativePeerbitBackboneHandle = {
1924
1952
  documentDeleteTrimmedHeads: boolean,
1925
1953
  documentProjectionPlanIds: Uint32Array,
1926
1954
  documentProjectionEncodedDocuments: Uint8Array[],
1927
- documentProjectionSigners: Array<Uint8Array | undefined>,
1928
- trimLengthTo: number | undefined,
1929
- ) => unknown[][];
1930
- prepare_plain_committed_storage_append_document_index_latest_required_previous_signer_cached_plan_batch_transaction?: (
1931
- wallTimes: BigUint64Array,
1932
- logicals: Uint32Array,
1933
- gids: string[],
1934
- type: number,
1935
- metaDatas: Array<Uint8Array | undefined>,
1936
- payloadDatas: Uint8Array[],
1937
- replicas: number,
1938
- roleAgeMs: number,
1939
- now: string,
1940
- selfHash: string,
1941
- selfReplicating: boolean,
1942
- resolveTrimmedEntries: boolean,
1943
- documentKeys: string[],
1944
- documentByteElementIndexLimit: number,
1945
- documentDeleteTrimmedHeads: boolean,
1946
- documentProjectionPlanIds: Uint32Array,
1947
- documentProjectionEncodedDocuments: Uint8Array[],
1948
- documentProjectionSigners: Array<Uint8Array | undefined>,
1949
- requiredPreviousSignerPublicKey: Uint8Array,
1950
- trimLengthTo: number | undefined,
1951
- ) => unknown[][];
1952
- prepare_plain_committed_storage_append_document_index_latest_cached_plan_compact_batch_transaction?: (
1953
- wallTimes: BigUint64Array,
1954
- logicals: Uint32Array,
1955
+ documentProjectionSigners: Array<Uint8Array | undefined>,
1956
+ requiredPreviousSignerPublicKey: Uint8Array,
1957
+ trimLengthTo: number | undefined,
1958
+ ) => unknown[][];
1959
+ prepare_plain_committed_storage_append_document_index_latest_cached_plan_compact_batch_transaction?: (
1960
+ wallTimes: BigUint64Array,
1961
+ logicals: Uint32Array,
1962
+ gids: string[],
1963
+ type: number,
1964
+ metaDatas: Array<Uint8Array | undefined>,
1965
+ payloadDatas: Uint8Array[],
1966
+ replicas: number,
1967
+ roleAgeMs: number,
1968
+ now: string,
1969
+ selfHash: string,
1970
+ selfReplicating: boolean,
1971
+ documentKeys: string[],
1972
+ documentByteElementIndexLimit: number,
1973
+ documentDeleteTrimmedHeads: boolean,
1974
+ documentProjectionPlanIds: Uint32Array,
1975
+ documentProjectionEncodedDocuments: Uint8Array[],
1976
+ documentProjectionSigners: Array<Uint8Array | undefined>,
1977
+ trimLengthTo: number | undefined,
1978
+ ) => unknown[][];
1979
+ prepare_plain_committed_storage_append_document_index_latest_required_previous_signer_cached_plan_compact_batch_transaction?: (
1980
+ wallTimes: BigUint64Array,
1981
+ logicals: Uint32Array,
1955
1982
  gids: string[],
1956
1983
  type: number,
1957
1984
  metaDatas: Array<Uint8Array | undefined>,
@@ -1966,33 +1993,13 @@ type NativePeerbitBackboneHandle = {
1966
1993
  documentDeleteTrimmedHeads: boolean,
1967
1994
  documentProjectionPlanIds: Uint32Array,
1968
1995
  documentProjectionEncodedDocuments: Uint8Array[],
1969
- documentProjectionSigners: Array<Uint8Array | undefined>,
1970
- trimLengthTo: number | undefined,
1971
- ) => unknown[][];
1972
- prepare_plain_committed_storage_append_document_index_latest_required_previous_signer_cached_plan_compact_batch_transaction?: (
1973
- wallTimes: BigUint64Array,
1974
- logicals: Uint32Array,
1975
- gids: string[],
1976
- type: number,
1977
- metaDatas: Array<Uint8Array | undefined>,
1978
- payloadDatas: Uint8Array[],
1979
- replicas: number,
1980
- roleAgeMs: number,
1981
- now: string,
1982
- selfHash: string,
1983
- selfReplicating: boolean,
1984
- documentKeys: string[],
1985
- documentByteElementIndexLimit: number,
1986
- documentDeleteTrimmedHeads: boolean,
1987
- documentProjectionPlanIds: Uint32Array,
1988
- documentProjectionEncodedDocuments: Uint8Array[],
1989
- documentProjectionSigners: Array<Uint8Array | undefined>,
1990
- requiredPreviousSignerPublicKey: Uint8Array,
1991
- trimLengthTo: number | undefined,
1992
- ) => unknown[][];
1993
- prepare_plain_committed_storage_append_document_index_latest_cached_plan_compact_plain_put_payload_batch_transaction?: (
1994
- wallTimes: BigUint64Array,
1995
- logicals: Uint32Array,
1996
+ documentProjectionSigners: Array<Uint8Array | undefined>,
1997
+ requiredPreviousSignerPublicKey: Uint8Array,
1998
+ trimLengthTo: number | undefined,
1999
+ ) => unknown[][];
2000
+ prepare_plain_committed_storage_append_document_index_latest_cached_plan_compact_plain_put_payload_batch_transaction?: (
2001
+ wallTimes: BigUint64Array,
2002
+ logicals: Uint32Array,
1996
2003
  gids: string[],
1997
2004
  type: number,
1998
2005
  metaDatas: Array<Uint8Array | undefined>,
@@ -2009,8 +2016,8 @@ type NativePeerbitBackboneHandle = {
2009
2016
  documentProjectionSigners: Array<Uint8Array | undefined>,
2010
2017
  trimLengthTo: number | undefined,
2011
2018
  ) => unknown[][];
2012
- prepare_plain_committed_storage_append_transaction_trim: (
2013
- wallTime: bigint,
2019
+ prepare_plain_committed_storage_append_transaction_trim: (
2020
+ wallTime: bigint,
2014
2021
  logical: number,
2015
2022
  gid: string,
2016
2023
  next: string[],
@@ -2022,27 +2029,10 @@ type NativePeerbitBackboneHandle = {
2022
2029
  now: string,
2023
2030
  selfHash: string,
2024
2031
  selfReplicating: boolean,
2025
- resolveTrimmedEntries: boolean,
2026
- trimLengthTo: number,
2027
- ) => unknown[];
2028
- prepare_plain_committed_storage_append_document_delete_transaction_trim: (
2029
- wallTime: bigint,
2030
- logical: number,
2031
- gid: string,
2032
- next: string[],
2033
- type: number,
2034
- metaData: Uint8Array | undefined,
2035
- payloadData: Uint8Array,
2036
- replicas: number,
2037
- roleAgeMs: number,
2038
- now: string,
2039
- selfHash: string,
2040
- selfReplicating: boolean,
2041
- resolveTrimmedEntries: boolean,
2042
- documentKey: string,
2043
- trimLengthTo: number,
2044
- ) => unknown[];
2045
- prepare_plain_committed_storage_append_document_index_transaction_trim: (
2032
+ resolveTrimmedEntries: boolean,
2033
+ trimLengthTo: number,
2034
+ ) => unknown[];
2035
+ prepare_plain_committed_storage_append_document_delete_transaction_trim: (
2046
2036
  wallTime: bigint,
2047
2037
  logical: number,
2048
2038
  gid: string,
@@ -2057,9 +2047,26 @@ type NativePeerbitBackboneHandle = {
2057
2047
  selfReplicating: boolean,
2058
2048
  resolveTrimmedEntries: boolean,
2059
2049
  documentKey: string,
2060
- documentValuePrefixBytes: Uint8Array,
2061
- documentExistingCreated: string,
2062
- documentByteElementIndexLimit: number,
2050
+ trimLengthTo: number,
2051
+ ) => unknown[];
2052
+ prepare_plain_committed_storage_append_document_index_transaction_trim: (
2053
+ wallTime: bigint,
2054
+ logical: number,
2055
+ gid: string,
2056
+ next: string[],
2057
+ type: number,
2058
+ metaData: Uint8Array | undefined,
2059
+ payloadData: Uint8Array,
2060
+ replicas: number,
2061
+ roleAgeMs: number,
2062
+ now: string,
2063
+ selfHash: string,
2064
+ selfReplicating: boolean,
2065
+ resolveTrimmedEntries: boolean,
2066
+ documentKey: string,
2067
+ documentValuePrefixBytes: Uint8Array,
2068
+ documentExistingCreated: string,
2069
+ documentByteElementIndexLimit: number,
2063
2070
  documentDeleteTrimmedHeads: boolean,
2064
2071
  documentProjectionPlan:
2065
2072
  | NativeBackboneSimpleDocumentProjectionPlan
@@ -2084,15 +2091,10 @@ type NativeWireSyncSessionHandle = {
2084
2091
  register_topic: (topic: string) => void;
2085
2092
  unregister_topic: (topic: string) => boolean;
2086
2093
  topic_count: () => number;
2087
- decode_and_verify_batch: (
2088
- frames: Uint8Array[],
2089
- nowMs: number,
2090
- ) => Uint32Array;
2094
+ decode_and_verify_batch: (frames: Uint8Array[], nowMs: number) => Uint32Array;
2091
2095
  stashed_meta: (
2092
2096
  id: Uint8Array,
2093
- ) =>
2094
- | [string[], string[][], Uint32Array, Uint8Array, number]
2095
- | undefined;
2097
+ ) => [string[], string[][], Uint32Array, Uint8Array, number] | undefined;
2096
2098
  stashed_blocks: (
2097
2099
  id: Uint8Array,
2098
2100
  indexes?: Uint32Array,
@@ -2386,10 +2388,7 @@ type NativeBackboneResidentRepairDispatchInput = Omit<
2386
2388
  "entries"
2387
2389
  >;
2388
2390
 
2389
- type NativeBackboneRepairDispatchPlan = Map<
2390
- string,
2391
- Map<string, string[]>
2392
- >;
2391
+ type NativeBackboneRepairDispatchPlan = Map<string, Map<string, string[]>>;
2393
2392
 
2394
2393
  type NativeBackboneCommittedEntry = {
2395
2394
  cid: string;
@@ -2959,26 +2958,65 @@ export type NativeBackboneCoordinatePersistenceStore = {
2959
2958
  /**
2960
2959
  * Appends `bytes` to the named file. Callers hand over ownership of
2961
2960
  * `bytes` and must not mutate it afterwards: buffering stores keep the
2962
- * array until their next flush instead of copying it.
2961
+ * array until their next flush instead of copying it. A rejected append
2962
+ * must either leave the file unchanged or make later appends fail closed.
2963
2963
  */
2964
2964
  append(name: string, bytes: Uint8Array): Promise<void>;
2965
2965
  remove?(name: string): Promise<void>;
2966
- flush?(): Promise<void>;
2967
- close?(): Promise<void>;
2966
+ /** Explicit physical durability barrier; its presence is a capability. */
2967
+ durableBarrier?(name?: string): Promise<void>;
2968
+ /** Override removal inference for wrappers whose remove method is conditional. */
2969
+ supportsRemoval?: boolean;
2970
+ /** Flush one named file when supported, otherwise the complete store. */
2971
+ flush?(name?: string): Promise<void>;
2972
+ close?(options?: { flush?: boolean }): Promise<void>;
2968
2973
  };
2969
2974
 
2970
2975
  export type NativeBackboneCoordinatePersistenceAdapter = {
2976
+ /**
2977
+ * Optional durable capability used by higher layers for atomic operation
2978
+ * intents that must share this persistence lifecycle.
2979
+ */
2980
+ intentStore?: NativeBackboneCoordinatePersistenceStore;
2971
2981
  flushOnAppend?: boolean;
2972
2982
  flushMaxPendingBytes?: number;
2973
2983
  flushIntervalMs?: number;
2974
2984
  compactMaxJournalBytes?: number;
2975
2985
  compactMaxJournalRecords?: number;
2986
+ /** Explicit opt-in for a generation-based, crash-atomic compaction protocol. */
2987
+ crashSafeCompaction?: boolean;
2988
+ /** Every acknowledged WAL/intent write crosses a physical durability barrier. */
2989
+ durableBarrier?: boolean;
2990
+ /** Drop is implemented by the underlying namespace, not only by a wrapper. */
2991
+ supportsDrop?: boolean;
2992
+ /** A successful drop owns handle cleanup and must not need ordinary close(). */
2993
+ dropIsTerminal?: boolean;
2976
2994
  hydrate(backbone: NativePeerbitBackbone): Promise<number>;
2977
2995
  flushJournal(backbone: NativePeerbitBackbone): Promise<number>;
2978
2996
  flushJournalOnAppend?(
2979
2997
  backbone: NativePeerbitBackbone,
2980
2998
  ): number | Promise<number>;
2981
2999
  compact?(backbone: NativePeerbitBackbone): Promise<void>;
3000
+ /**
3001
+ * Durably erase this adapter's configured files and any additional files
3002
+ * sharing the same namespace. A tombstone makes interrupted erases resumable.
3003
+ */
3004
+ drop?(additionalFiles?: readonly string[]): Promise<void>;
3005
+ /**
3006
+ * Complete an interrupted drop before hydration or on the same adapter
3007
+ * generation after `drop()` rejected. Returning `true` means the tombstoned
3008
+ * erase completed: this generation remains terminal only if it initiated that
3009
+ * drop, while recovery of a prior generation's marker returns to active.
3010
+ * Returning `false` means no durable marker exists and an explicit `drop()`
3011
+ * may start again; a generation that already initiated drop remains fenced
3012
+ * from ordinary hydrate/flush work until that destructive retry completes.
3013
+ * A corrupt/invalid marker rejection must likewise restore the adapter to an
3014
+ * explicit-drop-admitting state so drop can overwrite it; transient I/O
3015
+ * failures may keep the generation in its resumable dropping state. Once
3016
+ * close is admitted, no new resume may queue behind terminal store teardown.
3017
+ */
3018
+ resumeDrop?(): Promise<boolean>;
3019
+ /** A rejected close may be retried to resume its first incomplete store stage. */
2982
3020
  close?(): Promise<void>;
2983
3021
  };
2984
3022
 
@@ -3013,10 +3051,76 @@ const nativeBackboneCoordinatePersistenceFiles = {
3013
3051
  documentSignerJournal: "document-signers.wal",
3014
3052
  } as const;
3015
3053
 
3054
+ export const nativeBackboneCoordinateDropTombstoneFile =
3055
+ "native-backbone-drop.tombstone";
3056
+
3016
3057
  export const defaultNativeBackboneCoordinateFlushMaxPendingBytes = 1024 * 1024;
3058
+ /** @deprecated Built-in coordinate persistence compaction is currently disabled. */
3017
3059
  export const defaultNativeBackboneCoordinateCompactMaxJournalBytes =
3018
3060
  64 * 1024 * 1024;
3019
3061
 
3062
+ const nativeBackboneCoordinateCompactionDisabledMessage =
3063
+ "Native backbone coordinate persistence compaction is disabled until snapshots use a crash-safe generation protocol";
3064
+
3065
+ const nativeBackboneCoordinateJournalMagic = Uint8Array.from([
3066
+ 0x50, 0x42, 0x52, 0x49, 0x44, 0x58, 0x57, 0x31,
3067
+ ]);
3068
+
3069
+ const readCoordinateJournalU32 = (bytes: Uint8Array, offset: number): number =>
3070
+ (bytes[offset]! |
3071
+ (bytes[offset + 1]! << 8) |
3072
+ (bytes[offset + 2]! << 16) |
3073
+ (bytes[offset + 3]! << 24)) >>>
3074
+ 0;
3075
+
3076
+ const coordinateJournalChecksum = (bytes: Uint8Array): number => {
3077
+ let checksum = 0x811c9dc5;
3078
+ for (const byte of bytes) {
3079
+ checksum = Math.imul(checksum ^ byte, 0x01000193) >>> 0;
3080
+ }
3081
+ return checksum;
3082
+ };
3083
+
3084
+ const hasCoordinateJournalMagic = (bytes: Uint8Array): boolean =>
3085
+ bytes.byteLength >= nativeBackboneCoordinateJournalMagic.byteLength &&
3086
+ nativeBackboneCoordinateJournalMagic.every(
3087
+ (byte, index) => bytes[index] === byte,
3088
+ );
3089
+
3090
+ /**
3091
+ * The Rust decoder intentionally stops at a torn/corrupt tail. Persistence
3092
+ * must reject that tail before hydrate, otherwise a later append can land
3093
+ * behind it and remain permanently invisible to replay.
3094
+ */
3095
+ const validateCoordinateJournal = (
3096
+ bytes: Uint8Array | undefined,
3097
+ name: string,
3098
+ ): void => {
3099
+ if (!bytes || bytes.byteLength === 0) {
3100
+ return;
3101
+ }
3102
+ let offset = hasCoordinateJournalMagic(bytes)
3103
+ ? nativeBackboneCoordinateJournalMagic.byteLength
3104
+ : 0;
3105
+ while (offset < bytes.byteLength) {
3106
+ if (bytes.byteLength - offset < 8) {
3107
+ throw new Error(`Native backbone ${name} has a torn record header`);
3108
+ }
3109
+ const length = readCoordinateJournalU32(bytes, offset);
3110
+ const expectedChecksum = readCoordinateJournalU32(bytes, offset + 4);
3111
+ const payloadOffset = offset + 8;
3112
+ const end = payloadOffset + length;
3113
+ if (!Number.isSafeInteger(end) || end > bytes.byteLength) {
3114
+ throw new Error(`Native backbone ${name} has a torn record payload`);
3115
+ }
3116
+ const payload = bytes.subarray(payloadOffset, end);
3117
+ if (coordinateJournalChecksum(payload) !== expectedChecksum) {
3118
+ throw new Error(`Native backbone ${name} has a checksum mismatch`);
3119
+ }
3120
+ offset = end;
3121
+ }
3122
+ };
3123
+
3020
3124
  const resolveCoordinateFlushMaxPendingBytes = (
3021
3125
  options: NativeBackboneCoordinatePersistenceOptions,
3022
3126
  ): number | undefined =>
@@ -3039,7 +3143,8 @@ type NativeBackboneNodeFs = {
3039
3143
  };
3040
3144
 
3041
3145
  type NativeBackboneNodeAppendFileHandle = {
3042
- write(data: Uint8Array): Promise<unknown>;
3146
+ write(data: Uint8Array): Promise<{ bytesWritten: number }>;
3147
+ sync?(): Promise<unknown>;
3043
3148
  close(): Promise<unknown>;
3044
3149
  };
3045
3150
 
@@ -3051,6 +3156,7 @@ type NativeBackboneOPFSFile = {
3051
3156
  type NativeBackboneOPFSSyncAccessHandle = {
3052
3157
  getSize(): number;
3053
3158
  write(buffer: Uint8Array, options?: { at?: number }): number;
3159
+ truncate?(size: number): void;
3054
3160
  flush?(): void;
3055
3161
  close(): void;
3056
3162
  };
@@ -3086,6 +3192,29 @@ const isNotFoundError = (error: unknown): boolean => {
3086
3192
  return maybeError?.code === "ENOENT" || maybeError?.name === "NotFoundError";
3087
3193
  };
3088
3194
 
3195
+ const isUnsupportedDirectorySyncError = (error: unknown): boolean => {
3196
+ const code = (error as { code?: string } | undefined)?.code;
3197
+ return (
3198
+ code === "EISDIR" ||
3199
+ code === "EINVAL" ||
3200
+ code === "EPERM" ||
3201
+ code === "ENOTSUP"
3202
+ );
3203
+ };
3204
+
3205
+ const validateCoordinatePersistenceWriteProgress = (
3206
+ written: number,
3207
+ remaining: number,
3208
+ target: string,
3209
+ ): number => {
3210
+ if (!Number.isSafeInteger(written) || written <= 0 || written > remaining) {
3211
+ throw new Error(
3212
+ `Invalid ${target} write progress: ${String(written)} for ${remaining} remaining bytes`,
3213
+ );
3214
+ }
3215
+ return written;
3216
+ };
3217
+
3089
3218
  // Non-literal specifiers keep browser bundlers (esbuild statically resolves
3090
3219
  // literal dynamic imports and hard-fails on node builtins) from following
3091
3220
  // these node-only imports; they are only reached on node runtimes.
@@ -3126,6 +3255,94 @@ const validateCoordinatePersistenceName = (name: string): string => {
3126
3255
  return name;
3127
3256
  };
3128
3257
 
3258
+ type NativeBackboneCoordinateDropTombstoneBody = {
3259
+ format: "peerbit-native-backbone-coordinate-drop";
3260
+ version: 1;
3261
+ files: string[];
3262
+ };
3263
+
3264
+ type NativeBackboneCoordinateDropTombstone =
3265
+ NativeBackboneCoordinateDropTombstoneBody & {
3266
+ checksum: string;
3267
+ };
3268
+
3269
+ const nativeBackboneCoordinateDropTombstoneBodyBytes = (
3270
+ body: NativeBackboneCoordinateDropTombstoneBody,
3271
+ ): Uint8Array => new TextEncoder().encode(JSON.stringify(body));
3272
+
3273
+ const nativeBackboneCoordinateDropChecksum = (bytes: Uint8Array): string => {
3274
+ let checksum = 0xffffffff;
3275
+ for (const byte of bytes) {
3276
+ checksum ^= byte;
3277
+ for (let bit = 0; bit < 8; bit++) {
3278
+ checksum = (checksum >>> 1) ^ (checksum & 1 ? 0xedb88320 : 0);
3279
+ }
3280
+ }
3281
+ return ((checksum ^ 0xffffffff) >>> 0).toString(16).padStart(8, "0");
3282
+ };
3283
+
3284
+ const nativeBackboneCoordinateDropTombstoneBytes = (
3285
+ files: readonly string[],
3286
+ ): Uint8Array => {
3287
+ const body: NativeBackboneCoordinateDropTombstoneBody = {
3288
+ format: "peerbit-native-backbone-coordinate-drop",
3289
+ version: 1,
3290
+ files: [...files],
3291
+ };
3292
+ return new TextEncoder().encode(
3293
+ JSON.stringify({
3294
+ ...body,
3295
+ checksum: nativeBackboneCoordinateDropChecksum(
3296
+ nativeBackboneCoordinateDropTombstoneBodyBytes(body),
3297
+ ),
3298
+ } satisfies NativeBackboneCoordinateDropTombstone),
3299
+ );
3300
+ };
3301
+
3302
+ const parseNativeBackboneCoordinateDropTombstone = (
3303
+ bytes: Uint8Array,
3304
+ ): NativeBackboneCoordinateDropTombstoneBody => {
3305
+ let parsed: unknown;
3306
+ try {
3307
+ parsed = JSON.parse(new TextDecoder().decode(bytes));
3308
+ } catch (error) {
3309
+ throw new Error("Invalid native backbone drop tombstone JSON", {
3310
+ cause: error,
3311
+ });
3312
+ }
3313
+ const candidate = parsed as Partial<NativeBackboneCoordinateDropTombstone>;
3314
+ if (
3315
+ !candidate ||
3316
+ candidate.format !== "peerbit-native-backbone-coordinate-drop" ||
3317
+ candidate.version !== 1 ||
3318
+ !Array.isArray(candidate.files) ||
3319
+ candidate.files.some((name) => typeof name !== "string") ||
3320
+ typeof candidate.checksum !== "string"
3321
+ ) {
3322
+ throw new Error("Invalid native backbone drop tombstone");
3323
+ }
3324
+ const files = candidate.files.map(validateCoordinatePersistenceName);
3325
+ if (
3326
+ new Set(files).size !== files.length ||
3327
+ files.includes(nativeBackboneCoordinateDropTombstoneFile)
3328
+ ) {
3329
+ throw new Error("Invalid native backbone drop tombstone file set");
3330
+ }
3331
+ const body: NativeBackboneCoordinateDropTombstoneBody = {
3332
+ format: "peerbit-native-backbone-coordinate-drop",
3333
+ version: 1,
3334
+ files,
3335
+ };
3336
+ if (
3337
+ nativeBackboneCoordinateDropChecksum(
3338
+ nativeBackboneCoordinateDropTombstoneBodyBytes(body),
3339
+ ) !== candidate.checksum
3340
+ ) {
3341
+ throw new Error("Native backbone drop tombstone checksum mismatch");
3342
+ }
3343
+ return body;
3344
+ };
3345
+
3129
3346
  const concatBytes = (chunks: Uint8Array[]): Uint8Array => {
3130
3347
  const total = chunks.reduce((sum, chunk) => sum + chunk.byteLength, 0);
3131
3348
  const out = new Uint8Array(total);
@@ -3591,8 +3808,12 @@ const metadataEntryFromRow = (row: unknown) => {
3591
3808
  Uint8Array | undefined,
3592
3809
  number | undefined,
3593
3810
  ];
3594
- const entry: { hash: string; gid: string; data?: Uint8Array; replicas?: number } =
3595
- { hash, gid, data };
3811
+ const entry: {
3812
+ hash: string;
3813
+ gid: string;
3814
+ data?: Uint8Array;
3815
+ replicas?: number;
3816
+ } = { hash, gid, data };
3596
3817
  if (replicas != null) {
3597
3818
  entry.replicas = replicas;
3598
3819
  }
@@ -3608,8 +3829,12 @@ const requestPruneEntryFromRow = (
3608
3829
  number | undefined,
3609
3830
  Uint8Array | undefined,
3610
3831
  ];
3611
- const entry: { hash: string; gid: string; data?: Uint8Array; replicas?: number } =
3612
- { hash, gid };
3832
+ const entry: {
3833
+ hash: string;
3834
+ gid: string;
3835
+ data?: Uint8Array;
3836
+ replicas?: number;
3837
+ } = { hash, gid };
3613
3838
  if (replicas != null) {
3614
3839
  entry.replicas = replicas;
3615
3840
  }
@@ -3990,7 +4215,11 @@ const validateNativeBackboneCoordinateCommitColumns = (
3990
4215
  ) {
3991
4216
  throw new Error("Expected equal native coordinate commit column lengths");
3992
4217
  }
3993
- if (columns.hashNumberValues || columns.coordinateCounts || columns.coordinateValues) {
4218
+ if (
4219
+ columns.hashNumberValues ||
4220
+ columns.coordinateCounts ||
4221
+ columns.coordinateValues
4222
+ ) {
3994
4223
  if (
3995
4224
  !columns.hashNumberValues ||
3996
4225
  !columns.coordinateCounts ||
@@ -3998,7 +4227,9 @@ const validateNativeBackboneCoordinateCommitColumns = (
3998
4227
  columns.hashNumberValues.length !== length ||
3999
4228
  columns.coordinateCounts.length !== length
4000
4229
  ) {
4001
- throw new Error("Expected equal native coordinate numeric column lengths");
4230
+ throw new Error(
4231
+ "Expected equal native coordinate numeric column lengths",
4232
+ );
4002
4233
  }
4003
4234
  let coordinateCount = 0;
4004
4235
  for (const count of columns.coordinateCounts) {
@@ -4014,7 +4245,11 @@ const validateNativeBackboneCoordinateCommitColumns = (
4014
4245
  ) {
4015
4246
  throw new Error("Expected equal native coordinate replica column lengths");
4016
4247
  }
4017
- if (columns.hashNumbers || columns.coordinateBatches || columns.requestedReplicas) {
4248
+ if (
4249
+ columns.hashNumbers ||
4250
+ columns.coordinateBatches ||
4251
+ columns.requestedReplicas
4252
+ ) {
4018
4253
  if (
4019
4254
  !columns.hashNumbers ||
4020
4255
  !columns.coordinateBatches ||
@@ -4065,7 +4300,11 @@ const nativeBackboneCoordinateCommitStringColumns = (
4065
4300
  "hashNumbers" | "coordinateBatches" | "requestedReplicas"
4066
4301
  >
4067
4302
  > => {
4068
- if (columns.hashNumbers && columns.coordinateBatches && columns.requestedReplicas) {
4303
+ if (
4304
+ columns.hashNumbers &&
4305
+ columns.coordinateBatches &&
4306
+ columns.requestedReplicas
4307
+ ) {
4069
4308
  return {
4070
4309
  hashNumbers: columns.hashNumbers,
4071
4310
  coordinateBatches: columns.coordinateBatches,
@@ -4186,8 +4425,7 @@ const rawReceivePreparedFactsFromColumns = ([
4186
4425
  requestedReplicas[i] && requestedReplicas[i] > 0
4187
4426
  ? requestedReplicas[i]
4188
4427
  : undefined,
4189
- hashNumber:
4190
- hashNumbers[i] == null ? undefined : String(hashNumbers[i]),
4428
+ hashNumber: hashNumbers[i] == null ? undefined : String(hashNumbers[i]),
4191
4429
  };
4192
4430
  }
4193
4431
  return out;
@@ -4956,11 +5194,7 @@ class NativeBackboneLogGraph {
4956
5194
  ),
4957
5195
  );
4958
5196
  }
4959
- if (
4960
- documentIndexArgs &&
4961
- input.trimLengthTo == null &&
4962
- hasNoNext
4963
- ) {
5197
+ if (documentIndexArgs && input.trimLengthTo == null && hasNoNext) {
4964
5198
  return preparedCommitFactsFromRow(
4965
5199
  this.native.prepare_plain_entry_commit_no_next_facts_document_index_compact(
4966
5200
  wallTime,
@@ -6310,9 +6544,7 @@ export class NativePeerbitBackbone {
6310
6544
  return { exists, publicKey };
6311
6545
  }
6312
6546
 
6313
- documentContextsAndPreviousSignaturePublicKeys(
6314
- keys: string[],
6315
- ):
6547
+ documentContextsAndPreviousSignaturePublicKeys(keys: string[]):
6316
6548
  | Array<{
6317
6549
  context?: NativeBackboneDocumentContextFacts;
6318
6550
  publicKey?: Uint8Array;
@@ -6703,12 +6935,8 @@ export class NativePeerbitBackbone {
6703
6935
  commitEntryCoordinatesColumnsBatch(
6704
6936
  columns: NativeBackboneCoordinateCommitColumns,
6705
6937
  ): void {
6706
- const {
6707
- hashes,
6708
- gids,
6709
- nextHashBatches,
6710
- assignedToRangeBoundaries,
6711
- } = columns;
6938
+ const { hashes, gids, nextHashBatches, assignedToRangeBoundaries } =
6939
+ columns;
6712
6940
  if (hashes.length === 0) {
6713
6941
  return;
6714
6942
  }
@@ -6972,7 +7200,9 @@ export class NativePeerbitBackbone {
6972
7200
  planRequestPruneAllConfirmed(
6973
7201
  hashes: Iterable<string>,
6974
7202
  prunePeer: string,
6975
- options?: NativeBackboneFindLeaderOptions & { omitPeerHistoryGids?: boolean },
7203
+ options?: NativeBackboneFindLeaderOptions & {
7204
+ omitPeerHistoryGids?: boolean;
7205
+ },
6976
7206
  ): NativeBackboneRequestPruneAllConfirmed | undefined {
6977
7207
  const hashArray = iterableToArray(hashes);
6978
7208
  if (
@@ -7452,10 +7682,12 @@ export class NativePeerbitBackbone {
7452
7682
  }
7453
7683
  }
7454
7684
  const projection = documentIndex.projection;
7455
- if (projection) {
7456
- const projectionPlanId = this.documentProjectionPlanId(projection.plan);
7457
- const nativeCompactPlainPutPayload =
7458
- documentIndex.usePlainPutPayload === true
7685
+ if (projection) {
7686
+ const projectionPlanId = this.documentProjectionPlanId(
7687
+ projection.plan,
7688
+ );
7689
+ const nativeCompactPlainPutPayload =
7690
+ documentIndex.usePlainPutPayload === true
7459
7691
  ? this.native
7460
7692
  .prepare_plain_committed_storage_append_document_index_latest_cached_plan_compact_plain_put_payload_transaction
7461
7693
  : undefined;
@@ -7512,45 +7744,45 @@ export class NativePeerbitBackbone {
7512
7744
  );
7513
7745
  return compactCommittedLatestStorageAppendResultFromRow(
7514
7746
  this.resolution,
7515
- row,
7516
- );
7517
- }
7518
- }
7519
- if (
7520
- !requiredPreviousSignerPublicKey &&
7521
- documentIndex.usePlainPutPayload === true
7522
- ) {
7523
- const nativeCompactPlainPutPayload =
7524
- this.native
7525
- .prepare_plain_committed_storage_append_document_index_latest_compact_plain_put_payload_transaction;
7526
- if (nativeCompactPlainPutPayload) {
7527
- const row = nativeCompactPlainPutPayload.call(
7528
- this.native,
7529
- BigInt(input.wallTime),
7530
- input.logical ?? 0,
7531
- input.gid,
7532
- input.type ?? 0,
7533
- input.metaData,
7534
- input.payloadData,
7535
- input.replicas,
7536
- input.roleAgeMs ?? 0,
7537
- integerString(input.now ?? Date.now()),
7538
- input.selfHash ?? "",
7539
- input.selfReplicating ?? true,
7540
- documentIndex.key,
7541
- documentIndex.byteElementIndexLimit ?? 0,
7542
- documentIndex.deleteTrimmedHeads === true,
7543
- input.trimLengthTo,
7544
- );
7545
- return compactCommittedLatestStorageAppendResultFromRow(
7546
- this.resolution,
7547
- row,
7548
- );
7549
- }
7747
+ row,
7748
+ );
7550
7749
  }
7551
- const nativeCompact =
7750
+ }
7751
+ if (
7752
+ !requiredPreviousSignerPublicKey &&
7753
+ documentIndex.usePlainPutPayload === true
7754
+ ) {
7755
+ const nativeCompactPlainPutPayload =
7552
7756
  this.native
7553
- .prepare_plain_committed_storage_append_document_index_latest_compact_transaction;
7757
+ .prepare_plain_committed_storage_append_document_index_latest_compact_plain_put_payload_transaction;
7758
+ if (nativeCompactPlainPutPayload) {
7759
+ const row = nativeCompactPlainPutPayload.call(
7760
+ this.native,
7761
+ BigInt(input.wallTime),
7762
+ input.logical ?? 0,
7763
+ input.gid,
7764
+ input.type ?? 0,
7765
+ input.metaData,
7766
+ input.payloadData,
7767
+ input.replicas,
7768
+ input.roleAgeMs ?? 0,
7769
+ integerString(input.now ?? Date.now()),
7770
+ input.selfHash ?? "",
7771
+ input.selfReplicating ?? true,
7772
+ documentIndex.key,
7773
+ documentIndex.byteElementIndexLimit ?? 0,
7774
+ documentIndex.deleteTrimmedHeads === true,
7775
+ input.trimLengthTo,
7776
+ );
7777
+ return compactCommittedLatestStorageAppendResultFromRow(
7778
+ this.resolution,
7779
+ row,
7780
+ );
7781
+ }
7782
+ }
7783
+ const nativeCompact =
7784
+ this.native
7785
+ .prepare_plain_committed_storage_append_document_index_latest_compact_transaction;
7554
7786
  if (nativeCompact) {
7555
7787
  const row = nativeCompact.call(
7556
7788
  this.native,
@@ -7703,8 +7935,7 @@ export class NativePeerbitBackbone {
7703
7935
  const requiredPreviousSignerPublicKeys = input.entries
7704
7936
  .map((entry) => entry.documentIndex.requiredPreviousSignerPublicKey)
7705
7937
  .filter((key): key is Uint8Array => !!key);
7706
- const requiredPreviousSignerPublicKey =
7707
- requiredPreviousSignerPublicKeys[0];
7938
+ const requiredPreviousSignerPublicKey = requiredPreviousSignerPublicKeys[0];
7708
7939
  if (
7709
7940
  requiredPreviousSignerPublicKeys.length > 0 &&
7710
7941
  requiredPreviousSignerPublicKeys.length !== input.entries.length
@@ -7716,25 +7947,25 @@ export class NativePeerbitBackbone {
7716
7947
  requiredPreviousSignerPublicKeys.some(
7717
7948
  (key) =>
7718
7949
  key.byteLength !== requiredPreviousSignerPublicKey.byteLength ||
7719
- key.some((byte, index) => byte !== requiredPreviousSignerPublicKey[index]),
7950
+ key.some(
7951
+ (byte, index) => byte !== requiredPreviousSignerPublicKey[index],
7952
+ ),
7720
7953
  )
7721
7954
  ) {
7722
7955
  return undefined;
7723
7956
  }
7724
- const projected = input.entries.every(
7725
- (entry) => entry.documentIndex.projection,
7957
+ const projected = input.entries.every(
7958
+ (entry) => entry.documentIndex.projection,
7959
+ );
7960
+ if (projected) {
7961
+ const usePlainPutPayload = input.entries.every(
7962
+ (entry) => entry.documentIndex.usePlainPutPayload === true,
7726
7963
  );
7727
- if (projected) {
7728
- const usePlainPutPayload = input.entries.every(
7729
- (entry) => entry.documentIndex.usePlainPutPayload === true,
7730
- );
7731
7964
  const baseArgs = [
7732
7965
  new BigUint64Array(
7733
7966
  input.entries.map((entry) => BigInt(entry.wallTime)),
7734
7967
  ),
7735
- new Uint32Array(
7736
- input.entries.map((entry) => entry.logical ?? 0),
7737
- ),
7968
+ new Uint32Array(input.entries.map((entry) => entry.logical ?? 0)),
7738
7969
  input.entries.map((entry) => entry.gid),
7739
7970
  input.type ?? 0,
7740
7971
  input.entries.map((entry) => entry.metaData),
@@ -7751,9 +7982,7 @@ export class NativePeerbitBackbone {
7751
7982
  input.documentDeleteTrimmedHeads === true,
7752
7983
  new Uint32Array(
7753
7984
  input.entries.map((entry) =>
7754
- this.documentProjectionPlanId(
7755
- entry.documentIndex.projection!.plan,
7756
- ),
7985
+ this.documentProjectionPlanId(entry.documentIndex.projection!.plan),
7757
7986
  ),
7758
7987
  ),
7759
7988
  ] as const;
@@ -7766,43 +7995,20 @@ export class NativePeerbitBackbone {
7766
7995
  const nativeCompactCachedBatch =
7767
7996
  this.native
7768
7997
  .prepare_plain_committed_storage_append_document_index_latest_cached_plan_compact_batch_transaction;
7769
- const nativeCompactCachedPlainPayloadBatch =
7770
- this.native
7771
- .prepare_plain_committed_storage_append_document_index_latest_cached_plan_compact_plain_put_payload_batch_transaction;
7772
- if (requiredPreviousSignerPublicKey) {
7773
- if (useCompact) {
7774
- const nativeRequiredCompactCachedBatch =
7775
- this.native
7776
- .prepare_plain_committed_storage_append_document_index_latest_required_previous_signer_cached_plan_compact_batch_transaction;
7777
- if (!nativeRequiredCompactCachedBatch) {
7778
- return undefined;
7779
- }
7780
- const rows = nativeRequiredCompactCachedBatch.call(
7781
- this.native,
7782
- ...baseArgs,
7783
- ...documentPlanArgs,
7784
- documentEncodedDocuments,
7785
- documentSigners,
7786
- requiredPreviousSignerPublicKey,
7787
- input.trimLengthTo,
7788
- );
7789
- return rows.map((row) =>
7790
- compactCommittedLatestStorageAppendResultFromRow(
7791
- this.resolution,
7792
- row,
7793
- ),
7794
- );
7795
- }
7796
- const nativeRequiredCachedBatch =
7998
+ const nativeCompactCachedPlainPayloadBatch =
7999
+ this.native
8000
+ .prepare_plain_committed_storage_append_document_index_latest_cached_plan_compact_plain_put_payload_batch_transaction;
8001
+ if (requiredPreviousSignerPublicKey) {
8002
+ if (useCompact) {
8003
+ const nativeRequiredCompactCachedBatch =
7797
8004
  this.native
7798
- .prepare_plain_committed_storage_append_document_index_latest_required_previous_signer_cached_plan_batch_transaction;
7799
- if (!nativeRequiredCachedBatch) {
8005
+ .prepare_plain_committed_storage_append_document_index_latest_required_previous_signer_cached_plan_compact_batch_transaction;
8006
+ if (!nativeRequiredCompactCachedBatch) {
7800
8007
  return undefined;
7801
8008
  }
7802
- const rows = nativeRequiredCachedBatch.call(
8009
+ const rows = nativeRequiredCompactCachedBatch.call(
7803
8010
  this.native,
7804
8011
  ...baseArgs,
7805
- input.resolveTrimmedEntries !== false,
7806
8012
  ...documentPlanArgs,
7807
8013
  documentEncodedDocuments,
7808
8014
  documentSigners,
@@ -7810,12 +8016,35 @@ export class NativePeerbitBackbone {
7810
8016
  input.trimLengthTo,
7811
8017
  );
7812
8018
  return rows.map((row) =>
7813
- committedStorageAppendResultFromRow(this.resolution, row),
8019
+ compactCommittedLatestStorageAppendResultFromRow(
8020
+ this.resolution,
8021
+ row,
8022
+ ),
7814
8023
  );
7815
8024
  }
7816
- if (
7817
- useCompact &&
7818
- usePlainPutPayload &&
8025
+ const nativeRequiredCachedBatch =
8026
+ this.native
8027
+ .prepare_plain_committed_storage_append_document_index_latest_required_previous_signer_cached_plan_batch_transaction;
8028
+ if (!nativeRequiredCachedBatch) {
8029
+ return undefined;
8030
+ }
8031
+ const rows = nativeRequiredCachedBatch.call(
8032
+ this.native,
8033
+ ...baseArgs,
8034
+ input.resolveTrimmedEntries !== false,
8035
+ ...documentPlanArgs,
8036
+ documentEncodedDocuments,
8037
+ documentSigners,
8038
+ requiredPreviousSignerPublicKey,
8039
+ input.trimLengthTo,
8040
+ );
8041
+ return rows.map((row) =>
8042
+ committedStorageAppendResultFromRow(this.resolution, row),
8043
+ );
8044
+ }
8045
+ if (
8046
+ useCompact &&
8047
+ usePlainPutPayload &&
7819
8048
  nativeCompactCachedPlainPayloadBatch
7820
8049
  ) {
7821
8050
  const rows = nativeCompactCachedPlainPayloadBatch.call(
@@ -7869,16 +8098,12 @@ export class NativePeerbitBackbone {
7869
8098
  }
7870
8099
  if (
7871
8100
  input.entries.some((entry) => entry.documentIndex.projection) ||
7872
- input.entries.some(
7873
- (entry) => !entry.documentIndex.valuePrefixBytes,
7874
- )
8101
+ input.entries.some((entry) => !entry.documentIndex.valuePrefixBytes)
7875
8102
  ) {
7876
8103
  return undefined;
7877
8104
  }
7878
8105
  const baseArgs = [
7879
- new BigUint64Array(
7880
- input.entries.map((entry) => BigInt(entry.wallTime)),
7881
- ),
8106
+ new BigUint64Array(input.entries.map((entry) => BigInt(entry.wallTime))),
7882
8107
  new Uint32Array(input.entries.map((entry) => entry.logical ?? 0)),
7883
8108
  input.entries.map((entry) => entry.gid),
7884
8109
  input.type ?? 0,
@@ -7890,38 +8115,34 @@ export class NativePeerbitBackbone {
7890
8115
  input.selfHash ?? "",
7891
8116
  input.selfReplicating ?? true,
7892
8117
  ] as const;
7893
- const documentKeys = input.entries.map((entry) => entry.documentIndex.key);
7894
- const usePlainPutPayload = input.entries.every(
7895
- (entry) => entry.documentIndex.usePlainPutPayload === true,
7896
- );
7897
- if (
7898
- !requiredPreviousSignerPublicKey &&
7899
- useCompact &&
7900
- usePlainPutPayload
7901
- ) {
7902
- const nativeCompactPlainPutPayloadBatch =
7903
- this.native
7904
- .prepare_plain_committed_storage_append_document_index_latest_compact_plain_put_payload_batch_transaction;
7905
- if (nativeCompactPlainPutPayloadBatch) {
7906
- const rows = nativeCompactPlainPutPayloadBatch.call(
7907
- this.native,
7908
- ...baseArgs,
7909
- documentKeys,
7910
- input.documentByteElementIndexLimit ?? 0,
7911
- input.documentDeleteTrimmedHeads === true,
7912
- input.trimLengthTo,
7913
- );
7914
- return rows.map((row) =>
7915
- compactCommittedLatestStorageAppendResultFromRow(
7916
- this.resolution,
7917
- row,
7918
- ),
7919
- );
7920
- }
8118
+ const documentKeys = input.entries.map((entry) => entry.documentIndex.key);
8119
+ const usePlainPutPayload = input.entries.every(
8120
+ (entry) => entry.documentIndex.usePlainPutPayload === true,
8121
+ );
8122
+ if (!requiredPreviousSignerPublicKey && useCompact && usePlainPutPayload) {
8123
+ const nativeCompactPlainPutPayloadBatch =
8124
+ this.native
8125
+ .prepare_plain_committed_storage_append_document_index_latest_compact_plain_put_payload_batch_transaction;
8126
+ if (nativeCompactPlainPutPayloadBatch) {
8127
+ const rows = nativeCompactPlainPutPayloadBatch.call(
8128
+ this.native,
8129
+ ...baseArgs,
8130
+ documentKeys,
8131
+ input.documentByteElementIndexLimit ?? 0,
8132
+ input.documentDeleteTrimmedHeads === true,
8133
+ input.trimLengthTo,
8134
+ );
8135
+ return rows.map((row) =>
8136
+ compactCommittedLatestStorageAppendResultFromRow(
8137
+ this.resolution,
8138
+ row,
8139
+ ),
8140
+ );
7921
8141
  }
7922
- const documentValuePrefixBytes = input.entries.map(
7923
- (entry) => entry.documentIndex.valuePrefixBytes!,
7924
- );
8142
+ }
8143
+ const documentValuePrefixBytes = input.entries.map(
8144
+ (entry) => entry.documentIndex.valuePrefixBytes!,
8145
+ );
7925
8146
  const documentByteElementIndexLimit =
7926
8147
  input.documentByteElementIndexLimit ?? 0;
7927
8148
  const documentDeleteTrimmedHeads =
@@ -7989,10 +8210,7 @@ export class NativePeerbitBackbone {
7989
8210
  ...documentArgs,
7990
8211
  );
7991
8212
  return rows.map((row) =>
7992
- compactCommittedLatestStorageAppendResultFromRow(
7993
- this.resolution,
7994
- row,
7995
- ),
8213
+ compactCommittedLatestStorageAppendResultFromRow(this.resolution, row),
7996
8214
  );
7997
8215
  }
7998
8216
  const nativeBatch =
@@ -8210,9 +8428,7 @@ export class NativePeerbitBackbone {
8210
8428
  new BigUint64Array(
8211
8429
  input.entries.map((entry) => BigInt(entry.wallTime)),
8212
8430
  ),
8213
- new Uint32Array(
8214
- input.entries.map((entry) => entry.logical ?? 0),
8215
- ),
8431
+ new Uint32Array(input.entries.map((entry) => entry.logical ?? 0)),
8216
8432
  input.entries.map((entry) => entry.gid),
8217
8433
  input.type ?? 0,
8218
8434
  input.entries.map((entry) => entry.metaData),
@@ -8232,46 +8448,35 @@ export class NativePeerbitBackbone {
8232
8448
  input.documentDeleteTrimmedHeads === true,
8233
8449
  new Uint32Array(
8234
8450
  input.entries.map((entry) =>
8235
- this.documentProjectionPlanId(
8236
- entry.documentIndex.projection!.plan,
8237
- ),
8451
+ this.documentProjectionPlanId(entry.documentIndex.projection!.plan),
8238
8452
  ),
8239
8453
  ),
8240
8454
  ] as const;
8241
8455
  const rows = usePlainPutPayload
8242
- ? this.native
8243
- .prepare_plain_committed_no_next_storage_append_document_index_cached_plan_compact_plain_put_payload_batch_transaction?.call(
8244
- this.native,
8245
- ...baseArgs,
8246
- input.entries.map(
8247
- (entry) =>
8248
- entry.documentIndex.projection!.signer,
8249
- ),
8250
- input.trimLengthTo,
8251
- )
8252
- : this.native
8253
- .prepare_plain_committed_no_next_storage_append_document_index_cached_plan_compact_batch_transaction?.call(
8254
- this.native,
8255
- ...baseArgs,
8256
- input.entries.map(
8257
- (entry) =>
8258
- entry.documentIndex.projection!
8259
- .encodedDocument,
8260
- ),
8261
- input.entries.map(
8262
- (entry) =>
8263
- entry.documentIndex.projection!.signer,
8264
- ),
8265
- input.trimLengthTo,
8266
- );
8456
+ ? this.native.prepare_plain_committed_no_next_storage_append_document_index_cached_plan_compact_plain_put_payload_batch_transaction?.call(
8457
+ this.native,
8458
+ ...baseArgs,
8459
+ input.entries.map(
8460
+ (entry) => entry.documentIndex.projection!.signer,
8461
+ ),
8462
+ input.trimLengthTo,
8463
+ )
8464
+ : this.native.prepare_plain_committed_no_next_storage_append_document_index_cached_plan_compact_batch_transaction?.call(
8465
+ this.native,
8466
+ ...baseArgs,
8467
+ input.entries.map(
8468
+ (entry) => entry.documentIndex.projection!.encodedDocument,
8469
+ ),
8470
+ input.entries.map(
8471
+ (entry) => entry.documentIndex.projection!.signer,
8472
+ ),
8473
+ input.trimLengthTo,
8474
+ );
8267
8475
  if (!rows) {
8268
8476
  return undefined;
8269
8477
  }
8270
8478
  return rows.map((row) =>
8271
- compactCommittedNoNextStorageAppendResultFromRow(
8272
- this.resolution,
8273
- row,
8274
- ),
8479
+ compactCommittedNoNextStorageAppendResultFromRow(this.resolution, row),
8275
8480
  );
8276
8481
  }
8277
8482
  if (
@@ -8329,9 +8534,7 @@ export class NativePeerbitBackbone {
8329
8534
  }
8330
8535
  const rows = nativeBatch.call(
8331
8536
  this.native,
8332
- new BigUint64Array(
8333
- input.entries.map((entry) => BigInt(entry.wallTime)),
8334
- ),
8537
+ new BigUint64Array(input.entries.map((entry) => BigInt(entry.wallTime))),
8335
8538
  new Uint32Array(input.entries.map((entry) => entry.logical ?? 0)),
8336
8539
  input.entries.map((entry) => entry.gid),
8337
8540
  input.type ?? 0,
@@ -8344,8 +8547,7 @@ export class NativePeerbitBackbone {
8344
8547
  input.selfReplicating ?? true,
8345
8548
  input.entries.map((entry) => entry.documentIndex.key),
8346
8549
  input.entries.map(
8347
- (entry) =>
8348
- entry.documentIndex.valuePrefixBytes ?? EMPTY_UINT8_ARRAY,
8550
+ (entry) => entry.documentIndex.valuePrefixBytes ?? EMPTY_UINT8_ARRAY,
8349
8551
  ),
8350
8552
  input.entries.map((entry) =>
8351
8553
  entry.documentIndex.existingCreated == null
@@ -8357,13 +8559,9 @@ export class NativePeerbitBackbone {
8357
8559
  input.trimLengthTo,
8358
8560
  );
8359
8561
  return rows.map((row) =>
8360
- compactCommittedNoNextStorageAppendResultFromRow(
8361
- this.resolution,
8362
- row,
8363
- ),
8562
+ compactCommittedNoNextStorageAppendResultFromRow(this.resolution, row),
8364
8563
  );
8365
8564
  }
8366
-
8367
8565
  }
8368
8566
 
8369
8567
  export class NativeBackboneMemoryCoordinatePersistenceStore
@@ -8392,6 +8590,8 @@ export class NativeBackboneMemoryCoordinatePersistenceStore
8392
8590
  async remove(name: string): Promise<void> {
8393
8591
  this.files.delete(validateCoordinatePersistenceName(name));
8394
8592
  }
8593
+
8594
+ async flush(_name?: string): Promise<void> {}
8395
8595
  }
8396
8596
 
8397
8597
  export class NativeBackboneNodeCoordinatePersistenceStore
@@ -8403,11 +8603,20 @@ export class NativeBackboneNodeCoordinatePersistenceStore
8403
8603
  >();
8404
8604
  private readonly filePaths = new Map<string, string>();
8405
8605
  private directoryEnsured = false;
8606
+ private appendFailure: unknown;
8607
+ readonly durableBarrier?: (name?: string) => Promise<void>;
8406
8608
 
8407
8609
  constructor(
8408
8610
  private readonly directory: string,
8409
8611
  private readonly fs?: NativeBackboneNodeFs,
8410
- ) {}
8612
+ ) {
8613
+ // The default Node backend has FileHandle.sync. Injected test/custom
8614
+ // backends only advertise durability when they at least expose open(); the
8615
+ // barrier itself verifies sync on every opened handle before ACK.
8616
+ if (!fs || typeof fs.open === "function") {
8617
+ this.durableBarrier = (name) => this.syncDurably(name);
8618
+ }
8619
+ }
8411
8620
 
8412
8621
  private async nodeFs(): Promise<NativeBackboneNodeFs> {
8413
8622
  return this.fs ?? (await importNodeFs());
@@ -8476,14 +8685,45 @@ export class NativeBackboneNodeCoordinatePersistenceStore
8476
8685
  }
8477
8686
 
8478
8687
  async append(name: string, bytes: Uint8Array): Promise<void> {
8688
+ if (this.appendFailure !== undefined) {
8689
+ throw this.appendFailure;
8690
+ }
8479
8691
  const fs = await this.ensureDirectory();
8480
8692
  const path = await this.filePath(name);
8481
8693
  const handle = await this.appendHandle(fs, path);
8482
8694
  if (handle) {
8483
- await handle.write(bytes);
8695
+ let offset = 0;
8696
+ while (offset < bytes.byteLength) {
8697
+ let result: { bytesWritten: number };
8698
+ try {
8699
+ result = await handle.write(bytes.subarray(offset));
8700
+ } catch (error) {
8701
+ // FileHandle.write does not expose progress on rejection, even for the
8702
+ // first call, so a partial tail can not be ruled out.
8703
+ this.appendFailure ??= error;
8704
+ throw this.appendFailure;
8705
+ }
8706
+ try {
8707
+ offset += validateCoordinatePersistenceWriteProgress(
8708
+ result.bytesWritten,
8709
+ bytes.byteLength - offset,
8710
+ "Node coordinate WAL",
8711
+ );
8712
+ } catch (error) {
8713
+ this.appendFailure ??= error;
8714
+ throw this.appendFailure;
8715
+ }
8716
+ }
8484
8717
  return;
8485
8718
  }
8486
- await fs.appendFile(path, bytes);
8719
+ try {
8720
+ await fs.appendFile(path, bytes);
8721
+ } catch (error) {
8722
+ // appendFile does not report partial progress. Conservatively prevent a
8723
+ // later append from landing behind a possibly torn tail.
8724
+ this.appendFailure ??= error;
8725
+ throw this.appendFailure;
8726
+ }
8487
8727
  }
8488
8728
 
8489
8729
  async remove(name: string): Promise<void> {
@@ -8499,6 +8739,74 @@ export class NativeBackboneNodeCoordinatePersistenceStore
8499
8739
  }
8500
8740
  }
8501
8741
 
8742
+ async flush(name?: string): Promise<void> {
8743
+ if (!this.durableBarrier) {
8744
+ return;
8745
+ }
8746
+ try {
8747
+ await this.durableBarrier(name);
8748
+ } catch (error) {
8749
+ // Ordinary buffering reads flush a named queue before discovering whether
8750
+ // the backing file exists. Missing files are expected there; strict ACK
8751
+ // paths call durableBarrier directly and therefore remain fail-closed.
8752
+ if (!name || !isNotFoundError(error)) {
8753
+ throw error;
8754
+ }
8755
+ }
8756
+ }
8757
+
8758
+ private async syncDurably(name?: string): Promise<void> {
8759
+ const fs = await this.nodeFs();
8760
+ if (!fs.open) {
8761
+ throw new Error(
8762
+ "Node coordinate persistence does not expose a durable FileHandle.sync barrier",
8763
+ );
8764
+ }
8765
+ const syncHandle = async (
8766
+ handle: NativeBackboneNodeAppendFileHandle,
8767
+ target: string,
8768
+ ): Promise<void> => {
8769
+ if (typeof handle.sync !== "function") {
8770
+ throw new Error(
8771
+ `Node coordinate persistence ${target} does not expose FileHandle.sync`,
8772
+ );
8773
+ }
8774
+ await handle.sync();
8775
+ };
8776
+ if (name) {
8777
+ const path = await this.filePath(name);
8778
+ const appendHandle = this.appendHandles.get(path);
8779
+ if (appendHandle) {
8780
+ await syncHandle(await appendHandle, `file ${name}`);
8781
+ } else {
8782
+ let handle: NativeBackboneNodeAppendFileHandle | undefined;
8783
+ try {
8784
+ handle = await fs.open(path, "r");
8785
+ await syncHandle(handle, `file ${name}`);
8786
+ } finally {
8787
+ await handle?.close();
8788
+ }
8789
+ }
8790
+ } else {
8791
+ await Promise.all(
8792
+ [...this.appendHandles.entries()].map(async ([path, handle]) =>
8793
+ syncHandle(await handle, `file ${path}`),
8794
+ ),
8795
+ );
8796
+ }
8797
+ let directoryHandle: NativeBackboneNodeAppendFileHandle | undefined;
8798
+ try {
8799
+ directoryHandle = await fs.open(this.directory, "r");
8800
+ await syncHandle(directoryHandle, "directory");
8801
+ } catch (error) {
8802
+ if (!isNotFoundError(error) && !isUnsupportedDirectorySyncError(error)) {
8803
+ throw error;
8804
+ }
8805
+ } finally {
8806
+ await directoryHandle?.close();
8807
+ }
8808
+ }
8809
+
8502
8810
  async close(): Promise<void> {
8503
8811
  this.directoryEnsured = false;
8504
8812
  const handles = [...this.appendHandles.values()];
@@ -8510,6 +8818,8 @@ export class NativeBackboneNodeCoordinatePersistenceStore
8510
8818
  export class NativeBackboneOPFSCoordinatePersistenceStore
8511
8819
  implements NativeBackboneCoordinatePersistenceStore
8512
8820
  {
8821
+ private appendFailure: unknown;
8822
+
8513
8823
  constructor(private readonly directory: NativeBackboneOPFSDirectoryHandle) {}
8514
8824
 
8515
8825
  static async create(options?: {
@@ -8581,6 +8891,9 @@ export class NativeBackboneOPFSCoordinatePersistenceStore
8581
8891
  }
8582
8892
 
8583
8893
  async append(name: string, bytes: Uint8Array): Promise<void> {
8894
+ if (this.appendFailure !== undefined) {
8895
+ throw this.appendFailure;
8896
+ }
8584
8897
  const handle = await this.directory.getFileHandle(
8585
8898
  validateCoordinatePersistenceName(name),
8586
8899
  { create: true },
@@ -8593,10 +8906,29 @@ export class NativeBackboneOPFSCoordinatePersistenceStore
8593
8906
  // Main-thread OPFS and some browser contexts do not expose sync handles.
8594
8907
  }
8595
8908
  if (access) {
8909
+ const originalSize = access.getSize();
8910
+ let offset = 0;
8596
8911
  try {
8597
- access.write(bytes, { at: access.getSize() });
8912
+ while (offset < bytes.byteLength) {
8913
+ offset += validateCoordinatePersistenceWriteProgress(
8914
+ access.write(bytes.subarray(offset), {
8915
+ at: originalSize + offset,
8916
+ }),
8917
+ bytes.byteLength - offset,
8918
+ "OPFS coordinate WAL",
8919
+ );
8920
+ }
8598
8921
  access.flush?.();
8599
8922
  return;
8923
+ } catch (error) {
8924
+ try {
8925
+ access.truncate?.(originalSize);
8926
+ access.flush?.();
8927
+ } catch {
8928
+ // The sticky error below prevents appending behind a torn tail.
8929
+ }
8930
+ this.appendFailure ??= error;
8931
+ throw this.appendFailure;
8600
8932
  } finally {
8601
8933
  access.close();
8602
8934
  }
@@ -8607,8 +8939,16 @@ export class NativeBackboneOPFSCoordinatePersistenceStore
8607
8939
  try {
8608
8940
  await writable.seek(file.size);
8609
8941
  await writable.write(bytes);
8610
- } finally {
8611
8942
  await writable.close();
8943
+ } catch (error) {
8944
+ try {
8945
+ await writable.close();
8946
+ } catch {
8947
+ // Preserve the first error; the adapter is terminal either way.
8948
+ }
8949
+ // Async OPFS reports no write progress, so failure may leave a torn tail.
8950
+ this.appendFailure ??= error;
8951
+ throw this.appendFailure;
8612
8952
  }
8613
8953
  }
8614
8954
 
@@ -8621,6 +8961,36 @@ export class NativeBackboneOPFSCoordinatePersistenceStore
8621
8961
  }
8622
8962
  }
8623
8963
  }
8964
+
8965
+ async flush(_name?: string): Promise<void> {}
8966
+
8967
+ async durableBarrier(name?: string): Promise<void> {
8968
+ if (!name) {
8969
+ throw new Error(
8970
+ "OPFS coordinate persistence requires a named durable barrier",
8971
+ );
8972
+ }
8973
+ const handle = await this.directory.getFileHandle(
8974
+ validateCoordinatePersistenceName(name),
8975
+ { create: false },
8976
+ );
8977
+ if (!handle.createSyncAccessHandle) {
8978
+ throw new Error(
8979
+ "OPFS coordinate persistence durable barriers require createSyncAccessHandle",
8980
+ );
8981
+ }
8982
+ const access = await handle.createSyncAccessHandle();
8983
+ try {
8984
+ if (typeof access.flush !== "function") {
8985
+ throw new Error(
8986
+ "OPFS coordinate persistence sync handle does not expose flush",
8987
+ );
8988
+ }
8989
+ access.flush();
8990
+ } finally {
8991
+ access.close();
8992
+ }
8993
+ }
8624
8994
  }
8625
8995
 
8626
8996
  export class NativeBackboneBufferedCoordinatePersistenceStore
@@ -8628,11 +8998,22 @@ export class NativeBackboneBufferedCoordinatePersistenceStore
8628
8998
  {
8629
8999
  private readonly buffers = new Map<string, Uint8Array[]>();
8630
9000
  private bufferedBytes = 0;
9001
+ readonly supportsRemoval: boolean;
9002
+ readonly durableBarrier?: (name?: string) => Promise<void>;
8631
9003
 
8632
9004
  constructor(
8633
9005
  private readonly inner: NativeBackboneCoordinatePersistenceStore,
8634
9006
  private readonly options: { maxBufferedBytes?: number } = {},
8635
- ) {}
9007
+ ) {
9008
+ this.supportsRemoval =
9009
+ inner.supportsRemoval ?? typeof inner.remove === "function";
9010
+ if (typeof inner.durableBarrier === "function") {
9011
+ this.durableBarrier = async (name) => {
9012
+ await this.flush(name);
9013
+ await inner.durableBarrier!(name);
9014
+ };
9015
+ }
9016
+ }
8636
9017
 
8637
9018
  private buffer(name: string): Uint8Array[] {
8638
9019
  const validName = validateCoordinatePersistenceName(name);
@@ -8678,7 +9059,12 @@ export class NativeBackboneBufferedCoordinatePersistenceStore
8678
9059
  this.bufferedBytes -= chunk.byteLength;
8679
9060
  }
8680
9061
  }
8681
- await this.inner.remove?.(name);
9062
+ if (!this.inner.remove) {
9063
+ throw new Error(
9064
+ "Native backbone coordinate persistence store does not support removal",
9065
+ );
9066
+ }
9067
+ await this.inner.remove(name);
8682
9068
  }
8683
9069
 
8684
9070
  async flush(name?: string): Promise<void> {
@@ -8695,12 +9081,17 @@ export class NativeBackboneBufferedCoordinatePersistenceStore
8695
9081
  this.bufferedBytes -= bytes.byteLength;
8696
9082
  await this.inner.append(fileName, bytes);
8697
9083
  }
8698
- await this.inner.flush?.();
9084
+ await this.inner.flush?.(name);
8699
9085
  }
8700
9086
 
8701
- async close(): Promise<void> {
8702
- await this.flush();
8703
- await this.inner.close?.();
9087
+ async close(options?: { flush?: boolean }): Promise<void> {
9088
+ if (options?.flush === false) {
9089
+ this.buffers.clear();
9090
+ this.bufferedBytes = 0;
9091
+ } else {
9092
+ await this.flush();
9093
+ }
9094
+ await this.inner.close?.(options);
8704
9095
  }
8705
9096
  }
8706
9097
 
@@ -8710,6 +9101,10 @@ export class NativeBackboneCoordinatePersistence {
8710
9101
  readonly flushIntervalMs?: number;
8711
9102
  readonly compactMaxJournalBytes?: number;
8712
9103
  readonly compactMaxJournalRecords?: number;
9104
+ readonly crashSafeCompaction = false;
9105
+ readonly durableBarrier: boolean;
9106
+ readonly supportsDrop: boolean;
9107
+ readonly dropIsTerminal = true;
8713
9108
  private readonly snapshotFile: string;
8714
9109
  private readonly journalFile: string;
8715
9110
  private readonly documentSnapshotFile: string;
@@ -8717,101 +9112,357 @@ export class NativeBackboneCoordinatePersistence {
8717
9112
  private readonly documentSignerSnapshotFile: string;
8718
9113
  private readonly documentSignerJournalFile: string;
8719
9114
  private journalInitialized: boolean | undefined;
8720
- private journalByteLength = 0;
8721
- private journalRecordCount = 0;
8722
9115
  private documentJournalInitialized: boolean | undefined;
8723
- private documentJournalByteLength = 0;
8724
- private documentJournalRecordCount = 0;
8725
9116
  private documentSignerJournalInitialized: boolean | undefined;
8726
- private documentSignerJournalByteLength = 0;
8727
- private documentSignerJournalRecordCount = 0;
8728
9117
  private lastFlushMs = Date.now();
8729
9118
  private persistenceQueue: Promise<unknown> | undefined;
9119
+ private persistenceLifecycle:
9120
+ | "active"
9121
+ | "hydrating"
9122
+ | "dropping"
9123
+ | "dropped"
9124
+ | "closing"
9125
+ | "closed" = "active";
9126
+ private dropInitiatedOnGeneration = false;
9127
+ private persistenceFailure: unknown;
9128
+ private closeMode: "flush" | "withoutFlush" | undefined;
9129
+ private closeFlushCompleted = false;
9130
+ private closeStoreCompleted = false;
9131
+ private closePromise: Promise<void> | undefined;
8730
9132
 
8731
9133
  constructor(
8732
9134
  private readonly store: NativeBackboneCoordinatePersistenceStore,
8733
9135
  options: NativeBackboneCoordinatePersistenceOptions = {},
8734
9136
  ) {
8735
- this.snapshotFile =
8736
- options.snapshot ?? nativeBackboneCoordinatePersistenceFiles.snapshot;
8737
- this.journalFile =
8738
- options.journal ?? nativeBackboneCoordinatePersistenceFiles.journal;
8739
- this.documentSnapshotFile =
9137
+ this.durableBarrier = typeof store.durableBarrier === "function";
9138
+ this.supportsDrop =
9139
+ (store.supportsRemoval ?? typeof store.remove === "function") &&
9140
+ typeof store.remove === "function";
9141
+ this.snapshotFile = validateCoordinatePersistenceName(
9142
+ options.snapshot ?? nativeBackboneCoordinatePersistenceFiles.snapshot,
9143
+ );
9144
+ this.journalFile = validateCoordinatePersistenceName(
9145
+ options.journal ?? nativeBackboneCoordinatePersistenceFiles.journal,
9146
+ );
9147
+ this.documentSnapshotFile = validateCoordinatePersistenceName(
8740
9148
  options.documentSnapshot ??
8741
- nativeBackboneCoordinatePersistenceFiles.documentSnapshot;
8742
- this.documentJournalFile =
9149
+ nativeBackboneCoordinatePersistenceFiles.documentSnapshot,
9150
+ );
9151
+ this.documentJournalFile = validateCoordinatePersistenceName(
8743
9152
  options.documentJournal ??
8744
- nativeBackboneCoordinatePersistenceFiles.documentJournal;
8745
- this.documentSignerSnapshotFile =
9153
+ nativeBackboneCoordinatePersistenceFiles.documentJournal,
9154
+ );
9155
+ this.documentSignerSnapshotFile = validateCoordinatePersistenceName(
8746
9156
  options.documentSignerSnapshot ??
8747
- nativeBackboneCoordinatePersistenceFiles.documentSignerSnapshot;
8748
- this.documentSignerJournalFile =
9157
+ nativeBackboneCoordinatePersistenceFiles.documentSignerSnapshot,
9158
+ );
9159
+ this.documentSignerJournalFile = validateCoordinatePersistenceName(
8749
9160
  options.documentSignerJournal ??
8750
- nativeBackboneCoordinatePersistenceFiles.documentSignerJournal;
9161
+ nativeBackboneCoordinatePersistenceFiles.documentSignerJournal,
9162
+ );
9163
+ if (
9164
+ this.configuredFiles().includes(nativeBackboneCoordinateDropTombstoneFile)
9165
+ ) {
9166
+ throw new Error(
9167
+ "Native backbone coordinate persistence file conflicts with its drop tombstone",
9168
+ );
9169
+ }
8751
9170
  this.flushOnAppend = options.flushOnAppend ?? true;
8752
9171
  this.flushMaxPendingBytes = resolveCoordinateFlushMaxPendingBytes(options);
8753
9172
  if (options.flushIntervalMs != null) {
8754
9173
  this.flushIntervalMs = Math.max(0, options.flushIntervalMs);
8755
9174
  }
8756
- if (options.compactMaxJournalBytes != null) {
8757
- this.compactMaxJournalBytes = Math.max(
8758
- 0,
8759
- options.compactMaxJournalBytes,
9175
+ if (
9176
+ options.compactMaxJournalBytes != null ||
9177
+ options.compactMaxJournalRecords != null
9178
+ ) {
9179
+ throw new Error(nativeBackboneCoordinateCompactionDisabledMessage);
9180
+ }
9181
+ }
9182
+
9183
+ /** Durable operation-intent capability for strict shared-log transactions. */
9184
+ get intentStore(): NativeBackboneCoordinatePersistenceStore {
9185
+ return this.store;
9186
+ }
9187
+
9188
+ private configuredFiles(): string[] {
9189
+ return [
9190
+ this.snapshotFile,
9191
+ this.journalFile,
9192
+ this.documentSnapshotFile,
9193
+ this.documentJournalFile,
9194
+ this.documentSignerSnapshotFile,
9195
+ this.documentSignerJournalFile,
9196
+ ];
9197
+ }
9198
+
9199
+ private assertLifecycleActive(operation: string): void {
9200
+ if (this.persistenceLifecycle !== "active") {
9201
+ throw new Error(
9202
+ `Native backbone coordinate persistence can not ${operation} while ${this.persistenceLifecycle}`,
8760
9203
  );
8761
9204
  }
8762
- if (options.compactMaxJournalRecords != null) {
8763
- this.compactMaxJournalRecords = Math.max(
8764
- 0,
8765
- options.compactMaxJournalRecords,
9205
+ }
9206
+
9207
+ private assertActive(operation: string): void {
9208
+ if (this.persistenceFailure !== undefined) {
9209
+ throw this.persistenceFailure;
9210
+ }
9211
+ this.assertLifecycleActive(operation);
9212
+ if (this.dropInitiatedOnGeneration) {
9213
+ throw new Error(
9214
+ `Native backbone coordinate persistence can not ${operation} after drop was initiated; retry drop or resume drop first`,
8766
9215
  );
8767
9216
  }
8768
9217
  }
8769
9218
 
8770
- async hydrate(backbone: NativePeerbitBackbone): Promise<number> {
8771
- const [
8772
- snapshot,
8773
- journal,
8774
- documentSnapshot,
8775
- documentJournal,
8776
- documentSignerSnapshot,
8777
- documentSignerJournal,
8778
- ] = await Promise.all([
8779
- this.store.read(this.snapshotFile),
8780
- this.store.read(this.journalFile),
8781
- this.store.read(this.documentSnapshotFile),
8782
- this.store.read(this.documentJournalFile),
8783
- this.store.read(this.documentSignerSnapshotFile),
8784
- this.store.read(this.documentSignerJournalFile),
8785
- ]);
8786
- const operations = backbone.loadCoordinateSnapshotAndJournal(
8787
- snapshot,
8788
- journal,
9219
+ private resetJournalTracking(): void {
9220
+ this.journalInitialized = undefined;
9221
+ this.documentJournalInitialized = undefined;
9222
+ this.documentSignerJournalInitialized = undefined;
9223
+ this.lastFlushMs = Date.now();
9224
+ }
9225
+
9226
+ private async eraseDropFiles(files: readonly string[]): Promise<void> {
9227
+ if (!this.supportsDrop || !this.store.remove) {
9228
+ throw new Error(
9229
+ "Native backbone coordinate persistence store does not support removal",
9230
+ );
9231
+ }
9232
+ const removals = await Promise.allSettled(
9233
+ files.map((name) => this.store.remove!(name)),
8789
9234
  );
8790
- const documentOperations = backbone.loadDocumentSnapshotAndJournal(
8791
- documentSnapshot,
8792
- documentJournal,
9235
+ const failures = removals.flatMap((result) =>
9236
+ result.status === "rejected" ? [result.reason] : [],
8793
9237
  );
8794
- const documentSignerOperations = backbone.loadDocumentSignerSnapshotAndJournal(
8795
- documentSignerSnapshot,
8796
- documentSignerJournal,
9238
+ if (failures.length > 0) {
9239
+ throw new AggregateError(
9240
+ failures,
9241
+ "Failed to erase native backbone coordinate persistence namespace",
9242
+ );
9243
+ }
9244
+ await this.store.flush?.();
9245
+ await this.store.remove(nativeBackboneCoordinateDropTombstoneFile);
9246
+ await this.store.flush?.();
9247
+ }
9248
+
9249
+ async drop(additionalFiles: readonly string[] = []): Promise<void> {
9250
+ // Drop is the recovery escape hatch for a persistence generation that has
9251
+ // already failed closed, so only the lifecycle (not persistenceFailure)
9252
+ // gates this destructive operation.
9253
+ this.assertLifecycleActive("drop");
9254
+ const files = [
9255
+ ...new Set([
9256
+ ...this.configuredFiles(),
9257
+ ...additionalFiles.map(validateCoordinatePersistenceName),
9258
+ ]),
9259
+ ];
9260
+ if (files.includes(nativeBackboneCoordinateDropTombstoneFile)) {
9261
+ throw new Error(
9262
+ "Native backbone drop targets can not include the drop tombstone",
9263
+ );
9264
+ }
9265
+ if (!this.supportsDrop || !this.store.remove) {
9266
+ throw new Error(
9267
+ "Native backbone coordinate persistence store does not support removal",
9268
+ );
9269
+ }
9270
+ // Flip synchronously so no later append/compact can enqueue behind this
9271
+ // erase and recreate a file after its removal.
9272
+ this.dropInitiatedOnGeneration = true;
9273
+ this.persistenceLifecycle = "dropping";
9274
+ await this.enqueuePersistence(async () => {
9275
+ await this.store.write(
9276
+ nativeBackboneCoordinateDropTombstoneFile,
9277
+ nativeBackboneCoordinateDropTombstoneBytes(files),
9278
+ );
9279
+ if (this.store.durableBarrier) {
9280
+ await this.store.durableBarrier(
9281
+ nativeBackboneCoordinateDropTombstoneFile,
9282
+ );
9283
+ } else {
9284
+ await this.store.flush?.(nativeBackboneCoordinateDropTombstoneFile);
9285
+ }
9286
+ await this.eraseDropFiles(files);
9287
+ this.resetJournalTracking();
9288
+ this.persistenceLifecycle = "dropped";
9289
+ });
9290
+ }
9291
+
9292
+ async resumeDrop(): Promise<boolean> {
9293
+ if (this.persistenceLifecycle === "dropped") {
9294
+ return true;
9295
+ }
9296
+ if (this.closeMode !== undefined) {
9297
+ throw new Error(
9298
+ "Native backbone coordinate persistence can not resume drop after close was initiated",
9299
+ );
9300
+ }
9301
+ const resumesInProgress = this.persistenceLifecycle === "dropping";
9302
+ const completesInitiatedDrop = this.dropInitiatedOnGeneration;
9303
+ if (!resumesInProgress) {
9304
+ if (completesInitiatedDrop) {
9305
+ this.assertLifecycleActive("resume drop");
9306
+ } else {
9307
+ this.assertActive("resume drop");
9308
+ }
9309
+ }
9310
+ this.persistenceLifecycle = "dropping";
9311
+ return this.enqueuePersistence(async () => {
9312
+ // A concurrent drop may have completed before this queued recovery runs.
9313
+ // Preserve its terminal lifecycle instead of reactivating the generation.
9314
+ if (this.persistenceLifecycle === "dropped") {
9315
+ return true;
9316
+ }
9317
+ return this.resumeDropInternal(
9318
+ completesInitiatedDrop ? "dropped" : "active",
9319
+ );
9320
+ });
9321
+ }
9322
+
9323
+ async hydrate(backbone: NativePeerbitBackbone): Promise<number> {
9324
+ this.assertActive("hydrate");
9325
+ // Claim the lifecycle synchronously. close() queues after this complete
9326
+ // read/validate/load operation; drop() rejects before erasing anything.
9327
+ this.persistenceLifecycle = "hydrating";
9328
+ return this.enqueuePersistence(async () => {
9329
+ try {
9330
+ this.assertHydrating();
9331
+ await this.resumeDropInternal("hydrating");
9332
+ this.assertHydrating();
9333
+ const [
9334
+ snapshot,
9335
+ journal,
9336
+ documentSnapshot,
9337
+ documentJournal,
9338
+ documentSignerSnapshot,
9339
+ documentSignerJournal,
9340
+ ] = await Promise.all([
9341
+ this.store.read(this.snapshotFile),
9342
+ this.store.read(this.journalFile),
9343
+ this.store.read(this.documentSnapshotFile),
9344
+ this.store.read(this.documentJournalFile),
9345
+ this.store.read(this.documentSignerSnapshotFile),
9346
+ this.store.read(this.documentSignerJournalFile),
9347
+ ]);
9348
+ this.assertHydrating();
9349
+ try {
9350
+ validateCoordinateJournal(journal, this.journalFile);
9351
+ validateCoordinateJournal(documentJournal, this.documentJournalFile);
9352
+ validateCoordinateJournal(
9353
+ documentSignerJournal,
9354
+ this.documentSignerJournalFile,
9355
+ );
9356
+ } catch (error) {
9357
+ this.persistenceFailure ??= error;
9358
+ throw this.persistenceFailure;
9359
+ }
9360
+ let operations: number;
9361
+ let documentOperations: number;
9362
+ let documentSignerOperations: number;
9363
+ try {
9364
+ this.assertHydrating();
9365
+ operations = backbone.loadCoordinateSnapshotAndJournal(
9366
+ snapshot,
9367
+ journal,
9368
+ );
9369
+ this.assertHydrating();
9370
+ documentOperations = backbone.loadDocumentSnapshotAndJournal(
9371
+ documentSnapshot,
9372
+ documentJournal,
9373
+ );
9374
+ this.assertHydrating();
9375
+ documentSignerOperations =
9376
+ backbone.loadDocumentSignerSnapshotAndJournal(
9377
+ documentSignerSnapshot,
9378
+ documentSignerJournal,
9379
+ );
9380
+ } catch (error) {
9381
+ if (
9382
+ journal?.byteLength ||
9383
+ documentJournal?.byteLength ||
9384
+ documentSignerJournal?.byteLength
9385
+ ) {
9386
+ this.persistenceFailure ??= error;
9387
+ throw this.persistenceFailure;
9388
+ }
9389
+ throw error;
9390
+ }
9391
+ this.assertHydrating();
9392
+ this.journalInitialized = !!journal && journal.byteLength > 0;
9393
+ this.documentJournalInitialized =
9394
+ !!documentJournal && documentJournal.byteLength > 0;
9395
+ this.documentSignerJournalInitialized =
9396
+ !!documentSignerJournal && documentSignerJournal.byteLength > 0;
9397
+ backbone.setCoordinateJournalEnabled(true);
9398
+ backbone.setDocumentJournalEnabled(true);
9399
+ backbone.setDocumentSignerJournalEnabled(true);
9400
+ this.lastFlushMs = Date.now();
9401
+ this.persistenceLifecycle = this.closePromise ? "closing" : "active";
9402
+ return operations + documentOperations + documentSignerOperations;
9403
+ } catch (error) {
9404
+ if (this.persistenceLifecycle === "hydrating") {
9405
+ this.persistenceLifecycle = this.closePromise ? "closing" : "active";
9406
+ }
9407
+ throw error;
9408
+ }
9409
+ });
9410
+ }
9411
+
9412
+ private assertHydrating(): void {
9413
+ if (this.persistenceLifecycle !== "hydrating") {
9414
+ throw new Error(
9415
+ `Native backbone coordinate persistence hydrate was interrupted while ${this.persistenceLifecycle}`,
9416
+ );
9417
+ }
9418
+ }
9419
+
9420
+ private async resumeDropInternal(
9421
+ finalLifecycle: "active" | "hydrating" | "dropped",
9422
+ ): Promise<boolean> {
9423
+ const bytes = await this.store.read(
9424
+ nativeBackboneCoordinateDropTombstoneFile,
8797
9425
  );
8798
- this.journalInitialized = !!journal && journal.byteLength > 0;
8799
- this.journalByteLength = journal?.byteLength ?? 0;
8800
- this.journalRecordCount = operations;
8801
- this.documentJournalInitialized =
8802
- !!documentJournal && documentJournal.byteLength > 0;
8803
- this.documentJournalByteLength = documentJournal?.byteLength ?? 0;
8804
- this.documentJournalRecordCount = documentOperations;
8805
- this.documentSignerJournalInitialized =
8806
- !!documentSignerJournal && documentSignerJournal.byteLength > 0;
8807
- this.documentSignerJournalByteLength =
8808
- documentSignerJournal?.byteLength ?? 0;
8809
- this.documentSignerJournalRecordCount = documentSignerOperations;
8810
- backbone.setCoordinateJournalEnabled(true);
8811
- backbone.setDocumentJournalEnabled(true);
8812
- backbone.setDocumentSignerJournalEnabled(true);
8813
- this.lastFlushMs = Date.now();
8814
- return operations + documentOperations + documentSignerOperations;
9426
+ if (!bytes) {
9427
+ // A failed drop can stop before its tombstone is durable. Restore the
9428
+ // generation to active so the caller can start a complete drop; only a
9429
+ // tombstone-backed erase may finish it as dropped.
9430
+ this.persistenceLifecycle =
9431
+ finalLifecycle === "hydrating"
9432
+ ? "hydrating"
9433
+ : this.closePromise
9434
+ ? "closing"
9435
+ : "active";
9436
+ return false;
9437
+ }
9438
+ let tombstone: NativeBackboneCoordinateDropTombstoneBody;
9439
+ try {
9440
+ tombstone = parseNativeBackboneCoordinateDropTombstone(bytes);
9441
+ for (const file of this.configuredFiles()) {
9442
+ if (!tombstone.files.includes(file)) {
9443
+ throw new Error(
9444
+ "Native backbone drop tombstone does not cover the configured namespace",
9445
+ );
9446
+ }
9447
+ }
9448
+ } catch (error) {
9449
+ // Corruption must never hydrate stale files, but an explicit drop must
9450
+ // remain available to overwrite the bad marker and erase the namespace.
9451
+ this.persistenceFailure ??= error;
9452
+ this.persistenceLifecycle = this.closePromise ? "closing" : "active";
9453
+ throw this.persistenceFailure;
9454
+ }
9455
+ await this.eraseDropFiles(tombstone.files);
9456
+ this.resetJournalTracking();
9457
+ this.persistenceLifecycle =
9458
+ finalLifecycle === "dropped"
9459
+ ? "dropped"
9460
+ : finalLifecycle === "hydrating"
9461
+ ? "hydrating"
9462
+ : this.closePromise
9463
+ ? "closing"
9464
+ : "active";
9465
+ return true;
8815
9466
  }
8816
9467
 
8817
9468
  shouldFlushJournalOnAppend(
@@ -8846,6 +9497,7 @@ export class NativeBackboneCoordinatePersistence {
8846
9497
  flushJournalOnAppend(
8847
9498
  backbone: NativePeerbitBackbone,
8848
9499
  ): number | Promise<number> {
9500
+ this.assertActive("flush on append");
8849
9501
  if (!this.shouldFlushJournalOnAppend(backbone)) {
8850
9502
  return 0;
8851
9503
  }
@@ -8853,6 +9505,7 @@ export class NativeBackboneCoordinatePersistence {
8853
9505
  }
8854
9506
 
8855
9507
  flushJournal(backbone: NativePeerbitBackbone): Promise<number> {
9508
+ this.assertActive("flush");
8856
9509
  // Serialized with compact() so a flush never clears records appended to
8857
9510
  // the wasm journal while a previous flush was awaiting its disk write.
8858
9511
  return this.enqueuePersistence(() => this.flushJournalInternal(backbone));
@@ -8862,9 +9515,7 @@ export class NativeBackboneCoordinatePersistence {
8862
9515
  // Runs `fn` immediately when no other persistence operation is in
8863
9516
  // flight so the common uncontended flush starts synchronously; queued
8864
9517
  // operations still run strictly one at a time, in order.
8865
- const next = this.persistenceQueue
8866
- ? this.persistenceQueue.then(fn)
8867
- : fn();
9518
+ const next = this.persistenceQueue ? this.persistenceQueue.then(fn) : fn();
8868
9519
  const tail: Promise<void> = next.then(
8869
9520
  () => undefined,
8870
9521
  () => undefined,
@@ -8882,153 +9533,172 @@ export class NativeBackboneCoordinatePersistence {
8882
9533
  backbone: NativePeerbitBackbone,
8883
9534
  ): Promise<number> {
8884
9535
  let written = 0;
9536
+ let persistenceMutationStarted = false;
9537
+ let coordinateBytes: Uint8Array | undefined;
9538
+ let documentBytes: Uint8Array | undefined;
9539
+ let signerBytes: Uint8Array | undefined;
8885
9540
  const coordinateRecords = backbone.coordinateJournal();
8886
9541
  const coordinateRecordCount = backbone.coordinatePendingJournalLength;
8887
- if (coordinateRecords.byteLength > 0) {
8888
- if (this.journalInitialized === undefined) {
8889
- const existing = await this.store.read(this.journalFile);
8890
- this.journalInitialized = !!existing && existing.byteLength > 0;
9542
+ const documentRecords = backbone.documentJournal();
9543
+ const documentRecordCount = backbone.documentPendingJournalLength;
9544
+ const signerRecords = backbone.documentSignerJournal();
9545
+ const signerRecordCount = backbone.documentSignerPendingJournalLength;
9546
+ try {
9547
+ if (coordinateRecords.byteLength > 0) {
9548
+ if (this.journalInitialized === undefined) {
9549
+ const existing = await this.store.read(this.journalFile);
9550
+ this.journalInitialized = !!existing && existing.byteLength > 0;
9551
+ }
9552
+ coordinateBytes = this.journalInitialized
9553
+ ? coordinateRecords
9554
+ : concatBytes([
9555
+ backbone.coordinateJournalHeader(),
9556
+ coordinateRecords,
9557
+ ]);
9558
+ await this.store.append(this.journalFile, coordinateBytes);
9559
+ persistenceMutationStarted = true;
9560
+ written += coordinateRecords.byteLength;
9561
+ }
9562
+ if (documentRecords.byteLength > 0) {
9563
+ if (this.documentJournalInitialized === undefined) {
9564
+ const existing = await this.store.read(this.documentJournalFile);
9565
+ this.documentJournalInitialized =
9566
+ !!existing && existing.byteLength > 0;
9567
+ }
9568
+ documentBytes = this.documentJournalInitialized
9569
+ ? documentRecords
9570
+ : concatBytes([backbone.documentJournalHeader(), documentRecords]);
9571
+ await this.store.append(this.documentJournalFile, documentBytes);
9572
+ persistenceMutationStarted = true;
9573
+ written += documentRecords.byteLength;
8891
9574
  }
8892
- const bytes = this.journalInitialized
8893
- ? coordinateRecords
8894
- : concatBytes([backbone.coordinateJournalHeader(), coordinateRecords]);
8895
- await this.store.append(this.journalFile, bytes);
8896
- this.journalInitialized = true;
8897
- this.journalByteLength += bytes.byteLength;
8898
- this.journalRecordCount += coordinateRecordCount;
9575
+ if (signerRecords.byteLength > 0) {
9576
+ if (this.documentSignerJournalInitialized === undefined) {
9577
+ const existing = await this.store.read(
9578
+ this.documentSignerJournalFile,
9579
+ );
9580
+ this.documentSignerJournalInitialized =
9581
+ !!existing && existing.byteLength > 0;
9582
+ }
9583
+ signerBytes = this.documentSignerJournalInitialized
9584
+ ? signerRecords
9585
+ : concatBytes([
9586
+ backbone.documentSignerJournalHeader(),
9587
+ signerRecords,
9588
+ ]);
9589
+ await this.store.append(this.documentSignerJournalFile, signerBytes);
9590
+ persistenceMutationStarted = true;
9591
+ written += signerRecords.byteLength;
9592
+ }
9593
+ if (written === 0) {
9594
+ this.lastFlushMs = Date.now();
9595
+ return 0;
9596
+ }
9597
+
9598
+ // `append` may only enqueue bytes in a buffered store. Drain and fsync
9599
+ // every affected WAL before clearing its wasm prefix or returning an ACK.
9600
+ for (const file of [
9601
+ coordinateBytes ? this.journalFile : undefined,
9602
+ documentBytes ? this.documentJournalFile : undefined,
9603
+ signerBytes ? this.documentSignerJournalFile : undefined,
9604
+ ]) {
9605
+ if (file) {
9606
+ if (this.store.durableBarrier) {
9607
+ await this.store.durableBarrier(file);
9608
+ } else {
9609
+ await this.store.flush?.(file);
9610
+ }
9611
+ }
9612
+ }
9613
+
9614
+ if (coordinateBytes) {
9615
+ this.journalInitialized = true;
9616
+ }
9617
+ if (documentBytes) {
9618
+ this.documentJournalInitialized = true;
9619
+ }
9620
+ if (signerBytes) {
9621
+ this.documentSignerJournalInitialized = true;
9622
+ }
9623
+
8899
9624
  backbone.clearCoordinateJournalPrefix(
8900
9625
  coordinateRecords.byteLength,
8901
9626
  coordinateRecordCount,
8902
9627
  );
8903
- written += coordinateRecords.byteLength;
8904
- }
8905
- const documentRecords = backbone.documentJournal();
8906
- const documentRecordCount = backbone.documentPendingJournalLength;
8907
- if (documentRecords.byteLength > 0) {
8908
- if (this.documentJournalInitialized === undefined) {
8909
- const existing = await this.store.read(this.documentJournalFile);
8910
- this.documentJournalInitialized = !!existing && existing.byteLength > 0;
8911
- }
8912
- const bytes = this.documentJournalInitialized
8913
- ? documentRecords
8914
- : concatBytes([backbone.documentJournalHeader(), documentRecords]);
8915
- await this.store.append(this.documentJournalFile, bytes);
8916
- this.documentJournalInitialized = true;
8917
- this.documentJournalByteLength += bytes.byteLength;
8918
- this.documentJournalRecordCount += documentRecordCount;
8919
9628
  backbone.clearDocumentJournalPrefix(
8920
9629
  documentRecords.byteLength,
8921
9630
  documentRecordCount,
8922
9631
  );
8923
- written += documentRecords.byteLength;
8924
- }
8925
- const signerRecords = backbone.documentSignerJournal();
8926
- const signerRecordCount = backbone.documentSignerPendingJournalLength;
8927
- if (signerRecords.byteLength > 0) {
8928
- if (this.documentSignerJournalInitialized === undefined) {
8929
- const existing = await this.store.read(this.documentSignerJournalFile);
8930
- this.documentSignerJournalInitialized =
8931
- !!existing && existing.byteLength > 0;
8932
- }
8933
- const bytes = this.documentSignerJournalInitialized
8934
- ? signerRecords
8935
- : concatBytes([backbone.documentSignerJournalHeader(), signerRecords]);
8936
- await this.store.append(this.documentSignerJournalFile, bytes);
8937
- this.documentSignerJournalInitialized = true;
8938
- this.documentSignerJournalByteLength += bytes.byteLength;
8939
- this.documentSignerJournalRecordCount += signerRecordCount;
8940
9632
  backbone.clearDocumentSignerJournalPrefix(
8941
9633
  signerRecords.byteLength,
8942
9634
  signerRecordCount,
8943
9635
  );
8944
- written += signerRecords.byteLength;
8945
- }
8946
- if (written === 0) {
8947
9636
  this.lastFlushMs = Date.now();
8948
- return 0;
8949
- }
8950
- this.lastFlushMs = Date.now();
8951
- if (this.shouldCompactJournal()) {
8952
- await this.compactInternal(backbone);
9637
+ return written;
9638
+ } catch (error) {
9639
+ if (persistenceMutationStarted) {
9640
+ this.persistenceFailure ??= error;
9641
+ throw this.persistenceFailure;
9642
+ }
9643
+ throw error;
8953
9644
  }
8954
- return written;
8955
9645
  }
8956
9646
 
8957
- private shouldCompactJournal(): boolean {
8958
- return (
8959
- (this.compactMaxJournalBytes != null &&
8960
- this.journalByteLength +
8961
- this.documentJournalByteLength +
8962
- this.documentSignerJournalByteLength >=
8963
- this.compactMaxJournalBytes) ||
8964
- (this.compactMaxJournalRecords != null &&
8965
- this.journalRecordCount +
8966
- this.documentJournalRecordCount +
8967
- this.documentSignerJournalRecordCount >=
8968
- this.compactMaxJournalRecords)
8969
- );
8970
- }
8971
-
8972
- compact(backbone: NativePeerbitBackbone): Promise<void> {
8973
- return this.enqueuePersistence(() => this.compactInternal(backbone));
9647
+ async compact(_backbone: NativePeerbitBackbone): Promise<void> {
9648
+ this.assertActive("compact");
9649
+ throw new Error(nativeBackboneCoordinateCompactionDisabledMessage);
8974
9650
  }
8975
9651
 
8976
- private async compactInternal(backbone: NativePeerbitBackbone): Promise<void> {
8977
- // The snapshots below cover exactly the journal records pending right
8978
- // now; records appended during the awaited writes must survive the
8979
- // clears at the end, so only this prefix is dropped.
8980
- const coordinateJournalByteLength =
8981
- backbone.coordinatePendingJournalByteLength;
8982
- const coordinateJournalRecordCount =
8983
- backbone.coordinatePendingJournalLength;
8984
- const documentJournalByteLength = backbone.documentPendingJournalByteLength;
8985
- const documentJournalRecordCount = backbone.documentPendingJournalLength;
8986
- const documentSignerJournalByteLength =
8987
- backbone.documentSignerPendingJournalByteLength;
8988
- const documentSignerJournalRecordCount =
8989
- backbone.documentSignerPendingJournalLength;
8990
- await Promise.all([
8991
- this.store.write(this.snapshotFile, backbone.coordinateSnapshot()),
8992
- this.store.write(this.documentSnapshotFile, backbone.documentSnapshot()),
8993
- this.store.write(
8994
- this.documentSignerSnapshotFile,
8995
- backbone.documentSignerSnapshot(),
8996
- ),
8997
- ]);
8998
- await Promise.all([
8999
- this.store.remove?.(this.journalFile),
9000
- this.store.remove?.(this.documentJournalFile),
9001
- this.store.remove?.(this.documentSignerJournalFile),
9002
- ]);
9003
- this.journalInitialized = false;
9004
- this.journalByteLength = 0;
9005
- this.journalRecordCount = 0;
9006
- this.documentJournalInitialized = false;
9007
- this.documentJournalByteLength = 0;
9008
- this.documentJournalRecordCount = 0;
9009
- this.documentSignerJournalInitialized = false;
9010
- this.documentSignerJournalByteLength = 0;
9011
- this.documentSignerJournalRecordCount = 0;
9012
- backbone.clearCoordinateJournalPrefix(
9013
- coordinateJournalByteLength,
9014
- coordinateJournalRecordCount,
9015
- );
9016
- backbone.clearDocumentJournalPrefix(
9017
- documentJournalByteLength,
9018
- documentJournalRecordCount,
9019
- );
9020
- backbone.clearDocumentSignerJournalPrefix(
9021
- documentSignerJournalByteLength,
9022
- documentSignerJournalRecordCount,
9023
- );
9024
- // Compact persists the full pending state, so it restarts the
9025
- // flushIntervalMs pacing window like a flush does.
9026
- this.lastFlushMs = Date.now();
9027
- }
9028
-
9029
- async close(): Promise<void> {
9030
- await this.store.flush?.();
9031
- await this.store.close?.();
9652
+ close(): Promise<void> {
9653
+ if (this.closePromise) {
9654
+ return this.closePromise;
9655
+ }
9656
+ const closeMode: "flush" | "withoutFlush" =
9657
+ this.closeMode ??
9658
+ (this.persistenceLifecycle === "active" && !this.dropInitiatedOnGeneration
9659
+ ? "flush"
9660
+ : "withoutFlush");
9661
+ this.closeMode = closeMode;
9662
+ // Close wins once invoked from an active generation. The synchronous
9663
+ // transition rejects any later drop/hydrate/flush before the terminal
9664
+ // store close starts, including for stores that forbid all post-close I/O.
9665
+ if (this.persistenceLifecycle === "active") {
9666
+ this.persistenceLifecycle = "closing";
9667
+ }
9668
+ const closeAttempt = this.enqueuePersistence(async () => {
9669
+ if (closeMode === "flush") {
9670
+ this.persistenceLifecycle = "closing";
9671
+ if (!this.closeFlushCompleted) {
9672
+ await this.store.flush?.();
9673
+ this.closeFlushCompleted = true;
9674
+ }
9675
+ if (!this.closeStoreCompleted) {
9676
+ await this.store.close?.();
9677
+ this.closeStoreCompleted = true;
9678
+ }
9679
+ this.persistenceLifecycle = "closed";
9680
+ return;
9681
+ }
9682
+ // A drop already in flight wins. Drain no buffered bytes after its
9683
+ // tombstone erase and preserve the dropped terminal lifecycle.
9684
+ if (!this.closeStoreCompleted) {
9685
+ await this.store.close?.({ flush: false });
9686
+ this.closeStoreCompleted = true;
9687
+ }
9688
+ if (this.persistenceLifecycle !== "dropped") {
9689
+ this.persistenceLifecycle = "closed";
9690
+ }
9691
+ });
9692
+ this.closePromise = closeAttempt;
9693
+ void closeAttempt.catch(() => {
9694
+ // A rejected close is only the failed attempt, not terminal progress.
9695
+ // Retain completed stages above, but let the exact owner retry the first
9696
+ // incomplete store operation.
9697
+ if (this.closePromise === closeAttempt) {
9698
+ this.closePromise = undefined;
9699
+ }
9700
+ });
9701
+ return closeAttempt;
9032
9702
  }
9033
9703
  }
9034
9704
 
@@ -9086,20 +9756,13 @@ export const createNativeBackboneCoordinatePersistence = (
9086
9756
  return config;
9087
9757
  }
9088
9758
  const { store, buffered, ...options } = config;
9089
- const isBuffered = buffered === true || !!buffered;
9090
9759
  const resolvedStore =
9091
9760
  buffered === true
9092
9761
  ? new NativeBackboneBufferedCoordinatePersistenceStore(store)
9093
9762
  : buffered
9094
9763
  ? new NativeBackboneBufferedCoordinatePersistenceStore(store, buffered)
9095
9764
  : store;
9096
- return new NativeBackboneCoordinatePersistence(resolvedStore, {
9097
- ...options,
9098
- compactMaxJournalBytes:
9099
- isBuffered && options.compactMaxJournalBytes == null
9100
- ? defaultNativeBackboneCoordinateCompactMaxJournalBytes
9101
- : options.compactMaxJournalBytes,
9102
- });
9765
+ return new NativeBackboneCoordinatePersistence(resolvedStore, options);
9103
9766
  };
9104
9767
 
9105
9768
  export const createBufferedNativeBackboneCoordinatePersistence = (
@@ -9110,8 +9773,7 @@ export const createBufferedNativeBackboneCoordinatePersistence = (
9110
9773
  options.maxBufferedBytes ??
9111
9774
  options.flushMaxPendingBytes ??
9112
9775
  defaultNativeBackboneCoordinateFlushMaxPendingBytes;
9113
- const flushMaxPendingBytes =
9114
- options.flushMaxPendingBytes ?? maxBufferedBytes;
9776
+ const flushMaxPendingBytes = options.flushMaxPendingBytes ?? maxBufferedBytes;
9115
9777
  return new NativeBackboneCoordinatePersistence(
9116
9778
  new NativeBackboneBufferedCoordinatePersistenceStore(store, {
9117
9779
  maxBufferedBytes,
@@ -9126,9 +9788,7 @@ export const createBufferedNativeBackboneCoordinatePersistence = (
9126
9788
  flushOnAppend: false,
9127
9789
  flushMaxPendingBytes,
9128
9790
  flushIntervalMs: options.flushIntervalMs,
9129
- compactMaxJournalBytes:
9130
- options.compactMaxJournalBytes ??
9131
- defaultNativeBackboneCoordinateCompactMaxJournalBytes,
9791
+ compactMaxJournalBytes: options.compactMaxJournalBytes,
9132
9792
  compactMaxJournalRecords: options.compactMaxJournalRecords,
9133
9793
  },
9134
9794
  );
@@ -9146,9 +9806,6 @@ export const createBufferedNativeBackboneNodeCoordinatePersistence = (
9146
9806
  flushOnAppend: false,
9147
9807
  flushMaxPendingBytes,
9148
9808
  writeBufferMaxBytes: options.writeBufferMaxBytes ?? flushMaxPendingBytes,
9149
- compactMaxJournalBytes:
9150
- options.compactMaxJournalBytes ??
9151
- defaultNativeBackboneCoordinateCompactMaxJournalBytes,
9152
9809
  });
9153
9810
  };
9154
9811