@automattic/vip 4.0.7 → 4.0.9
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/bin/vip-wp.js +12 -10
- package/dist/lib/client-file-uploader.js +43 -8
- package/dist/lib/database.js +7 -12
- package/dist/lib/wp/readline.js +112 -0
- package/npm-shrinkwrap.json +11 -11
- package/package.json +3 -3
package/dist/bin/vip-wp.js
CHANGED
|
@@ -20,6 +20,7 @@ var _proxyAgent = require("../lib/http/proxy-agent");
|
|
|
20
20
|
var _token = _interopRequireDefault(require("../lib/token"));
|
|
21
21
|
var _tracker = require("../lib/tracker");
|
|
22
22
|
var _helpers = require("../lib/wp/helpers");
|
|
23
|
+
var _readline2 = require("../lib/wp/readline");
|
|
23
24
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
24
25
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
25
26
|
const debug = (0, _debug.default)('@automattic/vip:wp');
|
|
@@ -107,8 +108,8 @@ const bindStreamEvents = ({
|
|
|
107
108
|
subShellRl.close();
|
|
108
109
|
process.exit();
|
|
109
110
|
}
|
|
110
|
-
|
|
111
|
-
|
|
111
|
+
(0, _readline2.safeResume)(subShellRl);
|
|
112
|
+
(0, _readline2.safePrompt)(subShellRl);
|
|
112
113
|
});
|
|
113
114
|
};
|
|
114
115
|
const getTokenForCommand = async (appId, envId, command) => {
|
|
@@ -233,7 +234,7 @@ const bindReconnectEvents = ({
|
|
|
233
234
|
});
|
|
234
235
|
|
|
235
236
|
// Resume readline interface
|
|
236
|
-
|
|
237
|
+
(0, _readline2.safeResume)(subShellRl);
|
|
237
238
|
});
|
|
238
239
|
currentJob.socket.on('retry', async () => {
|
|
239
240
|
debug('socket: retry');
|
|
@@ -391,6 +392,7 @@ const examples = [{
|
|
|
391
392
|
const commandState = (0, _helpers.initState)();
|
|
392
393
|
let seenWP = false;
|
|
393
394
|
const subShellRl = _readline.default.createInterface(subShellSettings);
|
|
395
|
+
(0, _readline2.trackReadline)(subShellRl);
|
|
394
396
|
subShellRl.on('line', async line => {
|
|
395
397
|
if (commandRunning) {
|
|
396
398
|
return;
|
|
@@ -398,7 +400,7 @@ const examples = [{
|
|
|
398
400
|
|
|
399
401
|
// Handle plain return / newline
|
|
400
402
|
if (!line) {
|
|
401
|
-
|
|
403
|
+
(0, _readline2.safePrompt)(subShellRl);
|
|
402
404
|
return;
|
|
403
405
|
}
|
|
404
406
|
|
|
@@ -411,7 +413,7 @@ const examples = [{
|
|
|
411
413
|
if (userCmdCancelled) {
|
|
412
414
|
seenWP = false;
|
|
413
415
|
(0, _helpers.resetState)(commandState);
|
|
414
|
-
|
|
416
|
+
(0, _readline2.safePrompt)(subShellRl);
|
|
415
417
|
return;
|
|
416
418
|
}
|
|
417
419
|
if (!seenWP && line.trimStart().startsWith('wp ')) {
|
|
@@ -426,10 +428,10 @@ const examples = [{
|
|
|
426
428
|
} else {
|
|
427
429
|
(0, _helpers.resetState)(commandState);
|
|
428
430
|
console.log(_chalk.default.red('Error:'), 'invalid command, please pass a valid WP-CLI command.');
|
|
429
|
-
|
|
431
|
+
(0, _readline2.safePrompt)(subShellRl);
|
|
430
432
|
return;
|
|
431
433
|
}
|
|
432
|
-
|
|
434
|
+
(0, _readline2.safePause)(subShellRl);
|
|
433
435
|
let result;
|
|
434
436
|
const wpCliCmd = commandState.command.replace(/^wp\s+/, '');
|
|
435
437
|
seenWP = false;
|
|
@@ -450,7 +452,7 @@ const examples = [{
|
|
|
450
452
|
subShellRl.close();
|
|
451
453
|
process.exit(1);
|
|
452
454
|
}
|
|
453
|
-
|
|
455
|
+
(0, _readline2.safePrompt)(subShellRl);
|
|
454
456
|
return;
|
|
455
457
|
}
|
|
456
458
|
const {
|
|
@@ -522,9 +524,9 @@ const examples = [{
|
|
|
522
524
|
});
|
|
523
525
|
if (!isSubShell) {
|
|
524
526
|
mutableStdout.muted = true;
|
|
525
|
-
|
|
527
|
+
(0, _readline2.safeWrite)(subShellRl, `wp ${cmd}\n`);
|
|
526
528
|
mutableStdout.muted = false;
|
|
527
529
|
return;
|
|
528
530
|
}
|
|
529
|
-
|
|
531
|
+
(0, _readline2.safePrompt)(subShellRl);
|
|
530
532
|
});
|
|
@@ -44,6 +44,43 @@ function parseEtagHeader(etag) {
|
|
|
44
44
|
return normalizedEtag.replace(/^"(.*)"$/u, '$1');
|
|
45
45
|
}
|
|
46
46
|
const isStreamBody = body => typeof body?.pipe === 'function';
|
|
47
|
+
function createProgressTransform(onChunk) {
|
|
48
|
+
return new _stream.Transform({
|
|
49
|
+
transform(chunk, _encoding, callback) {
|
|
50
|
+
onChunk(chunk);
|
|
51
|
+
callback(null, chunk);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function omitUnsupportedFetchHeaders(init) {
|
|
56
|
+
if (!init.headers) {
|
|
57
|
+
return init;
|
|
58
|
+
}
|
|
59
|
+
const headers = new _undici.Headers(init.headers);
|
|
60
|
+
headers.delete('expect');
|
|
61
|
+
return {
|
|
62
|
+
...init,
|
|
63
|
+
headers
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function withCauseMessage(err) {
|
|
67
|
+
if (!(err instanceof Error)) {
|
|
68
|
+
return err;
|
|
69
|
+
}
|
|
70
|
+
const cause = err.cause;
|
|
71
|
+
let causeMessage;
|
|
72
|
+
if (cause instanceof Error) {
|
|
73
|
+
causeMessage = cause.message;
|
|
74
|
+
} else if (typeof cause === 'string') {
|
|
75
|
+
causeMessage = cause;
|
|
76
|
+
}
|
|
77
|
+
if (!causeMessage || err.message.includes(causeMessage)) {
|
|
78
|
+
return err;
|
|
79
|
+
}
|
|
80
|
+
return new Error(`${err.message}: ${causeMessage}`, {
|
|
81
|
+
cause: err
|
|
82
|
+
});
|
|
83
|
+
}
|
|
47
84
|
|
|
48
85
|
/**
|
|
49
86
|
* Wraps `fetch` with exponential-backoff retries.
|
|
@@ -75,10 +112,10 @@ async function fetchWithRetry(input, init = {}, retries = 3, createBody) {
|
|
|
75
112
|
}
|
|
76
113
|
try {
|
|
77
114
|
// eslint-disable-next-line no-await-in-loop
|
|
78
|
-
return await (0, _undici.fetch)(input, requestInit);
|
|
115
|
+
return await (0, _undici.fetch)(input, omitUnsupportedFetchHeaders(requestInit));
|
|
79
116
|
} catch (err) {
|
|
80
117
|
if (attempt === maxAttempts) {
|
|
81
|
-
throw err;
|
|
118
|
+
throw withCauseMessage(err);
|
|
82
119
|
}
|
|
83
120
|
// eslint-disable-next-line no-await-in-loop
|
|
84
121
|
await (0, _promises3.setTimeout)(Math.pow(2, attempt) * 1000); // 1000, 2000, 4000
|
|
@@ -260,8 +297,7 @@ async function uploadUsingPutObject({
|
|
|
260
297
|
return fileContent;
|
|
261
298
|
}
|
|
262
299
|
let readBytes = 0;
|
|
263
|
-
const
|
|
264
|
-
progressPassThrough.on('data', data => {
|
|
300
|
+
const progressTransform = createProgressTransform(data => {
|
|
265
301
|
readBytes += data.length;
|
|
266
302
|
const percentage = `${Math.floor(100 * readBytes / fileSize)}%`;
|
|
267
303
|
debug(percentage);
|
|
@@ -269,7 +305,7 @@ async function uploadUsingPutObject({
|
|
|
269
305
|
progressCallback(percentage);
|
|
270
306
|
}
|
|
271
307
|
});
|
|
272
|
-
return (0, _fs.createReadStream)(fileName).pipe(
|
|
308
|
+
return (0, _fs.createReadStream)(fileName).pipe(progressTransform);
|
|
273
309
|
};
|
|
274
310
|
const response = await fetchWithRetry(presignedRequest.url, fetchOptions, 3, createBody);
|
|
275
311
|
if (response.status === 200) {
|
|
@@ -507,15 +543,14 @@ async function uploadParts({
|
|
|
507
543
|
const createBody = () => {
|
|
508
544
|
partBytesRead[index] = 0;
|
|
509
545
|
partPercentages[index] = 0;
|
|
510
|
-
const
|
|
511
|
-
progressPassThrough.on('data', data => {
|
|
546
|
+
const progressTransform = createProgressTransform(data => {
|
|
512
547
|
partBytesRead[index] += data.length;
|
|
513
548
|
partPercentages[index] = Math.floor(100 * partBytesRead[index] / partSize);
|
|
514
549
|
});
|
|
515
550
|
return (0, _fs.createReadStream)(fileMeta.fileName, {
|
|
516
551
|
start,
|
|
517
552
|
end
|
|
518
|
-
}).pipe(
|
|
553
|
+
}).pipe(progressTransform);
|
|
519
554
|
};
|
|
520
555
|
await readyForPartUpload();
|
|
521
556
|
const uploadResult = await uploadPart({
|
package/dist/lib/database.js
CHANGED
|
@@ -86,21 +86,16 @@ const getSqlFileStreamFromCompressedFile = async filePath => {
|
|
|
86
86
|
}
|
|
87
87
|
throw new Error('Not a supported compressed file');
|
|
88
88
|
};
|
|
89
|
+
|
|
90
|
+
// Replaces the byte-size value that mydumper embeds in chunk header comments (e.g. `-- tablename 1234`)
|
|
91
|
+
// with -1. mydumper exports the original file size in those headers, but since we modify the dump,
|
|
92
|
+
// the size is no longer accurate — setting it to -1 tells mydumper to ignore it.
|
|
93
|
+
// Lines starting with `-- metadata` are left untouched as they use the same format but are not chunk headers.
|
|
89
94
|
const fixMyDumperTransform = () => {
|
|
90
|
-
const regex = /^-- ([^ ]+) \d
|
|
95
|
+
const regex = /^-- (?!metadata)([^ ]+) \d+$/gm;
|
|
91
96
|
return new _nodeStream.Transform({
|
|
92
97
|
transform(chunk, _encoding, callback) {
|
|
93
|
-
|
|
94
|
-
const lineEnding = chunkString.includes('\r\n') ? '\r\n' : '\n';
|
|
95
|
-
const lines = chunk.toString().split(lineEnding).map(line => {
|
|
96
|
-
const match = regex.exec(line);
|
|
97
|
-
if (!match) {
|
|
98
|
-
return line;
|
|
99
|
-
}
|
|
100
|
-
const tablePart = match[1];
|
|
101
|
-
return `-- ${tablePart} -1`;
|
|
102
|
-
});
|
|
103
|
-
callback(null, lines.join(lineEnding));
|
|
98
|
+
callback(null, chunk.toString().replace(regex, '-- $1 -1'));
|
|
104
99
|
}
|
|
105
100
|
});
|
|
106
101
|
};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.isReadlineClosed = isReadlineClosed;
|
|
5
|
+
exports.safePause = safePause;
|
|
6
|
+
exports.safePrompt = safePrompt;
|
|
7
|
+
exports.safeResume = safeResume;
|
|
8
|
+
exports.safeWrite = safeWrite;
|
|
9
|
+
exports.trackReadline = trackReadline;
|
|
10
|
+
/**
|
|
11
|
+
* Safe wrappers around `readline.Interface` lifecycle methods.
|
|
12
|
+
*
|
|
13
|
+
* On Node.js >= 24, calling `resume()`, `pause()`, `prompt()`, or `write()` on a
|
|
14
|
+
* readline interface that has already been closed throws
|
|
15
|
+
* `Error [ERR_USE_AFTER_CLOSE]: readline was closed`. On Node 20/22 the same
|
|
16
|
+
* calls are silent no-ops.
|
|
17
|
+
*
|
|
18
|
+
* `vip wp` drives non-interactive, one-shot commands through a readline
|
|
19
|
+
* interface bound to `process.stdin`. When stdin is redirected from
|
|
20
|
+
* `/dev/null` (no TTY, e.g. CI or container runs) the interface receives EOF
|
|
21
|
+
* immediately and closes, while the command keeps streaming output. On a
|
|
22
|
+
* websocket reconnect during a long-running command the reconnect handler then
|
|
23
|
+
* calls `resume()` on the already-closed interface, crashing the process on
|
|
24
|
+
* Node 24.
|
|
25
|
+
*
|
|
26
|
+
* These helpers guard every such call so the interface is only driven while it
|
|
27
|
+
* is still open. Closure is tracked through the documented `'close'` event
|
|
28
|
+
* rather than any internal interface property, so the behaviour does not depend
|
|
29
|
+
* on Node.js implementation details.
|
|
30
|
+
*
|
|
31
|
+
* Register an interface with {@link trackReadline} once, right after it is
|
|
32
|
+
* created, so the `'close'` listener is attached before the interface can
|
|
33
|
+
* close. Calls made through the `safe*` helpers on an untracked-but-open
|
|
34
|
+
* interface still work; tracking only adds the closed-state guard.
|
|
35
|
+
*
|
|
36
|
+
* @see https://nodejs.org/api/readline.html#event-close
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
const closedInterfaces = new WeakSet();
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Begin tracking a readline interface so its closed state can be detected.
|
|
43
|
+
*
|
|
44
|
+
* Attaches a one-time `'close'` listener that records the interface as closed.
|
|
45
|
+
* Safe to call more than once for the same interface.
|
|
46
|
+
*
|
|
47
|
+
* @param rl The readline interface to track.
|
|
48
|
+
* @returns The same interface, for convenient chaining.
|
|
49
|
+
*/
|
|
50
|
+
function trackReadline(rl) {
|
|
51
|
+
rl.once('close', () => {
|
|
52
|
+
closedInterfaces.add(rl);
|
|
53
|
+
});
|
|
54
|
+
return rl;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Whether a tracked readline interface has already emitted `'close'`.
|
|
59
|
+
*
|
|
60
|
+
* @param rl The readline interface to inspect.
|
|
61
|
+
* @returns `true` if the interface has been closed, otherwise `false`.
|
|
62
|
+
*/
|
|
63
|
+
function isReadlineClosed(rl) {
|
|
64
|
+
return closedInterfaces.has(rl);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Resume the readline interface unless it has already been closed.
|
|
69
|
+
*
|
|
70
|
+
* @param rl The readline interface to resume.
|
|
71
|
+
*/
|
|
72
|
+
function safeResume(rl) {
|
|
73
|
+
if (!isReadlineClosed(rl)) {
|
|
74
|
+
rl.resume();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Pause the readline interface unless it has already been closed.
|
|
80
|
+
*
|
|
81
|
+
* @param rl The readline interface to pause.
|
|
82
|
+
*/
|
|
83
|
+
function safePause(rl) {
|
|
84
|
+
if (!isReadlineClosed(rl)) {
|
|
85
|
+
rl.pause();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Display the prompt unless the readline interface has already been closed.
|
|
91
|
+
*
|
|
92
|
+
* @param rl The readline interface to prompt on.
|
|
93
|
+
* @param preserveCursor When `true`, prevents the cursor from being reset to 0.
|
|
94
|
+
*/
|
|
95
|
+
function safePrompt(rl, preserveCursor) {
|
|
96
|
+
if (!isReadlineClosed(rl)) {
|
|
97
|
+
rl.prompt(preserveCursor);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Write data into the readline interface unless it has already been closed.
|
|
103
|
+
*
|
|
104
|
+
* @param rl The readline interface to write to.
|
|
105
|
+
* @param data The data to write.
|
|
106
|
+
* @param key An optional key sequence, mirroring `Interface#write`.
|
|
107
|
+
*/
|
|
108
|
+
function safeWrite(rl, data, key) {
|
|
109
|
+
if (!isReadlineClosed(rl)) {
|
|
110
|
+
rl.write(data, key);
|
|
111
|
+
}
|
|
112
|
+
}
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/vip",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.9",
|
|
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.9",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"dependencies": {
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"socks-proxy-agent": "^10.0.0",
|
|
42
42
|
"ssh2": "1.17.0",
|
|
43
43
|
"tar": "^7.4.0",
|
|
44
|
-
"undici": "^
|
|
44
|
+
"undici": "^8.5.0",
|
|
45
45
|
"update-notifier": "7.3.1",
|
|
46
46
|
"xml2js": "^0.6.2"
|
|
47
47
|
},
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
"typescript": "^6.0.2"
|
|
138
138
|
},
|
|
139
139
|
"engines": {
|
|
140
|
-
"node": "
|
|
140
|
+
"node": ">=22.19.0",
|
|
141
141
|
"npm": ">=8"
|
|
142
142
|
},
|
|
143
143
|
"optionalDependencies": {
|
|
@@ -11418,9 +11418,9 @@
|
|
|
11418
11418
|
"license": "MIT"
|
|
11419
11419
|
},
|
|
11420
11420
|
"node_modules/js-yaml": {
|
|
11421
|
-
"version": "5.
|
|
11422
|
-
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.
|
|
11423
|
-
"integrity": "sha512-
|
|
11421
|
+
"version": "5.1.0",
|
|
11422
|
+
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.1.0.tgz",
|
|
11423
|
+
"integrity": "sha512-s8VA5jkR8f22S3NAXmhKPFqGUduqZGlsufabVOgN14iTdw/RXcym7bKkbwjxLK9Yw2lEvvmJjFp119+KPeo8Kg==",
|
|
11424
11424
|
"funding": [
|
|
11425
11425
|
{
|
|
11426
11426
|
"type": "github",
|
|
@@ -14624,12 +14624,12 @@
|
|
|
14624
14624
|
}
|
|
14625
14625
|
},
|
|
14626
14626
|
"node_modules/undici": {
|
|
14627
|
-
"version": "
|
|
14628
|
-
"resolved": "https://registry.npmjs.org/undici/-/undici-
|
|
14629
|
-
"integrity": "sha512-
|
|
14627
|
+
"version": "8.5.0",
|
|
14628
|
+
"resolved": "https://registry.npmjs.org/undici/-/undici-8.5.0.tgz",
|
|
14629
|
+
"integrity": "sha512-xamtWoB1EshgjpmlXd7GGm2VfdDtw1+rD8uhry8pSNW3If6S8E0m2T2+orSKeZXEn/aPJMviCpDBA65WJt8zhg==",
|
|
14630
14630
|
"license": "MIT",
|
|
14631
14631
|
"engines": {
|
|
14632
|
-
"node": ">=
|
|
14632
|
+
"node": ">=22.19.0"
|
|
14633
14633
|
}
|
|
14634
14634
|
},
|
|
14635
14635
|
"node_modules/undici-types": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/vip",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.9",
|
|
4
4
|
"description": "The VIP Javascript library & CLI",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
],
|
|
108
108
|
"license": "MIT",
|
|
109
109
|
"engines": {
|
|
110
|
-
"node": "
|
|
110
|
+
"node": ">=22.19.0",
|
|
111
111
|
"npm": ">=8"
|
|
112
112
|
},
|
|
113
113
|
"bugs": {
|
|
@@ -172,7 +172,7 @@
|
|
|
172
172
|
"socks-proxy-agent": "^10.0.0",
|
|
173
173
|
"ssh2": "1.17.0",
|
|
174
174
|
"tar": "^7.4.0",
|
|
175
|
-
"undici": "^
|
|
175
|
+
"undici": "^8.5.0",
|
|
176
176
|
"update-notifier": "7.3.1",
|
|
177
177
|
"xml2js": "^0.6.2"
|
|
178
178
|
},
|