@automattic/vip 2.30.0 → 2.31.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.
Files changed (56) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/assets/dev-env.lando.template.yml.ejs +14 -0
  3. package/assets/dev-env.nginx.template.conf.ejs +23 -2
  4. package/dist/bin/vip-dev-env-shell.js +2 -1
  5. package/dist/bin/vip-dev-env-sync-sql.js +15 -19
  6. package/dist/bin/vip-dev-env-sync.js +0 -0
  7. package/dist/bin/vip-dev-env-update.js +1 -0
  8. package/dist/bin/vip-export-sql.js +12 -11
  9. package/dist/bin/vip-import-sql.js +2 -2
  10. package/dist/bin/vip-whoami.js +7 -10
  11. package/dist/commands/dev-env-sync-sql.js +53 -20
  12. package/dist/commands/export-sql.js +13 -4
  13. package/dist/lib/analytics/clients/pendo.js +11 -20
  14. package/dist/lib/analytics/clients/tracks.js +12 -12
  15. package/dist/lib/analytics/index.js +9 -12
  16. package/dist/lib/api/app.js +10 -13
  17. package/dist/lib/api/cache-purge.js +3 -10
  18. package/dist/lib/api/feature-flags.js +4 -2
  19. package/dist/lib/api/http.js +10 -18
  20. package/dist/lib/api/user.js +3 -8
  21. package/dist/lib/api.js +11 -14
  22. package/dist/lib/app-logs/app-logs.js +3 -6
  23. package/dist/lib/cli/apiConfig.js +10 -7
  24. package/dist/lib/cli/config.js +2 -3
  25. package/dist/lib/cli/envAlias.js +11 -9
  26. package/dist/lib/cli/exit.js +4 -7
  27. package/dist/lib/cli/format.js +25 -26
  28. package/dist/lib/cli/progress.js +7 -3
  29. package/dist/lib/cli/prompt.js +3 -2
  30. package/dist/lib/client-file-uploader.js +86 -87
  31. package/dist/lib/config/software.js +18 -12
  32. package/dist/lib/dev-environment/dev-environment-cli.js +6 -4
  33. package/dist/lib/dev-environment/dev-environment-configuration-file.js +4 -2
  34. package/dist/lib/dev-environment/dev-environment-core.js +3 -0
  35. package/dist/lib/env.js +16 -13
  36. package/dist/lib/envvar/api-delete.js +2 -0
  37. package/dist/lib/envvar/api-get-all.js +4 -1
  38. package/dist/lib/envvar/api-get.js +3 -1
  39. package/dist/lib/envvar/api-list.js +8 -3
  40. package/dist/lib/envvar/api-set.js +2 -0
  41. package/dist/lib/envvar/api.js +2 -5
  42. package/dist/lib/envvar/input.js +7 -8
  43. package/dist/lib/envvar/read-file.js +4 -7
  44. package/dist/lib/http/proxy-agent.js +5 -4
  45. package/dist/lib/read-file.js +13 -14
  46. package/dist/lib/search-and-replace.js +17 -26
  47. package/dist/lib/tracker.js +12 -12
  48. package/dist/lib/user-error.js +6 -5
  49. package/dist/lib/utils.js +18 -22
  50. package/dist/lib/vip-import-validate-files.js +23 -22
  51. package/npm-shrinkwrap.json +9 -1043
  52. package/package.json +3 -6
  53. package/tsconfig.json +4 -2
  54. package/dist/lib/analytics/clients/stub.js +0 -16
  55. package/dist/lib/cli/repo.js +0 -61
  56. package/noImplictAnyImportBypass.d.ts +0 -6
@@ -5,42 +5,31 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.MULTIPART_THRESHOLD = exports.COMPRESS_THRESHOLD = void 0;
7
7
  exports.checkFileAccess = checkFileAccess;
8
- exports.completeMultipartUpload = completeMultipartUpload;
9
8
  exports.detectCompressedMimeType = detectCompressedMimeType;
10
9
  exports.getFileMD5Hash = void 0;
11
10
  exports.getFileMeta = getFileMeta;
12
11
  exports.getFileSize = getFileSize;
13
- exports.getFileStats = getFileStats;
14
12
  exports.getPartBoundaries = getPartBoundaries;
15
- exports.getSignedUploadRequestData = getSignedUploadRequestData;
16
- exports.gzipFile = exports.getWorkingTempDir = void 0;
17
13
  exports.isFile = isFile;
18
14
  exports.unzipFile = void 0;
19
15
  exports.uploadImportSqlFileToS3 = uploadImportSqlFileToS3;
20
- exports.uploadPart = uploadPart;
21
16
  exports.uploadParts = uploadParts;
22
- exports.uploadUsingMultipart = uploadUsingMultipart;
23
- exports.uploadUsingPutObject = uploadUsingPutObject;
24
- var _fs = _interopRequireWildcard(require("fs"));
17
+ var _fs = require("fs");
18
+ var _promises = require("node:fs/promises");
25
19
  var _os = _interopRequireDefault(require("os"));
26
20
  var _path = _interopRequireDefault(require("path"));
27
21
  var _nodeFetch = _interopRequireDefault(require("node-fetch"));
28
22
  var _chalk = _interopRequireDefault(require("chalk"));
29
23
  var _zlib = require("zlib");
30
24
  var _crypto = require("crypto");
31
- var _promises = require("node:stream/promises");
25
+ var _promises2 = require("node:stream/promises");
32
26
  var _stream = require("stream");
33
27
  var _xml2js = require("xml2js");
34
28
  var _debug = _interopRequireDefault(require("debug"));
35
29
  var _http = _interopRequireDefault(require("../lib/api/http"));
36
30
  var _fileSize = require("../lib/constants/file-size");
37
31
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
38
- function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
39
- function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
40
- /**
41
- *
42
- * @format
43
- */
32
+ // @format
44
33
 
45
34
  /**
46
35
  * External dependencies
@@ -65,20 +54,28 @@ const UPLOAD_PART_SIZE = 16 * _fileSize.MB_IN_BYTES;
65
54
 
66
55
  // How many parts will upload at the same time
67
56
  const MAX_CONCURRENT_PART_UPLOADS = 5;
68
- const getWorkingTempDir = async () => new Promise((resolve, reject) => {
69
- _fs.default.mkdtemp(_path.default.join(_os.default.tmpdir(), 'vip-client-file-uploader'), (err, dir) => {
70
- if (err) {
71
- return reject(err);
72
- }
73
- resolve(dir);
74
- });
75
- });
76
- exports.getWorkingTempDir = getWorkingTempDir;
77
- const getFileMD5Hash = async fileName => new Promise((resolve, reject) => _fs.default.createReadStream(fileName).pipe((0, _crypto.createHash)('md5').setEncoding('hex')).on('finish', function () {
78
- resolve(this.read());
79
- }).on('error', error => reject(`could not generate file hash: ${error}`)));
57
+
58
+ // TODO: Replace with a proper definitions once we convert lib/cli/command.js to TypeScript
59
+
60
+ const getWorkingTempDir = () => (0, _promises.mkdtemp)(_path.default.join(_os.default.tmpdir(), 'vip-client-file-uploader'));
61
+ const getFileMD5Hash = async fileName => {
62
+ const src = (0, _fs.createReadStream)(fileName);
63
+ const dst = (0, _crypto.createHash)('md5');
64
+ try {
65
+ await (0, _promises2.pipeline)(src, dst);
66
+ return dst.digest().toString('hex');
67
+ } catch (err) {
68
+ throw new Error(`could not generate file hash: ${err.message}`);
69
+ }
70
+ };
80
71
  exports.getFileMD5Hash = getFileMD5Hash;
81
- const gzipFile = async (uncompressedFileName, compressedFileName) => new Promise((resolve, reject) => _fs.default.createReadStream(uncompressedFileName).pipe((0, _zlib.createGzip)()).pipe(_fs.default.createWriteStream(compressedFileName)).on('finish', resolve).on('error', error => reject(`could not compress file: ${error}`)));
72
+ const gzipFile = async (uncompressedFileName, compressedFileName) => {
73
+ try {
74
+ await (0, _promises2.pipeline)((0, _fs.createReadStream)(uncompressedFileName), (0, _zlib.createGzip)(), (0, _fs.createWriteStream)(compressedFileName));
75
+ } catch (err) {
76
+ throw new Error(`could not compress file: ${err.message}`);
77
+ }
78
+ };
82
79
 
83
80
  /**
84
81
  * Extract a .gz file and save it to a specified location
@@ -87,11 +84,10 @@ const gzipFile = async (uncompressedFileName, compressedFileName) => new Promise
87
84
  * @param {string} outputFilename The file where the unzipped data will be written
88
85
  * @return {Promise} A promise that resolves when the file is unzipped
89
86
  */
90
- exports.gzipFile = gzipFile;
91
87
  const unzipFile = async (inputFilename, outputFilename) => {
92
- const source = _fs.default.createReadStream(inputFilename);
93
- const destination = _fs.default.createWriteStream(outputFilename);
94
- await (0, _promises.pipeline)(source, (0, _zlib.createGunzip)(), destination);
88
+ const source = (0, _fs.createReadStream)(inputFilename);
89
+ const destination = (0, _fs.createWriteStream)(outputFilename);
90
+ await (0, _promises2.pipeline)(source, (0, _zlib.createGunzip)(), destination);
95
91
  };
96
92
  exports.unzipFile = unzipFile;
97
93
  async function getFileMeta(fileName) {
@@ -120,7 +116,7 @@ async function uploadImportSqlFileToS3({
120
116
  try {
121
117
  tmpDir = await getWorkingTempDir();
122
118
  } catch (err) {
123
- throw `Unable to create temporary working directory: ${err}`;
119
+ throw new Error(`Unable to create temporary working directory: ${err.message}`);
124
120
  }
125
121
  debug(`File ${_chalk.default.cyan(fileMeta.basename)} is ~ ${Math.floor(fileMeta.fileSize / _fileSize.MB_IN_BYTES)} MB\n`);
126
122
 
@@ -162,6 +158,11 @@ async function uploadImportSqlFileToS3({
162
158
  result
163
159
  };
164
160
  }
161
+
162
+ /**
163
+ * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html#API_CompleteMultipartUpload_Example_3
164
+ */
165
+
165
166
  async function uploadUsingPutObject({
166
167
  app,
167
168
  env,
@@ -190,7 +191,7 @@ async function uploadUsingPutObject({
190
191
  const progressPassThrough = new _stream.PassThrough();
191
192
  progressPassThrough.on('data', data => {
192
193
  readBytes += data.length;
193
- const percentage = Math.floor(100 * readBytes / fileSize) + '%';
194
+ const percentage = `${Math.floor(100 * readBytes / fileSize)}%`;
194
195
  debug(percentage);
195
196
  if (typeof progressCallback === 'function') {
196
197
  progressCallback(percentage);
@@ -198,7 +199,7 @@ async function uploadUsingPutObject({
198
199
  });
199
200
  const response = await (0, _nodeFetch.default)(presignedRequest.url, {
200
201
  ...fetchOptions,
201
- body: fileContent ? fileContent : _fs.default.createReadStream(fileName).pipe(progressPassThrough)
202
+ body: fileContent ? fileContent : (0, _fs.createReadStream)(fileName).pipe(progressPassThrough)
202
203
  });
203
204
  if (response.status === 200) {
204
205
  return 'ok';
@@ -214,17 +215,22 @@ async function uploadUsingPutObject({
214
215
  try {
215
216
  parsedResponse = await parser.parseStringPromise(result);
216
217
  } catch (err) {
217
- throw `Invalid response from cloud service. ${err}`;
218
+ throw new Error(`Invalid response from cloud service. ${err.message}`);
218
219
  }
219
220
  const {
220
221
  Code,
221
222
  Message
222
- } = parsedResponse.Error || {};
223
- throw `Unable to upload to cloud storage. ${JSON.stringify({
223
+ } = parsedResponse.Error;
224
+ throw new Error(`Unable to upload to cloud storage. ${JSON.stringify({
224
225
  Code,
225
226
  Message
226
- })}`;
227
+ })}`);
227
228
  }
229
+
230
+ /**
231
+ * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html#API_CreateMultipartUpload_ResponseSyntax
232
+ */
233
+
228
234
  async function uploadUsingMultipart({
229
235
  app,
230
236
  env,
@@ -250,18 +256,18 @@ async function uploadUsingMultipart({
250
256
  ignoreAttrs: true
251
257
  });
252
258
  const parsedResponse = await parser.parseStringPromise(multipartUploadResult);
253
- if (parsedResponse.Error) {
259
+ if ('Error' in parsedResponse) {
254
260
  const {
255
261
  Code,
256
262
  Message
257
263
  } = parsedResponse.Error;
258
- throw `Unable to create cloud storage object. Error: ${JSON.stringify({
264
+ throw new Error(`Unable to create cloud storage object. Error: ${JSON.stringify({
259
265
  Code,
260
266
  Message
261
- })}`;
267
+ })}`);
262
268
  }
263
- if (!parsedResponse && parsedResponse.InitiateMultipartUploadResult && parsedResponse.InitiateMultipartUploadResult.UploadId) {
264
- throw `Unable to get Upload ID from cloud storage. Error: ${multipartUploadResult}`;
269
+ if (!('InitiateMultipartUploadResult' in parsedResponse) || !parsedResponse.InitiateMultipartUploadResult.UploadId) {
270
+ throw new Error(`Unable to get Upload ID from cloud storage. Error: ${multipartUploadResult}`);
265
271
  }
266
272
  const uploadId = parsedResponse.InitiateMultipartUploadResult.UploadId;
267
273
  debug({
@@ -309,54 +315,45 @@ async function getSignedUploadRequestData({
309
315
  }
310
316
  });
311
317
  if (response.status !== 200) {
312
- throw (await response.text()) || response.statusText;
318
+ throw new Error((await response.text()) || response.statusText);
313
319
  }
314
320
  return response.json();
315
321
  }
316
322
  async function checkFileAccess(fileName) {
317
- return _fs.default.promises.access(fileName, _fs.default.R_OK);
318
- }
319
- async function getFileStats(fileName) {
320
- return _fs.default.promises.stat(fileName);
323
+ return (0, _promises.access)(fileName, _fs.constants.R_OK);
321
324
  }
322
325
  async function isFile(fileName) {
323
326
  try {
324
- const stats = await getFileStats(fileName);
327
+ const stats = await (0, _promises.stat)(fileName);
325
328
  return stats.isFile();
326
329
  } catch (err) {
327
- debug(`isFile error: ${err}`);
330
+ debug(`isFile error: ${err.message}`);
328
331
  return false;
329
332
  }
330
333
  }
331
334
  async function getFileSize(fileName) {
332
- const stats = await getFileStats(fileName);
335
+ const stats = await (0, _promises.stat)(fileName);
333
336
  return stats.size;
334
337
  }
335
338
  async function detectCompressedMimeType(fileName) {
336
339
  const ZIP_MAGIC_NUMBER = '504b0304';
337
340
  const GZ_MAGIC_NUMBER = '1f8b';
338
- let fileHeader = '';
339
- return new Promise(resolve => {
340
- _fs.default.createReadStream(fileName, {
341
- start: 0,
342
- end: 8,
343
- encoding: 'hex'
344
- }).on('data', data => {
345
- fileHeader += data;
346
- }).on('end', () => {
347
- if (ZIP_MAGIC_NUMBER === fileHeader.slice(0, ZIP_MAGIC_NUMBER.length)) {
348
- return resolve('application/zip');
349
- }
350
- if (GZ_MAGIC_NUMBER === fileHeader.slice(0, GZ_MAGIC_NUMBER.length)) {
351
- return resolve('application/gzip');
352
- }
353
- resolve();
354
- });
355
- });
341
+ const file = await (0, _promises.open)(fileName, 'r');
342
+ const {
343
+ buffer
344
+ } = await file.read(Buffer.alloc(4), 0, 4, 0);
345
+ const fileHeader = buffer.toString('hex');
346
+ if (ZIP_MAGIC_NUMBER === fileHeader.slice(0, ZIP_MAGIC_NUMBER.length)) {
347
+ return 'application/zip';
348
+ }
349
+ if (GZ_MAGIC_NUMBER === fileHeader.slice(0, GZ_MAGIC_NUMBER.length)) {
350
+ return 'application/gzip';
351
+ }
352
+ return '';
356
353
  }
357
354
  function getPartBoundaries(fileSize) {
358
355
  if (fileSize < 1) {
359
- throw 'fileSize must be greater than zero';
356
+ throw new Error('fileSize must be greater than zero');
360
357
  }
361
358
  const numParts = Math.ceil(fileSize / UPLOAD_PART_SIZE);
362
359
  return new Array(numParts).fill(undefined).map((_numPart, index) => {
@@ -393,7 +390,7 @@ async function uploadParts({
393
390
  }, 300);
394
391
  });
395
392
  const updateProgress = () => {
396
- const percentage = Math.floor(100 * totalBytesRead / fileMeta.fileSize) + '%';
393
+ const percentage = `${Math.floor(100 * totalBytesRead / fileMeta.fileSize)}%`;
397
394
  if (typeof progressCallback === 'function') {
398
395
  progressCallback(percentage);
399
396
  }
@@ -475,7 +472,7 @@ async function uploadPart({
475
472
  */
476
473
  };
477
474
 
478
- fetchOptions.body = _fs.default.createReadStream(fileName, {
475
+ fetchOptions.body = (0, _fs.createReadStream)(fileName, {
479
476
  start,
480
477
  end
481
478
  }).pipe(progressPassThrough);
@@ -493,23 +490,25 @@ async function uploadPart({
493
490
  ignoreAttrs: true
494
491
  });
495
492
  const parsed = await parser.parseStringPromise(result);
496
- if (parsed.Error) {
497
- const {
498
- Code,
499
- Message
500
- } = parsed.Error;
501
- throw `Unable to upload file part. Error: ${JSON.stringify({
502
- Code,
503
- Message
504
- })}`;
505
- }
506
- return parsed;
493
+ const {
494
+ Code,
495
+ Message
496
+ } = parsed.Error;
497
+ throw new Error(`Unable to upload file part. Error: ${JSON.stringify({
498
+ Code,
499
+ Message
500
+ })}`);
507
501
  };
508
502
  return {
509
503
  ETag: await doUpload(),
510
504
  PartNumber: s3PartNumber
511
505
  };
512
506
  }
507
+
508
+ /**
509
+ * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html#API_CompleteMultipartUpload_ResponseSyntax
510
+ */
511
+
513
512
  async function completeMultipartUpload({
514
513
  app,
515
514
  env,
@@ -546,15 +545,15 @@ async function completeMultipartUpload({
546
545
  ignoreAttrs: true
547
546
  });
548
547
  const parsed = await parser.parseStringPromise(result);
549
- if (parsed.Error) {
548
+ if ('Error' in parsed) {
550
549
  const {
551
550
  Code,
552
551
  Message
553
552
  } = parsed.Error;
554
- throw `Unable to complete the upload. Error: ${JSON.stringify({
553
+ throw new Error(`Unable to complete the upload. Error: ${JSON.stringify({
555
554
  Code,
556
555
  Message
557
- })}`;
556
+ })}`);
558
557
  }
559
558
  return parsed;
560
559
  }
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.triggerUpdate = exports.promptForUpdate = exports.getUpdateResult = exports.formatSoftwareSettings = exports.appQueryFragments = exports.appQuery = void 0;
7
+ var _promises = require("node:timers/promises");
7
8
  var _enquirer = require("enquirer");
8
9
  var _graphqlTag = _interopRequireDefault(require("graphql-tag"));
9
10
  var _debug = _interopRequireDefault(require("debug"));
@@ -14,9 +15,11 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
14
15
  /**
15
16
  * External dependencies
16
17
  */
18
+
17
19
  /**
18
20
  * Internal dependencies
19
21
  */
22
+
20
23
  const UPDATE_PROGRESS_POLL_INTERVAL = 5;
21
24
  const debug = (0, _debug.default)('@automattic/vip:bin:config-software');
22
25
  const appQuery = `
@@ -182,7 +185,7 @@ const _optionsForVersion = softwareSettings => {
182
185
  return option;
183
186
  });
184
187
  };
185
- const _processComponent = async (appTypeId, userProvidedComponent) => {
188
+ const _processComponent = (appTypeId, userProvidedComponent) => {
186
189
  const validComponents = [];
187
190
  if ((0, _app.isAppWordPress)(appTypeId)) {
188
191
  validComponents.push('wordpress', 'php', 'muplugins');
@@ -193,13 +196,13 @@ const _processComponent = async (appTypeId, userProvidedComponent) => {
193
196
  if (!validComponents.includes(userProvidedComponent)) {
194
197
  throw new _userError.default(`Component ${userProvidedComponent} is not supported. Use one of: ${validComponents.join(',')}`);
195
198
  }
196
- return userProvidedComponent;
199
+ return Promise.resolve(userProvidedComponent);
197
200
  }
198
201
  if (validComponents.length === 0) {
199
202
  throw new _userError.default('No components are supported for this application');
200
203
  }
201
204
  if (validComponents.length === 1) {
202
- return validComponents[0];
205
+ return Promise.resolve(validComponents[0]);
203
206
  }
204
207
  const choices = validComponents.map(item => ({
205
208
  message: COMPONENT_NAMES[item],
@@ -213,14 +216,14 @@ const _processComponent = async (appTypeId, userProvidedComponent) => {
213
216
  throw new _userError.default('Command cancelled by user.');
214
217
  });
215
218
  };
216
- const _processComponentVersion = async (softwareSettings, component, userProvidedVersion) => {
219
+ const _processComponentVersion = (softwareSettings, component, userProvidedVersion) => {
217
220
  const versionChoices = _optionsForVersion(softwareSettings[component]);
218
221
  if (userProvidedVersion) {
219
222
  const validValues = versionChoices.map(item => item.value);
220
223
  if (!validValues.includes(userProvidedVersion)) {
221
224
  throw new _userError.default(`Version ${userProvidedVersion} is not supported for ${COMPONENT_NAMES[component]}. Use one of: ${validValues.join(',')}`);
222
225
  }
223
- return userProvidedVersion;
226
+ return Promise.resolve(userProvidedVersion);
224
227
  }
225
228
  const versionSelect = new _enquirer.Select({
226
229
  message: `Version for ${COMPONENT_NAMES[component]} to upgrade to`,
@@ -233,7 +236,10 @@ const _processComponentVersion = async (softwareSettings, component, userProvide
233
236
  const promptForUpdate = async (appTypeId, opts, softwareSettings) => {
234
237
  const component = await _processComponent(appTypeId, opts.component);
235
238
  const version = await _processComponentVersion(softwareSettings, component, opts.version);
239
+
240
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
236
241
  const confirm = opts.force || (await new _enquirer.Confirm({
242
+ // NOSONAR
237
243
  message: `Are you sure you want to upgrade ${COMPONENT_NAMES[component]} to ${version}?`
238
244
  }).run().catch(() => {
239
245
  throw new _userError.default('Command cancelled by user.');
@@ -257,7 +263,7 @@ const triggerUpdate = async variables => {
257
263
  };
258
264
  exports.triggerUpdate = triggerUpdate;
259
265
  const _getLatestJob = async (appId, envId) => {
260
- var _result$data, _result$data$app;
266
+ var _result$data$app$envi, _result$data$app, _result$data$app$envi2, _result$data$app$envi3;
261
267
  const api = await (0, _api.default)();
262
268
  const result = await api.query({
263
269
  query: updateJobQuery,
@@ -267,20 +273,20 @@ const _getLatestJob = async (appId, envId) => {
267
273
  },
268
274
  fetchPolicy: 'network-only'
269
275
  });
270
- const jobs = (result === null || result === void 0 ? void 0 : (_result$data = result.data) === null || _result$data === void 0 ? void 0 : (_result$data$app = _result$data.app) === null || _result$data$app === void 0 ? void 0 : _result$data$app.environments[0].jobs) || [];
276
+ const jobs = (_result$data$app$envi = (_result$data$app = result.data.app) === null || _result$data$app === void 0 ? void 0 : (_result$data$app$envi2 = _result$data$app.environments) === null || _result$data$app$envi2 === void 0 ? void 0 : (_result$data$app$envi3 = _result$data$app$envi2[0]) === null || _result$data$app$envi3 === void 0 ? void 0 : _result$data$app$envi3.jobs) !== null && _result$data$app$envi !== void 0 ? _result$data$app$envi : [];
271
277
  if (jobs.length) {
272
- return jobs.reduce((prev, current) => prev.createdAt > current.createdAt ? prev : current);
278
+ return jobs.reduce((prev, current) => ((prev === null || prev === void 0 ? void 0 : prev.createdAt) || '') > ((current === null || current === void 0 ? void 0 : current.createdAt) || '') ? prev : current);
273
279
  }
274
280
  return null;
275
281
  };
276
282
  const _getCompletedJob = async (appId, envId) => {
277
283
  const latestJob = await _getLatestJob(appId, envId);
278
284
  debug('Latest job result:', latestJob);
279
- if (!latestJob || !latestJob.inProgressLock) {
285
+ if (!(latestJob !== null && latestJob !== void 0 && latestJob.inProgressLock)) {
280
286
  return latestJob;
281
287
  }
282
288
  debug(`Sleep for ${UPDATE_PROGRESS_POLL_INTERVAL} seconds`);
283
- await new Promise(resolve => setTimeout(resolve, UPDATE_PROGRESS_POLL_INTERVAL * 1000));
289
+ await (0, _promises.setTimeout)(UPDATE_PROGRESS_POLL_INTERVAL * 1000);
284
290
  return _getCompletedJob(appId, envId);
285
291
  };
286
292
  const getUpdateResult = async (appId, envId) => {
@@ -290,13 +296,13 @@ const getUpdateResult = async (appId, envId) => {
290
296
  envId
291
297
  });
292
298
  const completedJob = await _getCompletedJob(appId, envId);
293
- const success = !completedJob || (completedJob === null || completedJob === void 0 ? void 0 : (_completedJob$progres = completedJob.progress) === null || _completedJob$progres === void 0 ? void 0 : _completedJob$progres.status) === 'success';
299
+ const success = !completedJob || ((_completedJob$progres = completedJob.progress) === null || _completedJob$progres === void 0 ? void 0 : _completedJob$progres.status) === 'success';
294
300
  if (success) {
295
301
  return {
296
302
  ok: true
297
303
  };
298
304
  }
299
- const failedStep = completedJob === null || completedJob === void 0 ? void 0 : (_completedJob$progres2 = completedJob.progress) === null || _completedJob$progres2 === void 0 ? void 0 : (_completedJob$progres3 = _completedJob$progres2.steps) === null || _completedJob$progres3 === void 0 ? void 0 : _completedJob$progres3.find(step => step.status === 'failed');
305
+ const failedStep = (_completedJob$progres2 = completedJob.progress) === null || _completedJob$progres2 === void 0 ? void 0 : (_completedJob$progres3 = _completedJob$progres2.steps) === null || _completedJob$progres3 === void 0 ? void 0 : _completedJob$progres3.find(step => (step === null || step === void 0 ? void 0 : step.status) === 'failed');
300
306
  const error = failedStep ? `Failed during step: ${failedStep.name}` : 'Software update failed';
301
307
  return {
302
308
  ok: false,
@@ -307,12 +307,14 @@ async function promptForArguments(preselectedOptions, defaultOptions, suppressPr
307
307
  xdebug: false,
308
308
  xdebugConfig: preselectedOptions.xdebugConfig,
309
309
  siteSlug: '',
310
- mailpit: false
310
+ mailpit: false,
311
+ photon: false
311
312
  };
312
313
  const promptLabels = {
313
314
  xdebug: 'XDebug',
314
315
  phpmyadmin: 'phpMyAdmin',
315
- mailpit: 'Mailpit'
316
+ mailpit: 'Mailpit',
317
+ photon: 'Photon'
316
318
  };
317
319
  if (!instanceData.mediaRedirectDomain && defaultOptions.mediaRedirectDomain) {
318
320
  const mediaRedirectPromptText = `Would you like to redirect to ${defaultOptions.mediaRedirectDomain} for missing media files?`;
@@ -340,7 +342,7 @@ async function promptForArguments(preselectedOptions, defaultOptions, suppressPr
340
342
  } else {
341
343
  instanceData.elasticsearch = await promptForBoolean('Enable Elasticsearch (needed by Enterprise Search)?', !!defaultOptions.elasticsearch);
342
344
  }
343
- for (const service of ['phpmyadmin', 'xdebug', 'mailpit']) {
345
+ for (const service of ['phpmyadmin', 'xdebug', 'mailpit', 'photon']) {
344
346
  if (service in instanceData) {
345
347
  if (service in preselectedOptions) {
346
348
  instanceData[service] = preselectedOptions[service];
@@ -636,7 +638,7 @@ function processVersionOption(value) {
636
638
  }
637
639
  function addDevEnvConfigurationOptions(command) {
638
640
  // We leave the third parameter to undefined on some because the defaults are handled in preProcessInstanceData()
639
- return command.option('wordpress', 'Use a specific WordPress version', undefined, processVersionOption).option(['u', 'mu-plugins'], 'Use a specific mu-plugins changeset or local directory').option('app-code', 'Use the application code from a local directory or use "demo" for VIP skeleton code').option('phpmyadmin', 'Enable PHPMyAdmin component. By default it is disabled', undefined, processBooleanOption).option('xdebug', 'Enable XDebug. By default it is disabled', undefined, processBooleanOption).option('xdebug_config', 'Extra configuration to pass to xdebug via XDEBUG_CONFIG environment variable').option('elasticsearch', 'Enable Elasticsearch (needed by Enterprise Search)', undefined, processBooleanOption).option(['r', 'media-redirect-domain'], 'Domain to redirect for missing media files. This can be used to still have images without the need to import them locally.').option('php', 'Explicitly choose PHP version to use', undefined, processVersionOption).option(['G', 'mailhog'], 'Enable Mailpit. By default it is disabled (deprecated option, please use --mailpit instead)', undefined, processBooleanOption).option(['A', 'mailpit'], 'Enable Mailpit. By default it is disabled', undefined, processBooleanOption);
641
+ return command.option('wordpress', 'Use a specific WordPress version', undefined, processVersionOption).option(['u', 'mu-plugins'], 'Use a specific mu-plugins changeset or local directory').option('app-code', 'Use the application code from a local directory or use "demo" for VIP skeleton code').option('phpmyadmin', 'Enable PHPMyAdmin component. By default it is disabled', undefined, processBooleanOption).option('xdebug', 'Enable XDebug. By default it is disabled', undefined, processBooleanOption).option('xdebug_config', 'Extra configuration to pass to xdebug via XDEBUG_CONFIG environment variable').option('elasticsearch', 'Enable Elasticsearch (needed by Enterprise Search)', undefined, processBooleanOption).option(['r', 'media-redirect-domain'], 'Domain to redirect for missing media files. This can be used to still have images without the need to import them locally.').option('php', 'Explicitly choose PHP version to use', undefined, processVersionOption).option(['G', 'mailhog'], 'Enable Mailpit. By default it is disabled (deprecated option, please use --mailpit instead)', undefined, processBooleanOption).option(['A', 'mailpit'], 'Enable Mailpit. By default it is disabled', undefined, processBooleanOption).option(['H', 'photon'], 'Enable Photon. By default it is disabled', undefined, processBooleanOption);
640
642
  }
641
643
 
642
644
  /**
@@ -94,7 +94,8 @@ async function sanitizeConfiguration(configuration) {
94
94
  phpmyadmin: stringToBooleanIfDefined(configuration.phpmyadmin),
95
95
  xdebug: stringToBooleanIfDefined(configuration.xdebug),
96
96
  mailpit: stringToBooleanIfDefined((_configuration$mailpi = configuration.mailpit) !== null && _configuration$mailpi !== void 0 ? _configuration$mailpi : configuration.mailhog),
97
- 'media-redirect-domain': configuration['media-redirect-domain']
97
+ 'media-redirect-domain': configuration['media-redirect-domain'],
98
+ photon: stringToBooleanIfDefined(configuration.photon)
98
99
  };
99
100
 
100
101
  // Remove undefined values
@@ -119,7 +120,8 @@ function mergeConfigurationFileOptions(preselectedOptions, configurationFileOpti
119
120
  xdebug: configurationFileOptions.xdebug,
120
121
  xdebugConfig: configurationFileOptions['xdebug-config'],
121
122
  mailpit: (_configurationFileOpt = configurationFileOptions.mailpit) !== null && _configurationFileOpt !== void 0 ? _configurationFileOpt : configurationFileOptions.mailhog,
122
- mediaRedirectDomain: configurationFileOptions['media-redirect-domain']
123
+ mediaRedirectDomain: configurationFileOptions['media-redirect-domain'],
124
+ photon: configurationFileOptions.photon
123
125
  };
124
126
  const mergedOptions = {};
125
127
  Object.keys(configurationFileInstanceOptions).forEach(key => {
@@ -146,6 +146,9 @@ function preProcessInstanceData(instanceData) {
146
146
  if (!newInstanceData.phpmyadmin) {
147
147
  newInstanceData.phpmyadmin = false;
148
148
  }
149
+ if (!newInstanceData.photon) {
150
+ newInstanceData.photon = false;
151
+ }
149
152
 
150
153
  // Mailpit migration
151
154
  if (!newInstanceData.mailpit) {
package/dist/lib/env.js CHANGED
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _os = _interopRequireDefault(require("os"));
7
+ var _nodeOs = require("node:os");
8
8
  var _package = _interopRequireDefault(require("../../package.json"));
9
9
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
10
  /**
@@ -15,19 +15,22 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
15
15
  * Internal dependencies
16
16
  */
17
17
 
18
+ const app = {
19
+ name: _package.default.name,
20
+ version: _package.default.version
21
+ };
22
+ const os = {
23
+ name: (0, _nodeOs.platform)(),
24
+ version: (0, _nodeOs.release)()
25
+ };
26
+ const node = {
27
+ version: process.version
28
+ };
18
29
  const env = {
19
- app: {
20
- name: _package.default.name,
21
- version: _package.default.version
22
- },
23
- os: {
24
- name: _os.default.platform(),
25
- version: _os.default.release()
26
- },
27
- node: {
28
- version: process.version
29
- }
30
+ app,
31
+ os,
32
+ node,
33
+ userAgent: `vip-cli/${app.version} (node/${node.version}; ${os.name}/${os.version}; +https://wpvip.com)`
30
34
  };
31
- env.userAgent = `vip-cli/${_package.default.version} (node/${env.node.version}; ${env.os.name}/${env.os.version}; +https://wpvip.com)`;
32
35
  var _default = env;
33
36
  exports.default = _default;
@@ -10,9 +10,11 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
10
10
  /**
11
11
  * External dependencies
12
12
  */
13
+
13
14
  /**
14
15
  * Internal dependencies
15
16
  */
17
+
16
18
  const mutation = (0, _graphqlTag.default)`
17
19
  mutation DeleteEnvironmentVariable(
18
20
  $appId: Int!
@@ -10,9 +10,11 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
10
10
  /**
11
11
  * External dependencies
12
12
  */
13
+
13
14
  /**
14
15
  * Internal dependencies
15
16
  */
17
+
16
18
  const query = (0, _graphqlTag.default)`
17
19
  query GetEnvironmentVariablesWithValues(
18
20
  $appId: Int!
@@ -38,6 +40,7 @@ const query = (0, _graphqlTag.default)`
38
40
  }
39
41
  `;
40
42
  async function getEnvVars(appId, envId) {
43
+ var _ref, _data$app, _data$app$environment, _data$app$environment2, _data$app$environment3;
41
44
  const api = await (0, _api.default)();
42
45
  const variables = {
43
46
  appId,
@@ -49,5 +52,5 @@ async function getEnvVars(appId, envId) {
49
52
  query,
50
53
  variables
51
54
  });
52
- return data.app.environments[0].environmentVariables.nodes;
55
+ return (_ref = (_data$app = data.app) === null || _data$app === void 0 ? void 0 : (_data$app$environment = _data$app.environments) === null || _data$app$environment === void 0 ? void 0 : (_data$app$environment2 = _data$app$environment[0]) === null || _data$app$environment2 === void 0 ? void 0 : (_data$app$environment3 = _data$app$environment2.environmentVariables) === null || _data$app$environment3 === void 0 ? void 0 : _data$app$environment3.nodes) !== null && _ref !== void 0 ? _ref : null;
53
56
  }
@@ -9,12 +9,14 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
9
9
  /**
10
10
  * External dependencies
11
11
  */
12
+
12
13
  /**
13
14
  * Internal dependencies
14
15
  */
16
+
15
17
  async function getEnvVar(appId, envId, name) {
16
18
  const envvars = await (0, _apiGetAll.default)(appId, envId);
17
- return envvars.find(({
19
+ return envvars === null || envvars === void 0 ? void 0 : envvars.find(({
18
20
  name: foundName
19
21
  }) => name === foundName);
20
22
  }