w-converhp 2.0.52 → 2.0.54
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/README.md +1 -1
- package/babel.config.js +4 -3
- package/dist/w-converhp-client.umd.js +2 -2
- package/dist/w-converhp-client.umd.js.map +1 -1
- package/docs/WConverhpClient.html +84 -4
- package/docs/WConverhpClient.mjs.html +100 -55
- package/docs/WConverhpServer.html +1 -1
- package/docs/WConverhpServer.mjs.html +1 -1
- package/docs/index.html +1 -1
- package/package.json +2 -2
- package/src/WConverhpClient.mjs +99 -54
- package/src/checkTotalHash.mjs +4 -2
- package/src/checkTotalHash.wk.umd.js +1 -1
- package/srv.mjs +1 -0
- package/web.html +18 -3
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
|
|
81
81
|
<dt class="tag-source">Source:</dt>
|
|
82
82
|
<dd class="tag-source"><ul class="dummy"><li>
|
|
83
|
-
<a href="WConverhpClient.mjs.html">WConverhpClient.mjs</a>, <a href="WConverhpClient.mjs.html#
|
|
83
|
+
<a href="WConverhpClient.mjs.html">WConverhpClient.mjs</a>, <a href="WConverhpClient.mjs.html#line100">line 100</a>
|
|
84
84
|
</li></ul></dd>
|
|
85
85
|
|
|
86
86
|
|
|
@@ -444,7 +444,47 @@
|
|
|
444
444
|
|
|
445
445
|
<tr>
|
|
446
446
|
|
|
447
|
-
<td class="name"><code>
|
|
447
|
+
<td class="name"><code>retryMain</code></td>
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
<td class="type">
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
<span class="param-type">Integer</span>
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
</td>
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
<td class="attributes">
|
|
462
|
+
|
|
463
|
+
<optional><br>
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
</td>
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
<td class="default">
|
|
474
|
+
|
|
475
|
+
<code>3</code>
|
|
476
|
+
|
|
477
|
+
</td>
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
<td class="description last"><p>輸入主要控制器傳輸失敗重試次數整數,預設為3</p></td>
|
|
481
|
+
</tr>
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
<tr>
|
|
486
|
+
|
|
487
|
+
<td class="name"><code>retryUpload</code></td>
|
|
448
488
|
|
|
449
489
|
|
|
450
490
|
<td class="type">
|
|
@@ -477,7 +517,47 @@
|
|
|
477
517
|
</td>
|
|
478
518
|
|
|
479
519
|
|
|
480
|
-
<td class="description last"><p
|
|
520
|
+
<td class="description last"><p>輸入切片上傳檔案傳輸失敗重試次數整數,預設為10</p></td>
|
|
521
|
+
</tr>
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
<tr>
|
|
526
|
+
|
|
527
|
+
<td class="name"><code>retryDownload</code></td>
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
<td class="type">
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
<span class="param-type">Integer</span>
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
</td>
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
<td class="attributes">
|
|
542
|
+
|
|
543
|
+
<optional><br>
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
</td>
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
<td class="default">
|
|
554
|
+
|
|
555
|
+
<code>2</code>
|
|
556
|
+
|
|
557
|
+
</td>
|
|
558
|
+
|
|
559
|
+
|
|
560
|
+
<td class="description last"><p>輸入下載檔案傳輸失敗重試次數整數,預設為2</p></td>
|
|
481
561
|
</tr>
|
|
482
562
|
|
|
483
563
|
|
|
@@ -569,7 +649,7 @@
|
|
|
569
649
|
<br class="clear">
|
|
570
650
|
|
|
571
651
|
<footer>
|
|
572
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> on
|
|
652
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> on Fri May 30 2025 11:51:17 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
573
653
|
</footer>
|
|
574
654
|
|
|
575
655
|
<script>prettyPrint();</script>
|
|
@@ -58,6 +58,7 @@ import isp0int from 'wsemi/src/isp0int.mjs'
|
|
|
58
58
|
import isestr from 'wsemi/src/isestr.mjs'
|
|
59
59
|
import isobj from 'wsemi/src/isobj.mjs'
|
|
60
60
|
import iseobj from 'wsemi/src/iseobj.mjs'
|
|
61
|
+
import isbol from 'wsemi/src/isbol.mjs'
|
|
61
62
|
import ispm from 'wsemi/src/ispm.mjs'
|
|
62
63
|
import cint from 'wsemi/src/cint.mjs'
|
|
63
64
|
import dig from 'wsemi/src/dig.mjs'
|
|
@@ -82,7 +83,9 @@ import getFileXxHash from 'wsemi/src/getFileXxHash.mjs'
|
|
|
82
83
|
* @param {String} [opt.tokenType='Bearer'] 輸入token類型字串,預設'Bearer'
|
|
83
84
|
* @param {Integer} [opt.sizeSlice=1024*1024] 輸入切片上傳檔案之切片檔案大小整數,單位為Byte,預設為1024*1024
|
|
84
85
|
* @param {Integer} [opt.timeout=5*60*1000] 輸入最長等待時間整數,單位ms,預設為5*60*1000、為5分鐘
|
|
85
|
-
* @param {Integer} [opt.
|
|
86
|
+
* @param {Integer} [opt.retryMain=3] 輸入主要控制器傳輸失敗重試次數整數,預設為3
|
|
87
|
+
* @param {Integer} [opt.retryUpload=10] 輸入切片上傳檔案傳輸失敗重試次數整數,預設為10
|
|
88
|
+
* @param {Integer} [opt.retryDownload=2] 輸入下載檔案傳輸失敗重試次數整數,預設為2
|
|
86
89
|
* @returns {Object} 回傳事件物件,可使用函數execute、upload
|
|
87
90
|
* @example
|
|
88
91
|
*
|
|
@@ -190,10 +193,22 @@ function WConverhpClient(opt) {
|
|
|
190
193
|
timeout = 5 * 60 * 1000 //5min
|
|
191
194
|
}
|
|
192
195
|
|
|
193
|
-
//
|
|
194
|
-
let
|
|
195
|
-
if (!isp0int(
|
|
196
|
-
|
|
196
|
+
//retryMain
|
|
197
|
+
let retryMain = get(opt, 'retryMain')
|
|
198
|
+
if (!isp0int(retryMain)) {
|
|
199
|
+
retryMain = 3
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
//retryUpload
|
|
203
|
+
let retryUpload = get(opt, 'retryUpload')
|
|
204
|
+
if (!isp0int(retryUpload)) {
|
|
205
|
+
retryUpload = 10
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
//retryDownload
|
|
209
|
+
let retryDownload = get(opt, 'retryDownload')
|
|
210
|
+
if (!isp0int(retryDownload)) {
|
|
211
|
+
retryDownload = 2
|
|
197
212
|
}
|
|
198
213
|
|
|
199
214
|
//env
|
|
@@ -289,6 +304,12 @@ function WConverhpClient(opt) {
|
|
|
289
304
|
cbProgress = () => {}
|
|
290
305
|
}
|
|
291
306
|
|
|
307
|
+
//retry
|
|
308
|
+
let retry = get(opt, 'retry')
|
|
309
|
+
if (!isp0int(retry)) {
|
|
310
|
+
retry = 1
|
|
311
|
+
}
|
|
312
|
+
|
|
292
313
|
//urlUse
|
|
293
314
|
let urlUse = getUrlUse(type)
|
|
294
315
|
|
|
@@ -359,12 +380,22 @@ function WConverhpClient(opt) {
|
|
|
359
380
|
// console.log('dd', dd)
|
|
360
381
|
|
|
361
382
|
//rt
|
|
362
|
-
let rt =
|
|
383
|
+
let rt = null
|
|
363
384
|
if (env === 'nodejs') {
|
|
364
|
-
rt = 'arraybuffer' //nodejs下沒有blob, 只能設定'json', 'arraybuffer', 'document', 'json', 'text', 'stream'
|
|
365
385
|
if (type === 'download') {
|
|
366
386
|
rt = 'stream' //nodejs download模式採用stream接收
|
|
367
387
|
}
|
|
388
|
+
else {
|
|
389
|
+
rt = 'arraybuffer' //nodejs下沒有blob, 只能設定'json', 'arraybuffer', 'document', 'json', 'text', 'stream'
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
else {
|
|
393
|
+
if (type === 'download') {
|
|
394
|
+
rt = 'blob' //瀏覽器使用blob下載
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
rt = 'blob' //瀏覽器使用blob取得資料
|
|
398
|
+
}
|
|
368
399
|
}
|
|
369
400
|
// console.log('rt', rt)
|
|
370
401
|
|
|
@@ -418,25 +449,15 @@ function WConverhpClient(opt) {
|
|
|
418
449
|
|
|
419
450
|
//streamRecv
|
|
420
451
|
let streamRecv = get(res, 'data')
|
|
452
|
+
// console.log(env, 'streamRecv', streamRecv)
|
|
421
453
|
|
|
422
454
|
if (env === 'browser') {
|
|
423
455
|
|
|
424
|
-
//browser通過
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
a.download = filename // 動態設置檔名
|
|
430
|
-
document.body.appendChild(a)
|
|
431
|
-
a.click()
|
|
432
|
-
a.remove()
|
|
433
|
-
URL.revokeObjectURL(url)
|
|
434
|
-
pm.resolve(filename)
|
|
435
|
-
}
|
|
436
|
-
catch (err) {
|
|
437
|
-
console.log(err)
|
|
438
|
-
pm.reject(err)
|
|
439
|
-
}
|
|
456
|
+
//browser通過axios使用blob接收時會自動把串流接收並組合成blob, 此時streamRecv已是blob
|
|
457
|
+
pm.resolve({
|
|
458
|
+
filename,
|
|
459
|
+
bb: streamRecv,
|
|
460
|
+
})
|
|
440
461
|
|
|
441
462
|
}
|
|
442
463
|
else {
|
|
@@ -672,6 +693,7 @@ function WConverhpClient(opt) {
|
|
|
672
693
|
|
|
673
694
|
//sendPkg
|
|
674
695
|
let sendPkg = async(type, data, cbProgress) => {
|
|
696
|
+
//主要為中心化控制器使用, 通過execute進行上下傳數據
|
|
675
697
|
|
|
676
698
|
//bb
|
|
677
699
|
let bb = null
|
|
@@ -691,7 +713,7 @@ function WConverhpClient(opt) {
|
|
|
691
713
|
}
|
|
692
714
|
|
|
693
715
|
//send
|
|
694
|
-
let res = await send(type, bb, { dataType: 'blob', cbProgress })
|
|
716
|
+
let res = await send(type, bb, { dataType: 'blob', retry: retryMain, cbProgress })
|
|
695
717
|
|
|
696
718
|
return res
|
|
697
719
|
}
|
|
@@ -778,7 +800,7 @@ function WConverhpClient(opt) {
|
|
|
778
800
|
|
|
779
801
|
//send check-total-hash
|
|
780
802
|
// console.log(`send check-total-hash...`)
|
|
781
|
-
let resUpCkt = await send('upload-controller', { mode: 'check-total-hash', fileHash: fileTotalHash, filename: fileTotalName, fileSize: fileTotalSize }, { dataType: 'json' })
|
|
803
|
+
let resUpCkt = await send('upload-controller', { mode: 'check-total-hash', fileHash: fileTotalHash, filename: fileTotalName, fileSize: fileTotalSize }, { dataType: 'json', retry: retryUpload })
|
|
782
804
|
// console.log('resUpCkt', resUpCkt)
|
|
783
805
|
// resUpCkt {
|
|
784
806
|
// path: 'uploadTemp\\2429b7ef08ce6ba9',
|
|
@@ -847,7 +869,7 @@ function WConverhpClient(opt) {
|
|
|
847
869
|
|
|
848
870
|
//send check-slices-hash
|
|
849
871
|
// console.log(`send check-slices-hash...`)
|
|
850
|
-
let resUpCks = await send('upload-controller', { mode: 'check-slices-hash', fileHash: fileTotalHash, fileSliceHashs }, { dataType: 'json' })
|
|
872
|
+
let resUpCks = await send('upload-controller', { mode: 'check-slices-hash', fileHash: fileTotalHash, fileSliceHashs }, { dataType: 'json', retry: retryUpload })
|
|
851
873
|
// console.log('resUpCks', resUpCks)
|
|
852
874
|
// resUpCks {
|
|
853
875
|
// slks: [
|
|
@@ -905,7 +927,8 @@ function WConverhpClient(opt) {
|
|
|
905
927
|
// let dir = msg.m
|
|
906
928
|
// if (dir === 'upload' && perc === 100) {
|
|
907
929
|
// }
|
|
908
|
-
}
|
|
930
|
+
},
|
|
931
|
+
retry: retryUpload,
|
|
909
932
|
})
|
|
910
933
|
// console.log('resSl', resSl)
|
|
911
934
|
|
|
@@ -916,7 +939,7 @@ function WConverhpClient(opt) {
|
|
|
916
939
|
|
|
917
940
|
//send merge-slices-push
|
|
918
941
|
// console.log(`send merge-slices-push...`)
|
|
919
|
-
let resUpMgp = await send('upload-controller', { mode: 'merge-slices-push', fileHash: fileTotalHash, chunkTotal }, { dataType: 'json' })
|
|
942
|
+
let resUpMgp = await send('upload-controller', { mode: 'merge-slices-push', fileHash: fileTotalHash, chunkTotal }, { dataType: 'json', retry: retryUpload })
|
|
920
943
|
// console.log('resUpMgp', resUpMgp)
|
|
921
944
|
|
|
922
945
|
//checkMerging
|
|
@@ -931,7 +954,7 @@ function WConverhpClient(opt) {
|
|
|
931
954
|
|
|
932
955
|
//send merge-slices-get
|
|
933
956
|
// console.log(`send merge-slices-get...`)
|
|
934
|
-
send('upload-controller', { mode: 'merge-slices-get', fileHash: fileTotalHash, filename: fileTotalName, queueId }, { dataType: 'json' })
|
|
957
|
+
send('upload-controller', { mode: 'merge-slices-get', fileHash: fileTotalHash, filename: fileTotalName, queueId }, { dataType: 'json', retry: retryUpload })
|
|
935
958
|
.then((res) => {
|
|
936
959
|
// console.log('res', res)
|
|
937
960
|
// res => {
|
|
@@ -1065,7 +1088,7 @@ function WConverhpClient(opt) {
|
|
|
1065
1088
|
|
|
1066
1089
|
//send download
|
|
1067
1090
|
let msg = { fileId }
|
|
1068
|
-
let resMg = await send('download', msg, { ...opt, dataType: 'json', cbProgress })
|
|
1091
|
+
let resMg = await send('download', msg, { ...opt, dataType: 'json', retry: retryDownload, cbProgress })
|
|
1069
1092
|
// console.log('resMg', resMg)
|
|
1070
1093
|
|
|
1071
1094
|
return resMg
|
|
@@ -1075,37 +1098,59 @@ function WConverhpClient(opt) {
|
|
|
1075
1098
|
let downloadBrowser = async(fileId, cbProgress, opt = {}) => {
|
|
1076
1099
|
//交由瀏覽器下載與管理故無法監聽進度, 不使用cbProgress
|
|
1077
1100
|
|
|
1078
|
-
//
|
|
1079
|
-
let
|
|
1080
|
-
if (
|
|
1081
|
-
|
|
1101
|
+
//downloadByManager
|
|
1102
|
+
let downloadByManager = get(opt, 'downloadByManager')
|
|
1103
|
+
if (!isbol(downloadByManager)) {
|
|
1104
|
+
downloadByManager = true
|
|
1082
1105
|
}
|
|
1083
|
-
// console.log('
|
|
1106
|
+
// console.log('downloadByManager', downloadByManager)
|
|
1084
1107
|
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
let resMg = await send('download-get-filename', msg, { dataType: 'json' })
|
|
1088
|
-
// console.log('resMg', resMg)
|
|
1108
|
+
if (downloadByManager) {
|
|
1109
|
+
//由瀏覽器的下載管理器下載, 使用get+stream
|
|
1089
1110
|
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1111
|
+
//token
|
|
1112
|
+
let token = getToken()
|
|
1113
|
+
if (ispm(token)) {
|
|
1114
|
+
token = await token
|
|
1115
|
+
}
|
|
1116
|
+
// console.log('token', token)
|
|
1093
1117
|
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1118
|
+
//send download-get-filename
|
|
1119
|
+
let msg = { fileId }
|
|
1120
|
+
let resMg = await send('download-get-filename', msg, { dataType: 'json', retry: retryDownload })
|
|
1121
|
+
// console.log('resMg', resMg)
|
|
1122
|
+
|
|
1123
|
+
//filename
|
|
1124
|
+
let filename = get(resMg, 'filename', '')
|
|
1125
|
+
// console.log('filename', filename)
|
|
1126
|
+
|
|
1127
|
+
//urlUse
|
|
1128
|
+
let urlUse = getUrlUse('download-get')
|
|
1129
|
+
// console.log('urlUse', urlUse)
|
|
1130
|
+
|
|
1131
|
+
//url
|
|
1132
|
+
let url = `${urlUse}?fileId=${fileId}&token=${token}`
|
|
1133
|
+
// console.log('url', url)
|
|
1134
|
+
|
|
1135
|
+
//透過a元素打url下載, 讓瀏覽器認定為直接下載模式, 由瀏覽器展示下載進度與排入正在下載清單
|
|
1136
|
+
let a = document.createElement('a')
|
|
1137
|
+
a.href = url
|
|
1138
|
+
a.download = filename
|
|
1139
|
+
a.click()
|
|
1097
1140
|
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1141
|
+
return filename
|
|
1142
|
+
}
|
|
1143
|
+
else {
|
|
1144
|
+
//通過axios下載得到blob, 回傳檔案名稱與blob供後續處理
|
|
1145
|
+
|
|
1146
|
+
//send download
|
|
1147
|
+
let msg = { fileId }
|
|
1148
|
+
let resMg = await send('download', msg, { ...opt, dataType: 'json', retry: retryDownload, cbProgress })
|
|
1149
|
+
// console.log('resMg', resMg)
|
|
1101
1150
|
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
a.href = url
|
|
1105
|
-
a.download = filename
|
|
1106
|
-
a.click()
|
|
1151
|
+
return resMg
|
|
1152
|
+
}
|
|
1107
1153
|
|
|
1108
|
-
return filename
|
|
1109
1154
|
}
|
|
1110
1155
|
|
|
1111
1156
|
//download
|
|
@@ -1142,7 +1187,7 @@ export default WConverhpClient
|
|
|
1142
1187
|
<br class="clear">
|
|
1143
1188
|
|
|
1144
1189
|
<footer>
|
|
1145
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> on
|
|
1190
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> on Fri May 30 2025 11:51:17 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
1146
1191
|
</footer>
|
|
1147
1192
|
|
|
1148
1193
|
<script>prettyPrint();</script>
|
|
@@ -749,7 +749,7 @@
|
|
|
749
749
|
<br class="clear">
|
|
750
750
|
|
|
751
751
|
<footer>
|
|
752
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> on
|
|
752
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> on Fri May 30 2025 11:51:17 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
753
753
|
</footer>
|
|
754
754
|
|
|
755
755
|
<script>prettyPrint();</script>
|
|
@@ -1485,7 +1485,7 @@ export default WConverhpServer
|
|
|
1485
1485
|
<br class="clear">
|
|
1486
1486
|
|
|
1487
1487
|
<footer>
|
|
1488
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> on
|
|
1488
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> on Fri May 30 2025 11:51:17 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
1489
1489
|
</footer>
|
|
1490
1490
|
|
|
1491
1491
|
<script>prettyPrint();</script>
|
package/docs/index.html
CHANGED
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
<br class="clear">
|
|
72
72
|
|
|
73
73
|
<footer>
|
|
74
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> on
|
|
74
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> on Fri May 30 2025 11:51:17 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
75
75
|
</footer>
|
|
76
76
|
|
|
77
77
|
<script>prettyPrint();</script>
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "w-converhp",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.54",
|
|
4
4
|
"main": "dist/w-converhp-server.umd.js",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@hapi/hapi": "^21.4.0",
|
|
7
7
|
"@hapi/inert": "^7.1.0",
|
|
8
8
|
"axios": "^1.9.0",
|
|
9
9
|
"lodash-es": "^4.17.21",
|
|
10
|
-
"wsemi": "^1.7.
|
|
10
|
+
"wsemi": "^1.7.92"
|
|
11
11
|
},
|
|
12
12
|
"devDependencies": {
|
|
13
13
|
"form-data": "^4.0.2",
|