@automattic/vip 3.21.2 → 3.21.3-dev.0
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-app-deploy.js +1 -1
- package/dist/bin/vip-import-media.js +67 -8
- package/dist/bin/vip-import-sql.js +1 -1
- package/dist/lib/api.js +41 -2
- package/dist/lib/client-file-uploader.js +3 -2
- package/dist/lib/media-import/utils.js +18 -0
- package/npm-shrinkwrap.json +15 -14
- package/package.json +1 -1
|
@@ -156,7 +156,7 @@ Processing the file for deployment to your environment...
|
|
|
156
156
|
},
|
|
157
157
|
checksum,
|
|
158
158
|
result
|
|
159
|
-
} = await (0, _clientFileUploader.
|
|
159
|
+
} = await (0, _clientFileUploader.uploadImportFileToS3)(uploadParams);
|
|
160
160
|
startDeployVariables.input = {
|
|
161
161
|
id: appId,
|
|
162
162
|
environmentId: envId,
|
|
@@ -7,8 +7,10 @@ var _graphqlTag = _interopRequireDefault(require("graphql-tag"));
|
|
|
7
7
|
var _api = _interopRequireDefault(require("../lib/api"));
|
|
8
8
|
var _command = _interopRequireDefault(require("../lib/cli/command"));
|
|
9
9
|
var _format = require("../lib/cli/format");
|
|
10
|
+
var _clientFileUploader = require("../lib/client-file-uploader");
|
|
10
11
|
var _progress = require("../lib/media-import/progress");
|
|
11
12
|
var _status = require("../lib/media-import/status");
|
|
13
|
+
var _utils = require("../lib/media-import/utils");
|
|
12
14
|
var _tracker = require("../lib/tracker");
|
|
13
15
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
14
16
|
// eslint-disable-next-line no-duplicate-imports
|
|
@@ -43,10 +45,18 @@ const START_IMPORT_MUTATION = (0, _graphqlTag.default)`
|
|
|
43
45
|
const usage = 'vip import media';
|
|
44
46
|
const debug = (0, _debug.default)('vip:vip-import-media');
|
|
45
47
|
|
|
48
|
+
// Support legacy direct invocation: when users run the built binary directly
|
|
49
|
+
// like `node ./dist/bin/vip-import-media.js @1234.production /path/to/archive.tar.gz --flag`
|
|
50
|
+
// inject the `import media` subcommand into process.argv so the command parser
|
|
51
|
+
// sees the same shape as the full CLI: `vip import media ...`.
|
|
52
|
+
|
|
46
53
|
// Command examples for the `vip import media` help prompt
|
|
47
54
|
const examples = [{
|
|
48
55
|
usage: 'vip @example-app.production import media https://example.com/uploads.tar.gz',
|
|
49
56
|
description: 'Import the archived file "uploads.tar.gz" from a publicly accessible URL to a production environment.'
|
|
57
|
+
}, {
|
|
58
|
+
usage: 'vip @example-app.production import media /path/to/uploads.tar.gz',
|
|
59
|
+
description: 'Import a local archive file (e.g. .tar.gz, .tgz, .zip) from your machine into a production environment. The file will be uploaded temporarily and then imported.'
|
|
50
60
|
},
|
|
51
61
|
// Format error logs
|
|
52
62
|
{
|
|
@@ -95,13 +105,58 @@ Are you sure you want to import the contents of the URL?
|
|
|
95
105
|
overwriteExistingFiles,
|
|
96
106
|
importIntermediateImages
|
|
97
107
|
} = opts;
|
|
98
|
-
const [
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
108
|
+
const [fileNameOrURL] = args;
|
|
109
|
+
let url = '';
|
|
110
|
+
let sourceIsLocal = false;
|
|
111
|
+
if (String(fileNameOrURL).startsWith('http://') || String(fileNameOrURL).startsWith('https://')) {
|
|
112
|
+
url = fileNameOrURL;
|
|
113
|
+
// validate supported URL
|
|
114
|
+
if (!isSupportedUrl(url)) {
|
|
115
|
+
console.log(_chalk.default.red(`
|
|
116
|
+
Error:
|
|
117
|
+
Invalid URL provided: ${url}
|
|
118
|
+
Please make sure that it is a publicly accessible web URL containing an archive of the media files to import.`));
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
// treat as local archive path
|
|
123
|
+
if (!(await (0, _utils.isLocalArchive)(fileNameOrURL))) {
|
|
124
|
+
console.log(_chalk.default.red(`
|
|
125
|
+
Error:
|
|
126
|
+
Invalid local archive provided: ${fileNameOrURL}
|
|
127
|
+
Please make sure the file exists and is one of: .tar.gz, .tgz, .zip`));
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// upload archive to S3 and get presigned URL for import
|
|
132
|
+
sourceIsLocal = true;
|
|
133
|
+
const fileMeta = await (0, _clientFileUploader.getFileMeta)(fileNameOrURL);
|
|
134
|
+
fileMeta.fileName = fileNameOrURL;
|
|
135
|
+
const {
|
|
136
|
+
fileMeta: {
|
|
137
|
+
basename
|
|
138
|
+
},
|
|
139
|
+
checksum: uploadedMD5,
|
|
140
|
+
result
|
|
141
|
+
} = await (0, _clientFileUploader.uploadImportFileToS3)({
|
|
142
|
+
app,
|
|
143
|
+
env,
|
|
144
|
+
fileMeta,
|
|
145
|
+
progressCallback: percentage => console.log(`Upload progress: ${percentage}%`)
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// small debug info to keep variables used
|
|
149
|
+
debug('Uploaded file basename:', basename);
|
|
150
|
+
debug('Uploaded checksum:', uploadedMD5);
|
|
151
|
+
debug('Upload result:', result && typeof result === 'object' ? Object.keys(result) : result);
|
|
152
|
+
({
|
|
153
|
+
url
|
|
154
|
+
} = await (0, _clientFileUploader.getSignedUploadRequestData)({
|
|
155
|
+
appId: app.id,
|
|
156
|
+
envId: env.id,
|
|
157
|
+
basename,
|
|
158
|
+
action: 'GetObject'
|
|
159
|
+
}));
|
|
105
160
|
}
|
|
106
161
|
const track = _tracker.trackEventWithEnv.bind(null, app.id, env.id);
|
|
107
162
|
const api = (0, _api.default)();
|
|
@@ -114,7 +169,11 @@ Error:
|
|
|
114
169
|
Importing Media into your App...
|
|
115
170
|
`;
|
|
116
171
|
console.log();
|
|
117
|
-
|
|
172
|
+
if (sourceIsLocal) {
|
|
173
|
+
console.log(`Importing local archive: ${fileNameOrURL} (uploaded to temporary URL)`);
|
|
174
|
+
} else {
|
|
175
|
+
console.log(`Importing archive from: ${url}`);
|
|
176
|
+
}
|
|
118
177
|
console.log(`to: ${env.primaryDomain.name} (${(0, _format.formatEnvironment)(env.type)})`);
|
|
119
178
|
try {
|
|
120
179
|
await api.mutate({
|
|
@@ -591,7 +591,7 @@ Processing the SQL import for your environment...
|
|
|
591
591
|
},
|
|
592
592
|
checksum: uploadedMD5,
|
|
593
593
|
result
|
|
594
|
-
} = await (0, _clientFileUploader.
|
|
594
|
+
} = await (0, _clientFileUploader.uploadImportFileToS3)({
|
|
595
595
|
app,
|
|
596
596
|
env,
|
|
597
597
|
fileMeta,
|
package/dist/lib/api.js
CHANGED
|
@@ -5,11 +5,15 @@ exports.PRODUCTION_API_HOST = exports.API_URL = exports.API_HOST = void 0;
|
|
|
5
5
|
exports.default = API;
|
|
6
6
|
exports.disableGlobalGraphQLErrorHandling = disableGlobalGraphQLErrorHandling;
|
|
7
7
|
exports.enableGlobalGraphQLErrorHandling = enableGlobalGraphQLErrorHandling;
|
|
8
|
+
exports.shouldRetryRequest = shouldRetryRequest;
|
|
8
9
|
var _core = require("@apollo/client/core");
|
|
9
10
|
var _context = require("@apollo/client/link/context");
|
|
10
11
|
var _core2 = require("@apollo/client/link/core");
|
|
11
12
|
var _error = require("@apollo/client/link/error");
|
|
13
|
+
var _retry = require("@apollo/client/link/retry");
|
|
12
14
|
var _chalk = _interopRequireDefault(require("chalk"));
|
|
15
|
+
var _debug = _interopRequireDefault(require("debug"));
|
|
16
|
+
var _nodeFetch = require("node-fetch");
|
|
13
17
|
var _http = _interopRequireDefault(require("./api/http"));
|
|
14
18
|
var _env = _interopRequireDefault(require("./env"));
|
|
15
19
|
var _token = _interopRequireDefault(require("./token"));
|
|
@@ -21,12 +25,39 @@ const PRODUCTION_API_HOST = exports.PRODUCTION_API_HOST = 'https://api.wpvip.com
|
|
|
21
25
|
const API_HOST = exports.API_HOST = process.env.API_HOST || PRODUCTION_API_HOST; // NOSONAR
|
|
22
26
|
const API_URL = exports.API_URL = `${API_HOST}/graphql`;
|
|
23
27
|
let globalGraphQLErrorHandlingEnabled = true;
|
|
28
|
+
const RETRY_LINK_MAX_ATTEMPTS = 5;
|
|
29
|
+
const RETRY_LINK_INITIAL_DELAY_MS = 1000; // 1 second
|
|
30
|
+
const RETRY_LINK_MAX_DELAY_MS = 5000; // 5 seconds
|
|
31
|
+
|
|
32
|
+
const debug = (0, _debug.default)('@automattic/vip:http:graphql');
|
|
24
33
|
function disableGlobalGraphQLErrorHandling() {
|
|
25
34
|
globalGraphQLErrorHandlingEnabled = false;
|
|
26
35
|
}
|
|
27
36
|
function enableGlobalGraphQLErrorHandling() {
|
|
28
37
|
globalGraphQLErrorHandlingEnabled = true;
|
|
29
38
|
}
|
|
39
|
+
function shouldRetryRequest(attempt, operation, error) {
|
|
40
|
+
const debugSuffix = `Operation: ${operation.operationName}. Attempt: ${attempt}.`;
|
|
41
|
+
if (!error || operation.query.definitions.some(def => def.kind === 'OperationDefinition' && def.operation !== 'query')) {
|
|
42
|
+
debug(`Request failed. ${debugSuffix}`);
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
if (attempt > RETRY_LINK_MAX_ATTEMPTS) {
|
|
46
|
+
debug(`Request failed and max retry attempts reached. ${debugSuffix}`, error);
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
if (error instanceof _nodeFetch.FetchError && error.code === 'ECONNREFUSED') {
|
|
50
|
+
debug(`Request failed. Retrying request due to connection refused error. ${debugSuffix}`);
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
const statusCode = error?.statusCode;
|
|
54
|
+
if (statusCode && statusCode !== 429 && statusCode < 500) {
|
|
55
|
+
debug(`Request failed. Status code: ${statusCode}. ${debugSuffix}`, error);
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
debug(`Request failed. Retrying request due to server error. ${debugSuffix}`, error);
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
30
61
|
function isServerError(networkError) {
|
|
31
62
|
if (!networkError) {
|
|
32
63
|
return false;
|
|
@@ -35,7 +66,8 @@ function isServerError(networkError) {
|
|
|
35
66
|
}
|
|
36
67
|
function API({
|
|
37
68
|
exitOnError = true,
|
|
38
|
-
silenceAuthErrors = false
|
|
69
|
+
silenceAuthErrors = false,
|
|
70
|
+
customRetryLink
|
|
39
71
|
} = {}) {
|
|
40
72
|
const errorLink = (0, _error.onError)(({
|
|
41
73
|
networkError,
|
|
@@ -90,8 +122,15 @@ function API({
|
|
|
90
122
|
agent: proxyAgent
|
|
91
123
|
}
|
|
92
124
|
});
|
|
125
|
+
const retryLink = new _retry.RetryLink({
|
|
126
|
+
delay: {
|
|
127
|
+
initial: RETRY_LINK_INITIAL_DELAY_MS,
|
|
128
|
+
max: RETRY_LINK_MAX_DELAY_MS
|
|
129
|
+
},
|
|
130
|
+
attempts: shouldRetryRequest
|
|
131
|
+
});
|
|
93
132
|
return new _core.ApolloClient({
|
|
94
|
-
link: _core2.ApolloLink.from([withToken, errorLink, authLink, httpLink]),
|
|
133
|
+
link: _core2.ApolloLink.from([withToken, errorLink, customRetryLink ? customRetryLink : retryLink, authLink, httpLink]),
|
|
95
134
|
cache: new _core.InMemoryCache({
|
|
96
135
|
typePolicies: {
|
|
97
136
|
WPSite: {
|
|
@@ -8,9 +8,10 @@ exports.getFileHash = void 0;
|
|
|
8
8
|
exports.getFileMeta = getFileMeta;
|
|
9
9
|
exports.getFileSize = getFileSize;
|
|
10
10
|
exports.getPartBoundaries = getPartBoundaries;
|
|
11
|
+
exports.getSignedUploadRequestData = getSignedUploadRequestData;
|
|
11
12
|
exports.isFile = isFile;
|
|
12
13
|
exports.unzipFile = void 0;
|
|
13
|
-
exports.
|
|
14
|
+
exports.uploadImportFileToS3 = uploadImportFileToS3;
|
|
14
15
|
exports.uploadParts = uploadParts;
|
|
15
16
|
var _chalk = _interopRequireDefault(require("chalk"));
|
|
16
17
|
var _crypto = require("crypto");
|
|
@@ -121,7 +122,7 @@ async function getFileMeta(fileName) {
|
|
|
121
122
|
isCompressed
|
|
122
123
|
};
|
|
123
124
|
}
|
|
124
|
-
async function
|
|
125
|
+
async function uploadImportFileToS3({
|
|
125
126
|
app,
|
|
126
127
|
env,
|
|
127
128
|
fileMeta,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.isLocalArchive = isLocalArchive;
|
|
5
|
+
var _promises = require("node:fs/promises");
|
|
6
|
+
async function isLocalArchive(filePath) {
|
|
7
|
+
const lower = filePath.toLowerCase();
|
|
8
|
+
const isArchive = lower.endsWith('.tar.gz') || lower.endsWith('.tgz') || lower.endsWith('.zip');
|
|
9
|
+
if (!isArchive) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
const fileStat = await (0, _promises.stat)(filePath);
|
|
14
|
+
return fileStat.isFile();
|
|
15
|
+
} catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/vip",
|
|
3
|
-
"version": "3.21.
|
|
3
|
+
"version": "3.21.3-dev.0",
|
|
4
4
|
"lockfileVersion": 2,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@automattic/vip",
|
|
9
|
-
"version": "3.21.
|
|
9
|
+
"version": "3.21.3-dev.0",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"dependencies": {
|
|
@@ -3989,9 +3989,9 @@
|
|
|
3989
3989
|
"dev": true
|
|
3990
3990
|
},
|
|
3991
3991
|
"node_modules/@types/node": {
|
|
3992
|
-
"version": "24.10.
|
|
3993
|
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.
|
|
3994
|
-
"integrity": "sha512-
|
|
3992
|
+
"version": "24.10.1",
|
|
3993
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz",
|
|
3994
|
+
"integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
|
|
3995
3995
|
"license": "MIT",
|
|
3996
3996
|
"dependencies": {
|
|
3997
3997
|
"undici-types": "~7.16.0"
|
|
@@ -10913,9 +10913,10 @@
|
|
|
10913
10913
|
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
|
10914
10914
|
},
|
|
10915
10915
|
"node_modules/js-yaml": {
|
|
10916
|
-
"version": "4.1.
|
|
10917
|
-
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.
|
|
10918
|
-
"integrity": "sha512-
|
|
10916
|
+
"version": "4.1.1",
|
|
10917
|
+
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
|
10918
|
+
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
|
|
10919
|
+
"license": "MIT",
|
|
10919
10920
|
"dependencies": {
|
|
10920
10921
|
"argparse": "^2.0.1"
|
|
10921
10922
|
},
|
|
@@ -17112,9 +17113,9 @@
|
|
|
17112
17113
|
"dev": true
|
|
17113
17114
|
},
|
|
17114
17115
|
"@types/node": {
|
|
17115
|
-
"version": "24.10.
|
|
17116
|
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.
|
|
17117
|
-
"integrity": "sha512-
|
|
17116
|
+
"version": "24.10.1",
|
|
17117
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz",
|
|
17118
|
+
"integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
|
|
17118
17119
|
"requires": {
|
|
17119
17120
|
"undici-types": "~7.16.0"
|
|
17120
17121
|
}
|
|
@@ -21845,9 +21846,9 @@
|
|
|
21845
21846
|
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
|
21846
21847
|
},
|
|
21847
21848
|
"js-yaml": {
|
|
21848
|
-
"version": "4.1.
|
|
21849
|
-
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.
|
|
21850
|
-
"integrity": "sha512-
|
|
21849
|
+
"version": "4.1.1",
|
|
21850
|
+
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
|
21851
|
+
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
|
|
21851
21852
|
"requires": {
|
|
21852
21853
|
"argparse": "^2.0.1"
|
|
21853
21854
|
}
|