@dignetwork/dig-sdk 0.0.1-alpha.17 → 0.0.1-alpha.170

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 (84) hide show
  1. package/dist/DataIntegrityTree/DataIntegrityTree.d.ts +10 -1
  2. package/dist/DataIntegrityTree/DataIntegrityTree.d.ts.map +1 -1
  3. package/dist/DataIntegrityTree/DataIntegrityTree.js +77 -10
  4. package/dist/DigNetwork/ContentServer.d.ts +24 -5
  5. package/dist/DigNetwork/ContentServer.d.ts.map +1 -1
  6. package/dist/DigNetwork/ContentServer.js +239 -27
  7. package/dist/DigNetwork/DigNetwork.d.ts +15 -9
  8. package/dist/DigNetwork/DigNetwork.d.ts.map +1 -1
  9. package/dist/DigNetwork/DigNetwork.js +129 -189
  10. package/dist/DigNetwork/DigPeer.d.ts +8 -3
  11. package/dist/DigNetwork/DigPeer.d.ts.map +1 -1
  12. package/dist/DigNetwork/DigPeer.js +72 -115
  13. package/dist/DigNetwork/IncentiveServer.d.ts.map +1 -1
  14. package/dist/DigNetwork/IncentiveServer.js +6 -5
  15. package/dist/DigNetwork/PropagationServer.d.ts +88 -33
  16. package/dist/DigNetwork/PropagationServer.d.ts.map +1 -1
  17. package/dist/DigNetwork/PropagationServer.js +636 -357
  18. package/dist/blockchain/DataStore.d.ts +25 -7
  19. package/dist/blockchain/DataStore.d.ts.map +1 -1
  20. package/dist/blockchain/DataStore.js +115 -159
  21. package/dist/blockchain/DataStoreSerializer.d.ts +1 -1
  22. package/dist/blockchain/DataStoreSerializer.d.ts.map +1 -1
  23. package/dist/blockchain/FullNodePeer.d.ts +95 -10
  24. package/dist/blockchain/FullNodePeer.d.ts.map +1 -1
  25. package/dist/blockchain/FullNodePeer.js +324 -115
  26. package/dist/blockchain/ServerCoin.d.ts +13 -5
  27. package/dist/blockchain/ServerCoin.d.ts.map +1 -1
  28. package/dist/blockchain/ServerCoin.js +90 -28
  29. package/dist/blockchain/StoreMonitorRegistry.d.ts +85 -0
  30. package/dist/blockchain/StoreMonitorRegistry.d.ts.map +1 -0
  31. package/dist/blockchain/StoreMonitorRegistry.js +238 -0
  32. package/dist/blockchain/Wallet.d.ts +2 -2
  33. package/dist/blockchain/Wallet.d.ts.map +1 -1
  34. package/dist/blockchain/Wallet.js +50 -18
  35. package/dist/blockchain/coins.d.ts +1 -2
  36. package/dist/blockchain/coins.d.ts.map +1 -1
  37. package/dist/blockchain/coins.js +1 -55
  38. package/dist/blockchain/index.d.ts +1 -0
  39. package/dist/blockchain/index.d.ts.map +1 -1
  40. package/dist/blockchain/index.js +1 -0
  41. package/dist/types.d.ts +2 -0
  42. package/dist/types.d.ts.map +1 -1
  43. package/dist/utils/ContentScanner.d.ts +63 -0
  44. package/dist/utils/ContentScanner.d.ts.map +1 -0
  45. package/dist/utils/ContentScanner.js +175 -0
  46. package/dist/utils/Environment.d.ts +21 -0
  47. package/dist/utils/Environment.d.ts.map +1 -0
  48. package/dist/utils/Environment.js +93 -0
  49. package/dist/utils/FileCache.d.ts +1 -1
  50. package/dist/utils/FileCache.d.ts.map +1 -1
  51. package/dist/utils/FileCache.js +2 -2
  52. package/dist/utils/FileTransfer.d.ts +47 -0
  53. package/dist/utils/FileTransfer.d.ts.map +1 -0
  54. package/dist/utils/FileTransfer.js +209 -0
  55. package/dist/utils/NconfManager.js +2 -1
  56. package/dist/utils/PeerRanker.d.ts +55 -0
  57. package/dist/utils/PeerRanker.d.ts.map +1 -0
  58. package/dist/utils/PeerRanker.js +186 -0
  59. package/dist/utils/StoreArchiveManager.d.ts +45 -0
  60. package/dist/utils/StoreArchiveManager.d.ts.map +1 -0
  61. package/dist/utils/StoreArchiveManager.js +153 -0
  62. package/dist/utils/config.d.ts +4 -3
  63. package/dist/utils/config.d.ts.map +1 -1
  64. package/dist/utils/config.js +13 -8
  65. package/dist/utils/directoryUtils.d.ts +16 -0
  66. package/dist/utils/directoryUtils.d.ts.map +1 -1
  67. package/dist/utils/directoryUtils.js +66 -0
  68. package/dist/utils/index.d.ts +3 -1
  69. package/dist/utils/index.d.ts.map +1 -1
  70. package/dist/utils/index.js +3 -1
  71. package/dist/utils/merkle.d.ts +2 -0
  72. package/dist/utils/merkle.d.ts.map +1 -0
  73. package/dist/utils/merkle.js +28 -0
  74. package/dist/utils/network.d.ts +2 -1
  75. package/dist/utils/network.d.ts.map +1 -1
  76. package/dist/utils/network.js +40 -15
  77. package/dist/utils/promiseUtils.d.ts +19 -0
  78. package/dist/utils/promiseUtils.d.ts.map +1 -0
  79. package/dist/utils/promiseUtils.js +43 -0
  80. package/dist/utils/ssl.js +2 -2
  81. package/package.json +18 -5
  82. package/dist/utils/deltaUtils.d.ts +0 -2
  83. package/dist/utils/deltaUtils.d.ts.map +0 -1
  84. package/dist/utils/deltaUtils.js +0 -83
@@ -38,9 +38,10 @@ const chia_root_resolver_1 = require("chia-root-resolver");
38
38
  const chia_config_loader_1 = require("chia-config-loader");
39
39
  const encryption_1 = require("../utils/encryption");
40
40
  const buffer_1 = require("buffer");
41
- const datalayer_driver_1 = require("datalayer-driver");
41
+ const datalayer_driver_1 = require("@dignetwork/datalayer-driver");
42
42
  const config_1 = require("../utils/config");
43
43
  const FileCache_1 = require("../utils/FileCache");
44
+ const config_2 = require("../utils/config");
44
45
  const KEYRING_FILE = "keyring.json";
45
46
  const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
46
47
  exports.DEFAULT_FEE_COIN_COST = 64000000;
@@ -174,31 +175,62 @@ class Wallet {
174
175
  const signature = (0, datalayer_driver_1.signMessage)(buffer_1.Buffer.from(message, "utf-8"), privateSyntheticKey);
175
176
  return signature.toString("hex");
176
177
  }
177
- async verifyKeyOwnershipSignature(nonce, signature, publicKey) {
178
+ static async verifyKeyOwnershipSignature(nonce, signature, publicKey) {
178
179
  const message = `Signing this message to prove ownership of key.\n\nNonce: ${nonce}`;
179
180
  return (0, datalayer_driver_1.verifySignedMessage)(buffer_1.Buffer.from(signature, "hex"), buffer_1.Buffer.from(publicKey, "hex"), buffer_1.Buffer.from(message, "utf-8"));
180
181
  }
181
182
  async selectUnspentCoins(peer, coinAmount, feeBigInt, omitCoins = []) {
182
- const cache = new FileCache_1.FileCache("reserved_coins");
183
- const cachedReservedCoins = cache.getCachedKeys();
184
- const now = Date.now();
185
- const omitCoinIds = omitCoins.map((coin) => (0, datalayer_driver_1.getCoinId)(coin).toString("hex"));
186
- cachedReservedCoins.forEach((coinId) => {
187
- const reservation = cache.get(coinId);
188
- if (reservation && reservation.expiry > now) {
189
- omitCoinIds.push(coinId);
183
+ const cache = new FileCache_1.FileCache("reserved_coins", config_2.USER_DIR_PATH);
184
+ const ownerPuzzleHash = await this.getOwnerPuzzleHash();
185
+ // Define a function to attempt selecting unspent coins
186
+ const trySelectCoins = async () => {
187
+ const now = Date.now();
188
+ const omitCoinIds = omitCoins.map((coin) => (0, datalayer_driver_1.getCoinId)(coin).toString("hex"));
189
+ // Update omitCoinIds with currently valid reserved coins
190
+ const cachedReservedCoins = cache.getCachedKeys();
191
+ cachedReservedCoins.forEach((coinId) => {
192
+ const reservation = cache.get(coinId);
193
+ if (reservation && reservation.expiry > now) {
194
+ if (!omitCoinIds.includes(coinId)) {
195
+ omitCoinIds.push(coinId);
196
+ }
197
+ }
198
+ else {
199
+ cache.delete(coinId);
200
+ }
201
+ });
202
+ const coinsResp = await peer.getAllUnspentCoins(ownerPuzzleHash, config_1.MIN_HEIGHT, buffer_1.Buffer.from(config_1.MIN_HEIGHT_HEADER_HASH, "hex"));
203
+ const unspentCoins = coinsResp.coins.filter((coin) => !omitCoinIds.includes((0, datalayer_driver_1.getCoinId)(coin).toString("hex")));
204
+ const selectedCoins = (0, datalayer_driver_1.selectCoins)(unspentCoins, feeBigInt + coinAmount);
205
+ return selectedCoins;
206
+ };
207
+ let selectedCoins = [];
208
+ let retry = true;
209
+ while (retry) {
210
+ selectedCoins = await trySelectCoins();
211
+ if (selectedCoins.length > 0) {
212
+ // Coins have been successfully selected
213
+ retry = false;
190
214
  }
191
215
  else {
192
- cache.delete(coinId);
216
+ const now = Date.now();
217
+ // Check if there are any valid cached reserved coins left
218
+ const cachedReservedCoins = cache.getCachedKeys().filter((coinId) => {
219
+ const reservation = cache.get(coinId);
220
+ return reservation && reservation.expiry > now;
221
+ });
222
+ if (cachedReservedCoins.length > 0) {
223
+ // Wait 10 seconds and try again
224
+ console.log("No unspent coins available. Waiting 10 seconds...");
225
+ await new Promise((resolve) => setTimeout(resolve, 10000));
226
+ }
227
+ else {
228
+ // No unspent coins and no reserved coins
229
+ throw new Error("No unspent coins available.");
230
+ }
193
231
  }
194
- });
195
- const ownerPuzzleHash = await this.getOwnerPuzzleHash();
196
- const coinsResp = await peer.getAllUnspentCoins(ownerPuzzleHash, config_1.MIN_HEIGHT, buffer_1.Buffer.from(config_1.MIN_HEIGHT_HEADER_HASH, "hex"));
197
- const unspentCoins = coinsResp.coins.filter((coin) => !omitCoinIds.includes((0, datalayer_driver_1.getCoinId)(coin).toString("hex")));
198
- const selectedCoins = (0, datalayer_driver_1.selectCoins)(unspentCoins, feeBigInt + coinAmount);
199
- if (selectedCoins.length === 0) {
200
- throw new Error("No unspent coins available.");
201
232
  }
233
+ // Reserve the selected coins
202
234
  selectedCoins.forEach((coin) => {
203
235
  const coinId = (0, datalayer_driver_1.getCoinId)(coin).toString("hex");
204
236
  cache.set(coinId, { coinId, expiry: Date.now() + CACHE_DURATION });
@@ -1,6 +1,5 @@
1
- import { Peer, Coin, CoinSpend } from "datalayer-driver";
1
+ import { Peer, CoinSpend } from "@dignetwork/datalayer-driver";
2
2
  export declare const DEFAULT_FEE_COIN_COST = 64000000;
3
3
  export declare const calculateFeeForCoinSpends: (peer: Peer, coinSpends: CoinSpend[] | null) => Promise<bigint>;
4
- export declare const selectUnspentCoins: (peer: Peer, coinAmount: bigint, feeBigInt: bigint, omitCoins?: Coin[], walletName?: string) => Promise<Coin[]>;
5
4
  export declare const isCoinSpendable: (peer: Peer, coinId: Buffer) => Promise<boolean>;
6
5
  //# sourceMappingURL=coins.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"coins.d.ts","sourceRoot":"","sources":["../../src/blockchain/coins.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,IAAI,EACJ,IAAI,EAEJ,SAAS,EAEV,MAAM,kBAAkB,CAAC;AAK1B,eAAO,MAAM,qBAAqB,WAAa,CAAC;AAWhD,eAAO,MAAM,yBAAyB,SAC9B,IAAI,cACE,SAAS,EAAE,GAAG,IAAI,KAC7B,OAAO,CAAC,MAAM,CA4BhB,CAAC;AAEF,eAAO,MAAM,kBAAkB,SACvB,IAAI,cACE,MAAM,aACP,MAAM,cACN,IAAI,EAAE,eACL,MAAM,KACjB,OAAO,CAAC,IAAI,EAAE,CAoEhB,CAAC;AAGF,eAAO,MAAM,eAAe,SACpB,IAAI,UACF,MAAM,KACb,OAAO,CAAC,OAAO,CAWjB,CAAC"}
1
+ {"version":3,"file":"coins.d.ts","sourceRoot":"","sources":["../../src/blockchain/coins.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,IAAI,EAGJ,SAAS,EAEV,MAAM,8BAA8B,CAAC;AAMtC,eAAO,MAAM,qBAAqB,WAAa,CAAC;AAWhD,eAAO,MAAM,yBAAyB,SAC9B,IAAI,cACE,SAAS,EAAE,GAAG,IAAI,KAC7B,OAAO,CAAC,MAAM,CA4BhB,CAAC;AAEF,eAAO,MAAM,eAAe,SACpB,IAAI,UACF,MAAM,KACb,OAAO,CAAC,OAAO,CAWjB,CAAC"}
@@ -1,10 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isCoinSpendable = exports.selectUnspentCoins = exports.calculateFeeForCoinSpends = exports.DEFAULT_FEE_COIN_COST = void 0;
4
- const datalayer_driver_1 = require("datalayer-driver");
5
- const Wallet_1 = require("./Wallet");
3
+ exports.isCoinSpendable = exports.calculateFeeForCoinSpends = exports.DEFAULT_FEE_COIN_COST = void 0;
6
4
  const config_1 = require("../utils/config");
7
- const FileCache_1 = require("../utils/FileCache");
8
5
  exports.DEFAULT_FEE_COIN_COST = 64000000;
9
6
  // Set cache expiration time (5 minutes)
10
7
  const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes in milliseconds
@@ -38,57 +35,6 @@ const calculateFeeForCoinSpends = async (peer, coinSpends) => {
38
35
  */
39
36
  };
40
37
  exports.calculateFeeForCoinSpends = calculateFeeForCoinSpends;
41
- const selectUnspentCoins = async (peer, coinAmount, feeBigInt, omitCoins = [], walletName = "default") => {
42
- // Initialize the cache for reserved coins
43
- const cache = new FileCache_1.FileCache("reserved_coins");
44
- // Get all cached reserved coins
45
- const cachedReservedCoins = cache.getCachedKeys();
46
- // Filter expired reserved coins and omit valid reservations
47
- const now = Date.now();
48
- const omitCoinIds = omitCoins.map((coin) => (0, datalayer_driver_1.getCoinId)(coin).toString("hex"));
49
- const validReservedCoins = cachedReservedCoins.filter((coinId) => {
50
- const reservation = cache.get(coinId);
51
- if (reservation && reservation.expiry > now) {
52
- // Valid reservation, add to omit list
53
- omitCoinIds.push(coinId);
54
- return true;
55
- }
56
- else {
57
- // Reservation expired, remove it
58
- cache.delete(coinId);
59
- return false;
60
- }
61
- });
62
- // Fetch all unspent coins from the peer
63
- const wallet = await Wallet_1.Wallet.load(walletName);
64
- const ownerPuzzleHash = await wallet.getOwnerPuzzleHash();
65
- const coinsResp = await peer.getAllUnspentCoins(ownerPuzzleHash, config_1.MIN_HEIGHT, Buffer.from(config_1.MIN_HEIGHT_HEADER_HASH, "hex"));
66
- if (process.env.DIG_DEBUG === "1") {
67
- console.log("Unspent Coins:", coinsResp); // Debugging
68
- }
69
- const unspentCoins = coinsResp.coins;
70
- // Filter out the omitted coins
71
- const filteredUnspentCoins = unspentCoins.filter((coin) => !omitCoinIds.includes((0, datalayer_driver_1.getCoinId)(coin).toString("hex")));
72
- if (process.env.DIG_DEBUG === "1") {
73
- console.log("Unspent Coins after filtering:", filteredUnspentCoins); // Debugging
74
- }
75
- // Select coins needed for the transaction
76
- const selectedCoins = (0, datalayer_driver_1.selectCoins)(filteredUnspentCoins, feeBigInt + coinAmount);
77
- if (process.env.DIG_DEBUG === "1") {
78
- console.log("Selected Coins:", selectedCoins); // Debugging
79
- }
80
- // If no coins are selected, throw an error
81
- if (selectedCoins.length === 0) {
82
- throw new Error("No unspent coins available.");
83
- }
84
- // Cache the selected coins as reserved for the next 5 minutes
85
- selectedCoins.forEach((coin) => {
86
- const coinId = (0, datalayer_driver_1.getCoinId)(coin).toString("hex");
87
- cache.set(coinId, { coinId, expiry: Date.now() + CACHE_DURATION });
88
- });
89
- return selectedCoins;
90
- };
91
- exports.selectUnspentCoins = selectUnspentCoins;
92
38
  const isCoinSpendable = async (peer, coinId) => {
93
39
  try {
94
40
  const spent = await peer.isCoinSpent(coinId, config_1.MIN_HEIGHT, Buffer.from(config_1.MIN_HEIGHT_HEADER_HASH, "hex"));
@@ -5,4 +5,5 @@ export * from './FullNodePeer';
5
5
  export * from './DataStoreSerializer';
6
6
  export * from './ServerCoin';
7
7
  export * from "./Wallet";
8
+ export * from './StoreMonitorRegistry';
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/blockchain/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAa,gBAAgB,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/blockchain/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAa,gBAAgB,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,wBAAwB,CAAC"}
@@ -34,3 +34,4 @@ __exportStar(require("./FullNodePeer"), exports);
34
34
  __exportStar(require("./DataStoreSerializer"), exports);
35
35
  __exportStar(require("./ServerCoin"), exports);
36
36
  __exportStar(require("./Wallet"), exports);
37
+ __exportStar(require("./StoreMonitorRegistry"), exports);
package/dist/types.d.ts CHANGED
@@ -23,6 +23,7 @@ export interface DigConfig {
23
23
  export interface RootHistoryItem {
24
24
  root_hash: string;
25
25
  timestamp: Number | undefined;
26
+ synced: boolean;
26
27
  }
27
28
  export interface DatFile {
28
29
  root: string;
@@ -47,6 +48,7 @@ export interface ServerCoinData {
47
48
  coin: CoinData;
48
49
  createdAt: string;
49
50
  epoch: number;
51
+ rootHash: string;
50
52
  }
51
53
  export interface IncentiveProgramData {
52
54
  storeId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,MAAM;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE;QACL,CAAC,GAAG,EAAE,MAAM,GAAG;YACb,IAAI,EAAE,MAAM,CAAC;YACb,MAAM,EAAE,MAAM,CAAC;SAChB,CAAC;KACH,CAAC;CACH;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,QAAQ,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,cAAc,CAAC;CAC9B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,MAAM;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE;QACL,CAAC,GAAG,EAAE,MAAM,GAAG;YACb,IAAI,EAAE,MAAM,CAAC;YACb,MAAM,EAAE,MAAM,CAAC;SAChB,CAAC;KACH,CAAC;CACH;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,QAAQ,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,cAAc,CAAC;CAC9B"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * @class IllegalContentScanner
3
+ * Scans files for illegal content using ClamAV running in a Docker container and deletes files if flagged.
4
+ */
5
+ export declare class IllegalContentScanner {
6
+ private clamAVContainerName;
7
+ private virusTotalApiKey?;
8
+ private openAiApiKey?;
9
+ /**
10
+ * @constructor
11
+ * @param clamAVContainerName The name of the Docker container running ClamAV (default: 'clamav').
12
+ */
13
+ constructor(clamAVContainerName?: string);
14
+ /**
15
+ * Scans a file for illegal content using ClamAV, VirusTotal, and OpenAI Moderation API.
16
+ * If a service is missing its API key, the scan for that service is skipped.
17
+ * @param filePath The path of the file to scan.
18
+ * @returns {Promise<void>} A promise that resolves after the scan and potential deletion.
19
+ */
20
+ scanFile(filePath: string): Promise<void>;
21
+ /**
22
+ * Scans a file using ClamAV running in Docker.
23
+ * @param filePath The path of the file to scan.
24
+ * @returns {Promise<string>} The result of the ClamAV scan.
25
+ */
26
+ private scanWithClamAV;
27
+ /**
28
+ * Submits a file to VirusTotal for scanning.
29
+ * @param filePath The path of the file to scan.
30
+ * @returns {Promise<any>} The result from VirusTotal.
31
+ */
32
+ private scanWithVirusTotal;
33
+ /**
34
+ * Scans file content (text) using OpenAI's Moderation API.
35
+ * @param content The text content to scan.
36
+ * @returns {Promise<any>} The result from OpenAI's Moderation API.
37
+ */
38
+ private scanWithOpenAI;
39
+ /**
40
+ * Checks if the ClamAV scan result indicates a malicious file.
41
+ * @param result The ClamAV scan output.
42
+ * @returns {boolean} True if the file is flagged, false otherwise.
43
+ */
44
+ private isClamAVResultMalicious;
45
+ /**
46
+ * Checks if the VirusTotal result indicates a malicious file.
47
+ * @param result The VirusTotal scan result.
48
+ * @returns {boolean} True if the file is flagged, false otherwise.
49
+ */
50
+ private isVirusTotalResultMalicious;
51
+ /**
52
+ * Checks if the OpenAI Moderation result indicates harmful content.
53
+ * @param result The OpenAI Moderation result.
54
+ * @returns {boolean} True if harmful content is detected, false otherwise.
55
+ */
56
+ private isOpenAiResultMalicious;
57
+ /**
58
+ * Deletes a file from the filesystem.
59
+ * @param filePath The file to delete.
60
+ */
61
+ private deleteFile;
62
+ }
63
+ //# sourceMappingURL=ContentScanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ContentScanner.d.ts","sourceRoot":"","sources":["../../src/utils/ContentScanner.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,qBAAa,qBAAqB;IAC9B,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,gBAAgB,CAAC,CAAS;IAClC,OAAO,CAAC,YAAY,CAAC,CAAS;IAE9B;;;OAGG;gBACS,mBAAmB,GAAE,MAAiB;IAMlD;;;;;OAKG;IACU,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqDtD;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAYtB;;;;OAIG;YACW,kBAAkB;IAgBhC;;;;OAIG;YACW,cAAc;IAa5B;;;;OAIG;IACH,OAAO,CAAC,uBAAuB;IAI/B;;;;OAIG;IACH,OAAO,CAAC,2BAA2B;IAKnC;;;;OAIG;IACH,OAAO,CAAC,uBAAuB;IAI/B;;;OAGG;IACH,OAAO,CAAC,UAAU;CASrB"}
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.IllegalContentScanner = void 0;
7
+ const child_process_1 = require("child_process");
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const axios_1 = __importDefault(require("axios"));
11
+ /**
12
+ * @class IllegalContentScanner
13
+ * Scans files for illegal content using ClamAV running in a Docker container and deletes files if flagged.
14
+ */
15
+ class IllegalContentScanner {
16
+ /**
17
+ * @constructor
18
+ * @param clamAVContainerName The name of the Docker container running ClamAV (default: 'clamav').
19
+ */
20
+ constructor(clamAVContainerName = "clamav") {
21
+ this.clamAVContainerName = clamAVContainerName;
22
+ this.virusTotalApiKey = process.env.VIRUSTOTAL_API_KEY || undefined;
23
+ this.openAiApiKey = process.env.OPENAI_API_KEY || undefined;
24
+ }
25
+ /**
26
+ * Scans a file for illegal content using ClamAV, VirusTotal, and OpenAI Moderation API.
27
+ * If a service is missing its API key, the scan for that service is skipped.
28
+ * @param filePath The path of the file to scan.
29
+ * @returns {Promise<void>} A promise that resolves after the scan and potential deletion.
30
+ */
31
+ async scanFile(filePath) {
32
+ try {
33
+ // 1. ClamAV Scan
34
+ console.log(`Starting ClamAV scan for file: ${filePath}`);
35
+ const clamAvResult = await this.scanWithClamAV(filePath);
36
+ if (this.isClamAVResultMalicious(clamAvResult)) {
37
+ console.log(`ClamAV flagged file: ${filePath}. Deleting...`);
38
+ this.deleteFile(filePath);
39
+ return;
40
+ }
41
+ else {
42
+ console.log(`ClamAV did not flag the file: ${filePath}.`);
43
+ }
44
+ // 2. VirusTotal Scan (if API key is provided)
45
+ if (this.virusTotalApiKey) {
46
+ console.log(`Submitting file to VirusTotal for scanning: ${filePath}`);
47
+ const virusTotalResult = await this.scanWithVirusTotal(filePath);
48
+ if (this.isVirusTotalResultMalicious(virusTotalResult)) {
49
+ console.log(`VirusTotal flagged file: ${filePath}. Deleting...`);
50
+ this.deleteFile(filePath);
51
+ return;
52
+ }
53
+ else {
54
+ console.log(`VirusTotal did not flag the file: ${filePath}.`);
55
+ }
56
+ }
57
+ else {
58
+ console.log(`VirusTotal API key not provided. Skipping VirusTotal scan.`);
59
+ }
60
+ // 3. OpenAI Moderation API (if API key is provided and file is text-based)
61
+ const fileExtension = path_1.default.extname(filePath).toLowerCase();
62
+ if (this.openAiApiKey && (fileExtension === ".txt" || fileExtension === ".json")) {
63
+ console.log(`Scanning file content with OpenAI Moderation API: ${filePath}`);
64
+ const fileContent = await fs_1.default.promises.readFile(filePath, "utf-8");
65
+ const openAiResult = await this.scanWithOpenAI(fileContent);
66
+ if (this.isOpenAiResultMalicious(openAiResult)) {
67
+ console.log(`OpenAI flagged file: ${filePath}. Deleting...`);
68
+ this.deleteFile(filePath);
69
+ return;
70
+ }
71
+ }
72
+ else {
73
+ if (!this.openAiApiKey) {
74
+ console.log(`OpenAI API key not provided. Skipping OpenAI scan.`);
75
+ }
76
+ else {
77
+ console.log(`OpenAI scan skipped: File type not supported (${fileExtension}).`);
78
+ }
79
+ }
80
+ console.log(`File ${filePath} passed all multilayer scans.`);
81
+ }
82
+ catch (error) {
83
+ console.error(`Error scanning file: ${filePath}`, error);
84
+ }
85
+ }
86
+ /**
87
+ * Scans a file using ClamAV running in Docker.
88
+ * @param filePath The path of the file to scan.
89
+ * @returns {Promise<string>} The result of the ClamAV scan.
90
+ */
91
+ scanWithClamAV(filePath) {
92
+ return new Promise((resolve, reject) => {
93
+ (0, child_process_1.exec)(`docker exec ${this.clamAVContainerName} clamdscan ${filePath}`, (error, stdout, stderr) => {
94
+ if (error) {
95
+ reject(`ClamAV scan error: ${stderr}`);
96
+ }
97
+ else {
98
+ resolve(stdout);
99
+ }
100
+ });
101
+ });
102
+ }
103
+ /**
104
+ * Submits a file to VirusTotal for scanning.
105
+ * @param filePath The path of the file to scan.
106
+ * @returns {Promise<any>} The result from VirusTotal.
107
+ */
108
+ async scanWithVirusTotal(filePath) {
109
+ const fileContent = await fs_1.default.promises.readFile(filePath);
110
+ const formData = new FormData();
111
+ // @ts-ignore
112
+ formData.append("file", fileContent);
113
+ const response = await axios_1.default.post("https://www.virustotal.com/vtapi/v2/file/scan", formData, {
114
+ headers: {
115
+ "x-apikey": this.virusTotalApiKey,
116
+ // @ts-ignore
117
+ ...formData.getHeaders(),
118
+ },
119
+ });
120
+ return response.data;
121
+ }
122
+ /**
123
+ * Scans file content (text) using OpenAI's Moderation API.
124
+ * @param content The text content to scan.
125
+ * @returns {Promise<any>} The result from OpenAI's Moderation API.
126
+ */
127
+ async scanWithOpenAI(content) {
128
+ const response = await axios_1.default.post("https://api.openai.com/v1/moderations", { input: content }, {
129
+ headers: {
130
+ Authorization: `Bearer ${this.openAiApiKey}`,
131
+ },
132
+ });
133
+ return response.data;
134
+ }
135
+ /**
136
+ * Checks if the ClamAV scan result indicates a malicious file.
137
+ * @param result The ClamAV scan output.
138
+ * @returns {boolean} True if the file is flagged, false otherwise.
139
+ */
140
+ isClamAVResultMalicious(result) {
141
+ return result.includes("FOUND");
142
+ }
143
+ /**
144
+ * Checks if the VirusTotal result indicates a malicious file.
145
+ * @param result The VirusTotal scan result.
146
+ * @returns {boolean} True if the file is flagged, false otherwise.
147
+ */
148
+ isVirusTotalResultMalicious(result) {
149
+ // Check if VirusTotal flagged the file based on its multiple antivirus results
150
+ return result.positives > 0;
151
+ }
152
+ /**
153
+ * Checks if the OpenAI Moderation result indicates harmful content.
154
+ * @param result The OpenAI Moderation result.
155
+ * @returns {boolean} True if harmful content is detected, false otherwise.
156
+ */
157
+ isOpenAiResultMalicious(result) {
158
+ return result.flagged === true;
159
+ }
160
+ /**
161
+ * Deletes a file from the filesystem.
162
+ * @param filePath The file to delete.
163
+ */
164
+ deleteFile(filePath) {
165
+ fs_1.default.unlink(filePath, (err) => {
166
+ if (err) {
167
+ console.error(`Error deleting file: ${filePath}`, err);
168
+ }
169
+ else {
170
+ console.log(`File ${filePath} was deleted successfully.`);
171
+ }
172
+ });
173
+ }
174
+ }
175
+ exports.IllegalContentScanner = IllegalContentScanner;
@@ -0,0 +1,21 @@
1
+ export declare class Environment {
2
+ private static cliMode;
3
+ private static isValidIp;
4
+ private static isValidHostnameOrIp;
5
+ private static isValidPort;
6
+ private static isValidFilePath;
7
+ private static getNumberEnvVar;
8
+ static get DIG_USERNAME(): string | undefined;
9
+ static get DIG_PASSWORD(): string | undefined;
10
+ static get TRUSTED_FULLNODE(): string | undefined;
11
+ static get TRUSTED_FULLNODE_PORT(): number | undefined;
12
+ static get PUBLIC_IP(): string | undefined;
13
+ static get DISK_SPACE_LIMIT_BYTES(): number | undefined;
14
+ static get MERCENARY_MODE(): boolean | undefined;
15
+ static get DEBUG(): boolean | undefined;
16
+ static get DIG_FOLDER_PATH(): string | undefined;
17
+ static get REMOTE_NODE(): boolean | undefined;
18
+ static set CLI_MODE(mode: boolean);
19
+ static get CLI_MODE(): boolean | undefined;
20
+ }
21
+ //# sourceMappingURL=Environment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Environment.d.ts","sourceRoot":"","sources":["../../src/utils/Environment.ts"],"names":[],"mappings":"AAGA,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAC,OAAO,CAAkB;IAGxC,OAAO,CAAC,MAAM,CAAC,SAAS;IAOxB,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAUlC,OAAO,CAAC,MAAM,CAAC,WAAW;IAK1B,OAAO,CAAC,MAAM,CAAC,eAAe;IAK9B,OAAO,CAAC,MAAM,CAAC,eAAe;IAO9B,MAAM,KAAK,YAAY,IAAI,MAAM,GAAG,SAAS,CAG5C;IAGD,MAAM,KAAK,YAAY,IAAI,MAAM,GAAG,SAAS,CAG5C;IAGD,MAAM,KAAK,gBAAgB,IAAI,MAAM,GAAG,SAAS,CAGhD;IAGD,MAAM,KAAK,qBAAqB,IAAI,MAAM,GAAG,SAAS,CAGrD;IAGD,MAAM,KAAK,SAAS,IAAI,MAAM,GAAG,SAAS,CAGzC;IAGD,MAAM,KAAK,sBAAsB,IAAI,MAAM,GAAG,SAAS,CAEtD;IAGD,MAAM,KAAK,cAAc,IAAI,OAAO,GAAG,SAAS,CAG/C;IAGD,MAAM,KAAK,KAAK,IAAI,OAAO,GAAG,SAAS,CAGtC;IAGD,MAAM,KAAK,eAAe,IAAI,MAAM,GAAG,SAAS,CAG/C;IAGD,MAAM,KAAK,WAAW,IAAI,OAAO,GAAG,SAAS,CAG5C;IAED,MAAM,KAAK,QAAQ,CAAC,IAAI,EAAE,OAAO,EAEhC;IAED,MAAM,KAAK,QAAQ,IAAI,OAAO,GAAG,SAAS,CAEzC;CACF"}
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Environment = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ class Environment {
10
+ // Helper to validate if a string is a valid IP address (IPv4)
11
+ static isValidIp(ip) {
12
+ const ipPattern = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
13
+ return ipPattern.test(ip);
14
+ }
15
+ // Helper to validate if a string is a valid hostname or IP address
16
+ static isValidHostnameOrIp(hostname) {
17
+ // Hostname regex (simple, allows subdomains but not special characters)
18
+ const hostnamePattern = /^(([a-zA-Z0-9](-*[a-zA-Z0-9])*)\.)*([a-zA-Z0-9](-*[a-zA-Z0-9])*)\.?$/;
19
+ const ipv6Pattern = /^(([0-9a-fA-F]{1,4}:){7}([0-9a-fA-F]{1,4}|:)|(([0-9a-fA-F]{1,4}:){1,7}|:):(([0-9a-fA-F]{1,4}:){1,6}|:):([0-9a-fA-F]{1,4}|:):([0-9a-fA-F]{1,4}|:)|::)$/;
20
+ return this.isValidIp(hostname) || ipv6Pattern.test(hostname) || hostnamePattern.test(hostname);
21
+ }
22
+ // Helper to validate if a number is a valid port (between 1 and 65535)
23
+ static isValidPort(port) {
24
+ return port > 0 && port <= 65535;
25
+ }
26
+ // Helper to validate if a string is a valid file path
27
+ static isValidFilePath(filePath) {
28
+ return fs_1.default.existsSync(filePath) && path_1.default.isAbsolute(filePath);
29
+ }
30
+ // Helper to get and validate number env variables
31
+ static getNumberEnvVar(envVar) {
32
+ const value = process.env[envVar];
33
+ const parsedValue = Number(value);
34
+ return !isNaN(parsedValue) ? parsedValue : undefined;
35
+ }
36
+ // Static getter for DIG_USERNAME (string, non-empty)
37
+ static get DIG_USERNAME() {
38
+ const value = process.env["DIG_USERNAME"];
39
+ return value && value.trim().length > 0 ? value : undefined;
40
+ }
41
+ // Static getter for DIG_PASSWORD (string, non-empty)
42
+ static get DIG_PASSWORD() {
43
+ const value = process.env["DIG_PASSWORD"];
44
+ return value && value.trim().length > 0 ? value : undefined;
45
+ }
46
+ // Static getter for TRUSTED_FULLNODE (valid IP or hostname)
47
+ static get TRUSTED_FULLNODE() {
48
+ const value = process.env["TRUSTED_FULLNODE"];
49
+ return value && this.isValidHostnameOrIp(value) ? value : undefined;
50
+ }
51
+ // Static getter for TRUSTED_FULLNODE_PORT (valid port)
52
+ static get TRUSTED_FULLNODE_PORT() {
53
+ const port = this.getNumberEnvVar("TRUSTED_FULLNODE_PORT");
54
+ return port && this.isValidPort(port) ? port : undefined;
55
+ }
56
+ // Static getter for PUBLIC_IP (valid IP)
57
+ static get PUBLIC_IP() {
58
+ const value = process.env["PUBLIC_IP"];
59
+ return value;
60
+ }
61
+ // Static getter for DISK_SPACE_LIMIT_BYTES (number, optional)
62
+ static get DISK_SPACE_LIMIT_BYTES() {
63
+ return this.getNumberEnvVar("DISK_SPACE_LIMIT_BYTES");
64
+ }
65
+ // Static getter for MERCENARY_MODE (boolean: "true" or "false")
66
+ static get MERCENARY_MODE() {
67
+ const value = process.env["MERCENARY_MODE"];
68
+ return value === "true" ? true : value === "false" ? false : undefined;
69
+ }
70
+ // Static getter for MERCENARY_MODE (boolean: "true" or "false")
71
+ static get DEBUG() {
72
+ const value = process.env["DIG_DEBUG"];
73
+ return value === "true" ? true : value === "false" ? false : undefined;
74
+ }
75
+ // Static getter for DIG_FOLDER_PATH (valid file path)
76
+ static get DIG_FOLDER_PATH() {
77
+ const value = process.env["DIG_FOLDER_PATH"];
78
+ return value && this.isValidFilePath(value) ? value : undefined;
79
+ }
80
+ // Static getter for REMOTE_NODE (boolean: "1" or "0", mapped to true/false)
81
+ static get REMOTE_NODE() {
82
+ const value = process.env["REMOTE_NODE"];
83
+ return value === "1" ? true : value === "0" ? false : undefined;
84
+ }
85
+ static set CLI_MODE(mode) {
86
+ this.cliMode = mode;
87
+ }
88
+ static get CLI_MODE() {
89
+ return Environment.cliMode;
90
+ }
91
+ }
92
+ exports.Environment = Environment;
93
+ Environment.cliMode = false;
@@ -1,6 +1,6 @@
1
1
  export declare class FileCache<T> {
2
2
  private cacheDir;
3
- constructor(relativeFilePath: string);
3
+ constructor(relativeFilePath: string, baseDir?: string);
4
4
  private ensureDirectoryExists;
5
5
  private getCacheFilePath;
6
6
  get(key: string): T | null;
@@ -1 +1 @@
1
- {"version":3,"file":"FileCache.d.ts","sourceRoot":"","sources":["../../src/utils/FileCache.ts"],"names":[],"mappings":"AAIA,qBAAa,SAAS,CAAC,CAAC;IACtB,OAAO,CAAC,QAAQ,CAAS;gBAEb,gBAAgB,EAAE,MAAM;IAMpC,OAAO,CAAC,qBAAqB;IAO7B,OAAO,CAAC,gBAAgB;IAKjB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI;IAY1B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI;IAO/B,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IASzB,aAAa,IAAI,MAAM,EAAE;CAUjC"}
1
+ {"version":3,"file":"FileCache.d.ts","sourceRoot":"","sources":["../../src/utils/FileCache.ts"],"names":[],"mappings":"AAIA,qBAAa,SAAS,CAAC,CAAC;IACtB,OAAO,CAAC,QAAQ,CAAS;gBAEb,gBAAgB,EAAE,MAAM,EAAE,OAAO,GAAE,MAAwB;IAMvE,OAAO,CAAC,qBAAqB;IAO7B,OAAO,CAAC,gBAAgB;IAKjB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI;IAY1B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI;IAO/B,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IASzB,aAAa,IAAI,MAAM,EAAE;CAUjC"}
@@ -8,8 +8,8 @@ const fs_1 = __importDefault(require("fs"));
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const config_1 = require("./config");
10
10
  class FileCache {
11
- constructor(relativeFilePath) {
12
- this.cacheDir = path_1.default.join(config_1.DIG_FOLDER_PATH, relativeFilePath);
11
+ constructor(relativeFilePath, baseDir = config_1.DIG_FOLDER_PATH) {
12
+ this.cacheDir = path_1.default.join(baseDir, relativeFilePath);
13
13
  this.ensureDirectoryExists();
14
14
  }
15
15
  // Ensure the directory exists or create it