@dignetwork/dig-sdk 0.0.1-alpha.99 → 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 (162) hide show
  1. package/LICENSE +21 -7
  2. package/README.md +412 -0
  3. package/dist/adapters.cjs +356 -0
  4. package/dist/adapters.cjs.map +1 -0
  5. package/dist/adapters.d.cts +20 -0
  6. package/dist/adapters.d.ts +20 -0
  7. package/dist/adapters.js +347 -0
  8. package/dist/adapters.js.map +1 -0
  9. package/dist/dev-shim-DfKRA1ok.d.cts +128 -0
  10. package/dist/dev-shim-DfKRA1ok.d.ts +128 -0
  11. package/dist/dig-client-entry-ChYxUvBn.d.cts +372 -0
  12. package/dist/dig-client-entry-ChYxUvBn.d.ts +372 -0
  13. package/dist/dig-client.cjs +443 -0
  14. package/dist/dig-client.cjs.map +1 -0
  15. package/dist/dig-client.d.cts +1 -0
  16. package/dist/dig-client.d.ts +1 -0
  17. package/dist/dig-client.js +432 -0
  18. package/dist/dig-client.js.map +1 -0
  19. package/dist/index.cjs +1186 -0
  20. package/dist/index.cjs.map +1 -0
  21. package/dist/index.d.cts +502 -0
  22. package/dist/index.d.ts +502 -5
  23. package/dist/index.js +1156 -19
  24. package/dist/index.js.map +1 -0
  25. package/dist/next.cjs +369 -0
  26. package/dist/next.cjs.map +1 -0
  27. package/dist/next.d.cts +23 -0
  28. package/dist/next.d.ts +23 -0
  29. package/dist/next.js +362 -0
  30. package/dist/next.js.map +1 -0
  31. package/dist/spend.cjs +14 -0
  32. package/dist/spend.cjs.map +1 -0
  33. package/dist/spend.d.cts +1 -0
  34. package/dist/spend.d.ts +1 -0
  35. package/dist/spend.js +3 -0
  36. package/dist/spend.js.map +1 -0
  37. package/dist/vite.cjs +381 -0
  38. package/dist/vite.cjs.map +1 -0
  39. package/dist/vite.d.cts +35 -0
  40. package/dist/vite.d.ts +35 -0
  41. package/dist/vite.js +375 -0
  42. package/dist/vite.js.map +1 -0
  43. package/package.json +87 -59
  44. package/vendor/PROVENANCE.md +102 -0
  45. package/vendor/dig_client.d.ts +150 -0
  46. package/vendor/dig_client.mjs +805 -0
  47. package/vendor/dig_client_bg.wasm +0 -0
  48. package/dist/DataIntegrityTree/DataIntegrityTree.d.ts +0 -163
  49. package/dist/DataIntegrityTree/DataIntegrityTree.d.ts.map +0 -1
  50. package/dist/DataIntegrityTree/DataIntegrityTree.js +0 -707
  51. package/dist/DataIntegrityTree/DataLayerError.d.ts +0 -6
  52. package/dist/DataIntegrityTree/DataLayerError.d.ts.map +0 -1
  53. package/dist/DataIntegrityTree/DataLayerError.js +0 -17
  54. package/dist/DataIntegrityTree/index.d.ts +0 -2
  55. package/dist/DataIntegrityTree/index.d.ts.map +0 -1
  56. package/dist/DataIntegrityTree/index.js +0 -17
  57. package/dist/DigNetwork/ContentServer.d.ts +0 -31
  58. package/dist/DigNetwork/ContentServer.d.ts.map +0 -1
  59. package/dist/DigNetwork/ContentServer.js +0 -176
  60. package/dist/DigNetwork/DigChallenge.d.ts +0 -82
  61. package/dist/DigNetwork/DigChallenge.d.ts.map +0 -1
  62. package/dist/DigNetwork/DigChallenge.js +0 -144
  63. package/dist/DigNetwork/DigNetwork.d.ts +0 -14
  64. package/dist/DigNetwork/DigNetwork.d.ts.map +0 -1
  65. package/dist/DigNetwork/DigNetwork.js +0 -169
  66. package/dist/DigNetwork/DigPeer.d.ts +0 -24
  67. package/dist/DigNetwork/DigPeer.d.ts.map +0 -1
  68. package/dist/DigNetwork/DigPeer.js +0 -118
  69. package/dist/DigNetwork/IncentiveServer.d.ts +0 -13
  70. package/dist/DigNetwork/IncentiveServer.d.ts.map +0 -1
  71. package/dist/DigNetwork/IncentiveServer.js +0 -76
  72. package/dist/DigNetwork/PropagationServer.d.ts +0 -81
  73. package/dist/DigNetwork/PropagationServer.d.ts.map +0 -1
  74. package/dist/DigNetwork/PropagationServer.js +0 -563
  75. package/dist/DigNetwork/index.d.ts +0 -4
  76. package/dist/DigNetwork/index.d.ts.map +0 -1
  77. package/dist/DigNetwork/index.js +0 -19
  78. package/dist/blockchain/DataStore.d.ts +0 -67
  79. package/dist/blockchain/DataStore.d.ts.map +0 -1
  80. package/dist/blockchain/DataStore.js +0 -413
  81. package/dist/blockchain/DataStoreSerializer.d.ts +0 -52
  82. package/dist/blockchain/DataStoreSerializer.d.ts.map +0 -1
  83. package/dist/blockchain/DataStoreSerializer.js +0 -109
  84. package/dist/blockchain/FullNodePeer.d.ts +0 -31
  85. package/dist/blockchain/FullNodePeer.d.ts.map +0 -1
  86. package/dist/blockchain/FullNodePeer.js +0 -295
  87. package/dist/blockchain/ServerCoin.d.ts +0 -29
  88. package/dist/blockchain/ServerCoin.d.ts.map +0 -1
  89. package/dist/blockchain/ServerCoin.js +0 -324
  90. package/dist/blockchain/Wallet.d.ts +0 -28
  91. package/dist/blockchain/Wallet.d.ts.map +0 -1
  92. package/dist/blockchain/Wallet.js +0 -253
  93. package/dist/blockchain/coins.d.ts +0 -6
  94. package/dist/blockchain/coins.d.ts.map +0 -1
  95. package/dist/blockchain/coins.js +0 -102
  96. package/dist/blockchain/index.d.ts +0 -8
  97. package/dist/blockchain/index.d.ts.map +0 -1
  98. package/dist/blockchain/index.js +0 -36
  99. package/dist/index.d.ts.map +0 -1
  100. package/dist/prompts.d.ts +0 -21
  101. package/dist/prompts.d.ts.map +0 -1
  102. package/dist/prompts.js +0 -149
  103. package/dist/types.d.ts +0 -64
  104. package/dist/types.d.ts.map +0 -1
  105. package/dist/types.js +0 -2
  106. package/dist/utils/ContentScanner.d.ts +0 -63
  107. package/dist/utils/ContentScanner.d.ts.map +0 -1
  108. package/dist/utils/ContentScanner.js +0 -175
  109. package/dist/utils/Environment.d.ts +0 -18
  110. package/dist/utils/Environment.d.ts.map +0 -1
  111. package/dist/utils/Environment.js +0 -85
  112. package/dist/utils/FileCache.d.ts +0 -11
  113. package/dist/utils/FileCache.d.ts.map +0 -1
  114. package/dist/utils/FileCache.js +0 -58
  115. package/dist/utils/FileTransfer.d.ts +0 -47
  116. package/dist/utils/FileTransfer.d.ts.map +0 -1
  117. package/dist/utils/FileTransfer.js +0 -209
  118. package/dist/utils/NconfManager.d.ts +0 -11
  119. package/dist/utils/NconfManager.d.ts.map +0 -1
  120. package/dist/utils/NconfManager.js +0 -56
  121. package/dist/utils/StoreArchiveManager.d.ts +0 -45
  122. package/dist/utils/StoreArchiveManager.d.ts.map +0 -1
  123. package/dist/utils/StoreArchiveManager.js +0 -153
  124. package/dist/utils/asyncPool.d.ts +0 -9
  125. package/dist/utils/asyncPool.d.ts.map +0 -1
  126. package/dist/utils/asyncPool.js +0 -23
  127. package/dist/utils/config.d.ts +0 -68
  128. package/dist/utils/config.d.ts.map +0 -1
  129. package/dist/utils/config.js +0 -223
  130. package/dist/utils/connectionUtils.d.ts +0 -10
  131. package/dist/utils/connectionUtils.d.ts.map +0 -1
  132. package/dist/utils/connectionUtils.js +0 -18
  133. package/dist/utils/credentialsUtils.d.ts +0 -8
  134. package/dist/utils/credentialsUtils.d.ts.map +0 -1
  135. package/dist/utils/credentialsUtils.js +0 -122
  136. package/dist/utils/directoryUtils.d.ts +0 -9
  137. package/dist/utils/directoryUtils.d.ts.map +0 -1
  138. package/dist/utils/directoryUtils.js +0 -110
  139. package/dist/utils/encryption.d.ts +0 -8
  140. package/dist/utils/encryption.d.ts.map +0 -1
  141. package/dist/utils/encryption.js +0 -55
  142. package/dist/utils/hashUtils.d.ts +0 -8
  143. package/dist/utils/hashUtils.d.ts.map +0 -1
  144. package/dist/utils/hashUtils.js +0 -44
  145. package/dist/utils/index.d.ts +0 -14
  146. package/dist/utils/index.d.ts.map +0 -1
  147. package/dist/utils/index.js +0 -29
  148. package/dist/utils/merkle.d.ts +0 -2
  149. package/dist/utils/merkle.d.ts.map +0 -1
  150. package/dist/utils/merkle.js +0 -28
  151. package/dist/utils/network.d.ts +0 -2
  152. package/dist/utils/network.d.ts.map +0 -1
  153. package/dist/utils/network.js +0 -54
  154. package/dist/utils/spinnerUtils.d.ts +0 -2
  155. package/dist/utils/spinnerUtils.d.ts.map +0 -1
  156. package/dist/utils/spinnerUtils.js +0 -47
  157. package/dist/utils/ssl.d.ts +0 -5
  158. package/dist/utils/ssl.d.ts.map +0 -1
  159. package/dist/utils/ssl.js +0 -50
  160. package/dist/utils/validationUtils.d.ts +0 -9
  161. package/dist/utils/validationUtils.d.ts.map +0 -1
  162. package/dist/utils/validationUtils.js +0 -55
@@ -1,707 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
- Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.DataIntegrityTree = void 0;
30
- const fs = __importStar(require("fs"));
31
- const path = __importStar(require("path"));
32
- const crypto = __importStar(require("crypto"));
33
- const zlib = __importStar(require("zlib"));
34
- const crypto_js_1 = require("crypto-js");
35
- const merkletreejs_1 = require("merkletreejs");
36
- const util_1 = require("util");
37
- const DataLayerError_1 = __importDefault(require("./DataLayerError"));
38
- const unlink = (0, util_1.promisify)(fs.unlink);
39
- /**
40
- * Convert a string to hexadecimal representation.
41
- * @param str - The input string.
42
- * @returns The hexadecimal representation of the input string.
43
- */
44
- const toHex = (str) => {
45
- return Buffer.from(str).toString("hex");
46
- };
47
- /**
48
- * Remove empty directories recursively.
49
- * @param dir - The directory path.
50
- */
51
- const removeEmptyDirectories = (dir) => {
52
- if (fs.existsSync(dir)) {
53
- const files = fs.readdirSync(dir);
54
- if (files.length === 0) {
55
- fs.rmdirSync(dir);
56
- const parentDir = path.dirname(dir);
57
- removeEmptyDirectories(parentDir);
58
- }
59
- }
60
- };
61
- /**
62
- * Check if a string is a valid hexadecimal string.
63
- * @param str - The string to validate.
64
- * @returns True if the string is a valid hex string, false otherwise.
65
- */
66
- const isHexString = (str) => {
67
- return /^[0-9a-fA-F]+$/.test(str) && str.length % 2 === 0;
68
- };
69
- /**
70
- * DataStoreManager class to manage Merkle tree operations.
71
- */
72
- class DataIntegrityTree {
73
- constructor(storeId, options = {}) {
74
- if (!isHexString(storeId) || storeId.length !== 64) {
75
- throw new Error("storeId must be a 64 char hex string");
76
- }
77
- this.storeId = storeId;
78
- this.storeBaseDir = options.storeDir || "./";
79
- if (!fs.existsSync(this.storeBaseDir)) {
80
- fs.mkdirSync(this.storeBaseDir, { recursive: true });
81
- }
82
- if (options.storageMode === "unified") {
83
- this.dataDir = path.join(this.storeBaseDir, "data");
84
- }
85
- else {
86
- this.dataDir = path.join(this.storeBaseDir, this.storeId, "data");
87
- }
88
- this.storeDir = path.join(this.storeBaseDir, this.storeId);
89
- if (!fs.existsSync(this.storeDir)) {
90
- fs.mkdirSync(this.storeDir, { recursive: true });
91
- }
92
- if (!fs.existsSync(this.dataDir)) {
93
- fs.mkdirSync(this.dataDir, { recursive: true });
94
- }
95
- this.files = new Map();
96
- if (options.rootHash) {
97
- if (fs.existsSync(path.join(this.storeDir, `${options.rootHash}.dat`))) {
98
- this.tree = this.deserializeTree(options.rootHash);
99
- }
100
- else {
101
- throw new DataLayerError_1.default(404, `Root hash ${options.rootHash} not found`);
102
- }
103
- }
104
- else {
105
- this.tree = this._loadLatestTree();
106
- }
107
- // Commit the empty Merkle tree immediately upon creation
108
- if (!options.disableInitialize && this.tree.getLeafCount() === 0) {
109
- this.commit();
110
- }
111
- }
112
- static from(storeId, options) {
113
- return new DataIntegrityTree(storeId, {
114
- ...options,
115
- disableInitialize: true,
116
- });
117
- }
118
- /**
119
- * Load the manifest file.
120
- * @private
121
- */
122
- _loadManifest() {
123
- const manifestPath = path.join(this.storeDir, "manifest.dat");
124
- if (fs.existsSync(manifestPath)) {
125
- return fs.readFileSync(manifestPath, "utf8").trim().split("\n");
126
- }
127
- return [];
128
- }
129
- /**
130
- * Load the latest tree from the manifest file.
131
- * @private
132
- */
133
- _loadLatestTree() {
134
- const manifest = this._loadManifest();
135
- if (manifest.length > 0) {
136
- const latestRootHash = manifest[manifest.length - 1];
137
- if (latestRootHash && isHexString(latestRootHash)) {
138
- return this.deserializeTree(latestRootHash);
139
- }
140
- return new merkletreejs_1.MerkleTree([], crypto_js_1.SHA256, { sortPairs: true });
141
- }
142
- else {
143
- return new merkletreejs_1.MerkleTree([], crypto_js_1.SHA256, { sortPairs: true });
144
- }
145
- }
146
- /**
147
- * Save a binary stream to the store's data directory.
148
- * @param sha256 - The SHA-256 hash of the buffer.
149
- * @returns The write stream for the file.
150
- */
151
- _createWriteStream(sha256) {
152
- const subDirs = sha256.match(/.{1,2}/g) || [];
153
- const fileDir = path.join(this.dataDir, ...subDirs.slice(0, -1));
154
- const fileName = subDirs[subDirs.length - 1];
155
- const fileSavePath = path.join(fileDir, fileName);
156
- if (!fs.existsSync(fileDir)) {
157
- fs.mkdirSync(fileDir, { recursive: true });
158
- }
159
- return fs.createWriteStream(fileSavePath);
160
- }
161
- /**
162
- * Stream file from one path to another.
163
- * @param src - The source file path.
164
- * @param dest - The destination file path.
165
- */
166
- async _streamFile(src, dest) {
167
- return new Promise((resolve, reject) => {
168
- const readStream = fs.createReadStream(src);
169
- const writeStream = fs.createWriteStream(dest);
170
- readStream.pipe(writeStream);
171
- writeStream.on("finish", resolve);
172
- writeStream.on("error", reject);
173
- readStream.on("error", reject);
174
- });
175
- }
176
- /**
177
- * Upsert a key with a binary stream to the Merkle tree.
178
- * Compresses the file, calculates the SHA-256 of the uncompressed file, and stores it.
179
- * @param readStream - The binary data stream.
180
- * @param key - The hexadecimal key for the binary data.
181
- */
182
- async upsertKey(readStream, key) {
183
- if (!isHexString(key)) {
184
- throw new Error(`key must be a valid hex string: ${key}`);
185
- }
186
- const uncompressedHash = crypto.createHash("sha256");
187
- const gzip = zlib.createGzip();
188
- let sha256;
189
- const tempDir = path.join(this.storeDir, "tmp");
190
- if (!fs.existsSync(tempDir)) {
191
- fs.mkdirSync(tempDir, { recursive: true });
192
- }
193
- const tempFilePath = path.join(tempDir, `${crypto.randomUUID()}.gz`);
194
- return new Promise((resolve, reject) => {
195
- const tempWriteStream = fs.createWriteStream(tempFilePath);
196
- readStream.on("data", (chunk) => {
197
- uncompressedHash.update(chunk);
198
- });
199
- readStream.pipe(gzip).pipe(tempWriteStream);
200
- tempWriteStream.on("finish", async () => {
201
- sha256 = uncompressedHash.digest("hex");
202
- const finalWriteStream = this._createWriteStream(sha256);
203
- const finalPath = finalWriteStream.path;
204
- // Ensure the directory exists before copying the file
205
- const finalDir = path.dirname(finalPath);
206
- if (!fs.existsSync(finalDir)) {
207
- fs.mkdirSync(finalDir, { recursive: true });
208
- }
209
- try {
210
- await this._streamFile(tempFilePath, finalPath);
211
- await unlink(tempFilePath);
212
- const combinedHash = crypto
213
- .createHash("sha256")
214
- .update(`${key}/${sha256}`)
215
- .digest("hex");
216
- if (Array.from(this.files.values()).some((file) => file.hash === combinedHash)) {
217
- console.log(`No changes detected for key: ${key}`);
218
- return resolve();
219
- }
220
- if (this.files.has(key)) {
221
- this.deleteKey(key);
222
- }
223
- console.log(`Inserted key: ${key}`);
224
- this.files.set(key, {
225
- hash: combinedHash,
226
- sha256: sha256,
227
- });
228
- await new Promise((resolve) => setTimeout(resolve, 100));
229
- this._rebuildTree();
230
- await new Promise((resolve) => setTimeout(resolve, 100));
231
- resolve();
232
- }
233
- catch (err) {
234
- reject(err);
235
- }
236
- tempWriteStream.end();
237
- finalWriteStream.end();
238
- });
239
- tempWriteStream.on("error", (err) => {
240
- tempWriteStream.end();
241
- reject(err);
242
- });
243
- readStream.on("error", (err) => {
244
- reject(err);
245
- });
246
- });
247
- }
248
- /**
249
- * Delete a key from the Merkle tree.
250
- * @param key - The hexadecimal key to delete.
251
- */
252
- deleteKey(key) {
253
- if (!isHexString(key)) {
254
- throw new Error("key must be a valid hex string");
255
- }
256
- if (this.files.has(key)) {
257
- this.files.delete(key);
258
- this._rebuildTree();
259
- console.log(`Deleted key: ${key}`);
260
- }
261
- }
262
- /**
263
- * List all keys in the Merkle tree.
264
- * @param rootHash - The root hash of the tree. Defaults to the latest root hash.
265
- * @returns The list of keys.
266
- */
267
- listKeys(rootHash = null) {
268
- if (rootHash && !isHexString(rootHash)) {
269
- throw new Error("rootHash must be a valid hex string");
270
- }
271
- if (rootHash) {
272
- const tree = this.deserializeTree(rootHash);
273
- // @ts-ignore
274
- return Array.from(tree.files.keys());
275
- }
276
- return Array.from(this.files.keys());
277
- }
278
- /**
279
- * Rebuild the Merkle tree from the current files.
280
- * @private
281
- */
282
- _rebuildTree() {
283
- const leaves = Array.from(this.files.values()).map(({ hash }) => Buffer.from(hash, "hex"));
284
- this.tree = new merkletreejs_1.MerkleTree(leaves, crypto_js_1.SHA256, { sortPairs: true });
285
- }
286
- /**
287
- * Get the root of the Merkle tree.
288
- * @param rootHash - The root hash of the tree. Defaults to the latest root hash.
289
- * @returns The Merkle root.
290
- */
291
- getRoot() {
292
- return this.tree.getRoot().toString("hex");
293
- }
294
- /**
295
- * Serialize the Merkle tree to a JSON object.
296
- * @param rootHash - The root hash of the tree. Defaults to the latest root hash.
297
- * @returns The serialized Merkle tree.
298
- */
299
- serialize(rootHash = null) {
300
- if (rootHash && !isHexString(rootHash)) {
301
- throw new Error("rootHash must be a valid hex string");
302
- }
303
- if (rootHash) {
304
- const tree = this.deserializeTree(rootHash);
305
- return {
306
- root: tree.getRoot().toString("hex"),
307
- leaves: tree.getLeaves().map((leaf) => leaf.toString("hex")),
308
- // @ts-ignore
309
- files: Object.fromEntries(tree.files),
310
- };
311
- }
312
- return {
313
- root: this.getRoot(),
314
- leaves: this.tree.getLeaves().map((leaf) => leaf.toString("hex")),
315
- files: Object.fromEntries(this.files),
316
- };
317
- }
318
- static getRootOfForeignTree(treeData) {
319
- const leaves = treeData.leaves.map((leaf) => Buffer.from(leaf, "hex"));
320
- const tree = new merkletreejs_1.MerkleTree(leaves, crypto_js_1.SHA256, { sortPairs: true });
321
- return tree.getRoot().toString("hex");
322
- }
323
- /**
324
- * Deserialize a JSON object to a Merkle tree.
325
- * @param rootHash - The root hash of the tree.
326
- * @returns The deserialized Merkle tree.
327
- */
328
- deserializeTree(rootHash) {
329
- if (!isHexString(rootHash)) {
330
- throw new Error("rootHash must be a valid hex string");
331
- }
332
- const treeFilePath = path.join(this.storeDir, `${rootHash}.dat`);
333
- if (!fs.existsSync(treeFilePath)) {
334
- throw new Error(`Tree file ${treeFilePath} does not exist`);
335
- }
336
- const data = JSON.parse(fs.readFileSync(treeFilePath, "utf8"));
337
- const leaves = data.leaves.map((leaf) => Buffer.from(leaf, "hex"));
338
- const tree = new merkletreejs_1.MerkleTree(leaves, crypto_js_1.SHA256, { sortPairs: true });
339
- // @ts-ignore
340
- tree.files = new Map(Object.entries(data.files).map(([key, value]) => [
341
- key,
342
- { hash: value.hash, sha256: value.sha256 },
343
- ]));
344
- // @ts-ignore
345
- this.files = tree.files;
346
- return tree;
347
- }
348
- appendRootHashToManifest(rootHash) {
349
- const manifestPath = path.join(this.storeDir, "manifest.dat");
350
- // Read the current manifest file
351
- const manifestContent = fs.existsSync(manifestPath)
352
- ? fs.readFileSync(manifestPath, "utf-8").trim().split("\n")
353
- : [];
354
- // Check if the last entry is the same as the rootHash to avoid duplicates
355
- const latestRootHash = manifestContent.length > 0
356
- ? manifestContent[manifestContent.length - 1]
357
- : null;
358
- if (latestRootHash !== rootHash) {
359
- // Append the new rootHash if it is not the same as the last one
360
- fs.appendFileSync(manifestPath, `${rootHash}\n`);
361
- }
362
- else {
363
- console.log(`Root hash ${rootHash} is already at the end of the file. Skipping append.`);
364
- }
365
- }
366
- /**
367
- * Commit the current state of the Merkle tree.
368
- */
369
- commit() {
370
- const emptyRootHash = "0000000000000000000000000000000000000000000000000000000000000000";
371
- const rootHash = this.tree.getLeafCount() === 0 ? emptyRootHash : this.getRoot();
372
- const manifest = this._loadManifest();
373
- const latestRootHash = manifest.length > 0 ? manifest[manifest.length - 1] : null;
374
- if (rootHash === latestRootHash && rootHash !== emptyRootHash) {
375
- console.log("No changes to commit. Aborting commit.");
376
- return undefined;
377
- }
378
- this.appendRootHashToManifest(rootHash);
379
- const treeFilePath = path.join(this.storeDir, `${rootHash}.dat`);
380
- if (!fs.existsSync(path.dirname(treeFilePath))) {
381
- fs.mkdirSync(path.dirname(treeFilePath), { recursive: true });
382
- }
383
- const serializedTree = this.serialize();
384
- if (rootHash === emptyRootHash) {
385
- serializedTree.root = emptyRootHash;
386
- }
387
- fs.writeFileSync(treeFilePath, JSON.stringify(serializedTree));
388
- console.log(`Committed new root`);
389
- console.log(this.tree.toString());
390
- return rootHash;
391
- }
392
- /**
393
- * Clear pending changes and revert to the latest committed state.
394
- */
395
- clearPendingRoot() {
396
- this.tree = this._loadLatestTree();
397
- }
398
- /**
399
- * Check if a file exists for a given key.
400
- * @param hexKey - The hexadecimal key of the file.
401
- * @param rootHash - The root hash of the tree. Defaults to the latest root hash.
402
- * @returns A boolean indicating if the file exists.
403
- */
404
- hasKey(hexKey, rootHash = null) {
405
- if (!isHexString(hexKey)) {
406
- throw new Error("key must be a valid hex string");
407
- }
408
- if (rootHash && !isHexString(rootHash)) {
409
- throw new Error("rootHash must be a valid hex string");
410
- }
411
- let sha256;
412
- if (rootHash) {
413
- const tree = this.deserializeTree(rootHash);
414
- // @ts-ignore
415
- sha256 = tree.files.get(hexKey)?.sha256;
416
- }
417
- else {
418
- sha256 = this.files.get(hexKey)?.sha256;
419
- }
420
- if (!sha256) {
421
- return false;
422
- }
423
- const filePath = path.join(this.dataDir, sha256.match(/.{1,2}/g).join("/"));
424
- // Check if the file exists at the calculated path
425
- return fs.existsSync(filePath);
426
- }
427
- /**
428
- * Get a readable stream for a file based on its key, with decompression.
429
- * @param hexKey - The hexadecimal key of the file.
430
- * @param rootHash - The root hash of the tree. Defaults to the latest root hash.
431
- * @returns The readable stream for the file.
432
- */
433
- getValueStream(hexKey, rootHash = null, byteOffset = null, length = null) {
434
- if (!isHexString(hexKey)) {
435
- throw new Error("key must be a valid hex string");
436
- }
437
- if (rootHash && !isHexString(rootHash)) {
438
- throw new Error("rootHash must be a valid hex string");
439
- }
440
- let sha256;
441
- if (rootHash) {
442
- const tree = this.deserializeTree(rootHash);
443
- // @ts-ignore
444
- sha256 = tree.files.get(hexKey)?.sha256;
445
- }
446
- else {
447
- sha256 = this.files.get(hexKey)?.sha256;
448
- }
449
- if (!sha256) {
450
- throw new Error(`File with key ${hexKey} not found.`);
451
- }
452
- const filePath = path.join(this.dataDir, sha256.match(/.{1,2}/g).join("/"));
453
- if (!fs.existsSync(filePath)) {
454
- throw new Error(`File at path ${filePath} does not exist`);
455
- }
456
- const fileSize = fs.statSync(filePath).size;
457
- // Validate offset and length
458
- if (byteOffset !== null && length !== null) {
459
- if (byteOffset + length > fileSize) {
460
- throw new Error(`Offset (${byteOffset}) and length (${length}) exceed the file size (${fileSize}).`);
461
- }
462
- }
463
- // Create the read stream with optional byte range
464
- const options = {};
465
- if (byteOffset !== null) {
466
- options.start = byteOffset;
467
- }
468
- if (length !== null && byteOffset !== null) {
469
- options.end = byteOffset + length - 1; // `end` is inclusive, hence `byteOffset + length - 1`
470
- }
471
- const readStream = fs.createReadStream(filePath, options);
472
- const decompressStream = zlib.createGunzip();
473
- // Return the combined stream as a generic Readable stream
474
- return readStream.pipe(decompressStream);
475
- }
476
- /**
477
- * Delete all leaves from the Merkle tree.
478
- */
479
- deleteAllLeaves() {
480
- this.files.clear();
481
- this._rebuildTree();
482
- }
483
- getSHA256(hexKey, rootHash) {
484
- if (!rootHash) {
485
- return this.files.get(hexKey)?.sha256;
486
- }
487
- const tree = this.deserializeTree(rootHash);
488
- // @ts-ignore
489
- return tree.files.get(hexKey)?.sha256;
490
- }
491
- /**
492
- * Get a proof for a file based on its key and SHA-256 hash.
493
- * @param hexKey - The hexadecimal key of the file.
494
- * @param sha256 - The SHA-256 hash of the file.
495
- * @param rootHash - The root hash of the tree. Defaults to the latest root hash.
496
- * @returns The proof for the file as a hex string.
497
- */
498
- getProof(hexKey, sha256, rootHash = null) {
499
- if (!isHexString(hexKey)) {
500
- throw new Error("key must be a valid hex string");
501
- }
502
- if (!isHexString(sha256)) {
503
- throw new Error("sha256 must be a valid hex string");
504
- }
505
- if (rootHash && !isHexString(rootHash)) {
506
- throw new Error("rootHash must be a valid hex string");
507
- }
508
- if (!rootHash) {
509
- const manifest = this._loadManifest();
510
- rootHash = manifest[manifest.length - 1];
511
- }
512
- const tree = this.deserializeTree(rootHash);
513
- const combinedHash = (0, crypto_js_1.SHA256)(`${hexKey}/${sha256}`).toString();
514
- const leaf = Buffer.from(combinedHash, "hex");
515
- const proof = tree.getProof(leaf);
516
- // Convert the proof to a single hex string
517
- const proofHex = proof.map((p) => p.data.toString("hex")).join("");
518
- // Create an object with the key, rootHash, and proofHex
519
- const proofObject = {
520
- key: hexKey,
521
- rootHash: rootHash,
522
- proof: proofHex,
523
- };
524
- // Convert the proofObject to JSON and then to a hex string
525
- const proofObjectHex = Buffer.from(JSON.stringify(proofObject)).toString("hex");
526
- return proofObjectHex;
527
- }
528
- /**
529
- * Verify a proof for a file against the Merkle tree.
530
- * @param proofObjectHex - The proof object as a hex string.
531
- * @param sha256 - The SHA-256 hash of the file.
532
- * @returns True if the proof is valid, false otherwise.
533
- */
534
- verifyProof(proofObjectHex, sha256) {
535
- if (!isHexString(proofObjectHex)) {
536
- throw new Error("proofObjectHex must be a valid hex string");
537
- }
538
- if (!isHexString(sha256)) {
539
- throw new Error("sha256 must be a valid hex string");
540
- }
541
- // Convert the proofObjectHex back to a proof object
542
- const proofObject = JSON.parse(Buffer.from(proofObjectHex, "hex").toString("utf8"));
543
- const { key, rootHash, proof } = proofObject;
544
- const tree = this.deserializeTree(rootHash);
545
- const combinedHash = (0, crypto_js_1.SHA256)(`${key}/${sha256}`).toString();
546
- const leaf = Buffer.from(combinedHash, "hex");
547
- // Convert the proofHex string back to the proof array
548
- const proofBufferArray = [];
549
- for (let i = 0; i < proof.length; i += 64) {
550
- proofBufferArray.push(Buffer.from(proof.slice(i, i + 64), "hex"));
551
- }
552
- const proofArray = proofBufferArray.map((data) => ({ data }));
553
- return tree.verify(proofArray, leaf, Buffer.from(rootHash, "hex"));
554
- }
555
- /**
556
- * Get the difference between two Merkle tree roots.
557
- * @param rootHash1 - The first root hash.
558
- * @param rootHash2 - The second root hash.
559
- * @returns An object containing the added and deleted keys and their SHA-256 hashes.
560
- */
561
- getRootDiff(rootHash1, rootHash2) {
562
- if (!isHexString(rootHash1) || !isHexString(rootHash2)) {
563
- throw new Error("rootHash1 and rootHash2 must be valid hex strings");
564
- }
565
- const tree1 = this.deserializeTree(rootHash1);
566
- const tree2 = this.deserializeTree(rootHash2);
567
- // @ts-ignore
568
- const files1 = tree1.files;
569
- // @ts-ignore
570
- const files2 = tree2.files;
571
- const added = new Map();
572
- const deleted = new Map();
573
- files1.forEach((value, key) => {
574
- if (!files2.has(key)) {
575
- deleted.set(key, value.sha256);
576
- }
577
- });
578
- files2.forEach((value, key) => {
579
- if (!files1.has(key)) {
580
- added.set(key, value.sha256);
581
- }
582
- });
583
- return { added, deleted };
584
- }
585
- /**
586
- * Verify the integrity of a file based on its SHA-256 hash and check if it is in the specified Merkle root.
587
- * @param sha256 - The SHA-256 hash of the file.
588
- * @param root - The root hash to check against.
589
- * @returns True if the file integrity is verified and it is in the Merkle root, false otherwise.
590
- */
591
- async verifyKeyIntegrity(sha256, rootHash) {
592
- if (!isHexString(sha256)) {
593
- throw new Error("sha256 must be a valid hex string");
594
- }
595
- if (!isHexString(rootHash)) {
596
- throw new Error("rootHash must be a valid hex string");
597
- }
598
- const filePath = path.join(this.dataDir, sha256.match(/.{1,2}/g).join("/"));
599
- if (!fs.existsSync(filePath)) {
600
- throw new Error(`File at path ${filePath} does not exist`);
601
- }
602
- const compressedReadStream = fs.createReadStream(filePath);
603
- const decompressStream = zlib.createGunzip();
604
- const hash = crypto.createHash("sha256");
605
- return new Promise((resolve, reject) => {
606
- compressedReadStream.pipe(decompressStream);
607
- decompressStream.on("data", (chunk) => {
608
- hash.update(chunk);
609
- });
610
- decompressStream.on("end", () => {
611
- const uncompressedSha256 = hash.digest("hex");
612
- const isValid = uncompressedSha256 === sha256;
613
- if (!isValid) {
614
- return resolve(false);
615
- }
616
- const tree = this.deserializeTree(rootHash);
617
- const combinedHash = crypto
618
- .createHash("sha256")
619
- .update(sha256)
620
- .digest("hex");
621
- const leaf = Buffer.from(combinedHash, "hex");
622
- const isInTree = tree.getLeafIndex(leaf) !== -1;
623
- resolve(isInTree);
624
- });
625
- decompressStream.on("error", (err) => {
626
- reject(err);
627
- });
628
- compressedReadStream.on("error", (err) => {
629
- reject(err);
630
- });
631
- });
632
- }
633
- /**
634
- * Static method to validate key integrity using a foreign Merkle tree.
635
- * Verifies if a given SHA-256 hash for a key exists within the foreign tree and checks if the root hash matches.
636
- *
637
- * @param key - The hexadecimal key of the file.
638
- * @param sha256 - The SHA-256 hash of the file.
639
- * @param serializedTree - The foreign serialized Merkle tree.
640
- * @param expectedRootHash - The expected root hash of the Merkle tree.
641
- * @returns A boolean indicating if the SHA-256 is present in the foreign tree and the root hash matches.
642
- */
643
- static async validateKeyIntegrityWithForeignTree(hexkey, sha256, serializedTree, expectedRootHash, dataDir) {
644
- if (!isHexString(hexkey)) {
645
- throw new Error("key must be a valid hex string");
646
- }
647
- if (!isHexString(sha256)) {
648
- throw new Error("sha256 must be a valid hex string");
649
- }
650
- if (!isHexString(expectedRootHash)) {
651
- throw new Error("expectedRootHash must be a valid hex string");
652
- }
653
- // File path based on sha256
654
- const filePath = path.join(dataDir, sha256.match(/.{1,2}/g).join("/"));
655
- // Check if the file exists
656
- if (!fs.existsSync(filePath)) {
657
- throw new Error(`File at path ${filePath} does not exist`);
658
- }
659
- const compressedReadStream = fs.createReadStream(filePath);
660
- const decompressStream = zlib.createGunzip();
661
- const hash = crypto.createHash("sha256");
662
- // Process file decompression and hash comparison
663
- return new Promise((resolve, reject) => {
664
- compressedReadStream.pipe(decompressStream);
665
- decompressStream.on("data", (chunk) => {
666
- hash.update(chunk);
667
- });
668
- decompressStream.on("end", () => {
669
- const uncompressedSha256 = hash.digest("hex");
670
- if (uncompressedSha256 !== sha256) {
671
- console.warn(`File hash mismatch. Expected: ${sha256}, got: ${uncompressedSha256}`);
672
- return resolve(false);
673
- }
674
- // Deserialize the foreign tree
675
- const leaves = serializedTree.leaves.map((leaf) => Buffer.from(leaf, "hex"));
676
- const tree = new merkletreejs_1.MerkleTree(leaves, crypto_js_1.SHA256, { sortPairs: true });
677
- // Verify that the deserialized tree's root matches the expected root hash
678
- const treeRootHash = tree.getRoot().toString("hex");
679
- if (treeRootHash !== expectedRootHash) {
680
- console.warn(`Expected root hash ${expectedRootHash}, but got ${treeRootHash}`);
681
- return resolve(false);
682
- }
683
- // Rebuild the files map from the serialized tree
684
- // @ts-ignore
685
- tree.files = new Map(Object.entries(serializedTree.files).map(([key, value]) => [
686
- key,
687
- { hash: value.hash, sha256: value.sha256 },
688
- ]));
689
- // Check if the SHA-256 exists in the foreign tree's files
690
- const combinedHash = crypto
691
- .createHash("sha256")
692
- .update(`${hexkey}/${sha256}`)
693
- .digest("hex");
694
- const leaf = Buffer.from(combinedHash, "hex");
695
- const isInTree = tree.getLeafIndex(leaf) !== -1;
696
- resolve(isInTree);
697
- });
698
- decompressStream.on("error", (err) => {
699
- reject(err);
700
- });
701
- compressedReadStream.on("error", (err) => {
702
- reject(err);
703
- });
704
- });
705
- }
706
- }
707
- exports.DataIntegrityTree = DataIntegrityTree;