@automattic/vip 3.18.0 → 3.19.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.
@@ -67,7 +67,7 @@ function isSupportedUrl(urlToTest) {
67
67
  let url;
68
68
  try {
69
69
  url = new URL(urlToTest);
70
- } catch (err) {
70
+ } catch {
71
71
  return false;
72
72
  }
73
73
  return url.protocol === 'http:' || url.protocol === 'https:';
@@ -147,7 +147,7 @@ async function gates(app, env, fileNameOrURL, isUrl = false, md5 = null) {
147
147
  }
148
148
  try {
149
149
  await (0, _clientFileUploader.checkFileAccess)(fileName);
150
- } catch (err) {
150
+ } catch {
151
151
  await track('import_sql_command_error', {
152
152
  error_type: 'sqlfile-unreadable'
153
153
  });
package/dist/bin/vip.js CHANGED
@@ -21,7 +21,7 @@ const tokenURL = 'https://dashboard.wpvip.com/me/cli/token';
21
21
  const customDeployToken = process.env.WPVIP_DEPLOY_TOKEN;
22
22
  const runCmd = async function () {
23
23
  const cmd = (0, _command.default)();
24
- cmd.command('logout', 'Log out the current authenticated VIP-CLI user.').command('app', 'Interact with applications that the current authenticated VIP-CLI user has permission to access.').command('backup', 'Generate a backup of an environment.').command('cache', 'Manage page cache for an environment.').command('config', 'Manage environment configurations.').command('dev-env', 'Create and manage VIP Local Development Environments.').command('export', 'Export a copy of data associated with an environment.').command('import', 'Import media or SQL database files to an environment.').command('logs', 'Retrieve Runtime Logs from an environment.').command('search-replace', 'Search for a string in a local SQL file and replace it with a new string.').command('slowlogs', 'Retrieve MySQL slow query logs from an environment.').command('db', "Access an environment's database.").command('sync', 'Sync the database from production to a non-production environment.').command('whoami', 'Retrieve details about the current authenticated VIP-CLI user.').command('validate', 'Scan a Node.js codebase for issues that could prevent building or deploying.').command('wp', 'Execute a WP-CLI command against an environment.');
24
+ cmd.command('logout', 'Log out the current authenticated VIP-CLI user.').command('app', 'Interact with applications that the current authenticated VIP-CLI user has permission to access.').command('backup', 'Generate a backup of an environment.').command('cache', 'Manage page cache for an environment.').command('config', 'Manage environment configurations.').command('dev-env', 'Create and manage VIP Local Development Environments.').command('export', 'Export a copy of data associated with an environment.').command('import', 'Import media or SQL database files to an environment.').command('logs', 'Retrieve Runtime Logs from an environment.').command('search-replace', 'Search for a string in a local SQL file and replace it with a new string.').command('slowlogs', 'Retrieve MySQL slow query logs from an environment.').command('db', "Access an environment's database.").command('sync', 'Sync the database from production to a non-production environment.').command('whoami', 'Retrieve details about the current authenticated VIP-CLI user.').command('wp', 'Execute a WP-CLI command against an environment.');
25
25
  cmd.argv(process.argv);
26
26
  };
27
27
 
@@ -80,8 +80,6 @@ async function createBackupJob(appId, envId) {
80
80
 
81
81
  // Library for a possible command in the future: vip backup db @app.env
82
82
  class BackupDBCommand {
83
- app;
84
- env;
85
83
  job;
86
84
  jobStatus;
87
85
  jobAge;
@@ -91,11 +89,11 @@ class BackupDBCommand {
91
89
  PREPARE: 'prepare',
92
90
  GENERATE: 'generate'
93
91
  };
94
- track;
95
92
  progressTracker;
96
- constructor(app, env, trackerFn = async () => {}) {
93
+ constructor(app, env, track = async () => {}) {
97
94
  this.app = app;
98
95
  this.env = env;
96
+ this.track = track;
99
97
  this.progressTracker = new _progress.ProgressTracker([{
100
98
  id: this.steps.PREPARE,
101
99
  name: 'Preparing for backup generation'
@@ -103,7 +101,6 @@ class BackupDBCommand {
103
101
  id: this.steps.GENERATE,
104
102
  name: 'Generating backup'
105
103
  }]);
106
- this.track = trackerFn;
107
104
  }
108
105
  log(msg) {
109
106
  if (this.silent) {
@@ -3,8 +3,10 @@
3
3
 
4
4
  exports.__esModule = true;
5
5
  exports.DevEnvSyncSQLCommand = void 0;
6
+ exports.findSiteHomeUrl = findSiteHomeUrl;
6
7
  var _vipSearchReplace = require("@automattic/vip-search-replace");
7
8
  var _chalk = _interopRequireDefault(require("chalk"));
9
+ var _debug = _interopRequireDefault(require("debug"));
8
10
  var _fs = _interopRequireDefault(require("fs"));
9
11
  var _promises = require("node:stream/promises");
10
12
  var _devEnvImportSql = require("./dev-env-import-sql");
@@ -17,6 +19,8 @@ var _utils = require("../lib/utils");
17
19
  var _lineByLine = require("../lib/validations/line-by-line");
18
20
  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); }
19
21
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
22
+ const debug = (0, _debug.default)('@automattic/vip:bin:dev-environment');
23
+
20
24
  /**
21
25
  * Replaces the domain in the given URL
22
26
  *
@@ -44,11 +48,11 @@ function stripProtocol(url) {
44
48
  * @return Site home url. null if not found
45
49
  */
46
50
  function findSiteHomeUrl(sql) {
47
- const regex = `['"](siteurl|home)['"],\\s?['"](.*?)['"]`;
48
- const url = sql.match(regex)?.[2] || '';
51
+ const regex = /(['"])(?:siteurl|home)\1,\s*\1([Hh][Tt][Tt][Pp][Ss]?:\/\/.+?)\1/;
52
+ const url = regex.exec(sql)?.[2] ?? '';
49
53
  try {
50
- new URL(url);
51
- return url;
54
+ const parsed = new URL(url);
55
+ return parsed.hostname ? url : null;
52
56
  } catch {
53
57
  return null;
54
58
  }
@@ -174,6 +178,10 @@ class DevEnvSyncSQLCommand {
174
178
  if (!networkSites) return;
175
179
  const primaryUrl = networkSites.find(site => site?.blogId === 1)?.homeUrl;
176
180
  const primaryDomain = primaryUrl ? new URL(primaryUrl).hostname : '';
181
+ debug('Network sites: %j, primary URL: %s, primary domain: %s', networkSites.map(site => ({
182
+ blogId: site?.blogId,
183
+ homeUrl: site?.homeUrl
184
+ })), primaryUrl, primaryDomain);
177
185
  for (const site of networkSites) {
178
186
  if (!site?.blogId || site.blogId === 1) continue;
179
187
  const url = site?.homeUrl;
@@ -285,6 +293,7 @@ DROP PROCEDURE vip_sync_update_blog_domains;
285
293
  try {
286
294
  console.log('Extracting site urls from the SQL file...');
287
295
  this.siteUrls = await extractSiteUrls(this.sqlFile);
296
+ debug('Extracted site URLs: %j', this.siteUrls);
288
297
  } catch (err) {
289
298
  const error = err;
290
299
  await this.track('error', {
@@ -106,19 +106,16 @@ async function getPhpMyAdminStatus(appId, envId) {
106
106
  return resp?.data?.app?.environments?.[0]?.phpMyAdminStatus?.status;
107
107
  }
108
108
  class PhpMyAdminCommand {
109
- app;
110
- env;
111
109
  silent;
112
- track;
113
110
  steps = {
114
111
  ENABLE: 'enable',
115
112
  GENERATE: 'generate'
116
113
  };
117
114
  progressTracker;
118
- constructor(app, env, trackerFn = async () => {}) {
115
+ constructor(app, env, track = async () => {}) {
119
116
  this.app = app;
120
117
  this.env = env;
121
- this.track = trackerFn;
118
+ this.track = track;
122
119
  this.progressTracker = new _progress.ProgressTracker([{
123
120
  id: this.steps.ENABLE,
124
121
  name: 'Enabling PHPMyAdmin for this environment'
@@ -49,15 +49,13 @@ class NonZeroExitCodeError extends Error {
49
49
  }
50
50
  exports.NonZeroExitCodeError = NonZeroExitCodeError;
51
51
  class WPCliCommandOverSSH {
52
- app;
53
- env;
54
52
  track;
55
53
  constructor(app, env) {
56
54
  this.app = app;
57
55
  this.env = env;
58
56
  this.track = (0, _tracker.makeCommandTracker)('wp', {
59
- app: this.app.id,
60
- env: this.env.id,
57
+ app: app.id,
58
+ env: env.id,
61
59
  execution_type: 'ssh'
62
60
  });
63
61
  }
@@ -188,7 +186,7 @@ class WPCliCommandOverSSH {
188
186
  async getSSHAuthForCommand(command, extraTrackingInfo) {
189
187
  const api = (0, _api.default)();
190
188
  try {
191
- return api.mutate({
189
+ return await api.mutate({
192
190
  mutation: TRIGGER_WP_CLI_COMMAND_MUTATION,
193
191
  variables: {
194
192
  input: {
@@ -18,7 +18,6 @@ const validEventOrPropNamePattern = /^[a-z_][a-z0-9_]*$/;
18
18
  // TODO: add batch support (can include multiples in `events` array)
19
19
 
20
20
  class Tracks {
21
- eventPrefix;
22
21
  userAgent;
23
22
  baseParams;
24
23
  static ENDPOINT = 'https://public-api.wordpress.com/rest/v1.1/tracks/record';
@@ -17,7 +17,6 @@ const client_info = {
17
17
  /* eslint-enable camelcase */
18
18
 
19
19
  class Analytics {
20
- clients;
21
20
  constructor(clients) {
22
21
  this.clients = clients;
23
22
  }
@@ -29,6 +29,8 @@ var _default = async (path, options = {}) => {
29
29
  url = `${_api.API_HOST}${path}`;
30
30
  }
31
31
  const authToken = await _token.default.get();
32
+
33
+ // TODO: remove this cast once the typings are fixed
32
34
  const proxyAgent = (0, _proxyAgent.createProxyAgent)(url);
33
35
  debug('running fetch', url);
34
36
  return (0, _nodeFetch.default)(url, {
@@ -13,7 +13,6 @@ var _format = require("../cli/format");
13
13
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
14
  const oneGiBInBytes = 1024 * 1024 * 1024;
15
15
  class BackupStorageAvailability {
16
- archiveSize;
17
16
  constructor(archiveSize) {
18
17
  this.archiveSize = archiveSize;
19
18
  }
@@ -48,7 +48,7 @@ async function validateCustomDeployKey(app, env) {
48
48
  throw new Error('Not found');
49
49
  }
50
50
  return result.data?.validateCustomDeployAccess;
51
- } catch (error) {
51
+ } catch {
52
52
  exit.withError(`Unauthorized: Invalid or non-existent custom deploy key for environment.`);
53
53
  }
54
54
  }
@@ -93,7 +93,7 @@ async function validateFile(appId, envId, fileMeta) {
93
93
  }
94
94
  try {
95
95
  await (0, _clientFileUploader.checkFileAccess)(fileName);
96
- } catch (err) {
96
+ } catch {
97
97
  await track('deploy_app_command_error', {
98
98
  error_type: 'appfile-unreadable'
99
99
  });
@@ -28,15 +28,15 @@ const getSqlDumpDetails = async filePath => {
28
28
  crlfDelay: Infinity
29
29
  });
30
30
  let isMyDumper = false;
31
- let sourceDB = '';
31
+ let sourceDB;
32
32
  let currentLineNumber = 0;
33
33
  for await (const line of readLine) {
34
34
  if (line === '') {
35
35
  continue;
36
36
  }
37
- const metadataMatch = line.match(/^-- metadata.header /);
38
- const sourceDBMatch = line.match(/^-- (.*)-schema-create.sql/) ?? [];
39
- const sourceDBName = sourceDBMatch[1];
37
+ const metadataMatch = /^-- metadata.header /.exec(line);
38
+ const sourceDBMatch = /^-- (.*)-schema-create.sql/.exec(line);
39
+ const sourceDBName = sourceDBMatch?.[1];
40
40
  if (metadataMatch && !isMyDumper) {
41
41
  isMyDumper = true;
42
42
  }
@@ -87,13 +87,13 @@ const getSqlFileStreamFromCompressedFile = async filePath => {
87
87
  throw new Error('Not a supported compressed file');
88
88
  };
89
89
  const fixMyDumperTransform = () => {
90
+ const regex = /^-- ([^ ]+) \d+$/;
90
91
  return new _nodeStream.Transform({
91
92
  transform(chunk, _encoding, callback) {
92
93
  const chunkString = chunk.toString();
93
94
  const lineEnding = chunkString.includes('\r\n') ? '\r\n' : '\n';
94
- const regex = /^-- ([^ ]+) [0-9]+$/;
95
95
  const lines = chunk.toString().split(lineEnding).map(line => {
96
- const match = line.match(regex);
96
+ const match = regex.exec(line);
97
97
  if (!match) {
98
98
  return line;
99
99
  }
@@ -300,11 +300,13 @@ async function processWordPress(preselectedValue, defaultValue) {
300
300
  if (versions.length) {
301
301
  versions.sort((before, after) => before.tag < after.tag ? 1 : -1);
302
302
  const match = versions.find(({
303
+ prerelease,
303
304
  tag
304
- }) => tag === result.tag);
305
- if (typeof match === 'undefined') {
305
+ }) => result.tag === 'latest' ? !prerelease : tag === result.tag);
306
+ if (match === undefined) {
306
307
  throw new _userError.default(`Unknown or unsupported WordPress version: ${result.tag}.`);
307
308
  }
309
+ result.tag = match.tag;
308
310
  }
309
311
  debug(result);
310
312
  return result;
@@ -677,7 +679,7 @@ function processVersionOption(value) {
677
679
  const phpVersionsSupported = Object.keys(_devEnvironment.DEV_ENVIRONMENT_PHP_VERSIONS).join(', ');
678
680
  function addDevEnvConfigurationOptions(command) {
679
681
  // We leave the third parameter to undefined on some because the defaults are handled in preProcessInstanceData()
680
- return command.option('wordpress', 'Manage the version of WordPress. Accepts a string value for major versions (6.x). Defaults to the most recent version of WordPress.', undefined, processVersionOption).option(['u', 'mu-plugins'], 'Manage the source for VIP MU plugins. Accepts "demo" (default) for a read-only image of the staging branch, or a path to a built copy of VIP MU plugins on the local machine.').option('app-code', 'Manage the source for application code. Accepts "demo" (default) for a read-only image of WordPress VIP skeleton application code, or a path to a VIP formatted application repo on the local machine.').option('phpmyadmin', 'Enable or disable phpMyAdmin, disabled by default. Accepts "y" (default value) to enable or "n" to disable. When enabled, refer to the value of "PHPMYADMIN URLS" in the information output for a local environment for the URL to access phpMyAdmin.', undefined, processBooleanOption).option('xdebug', 'Enable or disable XDebug, disabled by default. Accepts "y" (default value) to enable or "n" to disable.', undefined, processBooleanOption).option('xdebug_config', 'Override some default configuration settings for Xdebug. Accepts a string value that is assigned to the XDEBUG_CONFIG environment variable.').option('elasticsearch', 'Enable or disable Elasticsearch (required by Enterprise Search), disabled by default. Accepts "y" (default value) to enable or "n" to disable.', undefined, processBooleanOption).option(['r', 'media-redirect-domain'], 'Configure media files to be proxied from a VIP Platform environment. Accepts a string value for the primary domain of the VIP Platform environment or "n" to disable the media proxy.', undefined, processMediaRedirectDomainOption).option('php', `Manage the version of PHP. Accepts a string value for minor versions: ${phpVersionsSupported}`, undefined, processVersionOption).option('cron', 'Enable or disable cron, disabled by default. Accepts "y" (default value) to enable or "n" to disable.', undefined, processBooleanOption).option(['A', 'mailpit'], 'Enable or disable Mailpit, disabled by default. Accepts "y" (default value) to enable or "n" to disable.', undefined, processBooleanOption).option(['H', 'photon'], 'Enable or disable Photon, disabled by default. Accepts "y" (default value) to enable or "n" to disable.', undefined, processBooleanOption);
682
+ return command.option('wordpress', 'Manage the version of WordPress. Accepts a string value for major versions (6.x) or "latest". Defaults to the recommended version of WordPress for development.', undefined, processVersionOption).option(['u', 'mu-plugins'], 'Manage the source for VIP MU plugins. Accepts "demo" (default) for a read-only image of the staging branch, or a path to a built copy of VIP MU plugins on the local machine.').option('app-code', 'Manage the source for application code. Accepts "demo" (default) for a read-only image of WordPress VIP skeleton application code, or a path to a VIP formatted application repo on the local machine.').option('phpmyadmin', 'Enable or disable phpMyAdmin, disabled by default. Accepts "y" (default value) to enable or "n" to disable. When enabled, refer to the value of "PHPMYADMIN URLS" in the information output for a local environment for the URL to access phpMyAdmin.', undefined, processBooleanOption).option('xdebug', 'Enable or disable XDebug, disabled by default. Accepts "y" (default value) to enable or "n" to disable.', undefined, processBooleanOption).option('xdebug_config', 'Override some default configuration settings for Xdebug. Accepts a string value that is assigned to the XDEBUG_CONFIG environment variable.').option('elasticsearch', 'Enable or disable Elasticsearch (required by Enterprise Search), disabled by default. Accepts "y" (default value) to enable or "n" to disable.', undefined, processBooleanOption).option(['r', 'media-redirect-domain'], 'Configure media files to be proxied from a VIP Platform environment. Accepts a string value for the primary domain of the VIP Platform environment or "n" to disable the media proxy.', undefined, processMediaRedirectDomainOption).option('php', `Manage the version of PHP. Accepts a string value for minor versions: ${phpVersionsSupported}`, undefined, processVersionOption).option('cron', 'Enable or disable cron, disabled by default. Accepts "y" (default value) to enable or "n" to disable.', undefined, processBooleanOption).option(['A', 'mailpit'], 'Enable or disable Mailpit, disabled by default. Accepts "y" (default value) to enable or "n" to disable.', undefined, processBooleanOption).option(['H', 'photon'], 'Enable or disable Photon, disabled by default. Accepts "y" (default value) to enable or "n" to disable.', undefined, processBooleanOption);
681
683
  }
682
684
 
683
685
  /**
@@ -692,6 +692,7 @@ async function maybeUpdateVersion(lando, slug) {
692
692
  */
693
693
  function fetchVersionList() {
694
694
  const url = `https://${_devEnvironment.DEV_ENVIRONMENT_RAW_GITHUB_HOST}${_devEnvironment.DEV_ENVIRONMENT_WORDPRESS_VERSIONS_URI}`;
695
+ // TODO: remove this cast once the typings are fixed
695
696
  const proxyAgent = (0, _proxyAgent.createProxyAgent)(url);
696
697
  return (0, _nodeFetch.default)(url, {
697
698
  agent: proxyAgent ?? undefined
@@ -712,7 +713,8 @@ async function isVersionListExpired(cacheFile, ttl) {
712
713
  } = await _nodeFs.default.promises.stat(cacheFile);
713
714
  expire.setSeconds(expire.getSeconds() + ttl);
714
715
  return Number(new Date()) > Number(expire);
715
- } catch (err) {
716
+ } catch (error) {
717
+ debug(`Error checking version list expiration for cache file ${cacheFile}:`, error);
716
718
  return true;
717
719
  }
718
720
  }
@@ -844,7 +846,6 @@ function getVSCodeWorkspacePath(slug) {
844
846
  function generatePHPStormWorkspace(slug) {
845
847
  debug('Generating PHPStorm Workspace');
846
848
  const location = getEnvironmentPath(slug);
847
- // const location = location;
848
849
  const instanceData = readEnvironmentData(slug);
849
850
  const pathMappings = generatePathMappings(location, instanceData);
850
851
 
@@ -2,8 +2,11 @@
2
2
 
3
3
  exports.__esModule = true;
4
4
  exports.reIndexSearch = exports.generatePassword = exports.flushCache = exports.executeQuery = exports.dataCleanup = exports.addAdminUser = void 0;
5
+ var _debug = _interopRequireDefault(require("debug"));
5
6
  var _nodeCrypto = require("node:crypto");
6
7
  var _devEnvironmentCore = require("./dev-environment-core");
8
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
+ const debug = (0, _debug.default)('@automattic/vip:bin:dev-environment');
7
10
  const generatePassword = () => {
8
11
  const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_';
9
12
  const passwordLength = 12;
@@ -36,6 +39,7 @@ const dataCleanup = async (lando, slug, quiet) => {
36
39
  } catch (error) {
37
40
  // This must not be a fatal error
38
41
  console.log('WARNING: data cleanup failed.');
42
+ debug('Error during data cleanup:', error);
39
43
  }
40
44
  };
41
45
  exports.dataCleanup = dataCleanup;
@@ -112,7 +112,8 @@ async function regenerateLandofile(lando, instancePath) {
112
112
  const backup = `${landoFile}.${now}`;
113
113
  await (0, _promises2.rename)(landoFile, backup);
114
114
  console.warn(_chalk.default.yellow('Backed up %s to %s'), landoFile, backup);
115
- } catch (err) {
115
+ } catch (error) {
116
+ debug(`Failed to backup lando file ${landoFile}:`, error);
116
117
  // Rename failed - possibly the file does not exist. Silently ignoring.
117
118
  }
118
119
  const slug = _nodePath.default.basename(instancePath);
@@ -409,7 +410,7 @@ async function tryResolveDomains(urls) {
409
410
  const domains = [...new Set(urls.filter(url => url.toLowerCase().startsWith('http')).map(url => {
410
411
  try {
411
412
  return new URL(url).hostname;
412
- } catch (err) {
413
+ } catch {
413
414
  return undefined;
414
415
  }
415
416
  }).filter(domain => domain !== undefined))];
@@ -5,7 +5,6 @@ exports.default = void 0;
5
5
  var _configstore = _interopRequireDefault(require("configstore"));
6
6
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
7
7
  class Insecure {
8
- file;
9
8
  configstore;
10
9
  constructor(file) {
11
10
  this.file = file;
@@ -21,5 +21,5 @@ async function getMediaImportConfig() {
21
21
  variables: {},
22
22
  fetchPolicy: 'network-only'
23
23
  });
24
- return response?.data?.mediaImportConfig;
24
+ return response?.data?.mediaImportConfig ?? null;
25
25
  }
@@ -289,14 +289,9 @@ ${maybeExitPrompt}
289
289
  importInProgress,
290
290
  importStepProgress
291
291
  });
292
- let jobCreationTime;
293
- try {
294
- jobCreationTime = new Date(createdAt ?? '').getTime();
295
- } catch (err) {
296
- debug('Unable to parse createdAt to a Date');
297
- }
292
+ const jobCreationTime = new Date(createdAt ?? '').getTime();
298
293
  let failedImportStep;
299
- if (jobCreationTime && (importStepProgress?.started_at ?? 0) * 1000 >= jobCreationTime) {
294
+ if (!isNaN(jobCreationTime) && (importStepProgress?.started_at ?? 0) * 1000 >= jobCreationTime) {
300
295
  // The contents of the `import_progress` meta are pertinent to the most recent import job
301
296
  failedImportStep = importStepProgress?.steps?.find(step => step?.result === 'failed' && 1000 * (step.started_at ?? 0) > new Date(createdAt ?? '').getTime());
302
297
  }
@@ -20,8 +20,9 @@ const getPrimaryDomainFromSQL = statements => {
20
20
  if (!statements.length) {
21
21
  return '';
22
22
  }
23
- const SQL_WP_SITE_DOMAINS_REGEX = /\(1,'(.*?)'/s;
24
- const matches = statements[0]?.join('').replace(/\s/g, '').match(SQL_WP_SITE_DOMAINS_REGEX);
23
+ const SQL_WP_SITE_DOMAINS_REGEX = /\(1,'([^']+)'/s;
24
+ const normalizedSql = statements[0]?.join('').replace(/\s/g, '') ?? '';
25
+ const matches = SQL_WP_SITE_DOMAINS_REGEX.exec(normalizedSql);
25
26
  return matches ? matches[1] : '';
26
27
  };
27
28
 
@@ -15,7 +15,7 @@ async function getReadInterface(filename) {
15
15
  let fd;
16
16
  try {
17
17
  fd = await (0, _promises.open)(filename);
18
- } catch (err) {
18
+ } catch {
19
19
  exit.withError('The file at the provided path is either missing or not readable. Please check the input and try again.');
20
20
  }
21
21
  return (0, _nodeReadline.createInterface)({
package/docs/CHANGELOG.md CHANGED
@@ -1,5 +1,60 @@
1
1
  ## Changelog
2
2
 
3
+ ### 3.19.0
4
+
5
+ * build(deps-dev): bump the testing group across 1 directory with 4 updates
6
+ * New develop release: 3.18.1-dev.0 by @gi
7
+ * build(deps-dev): bump the testing group with 3 updates
8
+ * Remove preflight as part of the harmonia deprecation
9
+ * Add changelog workflow
10
+ * Changelogs: Update `vip-actions`
11
+ * build(deps-dev): bump @types/dockerode from 3.3.41 to 3.3.42
12
+ * build(deps-dev): bump the testing group with 2 updates
13
+ * build(deps): bump step-security/harden-runner from 2.12.1 to 2.12.2
14
+ * build(deps-dev): bump @babel/core from 7.27.4 to 7.27.7 in the babel group
15
+ * build(deps-dev): bump the babel group with 3 updates
16
+ * build(deps-dev): bump @types/shelljs from 0.8.16 to 0.8.17
17
+ * build(deps-dev): bump the testing group with 3 updates
18
+ * chore(deps): update Lando to fix PLTFRM-1195
19
+ * build(deps): bump socks-proxy-agent from 5.0.1 to 8.0.5
20
+ * build(deps): bump https-proxy-agent from 5.0.1 to 7.0.6
21
+ * build(deps-dev): bump @types/node from 24.0.3 to 24.0.10
22
+ * feat(dev-env): allow `latest` as WP version
23
+ * feat(dev-env): add some logging to `DevEnvSyncSQLCommand`
24
+ * Update to the description of the `--wordpress` option for `dev-env`
25
+ * build(deps-dev): bump @types/node from 24.0.10 to 24.0.12
26
+ * fix: drop superfluous `as unknown` casts
27
+ * fix: exception handling-related code smells
28
+ * fix: Promise rejection is not caught by `try`
29
+ * fix: RegExp-related issues
30
+ * fix: fields that are only assigned in the constructor should be "readonly"
31
+ * fix(dev-env): make URL extraction less error-prone
32
+
33
+ **Full Changelog**: https://github.com/Automattic/vip-cli/compare/3.18.0...3.19.0
34
+
35
+ ### 3.18.0
36
+
37
+ * fix: properly quote parameters for `vip wp`
38
+ * build(deps-dev): bump dockerode from 4.0.6 to 4.0.7
39
+ * build(deps-dev): bump @types/node from 22.15.29 to 22.15.30
40
+ * build(deps-dev): bump @types/dockerode from 3.3.39 to 3.3.40
41
+ * build(deps-dev): bump @types/node from 22.15.30 to 24.0.0
42
+ * build(deps): bump step-security/harden-runner from 2.12.0 to 2.12.1
43
+ * build(deps-dev): bump @types/node from 24.0.0 to 24.0.1
44
+ * fix(dev-env): clear proxy cache before startup and after shutdown
45
+ * feat(dev-env): add `vip dev-env envvar` commands
46
+ * chore(deps): update `lando` to the latest version
47
+ * Remove MD5 requirement restrictions for URL imports in vip-import-sql
48
+ * build(deps-dev): bump @types/node from 24.0.1 to 24.0.3
49
+ * build(deps-dev): bump @types/dockerode from 3.3.40 to 3.3.41
50
+ * chore(deps): update `brace-expansion` to fix CVE-2025-5889
51
+ * Bump ES to 8.18.2
52
+ * fix: suppress prompt for media redirect with config files
53
+ * Add changelog section to PR template
54
+ * Update/Org salesforceId
55
+
56
+ **Full Changelog**: https://github.com/Automattic/vip-cli/compare/3.17.1...3.18.0
57
+
3
58
  ### 3.17.1
4
59
 
5
60
  * chore: Update Git Hash Checker Github Action