@trap_stevo/filetide 0.0.37 → 0.0.39
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/cjs/FileMessager.js +6 -2
- package/dist/cjs/FileMessagerClient.js +8 -6
- package/dist/cjs/FileTide.js +45 -27
- package/dist/cjs/HUDManagers/FileTransferManager.js +2 -2
- package/dist/cjs/HUDManagers/FileTransferReceiverManager.js +82 -0
- package/dist/cjs/HUDManagers/FileUtilityManager.js +23 -12
- package/package.json +1 -1
package/dist/cjs/FileMessager.js
CHANGED
|
@@ -84,7 +84,7 @@ class FileMessager {
|
|
|
84
84
|
* @param {String} fileName - The name of the file
|
|
85
85
|
* @param {Number} chunkIndex - The index of the current chunk
|
|
86
86
|
*/
|
|
87
|
-
sendFileChunkToClient(senderData, clientData, fileChunk, fileName, chunkIndex, totalChunks, filePath = process.cwd(), fileSize = 100) {
|
|
87
|
+
sendFileChunkToClient(senderData, clientData, fileChunk, fileName, chunkIndex, chunkSize, totalChunks, filePath = process.cwd(), fileSize = 100) {
|
|
88
88
|
const senderClient = this.getClientFromID(senderData.id);
|
|
89
89
|
const client = this.getClientFromID(clientData.id);
|
|
90
90
|
if (!client) {
|
|
@@ -106,6 +106,7 @@ class FileMessager {
|
|
|
106
106
|
fileName,
|
|
107
107
|
fileChunk,
|
|
108
108
|
chunkIndex,
|
|
109
|
+
chunkSize,
|
|
109
110
|
path: filePath,
|
|
110
111
|
fileSize
|
|
111
112
|
});
|
|
@@ -173,6 +174,7 @@ class FileMessager {
|
|
|
173
174
|
fileSize,
|
|
174
175
|
filePath,
|
|
175
176
|
chunkIndex,
|
|
177
|
+
chunkSize,
|
|
176
178
|
totalChunks
|
|
177
179
|
} = transferData;
|
|
178
180
|
console.log(`Transferring file ~ ${fileName} | chunk ${chunkIndex + 1} of ${totalChunks} to client (${recipientId})`);
|
|
@@ -182,7 +184,7 @@ class FileMessager {
|
|
|
182
184
|
}, {
|
|
183
185
|
userID: recipientId,
|
|
184
186
|
id: FileNetClientManager.getOnlineClient(recipientId).id
|
|
185
|
-
}, fileChunk, fileName, chunkIndex, totalChunks, filePath, fileSize);
|
|
187
|
+
}, fileChunk, fileName, chunkIndex, chunkSize, totalChunks, filePath, fileSize);
|
|
186
188
|
if (chunkIndex + 1 === totalChunks) {
|
|
187
189
|
this.fileNet.emit("transfer-complete", {
|
|
188
190
|
senderID,
|
|
@@ -270,10 +272,12 @@ class FileMessager {
|
|
|
270
272
|
activeTransferBarrier
|
|
271
273
|
});
|
|
272
274
|
this.fileNet.emitToTide(tideID, "current-online-clients", Object.fromEntries(FileNetClientManager.getOnlineClients()));
|
|
275
|
+
this.fileNet.emit("current-clients", Object.fromEntries(FileNetClientManager.getOnlineClients()));
|
|
273
276
|
return;
|
|
274
277
|
}
|
|
275
278
|
handleClientOffline(clientID) {
|
|
276
279
|
FileNetClientManager.clearOnlineClient(clientID);
|
|
280
|
+
this.fileNet.emit("current-clients", Object.fromEntries(FileNetClientManager.getOnlineClients()));
|
|
277
281
|
return;
|
|
278
282
|
}
|
|
279
283
|
}
|
|
@@ -154,7 +154,7 @@ class FileMessagerClient {
|
|
|
154
154
|
});
|
|
155
155
|
}
|
|
156
156
|
this.transporter.sendFile(file, {
|
|
157
|
-
onSendChunk: (transferId, chunkIndex, chunkData, totalChunks) => {
|
|
157
|
+
onSendChunk: (transferId, chunkIndex, chunkSize, chunkData, totalChunks) => {
|
|
158
158
|
if (chunkIndex === 0) {
|
|
159
159
|
this.progressBarManager.addTask({
|
|
160
160
|
name: fileName,
|
|
@@ -169,6 +169,7 @@ class FileMessagerClient {
|
|
|
169
169
|
fileChunk: chunkData,
|
|
170
170
|
totalChunks,
|
|
171
171
|
chunkIndex,
|
|
172
|
+
chunkSize,
|
|
172
173
|
filePath,
|
|
173
174
|
fileSize
|
|
174
175
|
});
|
|
@@ -186,8 +187,8 @@ class FileMessagerClient {
|
|
|
186
187
|
resolve();
|
|
187
188
|
});
|
|
188
189
|
},
|
|
189
|
-
onProgress: progress => {
|
|
190
|
-
this.progressBarManager.updateTaskProgress(fileName,
|
|
190
|
+
onProgress: (progress, chunkSize) => {
|
|
191
|
+
this.progressBarManager.updateTaskProgress(fileName, chunkSize);
|
|
191
192
|
},
|
|
192
193
|
originDetails: {
|
|
193
194
|
recipientID: recipientId,
|
|
@@ -224,7 +225,7 @@ class FileMessagerClient {
|
|
|
224
225
|
path: filePath
|
|
225
226
|
});
|
|
226
227
|
this.transporter.sendFile(file, {
|
|
227
|
-
onSendChunk: (transferId, chunkIndex, chunkData, totalChunks) => {
|
|
228
|
+
onSendChunk: (transferId, chunkIndex, chunkSize, chunkData, totalChunks) => {
|
|
228
229
|
if (chunkIndex === 0) {
|
|
229
230
|
this.progressBarManager.addTask({
|
|
230
231
|
name: fileName,
|
|
@@ -239,6 +240,7 @@ class FileMessagerClient {
|
|
|
239
240
|
fileChunk: chunkData,
|
|
240
241
|
totalChunks,
|
|
241
242
|
chunkIndex,
|
|
243
|
+
chunkSize,
|
|
242
244
|
filePath,
|
|
243
245
|
fileSize
|
|
244
246
|
});
|
|
@@ -256,8 +258,8 @@ class FileMessagerClient {
|
|
|
256
258
|
resolve();
|
|
257
259
|
});
|
|
258
260
|
},
|
|
259
|
-
onProgress: progress => {
|
|
260
|
-
this.progressBarManager.updateTaskProgress(fileName,
|
|
261
|
+
onProgress: (progress, chunkSize) => {
|
|
262
|
+
this.progressBarManager.updateTaskProgress(fileName, chunkSize);
|
|
261
263
|
},
|
|
262
264
|
originDetails: {
|
|
263
265
|
recipientID: recipientId,
|
package/dist/cjs/FileTide.js
CHANGED
|
@@ -12,6 +12,9 @@ const {
|
|
|
12
12
|
significantMessageColors,
|
|
13
13
|
errorMessageColors
|
|
14
14
|
} = require("./HUDManagers/FileNetUtilityManager.js");
|
|
15
|
+
const {
|
|
16
|
+
FileTransferReceiverManager
|
|
17
|
+
} = require("./HUDManagers/FileTransferReceiverManager.js");
|
|
15
18
|
const {
|
|
16
19
|
FileNetConfigManager
|
|
17
20
|
} = require("./HUDManagers/FileNetConfigManager.js");
|
|
@@ -236,6 +239,7 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
236
239
|
onTransferStart,
|
|
237
240
|
onTransferComplete,
|
|
238
241
|
onTransferRequested,
|
|
242
|
+
onTransferStatus,
|
|
239
243
|
onListFiles,
|
|
240
244
|
onCurrentOnlineClients
|
|
241
245
|
} = options;
|
|
@@ -265,7 +269,7 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
265
269
|
return content;
|
|
266
270
|
}
|
|
267
271
|
});
|
|
268
|
-
|
|
272
|
+
const fileTransferReceiver = new FileTransferReceiverManager();
|
|
269
273
|
client.clientTide.onEvent(userID, "current-online-clients", data => {
|
|
270
274
|
const currentClients = {};
|
|
271
275
|
Object.keys(data).forEach(key => {
|
|
@@ -280,7 +284,22 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
280
284
|
cliTable.setData(currentClients);
|
|
281
285
|
console.log(`\n[FileTide ~ FileNet]\n\n`, cliTable.render(), "\n");
|
|
282
286
|
if (onCurrentOnlineClients) {
|
|
283
|
-
onCurrentOnlineClients(currentClients);
|
|
287
|
+
onCurrentOnlineClients(currentClients, true);
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
client.clientTide.onEvent(userID, "current-clients", data => {
|
|
291
|
+
const currentClients = {};
|
|
292
|
+
Object.keys(data).forEach(key => {
|
|
293
|
+
if (key !== userID) {
|
|
294
|
+
currentClients[key] = data[key];
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
if (Object.keys(currentClients).length <= 0) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
_FileTide.outputGradient(`\n[FileTide ~ FileNet]\n\n✨ Current Clients >${Object.keys(currentClients).length}< ✨\n`, significantMessageColors);
|
|
301
|
+
if (onCurrentOnlineClients) {
|
|
302
|
+
onCurrentOnlineClients(currentClients, false);
|
|
284
303
|
}
|
|
285
304
|
});
|
|
286
305
|
client.clientTide.onEvent(userID, "queue-incoming-transfer", async data => {
|
|
@@ -309,14 +328,10 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
309
328
|
this.progressBarManager.displayPage("Page Number:", "Press 'n' for next page, 'p' for previous page.", chalk.blue, chalk.magenta);
|
|
310
329
|
this.progressBarManager.listenForInput("Page Number:", "Press 'n' for next page, 'p' for previous page.", chalk.blue, chalk.magenta, chalk.yellow);
|
|
311
330
|
});
|
|
312
|
-
client.clientTide.onEvent(userID, "incoming-file", data => {
|
|
331
|
+
client.clientTide.onEvent(userID, "incoming-file", async data => {
|
|
313
332
|
try {
|
|
314
333
|
_FileTide.outputGradient(`[${userID}] Preparing to receive file : ${data.fileName}`, significantMessageColors);
|
|
315
|
-
|
|
316
|
-
receivedChunks: [],
|
|
317
|
-
totalChunks: data.totalChunks,
|
|
318
|
-
fileInfo: data
|
|
319
|
-
});
|
|
334
|
+
await fileTransferReceiver.initializeTransfer(data);
|
|
320
335
|
const saveDir = FileUtilityManager.getTidePath(data.path);
|
|
321
336
|
const verifiedSender = data.senderID && data.senderID !== userID;
|
|
322
337
|
if (verifiedSender) {
|
|
@@ -326,7 +341,7 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
326
341
|
});
|
|
327
342
|
}
|
|
328
343
|
if (onIncomingFile) {
|
|
329
|
-
onIncomingFile(verifiedSender, data, activeTransfers);
|
|
344
|
+
onIncomingFile(verifiedSender, data, fileTransferReceiver.activeTransfers);
|
|
330
345
|
}
|
|
331
346
|
if (verifiedSender && !fs.existsSync(saveDir)) {
|
|
332
347
|
fs.mkdirSync(saveDir, {
|
|
@@ -350,41 +365,44 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
350
365
|
onTransferBarrier(data);
|
|
351
366
|
}
|
|
352
367
|
});
|
|
353
|
-
client.clientTide.onEvent(userID, "transfer-progress", data => {
|
|
368
|
+
client.clientTide.onEvent(userID, "transfer-progress", async data => {
|
|
354
369
|
if (!data || data.fileChunk === undefined || data.fileChunk === null) {
|
|
355
370
|
return;
|
|
356
371
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
return;
|
|
360
|
-
}
|
|
361
|
-
transferState.receivedChunks[data.chunkIndex] = Buffer.from(data.fileChunk);
|
|
362
|
-
const progress = (data.chunkIndex + 1) / transferState.totalChunks * 100;
|
|
363
|
-
this.progressBarManager.updateTaskProgress(data.fileName, 512 * 1024);
|
|
372
|
+
await fileTransferReceiver.handleTransferProgress(data);
|
|
373
|
+
this.progressBarManager.updateTaskProgress(data.fileName, data.chunkSize || 512 * 1024);
|
|
364
374
|
if (onTransferProgress) {
|
|
365
375
|
onTransferProgress(data);
|
|
366
376
|
}
|
|
367
377
|
});
|
|
378
|
+
client.clientTide.onEvent(userID, "transfer-status", data => {
|
|
379
|
+
if (onTransferStatus) {
|
|
380
|
+
onTransferStatus(data);
|
|
381
|
+
}
|
|
382
|
+
return;
|
|
383
|
+
});
|
|
368
384
|
client.clientTide.onEvent(userID, "transfer-complete", data => {
|
|
369
385
|
const savePath = FileUtilityManager.getTidePath(path.join(data.filePath, data.fileName));
|
|
370
386
|
try {
|
|
371
387
|
_FileTide.outputGradient(`[${userID}] File transfer complete : ${data.fileName}`, significantMessageColors);
|
|
372
|
-
const transferState = activeTransfers.get(data.fileName);
|
|
388
|
+
const transferState = fileTransferReceiver.activeTransfers.get(data.fileName);
|
|
373
389
|
if (!transferState) {
|
|
374
390
|
return;
|
|
375
391
|
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
392
|
+
fileTransferReceiver.completeTransfer(data, (transferData, transfers, success) => {
|
|
393
|
+
if (success) {
|
|
394
|
+
_FileTide.outputGradient(`[${userID}] File saved at : ${savePath}\n`, significantMessageColors);
|
|
395
|
+
} else if (!success) {
|
|
396
|
+
_FileTide.outputGradient(`[${userID}] Did not save file at : ${savePath}\n`, errorMessageColors);
|
|
397
|
+
}
|
|
398
|
+
if (onTransferComplete) {
|
|
399
|
+
onTransferComplete(data, fileTransferReceiver.activeTransfers, success);
|
|
400
|
+
}
|
|
401
|
+
});
|
|
383
402
|
} catch (error) {
|
|
384
403
|
_FileTide.outputGradient(`[${userID}] Did not save file at : ${savePath}\n${error}`, errorMessageColors);
|
|
385
|
-
activeTransfers.delete(data.fileName);
|
|
386
404
|
if (onTransferComplete) {
|
|
387
|
-
onTransferComplete(data, activeTransfers, false);
|
|
405
|
+
onTransferComplete(data, fileTransferReceiver.activeTransfers, false);
|
|
388
406
|
}
|
|
389
407
|
}
|
|
390
408
|
});
|
|
@@ -41,7 +41,7 @@ function _startTransfer(file, transferId, fileDetails, onSendChunk, onComplete,
|
|
|
41
41
|
const updateProgress = () => {
|
|
42
42
|
const transferState = this.activeTransfers.get(transferId);
|
|
43
43
|
if (onProgress) {
|
|
44
|
-
onProgress(transferState.completedChunks / transferState.totalChunks * 100);
|
|
44
|
+
onProgress(transferState.completedChunks / transferState.totalChunks * 100, this.chunkSize);
|
|
45
45
|
}
|
|
46
46
|
};
|
|
47
47
|
return new Promise((resolve, reject) => {
|
|
@@ -60,7 +60,7 @@ function _startTransfer(file, transferId, fileDetails, onSendChunk, onComplete,
|
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
62
|
transferState.activeChunks++;
|
|
63
|
-
onSendChunk(transferId, chunkIndex, chunk, transferState.totalChunks).then(() => {
|
|
63
|
+
onSendChunk(transferId, chunkIndex, this.chunkSize, chunk, transferState.totalChunks).then(() => {
|
|
64
64
|
transferState.completedChunks++;
|
|
65
65
|
transferState.activeChunks--;
|
|
66
66
|
updateProgress();
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const {
|
|
6
|
+
FileUtilityManager
|
|
7
|
+
} = require("./FileUtilityManager.js");
|
|
8
|
+
class FileTransferReceiverManager {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.activeTransfers = new Map();
|
|
11
|
+
}
|
|
12
|
+
async initializeTransfer(data, onError) {
|
|
13
|
+
const savePath = FileUtilityManager.getTidePath(path.join(data.path || data.filePath, data.fileName));
|
|
14
|
+
if (this.activeTransfers.has(data.fileName)) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const totalChunks = data.totalChunks || Math.ceil(data.fileSize / (data.chunkSize || 512 * 1024));
|
|
18
|
+
const chunkSize = data.chunkSize || 512 * 1024;
|
|
19
|
+
try {
|
|
20
|
+
const dir = path.dirname(savePath);
|
|
21
|
+
if (!fs.existsSync(dir)) {
|
|
22
|
+
fs.mkdirSync(dir, {
|
|
23
|
+
recursive: true
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
const fileStream = fs.createWriteStream(savePath, {
|
|
27
|
+
flags: "w"
|
|
28
|
+
});
|
|
29
|
+
this.activeTransfers.set(data.fileName, {
|
|
30
|
+
receivedChunks: new Set(),
|
|
31
|
+
fileInfo: data,
|
|
32
|
+
totalChunks,
|
|
33
|
+
fileStream,
|
|
34
|
+
chunkSize
|
|
35
|
+
});
|
|
36
|
+
} catch (error) {
|
|
37
|
+
if (onError) {
|
|
38
|
+
onError(`[${data.fileName}] Did not initialize transfer ~ ${error.message}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async handleTransferProgress(data, onError) {
|
|
43
|
+
let transferState = this.activeTransfers.get(data.fileName);
|
|
44
|
+
if (!transferState) {
|
|
45
|
+
await this.initializeTransfer(data);
|
|
46
|
+
transferState = this.activeTransfers.get(data.fileName);
|
|
47
|
+
}
|
|
48
|
+
const chunkBuffer = Buffer.from(data.fileChunk);
|
|
49
|
+
try {
|
|
50
|
+
transferState.fileStream.write(chunkBuffer);
|
|
51
|
+
transferState.receivedChunks.add(data.chunkIndex);
|
|
52
|
+
} catch (error) {
|
|
53
|
+
if (onError) {
|
|
54
|
+
onError(`[${data.fileName}] Did not write chunk ${data.chunkIndex} ~ ${error.message}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async completeTransfer(data, onComplete) {
|
|
59
|
+
let transferState = this.activeTransfers.get(data.fileName);
|
|
60
|
+
if (!transferState) {
|
|
61
|
+
await this.initializeTransfer(data);
|
|
62
|
+
transferState = this.activeTransfers.get(data.fileName);
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
if (transferState.receivedChunks.size === transferState.totalChunks) {
|
|
66
|
+
transferState.fileStream.end();
|
|
67
|
+
console.log(`[${data.fileName}] Transfer complete. All chunks received and file written.`);
|
|
68
|
+
this.activeTransfers.delete(data.fileName);
|
|
69
|
+
if (onComplete) onComplete(data, this.activeTransfers, true);
|
|
70
|
+
} else {
|
|
71
|
+
throw new Error(`[${data.fileName}] Transfer incomplete. Received ${transferState.receivedChunks.size}/${transferState.totalChunks} chunks.`);
|
|
72
|
+
}
|
|
73
|
+
} catch (error) {
|
|
74
|
+
if (onComplete) {
|
|
75
|
+
onComplete(data, this.activeTransfers, false);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
module.exports = {
|
|
81
|
+
FileTransferReceiverManager
|
|
82
|
+
};
|
|
@@ -292,7 +292,7 @@ class FileUtilityManager {
|
|
|
292
292
|
for (const file of files) {
|
|
293
293
|
const stats = await fs.promises.stat(file.path);
|
|
294
294
|
if (stats.isFile()) {
|
|
295
|
-
const fileData = FileUtilityManager.getFileData(file.path);
|
|
295
|
+
const fileData = await FileUtilityManager.getFileData(file.path);
|
|
296
296
|
if (fileData) {
|
|
297
297
|
filesData.push(fileData);
|
|
298
298
|
}
|
|
@@ -310,22 +310,33 @@ class FileUtilityManager {
|
|
|
310
310
|
* @param {string} inputFilePath - The full path to the file.
|
|
311
311
|
* @returns {Object|null} - An object containing file data, name, path, and size or null if the file doesn't exist.
|
|
312
312
|
*/
|
|
313
|
-
static getFileData(inputFilePath) {
|
|
313
|
+
static async getFileData(inputFilePath) {
|
|
314
314
|
const filePath = this.getTidePath(inputFilePath);
|
|
315
315
|
if (!fs.existsSync(filePath)) {
|
|
316
316
|
console.log(`File at path ${filePath} not found.`);
|
|
317
317
|
return null;
|
|
318
318
|
}
|
|
319
|
-
const fileData = fs.readFileSync(filePath, {
|
|
320
|
-
encoding: null
|
|
321
|
-
});
|
|
322
319
|
const fileName = path.basename(filePath);
|
|
323
|
-
return {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
320
|
+
return new Promise((resolve, reject) => {
|
|
321
|
+
const fileStream = fs.createReadStream(filePath);
|
|
322
|
+
const chunks = [];
|
|
323
|
+
fileStream.on("data", chunk => {
|
|
324
|
+
chunks.push(chunk);
|
|
325
|
+
});
|
|
326
|
+
fileStream.on("end", () => {
|
|
327
|
+
const fileData = Buffer.concat(chunks);
|
|
328
|
+
resolve({
|
|
329
|
+
size: fileData.length,
|
|
330
|
+
fileName,
|
|
331
|
+
fileData,
|
|
332
|
+
filePath
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
fileStream.on("error", error => {
|
|
336
|
+
console.error(`Did not read file ${filePath}: `, error);
|
|
337
|
+
resolve(null);
|
|
338
|
+
});
|
|
339
|
+
});
|
|
329
340
|
}
|
|
330
341
|
|
|
331
342
|
/**
|
|
@@ -343,7 +354,7 @@ class FileUtilityManager {
|
|
|
343
354
|
const stats = fs.statSync(currentInputPath);
|
|
344
355
|
if (stats.isFile()) {
|
|
345
356
|
return {
|
|
346
|
-
content: this.getFileData(currentInputPath),
|
|
357
|
+
content: await this.getFileData(currentInputPath),
|
|
347
358
|
type: "file"
|
|
348
359
|
};
|
|
349
360
|
} else if (stats.isDirectory()) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trap_stevo/filetide",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.39",
|
|
4
4
|
"description": "Revolutionizing real-time file transfer with seamless, instant communication across any device. Deliver files instantly, regardless of platform, and experience unparalleled speed and control in managing transfers. Elevate your file-sharing capabilities with a tool designed for precision, efficiency, and effortless connectivity.",
|
|
5
5
|
"main": "dist/cjs/FileTide.js",
|
|
6
6
|
"scripts": {
|