@automattic/vip 2.32.4 → 2.33.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.
@@ -7,7 +7,9 @@ exports.RunningSprite = exports.RUNNING_SPRITE_GLYPHS = void 0;
7
7
  exports.capitalize = capitalize;
8
8
  exports.formatBytes = void 0;
9
9
  exports.formatData = formatData;
10
+ exports.formatDuration = formatDuration;
10
11
  exports.formatEnvironment = formatEnvironment;
12
+ exports.formatMetricBytes = void 0;
11
13
  exports.formatSearchReplaceValues = formatSearchReplaceValues;
12
14
  exports.getGlyphForStatus = getGlyphForStatus;
13
15
  exports.isJson = isJson;
@@ -185,14 +187,56 @@ function formatSearchReplaceValues(values, message) {
185
187
  }
186
188
 
187
189
  // Format bytes into kilobytes, megabytes, etc based on the size
188
- const formatBytes = (bytes, decimals = 2) => {
190
+ // for historical reasons, this uses KB instead of KiB, MB instead of MiB and so on.
191
+ const formatBytes = (bytes, decimals = 2, bytesMultiplier = 1024, sizes = ['bytes', 'KB', 'MB', 'GB', 'TB']) => {
189
192
  if (0 === bytes) {
190
193
  return '0 Bytes';
191
194
  }
192
- const bytesMultiplier = 1024;
193
195
  const dm = decimals < 0 ? 0 : decimals;
194
- const sizes = ['bytes', 'KB', 'MB', 'GB', 'TB'];
195
196
  const idx = Math.floor(Math.log(bytes) / Math.log(bytesMultiplier));
196
197
  return `${parseFloat((bytes / Math.pow(bytesMultiplier, idx)).toFixed(dm))} ${sizes[idx]}`;
197
198
  };
198
- exports.formatBytes = formatBytes;
199
+
200
+ /**
201
+ * Format bytes in powers of 1000, based on the size
202
+ * This is how it's displayed on Macs
203
+ */
204
+ exports.formatBytes = formatBytes;
205
+ const formatMetricBytes = (bytes, decimals = 2) => {
206
+ return formatBytes(bytes, decimals, 1000);
207
+ };
208
+
209
+ /*
210
+ * Get the duration between two dates
211
+ *
212
+ * @param {Date} from The start date
213
+ * @param {Date} to The end date
214
+ * @returns {string} The duration between the two dates
215
+ */
216
+ exports.formatMetricBytes = formatMetricBytes;
217
+ function formatDuration(from, to) {
218
+ const millisecondsPerSecond = 1000;
219
+ const millisecondsPerMinute = 60 * millisecondsPerSecond;
220
+ const millisecondsPerHour = 60 * millisecondsPerMinute;
221
+ const millisecondsPerDay = 24 * millisecondsPerHour;
222
+ const duration = to.getTime() - from.getTime();
223
+ if (duration < 1000) return '0 second';
224
+ const days = Math.floor(duration / millisecondsPerDay);
225
+ const hours = Math.floor(duration % millisecondsPerDay / millisecondsPerHour);
226
+ const minutes = Math.floor(duration % millisecondsPerHour / millisecondsPerMinute);
227
+ const seconds = Math.floor(duration % millisecondsPerMinute / millisecondsPerSecond);
228
+ let durationString = '';
229
+ if (days > 0) {
230
+ durationString += `${days} day${days > 1 ? 's' : ''} `;
231
+ }
232
+ if (hours > 0) {
233
+ durationString += `${hours} hour${hours > 1 ? 's' : ''} `;
234
+ }
235
+ if (minutes > 0) {
236
+ durationString += `${minutes} minute${minutes > 1 ? 's' : ''} `;
237
+ }
238
+ if (seconds > 0) {
239
+ durationString += `${seconds} second${seconds > 1 ? 's' : ''}`;
240
+ }
241
+ return durationString.trim();
242
+ }
@@ -3,9 +3,11 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.ProgressTracker = void 0;
6
+ exports.StepStatus = exports.ProgressTracker = void 0;
7
7
  var _singleLineLog = require("single-line-log");
8
8
  var _format = require("../../lib/cli/format");
9
+ var _os = _interopRequireDefault(require("os"));
10
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
9
11
  // @format
10
12
 
11
13
  /**
@@ -17,7 +19,17 @@ var _format = require("../../lib/cli/format");
17
19
  */
18
20
 
19
21
  const PRINT_INTERVAL = process.env.DEBUG ? 5000 : 200; // How often the report is printed. Mainly affects the "spinner" animation.
20
- const COMPLETED_STEP_SLUGS = ['success', 'skipped'];
22
+ let StepStatus = /*#__PURE__*/function (StepStatus) {
23
+ StepStatus["PENDING"] = "pending";
24
+ StepStatus["RUNNING"] = "running";
25
+ StepStatus["SUCCESS"] = "success";
26
+ StepStatus["FAILED"] = "failed";
27
+ StepStatus["UNKNOWN"] = "unknown";
28
+ StepStatus["SKIPPED"] = "skipped";
29
+ return StepStatus;
30
+ }({});
31
+ exports.StepStatus = StepStatus;
32
+ const COMPLETED_STEP_SLUGS = [StepStatus.SUCCESS, StepStatus.SKIPPED];
21
33
  class ProgressTracker {
22
34
  // Track the state of each step
23
35
 
@@ -27,6 +39,14 @@ class ProgressTracker {
27
39
 
28
40
  // This gets printed after the step status
29
41
 
42
+ /**
43
+ * This determines from which step should we display the steps
44
+ *
45
+ * Useful when you want to display a prompt.
46
+ *
47
+ * And we don't want to repeatedly display the steps that has finished.
48
+ */
49
+ displayFromStep = 0;
30
50
  constructor(steps) {
31
51
  this.runningSprite = new _format.RunningSprite();
32
52
  this.hasFailure = false;
@@ -48,7 +68,7 @@ class ProgressTracker {
48
68
  map.set(id, {
49
69
  id,
50
70
  name,
51
- status: status || 'pending'
71
+ status: status || StepStatus.PENDING
52
72
  });
53
73
  return map;
54
74
  }, new Map());
@@ -90,7 +110,7 @@ class ProgressTracker {
90
110
  }) => status === 'pending');
91
111
  if (firstPendingStepIndex !== -1) {
92
112
  // "Promote" the first "pending" to "running"
93
- formattedSteps[firstPendingStepIndex].status = 'running';
113
+ formattedSteps[firstPendingStepIndex].status = StepStatus.RUNNING;
94
114
  }
95
115
  }
96
116
  this.stepsFromServer = this.mapSteps(formattedSteps);
@@ -114,16 +134,16 @@ class ProgressTracker {
114
134
  }) => status === 'running');
115
135
  }
116
136
  stepRunning(stepId) {
117
- this.setStatusForStepId(stepId, 'running');
137
+ this.setStatusForStepId(stepId, StepStatus.RUNNING);
118
138
  }
119
139
  stepFailed(stepId) {
120
- this.setStatusForStepId(stepId, 'failed');
140
+ this.setStatusForStepId(stepId, StepStatus.FAILED);
121
141
  }
122
142
  stepSkipped(stepId) {
123
- this.setStatusForStepId(stepId, 'skipped');
143
+ this.setStatusForStepId(stepId, StepStatus.SKIPPED);
124
144
  }
125
145
  stepSuccess(stepId) {
126
- this.setStatusForStepId(stepId, 'success');
146
+ this.setStatusForStepId(stepId, StepStatus.SUCCESS);
127
147
  // The stepSuccess helper automatically sets the next step to "running"
128
148
  const nextStep = this.getNextStep();
129
149
  if (nextStep) {
@@ -163,6 +183,32 @@ class ProgressTracker {
163
183
  clearInterval(this.printInterval);
164
184
  }
165
185
  }
186
+ async handleContinuePrompt(prompt) {
187
+ this.print();
188
+ this.stopPrinting();
189
+ const returnValue = await prompt();
190
+ this.displayFromStep = [...this.getSteps().values()].findIndex(step => step.status === StepStatus.RUNNING);
191
+ let hasPrintedOnce = false;
192
+ const printingStartedPromise = new Promise(resolve => {
193
+ this.startPrinting(() => {
194
+ if (hasPrintedOnce) {
195
+ return;
196
+ }
197
+
198
+ // this is so that we leave some room for the progress tracker to refresh
199
+ // without this, any prompt, or any text in between will get overwritten by the progress tracker
200
+ let linesToSkip = '';
201
+ for (let iteration = 0; iteration < this.stepsFromCaller.size; iteration++) {
202
+ linesToSkip += _os.default.EOL;
203
+ }
204
+ process.stdout.write(linesToSkip);
205
+ hasPrintedOnce = true;
206
+ resolve();
207
+ });
208
+ });
209
+ await printingStartedPromise;
210
+ return returnValue;
211
+ }
166
212
  print({
167
213
  clearAfter = false
168
214
  } = {}) {
@@ -177,7 +223,10 @@ class ProgressTracker {
177
223
  percentage,
178
224
  status,
179
225
  progress
180
- }) => {
226
+ }, stepNumber) => {
227
+ if (stepNumber < this.displayFromStep) {
228
+ return accumulator;
229
+ }
181
230
  const statusIcon = (0, _format.getGlyphForStatus)(status, this.runningSprite);
182
231
  let suffix = '';
183
232
  if (id === 'upload') {
@@ -24,13 +24,13 @@ exports.startEnvironment = startEnvironment;
24
24
  exports.stopEnvironment = stopEnvironment;
25
25
  exports.updateEnvironment = updateEnvironment;
26
26
  exports.writeEnvironmentData = writeEnvironmentData;
27
+ var _nodeOs = _interopRequireDefault(require("node:os"));
28
+ var _nodeFs = _interopRequireDefault(require("node:fs"));
29
+ var _nodePath = _interopRequireDefault(require("node:path"));
27
30
  var _debug = _interopRequireDefault(require("debug"));
28
31
  var _xdgBasedir = _interopRequireDefault(require("xdg-basedir"));
29
32
  var _nodeFetch = _interopRequireDefault(require("node-fetch"));
30
- var _os = _interopRequireDefault(require("os"));
31
- var _fs = _interopRequireDefault(require("fs"));
32
33
  var _ejs = _interopRequireDefault(require("ejs"));
33
- var _path = _interopRequireDefault(require("path"));
34
34
  var _chalk = _interopRequireDefault(require("chalk"));
35
35
  var _enquirer = require("enquirer");
36
36
  var _copyDir = _interopRequireDefault(require("copy-dir"));
@@ -43,6 +43,7 @@ var _app = _interopRequireDefault(require("../api/app"));
43
43
  var _devEnvironment = require("../constants/dev-environment");
44
44
  var _software = require("../config/software");
45
45
  var _userError = _interopRequireDefault(require("../user-error"));
46
+ var _proxyAgent = require("../http/proxy-agent");
46
47
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
47
48
  /**
48
49
  * External dependencies
@@ -53,8 +54,8 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
53
54
  */
54
55
 
55
56
  const debug = (0, _debug.default)('@automattic/vip:bin:dev-environment');
56
- const landoFileTemplatePath = _path.default.join(__dirname, '..', '..', '..', 'assets', 'dev-env.lando.template.yml.ejs');
57
- const nginxFileTemplatePath = _path.default.join(__dirname, '..', '..', '..', 'assets', 'dev-env.nginx.template.conf.ejs');
57
+ const landoFileTemplatePath = _nodePath.default.join(__dirname, '..', '..', '..', 'assets', 'dev-env.lando.template.yml.ejs');
58
+ const nginxFileTemplatePath = _nodePath.default.join(__dirname, '..', '..', '..', 'assets', 'dev-env.nginx.template.conf.ejs');
58
59
  const landoFileName = '.lando.yml';
59
60
  const landoBackupFileName = '.lando.backup.yml';
60
61
  const nginxFileName = 'extra.conf';
@@ -63,13 +64,13 @@ const uploadPathString = 'uploads';
63
64
  const nginxPathString = 'nginx';
64
65
  function xdgDataDirectory() {
65
66
  var _xdgBasedir$data;
66
- return (_xdgBasedir$data = _xdgBasedir.default.data) !== null && _xdgBasedir$data !== void 0 && _xdgBasedir$data.length ? _xdgBasedir.default.data : _os.default.tmpdir();
67
+ return (_xdgBasedir$data = _xdgBasedir.default.data) !== null && _xdgBasedir$data !== void 0 && _xdgBasedir$data.length ? _xdgBasedir.default.data : _nodeOs.default.tmpdir();
67
68
  }
68
69
  async function startEnvironment(lando, slug, options) {
69
70
  debug('Will start an environment', slug);
70
71
  const instancePath = getEnvironmentPath(slug);
71
72
  debug('Instance path for', slug, 'is:', instancePath);
72
- const environmentExists = _fs.default.existsSync(instancePath);
73
+ const environmentExists = _nodeFs.default.existsSync(instancePath);
73
74
  if (!environmentExists) {
74
75
  throw new Error(_devEnvironment.DEV_ENVIRONMENT_NOT_FOUND);
75
76
  }
@@ -91,7 +92,7 @@ async function stopEnvironment(lando, slug) {
91
92
  debug('Will stop an environment', slug);
92
93
  const instancePath = getEnvironmentPath(slug);
93
94
  debug('Instance path for', slug, 'is:', instancePath);
94
- const environmentExists = _fs.default.existsSync(instancePath);
95
+ const environmentExists = _nodeFs.default.existsSync(instancePath);
95
96
  if (!environmentExists) {
96
97
  throw new Error(_devEnvironment.DEV_ENVIRONMENT_NOT_FOUND);
97
98
  }
@@ -102,7 +103,7 @@ async function createEnvironment(instanceData) {
102
103
  debug('Will process an environment', slug, 'with instanceData for creation: ', instanceData);
103
104
  const instancePath = getEnvironmentPath(slug);
104
105
  debug('Instance path for', slug, 'is:', instancePath);
105
- const alreadyExists = _fs.default.existsSync(instancePath);
106
+ const alreadyExists = _nodeFs.default.existsSync(instancePath);
106
107
  if (alreadyExists) {
107
108
  throw new Error('Environment already exists.');
108
109
  }
@@ -115,7 +116,7 @@ async function updateEnvironment(instanceData) {
115
116
  debug('Will process an environment', slug, 'with instanceData for updating: ', instanceData);
116
117
  const instancePath = getEnvironmentPath(slug);
117
118
  debug('Instance path for', slug, 'is:', instancePath);
118
- const alreadyExists = _fs.default.existsSync(instancePath);
119
+ const alreadyExists = _nodeFs.default.existsSync(instancePath);
119
120
  if (!alreadyExists) {
120
121
  throw new Error("Environment doesn't exist.");
121
122
  }
@@ -180,15 +181,15 @@ async function destroyEnvironment(lando, slug, removeFiles) {
180
181
  if (!environmentExists) {
181
182
  throw new Error(_devEnvironment.DEV_ENVIRONMENT_NOT_FOUND);
182
183
  }
183
- const landoFilePath = _path.default.join(instancePath, landoFileName);
184
- if (_fs.default.existsSync(landoFilePath)) {
184
+ const landoFilePath = _nodePath.default.join(instancePath, landoFileName);
185
+ if (_nodeFs.default.existsSync(landoFilePath)) {
185
186
  debug('Lando file exists, will lando destroy.');
186
187
  await (0, _devEnvironmentLando.landoDestroy)(lando, instancePath);
187
188
  } else {
188
189
  debug("Lando file doesn't exist, skipping lando destroy.");
189
190
  }
190
191
  if (removeFiles) {
191
- await _fs.default.promises.rm(instancePath, {
192
+ await _nodeFs.default.promises.rm(instancePath, {
192
193
  recursive: true
193
194
  });
194
195
  console.log(`${_chalk.default.green('✓')} Environment files deleted successfully.`);
@@ -265,9 +266,9 @@ function exec(lando, slug, args, options = {}) {
265
266
  }
266
267
  async function doesEnvironmentExist(instancePath) {
267
268
  debug('Will check for environment at', instancePath);
268
- const file = _path.default.join(instancePath, instanceDataFileName);
269
+ const file = _nodePath.default.join(instancePath, instanceDataFileName);
269
270
  try {
270
- const stats = await _fs.default.promises.stat(file);
271
+ const stats = await _nodeFs.default.promises.stat(file);
271
272
  return stats.isFile();
272
273
  } catch (err) {
273
274
  return false;
@@ -276,11 +277,11 @@ async function doesEnvironmentExist(instancePath) {
276
277
  function readEnvironmentData(slug) {
277
278
  debug('Will try to get instance data for environment', slug);
278
279
  const instancePath = getEnvironmentPath(slug);
279
- const instanceDataTargetPath = _path.default.join(instancePath, instanceDataFileName);
280
+ const instanceDataTargetPath = _nodePath.default.join(instancePath, instanceDataFileName);
280
281
  let instanceDataString;
281
282
  let instanceData;
282
283
  try {
283
- instanceDataString = _fs.default.readFileSync(instanceDataTargetPath, 'utf8');
284
+ instanceDataString = _nodeFs.default.readFileSync(instanceDataTargetPath, 'utf8');
284
285
  } catch (error) {
285
286
  const err = error;
286
287
  throw new _userError.default(`There was an error reading file "${instanceDataTargetPath}": ${err.message}.`);
@@ -326,44 +327,44 @@ function readEnvironmentData(slug) {
326
327
  function writeEnvironmentData(slug, data) {
327
328
  debug('Will try to write instance data for environment', slug);
328
329
  const instancePath = getEnvironmentPath(slug);
329
- const instanceDataTargetPath = _path.default.join(instancePath, instanceDataFileName);
330
- return _fs.default.promises.writeFile(instanceDataTargetPath, JSON.stringify(data, null, 2));
330
+ const instanceDataTargetPath = _nodePath.default.join(instancePath, instanceDataFileName);
331
+ return _nodeFs.default.promises.writeFile(instanceDataTargetPath, JSON.stringify(data, null, 2));
331
332
  }
332
333
  async function prepareLandoEnv(instanceData, instancePath) {
333
334
  const landoFile = await _ejs.default.renderFile(landoFileTemplatePath, instanceData);
334
335
  const nginxFile = await _ejs.default.renderFile(nginxFileTemplatePath, instanceData);
335
336
  const instanceDataFile = JSON.stringify(instanceData);
336
- const landoFileTargetPath = _path.default.join(instancePath, landoFileName);
337
- const landoBackupFileTargetPath = _path.default.join(instancePath, landoBackupFileName);
338
- const nginxFolderPath = _path.default.join(instancePath, nginxPathString);
339
- const nginxFileTargetPath = _path.default.join(nginxFolderPath, nginxFileName);
340
- const instanceDataTargetPath = _path.default.join(instancePath, instanceDataFileName);
341
- await _fs.default.promises.mkdir(instancePath, {
337
+ const landoFileTargetPath = _nodePath.default.join(instancePath, landoFileName);
338
+ const landoBackupFileTargetPath = _nodePath.default.join(instancePath, landoBackupFileName);
339
+ const nginxFolderPath = _nodePath.default.join(instancePath, nginxPathString);
340
+ const nginxFileTargetPath = _nodePath.default.join(nginxFolderPath, nginxFileName);
341
+ const instanceDataTargetPath = _nodePath.default.join(instancePath, instanceDataFileName);
342
+ await _nodeFs.default.promises.mkdir(instancePath, {
342
343
  recursive: true
343
344
  });
344
- await _fs.default.promises.mkdir(nginxFolderPath, {
345
+ await _nodeFs.default.promises.mkdir(nginxFolderPath, {
345
346
  recursive: true
346
347
  });
347
- const landoFileExists = await _fs.default.promises.stat(landoFileTargetPath).catch(() => false);
348
+ const landoFileExists = await _nodeFs.default.promises.stat(landoFileTargetPath).catch(() => false);
348
349
  if (landoFileExists) {
349
- await _fs.default.promises.copyFile(landoFileTargetPath, landoBackupFileTargetPath);
350
+ await _nodeFs.default.promises.copyFile(landoFileTargetPath, landoBackupFileTargetPath);
350
351
  console.log(`Backup of ${landoFileName} was created in ${landoBackupFileTargetPath}`);
351
352
  }
352
- await Promise.all([_fs.default.promises.writeFile(landoFileTargetPath, landoFile), _fs.default.promises.writeFile(nginxFileTargetPath, nginxFile), _fs.default.promises.writeFile(instanceDataTargetPath, instanceDataFile)]);
353
+ await Promise.all([_nodeFs.default.promises.writeFile(landoFileTargetPath, landoFile), _nodeFs.default.promises.writeFile(nginxFileTargetPath, nginxFile), _nodeFs.default.promises.writeFile(instanceDataTargetPath, instanceDataFile)]);
353
354
  debug(`Lando file created in ${landoFileTargetPath}`);
354
355
  debug(`Nginx file created in ${nginxFileTargetPath}`);
355
356
  debug(`Instance data file created in ${instanceDataTargetPath}`);
356
357
  }
357
358
  function getAllEnvironmentNames() {
358
359
  const mainEnvironmentPath = xdgDataDirectory();
359
- const baseDir = _path.default.join(mainEnvironmentPath, 'vip', 'dev-environment');
360
- const doWeHaveAnyEnvironment = _fs.default.existsSync(baseDir);
360
+ const baseDir = _nodePath.default.join(mainEnvironmentPath, 'vip', 'dev-environment');
361
+ const doWeHaveAnyEnvironment = _nodeFs.default.existsSync(baseDir);
361
362
  let envNames = [];
362
363
  if (doWeHaveAnyEnvironment) {
363
- const files = _fs.default.readdirSync(baseDir);
364
+ const files = _nodeFs.default.readdirSync(baseDir);
364
365
  envNames = files.filter(file => {
365
- const fullPath = _path.default.join(baseDir, file);
366
- return _fs.default.lstatSync(fullPath).isDirectory();
366
+ const fullPath = _nodePath.default.join(baseDir, file);
367
+ return _nodeFs.default.lstatSync(fullPath).isDirectory();
367
368
  });
368
369
  }
369
370
  return envNames;
@@ -373,7 +374,7 @@ function getEnvironmentPath(name) {
373
374
  throw new Error('Name was not provided');
374
375
  }
375
376
  const mainEnvironmentPath = xdgDataDirectory();
376
- return _path.default.join(mainEnvironmentPath, 'vip', 'dev-environment', name + '');
377
+ return _nodePath.default.join(mainEnvironmentPath, 'vip', 'dev-environment', name + '');
377
378
  }
378
379
  async function getApplicationInformation(appId, envType) {
379
380
  // $FlowFixMe: gql template is not supported by flow
@@ -448,10 +449,10 @@ async function resolveImportPath(slug, fileName, searchReplace, inPlace) {
448
449
  debug(`Will try to resolve path - ${fileName}`);
449
450
  let resolvedPath = (0, _devEnvironmentCli.resolvePath)(fileName);
450
451
  debug(`Filename ${fileName} resolved to ${resolvedPath}`);
451
- if (!_fs.default.existsSync(resolvedPath)) {
452
+ if (!_nodeFs.default.existsSync(resolvedPath)) {
452
453
  throw new _userError.default(`The provided file ${resolvedPath} does not exist or it is not valid (see "--help" for examples)`);
453
454
  }
454
- if (_fs.default.lstatSync(resolvedPath).isDirectory()) {
455
+ if (_nodeFs.default.lstatSync(resolvedPath).isDirectory()) {
455
456
  throw new _userError.default(`The provided file ${resolvedPath} is a directory. Please point to a sql file.`);
456
457
  }
457
458
 
@@ -473,14 +474,14 @@ async function resolveImportPath(slug, fileName, searchReplace, inPlace) {
473
474
  }
474
475
  async function importMediaPath(slug, filePath) {
475
476
  const resolvedPath = (0, _devEnvironmentCli.resolvePath)(filePath);
476
- if (!_fs.default.existsSync(resolvedPath) || !_fs.default.lstatSync(resolvedPath).isDirectory()) {
477
+ if (!_nodeFs.default.existsSync(resolvedPath) || !_nodeFs.default.lstatSync(resolvedPath).isDirectory()) {
477
478
  throw new Error('The provided path does not exist or it is not valid (see "--help" for examples)');
478
479
  }
479
480
  const environmentPath = getEnvironmentPath(slug);
480
481
  if (!(await doesEnvironmentExist(environmentPath))) {
481
482
  throw new Error(_devEnvironment.DEV_ENVIRONMENT_NOT_FOUND);
482
483
  }
483
- const files = _fs.default.readdirSync(resolvedPath);
484
+ const files = _nodeFs.default.readdirSync(resolvedPath);
484
485
  if (files.includes(uploadPathString)) {
485
486
  const confirm = await (0, _enquirer.prompt)({
486
487
  type: 'confirm',
@@ -491,7 +492,7 @@ async function importMediaPath(slug, filePath) {
491
492
  return;
492
493
  }
493
494
  }
494
- const uploadsPath = _path.default.join(environmentPath, uploadPathString);
495
+ const uploadsPath = _nodePath.default.join(environmentPath, uploadPathString);
495
496
  console.log(`${_chalk.default.yellow('-')} Started copying files`);
496
497
  _copyDir.default.sync(resolvedPath, uploadsPath);
497
498
  console.log(`${_chalk.default.green('✓')} Files successfully copied to ${uploadsPath}.`);
@@ -617,7 +618,10 @@ async function maybeUpdateVersion(slug) {
617
618
  */
618
619
  function fetchVersionList() {
619
620
  const url = `https://${_devEnvironment.DEV_ENVIRONMENT_RAW_GITHUB_HOST}${_devEnvironment.DEV_ENVIRONMENT_WORDPRESS_VERSIONS_URI}`;
620
- return (0, _nodeFetch.default)(url).then(res => res.json());
621
+ const proxyAgent = (0, _proxyAgent.createProxyAgent)(url);
622
+ return (0, _nodeFetch.default)(url, {
623
+ agent: proxyAgent ?? undefined
624
+ }).then(res => res.json());
621
625
  }
622
626
 
623
627
  /**
@@ -631,7 +635,7 @@ async function isVersionListExpired(cacheFile, ttl) {
631
635
  try {
632
636
  const {
633
637
  mtime: expire
634
- } = await _fs.default.promises.stat(cacheFile);
638
+ } = await _nodeFs.default.promises.stat(cacheFile);
635
639
  expire.setSeconds(expire.getSeconds() + ttl);
636
640
  return +new Date() > +expire;
637
641
  } catch (err) {
@@ -645,13 +649,13 @@ async function isVersionListExpired(cacheFile, ttl) {
645
649
  async function getVersionList() {
646
650
  let res;
647
651
  const mainEnvironmentPath = xdgDataDirectory();
648
- const cacheFilePath = _path.default.join(mainEnvironmentPath, 'vip');
649
- const cacheFile = _path.default.join(cacheFilePath, _devEnvironment.DEV_ENVIRONMENT_WORDPRESS_CACHE_KEY);
652
+ const cacheFilePath = _nodePath.default.join(mainEnvironmentPath, 'vip');
653
+ const cacheFile = _nodePath.default.join(cacheFilePath, _devEnvironment.DEV_ENVIRONMENT_WORDPRESS_CACHE_KEY);
650
654
  // Handle from cache
651
655
  try {
652
656
  // If the path for the cache file doesn't exist, create it
653
- if (!_fs.default.existsSync(cacheFilePath)) {
654
- await _fs.default.promises.mkdir(cacheFilePath, {
657
+ if (!_nodeFs.default.existsSync(cacheFilePath)) {
658
+ await _nodeFs.default.promises.mkdir(cacheFilePath, {
655
659
  recursive: true
656
660
  });
657
661
  }
@@ -659,7 +663,7 @@ async function getVersionList() {
659
663
  // If the cache does not exist or has expired, refresh it
660
664
  if (await isVersionListExpired(cacheFile, _devEnvironment.DEV_ENVIRONMENT_WORDPRESS_VERSION_TTL)) {
661
665
  res = await fetchVersionList();
662
- await _fs.default.promises.writeFile(cacheFile, JSON.stringify(res));
666
+ await _nodeFs.default.promises.writeFile(cacheFile, JSON.stringify(res));
663
667
  }
664
668
  } catch (err) {
665
669
  // Soft error handling here, since it's still possible to use a previously cached file.
@@ -669,7 +673,7 @@ async function getVersionList() {
669
673
 
670
674
  // Try to parse the cached file if it exists.
671
675
  try {
672
- const data = await _fs.default.promises.readFile(cacheFile, 'utf8');
676
+ const data = await _nodeFs.default.promises.readFile(cacheFile, 'utf8');
673
677
  return JSON.parse(data);
674
678
  } catch (err) {
675
679
  debug(err);
@@ -721,7 +725,7 @@ function generateVSCodeWorkspace(slug) {
721
725
  }]
722
726
  }
723
727
  };
724
- _fs.default.writeFileSync(workspacePath, JSON.stringify(workspace, null, 2));
728
+ _nodeFs.default.writeFileSync(workspacePath, JSON.stringify(workspace, null, 2));
725
729
  return workspacePath;
726
730
  }
727
731
  const generatePathMappings = (location, instanceData) => {
@@ -730,19 +734,19 @@ const generatePathMappings = (location, instanceData) => {
730
734
  pathMappings['/wp/wp-content/mu-plugins'] = instanceData.muPlugins.dir;
731
735
  }
732
736
  if (instanceData.appCode.dir) {
733
- pathMappings['/wp/wp-content/client-mu-plugins'] = _path.default.resolve(instanceData.appCode.dir, 'client-mu-plugins');
734
- pathMappings['/wp/wp-content/images'] = _path.default.resolve(instanceData.appCode.dir, 'images');
735
- pathMappings['/wp/wp-content/languages'] = _path.default.resolve(instanceData.appCode.dir, 'languages');
736
- pathMappings['/wp/wp-content/plugins'] = _path.default.resolve(instanceData.appCode.dir, 'plugins');
737
- pathMappings['/wp/wp-content/private'] = _path.default.resolve(instanceData.appCode.dir, 'private');
738
- pathMappings['/wp/wp-content/themes'] = _path.default.resolve(instanceData.appCode.dir, 'themes');
739
- pathMappings['/wp/wp-content/vip-config'] = _path.default.resolve(instanceData.appCode.dir, 'vip-config');
740
- }
741
- pathMappings['/wp'] = _path.default.resolve(location, 'wordpress');
737
+ pathMappings['/wp/wp-content/client-mu-plugins'] = _nodePath.default.resolve(instanceData.appCode.dir, 'client-mu-plugins');
738
+ pathMappings['/wp/wp-content/images'] = _nodePath.default.resolve(instanceData.appCode.dir, 'images');
739
+ pathMappings['/wp/wp-content/languages'] = _nodePath.default.resolve(instanceData.appCode.dir, 'languages');
740
+ pathMappings['/wp/wp-content/plugins'] = _nodePath.default.resolve(instanceData.appCode.dir, 'plugins');
741
+ pathMappings['/wp/wp-content/private'] = _nodePath.default.resolve(instanceData.appCode.dir, 'private');
742
+ pathMappings['/wp/wp-content/themes'] = _nodePath.default.resolve(instanceData.appCode.dir, 'themes');
743
+ pathMappings['/wp/wp-content/vip-config'] = _nodePath.default.resolve(instanceData.appCode.dir, 'vip-config');
744
+ }
745
+ pathMappings['/wp'] = _nodePath.default.resolve(location, 'wordpress');
742
746
  return pathMappings;
743
747
  };
744
748
  function getVSCodeWorkspacePath(slug) {
745
749
  const location = getEnvironmentPath(slug);
746
- const workspacePath = _path.default.join(location, `${slug}.code-workspace`);
750
+ const workspacePath = _nodePath.default.join(location, `${slug}.code-workspace`);
747
751
  return workspacePath;
748
752
  }
@@ -366,9 +366,14 @@ async function getExtraServicesConnections(lando, app) {
366
366
  const allServices = await lando.engine.list({
367
367
  project: app.project
368
368
  });
369
+ const defaultDisplayConfiguration = {
370
+ skip: false,
371
+ label: null,
372
+ protocol: null
373
+ };
369
374
  for (const service of allServices) {
370
- const displayConfiguration = extraServiceDisplayConfiguration.find(conf => conf.name === service.service);
371
- if (!displayConfiguration || displayConfiguration.skip) {
375
+ const displayConfiguration = extraServiceDisplayConfiguration.find(conf => conf.name === service.service) ?? defaultDisplayConfiguration;
376
+ if (displayConfiguration.skip) {
372
377
  continue;
373
378
  }
374
379
 
@@ -398,7 +403,7 @@ async function checkEnvHealth(lando, instancePath) {
398
403
  urls[url] = service.service;
399
404
  });
400
405
  });
401
- const urlsToScan = Object.keys(urls);
406
+ const urlsToScan = Object.keys(urls).filter(url => !url.includes('*'));
402
407
  let scanResults = [];
403
408
  if (Array.isArray(app.urls)) {
404
409
  scanResults = app.urls;