@optimystic/db-p2p 0.0.1

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 (189) hide show
  1. package/dist/index.min.js +52 -0
  2. package/dist/index.min.js.map +7 -0
  3. package/dist/src/cluster/client.d.ts +12 -0
  4. package/dist/src/cluster/client.d.ts.map +1 -0
  5. package/dist/src/cluster/client.js +65 -0
  6. package/dist/src/cluster/client.js.map +1 -0
  7. package/dist/src/cluster/cluster-repo.d.ts +79 -0
  8. package/dist/src/cluster/cluster-repo.d.ts.map +1 -0
  9. package/dist/src/cluster/cluster-repo.js +613 -0
  10. package/dist/src/cluster/cluster-repo.js.map +1 -0
  11. package/dist/src/cluster/partition-detector.d.ts +59 -0
  12. package/dist/src/cluster/partition-detector.d.ts.map +1 -0
  13. package/dist/src/cluster/partition-detector.js +129 -0
  14. package/dist/src/cluster/partition-detector.js.map +1 -0
  15. package/dist/src/cluster/service.d.ts +49 -0
  16. package/dist/src/cluster/service.d.ts.map +1 -0
  17. package/dist/src/cluster/service.js +107 -0
  18. package/dist/src/cluster/service.js.map +1 -0
  19. package/dist/src/index.d.ts +29 -0
  20. package/dist/src/index.d.ts.map +1 -0
  21. package/dist/src/index.js +29 -0
  22. package/dist/src/index.js.map +1 -0
  23. package/dist/src/it-utility.d.ts +4 -0
  24. package/dist/src/it-utility.d.ts.map +1 -0
  25. package/dist/src/it-utility.js +32 -0
  26. package/dist/src/it-utility.js.map +1 -0
  27. package/dist/src/libp2p-key-network.d.ts +59 -0
  28. package/dist/src/libp2p-key-network.d.ts.map +1 -0
  29. package/dist/src/libp2p-key-network.js +278 -0
  30. package/dist/src/libp2p-key-network.js.map +1 -0
  31. package/dist/src/libp2p-node.d.ts +28 -0
  32. package/dist/src/libp2p-node.d.ts.map +1 -0
  33. package/dist/src/libp2p-node.js +270 -0
  34. package/dist/src/libp2p-node.js.map +1 -0
  35. package/dist/src/logger.d.ts +3 -0
  36. package/dist/src/logger.d.ts.map +1 -0
  37. package/dist/src/logger.js +6 -0
  38. package/dist/src/logger.js.map +1 -0
  39. package/dist/src/network/get-network-manager.d.ts +4 -0
  40. package/dist/src/network/get-network-manager.d.ts.map +1 -0
  41. package/dist/src/network/get-network-manager.js +17 -0
  42. package/dist/src/network/get-network-manager.js.map +1 -0
  43. package/dist/src/network/network-manager-service.d.ts +82 -0
  44. package/dist/src/network/network-manager-service.d.ts.map +1 -0
  45. package/dist/src/network/network-manager-service.js +283 -0
  46. package/dist/src/network/network-manager-service.js.map +1 -0
  47. package/dist/src/peer-utils.d.ts +2 -0
  48. package/dist/src/peer-utils.d.ts.map +1 -0
  49. package/dist/src/peer-utils.js +28 -0
  50. package/dist/src/peer-utils.js.map +1 -0
  51. package/dist/src/protocol-client.d.ts +12 -0
  52. package/dist/src/protocol-client.d.ts.map +1 -0
  53. package/dist/src/protocol-client.js +34 -0
  54. package/dist/src/protocol-client.js.map +1 -0
  55. package/dist/src/repo/client.d.ts +17 -0
  56. package/dist/src/repo/client.d.ts.map +1 -0
  57. package/dist/src/repo/client.js +82 -0
  58. package/dist/src/repo/client.js.map +1 -0
  59. package/dist/src/repo/cluster-coordinator.d.ts +59 -0
  60. package/dist/src/repo/cluster-coordinator.d.ts.map +1 -0
  61. package/dist/src/repo/cluster-coordinator.js +539 -0
  62. package/dist/src/repo/cluster-coordinator.js.map +1 -0
  63. package/dist/src/repo/coordinator-repo.d.ts +29 -0
  64. package/dist/src/repo/coordinator-repo.d.ts.map +1 -0
  65. package/dist/src/repo/coordinator-repo.js +102 -0
  66. package/dist/src/repo/coordinator-repo.js.map +1 -0
  67. package/dist/src/repo/redirect.d.ts +14 -0
  68. package/dist/src/repo/redirect.d.ts.map +1 -0
  69. package/dist/src/repo/redirect.js +9 -0
  70. package/dist/src/repo/redirect.js.map +1 -0
  71. package/dist/src/repo/service.d.ts +52 -0
  72. package/dist/src/repo/service.d.ts.map +1 -0
  73. package/dist/src/repo/service.js +181 -0
  74. package/dist/src/repo/service.js.map +1 -0
  75. package/dist/src/repo/types.d.ts +7 -0
  76. package/dist/src/repo/types.d.ts.map +1 -0
  77. package/dist/src/repo/types.js +2 -0
  78. package/dist/src/repo/types.js.map +1 -0
  79. package/dist/src/routing/libp2p-known-peers.d.ts +4 -0
  80. package/dist/src/routing/libp2p-known-peers.d.ts.map +1 -0
  81. package/dist/src/routing/libp2p-known-peers.js +19 -0
  82. package/dist/src/routing/libp2p-known-peers.js.map +1 -0
  83. package/dist/src/routing/responsibility.d.ts +14 -0
  84. package/dist/src/routing/responsibility.d.ts.map +1 -0
  85. package/dist/src/routing/responsibility.js +45 -0
  86. package/dist/src/routing/responsibility.js.map +1 -0
  87. package/dist/src/routing/simple-cluster-coordinator.d.ts +23 -0
  88. package/dist/src/routing/simple-cluster-coordinator.d.ts.map +1 -0
  89. package/dist/src/routing/simple-cluster-coordinator.js +59 -0
  90. package/dist/src/routing/simple-cluster-coordinator.js.map +1 -0
  91. package/dist/src/storage/arachnode-fret-adapter.d.ts +65 -0
  92. package/dist/src/storage/arachnode-fret-adapter.d.ts.map +1 -0
  93. package/dist/src/storage/arachnode-fret-adapter.js +93 -0
  94. package/dist/src/storage/arachnode-fret-adapter.js.map +1 -0
  95. package/dist/src/storage/block-storage.d.ts +31 -0
  96. package/dist/src/storage/block-storage.d.ts.map +1 -0
  97. package/dist/src/storage/block-storage.js +154 -0
  98. package/dist/src/storage/block-storage.js.map +1 -0
  99. package/dist/src/storage/file-storage.d.ts +30 -0
  100. package/dist/src/storage/file-storage.d.ts.map +1 -0
  101. package/dist/src/storage/file-storage.js +127 -0
  102. package/dist/src/storage/file-storage.js.map +1 -0
  103. package/dist/src/storage/helpers.d.ts +3 -0
  104. package/dist/src/storage/helpers.d.ts.map +1 -0
  105. package/dist/src/storage/helpers.js +28 -0
  106. package/dist/src/storage/helpers.js.map +1 -0
  107. package/dist/src/storage/i-block-storage.d.ts +32 -0
  108. package/dist/src/storage/i-block-storage.d.ts.map +1 -0
  109. package/dist/src/storage/i-block-storage.js +2 -0
  110. package/dist/src/storage/i-block-storage.js.map +1 -0
  111. package/dist/src/storage/i-raw-storage.d.ts +20 -0
  112. package/dist/src/storage/i-raw-storage.d.ts.map +1 -0
  113. package/dist/src/storage/i-raw-storage.js +2 -0
  114. package/dist/src/storage/i-raw-storage.js.map +1 -0
  115. package/dist/src/storage/memory-storage.d.ts +27 -0
  116. package/dist/src/storage/memory-storage.d.ts.map +1 -0
  117. package/dist/src/storage/memory-storage.js +87 -0
  118. package/dist/src/storage/memory-storage.js.map +1 -0
  119. package/dist/src/storage/restoration-coordinator-v2.d.ts +63 -0
  120. package/dist/src/storage/restoration-coordinator-v2.d.ts.map +1 -0
  121. package/dist/src/storage/restoration-coordinator-v2.js +157 -0
  122. package/dist/src/storage/restoration-coordinator-v2.js.map +1 -0
  123. package/dist/src/storage/ring-selector.d.ts +56 -0
  124. package/dist/src/storage/ring-selector.d.ts.map +1 -0
  125. package/dist/src/storage/ring-selector.js +118 -0
  126. package/dist/src/storage/ring-selector.js.map +1 -0
  127. package/dist/src/storage/storage-monitor.d.ts +23 -0
  128. package/dist/src/storage/storage-monitor.d.ts.map +1 -0
  129. package/dist/src/storage/storage-monitor.js +40 -0
  130. package/dist/src/storage/storage-monitor.js.map +1 -0
  131. package/dist/src/storage/storage-repo.d.ts +17 -0
  132. package/dist/src/storage/storage-repo.d.ts.map +1 -0
  133. package/dist/src/storage/storage-repo.js +267 -0
  134. package/dist/src/storage/storage-repo.js.map +1 -0
  135. package/dist/src/storage/struct.d.ts +29 -0
  136. package/dist/src/storage/struct.d.ts.map +1 -0
  137. package/dist/src/storage/struct.js +2 -0
  138. package/dist/src/storage/struct.js.map +1 -0
  139. package/dist/src/sync/client.d.ts +27 -0
  140. package/dist/src/sync/client.d.ts.map +1 -0
  141. package/dist/src/sync/client.js +32 -0
  142. package/dist/src/sync/client.js.map +1 -0
  143. package/dist/src/sync/protocol.d.ts +58 -0
  144. package/dist/src/sync/protocol.d.ts.map +1 -0
  145. package/dist/src/sync/protocol.js +12 -0
  146. package/dist/src/sync/protocol.js.map +1 -0
  147. package/dist/src/sync/service.d.ts +62 -0
  148. package/dist/src/sync/service.d.ts.map +1 -0
  149. package/dist/src/sync/service.js +168 -0
  150. package/dist/src/sync/service.js.map +1 -0
  151. package/package.json +73 -0
  152. package/readme.md +497 -0
  153. package/src/cluster/client.ts +63 -0
  154. package/src/cluster/cluster-repo.ts +711 -0
  155. package/src/cluster/partition-detector.ts +158 -0
  156. package/src/cluster/service.ts +156 -0
  157. package/src/index.ts +30 -0
  158. package/src/it-utility.ts +36 -0
  159. package/src/libp2p-key-network.ts +334 -0
  160. package/src/libp2p-node.ts +335 -0
  161. package/src/logger.ts +9 -0
  162. package/src/network/get-network-manager.ts +17 -0
  163. package/src/network/network-manager-service.ts +334 -0
  164. package/src/peer-utils.ts +24 -0
  165. package/src/protocol-client.ts +54 -0
  166. package/src/repo/client.ts +112 -0
  167. package/src/repo/cluster-coordinator.ts +592 -0
  168. package/src/repo/coordinator-repo.ts +137 -0
  169. package/src/repo/redirect.ts +17 -0
  170. package/src/repo/service.ts +219 -0
  171. package/src/repo/types.ts +7 -0
  172. package/src/routing/libp2p-known-peers.ts +26 -0
  173. package/src/routing/responsibility.ts +63 -0
  174. package/src/routing/simple-cluster-coordinator.ts +70 -0
  175. package/src/storage/arachnode-fret-adapter.ts +128 -0
  176. package/src/storage/block-storage.ts +182 -0
  177. package/src/storage/file-storage.ts +163 -0
  178. package/src/storage/helpers.ts +29 -0
  179. package/src/storage/i-block-storage.ts +40 -0
  180. package/src/storage/i-raw-storage.ts +30 -0
  181. package/src/storage/memory-storage.ts +108 -0
  182. package/src/storage/restoration-coordinator-v2.ts +191 -0
  183. package/src/storage/ring-selector.ts +155 -0
  184. package/src/storage/storage-monitor.ts +59 -0
  185. package/src/storage/storage-repo.ts +320 -0
  186. package/src/storage/struct.ts +34 -0
  187. package/src/sync/client.ts +42 -0
  188. package/src/sync/protocol.ts +71 -0
  189. package/src/sync/service.ts +229 -0
@@ -0,0 +1,59 @@
1
+ import { sha256 } from 'multiformats/hashes/sha2';
2
+ /**
3
+ * Simple consistent hashing for small clusters
4
+ * Uses modulo arithmetic instead of XOR distance
5
+ */
6
+ export class ModuloCoordinator {
7
+ async hashPeer(peerId) {
8
+ const mh = await sha256.digest(peerId.toMultihash().bytes);
9
+ // Take first 8 bytes as bigint
10
+ const view = new DataView(mh.digest.buffer, mh.digest.byteOffset, 8);
11
+ return view.getBigUint64(0, false);
12
+ }
13
+ async hashKey(key) {
14
+ const mh = await sha256.digest(key);
15
+ const view = new DataView(mh.digest.buffer, mh.digest.byteOffset, 8);
16
+ return view.getBigUint64(0, false);
17
+ }
18
+ async selectCoordinator(key, peers) {
19
+ if (peers.length === 0)
20
+ throw new Error('No peers available');
21
+ if (peers.length === 1)
22
+ return peers[0];
23
+ // Simple modulo selection - deterministic but not distance-based
24
+ const keyHash = await this.hashKey(key);
25
+ const index = Number(keyHash % BigInt(peers.length));
26
+ return peers[index];
27
+ }
28
+ async selectReplicas(key, peers, replicationFactor) {
29
+ if (peers.length <= replicationFactor)
30
+ return [...peers];
31
+ const coordinator = await this.selectCoordinator(key, peers);
32
+ const replicas = [coordinator];
33
+ const remaining = peers.filter(p => !p.equals(coordinator));
34
+ // Select additional replicas deterministically
35
+ for (let i = 1; i < replicationFactor && remaining.length > 0; i++) {
36
+ const subKey = new Uint8Array([...key, i]);
37
+ const replica = await this.selectCoordinator(subKey, remaining);
38
+ replicas.push(replica);
39
+ remaining.splice(remaining.findIndex(p => p.equals(replica)), 1);
40
+ }
41
+ return replicas;
42
+ }
43
+ }
44
+ /**
45
+ * For very small clusters, just replicate everywhere
46
+ */
47
+ export class FullReplicationCoordinator {
48
+ async selectCoordinator(key, peers) {
49
+ // Always select first peer as primary
50
+ if (peers.length === 0)
51
+ throw new Error('No peers available');
52
+ return peers[0];
53
+ }
54
+ async selectReplicas(key, peers, replicationFactor) {
55
+ // Replicate to all peers in small clusters
56
+ return [...peers];
57
+ }
58
+ }
59
+ //# sourceMappingURL=simple-cluster-coordinator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simple-cluster-coordinator.js","sourceRoot":"","sources":["../../../src/routing/simple-cluster-coordinator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ import type { FretService } from 'p2p-fret';
2
+ /**
3
+ * Arachnode ring membership information.
4
+ * Stored in FRET's generic metadata field.
5
+ */
6
+ export interface ArachnodeInfo {
7
+ /** Ring depth: 0 = full keyspace, N = 2^N partitions */
8
+ ringDepth: number;
9
+ /** Partition this node covers (undefined if ringDepth = 0) */
10
+ partition?: {
11
+ prefixBits: number;
12
+ prefixValue: number;
13
+ };
14
+ /** Storage capacity in bytes */
15
+ capacity: {
16
+ total: number;
17
+ used: number;
18
+ available: number;
19
+ };
20
+ /** Ring membership status */
21
+ status: 'joining' | 'active' | 'moving' | 'leaving';
22
+ }
23
+ /**
24
+ * Adapter that provides Arachnode-specific methods on top of FRET's generic metadata.
25
+ *
26
+ * FRET remains a pure DHT, while this adapter layers Arachnode semantics.
27
+ */
28
+ export declare class ArachnodeFretAdapter {
29
+ private readonly fret;
30
+ private static readonly ARACHNODE_KEY;
31
+ constructor(fret: FretService);
32
+ /**
33
+ * Set this node's Arachnode ring membership.
34
+ */
35
+ setArachnodeInfo(info: ArachnodeInfo): void;
36
+ /**
37
+ * Get Arachnode info for a specific peer.
38
+ */
39
+ getArachnodeInfo(peerId: string): ArachnodeInfo | undefined;
40
+ /**
41
+ * Get my own Arachnode info.
42
+ */
43
+ getMyArachnodeInfo(): ArachnodeInfo | undefined;
44
+ /**
45
+ * Find all peers at a specific ring depth.
46
+ */
47
+ findPeersAtRing(ringDepth: number): string[];
48
+ /**
49
+ * Find all known storage rings (unique ring depths).
50
+ */
51
+ getKnownRings(): number[];
52
+ /**
53
+ * Get statistics about discovered rings.
54
+ */
55
+ getRingStats(): Array<{
56
+ ringDepth: number;
57
+ peerCount: number;
58
+ avgCapacity: number;
59
+ }>;
60
+ /**
61
+ * Access the underlying FRET service.
62
+ */
63
+ getFret(): FretService;
64
+ }
65
+ //# sourceMappingURL=arachnode-fret-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arachnode-fret-adapter.d.ts","sourceRoot":"","sources":["../../../src/storage/arachnode-fret-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC7B,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;IAElB,8DAA8D;IAC9D,SAAS,CAAC,EAAE;QACX,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;KACpB,CAAC;IAEF,gCAAgC;IAChC,QAAQ,EAAE;QACT,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;KAClB,CAAC;IAEF,6BAA6B;IAC7B,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;CACpD;AAED;;;;GAIG;AACH,qBAAa,oBAAoB;IAGpB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFjC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAe;gBAEvB,IAAI,EAAE,WAAW;IAE9C;;OAEG;IACH,gBAAgB,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI;IAM3C;;OAEG;IACH,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAK3D;;OAEG;IACH,kBAAkB,IAAI,aAAa,GAAG,SAAS;IAM/C;;OAEG;IACH,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE;IAU5C;;OAEG;IACH,aAAa,IAAI,MAAM,EAAE;IAczB;;OAEG;IACH,YAAY,IAAI,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAwBpF;;OAEG;IACH,OAAO,IAAI,WAAW;CAGtB"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Adapter that provides Arachnode-specific methods on top of FRET's generic metadata.
3
+ *
4
+ * FRET remains a pure DHT, while this adapter layers Arachnode semantics.
5
+ */
6
+ export class ArachnodeFretAdapter {
7
+ fret;
8
+ static ARACHNODE_KEY = 'arachnode';
9
+ constructor(fret) {
10
+ this.fret = fret;
11
+ }
12
+ /**
13
+ * Set this node's Arachnode ring membership.
14
+ */
15
+ setArachnodeInfo(info) {
16
+ this.fret.setMetadata({
17
+ [ArachnodeFretAdapter.ARACHNODE_KEY]: info
18
+ });
19
+ }
20
+ /**
21
+ * Get Arachnode info for a specific peer.
22
+ */
23
+ getArachnodeInfo(peerId) {
24
+ const metadata = this.fret.getMetadata(peerId);
25
+ return metadata?.[ArachnodeFretAdapter.ARACHNODE_KEY];
26
+ }
27
+ /**
28
+ * Get my own Arachnode info.
29
+ */
30
+ getMyArachnodeInfo() {
31
+ const myPeerId = this.fret.node?.peerId?.toString();
32
+ if (!myPeerId)
33
+ return undefined;
34
+ return this.getArachnodeInfo(myPeerId);
35
+ }
36
+ /**
37
+ * Find all peers at a specific ring depth.
38
+ */
39
+ findPeersAtRing(ringDepth) {
40
+ const peers = this.fret.listPeers();
41
+ return peers
42
+ .filter(peer => {
43
+ const arachnode = peer.metadata?.[ArachnodeFretAdapter.ARACHNODE_KEY];
44
+ return arachnode?.ringDepth === ringDepth;
45
+ })
46
+ .map(peer => peer.id);
47
+ }
48
+ /**
49
+ * Find all known storage rings (unique ring depths).
50
+ */
51
+ getKnownRings() {
52
+ const peers = this.fret.listPeers();
53
+ const rings = new Set();
54
+ for (const peer of peers) {
55
+ const arachnode = peer.metadata?.[ArachnodeFretAdapter.ARACHNODE_KEY];
56
+ if (arachnode?.ringDepth !== undefined) {
57
+ rings.add(arachnode.ringDepth);
58
+ }
59
+ }
60
+ return Array.from(rings).sort((a, b) => a - b);
61
+ }
62
+ /**
63
+ * Get statistics about discovered rings.
64
+ */
65
+ getRingStats() {
66
+ const peers = this.fret.listPeers();
67
+ const ringMap = new Map();
68
+ for (const peer of peers) {
69
+ const arachnode = peer.metadata?.[ArachnodeFretAdapter.ARACHNODE_KEY];
70
+ if (arachnode) {
71
+ const existing = ringMap.get(arachnode.ringDepth) ?? { count: 0, totalCapacity: 0 };
72
+ ringMap.set(arachnode.ringDepth, {
73
+ count: existing.count + 1,
74
+ totalCapacity: existing.totalCapacity + arachnode.capacity.available
75
+ });
76
+ }
77
+ }
78
+ return Array.from(ringMap.entries())
79
+ .map(([ringDepth, stats]) => ({
80
+ ringDepth,
81
+ peerCount: stats.count,
82
+ avgCapacity: stats.totalCapacity / stats.count
83
+ }))
84
+ .sort((a, b) => a.ringDepth - b.ringDepth);
85
+ }
86
+ /**
87
+ * Access the underlying FRET service.
88
+ */
89
+ getFret() {
90
+ return this.fret;
91
+ }
92
+ }
93
+ //# sourceMappingURL=arachnode-fret-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arachnode-fret-adapter.js","sourceRoot":"","sources":["../../../src/storage/arachnode-fret-adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import type { BlockId, IBlock, Transform, ActionId, ActionRev } from "@optimystic/db-core";
2
+ import type { RestoreCallback } from "./struct.js";
3
+ import type { IRawStorage } from "./i-raw-storage.js";
4
+ import type { IBlockStorage } from "./i-block-storage.js";
5
+ export declare class BlockStorage implements IBlockStorage {
6
+ private readonly blockId;
7
+ private readonly storage;
8
+ private readonly restoreCallback?;
9
+ constructor(blockId: BlockId, storage: IRawStorage, restoreCallback?: RestoreCallback | undefined);
10
+ getLatest(): Promise<ActionRev | undefined>;
11
+ getBlock(rev?: number): Promise<{
12
+ block: IBlock;
13
+ actionRev: ActionRev;
14
+ } | undefined>;
15
+ getTransaction(actionId: ActionId): Promise<Transform | undefined>;
16
+ getPendingTransaction(actionId: ActionId): Promise<Transform | undefined>;
17
+ listPendingTransactions(): AsyncIterable<ActionId>;
18
+ savePendingTransaction(actionId: ActionId, transform: Transform): Promise<void>;
19
+ deletePendingTransaction(actionId: ActionId): Promise<void>;
20
+ listRevisions(startRev: number, endRev: number): AsyncIterable<ActionRev>;
21
+ saveMaterializedBlock(actionId: ActionId, block: IBlock | undefined): Promise<void>;
22
+ saveRevision(rev: number, actionId: ActionId): Promise<void>;
23
+ promotePendingTransaction(actionId: ActionId): Promise<void>;
24
+ setLatest(latest: ActionRev): Promise<void>;
25
+ private ensureRevision;
26
+ private materializeBlock;
27
+ private restoreBlock;
28
+ private saveRestored;
29
+ private inRanges;
30
+ }
31
+ //# sourceMappingURL=block-storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"block-storage.d.ts","sourceRoot":"","sources":["../../../src/storage/block-storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAE3F,OAAO,KAAK,EAA+B,eAAe,EAAiB,MAAM,aAAa,CAAC;AAC/F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,qBAAa,YAAa,YAAW,aAAa;IAEhD,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC;gBAFhB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,WAAW,EACpB,eAAe,CAAC,EAAE,eAAe,YAAA;IAG7C,SAAS,IAAI,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAK3C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,SAAS,CAAA;KAAE,GAAG,SAAS,CAAC;IAepF,cAAc,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAIlE,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAIxE,uBAAuB,IAAI,aAAa,CAAC,QAAQ,CAAC;IAInD,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAS/E,wBAAwB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAI1D,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,CAAC,SAAS,CAAC;IAI1E,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAInF,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5D,yBAAyB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5D,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;YASnC,cAAc;YA+Bd,gBAAgB;YA0ChB,YAAY;YAKZ,YAAY;IAc1B,OAAO,CAAC,QAAQ;CAKhB"}
@@ -0,0 +1,154 @@
1
+ import { Latches, applyTransform } from "@optimystic/db-core";
2
+ import { mergeRanges } from "./helpers.js";
3
+ export class BlockStorage {
4
+ blockId;
5
+ storage;
6
+ restoreCallback;
7
+ constructor(blockId, storage, restoreCallback) {
8
+ this.blockId = blockId;
9
+ this.storage = storage;
10
+ this.restoreCallback = restoreCallback;
11
+ }
12
+ async getLatest() {
13
+ const meta = await this.storage.getMetadata(this.blockId);
14
+ return meta?.latest;
15
+ }
16
+ async getBlock(rev) {
17
+ const meta = await this.storage.getMetadata(this.blockId);
18
+ if (!meta) {
19
+ return undefined;
20
+ }
21
+ const targetRev = rev ?? meta.latest?.rev;
22
+ if (targetRev === undefined) {
23
+ throw new Error(`No revision specified and no latest revision exists for block ${this.blockId}`);
24
+ }
25
+ await this.ensureRevision(meta, targetRev);
26
+ return await this.materializeBlock(meta, targetRev);
27
+ }
28
+ async getTransaction(actionId) {
29
+ return await this.storage.getTransaction(this.blockId, actionId);
30
+ }
31
+ async getPendingTransaction(actionId) {
32
+ return await this.storage.getPendingTransaction(this.blockId, actionId);
33
+ }
34
+ async *listPendingTransactions() {
35
+ yield* this.storage.listPendingTransactions(this.blockId);
36
+ }
37
+ async savePendingTransaction(actionId, transform) {
38
+ let meta = await this.storage.getMetadata(this.blockId);
39
+ if (!meta) {
40
+ meta = { latest: undefined, ranges: [[0]] };
41
+ await this.storage.saveMetadata(this.blockId, meta);
42
+ }
43
+ await this.storage.savePendingTransaction(this.blockId, actionId, transform);
44
+ }
45
+ async deletePendingTransaction(actionId) {
46
+ await this.storage.deletePendingTransaction(this.blockId, actionId);
47
+ }
48
+ async *listRevisions(startRev, endRev) {
49
+ yield* this.storage.listRevisions(this.blockId, startRev, endRev);
50
+ }
51
+ async saveMaterializedBlock(actionId, block) {
52
+ await this.storage.saveMaterializedBlock(this.blockId, actionId, block);
53
+ }
54
+ async saveRevision(rev, actionId) {
55
+ await this.storage.saveRevision(this.blockId, rev, actionId);
56
+ }
57
+ async promotePendingTransaction(actionId) {
58
+ await this.storage.promotePendingTransaction(this.blockId, actionId);
59
+ }
60
+ async setLatest(latest) {
61
+ const meta = await this.storage.getMetadata(this.blockId);
62
+ if (!meta) {
63
+ throw new Error(`Block ${this.blockId} not found`);
64
+ }
65
+ meta.latest = latest;
66
+ await this.storage.saveMetadata(this.blockId, meta);
67
+ }
68
+ async ensureRevision(meta, rev) {
69
+ if (this.inRanges(rev, meta.ranges)) {
70
+ return;
71
+ }
72
+ const lockId = `BlockStorage.ensureRevision:${this.blockId}`;
73
+ const release = await Latches.acquire(lockId);
74
+ try {
75
+ const currentMeta = await this.storage.getMetadata(this.blockId);
76
+ if (!currentMeta) {
77
+ throw new Error(`Block ${this.blockId} metadata disappeared unexpectedly.`);
78
+ }
79
+ if (this.inRanges(rev, currentMeta.ranges)) {
80
+ return;
81
+ }
82
+ const restored = await this.restoreBlock(rev);
83
+ if (!restored) {
84
+ throw new Error(`Block ${this.blockId} revision ${rev} not found during restore attempt.`);
85
+ }
86
+ await this.saveRestored(restored);
87
+ currentMeta.ranges.unshift(restored.range);
88
+ currentMeta.ranges = mergeRanges(currentMeta.ranges);
89
+ await this.storage.saveMetadata(this.blockId, currentMeta);
90
+ }
91
+ finally {
92
+ release();
93
+ }
94
+ }
95
+ async materializeBlock(_meta, targetRev) {
96
+ let block;
97
+ let materializedActionRev;
98
+ const actions = [];
99
+ // Find the materialized block
100
+ for await (const actionRev of this.storage.listRevisions(this.blockId, targetRev, 1)) {
101
+ const materializedBlock = await this.storage.getMaterializedBlock(this.blockId, actionRev.actionId);
102
+ if (materializedBlock) {
103
+ block = materializedBlock;
104
+ materializedActionRev = actionRev;
105
+ break;
106
+ }
107
+ else {
108
+ actions.push(actionRev);
109
+ }
110
+ }
111
+ if (!block || !materializedActionRev) {
112
+ // There is an implicit requirement that there must be a materialization of the block somewhere in it's history. If the log is truncated, a materialization must be made at the truncation point..
113
+ throw new Error(`Failed to find materialized block ${this.blockId} for revision ${targetRev}`);
114
+ }
115
+ // Apply transforms in reverse order
116
+ for (let i = actions.length - 1; i >= 0; --i) {
117
+ const { actionId } = actions[i];
118
+ const transform = await this.storage.getTransaction(this.blockId, actionId);
119
+ if (!transform) {
120
+ throw new Error(`Missing action ${actionId} for block ${this.blockId}`);
121
+ }
122
+ block = applyTransform(block, transform);
123
+ }
124
+ if (!block) {
125
+ throw new Error(`Block ${this.blockId} has been deleted`);
126
+ }
127
+ if (actions.length) {
128
+ await this.storage.saveMaterializedBlock(this.blockId, actions[0].actionId, block);
129
+ return { block, actionRev: actions[0] };
130
+ }
131
+ return { block, actionRev: materializedActionRev };
132
+ }
133
+ async restoreBlock(rev) {
134
+ if (!this.restoreCallback)
135
+ return undefined;
136
+ return await this.restoreCallback(this.blockId, rev);
137
+ }
138
+ async saveRestored(archive) {
139
+ const revisions = Object.entries(archive.revisions)
140
+ .map(([rev, data]) => ({ rev: Number(rev), data }));
141
+ // Save all revisions, actions, and materializations
142
+ for (const { rev, data: { action, block } } of revisions) {
143
+ await Promise.all([
144
+ this.storage.saveRevision(this.blockId, rev, action.actionId),
145
+ this.storage.saveTransaction(this.blockId, action.actionId, action.transform),
146
+ block ? this.storage.saveMaterializedBlock(this.blockId, action.actionId, block) : Promise.resolve()
147
+ ]);
148
+ }
149
+ }
150
+ inRanges(rev, ranges) {
151
+ return ranges.some(range => rev >= range[0] && (range[1] === undefined || rev < range[1]));
152
+ }
153
+ }
154
+ //# sourceMappingURL=block-storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"block-storage.js","sourceRoot":"","sources":["../../../src/storage/block-storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { BlockId, IBlock, Transform, ActionId, ActionRev } from "@optimystic/db-core";
2
+ import type { BlockMetadata } from "./struct.js";
3
+ import type { IRawStorage } from "./i-raw-storage.js";
4
+ export declare class FileRawStorage implements IRawStorage {
5
+ private readonly basePath;
6
+ constructor(basePath: string);
7
+ getMetadata(blockId: BlockId): Promise<BlockMetadata | undefined>;
8
+ saveMetadata(blockId: BlockId, metadata: BlockMetadata): Promise<void>;
9
+ getRevision(blockId: BlockId, rev: number): Promise<ActionId | undefined>;
10
+ saveRevision(blockId: BlockId, rev: number, actionId: ActionId): Promise<void>;
11
+ getPendingTransaction(blockId: BlockId, actionId: ActionId): Promise<Transform | undefined>;
12
+ savePendingTransaction(blockId: BlockId, actionId: ActionId, transform: Transform): Promise<void>;
13
+ deletePendingTransaction(blockId: BlockId, actionId: ActionId): Promise<void>;
14
+ listPendingTransactions(blockId: BlockId): AsyncIterable<ActionId>;
15
+ getTransaction(blockId: BlockId, actionId: ActionId): Promise<Transform | undefined>;
16
+ listRevisions(blockId: BlockId, startRev: number, endRev: number): AsyncIterable<ActionRev>;
17
+ saveTransaction(blockId: BlockId, actionId: ActionId, transform: Transform): Promise<void>;
18
+ getMaterializedBlock(blockId: BlockId, actionId: ActionId): Promise<IBlock | undefined>;
19
+ saveMaterializedBlock(blockId: BlockId, actionId: ActionId, block?: IBlock): Promise<void>;
20
+ promotePendingTransaction(blockId: BlockId, actionId: ActionId): Promise<void>;
21
+ private getBlockPath;
22
+ private getMetadataPath;
23
+ private getRevisionPath;
24
+ private getPendingActionPath;
25
+ private getActionPath;
26
+ private getMaterializedPath;
27
+ private readIfExists;
28
+ private ensureAndWriteFile;
29
+ }
30
+ //# sourceMappingURL=file-storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-storage.d.ts","sourceRoot":"","sources":["../../../src/storage/file-storage.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC3F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAKtD,qBAAa,cAAe,YAAW,WAAW;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,MAAM;IAIvC,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC;IAIjE,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAOtE,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;IAIzE,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAO9E,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAI3F,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAOjG,wBAAwB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAS5E,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC;IAYnE,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAInF,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,CAAC,SAAS,CAAC;IAU5F,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAO1F,oBAAoB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAIvF,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAe1F,yBAAyB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBpF,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,mBAAmB;YAIb,YAAY;YASZ,kBAAkB;CAIhC"}
@@ -0,0 +1,127 @@
1
+ import { promises as fs } from 'fs';
2
+ import * as path from 'path';
3
+ import { createLogger } from '../logger.js';
4
+ const log = createLogger('storage:file');
5
+ export class FileRawStorage {
6
+ basePath;
7
+ constructor(basePath) {
8
+ this.basePath = basePath;
9
+ // TODO: use https://www.npmjs.com/package/proper-lockfile to take a lock on the basePath, also introduce explicit dispose pattern
10
+ }
11
+ async getMetadata(blockId) {
12
+ return this.readIfExists(this.getMetadataPath(blockId));
13
+ }
14
+ async saveMetadata(blockId, metadata) {
15
+ await this.ensureAndWriteFile(this.getMetadataPath(blockId), JSON.stringify(metadata));
16
+ }
17
+ async getRevision(blockId, rev) {
18
+ return this.readIfExists(this.getRevisionPath(blockId, rev));
19
+ }
20
+ async saveRevision(blockId, rev, actionId) {
21
+ await this.ensureAndWriteFile(this.getRevisionPath(blockId, rev), actionId);
22
+ }
23
+ async getPendingTransaction(blockId, actionId) {
24
+ return this.readIfExists(this.getPendingActionPath(blockId, actionId));
25
+ }
26
+ async savePendingTransaction(blockId, actionId, transform) {
27
+ await this.ensureAndWriteFile(this.getPendingActionPath(blockId, actionId), JSON.stringify(transform));
28
+ }
29
+ async deletePendingTransaction(blockId, actionId) {
30
+ const pendingPath = this.getPendingActionPath(blockId, actionId);
31
+ await fs.unlink(pendingPath)
32
+ .catch((err) => {
33
+ // Ignore if file doesn't exist
34
+ if (err?.code !== 'ENOENT')
35
+ log('deletePendingTransaction unlink failed for %s/%s - %o', blockId, actionId, err);
36
+ });
37
+ }
38
+ async *listPendingTransactions(blockId) {
39
+ const pendingPath = path.join(this.getBlockPath(blockId), 'pend');
40
+ const files = await fs.readdir(pendingPath).catch((err) => { log('listPendingTransactions readdir failed for %s - %o', blockId, err); return []; });
41
+ for (const file of files) {
42
+ if (!file.endsWith('.json'))
43
+ continue;
44
+ const rawActionId = file.slice(0, -5);
45
+ if (!/^[\w\d]+-[\w\d]+-[\w\d]+-[\w\d]+-[\w\d]+$/.test(rawActionId))
46
+ continue;
47
+ yield rawActionId;
48
+ }
49
+ }
50
+ async getTransaction(blockId, actionId) {
51
+ return this.readIfExists(this.getActionPath(blockId, actionId));
52
+ }
53
+ async *listRevisions(blockId, startRev, endRev) {
54
+ // TODO: Optimize this for sparse revs
55
+ for (let rev = startRev; startRev <= endRev ? rev <= endRev : rev >= endRev; startRev <= endRev ? ++rev : --rev) {
56
+ const actionId = await this.getRevision(blockId, rev);
57
+ if (actionId) {
58
+ yield { actionId, rev };
59
+ }
60
+ }
61
+ }
62
+ async saveTransaction(blockId, actionId, transform) {
63
+ await this.ensureAndWriteFile(this.getActionPath(blockId, actionId), JSON.stringify(transform));
64
+ }
65
+ async getMaterializedBlock(blockId, actionId) {
66
+ return this.readIfExists(this.getMaterializedPath(blockId, actionId));
67
+ }
68
+ async saveMaterializedBlock(blockId, actionId, block) {
69
+ if (block) {
70
+ await this.ensureAndWriteFile(this.getMaterializedPath(blockId, actionId), JSON.stringify(block));
71
+ }
72
+ else {
73
+ await fs.unlink(this.getMaterializedPath(blockId, actionId))
74
+ .catch((err) => {
75
+ // Ignore if file doesn't exist
76
+ if (err?.code !== 'ENOENT')
77
+ log('saveMaterializedBlock unlink failed for %s/%s - %o', blockId, actionId, err);
78
+ });
79
+ }
80
+ }
81
+ async promotePendingTransaction(blockId, actionId) {
82
+ const pendingPath = this.getPendingActionPath(blockId, actionId);
83
+ const actionPath = this.getActionPath(blockId, actionId);
84
+ // Ensure target directory exists
85
+ await fs.mkdir(path.dirname(actionPath), { recursive: true });
86
+ return fs.rename(pendingPath, actionPath)
87
+ .catch(err => {
88
+ if (err.code === 'ENOENT') {
89
+ throw new Error(`Pending action ${actionId} not found for block ${blockId}`);
90
+ }
91
+ log('promotePendingTransaction rename failed for %s/%s - %o', blockId, actionId, err);
92
+ throw err;
93
+ });
94
+ }
95
+ getBlockPath(blockId) {
96
+ return path.join(this.basePath, blockId);
97
+ }
98
+ getMetadataPath(blockId) {
99
+ return path.join(this.getBlockPath(blockId), 'meta.json');
100
+ }
101
+ getRevisionPath(blockId, rev) {
102
+ return path.join(this.getBlockPath(blockId), 'revs', `${rev}.json`);
103
+ }
104
+ getPendingActionPath(blockId, actionId) {
105
+ return path.join(this.getBlockPath(blockId), 'pend', `${actionId}.json`);
106
+ }
107
+ getActionPath(blockId, actionId) {
108
+ return path.join(this.getBlockPath(blockId), 'actions', `${actionId}.json`);
109
+ }
110
+ getMaterializedPath(blockId, actionId) {
111
+ return path.join(this.getBlockPath(blockId), 'blocks', `${actionId}.json`);
112
+ }
113
+ async readIfExists(filePath) {
114
+ return fs.readFile(filePath, 'utf-8')
115
+ .then(content => JSON.parse(content))
116
+ .catch(err => {
117
+ if (err.code === 'ENOENT')
118
+ return undefined;
119
+ throw err;
120
+ });
121
+ }
122
+ async ensureAndWriteFile(filePath, content) {
123
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
124
+ await fs.writeFile(filePath, content);
125
+ }
126
+ }
127
+ //# sourceMappingURL=file-storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-storage.js","sourceRoot":"","sources":["../../../src/storage/file-storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { RevisionRange } from "./struct.js";
2
+ export declare function mergeRanges(ranges: RevisionRange[]): RevisionRange[];
3
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/storage/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,wBAAgB,WAAW,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,aAAa,EAAE,CA0BpE"}
@@ -0,0 +1,28 @@
1
+ export function mergeRanges(ranges) {
2
+ if (ranges.length <= 1)
3
+ return ranges;
4
+ ranges.sort((a, b) => a[0] - b[0]);
5
+ const merged = [ranges[0]];
6
+ for (const range of ranges.slice(1)) {
7
+ const last = merged[merged.length - 1];
8
+ // If last range is open-ended, it consumes all following ranges
9
+ if (last[1] === undefined) {
10
+ continue;
11
+ }
12
+ // If this range starts at or before last range's end (exclusive)
13
+ if (range[0] <= last[1]) {
14
+ // If this range is open-ended, make last range open-ended
15
+ if (range[1] === undefined) {
16
+ last[1] = undefined;
17
+ }
18
+ else {
19
+ last[1] = Math.max(last[1], range[1]);
20
+ }
21
+ }
22
+ else {
23
+ merged.push(range);
24
+ }
25
+ }
26
+ return merged;
27
+ }
28
+ //# sourceMappingURL=helpers.js.map