@dignetwork/dig-sdk 0.0.1-alpha.57 → 0.0.1-alpha.59

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.
@@ -78,6 +78,9 @@ declare class DataIntegrityTree {
78
78
  * @returns The serialized Merkle tree.
79
79
  */
80
80
  serialize(rootHash?: string | null): object;
81
+ static getRootOfForeignTree(treeData: {
82
+ leaves: string[];
83
+ }): string;
81
84
  /**
82
85
  * Deserialize a JSON object to a Merkle tree.
83
86
  * @param rootHash - The root hash of the tree.
@@ -1 +1 @@
1
- {"version":3,"file":"DataIntegrityTree.d.ts","sourceRoot":"","sources":["../../src/DataIntegrityTree/DataIntegrityTree.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAuClC,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;GAEG;AACH,cAAM,iBAAiB;IACrB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAS;IACjB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5D,OAAO,CAAC,IAAI,CAAa;gBAEb,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,wBAA6B;WAiDrD,IAAI,CAChB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,wBAAwB,GAChC,iBAAiB;IAOpB;;;OAGG;IACH,OAAO,CAAC,aAAa;IAQrB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAUvB;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAa1B;;;;OAIG;YACW,WAAW;IAazB;;;;;OAKG;IACG,SAAS,CAAC,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqFjE;;;OAGG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAW5B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,GAAE,MAAM,GAAG,IAAW,GAAG,MAAM,EAAE;IAalD;;;OAGG;IACH,OAAO,CAAC,YAAY;IAOpB;;;;OAIG;IACH,OAAO,IAAI,MAAM;IAIjB;;;;OAIG;IACH,SAAS,CAAC,QAAQ,GAAE,MAAM,GAAG,IAAW,GAAG,MAAM;IAqBjD;;;;OAIG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU;IAwB7C,OAAO,CAAC,wBAAwB;IAuBhC;;OAEG;IACH,MAAM,IAAI,MAAM,GAAG,SAAS;IAoC5B;;OAEG;IACH,gBAAgB,IAAI,IAAI;IAIxB;;;;;OAKG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAM,GAAG,IAAW,GAAG,OAAO;IA+B/D;;;;;OAKG;IACH,cAAc,CACZ,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,MAAM,GAAG,IAAW,EAC9B,UAAU,GAAE,MAAM,GAAG,IAAW,EAChC,MAAM,GAAE,MAAM,GAAG,IAAW,GAC3B,QAAQ;IA4DX;;OAEG;IACH,eAAe,IAAI,IAAI;IAKvB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAUhE;;;;;;OAMG;IACH,QAAQ,CACN,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,MAAM,GAAG,IAAW,GAC7B,MAAM;IAsCT;;;;;OAKG;IACH,WAAW,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO;IA4B5D;;;;;OAKG;IACH,WAAW,CACT,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB;QAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE;IA+B/D;;;;;OAKG;IACG,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA0D5E;;;;;;;;;OASG;WACU,mCAAmC,CAC9C,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,EACtB,gBAAgB,EAAE,MAAM,EACxB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,OAAO,CAAC;CAyFpB;AAED,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
1
+ {"version":3,"file":"DataIntegrityTree.d.ts","sourceRoot":"","sources":["../../src/DataIntegrityTree/DataIntegrityTree.ts"],"names":[],"mappings":"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"}
@@ -313,6 +313,11 @@ class DataIntegrityTree {
313
313
  files: Object.fromEntries(this.files),
314
314
  };
315
315
  }
316
+ static getRootOfForeignTree(treeData) {
317
+ const leaves = treeData.leaves.map((leaf) => Buffer.from(leaf, "hex"));
318
+ const tree = new merkletreejs_1.MerkleTree(leaves, crypto_js_1.SHA256, { sortPairs: true });
319
+ return tree.getRoot().toString("hex");
320
+ }
316
321
  /**
317
322
  * Deserialize a JSON object to a Merkle tree.
318
323
  * @param rootHash - The root hash of the tree.
@@ -603,7 +608,6 @@ class DataIntegrityTree {
603
608
  decompressStream.on("end", () => {
604
609
  const uncompressedSha256 = hash.digest("hex");
605
610
  const isValid = uncompressedSha256 === sha256;
606
- console.log(`SHA-256 of uncompressed file: ${uncompressedSha256}`);
607
611
  if (!isValid) {
608
612
  return resolve(false);
609
613
  }
@@ -661,7 +665,6 @@ class DataIntegrityTree {
661
665
  });
662
666
  decompressStream.on("end", () => {
663
667
  const uncompressedSha256 = hash.digest("hex");
664
- console.log(`SHA-256 of uncompressed file: ${uncompressedSha256}`);
665
668
  if (uncompressedSha256 !== sha256) {
666
669
  console.warn(`File hash mismatch. Expected: ${sha256}, got: ${uncompressedSha256}`);
667
670
  return resolve(false);
@@ -31,18 +31,30 @@ export declare class PropagationServer {
31
31
  rootHashExists: boolean;
32
32
  }>;
33
33
  /**
34
- * Start an upload session by sending a POST request to the server.
34
+ * Start an upload session by sending a POST request with the rootHash.dat file.
35
+ *
36
+ * @param {string} rootHash - The root hash used to name the .dat file.
37
+ * @param {string} datFilePath - The full path to the rootHash.dat file.
35
38
  */
36
- startUploadSession(): Promise<void>;
39
+ startUploadSession(rootHash: string): Promise<void>;
37
40
  /**
38
41
  * Request a nonce for a file by sending a HEAD request to the server.
42
+ * Checks if the file already exists based on the 'x-file-exists' header.
39
43
  */
40
- getFileNonce(filename: string): Promise<string>;
44
+ getFileNonce(filename: string): Promise<{
45
+ nonce: string;
46
+ fileExists: boolean;
47
+ }>;
41
48
  /**
42
49
  * Upload a file to the server by sending a PUT request.
43
50
  * Logs progress using cli-progress for each file.
44
51
  */
45
- uploadFile(filePath: string): Promise<any>;
52
+ uploadFile(label: string, dataPath: string): Promise<any>;
53
+ /**
54
+ * Commit the upload session by sending a POST request to the server.
55
+ * This finalizes the upload and moves files from the temporary session directory to the permanent location.
56
+ */
57
+ commitUploadSession(): Promise<any>;
46
58
  /**
47
59
  * Static function to handle the entire upload process for multiple files based on rootHash.
48
60
  * @param {string} storeId - The ID of the DataStore.
@@ -1 +1 @@
1
- {"version":3,"file":"PropagationServer.d.ts","sourceRoot":"","sources":["../../src/DigNetwork/PropagationServer.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,MAAM,OAAO,CAAC;AAO1B,qBAAa,iBAAiB;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,GAAG,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAE7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAQ;IAGpC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAYrB;gBAEU,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAY9C;;OAEG;IACG,gBAAgB;IAKtB;;OAEG;IACH,gBAAgB;IAQhB;;;;;OAKG;IACG,gBAAgB,CACpB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC;QAAE,WAAW,EAAE,OAAO,CAAC;QAAC,cAAc,EAAE,OAAO,CAAA;KAAE,CAAC;IA4C7D;;OAEG;IACG,kBAAkB;IAqCxB;;OAEG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAoBrD;;;OAGG;IACG,UAAU,CAAC,QAAQ,EAAE,MAAM;IAwDjC;;;;;;OAMG;WACU,WAAW,CACtB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM;IAyCnB;;;;;OAKG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA4ClD;;;;OAIG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM;IAkEnC;;;;;OAKG;WACU,aAAa,CACxB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM;CA4BpB"}
1
+ {"version":3,"file":"PropagationServer.d.ts","sourceRoot":"","sources":["../../src/DigNetwork/PropagationServer.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,MAAM,OAAO,CAAC;AAiB1B,qBAAa,iBAAiB;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,GAAG,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAE7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAQ;IAIpC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAqCrB;gBAEU,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAY9C;;OAEG;IACG,gBAAgB;IAKtB;;OAEG;IACH,gBAAgB;IAQhB;;;;;OAKG;IACG,gBAAgB,CACpB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC;QAAE,WAAW,EAAE,OAAO,CAAC;QAAC,cAAc,EAAE,OAAO,CAAA;KAAE,CAAC;IAwC7D;;;;;OAKG;IACG,kBAAkB,CAAC,QAAQ,EAAE,MAAM;IAqDzC;;;OAGG;IACG,YAAY,CAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE,CAAC;IAyBlD;;;OAGG;IACG,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IA+DhD;;;OAGG;IACG,mBAAmB;IAgCzB;;;;;;OAMG;WACU,WAAW,CACtB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM;IAiDnB;;;;;OAKG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA4ClD;;;;OAIG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM;IAgEnC;;;;;OAKG;WACU,aAAa,CACxB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM;CA4BpB"}
@@ -17,6 +17,15 @@ const colorette_1 = require("colorette"); // For colored output
17
17
  const config_1 = require("../utils/config");
18
18
  const hashUtils_1 = require("../utils/hashUtils");
19
19
  const nanospinner_1 = require("nanospinner");
20
+ // Helper function to trim long filenames with ellipsis and ensure consistent padding
21
+ function formatFilename(filename, maxLength = 30) {
22
+ if (filename.length > maxLength) {
23
+ // Trim the filename and add ellipsis
24
+ return `...${filename.slice(-(maxLength - 3))}`.padEnd(maxLength, " ");
25
+ }
26
+ // For shorter filenames, just pad to the maxLength
27
+ return filename.padEnd(maxLength, " ");
28
+ }
20
29
  class PropagationServer {
21
30
  constructor(storeId, ipAddress) {
22
31
  this.storeId = storeId;
@@ -33,7 +42,7 @@ class PropagationServer {
33
42
  */
34
43
  async initializeWallet() {
35
44
  this.wallet = await blockchain_1.Wallet.load("default");
36
- this.publicKey = await this.wallet.getPublicSyntheticKey().toString('hex');
45
+ this.publicKey = await this.wallet.getPublicSyntheticKey().toString("hex");
37
46
  }
38
47
  /**
39
48
  * Create an Axios HTTPS Agent with self-signed certificate allowance.
@@ -66,18 +75,14 @@ class PropagationServer {
66
75
  const storeExists = response.headers["x-store-exists"] === "true";
67
76
  const rootHashExists = response.headers["x-has-root-hash"] === "true";
68
77
  if (storeExists) {
69
- spinner.success({ text: (0, colorette_1.green)(`Store ${this.storeId} exists on peer!`) });
78
+ spinner.success({
79
+ text: (0, colorette_1.green)(`Store ${this.storeId} exists on peer!`),
80
+ });
70
81
  }
71
82
  else {
72
- spinner.error({ text: (0, colorette_1.red)(`Store ${this.storeId} does not exist. Credentials will be required to push.`) });
73
- }
74
- if (rootHash) {
75
- if (rootHashExists) {
76
- console.log((0, colorette_1.green)(`Root hash ${rootHash} exists in the store.`));
77
- }
78
- else {
79
- console.log((0, colorette_1.red)(`Root hash ${rootHash} does not exist in the store.`));
80
- }
83
+ spinner.error({
84
+ text: (0, colorette_1.red)(`Store ${this.storeId} does not exist. Credentials will be required to push.`),
85
+ });
81
86
  }
82
87
  return { storeExists, rootHashExists };
83
88
  }
@@ -88,23 +93,38 @@ class PropagationServer {
88
93
  }
89
94
  }
90
95
  /**
91
- * Start an upload session by sending a POST request to the server.
96
+ * Start an upload session by sending a POST request with the rootHash.dat file.
97
+ *
98
+ * @param {string} rootHash - The root hash used to name the .dat file.
99
+ * @param {string} datFilePath - The full path to the rootHash.dat file.
92
100
  */
93
- async startUploadSession() {
101
+ async startUploadSession(rootHash) {
94
102
  const spinner = (0, nanospinner_1.createSpinner)(`Starting upload session for store ${this.storeId}...`).start();
95
103
  try {
104
+ const formData = new form_data_1.default();
105
+ const datFilePath = path_1.default.join(config_1.STORE_PATH, this.storeId, `${rootHash}.dat`);
106
+ // Ensure the rootHash.dat file exists
107
+ if (!fs_1.default.existsSync(datFilePath)) {
108
+ throw new Error(`File not found: ${datFilePath}`);
109
+ }
110
+ formData.append("file", fs_1.default.createReadStream(datFilePath), {
111
+ filename: `${rootHash}.dat`,
112
+ });
96
113
  const config = {
97
114
  httpsAgent: this.createHttpsAgent(),
115
+ headers: {
116
+ ...formData.getHeaders(),
117
+ },
98
118
  };
99
- // Add Basic Auth headers if credentials are provided
119
+ // Add Basic Auth if username and password are present
100
120
  if (this.username && this.password) {
101
121
  config.auth = {
102
122
  username: this.username,
103
123
  password: this.password,
104
124
  };
105
125
  }
106
- const url = `https://${this.ipAddress}:${PropagationServer.port}/upload/${this.storeId}`;
107
- const response = await axios_1.default.post(url, { publicKey: this.publicKey }, config);
126
+ const url = `https://${this.ipAddress}:${PropagationServer.port}/upload/${this.storeId}?roothash=${rootHash}`;
127
+ const response = await axios_1.default.post(url, formData, config);
108
128
  this.sessionId = response.data.sessionId;
109
129
  spinner.success({
110
130
  text: (0, colorette_1.green)(`Upload session started for DataStore ${this.storeId} with session ID ${this.sessionId}`),
@@ -118,6 +138,7 @@ class PropagationServer {
118
138
  }
119
139
  /**
120
140
  * Request a nonce for a file by sending a HEAD request to the server.
141
+ * Checks if the file already exists based on the 'x-file-exists' header.
121
142
  */
122
143
  async getFileNonce(filename) {
123
144
  try {
@@ -126,9 +147,11 @@ class PropagationServer {
126
147
  };
127
148
  const url = `https://${this.ipAddress}:${PropagationServer.port}/upload/${this.storeId}/${this.sessionId}/${filename}`;
128
149
  const response = await axios_1.default.head(url, config);
150
+ // Check for 'x-file-exists' header
151
+ const fileExists = response.headers["x-file-exists"] === "true";
152
+ // If file exists, no need to generate a nonce
129
153
  const nonce = response.headers["x-nonce"];
130
- console.log((0, colorette_1.blue)(`Nonce received for file ${filename}: ${nonce}`));
131
- return nonce;
154
+ return { nonce, fileExists };
132
155
  }
133
156
  catch (error) {
134
157
  console.error((0, colorette_1.red)(`Error generating nonce for file ${filename}:`), error.message);
@@ -139,9 +162,13 @@ class PropagationServer {
139
162
  * Upload a file to the server by sending a PUT request.
140
163
  * Logs progress using cli-progress for each file.
141
164
  */
142
- async uploadFile(filePath) {
143
- const filename = path_1.default.basename(filePath);
144
- const nonce = await this.getFileNonce(filename);
165
+ async uploadFile(label, dataPath) {
166
+ const filePath = path_1.default.join(config_1.STORE_PATH, this.storeId, dataPath);
167
+ const { nonce, fileExists } = await this.getFileNonce(dataPath);
168
+ if (fileExists) {
169
+ console.log((0, colorette_1.blue)(`File ${label} already exists. Skipping upload.`));
170
+ return;
171
+ }
145
172
  const wallet = await blockchain_1.Wallet.load("default");
146
173
  const keyOwnershipSig = await wallet.createKeyOwnershipSignature(nonce);
147
174
  const publicKey = await wallet.getPublicSyntheticKey();
@@ -150,7 +177,7 @@ class PropagationServer {
150
177
  const fileSize = fs_1.default.statSync(filePath).size;
151
178
  // Create a new progress bar for each file
152
179
  const progressBar = PropagationServer.multiBar.create(fileSize, 0, {
153
- filename: (0, colorette_1.yellow)(filename),
180
+ filename: (0, colorette_1.yellow)(path_1.default.basename(label)),
154
181
  percentage: 0,
155
182
  });
156
183
  let uploadedBytes = 0;
@@ -165,26 +192,54 @@ class PropagationServer {
165
192
  httpsAgent: this.createHttpsAgent(),
166
193
  // Tracking upload progress and updating the progress bar
167
194
  onUploadProgress: (progressEvent) => {
168
- uploadedBytes += progressEvent.loaded;
169
- const percentage = Math.round((uploadedBytes / fileSize) * 100);
195
+ const uploadedBytes = progressEvent.loaded;
196
+ const percentage = Math.round((100 * progressEvent.loaded) / progressEvent.total);
170
197
  progressBar.update(uploadedBytes, { percentage });
171
198
  },
172
199
  };
173
200
  try {
174
- const url = `https://${this.ipAddress}:${PropagationServer.port}/upload/${this.storeId}/${this.sessionId}/${filename}`;
201
+ const url = `https://${this.ipAddress}:${PropagationServer.port}/upload/${this.storeId}/${this.sessionId}/${dataPath}`;
175
202
  const response = await axios_1.default.put(url, formData, config);
176
- console.log((0, colorette_1.green)(`✔ File ${filename} uploaded successfully.`));
177
203
  // Complete the progress bar
178
204
  progressBar.update(fileSize, { percentage: 100 });
179
205
  progressBar.stop();
180
206
  return response.data;
181
207
  }
182
208
  catch (error) {
183
- console.error((0, colorette_1.red)(`✖ Error uploading file ${filename}:`), error.message);
209
+ console.error((0, colorette_1.red)(`✖ Error uploading file ${label}:`), error.message);
184
210
  progressBar.stop(); // Stop the progress bar in case of error
185
211
  throw error;
186
212
  }
187
213
  }
214
+ /**
215
+ * Commit the upload session by sending a POST request to the server.
216
+ * This finalizes the upload and moves files from the temporary session directory to the permanent location.
217
+ */
218
+ async commitUploadSession() {
219
+ const spinner = (0, nanospinner_1.createSpinner)(`Committing upload session for store ${this.storeId}...`).start();
220
+ try {
221
+ const config = {
222
+ httpsAgent: this.createHttpsAgent(),
223
+ auth: this.username && this.password
224
+ ? {
225
+ username: this.username,
226
+ password: this.password,
227
+ }
228
+ : undefined,
229
+ };
230
+ const url = `https://${this.ipAddress}:${PropagationServer.port}/commit/${this.storeId}/${this.sessionId}`;
231
+ const response = await axios_1.default.post(url, {}, config);
232
+ spinner.success({
233
+ text: (0, colorette_1.green)(`Upload session ${this.sessionId} successfully committed.`),
234
+ });
235
+ return response.data;
236
+ }
237
+ catch (error) {
238
+ spinner.error({ text: (0, colorette_1.red)("Error committing upload session:") });
239
+ console.error((0, colorette_1.red)(error.message));
240
+ throw error;
241
+ }
242
+ }
188
243
  /**
189
244
  * Static function to handle the entire upload process for multiple files based on rootHash.
190
245
  * @param {string} storeId - The ID of the DataStore.
@@ -197,7 +252,7 @@ class PropagationServer {
197
252
  // Initialize wallet
198
253
  await propagationServer.initializeWallet();
199
254
  // Check if the store exists
200
- const storeExists = await propagationServer.checkStoreExists();
255
+ const { storeExists, rootHashExists } = await propagationServer.checkStoreExists(rootHash);
201
256
  // If the store does not exist, prompt for credentials
202
257
  if (!storeExists) {
203
258
  console.log((0, colorette_1.red)(`Store ${storeId} does not exist. Prompting for credentials...`));
@@ -205,16 +260,20 @@ class PropagationServer {
205
260
  propagationServer.username = credentials.username;
206
261
  propagationServer.password = credentials.password;
207
262
  }
263
+ if (rootHashExists) {
264
+ console.log((0, colorette_1.blue)(`Root hash ${rootHash} already exists in the store. Skipping upload.`));
265
+ return;
266
+ }
208
267
  // Start the upload session
209
- await propagationServer.startUploadSession();
268
+ await propagationServer.startUploadSession(rootHash);
210
269
  const dataStore = blockchain_1.DataStore.from(storeId);
211
- const filePaths = await dataStore.getFileSetForRootHash(rootHash);
270
+ const files = await dataStore.getFileSetForRootHash(rootHash);
212
271
  // Upload each file
213
- for (const filePath of filePaths) {
214
- await propagationServer.uploadFile(filePath);
272
+ for (const file of files) {
273
+ await propagationServer.uploadFile(file.name, file.path);
215
274
  }
216
- // Stop all progress bars after the files are uploaded
217
- PropagationServer.multiBar.stop();
275
+ // Commit the session after all files have been uploaded
276
+ await propagationServer.commitUploadSession();
218
277
  console.log((0, colorette_1.green)(`✔ All files have been uploaded to DataStore ${storeId}.`));
219
278
  }
220
279
  /**
@@ -296,7 +355,8 @@ class PropagationServer {
296
355
  fileWriteStream.on("finish", () => {
297
356
  progressBar.update(totalLength, { percentage: 100 });
298
357
  progressBar.stop();
299
- console.log((0, colorette_1.green)(`✔ File ${dataPath} downloaded successfully to ${downloadPath}.`));
358
+ console.log((0, colorette_1.green)(`
359
+ File ${dataPath} downloaded successfully to ${downloadPath}.`));
300
360
  resolve();
301
361
  });
302
362
  fileWriteStream.on("error", (error) => {
@@ -338,13 +398,29 @@ class PropagationServer {
338
398
  }
339
399
  exports.PropagationServer = PropagationServer;
340
400
  PropagationServer.port = 4159; // Static port used for all requests
341
- // MultiBar for handling multiple progress bars
401
+ // Adjust cliProgress settings to align output properly and handle potential undefined values
402
+ // MultiBar for handling multiple progress bars with green progress and margin between bars
342
403
  PropagationServer.multiBar = new cli_progress_1.default.MultiBar({
343
404
  clearOnComplete: false,
344
405
  hideCursor: true,
345
- format: (0, colorette_1.green)(" {bar} ") +
346
- (0, colorette_1.cyan)(" | {filename} | {percentage}% | {value}/{total} bytes"),
347
- barsize: 40,
406
+ format: (options, params, payload) => {
407
+ // Bar length and padding settings
408
+ const barCompleteChar = (0, colorette_1.green)(options.barCompleteChar || "="); // Green bar for completed portion
409
+ const barIncompleteChar = options.barIncompleteChar || "-"; // Default incomplete character
410
+ const barSize = options.barsize || 40; // Default size of the bar
411
+ // Calculate the bar progress
412
+ const progressBar = `${barCompleteChar.repeat(Math.round(params.progress * barSize))}${barIncompleteChar.repeat(barSize - Math.round(params.progress * barSize))}`;
413
+ // Calculate the percentage manually
414
+ const percentage = Math.round((params.value / params.total) * 100);
415
+ // Format the filename to a fixed length
416
+ const formattedFilename = formatFilename(payload.filename, 30); // Trim to max 30 chars
417
+ // Padding the filename, percentage, and size
418
+ const percentageStr = `${percentage}%`.padEnd(4); // Ensure percentage is always 7 characters wide
419
+ const size = `${params.value}/${params.total} bytes`.padEnd(20); // Ensure size is always 20 characters wide
420
+ // Return the complete formatted progress bar with padding
421
+ return `${progressBar} | ${formattedFilename.padEnd(35)} | ${percentageStr} | ${size}`;
422
+ },
348
423
  stopOnComplete: true,
349
- align: "center",
424
+ barsize: 40,
425
+ align: "left",
350
426
  }, cli_progress_1.default.Presets.shades_classic);
@@ -48,6 +48,15 @@ export declare class DataStore {
48
48
  isSynced(): Promise<boolean>;
49
49
  hasMetaWritePermissions(publicSyntheticKey?: Buffer): Promise<boolean>;
50
50
  updateMetadata(metadata: DataStoreMetadata): Promise<DataStoreDriver>;
51
- getFileSetForRootHash(rootHash: string): Promise<string[]>;
51
+ /**
52
+ * Retrieve the file set for a given root hash and validate file integrity.
53
+ *
54
+ * @param {string} rootHash - The root hash to fetch the file set.
55
+ * @returns {Promise<{ fileName: string, file: string }[]>} - An array of unique file objects.
56
+ */
57
+ getFileSetForRootHash(rootHash: string): Promise<{
58
+ name: string;
59
+ path: string;
60
+ }[]>;
52
61
  }
53
62
  //# sourceMappingURL=DataStore.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DataStore.d.ts","sourceRoot":"","sources":["../../src/blockchain/DataStore.ts"],"names":[],"mappings":"AAEA,OAAO,EAOL,SAAS,IAAI,eAAe,EAE5B,iBAAiB,EAIlB,MAAM,8BAA8B,CAAC;AAWtC,OAAO,EAAE,eAAe,EAAW,MAAM,UAAU,CAAC;AAGpD,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACzB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAQjD,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,IAAI,CAAoB;gBAEpB,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,wBAAwB;IAiB/D,IAAW,OAAO,IAAI,MAAM,CAE3B;IAED,IAAW,IAAI,IAAI,iBAAiB,CAEnC;IAEM,QAAQ,IAAI,MAAM;IAIlB,QAAQ,IAAI,MAAM;IAIlB,SAAS,IAAI,MAAM;WAMN,cAAc,IAAI,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;WAOtD,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS;WAK1C,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;WAYnC,MAAM,CACxB,MAAM,GAAE,qBAA0B,GACjC,OAAO,CAAC,SAAS,CAAC;mBAyCA,IAAI;IA4FzB;;;OAGG;IACU,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAK5C;;;OAGG;WACiB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;IAIxD;;;;OAIG;mBACkB,mBAAmB;WAqB1B,YAAY,IAAI,SAAS,EAAE;IAW5B,aAAa,IAAI,OAAO,CAAC;QACpC,WAAW,EAAE,eAAe,CAAC;QAC7B,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IAyGW,iBAAiB,IAAI,OAAO,CAAC;QACxC,eAAe,EAAE,MAAM,CAAC;QACxB,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;YA0BY,iBAAiB;IAYlB,cAAc,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IA2B5C,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAKzC,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAM5B,uBAAuB,CAClC,kBAAkB,CAAC,EAAE,MAAM,GAC1B,OAAO,CAAC,OAAO,CAAC;IAkBN,cAAc,CACzB,QAAQ,EAAE,iBAAiB,GAC1B,OAAO,CAAC,eAAe,CAAC;IA+Cd,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CA8CxE"}
1
+ {"version":3,"file":"DataStore.d.ts","sourceRoot":"","sources":["../../src/blockchain/DataStore.ts"],"names":[],"mappings":"AAEA,OAAO,EAOL,SAAS,IAAI,eAAe,EAE5B,iBAAiB,EAIlB,MAAM,8BAA8B,CAAC;AAWtC,OAAO,EAAE,eAAe,EAAW,MAAM,UAAU,CAAC;AAGpD,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACzB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAYjD,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,IAAI,CAAoB;gBAEpB,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,wBAAwB;IAqB/D,IAAW,OAAO,IAAI,MAAM,CAE3B;IAED,IAAW,IAAI,IAAI,iBAAiB,CAEnC;IAEM,QAAQ,IAAI,MAAM;IAIlB,QAAQ,IAAI,MAAM;IAIlB,SAAS,IAAI,MAAM;WAMN,cAAc,IAAI,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;WAOtD,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS;WAK1C,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;WAYnC,MAAM,CACxB,MAAM,GAAE,qBAA0B,GACjC,OAAO,CAAC,SAAS,CAAC;mBAyCA,IAAI;IA4FzB;;;OAGG;IACU,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAK5C;;;OAGG;WACiB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;IAIxD;;;;OAIG;mBACkB,mBAAmB;WAqB1B,YAAY,IAAI,SAAS,EAAE;IAW5B,aAAa,IAAI,OAAO,CAAC;QACpC,WAAW,EAAE,eAAe,CAAC;QAC7B,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IAyGW,iBAAiB,IAAI,OAAO,CAAC;QACxC,eAAe,EAAE,MAAM,CAAC;QACxB,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;YA0BY,iBAAiB;IAYlB,cAAc,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IA+C5C,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAKzC,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAM5B,uBAAuB,CAClC,kBAAkB,CAAC,EAAE,MAAM,GAC1B,OAAO,CAAC,OAAO,CAAC;IAkBN,cAAc,CACzB,QAAQ,EAAE,iBAAiB,GAC1B,OAAO,CAAC,eAAe,CAAC;IA+C3B;;;;;OAKG;IACU,qBAAqB,CAChC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAsD7C"}
@@ -18,11 +18,17 @@ const DataIntegrityTree_1 = require("../DataIntegrityTree");
18
18
  const prompts_1 = require("../prompts");
19
19
  const FileCache_1 = require("../utils/FileCache");
20
20
  const DataStoreSerializer_1 = require("./DataStoreSerializer");
21
+ const node_cache_1 = __importDefault(require("node-cache"));
22
+ // Initialize the cache with a TTL of 180 seconds (3 minutes)
23
+ const rootHistoryCache = new node_cache_1.default({ stdTTL: 180 });
21
24
  const stat = (0, util_1.promisify)(fs_1.default.stat);
22
25
  const readdir = (0, util_1.promisify)(fs_1.default.readdir);
23
26
  class DataStore {
24
27
  constructor(storeId, options) {
25
28
  this.storeId = storeId;
29
+ // This will create the manifest file if it doesn't exist
30
+ // might be a hacky way to do this, but it works for now
31
+ this.getRootHistory();
26
32
  let _options;
27
33
  if (options) {
28
34
  _options = options;
@@ -284,18 +290,32 @@ class DataStore {
284
290
  });
285
291
  }
286
292
  async getRootHistory() {
293
+ // Check if the root history is cached for this storeId
294
+ const cachedHistory = rootHistoryCache.get(this.storeId);
295
+ if (cachedHistory) {
296
+ return cachedHistory;
297
+ }
298
+ // Fetch root history from peer if not cached
287
299
  const peer = await FullNodePeer_1.FullNodePeer.connect();
288
300
  const { createdAtHeight, createdAtHash } = await this.getCreationHeight();
289
301
  const { rootHashes, rootHashesTimestamps } = await peer.syncStoreFromLauncherId(Buffer.from(this.storeId, "hex"), createdAtHeight, createdAtHash, true);
290
302
  if (!rootHashes) {
291
303
  return [];
292
304
  }
293
- // TODO: add 3 min cache to thisqwz ~
294
- return rootHashes.map((rootHash, index) => ({
305
+ // Build the root history list
306
+ const rootHistory = rootHashes.map((rootHash, index) => ({
295
307
  root_hash: rootHash.toString("hex"),
296
308
  timestamp: Number(rootHashesTimestamps?.[index].toString()),
297
309
  synced: fs_1.default.existsSync(path_1.default.join(config_1.STORE_PATH, this.storeId, `${rootHash.toString("hex")}.dat`)),
298
310
  }));
311
+ // Store the root history in the cache
312
+ rootHistoryCache.set(this.storeId, rootHistory);
313
+ // Need this for the dataintegrity tree to work properly
314
+ fs_1.default.writeFileSync(path_1.default.join(config_1.STORE_PATH, this.storeId, "manifest.dat"), rootHistory
315
+ .filter((root) => root.synced)
316
+ .map((root) => root.root_hash)
317
+ .join("\n"));
318
+ return rootHistory;
299
319
  }
300
320
  async getMetaData() {
301
321
  const { latestStore } = await this.fetchCoinInfo();
@@ -337,29 +357,42 @@ class DataStore {
337
357
  }
338
358
  return updateStoreResponse.newStore;
339
359
  }
360
+ /**
361
+ * Retrieve the file set for a given root hash and validate file integrity.
362
+ *
363
+ * @param {string} rootHash - The root hash to fetch the file set.
364
+ * @returns {Promise<{ fileName: string, file: string }[]>} - An array of unique file objects.
365
+ */
340
366
  async getFileSetForRootHash(rootHash) {
341
367
  const datFilePath = path_1.default.join(config_1.STORE_PATH, this.storeId, `${rootHash}.dat`);
342
368
  const datFileContent = JSON.parse(fs_1.default.readFileSync(datFilePath, "utf-8"));
343
369
  const heightDatFilePath = path_1.default.join(config_1.STORE_PATH, this.storeId, "height.json");
344
- const filesInvolved = [];
345
- filesInvolved.push(datFilePath);
346
- filesInvolved.push(heightDatFilePath);
370
+ // Use a Set to ensure uniqueness
371
+ const filesInvolved = new Set();
372
+ filesInvolved.add({
373
+ name: "height.json",
374
+ path: "height.json",
375
+ });
347
376
  // Iterate over each file and perform an integrity check
348
377
  for (const [fileKey, fileData] of Object.entries(datFileContent.files)) {
349
- const filePath = (0, hashUtils_1.getFilePathFromSha256)(datFileContent.files[fileKey].sha256, path_1.default.join(config_1.STORE_PATH, this.storeId, "data"));
350
- // Perform the integrity check before adding to the file set
378
+ const filePath = (0, hashUtils_1.getFilePathFromSha256)(datFileContent.files[fileKey].sha256, "data");
379
+ // Perform the integrity check
351
380
  const integrityCheck = await DataIntegrityTree_1.DataIntegrityTree.validateKeyIntegrityWithForeignTree(fileKey, datFileContent.files[fileKey].sha256, datFileContent, rootHash, path_1.default.join(config_1.STORE_PATH, this.storeId, "data"));
352
381
  if (integrityCheck) {
353
- console.log((0, colorette_1.green)(`File ${fileKey} has passed the integrity check.`));
354
- // Add the file to the file set only if the integrity check passes
355
- filesInvolved.push(filePath);
382
+ console.log((0, colorette_1.green)(`✔ File ${fileKey} has passed the integrity check.`));
383
+ // Add the file to the Set
384
+ filesInvolved.add({
385
+ name: Buffer.from(fileKey, "hex").toString("utf-8"),
386
+ path: filePath,
387
+ });
356
388
  }
357
389
  else {
358
390
  console.error((0, colorette_1.red)(`File ${fileKey} failed the integrity check.`));
359
391
  throw new Error(`Integrity check failed for file: ${fileKey}. Aborting.`);
360
392
  }
361
393
  }
362
- return filesInvolved;
394
+ // Convert Set to Array and return
395
+ return Array.from(filesInvolved);
363
396
  }
364
397
  }
365
398
  exports.DataStore = DataStore;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dignetwork/dig-sdk",
3
- "version": "0.0.1-alpha.57",
3
+ "version": "0.0.1-alpha.59",
4
4
  "description": "",
5
5
  "type": "commonjs",
6
6
  "main": "./dist/index.js",