@dignetwork/dig-sdk 0.0.1-alpha.16 → 0.0.1-alpha.18
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.
- package/dist/DataIntegrityTree/DataIntegrityTree.d.ts +1 -1
- package/dist/DataIntegrityTree/DataIntegrityTree.d.ts.map +1 -1
- package/dist/DataIntegrityTree/DataIntegrityTree.js +17 -3
- package/dist/DigNetwork/ContentServer.d.ts +2 -0
- package/dist/DigNetwork/ContentServer.d.ts.map +1 -1
- package/dist/DigNetwork/ContentServer.js +22 -9
- package/dist/utils/directoryUtils.d.ts.map +1 -1
- package/dist/utils/directoryUtils.js +9 -12
- package/package.json +1 -1
|
@@ -106,7 +106,7 @@ declare class DataIntegrityTree {
|
|
|
106
106
|
* @param rootHash - The root hash of the tree. Defaults to the latest root hash.
|
|
107
107
|
* @returns The readable stream for the file.
|
|
108
108
|
*/
|
|
109
|
-
getValueStream(hexKey: string, rootHash?: string | null): Readable;
|
|
109
|
+
getValueStream(hexKey: string, rootHash?: string | null, byteOffset?: number | null, length?: number | null): Readable;
|
|
110
110
|
/**
|
|
111
111
|
* Delete all leaves from the Merkle tree.
|
|
112
112
|
*/
|
|
@@ -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,
|
|
1
|
+
{"version":3,"file":"DataIntegrityTree.d.ts","sourceRoot":"","sources":["../../src/DataIntegrityTree/DataIntegrityTree.ts"],"names":[],"mappings":"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"}
|
|
@@ -423,7 +423,7 @@ class DataIntegrityTree {
|
|
|
423
423
|
* @param rootHash - The root hash of the tree. Defaults to the latest root hash.
|
|
424
424
|
* @returns The readable stream for the file.
|
|
425
425
|
*/
|
|
426
|
-
getValueStream(hexKey, rootHash = null) {
|
|
426
|
+
getValueStream(hexKey, rootHash = null, byteOffset = null, length = null) {
|
|
427
427
|
if (!isHexString(hexKey)) {
|
|
428
428
|
throw new Error("key must be a valid hex string");
|
|
429
429
|
}
|
|
@@ -446,8 +446,22 @@ class DataIntegrityTree {
|
|
|
446
446
|
if (!fs.existsSync(filePath)) {
|
|
447
447
|
throw new Error(`File at path ${filePath} does not exist`);
|
|
448
448
|
}
|
|
449
|
-
|
|
450
|
-
|
|
449
|
+
const fileSize = fs.statSync(filePath).size;
|
|
450
|
+
// Validate offset and length
|
|
451
|
+
if (byteOffset !== null && length !== null) {
|
|
452
|
+
if (byteOffset + length > fileSize) {
|
|
453
|
+
throw new Error(`Offset (${byteOffset}) and length (${length}) exceed the file size (${fileSize}).`);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
// Create the read stream with optional byte range
|
|
457
|
+
const options = {};
|
|
458
|
+
if (byteOffset !== null) {
|
|
459
|
+
options.start = byteOffset;
|
|
460
|
+
}
|
|
461
|
+
if (length !== null && byteOffset !== null) {
|
|
462
|
+
options.end = byteOffset + length - 1; // `end` is inclusive, hence `byteOffset + length - 1`
|
|
463
|
+
}
|
|
464
|
+
const readStream = fs.createReadStream(filePath, options);
|
|
451
465
|
const decompressStream = zlib.createGunzip();
|
|
452
466
|
// Return the combined stream as a generic Readable stream
|
|
453
467
|
return readStream.pipe(decompressStream);
|
|
@@ -3,6 +3,8 @@ import { Readable } from "stream";
|
|
|
3
3
|
export declare class ContentServer {
|
|
4
4
|
private ipAddress;
|
|
5
5
|
private storeId;
|
|
6
|
+
private static certPath;
|
|
7
|
+
private static keyPath;
|
|
6
8
|
private static readonly port;
|
|
7
9
|
constructor(ipAddress: string, storeId: string);
|
|
8
10
|
getKey(key: string, rootHash: string, challengeHex?: string): Promise<string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContentServer.d.ts","sourceRoot":"","sources":["../../src/DigNetwork/ContentServer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ContentServer.d.ts","sourceRoot":"","sources":["../../src/DigNetwork/ContentServer.ts"],"names":[],"mappings":"AACA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAGlC,qBAAa,aAAa;IACxB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAS;IAChC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAS;IAC/B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAQ;gBAExB,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAYjC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAa7E,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;IAepC,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC;IAM5B,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC;IAM9B,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC;IAM9B,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC;IAM5B,OAAO,CAClB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,IAAI,CAAC,mBAAmB,CAAA;KAAE,CAAC;IAMvD,SAAS,IAAI,OAAO,CAAC;QAChC,OAAO,EAAE,OAAO,CAAC;QACjB,OAAO,CAAC,EAAE,IAAI,CAAC,mBAAmB,CAAC;KACpC,CAAC;IAMK,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;YA0ClC,IAAI;YA0EJ,SAAS;YAMT,gBAAgB;YAiChB,KAAK;CA0DpB"}
|
|
@@ -4,17 +4,24 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.ContentServer = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
7
8
|
const http_1 = __importDefault(require("http"));
|
|
8
9
|
const url_1 = require("url");
|
|
10
|
+
const ssl_1 = require("../utils/ssl");
|
|
9
11
|
class ContentServer {
|
|
10
12
|
constructor(ipAddress, storeId) {
|
|
11
13
|
this.ipAddress = ipAddress;
|
|
12
14
|
this.storeId = storeId;
|
|
15
|
+
if (!ContentServer.certPath || !ContentServer.keyPath) {
|
|
16
|
+
const { certPath, keyPath } = (0, ssl_1.getOrCreateSSLCerts)();
|
|
17
|
+
ContentServer.certPath = certPath;
|
|
18
|
+
ContentServer.keyPath = keyPath;
|
|
19
|
+
}
|
|
13
20
|
}
|
|
14
21
|
// Method to get the content of a specified key from the peer, with optional challenge query
|
|
15
22
|
async getKey(key, rootHash, challengeHex) {
|
|
16
23
|
// Construct the base URL
|
|
17
|
-
let url = `
|
|
24
|
+
let url = `https://${this.ipAddress}/chia.${this.storeId}.${rootHash}/${key}`;
|
|
18
25
|
// If a challenge is provided, append it as a query parameter
|
|
19
26
|
if (challengeHex) {
|
|
20
27
|
url += `?challenge=${challengeHex}`;
|
|
@@ -35,38 +42,38 @@ class ContentServer {
|
|
|
35
42
|
}
|
|
36
43
|
// Method to get the .well-known information
|
|
37
44
|
async getWellKnown() {
|
|
38
|
-
const url = `
|
|
45
|
+
const url = `https://${this.ipAddress}/.well-known`;
|
|
39
46
|
return this.fetchJson(url);
|
|
40
47
|
}
|
|
41
48
|
// Method to get the list of known stores
|
|
42
49
|
async getKnownStores() {
|
|
43
|
-
const url = `
|
|
50
|
+
const url = `https://${this.ipAddress}/.well-known/stores`;
|
|
44
51
|
return this.fetchJson(url);
|
|
45
52
|
}
|
|
46
53
|
// Method to get the index of all stores
|
|
47
54
|
async getStoresIndex() {
|
|
48
|
-
const url = `
|
|
55
|
+
const url = `https://${this.ipAddress}/`;
|
|
49
56
|
return this.fetchJson(url);
|
|
50
57
|
}
|
|
51
58
|
// Method to get the index of keys in a store
|
|
52
59
|
async getKeysIndex() {
|
|
53
|
-
const url = `
|
|
60
|
+
const url = `https://${this.ipAddress}/${this.storeId}`;
|
|
54
61
|
return this.fetchJson(url);
|
|
55
62
|
}
|
|
56
63
|
// Method to check if a specific key exists (HEAD request)
|
|
57
64
|
async headKey(key) {
|
|
58
|
-
const url = `
|
|
65
|
+
const url = `https://${this.ipAddress}/${this.storeId}/${key}`;
|
|
59
66
|
return this.head(url); // Return the object from head method
|
|
60
67
|
}
|
|
61
68
|
// Method to check if a specific store exists (HEAD request)
|
|
62
69
|
async headStore() {
|
|
63
|
-
const url = `
|
|
70
|
+
const url = `https://${this.ipAddress}/${this.storeId}`;
|
|
64
71
|
console.log({ url });
|
|
65
72
|
return this.head(url); // Return the object from head method
|
|
66
73
|
}
|
|
67
74
|
streamKey(key) {
|
|
68
75
|
return new Promise((resolve, reject) => {
|
|
69
|
-
const url = `
|
|
76
|
+
const url = `https://${this.ipAddress}/${this.storeId}/${key}`;
|
|
70
77
|
const urlObj = new url_1.URL(url);
|
|
71
78
|
const requestOptions = {
|
|
72
79
|
hostname: urlObj.hostname,
|
|
@@ -111,6 +118,9 @@ class ContentServer {
|
|
|
111
118
|
(urlObj.protocol === "http:" ? 80 : ContentServer.port),
|
|
112
119
|
path: urlObj.pathname + urlObj.search,
|
|
113
120
|
method: "HEAD",
|
|
121
|
+
key: fs_1.default.readFileSync(ContentServer.keyPath),
|
|
122
|
+
cert: fs_1.default.readFileSync(ContentServer.certPath),
|
|
123
|
+
rejectUnauthorized: false,
|
|
114
124
|
};
|
|
115
125
|
const request = http_1.default.request(requestOptions, (response) => {
|
|
116
126
|
const { statusCode, headers } = response;
|
|
@@ -201,6 +211,9 @@ class ContentServer {
|
|
|
201
211
|
port: urlObj.port || ContentServer.port,
|
|
202
212
|
path: urlObj.pathname + urlObj.search, // Include query params
|
|
203
213
|
method: "GET",
|
|
214
|
+
key: fs_1.default.readFileSync(ContentServer.keyPath),
|
|
215
|
+
cert: fs_1.default.readFileSync(ContentServer.certPath),
|
|
216
|
+
rejectUnauthorized: false,
|
|
204
217
|
};
|
|
205
218
|
const request = http_1.default.request(requestOptions, (response) => {
|
|
206
219
|
let data = "";
|
|
@@ -240,4 +253,4 @@ class ContentServer {
|
|
|
240
253
|
}
|
|
241
254
|
}
|
|
242
255
|
exports.ContentServer = ContentServer;
|
|
243
|
-
ContentServer.port =
|
|
256
|
+
ContentServer.port = 4161;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"directoryUtils.d.ts","sourceRoot":"","sources":["../../src/utils/directoryUtils.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"directoryUtils.d.ts","sourceRoot":"","sources":["../../src/utils/directoryUtils.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AA+BzD,eAAO,MAAM,YAAY,cACZ,iBAAiB,WACnB,MAAM,YACN,MAAM,KACd,OAAO,CAAC,IAAI,CA4Cd,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,eAAgB,MAAM,KAAG,MAiBxD,CAAC"}
|
|
@@ -32,22 +32,23 @@ const fs = __importStar(require("fs"));
|
|
|
32
32
|
const ignore_1 = __importDefault(require("ignore"));
|
|
33
33
|
// Custom concurrency handler
|
|
34
34
|
const limitConcurrency = async (concurrencyLimit, tasks) => {
|
|
35
|
-
const results = [];
|
|
36
35
|
const executing = [];
|
|
37
36
|
for (const task of tasks) {
|
|
38
37
|
const p = task();
|
|
39
|
-
|
|
38
|
+
// Add the new task to the executing array
|
|
39
|
+
executing.push(p);
|
|
40
|
+
// When a task completes, remove it from the executing array
|
|
41
|
+
const cleanup = p.finally(() => {
|
|
42
|
+
executing.splice(executing.indexOf(cleanup), 1);
|
|
43
|
+
});
|
|
40
44
|
// Once the limit is reached, wait for one to complete
|
|
41
45
|
if (executing.length >= concurrencyLimit) {
|
|
46
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
42
47
|
await Promise.race(executing);
|
|
43
48
|
}
|
|
44
|
-
// Add the new task to the executing array
|
|
45
|
-
executing.push(p);
|
|
46
|
-
// When a task completes, remove it from the executing array
|
|
47
|
-
p.finally(() => executing.splice(executing.indexOf(p), 1));
|
|
48
49
|
}
|
|
49
50
|
// Wait for all remaining tasks to complete
|
|
50
|
-
return Promise.all(
|
|
51
|
+
return Promise.all(executing);
|
|
51
52
|
};
|
|
52
53
|
const addDirectory = async (datalayer, dirPath, baseDir = dirPath) => {
|
|
53
54
|
const ig = (0, ignore_1.default)();
|
|
@@ -77,14 +78,10 @@ const addDirectory = async (datalayer, dirPath, baseDir = dirPath) => {
|
|
|
77
78
|
const stream = fs.createReadStream(filePath);
|
|
78
79
|
datalayer
|
|
79
80
|
.upsertKey(stream, Buffer.from(relativePath).toString("hex"))
|
|
80
|
-
.then(
|
|
81
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
82
|
-
resolve();
|
|
83
|
-
})
|
|
81
|
+
.then(() => resolve())
|
|
84
82
|
.catch(reject);
|
|
85
83
|
}));
|
|
86
84
|
}
|
|
87
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
88
85
|
}
|
|
89
86
|
// Run tasks with limited concurrency (set the concurrency limit as needed)
|
|
90
87
|
await limitConcurrency(10, tasks); // Adjust 10 based on your system limits
|