Merge pull request #522 from hashicorp/desktop-update-feature
feat: 🎸 Update desktop through menu option
This commit is contained in:
10 files changed
+298
-31
No files matched your search
@@ -4,6 +4,10 @@ Canonical reference for changes, improvements, and bugfixes for Boundary Desktop
|
||||
|
||||
## Next
|
||||
|
||||
### New
|
||||
|
||||
- Check for client updates and update on-demand using new menu option. ([PR](https://github.com/hashicorp/boundary-ui/pull/522))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Trigger zoom-in menu option on keyboard shortcut. ([PR](https://github.com/hashicorp/boundary-ui/pull/505))
|
||||
|
||||
@@ -65,6 +65,17 @@ To run as a desktop app:
|
||||
The Boundary CLI is downloaded and extracted to `electron-app/cli/` folder as part of
|
||||
build. CLI version is defined in `electron-app/config/cli.js`.
|
||||
|
||||
#### Environment Variables
|
||||
|
||||
These environment variables may be used to customized the build.
|
||||
|
||||
| Variable | Description |
|
||||
| -------- | ----------- |
|
||||
| `DEBUG_APP_UPDATER` | Enable to debug app updater feature. Must be enabled for all `APP_UPDATER_*` variables to be used. |
|
||||
| `APP_UPDATER_CURRENT_VERSION` | Version of client. |
|
||||
| `APP_UPDATER_LATEST_VERSION_TAG` | Next version for comparison with current version. |
|
||||
| `APP_UPDATER_LATEST_VERSION_LOCATION` | Location of app release to use for updating client. Can be a filepath or url. |
|
||||
|
||||
### Building for Production
|
||||
|
||||
Before executing a build, be sure to set any environment variables necessary
|
||||
|
||||
@@ -93,4 +93,7 @@ ember-dist/
|
||||
ember-test/
|
||||
|
||||
# CLI
|
||||
cli/
|
||||
cli/
|
||||
|
||||
# Autoupdate
|
||||
nextVersion/
|
||||
@@ -10,7 +10,7 @@ const artifactDestination = path.resolve(__dirname, '..', 'cli');
|
||||
const downloadArtifact = version => {
|
||||
const url = `https://releases.hashicorp.com/boundary/${version}/boundary_${version}_darwin_amd64.zip`;
|
||||
return new Promise((resolve, reject) => {
|
||||
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'boundary-artifact-'))
|
||||
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'boundary-artifact-'));
|
||||
console.log('Create tmp artifact directory: ', tmpDir);
|
||||
|
||||
const artifactFileName = url.split('/').pop();
|
||||
|
||||
@@ -18,41 +18,42 @@ console.log('RELEASE_VERSION ', process.env.RELEASE_VERSION);
|
||||
console.log('RELEASE_COMMIT ', process.env.RELEASE_COMMIT);
|
||||
|
||||
module.exports = {
|
||||
releaseVersion: process.env.RELEASE_VERSION,
|
||||
hooks: {
|
||||
prePackage: () => {
|
||||
if (!process.env.BOUNDARY_DESKTOP_SIGNING_IDENTITY) {
|
||||
console.warn('\nWARNING: Could not find signing identity.');
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
packagerConfig: {
|
||||
ignore: [
|
||||
"/ember-test(/|$)",
|
||||
"/tests(/|$)"
|
||||
],
|
||||
name: "Boundary",
|
||||
appBundleId: "com.electron.boundary",
|
||||
ignore: ['/ember-test(/|$)', '/tests(/|$)'],
|
||||
name: 'Boundary',
|
||||
appBundleId: 'com.electron.boundary',
|
||||
// TODO: where should the client version number come from?
|
||||
appVersion: `${formattedAppVersion}${formattedCLIVersion}\n`,
|
||||
appCopyright: "Copyright © 2021 HashiCorp, Inc.",
|
||||
icon: "./config/macos/icon.icns",
|
||||
appCopyright: 'Copyright © 2021 HashiCorp, Inc.',
|
||||
icon: './config/macos/icon.icns',
|
||||
osxSign: {
|
||||
identity: process.env.BOUNDARY_DESKTOP_SIGNING_IDENTITY,
|
||||
"hardened-runtime": true,
|
||||
entitlements: "./config/macos/entitlements.plist",
|
||||
"entitlements-inherit": "./config/macos/entitlements.plist",
|
||||
"signature-flags": "library"
|
||||
}
|
||||
'hardened-runtime': true,
|
||||
entitlements: './config/macos/entitlements.plist',
|
||||
'entitlements-inherit': './config/macos/entitlements.plist',
|
||||
'signature-flags': 'library',
|
||||
},
|
||||
},
|
||||
makers: [
|
||||
{
|
||||
name: "@electron-forge/maker-dmg",
|
||||
name: '@electron-forge/maker-dmg',
|
||||
config: {
|
||||
title: "Boundary",
|
||||
name: "boundary",
|
||||
icon: "./config/macos/disk.icns",
|
||||
background: "./config/macos/background.png"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
title: 'Boundary',
|
||||
name: 'boundary',
|
||||
icon: './config/macos/disk.icns',
|
||||
background: './config/macos/background.png',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '@electron-forge/maker-zip',
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -25,11 +25,14 @@
|
||||
"electron-is-dev": "^1.2.0",
|
||||
"electron-squirrel-startup": "^1.0.0",
|
||||
"lookpath": "^1.1.0",
|
||||
"node-html-parser": "^3.1.3",
|
||||
"semver": "^7.3.5",
|
||||
"shell-quote": "^1.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@electron-forge/cli": "6.0.0-beta.54",
|
||||
"@electron-forge/maker-dmg": "^6.0.0-beta.54",
|
||||
"@electron-forge/maker-zip": "^6.0.0-beta.54",
|
||||
"decompress": "^4.2.1",
|
||||
"devtron": "^1.4.0",
|
||||
"electron": "12.0.2"
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const https = require('https');
|
||||
const semver = require('semver');
|
||||
const { parse } = require('node-html-parser');
|
||||
const { autoUpdater, dialog } = require('electron');
|
||||
const { releaseVersion } = require('../config/forge.config.js');
|
||||
|
||||
const debug = process.env.DEBUG_APP_UPDATER;
|
||||
const releasesUrl = 'https://releases.hashicorp.com/boundary-desktop/';
|
||||
let currentVersion = releaseVersion;
|
||||
if (debug && process.env.APP_UPDATER_CURRENT_VERSION) {
|
||||
currentVersion = process.env.APP_UPDATER_CURRENT_VERSION;
|
||||
}
|
||||
|
||||
// Query releases url to find latest version
|
||||
const findLatestVersion = (url) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let data = '';
|
||||
https.get(url, (response) => {
|
||||
response.on('data', (chunk) => (data += chunk));
|
||||
response.on('end', () => {
|
||||
const html = parse(data);
|
||||
// Ignore first link as it navigates to root
|
||||
const fullVersion = html.querySelectorAll('a')[1].innerHTML;
|
||||
resolve(fullVersion.split('_')[1]);
|
||||
});
|
||||
response.on('error', (err) => reject(err));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Create update config using downloaded archive
|
||||
const createAppUpdaterConfig = (url, version, destination) => {
|
||||
if (debug) console.log(`[app-updater] url: ${url}, destination: ${destination}`);
|
||||
const json = { url, version};
|
||||
const config = JSON.stringify(json);
|
||||
const configPath = `${destination}/feed.json`;
|
||||
if (debug) console.log(`[app-updater] config: ${config}`);
|
||||
fs.writeFileSync(configPath, config);
|
||||
return configPath;
|
||||
};
|
||||
|
||||
const downloadAndInstallUpdate = async (version) => {
|
||||
const url = `${releasesUrl}boundary-desktop_${version}/boundary-desktop_${version}_darwin_amd64.zip`;
|
||||
const destination = path.resolve(__dirname, '..', 'nextVersion');
|
||||
if (!fs.existsSync(destination)) fs.mkdirSync(destination);
|
||||
|
||||
try {
|
||||
let configPath;
|
||||
if (debug) {
|
||||
// Support hosted url and file paths
|
||||
const location = process.env.APP_UPDATER_LATEST_VERSION_LOCATION;
|
||||
configPath = createAppUpdaterConfig(
|
||||
location.match(/^https/i) ? location : `file://${location}`,
|
||||
version,
|
||||
destination
|
||||
);
|
||||
} else {
|
||||
configPath = createAppUpdaterConfig(url, version, destination);
|
||||
}
|
||||
|
||||
autoUpdater.on('update-downloaded', () => {
|
||||
const dialogOpts = {
|
||||
type: 'info',
|
||||
buttons: ['Restart', 'Later'],
|
||||
detail:
|
||||
'A new version has been downloaded. Restart the application to apply the updates.',
|
||||
};
|
||||
dialog.showMessageBox(dialogOpts).then((returnValue) => {
|
||||
if (returnValue.response === 0) autoUpdater.quitAndInstall(true, true);
|
||||
});
|
||||
});
|
||||
|
||||
autoUpdater.on('error', (e) => {
|
||||
dialog.showErrorBox('Could not update', e.message);
|
||||
});
|
||||
|
||||
if (debug) console.log('[app-updater] config:', configPath);
|
||||
autoUpdater.setFeedURL(`file://${configPath}`);
|
||||
autoUpdater.checkForUpdates();
|
||||
} catch (e) {
|
||||
dialog.showErrorBox('Could not update', e.message);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Configure inbuilt app updater to use a custom config file
|
||||
* to download and install next available app version.
|
||||
* TODO: download progress in dialog
|
||||
**/
|
||||
module.exports = {
|
||||
run: async ({ suppressNoUpdatePrompt }) => {
|
||||
let latestVersion;
|
||||
if (debug) {
|
||||
latestVersion = process.env.APP_UPDATER_LATEST_VERSION_TAG;
|
||||
} else {
|
||||
latestVersion = await findLatestVersion(releasesUrl);
|
||||
}
|
||||
|
||||
// Ensure version is in proper format
|
||||
if (!semver.valid(latestVersion)) {
|
||||
latestVersion = semver.coerce(latestVersion);
|
||||
}
|
||||
|
||||
// Update not available - do nothing
|
||||
if (!suppressNoUpdatePrompt && semver.lte(latestVersion, currentVersion)) {
|
||||
const dialogOpts = {
|
||||
type: 'info',
|
||||
icon: null,
|
||||
detail: 'No updates available',
|
||||
};
|
||||
|
||||
dialog.showMessageBox(dialogOpts);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update is available - prompt for download
|
||||
const dialogOpts = {
|
||||
type: 'info',
|
||||
buttons: ['Download', 'Later'],
|
||||
icon: null,
|
||||
detail: 'A new version is available for download',
|
||||
};
|
||||
|
||||
dialog.showMessageBox(dialogOpts).then((returnValue) => {
|
||||
if (returnValue.response === 0) {
|
||||
downloadAndInstallUpdate(latestVersion);
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
@@ -11,6 +11,7 @@ const {
|
||||
BrowserWindow,
|
||||
ipcMain,
|
||||
Menu,
|
||||
MenuItem,
|
||||
} = require('electron');
|
||||
require('./handlers.js');
|
||||
|
||||
@@ -18,7 +19,7 @@ const origin = require('./origin.js');
|
||||
const { generateCSPHeader } = require('./content-security-policy.js');
|
||||
|
||||
const menu = require('./menu.js');
|
||||
|
||||
const appUpdater = require('./app-updater.js');
|
||||
const isDev = require('electron-is-dev');
|
||||
|
||||
// Register the custom file protocol
|
||||
@@ -101,11 +102,13 @@ app.on('ready', async () => {
|
||||
}
|
||||
}
|
||||
|
||||
// Configure menu in prod env
|
||||
if (!isDev) {
|
||||
const menuTemplate = Menu.buildFromTemplate(menu.generateMenuTemplate());
|
||||
Menu.setApplicationMenu(menuTemplate);
|
||||
// Configure dev tools menu
|
||||
const menuTemplate = Menu.buildFromTemplate(menu.generateMenuTemplate());
|
||||
if (isDev) {
|
||||
const view = menuTemplate.getMenuItemById('view');
|
||||
view.submenu.append(new MenuItem({ role: 'toggleDevTools' }));
|
||||
}
|
||||
Menu.setApplicationMenu(menuTemplate);
|
||||
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 1280,
|
||||
@@ -136,6 +139,9 @@ app.on('ready', async () => {
|
||||
// Load the ember application
|
||||
mainWindow.loadURL(emberAppURL);
|
||||
|
||||
// Check for updates on launch
|
||||
appUpdater.run({ suppressNoUpdatePrompt: true });
|
||||
|
||||
// If a loading operation goes wrong, we'll send Electron back to
|
||||
// Ember App entry point
|
||||
mainWindow.webContents.on('did-fail-load', () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { shell } = require('electron');
|
||||
const appUpdater = require('./app-updater.js');
|
||||
|
||||
const generateMenuTemplate = () => {
|
||||
return [
|
||||
@@ -7,6 +8,11 @@ const generateMenuTemplate = () => {
|
||||
label: 'Boundary',
|
||||
submenu: [
|
||||
{ role: 'about' },
|
||||
{
|
||||
id: 'update',
|
||||
label: 'Check for Updates',
|
||||
click: async () => appUpdater.run(),
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{ role: 'services' },
|
||||
{ type: 'separator' },
|
||||
@@ -44,6 +50,7 @@ const generateMenuTemplate = () => {
|
||||
},
|
||||
// { role: 'viewMenu' }
|
||||
{
|
||||
id: 'view',
|
||||
label: 'View',
|
||||
submenu: [
|
||||
{ role: 'reload' },
|
||||
|
||||
@@ -155,6 +155,16 @@
|
||||
optionalDependencies:
|
||||
electron-installer-dmg "^3.0.0"
|
||||
|
||||
"@electron-forge/maker-zip@^6.0.0-beta.54":
|
||||
version "6.0.0-beta.54"
|
||||
resolved "https://registry.yarnpkg.com/@electron-forge/maker-zip/-/maker-zip-6.0.0-beta.54.tgz#83d322afd912587fd233e87c30339d8150f29bed"
|
||||
integrity sha512-wbJhK1rDOCZMTtKrjvavT8R+Yi+v/6axsnTXvzbkzzMQ0xADKNslTwzO6mmbBJea4oIbYmQ44DRAjI21TNyQ/A==
|
||||
dependencies:
|
||||
"@electron-forge/maker-base" "6.0.0-beta.54"
|
||||
"@electron-forge/shared-types" "6.0.0-beta.54"
|
||||
cross-zip "^3.0.0"
|
||||
fs-extra "^9.0.1"
|
||||
|
||||
"@electron-forge/plugin-base@6.0.0-beta.54":
|
||||
version "6.0.0-beta.54"
|
||||
resolved "https://registry.yarnpkg.com/@electron-forge/plugin-base/-/plugin-base-6.0.0-beta.54.tgz#1847eeee00e9558d61ef9ff7c2d7c9f5dbf1109c"
|
||||
@@ -505,6 +515,11 @@ bluebird@^3.1.1, bluebird@^3.5.0:
|
||||
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
|
||||
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
|
||||
|
||||
boolbase@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
|
||||
integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
|
||||
|
||||
boolean@^3.0.1:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.0.3.tgz#0fee0c9813b66bef25a8a6a904bb46736d05f024"
|
||||
@@ -788,6 +803,29 @@ cross-spawn@^7.0.1:
|
||||
shebang-command "^2.0.0"
|
||||
which "^2.0.1"
|
||||
|
||||
cross-zip@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cross-zip/-/cross-zip-3.1.0.tgz#2b7d33f2a893bf83e232ccbabf4c6c706f6b313c"
|
||||
integrity sha512-aX02l0SD3KE27pMl69gkxDdDM5D3u9Ic4Je+2b1B2fP0dWnlWWY6ns2Vk5DEgCXJRhL3GasSpicNQRNbDkq0+w==
|
||||
dependencies:
|
||||
rimraf "^3.0.0"
|
||||
|
||||
css-select@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/css-select/-/css-select-3.1.2.tgz#d52cbdc6fee379fba97fb0d3925abbd18af2d9d8"
|
||||
integrity sha512-qmss1EihSuBNWNNhHjxzxSfJoFBM/lERB/Q4EnsJQQC62R2evJDW481091oAdOr9uh46/0n4nrg0It5cAnj1RA==
|
||||
dependencies:
|
||||
boolbase "^1.0.0"
|
||||
css-what "^4.0.0"
|
||||
domhandler "^4.0.0"
|
||||
domutils "^2.4.3"
|
||||
nth-check "^2.0.0"
|
||||
|
||||
css-what@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/css-what/-/css-what-4.0.0.tgz#35e73761cab2eeb3d3661126b23d7aa0e8432233"
|
||||
integrity sha512-teijzG7kwYfNVsUh2H/YN62xW3KK9YhXEgSlbxMlcyjPNvdKJqFx5lrwlJgoFP1ZHlB89iGDlo/JyshKeRhv5A==
|
||||
|
||||
currently-unhandled@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
|
||||
@@ -953,6 +991,36 @@ devtron@^1.4.0:
|
||||
highlight.js "^9.3.0"
|
||||
humanize-plus "^1.8.1"
|
||||
|
||||
dom-serializer@^1.0.1:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.2.0.tgz#3433d9136aeb3c627981daa385fc7f32d27c48f1"
|
||||
integrity sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==
|
||||
dependencies:
|
||||
domelementtype "^2.0.1"
|
||||
domhandler "^4.0.0"
|
||||
entities "^2.0.0"
|
||||
|
||||
domelementtype@^2.0.1, domelementtype@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57"
|
||||
integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==
|
||||
|
||||
domhandler@^4.0.0, domhandler@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.1.0.tgz#c1d8d494d5ec6db22de99e46a149c2a4d23ddd43"
|
||||
integrity sha512-/6/kmsGlMY4Tup/nGVutdrK9yQi4YjWVcVeoQmixpzjOUK1U7pQkvAPHBJeUxOgxF0J8f8lwCJSlCfD0V4CMGQ==
|
||||
dependencies:
|
||||
domelementtype "^2.2.0"
|
||||
|
||||
domutils@^2.4.3:
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.5.1.tgz#9b8e84b5d9f788499ae77506ea832e9b4f9aa1c0"
|
||||
integrity sha512-hO1XwHMGAthA/1KL7c83oip/6UWo3FlUNIuWiWKltoiQ5oCOiqths8KknvY2jpOohUoUgnwa/+Rm7UpwpSbY/Q==
|
||||
dependencies:
|
||||
dom-serializer "^1.0.1"
|
||||
domelementtype "^2.2.0"
|
||||
domhandler "^4.1.0"
|
||||
|
||||
ds-store@^0.1.5:
|
||||
version "0.1.6"
|
||||
resolved "https://registry.yarnpkg.com/ds-store/-/ds-store-0.1.6.tgz#d1024ef746ed0c13f0f7fec85c7e858e8c4b7ca7"
|
||||
@@ -1099,6 +1167,11 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0:
|
||||
dependencies:
|
||||
once "^1.4.0"
|
||||
|
||||
entities@^2.0.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
|
||||
integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
|
||||
|
||||
env-paths@^2.2.0:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2"
|
||||
@@ -1611,6 +1684,11 @@ has@^1.0.3:
|
||||
dependencies:
|
||||
function-bind "^1.1.1"
|
||||
|
||||
he@1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
|
||||
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
|
||||
|
||||
highlight.js@^10.4.1, highlight.js@^9.3.0:
|
||||
version "10.7.2"
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.2.tgz#89319b861edc66c48854ed1e6da21ea89f847360"
|
||||
@@ -2280,6 +2358,14 @@ node-gyp@^7.1.0:
|
||||
tar "^6.0.2"
|
||||
which "^2.0.2"
|
||||
|
||||
node-html-parser@^3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/node-html-parser/-/node-html-parser-3.1.3.tgz#987d39bc8df27bc70cbe3b4e9a31fd84f7454dfb"
|
||||
integrity sha512-pCE2I5UY5iOBnWdJQkbYZSk+fyq2zepw0nsELpHQjVFyCzOeZhkMhnvKqGceKgzWsWx7EG4KtMqsy9Eklf5Thw==
|
||||
dependencies:
|
||||
css-select "^3.1.2"
|
||||
he "1.2.0"
|
||||
|
||||
node-pre-gyp@^0.11.0:
|
||||
version "0.11.0"
|
||||
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054"
|
||||
@@ -2372,6 +2458,13 @@ npmlog@^4.0.2, npmlog@^4.1.2:
|
||||
gauge "~2.7.3"
|
||||
set-blocking "~2.0.0"
|
||||
|
||||
nth-check@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.0.tgz#1bb4f6dac70072fc313e8c9cd1417b5074c0a125"
|
||||
integrity sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==
|
||||
dependencies:
|
||||
boolbase "^1.0.0"
|
||||
|
||||
nugget@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/nugget/-/nugget-2.0.1.tgz#201095a487e1ad36081b3432fa3cada4f8d071b0"
|
||||
@@ -2947,7 +3040,7 @@ rimraf@^2.6.1, rimraf@^2.7.1:
|
||||
dependencies:
|
||||
glob "^7.1.3"
|
||||
|
||||
rimraf@^3.0.2:
|
||||
rimraf@^3.0.0, rimraf@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
|
||||
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
|
||||
@@ -3027,6 +3120,13 @@ semver@^7.1.3, semver@^7.2.1, semver@^7.3.2:
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
semver@^7.3.5:
|
||||
version "7.3.5"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
|
||||
integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
serialize-error@^7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-7.0.1.tgz#f1360b0447f61ffb483ec4157c737fab7d778e18"
|
||||
|
||||
Reference in new issue
Block a user