Implemented Java validations within the UI.
When a user attemps to launch, the configured Java executable will be validated. If it is invalid, we will look for a valid installation. If no valid installation is found, the user will be prompted with an option to install Java. An option to decline needs to be added. If they choose to install, it will download, extract, and update the executable in the config. The game will then be launched. Also added progress tracking for asset validations, as they can potentially take a bit longer. Showing progress assures the user that the program isn't stuck or broken.
This commit is contained in:
parent
9b63d9bb58
commit
0a79634b8a
@ -104,4 +104,6 @@ Run either of the build scrips noted below. Note that each platform can only be
|
||||
|
||||
If you run into any issue which cannot be resolved via a quick google search, create an issue using the tab above.
|
||||
|
||||
Much of the discussion regarding this launcher is done on Discord, feel free to join us there [![Discord](https://discordapp.com/api/guilds/98469309352775680/widget.png)](https://discord.gg/hqdjs3m)
|
||||
Much of the discussion regarding this launcher is done on #launcherdev in Discord, feel free to join us there.
|
||||
|
||||
[![Discord](https://discordapp.com/api/guilds/98469309352775680/embed.png?style=banner2)](https://discord.gg/hqdjs3m)
|
@ -1210,15 +1210,38 @@ p {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
/*justify-content: space-between;*/
|
||||
width: 300px;
|
||||
height: 35%;
|
||||
/*height: 35%;*/
|
||||
box-sizing: border-box;
|
||||
padding: 15px 0px;
|
||||
/* background-color: #424242; */
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#overlayContent a {
|
||||
color: rgba(202, 202, 202, 0.75);
|
||||
transition: 0.25s ease;
|
||||
}
|
||||
#overlayContent a:hover {
|
||||
color: rgba(255, 255, 255, 0.75);
|
||||
}
|
||||
#overlayContent a:active {
|
||||
color: rgba(165, 165, 165, 0.75);
|
||||
}
|
||||
|
||||
#overlayContent > *:first-child {
|
||||
margin-top: 0px !important;
|
||||
}
|
||||
|
||||
#overlayContent > *:last-child {
|
||||
margin-bottom: 0px !important;
|
||||
}
|
||||
|
||||
#overlayContent > * {
|
||||
margin: 8px 0px;
|
||||
}
|
||||
|
||||
#overlayTitle {
|
||||
font-family: 'Avenir Medium';
|
||||
font-size: 20px;
|
||||
|
@ -39,6 +39,11 @@ document.addEventListener('readystatechange', function(){
|
||||
if(jExe == null){
|
||||
asyncSystemScan()
|
||||
} else {
|
||||
|
||||
setLaunchDetails('Please wait..')
|
||||
toggleLaunchArea(true)
|
||||
setLaunchPercentage(0, 100)
|
||||
|
||||
AssetGuard._validateJavaBinary(jExe).then((v) => {
|
||||
if(v){
|
||||
dlAsync()
|
||||
@ -194,12 +199,13 @@ function setDownloadPercentage(value, max, percent = ((value/max)*100)){
|
||||
let sysAEx
|
||||
let scanAt
|
||||
|
||||
function asyncSystemScan(){
|
||||
function asyncSystemScan(launchAfter = true){
|
||||
|
||||
setLaunchDetails('Please wait..')
|
||||
toggleLaunchArea(true)
|
||||
setLaunchPercentage(0, 100)
|
||||
|
||||
// Fork a process to run validations.
|
||||
sysAEx = cp.fork(path.join(__dirname, 'assets', 'js', 'assetexec.js'), [
|
||||
ConfigManager.getGameDirectory(),
|
||||
ConfigManager.getJavaExecutable()
|
||||
@ -207,21 +213,96 @@ function asyncSystemScan(){
|
||||
|
||||
sysAEx.on('message', (m) => {
|
||||
if(m.content === 'validateJava'){
|
||||
jPath = m.result
|
||||
console.log(m.result)
|
||||
sysAEx.disconnect()
|
||||
|
||||
//m.result = null
|
||||
|
||||
if(m.result == null){
|
||||
// If the result is null, no valid Java installation was found.
|
||||
// Show this information to the user.
|
||||
setOverlayContent(
|
||||
'No Compatible<br>Java Installation Found..',
|
||||
'In order to join WesterosCraft, you need a 64-bit installation of Java 8. Would you like us to install a copy? By installing, you accept <a href="http://www.oracle.com/technetwork/java/javase/terms/license/index.html">Oracle\'s license agreement</a>.',
|
||||
'Install Java'
|
||||
)
|
||||
setOverlayHandler(() => {
|
||||
setLaunchDetails('Preparing Java Download..')
|
||||
sysAEx.send({task: 0, content: '_enqueueOracleJRE', argsArr: [ConfigManager.getLauncherDirectory()]})
|
||||
toggleOverlay(false)
|
||||
})
|
||||
toggleOverlay(true)
|
||||
|
||||
// TODO Add option to not install Java x64.
|
||||
|
||||
} else {
|
||||
// Java installation found, use this to launch the game.
|
||||
ConfigManager.setJavaExecutable(m.result)
|
||||
ConfigManager.save()
|
||||
if(launchAfter){
|
||||
dlAsync()
|
||||
}
|
||||
sysAEx.disconnect()
|
||||
}
|
||||
|
||||
} else if(m.content === '_enqueueOracleJRE'){
|
||||
|
||||
if(m.result === true){
|
||||
|
||||
// Oracle JRE enqueued successfully, begin download.
|
||||
setLaunchDetails('Downloading Java..')
|
||||
sysAEx.send({task: 0, content: 'processDlQueues', argsArr: [[{id:'java', limit:1}]]})
|
||||
|
||||
} else {
|
||||
|
||||
// Oracle JRE enqueue failed. Probably due to a change in their website format.
|
||||
// User will have to follow the guide to install Java.
|
||||
setOverlayContent(
|
||||
'Yikes!<br>Java download failed.',
|
||||
'Unfortunately we\'ve encountered an issue while attempting to install Java. You will need to install a copy yourself. Please check out <a href="http://westeroscraft.wikia.com/wiki/Troubleshooting_Guide">this guide</a> for more details and instructions.',
|
||||
'Got it'
|
||||
)
|
||||
setOverlayHandler(null)
|
||||
toggleOverlay(true)
|
||||
sysAEx.disconnect()
|
||||
|
||||
}
|
||||
|
||||
} else if(m.content === 'dl'){
|
||||
|
||||
if(m.task === 0){
|
||||
// Downloading..
|
||||
setDownloadPercentage(m.value, m.total, m.percent)
|
||||
} else if(m.task === 1){
|
||||
// Download will be at 100%, remove the loading from the OS progress bar.
|
||||
remote.getCurrentWindow().setProgressBar(-1)
|
||||
|
||||
// Wait for extration to complete.
|
||||
setLaunchDetails('Extracting..')
|
||||
|
||||
} else if(m.task === 2){
|
||||
|
||||
// Extraction completed successfully.
|
||||
ConfigManager.setJavaExecutable(m.jPath)
|
||||
ConfigManager.save()
|
||||
|
||||
setLaunchDetails('Java Installed!')
|
||||
|
||||
if(launchAfter){
|
||||
dlAsync()
|
||||
}
|
||||
|
||||
sysAEx.disconnect()
|
||||
} else {
|
||||
console.error('Unknown download data type.', m)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Begin system Java scan.
|
||||
setLaunchDetails('Checking system info..')
|
||||
sysAEx.send({task: 0, content: 'validateJava', argsArr: [ConfigManager.getLauncherDirectory()]})
|
||||
|
||||
}
|
||||
|
||||
function overlayError(){
|
||||
|
||||
}
|
||||
|
||||
// Keep reference to Minecraft Process
|
||||
let proc
|
||||
// Is DiscordRPC enabled
|
||||
@ -283,12 +364,18 @@ function dlAsync(login = true){
|
||||
|
||||
} else if(m.content === 'validateAssets'){
|
||||
|
||||
setLaunchPercentage(60, 100)
|
||||
console.log('Asset Validation Complete')
|
||||
// Asset validation can *potentially* take longer, so let's track progress.
|
||||
if(m.task === 0){
|
||||
const perc = (m.value/m.total)*20
|
||||
setLaunchPercentage(40+perc, 100, parseInt(40+perc))
|
||||
} else {
|
||||
setLaunchPercentage(60, 100)
|
||||
console.log('Asset Validation Complete')
|
||||
|
||||
// Begin library validation.
|
||||
setLaunchDetails('Validating library integrity..')
|
||||
aEx.send({task: 0, content: 'validateLibraries', argsArr: [versionData]})
|
||||
// Begin library validation.
|
||||
setLaunchDetails('Validating library integrity..')
|
||||
aEx.send({task: 0, content: 'validateLibraries', argsArr: [versionData]})
|
||||
}
|
||||
|
||||
} else if(m.content === 'validateLibraries'){
|
||||
|
||||
|
@ -6,6 +6,10 @@ console.log('AssetExec Started')
|
||||
// Temporary for debug purposes.
|
||||
process.on('unhandledRejection', r => console.log(r))
|
||||
|
||||
tracker.on('assetVal', (data) => {
|
||||
process.send({task: 0, total: data.total, value: data.acc, content: 'validateAssets'})
|
||||
})
|
||||
|
||||
tracker.on('totaldlprogress', (data) => {
|
||||
process.send({task: 0, total: data.total, value: data.acc, percent: parseInt((data.acc/data.total)*100), content: 'dl'})
|
||||
})
|
||||
@ -14,6 +18,10 @@ tracker.on('dlcomplete', () => {
|
||||
process.send({task: 1, content: 'dl'})
|
||||
})
|
||||
|
||||
tracker.on('jExtracted', (jPath) => {
|
||||
process.send({task: 2, content: 'dl', jPath})
|
||||
})
|
||||
|
||||
process.on('message', (msg) => {
|
||||
if(msg.task === 0){
|
||||
const func = msg.content
|
||||
|
@ -32,7 +32,8 @@ const mkpath = require('mkdirp');
|
||||
const path = require('path')
|
||||
const Registry = require('winreg')
|
||||
const request = require('request')
|
||||
const targz = require('targz')
|
||||
const tar = require('tar-fs')
|
||||
const zlib = require('zlib')
|
||||
|
||||
// Constants
|
||||
const PLATFORM_MAP = {
|
||||
@ -558,6 +559,23 @@ class AssetGuard extends EventEmitter {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path of the OS-specific executable for the given Java
|
||||
* installation. Supported OS's are win32, darwin, linux.
|
||||
*
|
||||
* @param {string} rootDir The root directory of the Java installation.
|
||||
*/
|
||||
static javaExecFromRoot(rootDir){
|
||||
if(process.platform === 'win32'){
|
||||
return path.join(rootDir, 'bin', 'javaw.exe')
|
||||
} else if(process.platform === 'darwin'){
|
||||
return path.join(rootDir, 'Contents', 'Home', 'bin', 'java')
|
||||
} else if(process.platform === 'linux'){
|
||||
return path.join(rootDir, 'bin', 'java')
|
||||
}
|
||||
return rootDir
|
||||
}
|
||||
|
||||
/**
|
||||
* Load Mojang's launcher.json file.
|
||||
*
|
||||
@ -583,20 +601,16 @@ class AssetGuard extends EventEmitter {
|
||||
* the function's code throws errors. That would indicate that the option is changed or
|
||||
* removed.
|
||||
*
|
||||
* @param {string} binaryPath Path to the root of the java binary we wish to validate.
|
||||
* @param {string} binaryExecPath Path to the java executable we wish to validate.
|
||||
*
|
||||
* @returns {Promise.<boolean>} Resolves to false only if the test is successful and the result
|
||||
* is less than 64.
|
||||
*/
|
||||
static _validateJavaBinary(binaryPath){
|
||||
static _validateJavaBinary(binaryExecPath){
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let fBp = binaryPath
|
||||
if(!fBp.endsWith('.exe')){
|
||||
fBp = path.join(binaryPath, 'bin', 'java.exe')
|
||||
}
|
||||
if(fs.existsSync(fBp)){
|
||||
child_process.exec('"' + fBp + '" -XshowSettings:properties', (err, stdout, stderr) => {
|
||||
if(fs.existsSync(binaryExecPath)){
|
||||
child_process.exec('"' + binaryExecPath + '" -XshowSettings:properties', (err, stdout, stderr) => {
|
||||
|
||||
try {
|
||||
// Output is stored in stderr?
|
||||
@ -605,7 +619,7 @@ class AssetGuard extends EventEmitter {
|
||||
for(let i=0; i<props.length; i++){
|
||||
if(props[i].indexOf('sun.arch.data.model') > -1){
|
||||
let arch = props[i].split('=')[1].trim()
|
||||
console.log(props[i].trim() + ' for ' + binaryPath)
|
||||
console.log(props[i].trim() + ' for ' + binaryExecPath)
|
||||
resolve(parseInt(arch) >= 64)
|
||||
}
|
||||
}
|
||||
@ -770,7 +784,7 @@ class AssetGuard extends EventEmitter {
|
||||
* If versions are equal, JRE > JDK.
|
||||
*
|
||||
* @param {string} dataDir The base launcher directory.
|
||||
* @returns {Promise.<string>} A Promise which resolves to the root path of a valid
|
||||
* @returns {Promise.<string>} A Promise which resolves to the executable path of a valid
|
||||
* x64 Java installation. If none are found, null is returned.
|
||||
*/
|
||||
static async _win32JavaValidate(dataDir){
|
||||
@ -813,9 +827,10 @@ class AssetGuard extends EventEmitter {
|
||||
|
||||
// Validate that the binary is actually x64.
|
||||
for(let i=0; i<pathArr.length; i++) {
|
||||
let res = await AssetGuard._validateJavaBinary(pathArr[i])
|
||||
const execPath = AssetGuard.javaExecFromRoot(pathArr[i])
|
||||
let res = await AssetGuard._validateJavaBinary(execPath)
|
||||
if(res){
|
||||
return pathArr[i]
|
||||
return execPath
|
||||
}
|
||||
}
|
||||
|
||||
@ -961,9 +976,13 @@ class AssetGuard extends EventEmitter {
|
||||
const objectPath = path.join(localPath, 'objects')
|
||||
|
||||
const assetDlQueue = []
|
||||
let dlSize = 0;
|
||||
let dlSize = 0
|
||||
let acc = 0
|
||||
const total = Object.keys(indexData.objects).length
|
||||
//const objKeys = Object.keys(data.objects)
|
||||
async.forEachOfLimit(indexData.objects, 10, function(value, key, cb){
|
||||
acc++
|
||||
self.emit('assetVal', {acc, total})
|
||||
const hash = value.hash
|
||||
const assetName = path.join(hash.substring(0, 2), hash)
|
||||
const urlName = hash.substring(0, 2) + "/" + hash
|
||||
@ -1128,7 +1147,7 @@ class AssetGuard extends EventEmitter {
|
||||
self.forge = self._parseDistroModules(serv.modules, serv.mc_version)
|
||||
//Correct our workaround here.
|
||||
let decompressqueue = self.forge.callback
|
||||
self.forge.callback = function(asset){
|
||||
self.forge.callback = function(asset, self){
|
||||
if(asset.to.toLowerCase().endsWith('.pack.xz')){
|
||||
AssetGuard._extractPackXZ([asset.to], self.javaexec)
|
||||
}
|
||||
@ -1251,7 +1270,7 @@ class AssetGuard extends EventEmitter {
|
||||
// Java (Category=''') Validation (download) Functions
|
||||
// #region
|
||||
|
||||
_enqueueOracleJRE(dir){
|
||||
_enqueueOracleJRE(dataDir){
|
||||
return new Promise((resolve, reject) => {
|
||||
AssetGuard._latestJREOracle().then(verData => {
|
||||
if(verData != null){
|
||||
@ -1269,24 +1288,37 @@ class AssetGuard extends EventEmitter {
|
||||
if(err){
|
||||
resolve(false)
|
||||
} else {
|
||||
dataDir = path.join(dataDir, 'runtime', 'x64')
|
||||
const name = combined.substring(combined.lastIndexOf('/')+1)
|
||||
const fDir = path.join(dir, name)
|
||||
const fDir = path.join(dataDir, name)
|
||||
const jre = new Asset(name, null, resp.headers['content-length'], opts, fDir)
|
||||
this.java = new DLTracker([jre], jre.size, a => {
|
||||
targz.decompress({
|
||||
src: a.to,
|
||||
dest: dir
|
||||
}, err => {
|
||||
if(err){
|
||||
console.log(err)
|
||||
} else {
|
||||
this.java = new DLTracker([jre], jre.size, (a, self) => {
|
||||
let h = null
|
||||
fs.createReadStream(a.to)
|
||||
.on('error', err => console.log(err))
|
||||
.pipe(zlib.createGunzip())
|
||||
.on('error', err => console.log(err))
|
||||
.pipe(tar.extract(dataDir, {
|
||||
map: (header) => {
|
||||
if(h == null){
|
||||
h = header.name
|
||||
}
|
||||
}
|
||||
}))
|
||||
.on('error', err => console.log(err))
|
||||
.on('finish', () => {
|
||||
fs.unlink(a.to, err => {
|
||||
if(err){
|
||||
console.log(err)
|
||||
}
|
||||
if(h.indexOf('/') > -1){
|
||||
h = h.substring(0, h.indexOf('/'))
|
||||
}
|
||||
const pos = path.join(dataDir, h)
|
||||
self.emit('jExtracted', AssetGuard.javaExecFromRoot(pos))
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
resolve(true)
|
||||
}
|
||||
@ -1371,7 +1403,7 @@ class AssetGuard extends EventEmitter {
|
||||
writeStream.on('close', () => {
|
||||
//console.log('DLResults ' + asset.size + ' ' + count + ' ', asset.size === count)
|
||||
if(concurrentDlTracker.callback != null){
|
||||
concurrentDlTracker.callback.apply(concurrentDlTracker, [asset])
|
||||
concurrentDlTracker.callback.apply(concurrentDlTracker, [asset, self])
|
||||
}
|
||||
cb()
|
||||
})
|
||||
|
@ -25,7 +25,7 @@ const DEFAULT_CONFIG = {
|
||||
java: {
|
||||
minRAM: '2G',
|
||||
maxRAM: resolveMaxRAM(), // Dynamic
|
||||
executable: 'C:\\Program Files\\Java\\jdk1.8.0_152\\bin\\javaw.exe', // TODO Resolve
|
||||
executable: null,
|
||||
jvmOptions: [
|
||||
'-XX:+UseConcMarkSweepGC',
|
||||
'-XX:+CMSIncrementalMode',
|
||||
|
40
package-lock.json
generated
40
package-lock.json
generated
@ -246,7 +246,7 @@
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
|
||||
"integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
|
||||
"requires": {
|
||||
"readable-stream": "2.3.5",
|
||||
"readable-stream": "2.3.6",
|
||||
"safe-buffer": "5.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -256,23 +256,23 @@
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.5",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.5.tgz",
|
||||
"integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==",
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"requires": {
|
||||
"core-util-is": "1.0.2",
|
||||
"inherits": "2.0.3",
|
||||
"isarray": "1.0.0",
|
||||
"process-nextick-args": "2.0.0",
|
||||
"safe-buffer": "5.1.1",
|
||||
"string_decoder": "1.0.3",
|
||||
"string_decoder": "1.1.1",
|
||||
"util-deprecate": "1.0.2"
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
||||
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.1"
|
||||
}
|
||||
@ -2750,7 +2750,7 @@
|
||||
"requires": {
|
||||
"bl": "1.2.2",
|
||||
"end-of-stream": "1.4.1",
|
||||
"readable-stream": "2.3.5",
|
||||
"readable-stream": "2.3.6",
|
||||
"xtend": "4.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -2760,23 +2760,23 @@
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.5",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.5.tgz",
|
||||
"integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==",
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"requires": {
|
||||
"core-util-is": "1.0.2",
|
||||
"inherits": "2.0.3",
|
||||
"isarray": "1.0.0",
|
||||
"process-nextick-args": "2.0.0",
|
||||
"safe-buffer": "5.1.1",
|
||||
"string_decoder": "1.0.3",
|
||||
"string_decoder": "1.1.1",
|
||||
"util-deprecate": "1.0.2"
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
||||
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.1"
|
||||
}
|
||||
@ -2788,14 +2788,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"targz": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/targz/-/targz-1.0.1.tgz",
|
||||
"integrity": "sha1-j3alI2lM3t+7XWCkB2/27uzFOY8=",
|
||||
"requires": {
|
||||
"tar-fs": "1.16.0"
|
||||
}
|
||||
},
|
||||
"temp-file": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.1.1.tgz",
|
||||
|
@ -33,7 +33,7 @@
|
||||
"ejs-electron": "^2.0.1",
|
||||
"jquery": "^3.3.1",
|
||||
"request-promise-native": "^1.0.5",
|
||||
"targz": "^1.0.1",
|
||||
"tar-fs": "^1.16.0",
|
||||
"uuid": "^3.2.1",
|
||||
"winreg": "^1.2.4"
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user