@automattic/vip 4.0.5 → 4.0.7
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/lib/client-file-uploader.js +88 -42
- package/npm-shrinkwrap.json +65 -19
- package/package.json +4 -4
|
@@ -4,6 +4,7 @@ exports.__esModule = true;
|
|
|
4
4
|
exports.MULTIPART_THRESHOLD = exports.COMPRESS_THRESHOLD = void 0;
|
|
5
5
|
exports.checkFileAccess = checkFileAccess;
|
|
6
6
|
exports.detectCompressedMimeType = detectCompressedMimeType;
|
|
7
|
+
exports.fetchWithRetry = fetchWithRetry;
|
|
7
8
|
exports.getFileHash = void 0;
|
|
8
9
|
exports.getFileMeta = getFileMeta;
|
|
9
10
|
exports.getFileSize = getFileSize;
|
|
@@ -20,6 +21,7 @@ var _debug = _interopRequireDefault(require("debug"));
|
|
|
20
21
|
var _fs = require("fs");
|
|
21
22
|
var _promises = require("node:fs/promises");
|
|
22
23
|
var _promises2 = require("node:stream/promises");
|
|
24
|
+
var _nodeTimers = require("node:timers");
|
|
23
25
|
var _promises3 = require("node:timers/promises");
|
|
24
26
|
var _os = _interopRequireDefault(require("os"));
|
|
25
27
|
var _path = _interopRequireDefault(require("path"));
|
|
@@ -41,13 +43,41 @@ function parseEtagHeader(etag) {
|
|
|
41
43
|
}
|
|
42
44
|
return normalizedEtag.replace(/^"(.*)"$/u, '$1');
|
|
43
45
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
const isStreamBody = body => typeof body?.pipe === 'function';
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Wraps `fetch` with exponential-backoff retries.
|
|
50
|
+
*
|
|
51
|
+
* A request body that is a Node stream can only be consumed once. If the body
|
|
52
|
+
* is a stream and we retried with the same `init`, the second attempt would
|
|
53
|
+
* pass an already-consumed (disturbed/locked) stream to `fetch`, which throws
|
|
54
|
+
* the misleading `Response body object should not be disturbed or locked` error
|
|
55
|
+
* and masks the original network failure.
|
|
56
|
+
*
|
|
57
|
+
* To retry safely, callers that send a stream body should pass `createBody`,
|
|
58
|
+
* which is invoked to produce a fresh body for every attempt. If a stream body
|
|
59
|
+
* is supplied without a `createBody` factory, the request is attempted only
|
|
60
|
+
* once so the underlying error surfaces instead of the misleading undici one.
|
|
61
|
+
*/
|
|
62
|
+
async function fetchWithRetry(input, init = {}, retries = 3, createBody) {
|
|
63
|
+
const bodyIsStream = isStreamBody(init.body);
|
|
64
|
+
// Only retry when we can hand `fetch` a fresh, replayable body each attempt.
|
|
65
|
+
const maxAttempts = createBody || !bodyIsStream ? retries : 0;
|
|
66
|
+
for (let attempt = 0; attempt <= maxAttempts; attempt++) {
|
|
67
|
+
const requestInit = createBody ? {
|
|
68
|
+
...init,
|
|
69
|
+
body: createBody()
|
|
70
|
+
} : {
|
|
71
|
+
...init
|
|
72
|
+
};
|
|
73
|
+
if (isStreamBody(requestInit.body) && !requestInit.duplex) {
|
|
74
|
+
requestInit.duplex = 'half';
|
|
75
|
+
}
|
|
46
76
|
try {
|
|
47
77
|
// eslint-disable-next-line no-await-in-loop
|
|
48
|
-
return await (0, _undici.fetch)(input,
|
|
78
|
+
return await (0, _undici.fetch)(input, requestInit);
|
|
49
79
|
} catch (err) {
|
|
50
|
-
if (attempt ===
|
|
80
|
+
if (attempt === maxAttempts) {
|
|
51
81
|
throw err;
|
|
52
82
|
}
|
|
53
83
|
// eslint-disable-next-line no-await-in-loop
|
|
@@ -220,20 +250,28 @@ async function uploadUsingPutObject({
|
|
|
220
250
|
...fetchOptions.headers,
|
|
221
251
|
'Content-Length': `${fileSize}` // This has to be a string
|
|
222
252
|
};
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
if (
|
|
230
|
-
|
|
253
|
+
|
|
254
|
+
// Build a fresh request body for every attempt. The upload streams the file
|
|
255
|
+
// from disk, and a stream can only be consumed once; recreating it per
|
|
256
|
+
// attempt lets `fetchWithRetry` retry without reusing a consumed stream
|
|
257
|
+
// (which would otherwise throw `... should not be disturbed or locked`).
|
|
258
|
+
const createBody = () => {
|
|
259
|
+
if (fileContent) {
|
|
260
|
+
return fileContent;
|
|
231
261
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
262
|
+
let readBytes = 0;
|
|
263
|
+
const progressPassThrough = new _stream.PassThrough();
|
|
264
|
+
progressPassThrough.on('data', data => {
|
|
265
|
+
readBytes += data.length;
|
|
266
|
+
const percentage = `${Math.floor(100 * readBytes / fileSize)}%`;
|
|
267
|
+
debug(percentage);
|
|
268
|
+
if (typeof progressCallback === 'function') {
|
|
269
|
+
progressCallback(percentage);
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
return (0, _fs.createReadStream)(fileName).pipe(progressPassThrough);
|
|
273
|
+
};
|
|
274
|
+
const response = await fetchWithRetry(presignedRequest.url, fetchOptions, 3, createBody);
|
|
237
275
|
if (response.status === 200) {
|
|
238
276
|
return 'ok';
|
|
239
277
|
}
|
|
@@ -428,18 +466,19 @@ async function uploadParts({
|
|
|
428
466
|
progressCallback
|
|
429
467
|
}) {
|
|
430
468
|
let uploadsInProgress = 0;
|
|
431
|
-
let totalBytesRead = 0;
|
|
432
469
|
const partPercentages = new Array(parts.length).fill(0);
|
|
470
|
+
const partBytesRead = new Array(parts.length).fill(0);
|
|
433
471
|
const readyForPartUpload = () => new Promise(resolve => {
|
|
434
|
-
const canDoInterval = setInterval(() => {
|
|
472
|
+
const canDoInterval = (0, _nodeTimers.setInterval)(() => {
|
|
435
473
|
if (uploadsInProgress < MAX_CONCURRENT_PART_UPLOADS) {
|
|
436
474
|
uploadsInProgress++;
|
|
437
|
-
clearInterval(canDoInterval);
|
|
475
|
+
(0, _nodeTimers.clearInterval)(canDoInterval);
|
|
438
476
|
resolve();
|
|
439
477
|
}
|
|
440
478
|
}, 300);
|
|
441
479
|
});
|
|
442
480
|
const updateProgress = () => {
|
|
481
|
+
const totalBytesRead = partBytesRead.reduce((sum, bytes) => sum + bytes, 0);
|
|
443
482
|
const percentage = `${Math.floor(100 * totalBytesRead / fileMeta.fileSize)}%`;
|
|
444
483
|
if (typeof progressCallback === 'function') {
|
|
445
484
|
progressCallback(percentage);
|
|
@@ -451,32 +490,46 @@ async function uploadParts({
|
|
|
451
490
|
return `Part # ${index}: ${partPercentage}% of ${(partSize / _fileSize.MB_IN_BYTES).toFixed(2)}MB`;
|
|
452
491
|
}).join('\n') + `\n\nOverall Progress: ${percentage}% of ${(fileMeta.fileSize / _fileSize.MB_IN_BYTES).toFixed(2)}MB`);
|
|
453
492
|
};
|
|
454
|
-
const updateProgressInterval = setInterval(updateProgress, 500);
|
|
493
|
+
const updateProgressInterval = (0, _nodeTimers.setInterval)(updateProgress, 500);
|
|
455
494
|
const allDone = await Promise.all(parts.map(async part => {
|
|
456
495
|
const {
|
|
457
496
|
index,
|
|
458
|
-
partSize
|
|
497
|
+
partSize,
|
|
498
|
+
start,
|
|
499
|
+
end
|
|
459
500
|
} = part;
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
501
|
+
|
|
502
|
+
// Build a fresh request body for every attempt. A stream can only be
|
|
503
|
+
// consumed once, so recreating the ranged read stream (and its progress
|
|
504
|
+
// PassThrough) per attempt lets `fetchWithRetry` retry without reusing a
|
|
505
|
+
// disturbed/locked stream. Reset this part's progress counters so a retry
|
|
506
|
+
// re-streams the part without double-counting bytes.
|
|
507
|
+
const createBody = () => {
|
|
508
|
+
partBytesRead[index] = 0;
|
|
509
|
+
partPercentages[index] = 0;
|
|
510
|
+
const progressPassThrough = new _stream.PassThrough();
|
|
511
|
+
progressPassThrough.on('data', data => {
|
|
512
|
+
partBytesRead[index] += data.length;
|
|
513
|
+
partPercentages[index] = Math.floor(100 * partBytesRead[index] / partSize);
|
|
514
|
+
});
|
|
515
|
+
return (0, _fs.createReadStream)(fileMeta.fileName, {
|
|
516
|
+
start,
|
|
517
|
+
end
|
|
518
|
+
}).pipe(progressPassThrough);
|
|
519
|
+
};
|
|
467
520
|
await readyForPartUpload();
|
|
468
521
|
const uploadResult = await uploadPart({
|
|
469
522
|
app,
|
|
470
523
|
env,
|
|
471
524
|
fileMeta,
|
|
472
525
|
part,
|
|
473
|
-
|
|
526
|
+
createBody,
|
|
474
527
|
uploadId
|
|
475
528
|
});
|
|
476
529
|
uploadsInProgress--;
|
|
477
530
|
return uploadResult;
|
|
478
531
|
}));
|
|
479
|
-
clearInterval(updateProgressInterval);
|
|
532
|
+
(0, _nodeTimers.clearInterval)(updateProgressInterval);
|
|
480
533
|
updateProgress();
|
|
481
534
|
return allDone;
|
|
482
535
|
}
|
|
@@ -484,18 +537,15 @@ async function uploadPart({
|
|
|
484
537
|
app,
|
|
485
538
|
env,
|
|
486
539
|
fileMeta: {
|
|
487
|
-
basename
|
|
488
|
-
fileName
|
|
540
|
+
basename
|
|
489
541
|
},
|
|
490
542
|
part,
|
|
491
|
-
|
|
543
|
+
createBody,
|
|
492
544
|
uploadId
|
|
493
545
|
}) {
|
|
494
546
|
const {
|
|
495
|
-
end,
|
|
496
547
|
index,
|
|
497
|
-
partSize
|
|
498
|
-
start
|
|
548
|
+
partSize
|
|
499
549
|
} = part;
|
|
500
550
|
const s3PartNumber = index + 1; // S3 multipart is indexed from 1
|
|
501
551
|
|
|
@@ -521,11 +571,7 @@ async function uploadPart({
|
|
|
521
571
|
* ...so it may not be feasible to include with presigned requests.
|
|
522
572
|
*/
|
|
523
573
|
};
|
|
524
|
-
|
|
525
|
-
start,
|
|
526
|
-
end
|
|
527
|
-
}).pipe(progressPassThrough);
|
|
528
|
-
const fetchResponse = await fetchWithRetry(partUploadRequestData.url, fetchOptions);
|
|
574
|
+
const fetchResponse = await fetchWithRetry(partUploadRequestData.url, fetchOptions, 3, createBody);
|
|
529
575
|
if (fetchResponse.status === 200) {
|
|
530
576
|
const etag = fetchResponse.headers.get('etag');
|
|
531
577
|
if (!etag) {
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/vip",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.7",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@automattic/vip",
|
|
9
|
-
"version": "4.0.
|
|
9
|
+
"version": "4.0.7",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"dependencies": {
|
|
@@ -28,13 +28,13 @@
|
|
|
28
28
|
"graphql": "17.0.1",
|
|
29
29
|
"graphql-tag": "2.12.7",
|
|
30
30
|
"https-proxy-agent": "^9.0.0",
|
|
31
|
-
"js-yaml": "^
|
|
31
|
+
"js-yaml": "^5.0.0",
|
|
32
32
|
"jwt-decode": "4.0.0",
|
|
33
33
|
"lando": "github:automattic/lando-cli#78d382fcf40357c4a4cebe4a3cfaef032eab743a",
|
|
34
34
|
"node-stream-zip": "1.15.0",
|
|
35
35
|
"open": "^11.0.0",
|
|
36
36
|
"proxy-from-env": "^2.0.0",
|
|
37
|
-
"semver": "7.8.
|
|
37
|
+
"semver": "7.8.5",
|
|
38
38
|
"shelljs": "^0.10.0",
|
|
39
39
|
"socket.io-client": "^4.5.3",
|
|
40
40
|
"socket.io-stream": "npm:@wwa/socket.io-stream@^0.10.0",
|
|
@@ -124,7 +124,7 @@
|
|
|
124
124
|
"@types/ejs": "^3.1.5",
|
|
125
125
|
"@types/jest": "^30.0.0",
|
|
126
126
|
"@types/js-yaml": "^4.0.9",
|
|
127
|
-
"@types/node": "^
|
|
127
|
+
"@types/node": "^26.0.0",
|
|
128
128
|
"@types/proxy-from-env": "^1.0.4",
|
|
129
129
|
"@types/semver": "^7.5.5",
|
|
130
130
|
"@types/shelljs": "^0.10.0",
|
|
@@ -2865,6 +2865,30 @@
|
|
|
2865
2865
|
"url": "https://github.com/sponsors/sindresorhus"
|
|
2866
2866
|
}
|
|
2867
2867
|
},
|
|
2868
|
+
"node_modules/@eslint/eslintrc/node_modules/js-yaml": {
|
|
2869
|
+
"version": "4.2.0",
|
|
2870
|
+
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz",
|
|
2871
|
+
"integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==",
|
|
2872
|
+
"dev": true,
|
|
2873
|
+
"funding": [
|
|
2874
|
+
{
|
|
2875
|
+
"type": "github",
|
|
2876
|
+
"url": "https://github.com/sponsors/puzrin"
|
|
2877
|
+
},
|
|
2878
|
+
{
|
|
2879
|
+
"type": "github",
|
|
2880
|
+
"url": "https://github.com/sponsors/nodeca"
|
|
2881
|
+
}
|
|
2882
|
+
],
|
|
2883
|
+
"license": "MIT",
|
|
2884
|
+
"peer": true,
|
|
2885
|
+
"dependencies": {
|
|
2886
|
+
"argparse": "^2.0.1"
|
|
2887
|
+
},
|
|
2888
|
+
"bin": {
|
|
2889
|
+
"js-yaml": "bin/js-yaml.js"
|
|
2890
|
+
}
|
|
2891
|
+
},
|
|
2868
2892
|
"node_modules/@eslint/eslintrc/node_modules/minimatch": {
|
|
2869
2893
|
"version": "3.1.5",
|
|
2870
2894
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
|
@@ -4570,12 +4594,12 @@
|
|
|
4570
4594
|
"license": "MIT"
|
|
4571
4595
|
},
|
|
4572
4596
|
"node_modules/@types/node": {
|
|
4573
|
-
"version": "
|
|
4574
|
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-
|
|
4575
|
-
"integrity": "sha512-
|
|
4597
|
+
"version": "26.0.0",
|
|
4598
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-26.0.0.tgz",
|
|
4599
|
+
"integrity": "sha512-vf2YFi1iY9lHGwNJMs01biZFbKJkrZR1T6/MlzjhJLPdntOHLhTrDSnSVcdtvjihi4VQNlrFRIxLsDBlQpAipA==",
|
|
4576
4600
|
"license": "MIT",
|
|
4577
4601
|
"dependencies": {
|
|
4578
|
-
"undici-types": "
|
|
4602
|
+
"undici-types": "~8.3.0"
|
|
4579
4603
|
}
|
|
4580
4604
|
},
|
|
4581
4605
|
"node_modules/@types/proxy-from-env": {
|
|
@@ -11394,9 +11418,9 @@
|
|
|
11394
11418
|
"license": "MIT"
|
|
11395
11419
|
},
|
|
11396
11420
|
"node_modules/js-yaml": {
|
|
11397
|
-
"version": "
|
|
11398
|
-
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-
|
|
11399
|
-
"integrity": "sha512-
|
|
11421
|
+
"version": "5.0.0",
|
|
11422
|
+
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.0.0.tgz",
|
|
11423
|
+
"integrity": "sha512-GSvaPUbk1U+FMZ7rJzF+F8e5YVtu7KnD40et/5rBXXRBv2jCO9L3qCewvIDDdudC0QycTFlf6EAA+h3kxBsuUw==",
|
|
11400
11424
|
"funding": [
|
|
11401
11425
|
{
|
|
11402
11426
|
"type": "github",
|
|
@@ -11412,7 +11436,7 @@
|
|
|
11412
11436
|
"argparse": "^2.0.1"
|
|
11413
11437
|
},
|
|
11414
11438
|
"bin": {
|
|
11415
|
-
"js-yaml": "bin/js-yaml.
|
|
11439
|
+
"js-yaml": "bin/js-yaml.mjs"
|
|
11416
11440
|
}
|
|
11417
11441
|
},
|
|
11418
11442
|
"node_modules/jsdoc-type-pratt-parser": {
|
|
@@ -11668,6 +11692,28 @@
|
|
|
11668
11692
|
"url": "https://github.com/sponsors/isaacs"
|
|
11669
11693
|
}
|
|
11670
11694
|
},
|
|
11695
|
+
"node_modules/lando/node_modules/js-yaml": {
|
|
11696
|
+
"version": "4.2.0",
|
|
11697
|
+
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz",
|
|
11698
|
+
"integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==",
|
|
11699
|
+
"funding": [
|
|
11700
|
+
{
|
|
11701
|
+
"type": "github",
|
|
11702
|
+
"url": "https://github.com/sponsors/puzrin"
|
|
11703
|
+
},
|
|
11704
|
+
{
|
|
11705
|
+
"type": "github",
|
|
11706
|
+
"url": "https://github.com/sponsors/nodeca"
|
|
11707
|
+
}
|
|
11708
|
+
],
|
|
11709
|
+
"license": "MIT",
|
|
11710
|
+
"dependencies": {
|
|
11711
|
+
"argparse": "^2.0.1"
|
|
11712
|
+
},
|
|
11713
|
+
"bin": {
|
|
11714
|
+
"js-yaml": "bin/js-yaml.js"
|
|
11715
|
+
}
|
|
11716
|
+
},
|
|
11671
11717
|
"node_modules/lando/node_modules/lru-cache": {
|
|
11672
11718
|
"version": "11.2.7",
|
|
11673
11719
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz",
|
|
@@ -13418,9 +13464,9 @@
|
|
|
13418
13464
|
}
|
|
13419
13465
|
},
|
|
13420
13466
|
"node_modules/semver": {
|
|
13421
|
-
"version": "7.8.
|
|
13422
|
-
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.
|
|
13423
|
-
"integrity": "sha512-
|
|
13467
|
+
"version": "7.8.5",
|
|
13468
|
+
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
|
|
13469
|
+
"integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
|
|
13424
13470
|
"license": "ISC",
|
|
13425
13471
|
"bin": {
|
|
13426
13472
|
"semver": "bin/semver.js"
|
|
@@ -14587,9 +14633,9 @@
|
|
|
14587
14633
|
}
|
|
14588
14634
|
},
|
|
14589
14635
|
"node_modules/undici-types": {
|
|
14590
|
-
"version": "
|
|
14591
|
-
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-
|
|
14592
|
-
"integrity": "sha512-
|
|
14636
|
+
"version": "8.3.0",
|
|
14637
|
+
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz",
|
|
14638
|
+
"integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==",
|
|
14593
14639
|
"license": "MIT"
|
|
14594
14640
|
},
|
|
14595
14641
|
"node_modules/unicode-canonical-property-names-ecmascript": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/vip",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.7",
|
|
4
4
|
"description": "The VIP Javascript library & CLI",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
"@types/ejs": "^3.1.5",
|
|
129
129
|
"@types/jest": "^30.0.0",
|
|
130
130
|
"@types/js-yaml": "^4.0.9",
|
|
131
|
-
"@types/node": "^
|
|
131
|
+
"@types/node": "^26.0.0",
|
|
132
132
|
"@types/proxy-from-env": "^1.0.4",
|
|
133
133
|
"@types/semver": "^7.5.5",
|
|
134
134
|
"@types/shelljs": "^0.10.0",
|
|
@@ -159,13 +159,13 @@
|
|
|
159
159
|
"graphql": "17.0.1",
|
|
160
160
|
"graphql-tag": "2.12.7",
|
|
161
161
|
"https-proxy-agent": "^9.0.0",
|
|
162
|
-
"js-yaml": "^
|
|
162
|
+
"js-yaml": "^5.0.0",
|
|
163
163
|
"jwt-decode": "4.0.0",
|
|
164
164
|
"lando": "github:automattic/lando-cli#78d382fcf40357c4a4cebe4a3cfaef032eab743a",
|
|
165
165
|
"node-stream-zip": "1.15.0",
|
|
166
166
|
"open": "^11.0.0",
|
|
167
167
|
"proxy-from-env": "^2.0.0",
|
|
168
|
-
"semver": "7.8.
|
|
168
|
+
"semver": "7.8.5",
|
|
169
169
|
"shelljs": "^0.10.0",
|
|
170
170
|
"socket.io-client": "^4.5.3",
|
|
171
171
|
"socket.io-stream": "npm:@wwa/socket.io-stream@^0.10.0",
|