Merge pull request #270 from dscalzi/assetguard-2

assetguard2
This commit is contained in:
Daniel Scalzi 2023-03-24 17:43:29 -04:00 committed by GitHub
commit 22233831dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 935 additions and 3834 deletions

View File

@ -12,15 +12,15 @@ jobs:
steps: steps:
- name: Check out Git repository - name: Check out Git repository
uses: actions/checkout@v1 uses: actions/checkout@v3
- name: Set up Node - name: Set up Node
uses: actions/setup-node@v1 uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 18
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v2 uses: actions/setup-python@v4
with: with:
python-version: 3.x python-version: 3.x

View File

@ -3772,6 +3772,7 @@ input:checked + .toggleSwitchSlider:before {
font-size: 10px; font-size: 10px;
line-height: 10px; line-height: 10px;
font-weight: bold; font-weight: bold;
text-align: left;
} }
/* Content container for the server listing's information. */ /* Content container for the server listing's information. */

View File

@ -1,74 +0,0 @@
let target = require('./assetguard')[process.argv[2]]
if(target == null){
process.send({context: 'error', data: null, error: 'Invalid class name'})
console.error('Invalid class name passed to argv[2], cannot continue.')
process.exit(1)
}
let tracker = new target(...(process.argv.splice(3)))
const { LoggerUtil } = require('helios-core')
const logger = LoggerUtil.getLogger('AssetExec')
//const tracker = new AssetGuard(process.argv[2], process.argv[3])
logger.info('AssetExec Started')
// Temporary for debug purposes.
process.on('unhandledRejection', r => console.log(r))
let percent = 0
function assignListeners(){
tracker.on('validate', (data) => {
process.send({context: 'validate', data})
})
tracker.on('progress', (data, acc, total) => {
const currPercent = parseInt((acc/total) * 100)
if (currPercent !== percent) {
percent = currPercent
process.send({context: 'progress', data, value: acc, total, percent})
}
})
tracker.on('complete', (data, ...args) => {
process.send({context: 'complete', data, args})
})
tracker.on('error', (data, error) => {
process.send({context: 'error', data, error})
})
}
assignListeners()
process.on('message', (msg) => {
if(msg.task === 'execute'){
const func = msg.function
let nS = tracker[func] // Nonstatic context
let iS = target[func] // Static context
if(typeof nS === 'function' || typeof iS === 'function'){
const f = typeof nS === 'function' ? nS : iS
const res = f.apply(f === nS ? tracker : null, msg.argsArr)
if(res instanceof Promise){
res.then((v) => {
process.send({result: v, context: func})
}).catch((err) => {
process.send({result: err.message || err, context: func})
})
} else {
process.send({result: res, context: func})
}
} else {
process.send({context: 'error', data: null, error: `Function ${func} not found on ${process.argv[2]}`})
}
} else if(msg.task === 'changeContext'){
target = require('./assetguard')[msg.class]
if(target == null){
process.send({context: 'error', data: null, error: `Invalid class ${msg.class}`})
} else {
tracker = new target(...(msg.args))
assignListeners()
}
}
})
process.on('disconnect', () => {
logger.info('AssetExec Disconnected')
process.exit(0)
})

File diff suppressed because it is too large Load Diff

View File

@ -6,11 +6,10 @@ const path = require('path')
const logger = LoggerUtil.getLogger('ConfigManager') const logger = LoggerUtil.getLogger('ConfigManager')
const sysRoot = process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + '/Library/Application Support' : process.env.HOME) const sysRoot = process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + '/Library/Application Support' : process.env.HOME)
// TODO change
const dataPath = path.join(sysRoot, '.helioslauncher') const dataPath = path.join(sysRoot, '.helioslauncher')
// Forked processes do not have access to electron, so we have this workaround. const launcherDir = require('@electron/remote').app.getPath('userData')
const launcherDir = process.env.CONFIG_DIRECT_PATH || require('@electron/remote').app.getPath('userData')
/** /**
* Retrieve the absolute path of the launcher directory. * Retrieve the absolute path of the launcher directory.
@ -44,45 +43,30 @@ const configPath = path.join(exports.getLauncherDirectory(), 'config.json')
const configPathLEGACY = path.join(dataPath, 'config.json') const configPathLEGACY = path.join(dataPath, 'config.json')
const firstLaunch = !fs.existsSync(configPath) && !fs.existsSync(configPathLEGACY) const firstLaunch = !fs.existsSync(configPath) && !fs.existsSync(configPathLEGACY)
exports.getAbsoluteMinRAM = function(){ exports.getAbsoluteMinRAM = function(ram){
if(ram?.minimum != null) {
return ram.minimum/1024
} else {
// Legacy behavior
const mem = os.totalmem() const mem = os.totalmem()
return mem >= 6000000000 ? 3 : 2 return mem >= (6*1073741824) ? 3 : 2
}
} }
exports.getAbsoluteMaxRAM = function(){ exports.getAbsoluteMaxRAM = function(ram){
const mem = os.totalmem() const mem = os.totalmem()
const gT16 = mem-16000000000 const gT16 = mem-(16*1073741824)
return Math.floor((mem-1000000000-(gT16 > 0 ? (Number.parseInt(gT16/8) + 16000000000/4) : mem/4))/1000000000) return Math.floor((mem-(gT16 > 0 ? (Number.parseInt(gT16/8) + (16*1073741824)/4) : mem/4))/1073741824)
} }
function resolveMaxRAM(){ function resolveSelectedRAM(ram) {
if(ram?.recommended != null) {
return `${ram.recommended}M`
} else {
// Legacy behavior
const mem = os.totalmem() const mem = os.totalmem()
return mem >= 8000000000 ? '4G' : (mem >= 6000000000 ? '3G' : '2G') return mem >= (8*1073741824) ? '4G' : (mem >= (6*1073741824) ? '3G' : '2G')
} }
function resolveMinRAM(){
return resolveMaxRAM()
}
/**
* TODO Copy pasted, should be in a utility file.
*
* Returns true if the actual version is greater than
* or equal to the desired version.
*
* @param {string} desired The desired version.
* @param {string} actual The actual version.
*/
function mcVersionAtLeast(desired, actual){
const des = desired.split('.')
const act = actual.split('.')
for(let i=0; i<des.length; i++){
if(!(parseInt(act[i]) >= parseInt(des[i]))){
return false
}
}
return true
} }
/** /**
@ -523,18 +507,18 @@ exports.setModConfiguration = function(serverid, configuration){
// Java Settings // Java Settings
function defaultJavaConfig(mcVersion) { function defaultJavaConfig(effectiveJavaOptions, ram) {
if(mcVersionAtLeast('1.17', mcVersion)) { if(effectiveJavaOptions.suggestedMajor > 8) {
return defaultJavaConfig117() return defaultJavaConfig17(ram)
} else { } else {
return defaultJavaConfigBelow117() return defaultJavaConfig8(ram)
} }
} }
function defaultJavaConfigBelow117() { function defaultJavaConfig8(ram) {
return { return {
minRAM: resolveMinRAM(), minRAM: resolveSelectedRAM(ram),
maxRAM: resolveMaxRAM(), // Dynamic maxRAM: resolveSelectedRAM(ram),
executable: null, executable: null,
jvmOptions: [ jvmOptions: [
'-XX:+UseConcMarkSweepGC', '-XX:+UseConcMarkSweepGC',
@ -545,10 +529,10 @@ function defaultJavaConfigBelow117() {
} }
} }
function defaultJavaConfig117() { function defaultJavaConfig17(ram) {
return { return {
minRAM: resolveMinRAM(), minRAM: resolveSelectedRAM(ram),
maxRAM: resolveMaxRAM(), // Dynamic maxRAM: resolveSelectedRAM(ram),
executable: null, executable: null,
jvmOptions: [ jvmOptions: [
'-XX:+UnlockExperimentalVMOptions', '-XX:+UnlockExperimentalVMOptions',
@ -567,9 +551,9 @@ function defaultJavaConfig117() {
* @param {string} serverid The server id. * @param {string} serverid The server id.
* @param {*} mcVersion The minecraft version of the server. * @param {*} mcVersion The minecraft version of the server.
*/ */
exports.ensureJavaConfig = function(serverid, mcVersion) { exports.ensureJavaConfig = function(serverid, effectiveJavaOptions, ram) {
if(!Object.prototype.hasOwnProperty.call(config.javaConfig, serverid)) { if(!Object.prototype.hasOwnProperty.call(config.javaConfig, serverid)) {
config.javaConfig[serverid] = defaultJavaConfig(mcVersion) config.javaConfig[serverid] = defaultJavaConfig(effectiveJavaOptions, ram)
} }
} }

View File

@ -1,621 +1,17 @@
const fs = require('fs') const { DistributionAPI } = require('helios-core/common')
const path = require('path')
const request = require('request')
const { LoggerUtil } = require('helios-core')
const ConfigManager = require('./configmanager') const ConfigManager = require('./configmanager')
const logger = LoggerUtil.getLogger('DistroManager') // Old WesterosCraft url.
// exports.REMOTE_DISTRO_URL = 'http://mc.westeroscraft.com/WesterosCraftLauncher/distribution.json'
/** exports.REMOTE_DISTRO_URL = 'https://helios-files.geekcorner.eu.org/distribution.json'
* Represents the download information
* for a specific module. const api = new DistributionAPI(
*/ ConfigManager.getLauncherDirectory(),
class Artifact { null, // Injected forcefully by the preloader.
null, // Injected forcefully by the preloader.
/** exports.REMOTE_DISTRO_URL,
* Parse a JSON object into an Artifact. false
* )
* @param {Object} json A JSON object representing an Artifact.
* exports.DistroAPI = api
* @returns {Artifact} The parsed Artifact.
*/
static fromJSON(json){
return Object.assign(new Artifact(), json)
}
/**
* Get the MD5 hash of the artifact. This value may
* be undefined for artifacts which are not to be
* validated and updated.
*
* @returns {string} The MD5 hash of the Artifact or undefined.
*/
getHash(){
return this.MD5
}
/**
* @returns {number} The download size of the artifact.
*/
getSize(){
return this.size
}
/**
* @returns {string} The download url of the artifact.
*/
getURL(){
return this.url
}
/**
* @returns {string} The artifact's destination path.
*/
getPath(){
return this.path
}
}
exports.Artifact
/**
* Represents a the requirement status
* of a module.
*/
class Required {
/**
* Parse a JSON object into a Required object.
*
* @param {Object} json A JSON object representing a Required object.
*
* @returns {Required} The parsed Required object.
*/
static fromJSON(json){
if(json == null){
return new Required(true, true)
} else {
return new Required(json.value == null ? true : json.value, json.def == null ? true : json.def)
}
}
constructor(value, def){
this.value = value
this.default = def
}
/**
* Get the default value for a required object. If a module
* is not required, this value determines whether or not
* it is enabled by default.
*
* @returns {boolean} The default enabled value.
*/
isDefault(){
return this.default
}
/**
* @returns {boolean} Whether or not the module is required.
*/
isRequired(){
return this.value
}
}
exports.Required
/**
* Represents a module.
*/
class Module {
/**
* Parse a JSON object into a Module.
*
* @param {Object} json A JSON object representing a Module.
* @param {string} serverid The ID of the server to which this module belongs.
*
* @returns {Module} The parsed Module.
*/
static fromJSON(json, serverid){
return new Module(json.id, json.name, json.type, json.classpath, json.required, json.artifact, json.subModules, serverid)
}
/**
* Resolve the default extension for a specific module type.
*
* @param {string} type The type of the module.
*
* @return {string} The default extension for the given type.
*/
static _resolveDefaultExtension(type){
switch (type) {
case exports.Types.Library:
case exports.Types.ForgeHosted:
case exports.Types.LiteLoader:
case exports.Types.ForgeMod:
return 'jar'
case exports.Types.LiteMod:
return 'litemod'
case exports.Types.File:
default:
return 'jar' // There is no default extension really.
}
}
constructor(id, name, type, classpath, required, artifact, subModules, serverid) {
this.identifier = id
this.type = type
this.classpath = classpath
this._resolveMetaData()
this.name = name
this.required = Required.fromJSON(required)
this.artifact = Artifact.fromJSON(artifact)
this._resolveArtifactPath(artifact.path, serverid)
this._resolveSubModules(subModules, serverid)
}
_resolveMetaData(){
try {
const m0 = this.identifier.split('@')
this.artifactExt = m0[1] || Module._resolveDefaultExtension(this.type)
const m1 = m0[0].split(':')
this.artifactClassifier = m1[3] || undefined
this.artifactVersion = m1[2] || '???'
this.artifactID = m1[1] || '???'
this.artifactGroup = m1[0] || '???'
} catch (err) {
// Improper identifier
logger.error('Improper ID for module', this.identifier, err)
}
}
_resolveArtifactPath(artifactPath, serverid){
const pth = artifactPath == null ? path.join(...this.getGroup().split('.'), this.getID(), this.getVersion(), `${this.getID()}-${this.getVersion()}${this.artifactClassifier != undefined ? `-${this.artifactClassifier}` : ''}.${this.getExtension()}`) : artifactPath
switch (this.type){
case exports.Types.Library:
case exports.Types.ForgeHosted:
case exports.Types.LiteLoader:
this.artifact.path = path.join(ConfigManager.getCommonDirectory(), 'libraries', pth)
break
case exports.Types.ForgeMod:
case exports.Types.LiteMod:
this.artifact.path = path.join(ConfigManager.getCommonDirectory(), 'modstore', pth)
break
case exports.Types.VersionManifest:
this.artifact.path = path.join(ConfigManager.getCommonDirectory(), 'versions', this.getIdentifier(), `${this.getIdentifier()}.json`)
break
case exports.Types.File:
default:
this.artifact.path = path.join(ConfigManager.getInstanceDirectory(), serverid, pth)
break
}
}
_resolveSubModules(json, serverid){
const arr = []
if(json != null){
for(let sm of json){
arr.push(Module.fromJSON(sm, serverid))
}
}
this.subModules = arr.length > 0 ? arr : null
}
/**
* @returns {string} The full, unparsed module identifier.
*/
getIdentifier(){
return this.identifier
}
/**
* @returns {string} The name of the module.
*/
getName(){
return this.name
}
/**
* @returns {Required} The required object declared by this module.
*/
getRequired(){
return this.required
}
/**
* @returns {Artifact} The artifact declared by this module.
*/
getArtifact(){
return this.artifact
}
/**
* @returns {string} The maven identifier of this module's artifact.
*/
getID(){
return this.artifactID
}
/**
* @returns {string} The maven group of this module's artifact.
*/
getGroup(){
return this.artifactGroup
}
/**
* @returns {string} The identifier without he version or extension.
*/
getVersionlessID(){
return this.getGroup() + ':' + this.getID()
}
/**
* @returns {string} The identifier without the extension.
*/
getExtensionlessID(){
return this.getIdentifier().split('@')[0]
}
/**
* @returns {string} The version of this module's artifact.
*/
getVersion(){
return this.artifactVersion
}
/**
* @returns {string} The classifier of this module's artifact
*/
getClassifier(){
return this.artifactClassifier
}
/**
* @returns {string} The extension of this module's artifact.
*/
getExtension(){
return this.artifactExt
}
/**
* @returns {boolean} Whether or not this module has sub modules.
*/
hasSubModules(){
return this.subModules != null
}
/**
* @returns {Array.<Module>} An array of sub modules.
*/
getSubModules(){
return this.subModules
}
/**
* @returns {string} The type of the module.
*/
getType(){
return this.type
}
/**
* @returns {boolean} Whether or not this library should be on the classpath.
*/
getClasspath(){
return this.classpath ?? true
}
}
exports.Module
/**
* Represents a server configuration.
*/
class Server {
/**
* Parse a JSON object into a Server.
*
* @param {Object} json A JSON object representing a Server.
*
* @returns {Server} The parsed Server object.
*/
static fromJSON(json){
const mdls = json.modules
json.modules = []
const serv = Object.assign(new Server(), json)
serv._resolveModules(mdls)
return serv
}
_resolveModules(json){
const arr = []
for(let m of json){
arr.push(Module.fromJSON(m, this.getID()))
}
this.modules = arr
}
/**
* @returns {string} The ID of the server.
*/
getID(){
return this.id
}
/**
* @returns {string} The name of the server.
*/
getName(){
return this.name
}
/**
* @returns {string} The description of the server.
*/
getDescription(){
return this.description
}
/**
* @returns {string} The URL of the server's icon.
*/
getIcon(){
return this.icon
}
/**
* @returns {string} The version of the server configuration.
*/
getVersion(){
return this.version
}
/**
* @returns {string} The IP address of the server.
*/
getAddress(){
return this.address
}
/**
* @returns {string} The minecraft version of the server.
*/
getMinecraftVersion(){
return this.minecraftVersion
}
/**
* @returns {boolean} Whether or not this server is the main
* server. The main server is selected by the launcher when
* no valid server is selected.
*/
isMainServer(){
return this.mainServer
}
/**
* @returns {boolean} Whether or not the server is autoconnect.
* by default.
*/
isAutoConnect(){
return this.autoconnect
}
/**
* @returns {Array.<Module>} An array of modules for this server.
*/
getModules(){
return this.modules
}
}
exports.Server
/**
* Represents the Distribution Index.
*/
class DistroIndex {
/**
* Parse a JSON object into a DistroIndex.
*
* @param {Object} json A JSON object representing a DistroIndex.
*
* @returns {DistroIndex} The parsed Server object.
*/
static fromJSON(json){
const servers = json.servers
json.servers = []
const distro = Object.assign(new DistroIndex(), json)
distro._resolveServers(servers)
distro._resolveMainServer()
return distro
}
_resolveServers(json){
const arr = []
for(let s of json){
arr.push(Server.fromJSON(s))
}
this.servers = arr
}
_resolveMainServer(){
for(let serv of this.servers){
if(serv.mainServer){
this.mainServer = serv.id
return
}
}
// If no server declares default_selected, default to the first one declared.
this.mainServer = (this.servers.length > 0) ? this.servers[0].getID() : null
}
/**
* @returns {string} The version of the distribution index.
*/
getVersion(){
return this.version
}
/**
* @returns {string} The URL to the news RSS feed.
*/
getRSS(){
return this.rss
}
/**
* @returns {Array.<Server>} An array of declared server configurations.
*/
getServers(){
return this.servers
}
/**
* Get a server configuration by its ID. If it does not
* exist, null will be returned.
*
* @param {string} id The ID of the server.
*
* @returns {Server} The server configuration with the given ID or null.
*/
getServer(id){
for(let serv of this.servers){
if(serv.id === id){
return serv
}
}
return null
}
/**
* Get the main server.
*
* @returns {Server} The main server.
*/
getMainServer(){
return this.mainServer != null ? this.getServer(this.mainServer) : null
}
}
exports.DistroIndex
exports.Types = {
Library: 'Library',
ForgeHosted: 'ForgeHosted',
Forge: 'Forge', // Unimplemented
LiteLoader: 'LiteLoader',
ForgeMod: 'ForgeMod',
LiteMod: 'LiteMod',
File: 'File',
VersionManifest: 'VersionManifest'
}
let DEV_MODE = false
const DISTRO_PATH = path.join(ConfigManager.getLauncherDirectory(), 'distribution.json')
const DEV_PATH = path.join(ConfigManager.getLauncherDirectory(), 'dev_distribution.json')
let data = null
/**
* @returns {Promise.<DistroIndex>}
*/
exports.pullRemote = function(){
if(DEV_MODE){
return exports.pullLocal()
}
return new Promise((resolve, reject) => {
const distroURL = 'http://mc.westeroscraft.com/WesterosCraftLauncher/distribution.json'
//const distroURL = 'https://gist.githubusercontent.com/dscalzi/53b1ba7a11d26a5c353f9d5ae484b71b/raw/'
const opts = {
url: distroURL,
timeout: 2500
}
const distroDest = path.join(ConfigManager.getLauncherDirectory(), 'distribution.json')
request(opts, (error, resp, body) => {
if(!error){
try {
data = DistroIndex.fromJSON(JSON.parse(body))
} catch (e) {
reject(e)
return
}
fs.writeFile(distroDest, body, 'utf-8', (err) => {
if(!err){
resolve(data)
return
} else {
reject(err)
return
}
})
} else {
reject(error)
return
}
})
})
}
/**
* @returns {Promise.<DistroIndex>}
*/
exports.pullLocal = function(){
return new Promise((resolve, reject) => {
fs.readFile(DEV_MODE ? DEV_PATH : DISTRO_PATH, 'utf-8', (err, d) => {
if(!err){
data = DistroIndex.fromJSON(JSON.parse(d))
resolve(data)
return
} else {
reject(err)
return
}
})
})
}
exports.setDevMode = function(value){
if(value){
logger.info('Developer mode enabled.')
logger.info('If you don\'t know what that means, revert immediately.')
} else {
logger.info('Developer mode disabled.')
}
DEV_MODE = value
}
exports.isDevMode = function(){
return DEV_MODE
}
/**
* @returns {DistroIndex}
*/
exports.getDistribution = function(){
return data
}

View File

@ -4,9 +4,11 @@ const os = require('os')
const path = require('path') const path = require('path')
const ConfigManager = require('./configmanager') const ConfigManager = require('./configmanager')
const DistroManager = require('./distromanager') const { DistroAPI } = require('./distromanager')
const LangLoader = require('./langloader') const LangLoader = require('./langloader')
const { LoggerUtil } = require('helios-core') const { LoggerUtil } = require('helios-core')
// eslint-disable-next-line no-unused-vars
const { HeliosDistribution } = require('helios-core/common')
const logger = LoggerUtil.getLogger('Preloader') const logger = LoggerUtil.getLogger('Preloader')
@ -15,16 +17,25 @@ logger.info('Loading..')
// Load ConfigManager // Load ConfigManager
ConfigManager.load() ConfigManager.load()
// Yuck!
// TODO Fix this
DistroAPI['commonDir'] = ConfigManager.getCommonDirectory()
DistroAPI['instanceDir'] = ConfigManager.getInstanceDirectory()
// Load Strings // Load Strings
LangLoader.loadLanguage('en_US') LangLoader.loadLanguage('en_US')
/**
*
* @param {HeliosDistribution} data
*/
function onDistroLoad(data){ function onDistroLoad(data){
if(data != null){ if(data != null){
// Resolve the selected server if its value has yet to be set. // Resolve the selected server if its value has yet to be set.
if(ConfigManager.getSelectedServer() == null || data.getServer(ConfigManager.getSelectedServer()) == null){ if(ConfigManager.getSelectedServer() == null || data.getServerById(ConfigManager.getSelectedServer()) == null){
logger.info('Determining default selected server..') logger.info('Determining default selected server..')
ConfigManager.setSelectedServer(data.getMainServer().getID()) ConfigManager.setSelectedServer(data.getMainServer().rawServer.id)
ConfigManager.save() ConfigManager.save()
} }
} }
@ -32,33 +43,18 @@ function onDistroLoad(data){
} }
// Ensure Distribution is downloaded and cached. // Ensure Distribution is downloaded and cached.
DistroManager.pullRemote().then((data) => { DistroAPI.getDistribution()
.then(heliosDistro => {
logger.info('Loaded distribution index.') logger.info('Loaded distribution index.')
onDistroLoad(data) onDistroLoad(heliosDistro)
})
}).catch((err) => { .catch(err => {
logger.info('Failed to load distribution index.')
logger.error(err)
logger.info('Attempting to load an older version of the distribution index.')
// Try getting a local copy, better than nothing.
DistroManager.pullLocal().then((data) => {
logger.info('Successfully loaded an older version of the distribution index.')
onDistroLoad(data)
}).catch((err) => {
logger.info('Failed to load an older version of the distribution index.') logger.info('Failed to load an older version of the distribution index.')
logger.info('Application cannot run.') logger.info('Application cannot run.')
logger.error(err) logger.error(err)
onDistroLoad(null) onDistroLoad(null)
})
}) })
// Clean up temp dir incase previous launches ended unexpectedly. // Clean up temp dir incase previous launches ended unexpectedly.

View File

@ -3,20 +3,19 @@ const child_process = require('child_process')
const crypto = require('crypto') const crypto = require('crypto')
const fs = require('fs-extra') const fs = require('fs-extra')
const { LoggerUtil } = require('helios-core') const { LoggerUtil } = require('helios-core')
const { getMojangOS, isLibraryCompatible, mcVersionAtLeast } = require('helios-core/common')
const { Type } = require('helios-distribution-types')
const os = require('os') const os = require('os')
const path = require('path') const path = require('path')
const { URL } = require('url')
const { Util, Library } = require('./assetguard')
const ConfigManager = require('./configmanager') const ConfigManager = require('./configmanager')
const DistroManager = require('./distromanager')
const logger = LoggerUtil.getLogger('ProcessBuilder') const logger = LoggerUtil.getLogger('ProcessBuilder')
class ProcessBuilder { class ProcessBuilder {
constructor(distroServer, versionData, forgeData, authUser, launcherVersion){ constructor(distroServer, versionData, forgeData, authUser, launcherVersion){
this.gameDir = path.join(ConfigManager.getInstanceDirectory(), distroServer.getID()) this.gameDir = path.join(ConfigManager.getInstanceDirectory(), distroServer.rawServer.id)
this.commonDir = ConfigManager.getCommonDirectory() this.commonDir = ConfigManager.getCommonDirectory()
this.server = distroServer this.server = distroServer
this.versionData = versionData this.versionData = versionData
@ -41,10 +40,10 @@ class ProcessBuilder {
process.throwDeprecation = true process.throwDeprecation = true
this.setupLiteLoader() this.setupLiteLoader()
logger.info('Using liteloader:', this.usingLiteLoader) logger.info('Using liteloader:', this.usingLiteLoader)
const modObj = this.resolveModConfiguration(ConfigManager.getModConfiguration(this.server.getID()).mods, this.server.getModules()) const modObj = this.resolveModConfiguration(ConfigManager.getModConfiguration(this.server.rawServer.id).mods, this.server.modules)
// Mod list below 1.13 // Mod list below 1.13
if(!Util.mcVersionAtLeast('1.13', this.server.getMinecraftVersion())){ if(!mcVersionAtLeast('1.13', this.server.rawServer.minecraftVersion)){
this.constructJSONModList('forge', modObj.fMods, true) this.constructJSONModList('forge', modObj.fMods, true)
if(this.usingLiteLoader){ if(this.usingLiteLoader){
this.constructJSONModList('liteloader', modObj.lMods, true) this.constructJSONModList('liteloader', modObj.lMods, true)
@ -54,14 +53,14 @@ class ProcessBuilder {
const uberModArr = modObj.fMods.concat(modObj.lMods) const uberModArr = modObj.fMods.concat(modObj.lMods)
let args = this.constructJVMArguments(uberModArr, tempNativePath) let args = this.constructJVMArguments(uberModArr, tempNativePath)
if(Util.mcVersionAtLeast('1.13', this.server.getMinecraftVersion())){ if(mcVersionAtLeast('1.13', this.server.rawServer.minecraftVersion)){
//args = args.concat(this.constructModArguments(modObj.fMods)) //args = args.concat(this.constructModArguments(modObj.fMods))
args = args.concat(this.constructModList(modObj.fMods)) args = args.concat(this.constructModList(modObj.fMods))
} }
logger.info('Launch Arguments:', args) logger.info('Launch Arguments:', args)
const child = child_process.spawn(ConfigManager.getJavaExecutable(this.server.getID()), args, { const child = child_process.spawn(ConfigManager.getJavaExecutable(this.server.rawServer.id), args, {
cwd: this.gameDir, cwd: this.gameDir,
detached: ConfigManager.getLaunchDetached() detached: ConfigManager.getLaunchDetached()
}) })
@ -122,7 +121,7 @@ class ProcessBuilder {
* @returns {boolean} True if the mod is enabled, false otherwise. * @returns {boolean} True if the mod is enabled, false otherwise.
*/ */
static isModEnabled(modCfg, required = null){ static isModEnabled(modCfg, required = null){
return modCfg != null ? ((typeof modCfg === 'boolean' && modCfg) || (typeof modCfg === 'object' && (typeof modCfg.value !== 'undefined' ? modCfg.value : true))) : required != null ? required.isDefault() : true return modCfg != null ? ((typeof modCfg === 'boolean' && modCfg) || (typeof modCfg === 'object' && (typeof modCfg.value !== 'undefined' ? modCfg.value : true))) : required != null ? required.def : true
} }
/** /**
@ -132,20 +131,20 @@ class ProcessBuilder {
* mod. It must not be declared as a submodule. * mod. It must not be declared as a submodule.
*/ */
setupLiteLoader(){ setupLiteLoader(){
for(let ll of this.server.getModules()){ for(let ll of this.server.modules){
if(ll.getType() === DistroManager.Types.LiteLoader){ if(ll.rawModule.type === Type.LiteLoader){
if(!ll.getRequired().isRequired()){ if(!ll.getRequired().value){
const modCfg = ConfigManager.getModConfiguration(this.server.getID()).mods const modCfg = ConfigManager.getModConfiguration(this.server.rawServer.id).mods
if(ProcessBuilder.isModEnabled(modCfg[ll.getVersionlessID()], ll.getRequired())){ if(ProcessBuilder.isModEnabled(modCfg[ll.getVersionlessMavenIdentifier()], ll.getRequired())){
if(fs.existsSync(ll.getArtifact().getPath())){ if(fs.existsSync(ll.getPath())){
this.usingLiteLoader = true this.usingLiteLoader = true
this.llPath = ll.getArtifact().getPath() this.llPath = ll.getPath()
} }
} }
} else { } else {
if(fs.existsSync(ll.getArtifact().getPath())){ if(fs.existsSync(ll.getPath())){
this.usingLiteLoader = true this.usingLiteLoader = true
this.llPath = ll.getArtifact().getPath() this.llPath = ll.getPath()
} }
} }
} }
@ -166,20 +165,20 @@ class ProcessBuilder {
let lMods = [] let lMods = []
for(let mdl of mdls){ for(let mdl of mdls){
const type = mdl.getType() const type = mdl.rawModule.type
if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){ if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader){
const o = !mdl.getRequired().isRequired() const o = !mdl.getRequired().value
const e = ProcessBuilder.isModEnabled(modCfg[mdl.getVersionlessID()], mdl.getRequired()) const e = ProcessBuilder.isModEnabled(modCfg[mdl.getVersionlessMavenIdentifier()], mdl.getRequired())
if(!o || (o && e)){ if(!o || (o && e)){
if(mdl.hasSubModules()){ if(mdl.subModules.length > 0){
const v = this.resolveModConfiguration(modCfg[mdl.getVersionlessID()].mods, mdl.getSubModules()) const v = this.resolveModConfiguration(modCfg[mdl.getVersionlessMavenIdentifier()].mods, mdl.subModules)
fMods = fMods.concat(v.fMods) fMods = fMods.concat(v.fMods)
lMods = lMods.concat(v.lMods) lMods = lMods.concat(v.lMods)
if(mdl.type === DistroManager.Types.LiteLoader){ if(type === Type.LiteLoader){
continue continue
} }
} }
if(mdl.type === DistroManager.Types.ForgeMod){ if(type === Type.ForgeMod){
fMods.push(mdl) fMods.push(mdl)
} else { } else {
lMods.push(mdl) lMods.push(mdl)
@ -242,11 +241,11 @@ class ProcessBuilder {
const ids = [] const ids = []
if(type === 'forge'){ if(type === 'forge'){
for(let mod of mods){ for(let mod of mods){
ids.push(mod.getExtensionlessID()) ids.push(mod.getExtensionlessMavenIdentifier())
} }
} else { } else {
for(let mod of mods){ for(let mod of mods){
ids.push(mod.getExtensionlessID() + '@' + mod.getExtension()) ids.push(mod.getMavenIdentifier())
} }
} }
modList.modRef = ids modList.modRef = ids
@ -266,7 +265,7 @@ class ProcessBuilder {
// */ // */
// constructModArguments(mods){ // constructModArguments(mods){
// const argStr = mods.map(mod => { // const argStr = mods.map(mod => {
// return mod.getExtensionlessID() // return mod.getExtensionlessMavenIdentifier()
// }).join(',') // }).join(',')
// if(argStr){ // if(argStr){
@ -289,7 +288,7 @@ class ProcessBuilder {
*/ */
constructModList(mods) { constructModList(mods) {
const writeBuffer = mods.map(mod => { const writeBuffer = mods.map(mod => {
return mod.getExtensionlessID() return mod.getExtensionlessMavenIdentifier()
}).join('\n') }).join('\n')
if(writeBuffer) { if(writeBuffer) {
@ -307,14 +306,11 @@ class ProcessBuilder {
} }
_processAutoConnectArg(args){ _processAutoConnectArg(args){
if(ConfigManager.getAutoConnect() && this.server.isAutoConnect()){ if(ConfigManager.getAutoConnect() && this.server.rawServer.autoconnect){
const serverURL = new URL('my://' + this.server.getAddress())
args.push('--server') args.push('--server')
args.push(serverURL.hostname) args.push(this.server.hostname)
if(serverURL.port){
args.push('--port') args.push('--port')
args.push(serverURL.port) args.push(this.server.port)
}
} }
} }
@ -326,7 +322,7 @@ class ProcessBuilder {
* @returns {Array.<string>} An array containing the full JVM arguments for this process. * @returns {Array.<string>} An array containing the full JVM arguments for this process.
*/ */
constructJVMArguments(mods, tempNativePath){ constructJVMArguments(mods, tempNativePath){
if(Util.mcVersionAtLeast('1.13', this.server.getMinecraftVersion())){ if(mcVersionAtLeast('1.13', this.server.rawServer.minecraftVersion)){
return this._constructJVMArguments113(mods, tempNativePath) return this._constructJVMArguments113(mods, tempNativePath)
} else { } else {
return this._constructJVMArguments112(mods, tempNativePath) return this._constructJVMArguments112(mods, tempNativePath)
@ -354,9 +350,9 @@ class ProcessBuilder {
args.push('-Xdock:name=HeliosLauncher') args.push('-Xdock:name=HeliosLauncher')
args.push('-Xdock:icon=' + path.join(__dirname, '..', 'images', 'minecraft.icns')) args.push('-Xdock:icon=' + path.join(__dirname, '..', 'images', 'minecraft.icns'))
} }
args.push('-Xmx' + ConfigManager.getMaxRAM(this.server.getID())) args.push('-Xmx' + ConfigManager.getMaxRAM(this.server.rawServer.id))
args.push('-Xms' + ConfigManager.getMinRAM(this.server.getID())) args.push('-Xms' + ConfigManager.getMinRAM(this.server.rawServer.id))
args = args.concat(ConfigManager.getJVMOptions(this.server.getID())) args = args.concat(ConfigManager.getJVMOptions(this.server.rawServer.id))
args.push('-Djava.library.path=' + tempNativePath) args.push('-Djava.library.path=' + tempNativePath)
// Main Java Class // Main Java Class
@ -405,9 +401,9 @@ class ProcessBuilder {
args.push('-Xdock:name=HeliosLauncher') args.push('-Xdock:name=HeliosLauncher')
args.push('-Xdock:icon=' + path.join(__dirname, '..', 'images', 'minecraft.icns')) args.push('-Xdock:icon=' + path.join(__dirname, '..', 'images', 'minecraft.icns'))
} }
args.push('-Xmx' + ConfigManager.getMaxRAM(this.server.getID())) args.push('-Xmx' + ConfigManager.getMaxRAM(this.server.rawServer.id))
args.push('-Xms' + ConfigManager.getMinRAM(this.server.getID())) args.push('-Xms' + ConfigManager.getMinRAM(this.server.rawServer.id))
args = args.concat(ConfigManager.getJVMOptions(this.server.getID())) args = args.concat(ConfigManager.getJVMOptions(this.server.rawServer.id))
// Main Java Class // Main Java Class
args.push(this.forgeData.mainClass) args.push(this.forgeData.mainClass)
@ -421,7 +417,7 @@ class ProcessBuilder {
let checksum = 0 let checksum = 0
for(let rule of args[i].rules){ for(let rule of args[i].rules){
if(rule.os != null){ if(rule.os != null){
if(rule.os.name === Library.mojangFriendlyOS() if(rule.os.name === getMojangOS()
&& (rule.os.version == null || new RegExp(rule.os.version).test(os.release))){ && (rule.os.version == null || new RegExp(rule.os.version).test(os.release))){
if(rule.action === 'allow'){ if(rule.action === 'allow'){
checksum++ checksum++
@ -471,7 +467,7 @@ class ProcessBuilder {
break break
case 'version_name': case 'version_name':
//val = versionData.id //val = versionData.id
val = this.server.getID() val = this.server.rawServer.id
break break
case 'game_directory': case 'game_directory':
val = this.gameDir val = this.gameDir
@ -523,7 +519,7 @@ class ProcessBuilder {
// Autoconnect // Autoconnect
let isAutoconnectBroken let isAutoconnectBroken
try { try {
isAutoconnectBroken = Util.isAutoconnectBroken(this.forgeData.id.split('-')[2]) isAutoconnectBroken = ProcessBuilder.isAutoconnectBroken(this.forgeData.id.split('-')[2])
} catch(err) { } catch(err) {
logger.error(err) logger.error(err)
logger.error('Forge version format changed.. assuming autoconnect works.') logger.error('Forge version format changed.. assuming autoconnect works.')
@ -569,7 +565,7 @@ class ProcessBuilder {
break break
case 'version_name': case 'version_name':
//val = versionData.id //val = versionData.id
val = this.server.getID() val = this.server.rawServer.id
break break
case 'game_directory': case 'game_directory':
val = this.gameDir val = this.gameDir
@ -668,7 +664,7 @@ class ProcessBuilder {
classpathArg(mods, tempNativePath){ classpathArg(mods, tempNativePath){
let cpArgs = [] let cpArgs = []
if(!Util.mcVersionAtLeast('1.17', this.server.getMinecraftVersion())) { if(!mcVersionAtLeast('1.17', this.server.rawServer.minecraftVersion)) {
// Add the version.jar to the classpath. // Add the version.jar to the classpath.
// Must not be added to the classpath for Forge 1.17+. // Must not be added to the classpath for Forge 1.17+.
const version = this.versionData.id const version = this.versionData.id
@ -714,13 +710,13 @@ class ProcessBuilder {
fs.ensureDirSync(tempNativePath) fs.ensureDirSync(tempNativePath)
for(let i=0; i<libArr.length; i++){ for(let i=0; i<libArr.length; i++){
const lib = libArr[i] const lib = libArr[i]
if(Library.validateRules(lib.rules, lib.natives)){ if(isLibraryCompatible(lib.rules, lib.natives)){
// Pre-1.19 has a natives object. // Pre-1.19 has a natives object.
if(lib.natives != null) { if(lib.natives != null) {
// Extract the native library. // Extract the native library.
const exclusionArr = lib.extract != null ? lib.extract.exclude : ['META-INF/'] const exclusionArr = lib.extract != null ? lib.extract.exclude : ['META-INF/']
const artifact = lib.downloads.classifiers[lib.natives[Library.mojangFriendlyOS()].replace('${arch}', process.arch.replace('x', ''))] const artifact = lib.downloads.classifiers[lib.natives[getMojangOS()].replace('${arch}', process.arch.replace('x', ''))]
// Location of native zip. // Location of native zip.
const to = path.join(this.libPath, artifact.path) const to = path.join(this.libPath, artifact.path)
@ -826,15 +822,15 @@ class ProcessBuilder {
* @returns {{[id: string]: string}} An object containing the paths of each library this server requires. * @returns {{[id: string]: string}} An object containing the paths of each library this server requires.
*/ */
_resolveServerLibraries(mods){ _resolveServerLibraries(mods){
const mdls = this.server.getModules() const mdls = this.server.modules
let libs = {} let libs = {}
// Locate Forge/Libraries // Locate Forge/Libraries
for(let mdl of mdls){ for(let mdl of mdls){
const type = mdl.getType() const type = mdl.rawModule.type
if(type === DistroManager.Types.ForgeHosted || type === DistroManager.Types.Library){ if(type === Type.ForgeHosted || type === Type.Library){
libs[mdl.getVersionlessID()] = mdl.getArtifact().getPath() libs[mdl.getVersionlessMavenIdentifier()] = mdl.getPath()
if(mdl.hasSubModules()){ if(mdl.subModules.length > 0){
const res = this._resolveModuleLibraries(mdl) const res = this._resolveModuleLibraries(mdl)
if(res.length > 0){ if(res.length > 0){
libs = {...libs, ...res} libs = {...libs, ...res}
@ -863,20 +859,20 @@ class ProcessBuilder {
* @returns {Array.<string>} An array containing the paths of each library this module requires. * @returns {Array.<string>} An array containing the paths of each library this module requires.
*/ */
_resolveModuleLibraries(mdl){ _resolveModuleLibraries(mdl){
if(!mdl.hasSubModules()){ if(!mdl.subModules.length > 0){
return [] return []
} }
let libs = [] let libs = []
for(let sm of mdl.getSubModules()){ for(let sm of mdl.subModules){
if(sm.getType() === DistroManager.Types.Library){ if(sm.rawModule.type === Type.Library){
if(sm.getClasspath()) { if(sm.rawModule.classpath ?? true) {
libs.push(sm.getArtifact().getPath()) libs.push(sm.getPath())
} }
} }
// If this module has submodules, we need to resolve the libraries for those. // If this module has submodules, we need to resolve the libraries for those.
// To avoid unnecessary recursive calls, base case is checked here. // To avoid unnecessary recursive calls, base case is checked here.
if(mdl.hasSubModules()){ if(mdl.subModules.length > 0){
const res = this._resolveModuleLibraries(sm) const res = this._resolveModuleLibraries(sm)
if(res.length > 0){ if(res.length > 0){
libs = libs.concat(res) libs = libs.concat(res)
@ -886,6 +882,24 @@ class ProcessBuilder {
return libs return libs
} }
static isAutoconnectBroken(forgeVersion) {
const minWorking = [31, 2, 15]
const verSplit = forgeVersion.split('.').map(v => Number(v))
if(verSplit[0] === 31) {
for(let i=0; i<minWorking.length; i++) {
if(verSplit[i] > minWorking[i]) {
return false
} else if(verSplit[i] < minWorking[i]) {
return true
}
}
}
return false
}
} }
module.exports = ProcessBuilder module.exports = ProcessBuilder

View File

@ -5,14 +5,33 @@
const cp = require('child_process') const cp = require('child_process')
const crypto = require('crypto') const crypto = require('crypto')
const { URL } = require('url') const { URL } = require('url')
const { MojangRestAPI, getServerStatus } = require('helios-core/mojang') const {
MojangRestAPI,
getServerStatus
} = require('helios-core/mojang')
const {
RestResponseStatus,
isDisplayableError,
validateLocalFile
} = require('helios-core/common')
const {
FullRepair,
DistributionIndexProcessor,
MojangIndexProcessor,
downloadFile
} = require('helios-core/dl')
const {
validateSelectedJvm,
ensureJavaDirIsRoot,
javaExecFromRoot,
discoverBestJvmInstallation,
latestOpenJDK,
extractJdk
} = require('helios-core/java')
// Internal Requirements // Internal Requirements
const DiscordWrapper = require('./assets/js/discordwrapper') const DiscordWrapper = require('./assets/js/discordwrapper')
const ProcessBuilder = require('./assets/js/processbuilder') const ProcessBuilder = require('./assets/js/processbuilder')
const { Util } = require('./assets/js/assetguard')
const { RestResponseStatus, isDisplayableError } = require('helios-core/common')
const { stdout } = require('process')
// Launch Elements // Launch Elements
const launch_content = document.getElementById('launch_content') const launch_content = document.getElementById('launch_content')
@ -54,26 +73,22 @@ function setLaunchDetails(details){
/** /**
* Set the value of the loading progress bar and display that value. * Set the value of the loading progress bar and display that value.
* *
* @param {number} value The progress value. * @param {number} percent Percentage (0-100)
* @param {number} max The total size.
* @param {number|string} percent Optional. The percentage to display on the progress label.
*/ */
function setLaunchPercentage(value, max, percent = ((value/max)*100)){ function setLaunchPercentage(percent){
launch_progress.setAttribute('max', max) launch_progress.setAttribute('max', 100)
launch_progress.setAttribute('value', value) launch_progress.setAttribute('value', percent)
launch_progress_label.innerHTML = percent + '%' launch_progress_label.innerHTML = percent + '%'
} }
/** /**
* Set the value of the OS progress bar and display that on the UI. * Set the value of the OS progress bar and display that on the UI.
* *
* @param {number} value The progress value. * @param {number} percent Percentage (0-100)
* @param {number} max The total download size.
* @param {number|string} percent Optional. The percentage to display on the progress label.
*/ */
function setDownloadPercentage(value, max, percent = ((value/max)*100)){ function setDownloadPercentage(percent){
remote.getCurrentWindow().setProgressBar(value/max) remote.getCurrentWindow().setProgressBar(percent/100)
setLaunchPercentage(value, max, percent) setLaunchPercentage(percent)
} }
/** /**
@ -86,39 +101,43 @@ function setLaunchEnabled(val){
} }
// Bind launch button // Bind launch button
document.getElementById('launch_button').addEventListener('click', function(e){ document.getElementById('launch_button').addEventListener('click', async e => {
loggerLanding.info('Launching game..') loggerLanding.info('Launching game..')
const mcVersion = DistroManager.getDistribution().getServer(ConfigManager.getSelectedServer()).getMinecraftVersion() try {
const server = (await DistroAPI.getDistribution()).getServerById(ConfigManager.getSelectedServer())
const jExe = ConfigManager.getJavaExecutable(ConfigManager.getSelectedServer()) const jExe = ConfigManager.getJavaExecutable(ConfigManager.getSelectedServer())
if(jExe == null){ if(jExe == null){
asyncSystemScan(mcVersion) await asyncSystemScan(server.effectiveJavaOptions)
} else { } else {
setLaunchDetails(Lang.queryJS('landing.launch.pleaseWait')) setLaunchDetails(Lang.queryJS('landing.launch.pleaseWait'))
toggleLaunchArea(true) toggleLaunchArea(true)
setLaunchPercentage(0, 100) setLaunchPercentage(0, 100)
const jg = new JavaGuard(mcVersion) const details = await validateSelectedJvm(ensureJavaDirIsRoot(jExe), server.effectiveJavaOptions.supported)
jg._validateJavaBinary(jExe).then((v) => { if(details != null){
loggerLanding.info('Java version meta', v) loggerLanding.info('Jvm Details', details)
if(v.valid){ await dlAsync()
dlAsync()
} else { } else {
asyncSystemScan(mcVersion) await asyncSystemScan(server.effectiveJavaOptions)
} }
}) }
} catch(err) {
loggerLanding.error('Unhandled error in during launch process.', err)
showLaunchFailure('Error During Launch', 'See console (CTRL + Shift + i) for more details.')
} }
}) })
// Bind settings button // Bind settings button
document.getElementById('settingsMediaButton').onclick = (e) => { document.getElementById('settingsMediaButton').onclick = async e => {
prepareSettings() await prepareSettings()
switchView(getCurrentView(), VIEWS.settings) switchView(getCurrentView(), VIEWS.settings)
} }
// Bind avatar overlay button. // Bind avatar overlay button.
document.getElementById('avatarOverlay').onclick = (e) => { document.getElementById('avatarOverlay').onclick = async e => {
prepareSettings() await prepareSettings()
switchView(getCurrentView(), VIEWS.settings, 500, 500, () => { switchView(getCurrentView(), VIEWS.settings, 500, 500, () => {
settingsNavItemListener(document.getElementById('settingsNavAccount'), false) settingsNavItemListener(document.getElementById('settingsNavAccount'), false)
}) })
@ -144,9 +163,9 @@ function updateSelectedServer(serv){
if(getCurrentView() === VIEWS.settings){ if(getCurrentView() === VIEWS.settings){
fullSettingsSave() fullSettingsSave()
} }
ConfigManager.setSelectedServer(serv != null ? serv.getID() : null) ConfigManager.setSelectedServer(serv != null ? serv.rawServer.id : null)
ConfigManager.save() ConfigManager.save()
server_selection_button.innerHTML = '\u2022 ' + (serv != null ? serv.getName() : 'No Server Selected') server_selection_button.innerHTML = '\u2022 ' + (serv != null ? serv.rawServer.name : 'No Server Selected')
if(getCurrentView() === VIEWS.settings){ if(getCurrentView() === VIEWS.settings){
animateSettingsTabRefresh() animateSettingsTabRefresh()
} }
@ -154,9 +173,9 @@ function updateSelectedServer(serv){
} }
// Real text is set in uibinder.js on distributionIndexDone. // Real text is set in uibinder.js on distributionIndexDone.
server_selection_button.innerHTML = '\u2022 Loading..' server_selection_button.innerHTML = '\u2022 Loading..'
server_selection_button.onclick = (e) => { server_selection_button.onclick = async e => {
e.target.blur() e.target.blur()
toggleServerSelection(true) await toggleServerSelection(true)
} }
// Update Mojang Status Color // Update Mojang Status Color
@ -220,17 +239,16 @@ const refreshMojangStatuses = async function(){
document.getElementById('mojang_status_icon').style.color = MojangRestAPI.statusToHex(status) document.getElementById('mojang_status_icon').style.color = MojangRestAPI.statusToHex(status)
} }
const refreshServerStatus = async function(fade = false){ const refreshServerStatus = async (fade = false) => {
loggerLanding.info('Refreshing Server Status') loggerLanding.info('Refreshing Server Status')
const serv = DistroManager.getDistribution().getServer(ConfigManager.getSelectedServer()) const serv = (await DistroAPI.getDistribution()).getServerById(ConfigManager.getSelectedServer())
let pLabel = 'SERVER' let pLabel = 'SERVER'
let pVal = 'OFFLINE' let pVal = 'OFFLINE'
try { try {
const serverURL = new URL('my://' + serv.getAddress())
const servStat = await getServerStatus(47, serverURL.hostname, Number(serverURL.port)) const servStat = await getServerStatus(47, serv.hostname, serv.port)
console.log(servStat) console.log(servStat)
pLabel = 'PLAYERS' pLabel = 'PLAYERS'
pVal = servStat.players.online + '/' + servStat.players.max pVal = servStat.players.online + '/' + servStat.players.max
@ -279,71 +297,48 @@ function showLaunchFailure(title, desc){
/* System (Java) Scan */ /* System (Java) Scan */
let sysAEx
let scanAt
let extractListener
/** /**
* Asynchronously scan the system for valid Java installations. * Asynchronously scan the system for valid Java installations.
* *
* @param {string} mcVersion The Minecraft version we are scanning for.
* @param {boolean} launchAfter Whether we should begin to launch after scanning. * @param {boolean} launchAfter Whether we should begin to launch after scanning.
*/ */
function asyncSystemScan(mcVersion, launchAfter = true){ async function asyncSystemScan(effectiveJavaOptions, launchAfter = true){
setLaunchDetails('Please wait..') setLaunchDetails('Checking system info..')
toggleLaunchArea(true) toggleLaunchArea(true)
setLaunchPercentage(0, 100) setLaunchPercentage(0, 100)
const forkEnv = JSON.parse(JSON.stringify(process.env)) const jvmDetails = await discoverBestJvmInstallation(
forkEnv.CONFIG_DIRECT_PATH = ConfigManager.getLauncherDirectory() ConfigManager.getDataDirectory(),
effectiveJavaOptions.supported
)
// Fork a process to run validations. if(jvmDetails == null) {
sysAEx = cp.fork(path.join(__dirname, 'assets', 'js', 'assetexec.js'), [
'JavaGuard',
mcVersion
], {
env: forkEnv,
stdio: 'pipe'
})
// Stdout
sysAEx.stdio[1].setEncoding('utf8')
sysAEx.stdio[1].on('data', (data) => {
console.log(`\x1b[32m[SysAEx]\x1b[0m ${data}`)
})
// Stderr
sysAEx.stdio[2].setEncoding('utf8')
sysAEx.stdio[2].on('data', (data) => {
console.log(`\x1b[31m[SysAEx]\x1b[0m ${data}`)
})
const javaVer = Util.mcVersionAtLeast('1.17', mcVersion) ? '17' : '8'
sysAEx.on('message', (m) => {
if(m.context === 'validateJava'){
if(m.result == null){
// If the result is null, no valid Java installation was found. // If the result is null, no valid Java installation was found.
// Show this information to the user. // Show this information to the user.
setOverlayContent( setOverlayContent(
'No Compatible<br>Java Installation Found', 'No Compatible<br>Java Installation Found',
`In order to join WesterosCraft, you need a 64-bit installation of Java ${javaVer}. Would you like us to install a copy?`, `In order to join WesterosCraft, you need a 64-bit installation of Java ${effectiveJavaOptions.suggestedMajor}. Would you like us to install a copy?`,
'Install Java', 'Install Java',
'Install Manually' 'Install Manually'
) )
setOverlayHandler(() => { setOverlayHandler(() => {
setLaunchDetails('Preparing Java Download..') setLaunchDetails('Preparing Java Download..')
sysAEx.send({task: 'changeContext', class: 'AssetGuard', args: [ConfigManager.getCommonDirectory(),ConfigManager.getJavaExecutable(ConfigManager.getSelectedServer())]})
sysAEx.send({task: 'execute', function: '_enqueueOpenJDK', argsArr: [ConfigManager.getDataDirectory(), mcVersion]})
toggleOverlay(false) toggleOverlay(false)
try {
downloadJava(effectiveJavaOptions, launchAfter)
} catch(err) {
loggerLanding.error('Unhandled error in Java Download', err)
showLaunchFailure('Error During Java Download', 'See console (CTRL + Shift + i) for more details.')
}
}) })
setDismissHandler(() => { setDismissHandler(() => {
$('#overlayContent').fadeOut(250, () => { $('#overlayContent').fadeOut(250, () => {
//$('#overlayDismiss').toggle(false) //$('#overlayDismiss').toggle(false)
setOverlayContent( setOverlayContent(
'Java is Required<br>to Launch', 'Java is Required<br>to Launch',
`A valid x64 installation of Java ${javaVer} is required to launch.<br><br>Please refer to our <a href="https://github.com/dscalzi/HeliosLauncher/wiki/Java-Management#manually-installing-a-valid-version-of-java">Java Management Guide</a> for instructions on how to manually install Java.`, `A valid x64 installation of Java ${effectiveJavaOptions.suggestedMajor} is required to launch.<br><br>Please refer to our <a href="https://github.com/dscalzi/HeliosLauncher/wiki/Java-Management#manually-installing-a-valid-version-of-java">Java Management Guide</a> for instructions on how to manually install Java.`,
'I Understand', 'I Understand',
'Go Back' 'Go Back'
) )
@ -353,75 +348,71 @@ function asyncSystemScan(mcVersion, launchAfter = true){
}) })
setDismissHandler(() => { setDismissHandler(() => {
toggleOverlay(false, true) toggleOverlay(false, true)
asyncSystemScan()
asyncSystemScan(effectiveJavaOptions, launchAfter)
}) })
$('#overlayContent').fadeIn(250) $('#overlayContent').fadeIn(250)
}) })
}) })
toggleOverlay(true, true) toggleOverlay(true, true)
} else { } else {
// Java installation found, use this to launch the game. // Java installation found, use this to launch the game.
ConfigManager.setJavaExecutable(ConfigManager.getSelectedServer(), m.result) const javaExec = javaExecFromRoot(jvmDetails.path)
ConfigManager.setJavaExecutable(ConfigManager.getSelectedServer(), javaExec)
ConfigManager.save() ConfigManager.save()
// We need to make sure that the updated value is on the settings UI. // We need to make sure that the updated value is on the settings UI.
// Just incase the settings UI is already open. // Just incase the settings UI is already open.
settingsJavaExecVal.value = m.result settingsJavaExecVal.value = javaExec
populateJavaExecDetails(settingsJavaExecVal.value) await populateJavaExecDetails(settingsJavaExecVal.value)
// TODO Callback hell, refactor
// TODO Move this out, separate concerns.
if(launchAfter){ if(launchAfter){
dlAsync() await dlAsync()
} }
sysAEx.disconnect()
} }
} else if(m.context === '_enqueueOpenJDK'){
if(m.result === true){ }
// Oracle JRE enqueued successfully, begin download. async function downloadJava(effectiveJavaOptions, launchAfter = true) {
setLaunchDetails('Downloading Java..')
sysAEx.send({task: 'execute', function: 'processDlQueues', argsArr: [[{id:'java', limit:1}]]})
} else { // TODO Error handling.
// asset can be null.
const asset = await latestOpenJDK(
effectiveJavaOptions.suggestedMajor,
ConfigManager.getDataDirectory(),
effectiveJavaOptions.distribution)
// Oracle JRE enqueue failed. Probably due to a change in their website format. if(asset == null) {
// User will have to follow the guide to install Java. throw new Error('Failed to find OpenJDK distribution.')
setOverlayContent( }
'Unexpected Issue:<br>Java Download Failed',
'Unfortunately we\'ve encountered an issue while attempting to install Java. You will need to manually install a copy. Please check out our <a href="https://github.com/dscalzi/HeliosLauncher/wiki">Troubleshooting Guide</a> for more details and instructions.', let received = 0
'I Understand' await downloadFile(asset.url, asset.path, ({ transferred }) => {
) received = transferred
setOverlayHandler(() => { setDownloadPercentage(Math.trunc((transferred/asset.size)*100))
toggleOverlay(false)
toggleLaunchArea(false)
}) })
toggleOverlay(true) setDownloadPercentage(100)
sysAEx.disconnect()
if(received != asset.size) {
loggerLanding.warn(`Java Download: Expected ${asset.size} bytes but received ${received}`)
if(!await validateLocalFile(asset.path, asset.algo, asset.hash)) {
log.error(`Hashes do not match, ${asset.id} may be corrupted.`)
// Don't know how this could happen, but report it.
throw new Error('Downloaded JDK has bad hash, file may be corrupted.')
}
} }
} else if(m.context === 'progress'){ // Extract
switch(m.data){
case 'download':
// Downloading..
setDownloadPercentage(m.value, m.total, m.percent)
break
}
} else if(m.context === 'complete'){
switch(m.data){
case 'download': {
// Show installing progress bar. // Show installing progress bar.
remote.getCurrentWindow().setProgressBar(2) remote.getCurrentWindow().setProgressBar(2)
// Wait for extration to complete. // Wait for extration to complete.
const eLStr = 'Extracting' const eLStr = 'Extracting Java'
let dotStr = '' let dotStr = ''
setLaunchDetails(eLStr) setLaunchDetails(eLStr)
extractListener = setInterval(() => { const extractListener = setInterval(() => {
if(dotStr.length >= 3){ if(dotStr.length >= 3){
dotStr = '' dotStr = ''
} else { } else {
@ -429,39 +420,22 @@ function asyncSystemScan(mcVersion, launchAfter = true){
} }
setLaunchDetails(eLStr + dotStr) setLaunchDetails(eLStr + dotStr)
}, 750) }, 750)
break
} const newJavaExec = await extractJdk(asset.path)
case 'java':
// Download & extraction complete, remove the loading from the OS progress bar. // Extraction complete, remove the loading from the OS progress bar.
remote.getCurrentWindow().setProgressBar(-1) remote.getCurrentWindow().setProgressBar(-1)
// Extraction completed successfully. // Extraction completed successfully.
ConfigManager.setJavaExecutable(ConfigManager.getSelectedServer(), m.args[0]) ConfigManager.setJavaExecutable(ConfigManager.getSelectedServer(), newJavaExec)
ConfigManager.save() ConfigManager.save()
if(extractListener != null){
clearInterval(extractListener) clearInterval(extractListener)
extractListener = null
}
setLaunchDetails('Java Installed!') setLaunchDetails('Java Installed!')
if(launchAfter){ // TODO Callback hell
dlAsync() // Refactor the launch functions
} asyncSystemScan(effectiveJavaOptions, launchAfter)
sysAEx.disconnect()
break
}
} else if(m.context === 'error'){
console.log(m.error)
}
})
// Begin system Java scan.
setLaunchDetails('Checking system info..')
sysAEx.send({task: 'execute', function: 'validateJava', argsArr: [ConfigManager.getDataDirectory()]})
} }
@ -475,18 +449,28 @@ const GAME_JOINED_REGEX = /\[.+\]: Sound engine started/
const GAME_LAUNCH_REGEX = /^\[.+\]: (?:MinecraftForge .+ Initialized|ModLauncher .+ starting: .+)$/ const GAME_LAUNCH_REGEX = /^\[.+\]: (?:MinecraftForge .+ Initialized|ModLauncher .+ starting: .+)$/
const MIN_LINGER = 5000 const MIN_LINGER = 5000
let aEx async function dlAsync(login = true) {
let serv
let versionData
let forgeData
let progressListener
function dlAsync(login = true){
// Login parameter is temporary for debug purposes. Allows testing the validation/downloads without // Login parameter is temporary for debug purposes. Allows testing the validation/downloads without
// launching the game. // launching the game.
const loggerLaunchSuite = LoggerUtil.getLogger('LaunchSuite')
setLaunchDetails('Loading server information..')
let distro
try {
distro = await DistroAPI.refreshDistributionOrFallback()
onDistroRefresh(distro)
} catch(err) {
loggerLaunchSuite.error('Unable to refresh distribution index.', err)
showLaunchFailure('Fatal Error', 'Could not load a copy of the distribution index. See the console (CTRL + Shift + i) for more details.')
return
}
const serv = distro.getServerById(ConfigManager.getSelectedServer())
if(login) { if(login) {
if(ConfigManager.getSelectedAccount() == null){ if(ConfigManager.getSelectedAccount() == null){
loggerLanding.error('You must be logged into an account.') loggerLanding.error('You must be logged into an account.')
@ -498,155 +482,80 @@ function dlAsync(login = true){
toggleLaunchArea(true) toggleLaunchArea(true)
setLaunchPercentage(0, 100) setLaunchPercentage(0, 100)
const loggerLaunchSuite = LoggerUtil.getLogger('LaunchSuite') const fullRepairModule = new FullRepair(
const forkEnv = JSON.parse(JSON.stringify(process.env))
forkEnv.CONFIG_DIRECT_PATH = ConfigManager.getLauncherDirectory()
// Start AssetExec to run validations and downloads in a forked process.
aEx = cp.fork(path.join(__dirname, 'assets', 'js', 'assetexec.js'), [
'AssetGuard',
ConfigManager.getCommonDirectory(), ConfigManager.getCommonDirectory(),
ConfigManager.getJavaExecutable(ConfigManager.getSelectedServer()) ConfigManager.getInstanceDirectory(),
], { ConfigManager.getLauncherDirectory(),
env: forkEnv, ConfigManager.getSelectedServer(),
stdio: 'pipe' DistroAPI.isDevMode()
}) )
// Stdout
aEx.stdio[1].setEncoding('utf8') fullRepairModule.spawnReceiver()
aEx.stdio[1].on('data', (data) => {
console.log(`\x1b[32m[AEx]\x1b[0m ${data}`) fullRepairModule.childProcess.on('error', (err) => {
})
// Stderr
aEx.stdio[2].setEncoding('utf8')
aEx.stdio[2].on('data', (data) => {
console.log(`\x1b[31m[AEx]\x1b[0m ${data}`)
})
aEx.on('error', (err) => {
loggerLaunchSuite.error('Error during launch', err) loggerLaunchSuite.error('Error during launch', err)
showLaunchFailure('Error During Launch', err.message || 'See console (CTRL + Shift + i) for more details.') showLaunchFailure('Error During Launch', err.message || 'See console (CTRL + Shift + i) for more details.')
}) })
aEx.on('close', (code, signal) => { fullRepairModule.childProcess.on('close', (code, _signal) => {
if(code !== 0){ if(code !== 0){
loggerLaunchSuite.error(`AssetExec exited with code ${code}, assuming error.`) loggerLaunchSuite.error(`Full Repair Module exited with code ${code}, assuming error.`)
showLaunchFailure('Error During Launch', 'See console (CTRL + Shift + i) for more details.') showLaunchFailure('Error During Launch', 'See console (CTRL + Shift + i) for more details.')
} }
}) })
// Establish communications between the AssetExec and current process. loggerLaunchSuite.info('Validating files.')
aEx.on('message', (m) => { setLaunchDetails('Validating file integrity..')
let invalidFileCount = 0
try {
invalidFileCount = await fullRepairModule.verifyFiles(percent => {
setLaunchPercentage(percent)
})
setLaunchPercentage(100)
} catch (err) {
loggerLaunchSuite.error('Error during file validation.')
showLaunchFailure('Error During File Verification', err.displayable || 'See console (CTRL + Shift + i) for more details.')
return
}
if(m.context === 'validate'){
switch(m.data){ if(invalidFileCount > 0) {
case 'distribution': loggerLaunchSuite.info('Downloading files.')
setLaunchPercentage(20, 100)
loggerLaunchSuite.info('Validated distibution index.')
setLaunchDetails('Loading version information..')
break
case 'version':
setLaunchPercentage(40, 100)
loggerLaunchSuite.info('Version data loaded.')
setLaunchDetails('Validating asset integrity..')
break
case 'assets':
setLaunchPercentage(60, 100)
loggerLaunchSuite.info('Asset Validation Complete')
setLaunchDetails('Validating library integrity..')
break
case 'libraries':
setLaunchPercentage(80, 100)
loggerLaunchSuite.info('Library validation complete.')
setLaunchDetails('Validating miscellaneous file integrity..')
break
case 'files':
setLaunchPercentage(100, 100)
loggerLaunchSuite.info('File validation complete.')
setLaunchDetails('Downloading files..') setLaunchDetails('Downloading files..')
break setLaunchPercentage(0)
try {
await fullRepairModule.download(percent => {
setDownloadPercentage(percent)
})
setDownloadPercentage(100)
} catch(err) {
loggerLaunchSuite.error('Error during file download.')
showLaunchFailure('Error During File Download', err.displayable || 'See console (CTRL + Shift + i) for more details.')
return
} }
} else if(m.context === 'progress'){
switch(m.data){
case 'assets': {
const perc = (m.value/m.total)*20
setLaunchPercentage(40+perc, 100, parseInt(40+perc))
break
}
case 'download':
setDownloadPercentage(m.value, m.total, m.percent)
break
case 'extract': {
// Show installing progress bar.
remote.getCurrentWindow().setProgressBar(2)
// Download done, extracting.
const eLStr = 'Extracting libraries'
let dotStr = ''
setLaunchDetails(eLStr)
progressListener = setInterval(() => {
if(dotStr.length >= 3){
dotStr = ''
} else { } else {
dotStr += '.' loggerLaunchSuite.info('No invalid files, skipping download.')
} }
setLaunchDetails(eLStr + dotStr)
}, 750) // Remove download bar.
break
}
}
} else if(m.context === 'complete'){
switch(m.data){
case 'download':
// Download and extraction complete, remove the loading from the OS progress bar.
remote.getCurrentWindow().setProgressBar(-1) remote.getCurrentWindow().setProgressBar(-1)
if(progressListener != null){
clearInterval(progressListener) fullRepairModule.destroyReceiver()
progressListener = null
}
setLaunchDetails('Preparing to launch..') setLaunchDetails('Preparing to launch..')
break
}
} else if(m.context === 'error'){
switch(m.data){
case 'download':
loggerLaunchSuite.error('Error while downloading:', m.error)
if(m.error.code === 'ENOENT'){ const mojangIndexProcessor = new MojangIndexProcessor(
showLaunchFailure( ConfigManager.getCommonDirectory(),
'Download Error', serv.rawServer.minecraftVersion)
'Could not connect to the file server. Ensure that you are connected to the internet and try again.' const distributionIndexProcessor = new DistributionIndexProcessor(
ConfigManager.getCommonDirectory(),
distro,
serv.rawServer.id
) )
} else {
showLaunchFailure(
'Download Error',
'Check the console (CTRL + Shift + i) for more details. Please try again.'
)
}
remote.getCurrentWindow().setProgressBar(-1) const forgeData = await distributionIndexProcessor.loadForgeVersionJson(serv)
const versionData = await mojangIndexProcessor.getVersionJson()
// Disconnect from AssetExec if(login) {
aEx.disconnect()
break
}
} else if(m.context === 'validateEverything'){
let allGood = true
// If these properties are not defined it's likely an error.
if(m.result.forgeData == null || m.result.versionData == null){
loggerLaunchSuite.error('Error during validation:', m.result)
loggerLaunchSuite.error('Error during launch', m.result.error)
showLaunchFailure('Error During Launch', 'Please check the console (CTRL + Shift + i) for more details.')
allGood = false
}
forgeData = m.result.forgeData
versionData = m.result.versionData
if(login && allGood) {
const authUser = ConfigManager.getSelectedAccount() const authUser = ConfigManager.getSelectedAccount()
loggerLaunchSuite.info(`Sending selected account (${authUser.displayName}) to ProcessBuilder.`) loggerLaunchSuite.info(`Sending selected account (${authUser.displayName}) to ProcessBuilder.`)
let pb = new ProcessBuilder(serv, versionData, forgeData, authUser, remote.app.getVersion()) let pb = new ProcessBuilder(serv, versionData, forgeData, authUser, remote.app.getVersion())
@ -659,8 +568,8 @@ function dlAsync(login = true){
toggleLaunchArea(false) toggleLaunchArea(false)
if(hasRPC){ if(hasRPC){
DiscordWrapper.updateDetails('Loading game..') DiscordWrapper.updateDetails('Loading game..')
}
proc.stdout.on('data', gameStateChange) proc.stdout.on('data', gameStateChange)
}
proc.stdout.removeListener('data', tempListener) proc.stdout.removeListener('data', tempListener)
proc.stderr.removeListener('data', gameErrorListener) proc.stderr.removeListener('data', gameErrorListener)
} }
@ -710,9 +619,8 @@ function dlAsync(login = true){
setLaunchDetails('Done. Enjoy the server!') setLaunchDetails('Done. Enjoy the server!')
// Init Discord Hook // Init Discord Hook
const distro = DistroManager.getDistribution() if(distro.rawDistribution.discord != null && serv.rawServerdiscord != null){
if(distro.discord != null && serv.discord != null){ DiscordWrapper.initRPC(distro.rawDistribution.discord, serv.rawServer.discord)
DiscordWrapper.initRPC(distro.discord, serv.discord)
hasRPC = true hasRPC = true
proc.on('close', (code, signal) => { proc.on('close', (code, signal) => {
loggerLaunchSuite.info('Shutting down Discord Rich Presence..') loggerLaunchSuite.info('Shutting down Discord Rich Presence..')
@ -730,40 +638,6 @@ function dlAsync(login = true){
} }
} }
// Disconnect from AssetExec
aEx.disconnect()
}
})
// Begin Validations
// Validate Forge files.
setLaunchDetails('Loading server information..')
refreshDistributionIndex(true, (data) => {
onDistroRefresh(data)
serv = data.getServer(ConfigManager.getSelectedServer())
aEx.send({task: 'execute', function: 'validateEverything', argsArr: [ConfigManager.getSelectedServer(), DistroManager.isDevMode()]})
}, (err) => {
loggerLaunchSuite.info('Error while fetching a fresh copy of the distribution index.', err)
refreshDistributionIndex(false, (data) => {
onDistroRefresh(data)
serv = data.getServer(ConfigManager.getSelectedServer())
aEx.send({task: 'execute', function: 'validateEverything', argsArr: [ConfigManager.getSelectedServer(), DistroManager.isDevMode()]})
}, (err) => {
loggerLaunchSuite.error('Unable to refresh distribution index.', err)
if(DistroManager.getDistribution() == null){
showLaunchFailure('Fatal Error', 'Could not load a copy of the distribution index. See the console (CTRL + Shift + i) for more details.')
// Disconnect from AssetExec
aEx.disconnect()
} else {
serv = data.getServer(ConfigManager.getSelectedServer())
aEx.send({task: 'execute', function: 'validateEverything', argsArr: [ConfigManager.getSelectedServer(), DistroManager.isDevMode()]})
}
})
})
} }
/** /**
@ -943,7 +817,7 @@ function initNews(){
let news = {} let news = {}
loadNews().then(news => { loadNews().then(news => {
newsArr = news.articles || null newsArr = news?.articles || null
if(newsArr == null){ if(newsArr == null){
// News Loading Failed // News Loading Failed
@ -1089,10 +963,17 @@ function displayArticle(articleObject, index){
* Load news information from the RSS feed specified in the * Load news information from the RSS feed specified in the
* distribution index. * distribution index.
*/ */
function loadNews(){ async function loadNews(){
return new Promise((resolve, reject) => {
const distroData = DistroManager.getDistribution() const distroData = await DistroAPI.getDistribution()
const newsFeed = distroData.getRSS() if(!distroData.rawDistribution.rss) {
loggerLanding.debug('No RSS feed provided.')
return null
}
const promise = new Promise((resolve, reject) => {
const newsFeed = distroData.rawDistribution.rss
const newsHost = new URL(newsFeed).origin + '/' const newsHost = new URL(newsFeed).origin + '/'
$.ajax({ $.ajax({
url: newsFeed, url: newsFeed,
@ -1147,4 +1028,6 @@ function loadNews(){
}) })
}) })
}) })
return await promise
} }

View File

@ -193,10 +193,10 @@ loginButton.addEventListener('click', () => {
$('.circle-loader').toggleClass('load-complete') $('.circle-loader').toggleClass('load-complete')
$('.checkmark').toggle() $('.checkmark').toggle()
setTimeout(() => { setTimeout(() => {
switchView(VIEWS.login, loginViewOnSuccess, 500, 500, () => { switchView(VIEWS.login, loginViewOnSuccess, 500, 500, async () => {
// Temporary workaround // Temporary workaround
if(loginViewOnSuccess === VIEWS.settings){ if(loginViewOnSuccess === VIEWS.settings){
prepareSettings() await prepareSettings()
} }
loginViewOnSuccess = VIEWS.landing // Reset this for good measure. loginViewOnSuccess = VIEWS.landing // Reset this for good measure.
loginCancelEnabled(false) // Reset this for good measure. loginCancelEnabled(false) // Reset this for good measure.

View File

@ -117,8 +117,8 @@ function toggleOverlay(toggleState, dismissable = false, content = 'overlayConte
} }
} }
function toggleServerSelection(toggleState){ async function toggleServerSelection(toggleState){
prepareServerSelectionList() await prepareServerSelectionList()
toggleOverlay(toggleState, true, 'serverSelectContent') toggleOverlay(toggleState, true, 'serverSelectContent')
} }
@ -171,11 +171,11 @@ function setDismissHandler(handler){
/* Server Select View */ /* Server Select View */
document.getElementById('serverSelectConfirm').addEventListener('click', () => { document.getElementById('serverSelectConfirm').addEventListener('click', async () => {
const listings = document.getElementsByClassName('serverListing') const listings = document.getElementsByClassName('serverListing')
for(let i=0; i<listings.length; i++){ for(let i=0; i<listings.length; i++){
if(listings[i].hasAttribute('selected')){ if(listings[i].hasAttribute('selected')){
const serv = DistroManager.getDistribution().getServer(listings[i].getAttribute('servid')) const serv = (await DistroAPI.getDistribution()).getServerById(listings[i].getAttribute('servid'))
updateSelectedServer(serv) updateSelectedServer(serv)
refreshServerStatus(true) refreshServerStatus(true)
toggleOverlay(false) toggleOverlay(false)
@ -184,13 +184,13 @@ document.getElementById('serverSelectConfirm').addEventListener('click', () => {
} }
// None are selected? Not possible right? Meh, handle it. // None are selected? Not possible right? Meh, handle it.
if(listings.length > 0){ if(listings.length > 0){
const serv = DistroManager.getDistribution().getServer(listings[i].getAttribute('servid')) const serv = (await DistroAPI.getDistribution()).getServerById(listings[i].getAttribute('servid'))
updateSelectedServer(serv) updateSelectedServer(serv)
toggleOverlay(false) toggleOverlay(false)
} }
}) })
document.getElementById('accountSelectConfirm').addEventListener('click', () => { document.getElementById('accountSelectConfirm').addEventListener('click', async () => {
const listings = document.getElementsByClassName('accountListing') const listings = document.getElementsByClassName('accountListing')
for(let i=0; i<listings.length; i++){ for(let i=0; i<listings.length; i++){
if(listings[i].hasAttribute('selected')){ if(listings[i].hasAttribute('selected')){
@ -198,7 +198,7 @@ document.getElementById('accountSelectConfirm').addEventListener('click', () =>
ConfigManager.save() ConfigManager.save()
updateSelectedAccount(authAcc) updateSelectedAccount(authAcc)
if(getCurrentView() === VIEWS.settings) { if(getCurrentView() === VIEWS.settings) {
prepareSettings() await prepareSettings()
} }
toggleOverlay(false) toggleOverlay(false)
validateSelectedAccount() validateSelectedAccount()
@ -211,7 +211,7 @@ document.getElementById('accountSelectConfirm').addEventListener('click', () =>
ConfigManager.save() ConfigManager.save()
updateSelectedAccount(authAcc) updateSelectedAccount(authAcc)
if(getCurrentView() === VIEWS.settings) { if(getCurrentView() === VIEWS.settings) {
prepareSettings() await prepareSettings()
} }
toggleOverlay(false) toggleOverlay(false)
validateSelectedAccount() validateSelectedAccount()
@ -267,21 +267,21 @@ function setAccountListingHandlers(){
}) })
} }
function populateServerListings(){ async function populateServerListings(){
const distro = DistroManager.getDistribution() const distro = await DistroAPI.getDistribution()
const giaSel = ConfigManager.getSelectedServer() const giaSel = ConfigManager.getSelectedServer()
const servers = distro.getServers() const servers = distro.servers
let htmlString = '' let htmlString = ''
for(const serv of servers){ for(const serv of servers){
htmlString += `<button class="serverListing" servid="${serv.getID()}" ${serv.getID() === giaSel ? 'selected' : ''}> htmlString += `<button class="serverListing" servid="${serv.rawServer.id}" ${serv.rawServer.id === giaSel ? 'selected' : ''}>
<img class="serverListingImg" src="${serv.getIcon()}"/> <img class="serverListingImg" src="${serv.rawServer.icon}"/>
<div class="serverListingDetails"> <div class="serverListingDetails">
<span class="serverListingName">${serv.getName()}</span> <span class="serverListingName">${serv.rawServer.name}</span>
<span class="serverListingDescription">${serv.getDescription()}</span> <span class="serverListingDescription">${serv.rawServer.description}</span>
<div class="serverListingInfo"> <div class="serverListingInfo">
<div class="serverListingVersion">${serv.getMinecraftVersion()}</div> <div class="serverListingVersion">${serv.rawServer.minecraftVersion}</div>
<div class="serverListingRevision">${serv.getVersion()}</div> <div class="serverListingRevision">${serv.rawServer.version}</div>
${serv.isMainServer() ? `<div class="serverListingStarWrapper"> ${serv.rawServer.mainServer ? `<div class="serverListingStarWrapper">
<svg id="Layer_1" viewBox="0 0 107.45 104.74" width="20px" height="20px"> <svg id="Layer_1" viewBox="0 0 107.45 104.74" width="20px" height="20px">
<defs> <defs>
<style>.cls-1{fill:#fff;}.cls-2{fill:none;stroke:#fff;stroke-miterlimit:10;}</style> <style>.cls-1{fill:#fff;}.cls-2{fill:none;stroke:#fff;stroke-miterlimit:10;}</style>
@ -313,8 +313,8 @@ function populateAccountListings(){
} }
function prepareServerSelectionList(){ async function prepareServerSelectionList(){
populateServerListings() await populateServerListings()
setServerListingHandlers() setServerListingHandlers()
} }

View File

@ -2,7 +2,6 @@
const os = require('os') const os = require('os')
const semver = require('semver') const semver = require('semver')
const { JavaGuard } = require('./assets/js/assetguard')
const DropinModUtil = require('./assets/js/dropinmodutil') const DropinModUtil = require('./assets/js/dropinmodutil')
const { MSFT_OPCODE, MSFT_REPLY_TYPE, MSFT_ERROR } = require('./assets/js/ipcconstants') const { MSFT_OPCODE, MSFT_REPLY_TYPE, MSFT_ERROR } = require('./assets/js/ipcconstants')
@ -69,7 +68,7 @@ function bindFileSelectors(){
if(!res.canceled) { if(!res.canceled) {
ele.previousElementSibling.value = res.filePaths[0] ele.previousElementSibling.value = res.filePaths[0]
if(isJavaExecSel) { if(isJavaExecSel) {
populateJavaExecDetails(ele.previousElementSibling.value) await populateJavaExecDetails(ele.previousElementSibling.value)
} }
} }
} }
@ -123,9 +122,10 @@ function initSettingsValidators(){
/** /**
* Load configuration values onto the UI. This is an automated process. * Load configuration values onto the UI. This is an automated process.
*/ */
function initSettingsValues(){ async function initSettingsValues(){
const sEls = document.getElementById('settingsContainer').querySelectorAll('[cValue]') const sEls = document.getElementById('settingsContainer').querySelectorAll('[cValue]')
Array.from(sEls).map((v, index, arr) => {
for(const v of sEls) {
const cVal = v.getAttribute('cValue') const cVal = v.getAttribute('cValue')
const serverDependent = v.hasAttribute('serverDependent') // Means the first argument is the server id. const serverDependent = v.hasAttribute('serverDependent') // Means the first argument is the server id.
const gFn = ConfigManager['get' + cVal] const gFn = ConfigManager['get' + cVal]
@ -139,7 +139,7 @@ function initSettingsValues(){
// Special Conditions // Special Conditions
if(cVal === 'JavaExecutable'){ if(cVal === 'JavaExecutable'){
v.value = gFn.apply(null, gFnOpts) v.value = gFn.apply(null, gFnOpts)
populateJavaExecDetails(v.value) await populateJavaExecDetails(v.value)
} else if (cVal === 'DataDirectory'){ } else if (cVal === 'DataDirectory'){
v.value = gFn.apply(null, gFnOpts) v.value = gFn.apply(null, gFnOpts)
} else if(cVal === 'JVMOptions'){ } else if(cVal === 'JVMOptions'){
@ -156,7 +156,7 @@ function initSettingsValues(){
if(cVal === 'MinRAM' || cVal === 'MaxRAM'){ if(cVal === 'MinRAM' || cVal === 'MaxRAM'){
let val = gFn.apply(null, gFnOpts) let val = gFn.apply(null, gFnOpts)
if(val.endsWith('M')){ if(val.endsWith('M')){
val = Number(val.substring(0, val.length-1))/1000 val = Number(val.substring(0, val.length-1))/1024
} else { } else {
val = Number.parseFloat(val) val = Number.parseFloat(val)
} }
@ -168,8 +168,8 @@ function initSettingsValues(){
} }
} }
} }
}
})
} }
/** /**
@ -416,8 +416,8 @@ ipcRenderer.on(MSFT_OPCODE.REPLY_LOGIN, (_, ...arguments_) => {
const authCode = queryMap.code const authCode = queryMap.code
AuthManager.addMicrosoftAccount(authCode).then(value => { AuthManager.addMicrosoftAccount(authCode).then(value => {
updateSelectedAccount(value) updateSelectedAccount(value)
switchView(getCurrentView(), viewOnClose, 500, 500, () => { switchView(getCurrentView(), viewOnClose, 500, 500, async () => {
prepareSettings() await prepareSettings()
}) })
}) })
.catch((displayableError) => { .catch((displayableError) => {
@ -713,13 +713,13 @@ const settingsModsContainer = document.getElementById('settingsModsContainer')
/** /**
* Resolve and update the mods on the UI. * Resolve and update the mods on the UI.
*/ */
function resolveModsForUI(){ async function resolveModsForUI(){
const serv = ConfigManager.getSelectedServer() const serv = ConfigManager.getSelectedServer()
const distro = DistroManager.getDistribution() const distro = await DistroAPI.getDistribution()
const servConf = ConfigManager.getModConfiguration(serv) const servConf = ConfigManager.getModConfiguration(serv)
const modStr = parseModulesForUI(distro.getServer(serv).getModules(), false, servConf.mods) const modStr = parseModulesForUI(distro.getServerById(serv).modules, false, servConf.mods)
document.getElementById('settingsReqModsContent').innerHTML = modStr.reqMods document.getElementById('settingsReqModsContent').innerHTML = modStr.reqMods
document.getElementById('settingsOptModsContent').innerHTML = modStr.optMods document.getElementById('settingsOptModsContent').innerHTML = modStr.optMods
@ -739,17 +739,17 @@ function parseModulesForUI(mdls, submodules, servConf){
for(const mdl of mdls){ for(const mdl of mdls){
if(mdl.getType() === DistroManager.Types.ForgeMod || mdl.getType() === DistroManager.Types.LiteMod || mdl.getType() === DistroManager.Types.LiteLoader){ if(mdl.rawModule.type === Type.ForgeMod || mdl.rawModule.type === Type.LiteMod || mdl.rawModule.type === Type.LiteLoader){
if(mdl.getRequired().isRequired()){ if(mdl.getRequired().value){
reqMods += `<div id="${mdl.getVersionlessID()}" class="settingsBaseMod settings${submodules ? 'Sub' : ''}Mod" enabled> reqMods += `<div id="${mdl.getVersionlessMavenIdentifier()}" class="settingsBaseMod settings${submodules ? 'Sub' : ''}Mod" enabled>
<div class="settingsModContent"> <div class="settingsModContent">
<div class="settingsModMainWrapper"> <div class="settingsModMainWrapper">
<div class="settingsModStatus"></div> <div class="settingsModStatus"></div>
<div class="settingsModDetails"> <div class="settingsModDetails">
<span class="settingsModName">${mdl.getName()}</span> <span class="settingsModName">${mdl.rawModule.name}</span>
<span class="settingsModVersion">v${mdl.getVersion()}</span> <span class="settingsModVersion">v${mdl.mavenComponents.version}</span>
</div> </div>
</div> </div>
<label class="toggleSwitch" reqmod> <label class="toggleSwitch" reqmod>
@ -757,32 +757,32 @@ function parseModulesForUI(mdls, submodules, servConf){
<span class="toggleSwitchSlider"></span> <span class="toggleSwitchSlider"></span>
</label> </label>
</div> </div>
${mdl.hasSubModules() ? `<div class="settingsSubModContainer"> ${mdl.subModules.length > 0 ? `<div class="settingsSubModContainer">
${Object.values(parseModulesForUI(mdl.getSubModules(), true, servConf[mdl.getVersionlessID()])).join('')} ${Object.values(parseModulesForUI(mdl.subModules, true, servConf[mdl.getVersionlessMavenIdentifier()])).join('')}
</div>` : ''} </div>` : ''}
</div>` </div>`
} else { } else {
const conf = servConf[mdl.getVersionlessID()] const conf = servConf[mdl.getVersionlessMavenIdentifier()]
const val = typeof conf === 'object' ? conf.value : conf const val = typeof conf === 'object' ? conf.value : conf
optMods += `<div id="${mdl.getVersionlessID()}" class="settingsBaseMod settings${submodules ? 'Sub' : ''}Mod" ${val ? 'enabled' : ''}> optMods += `<div id="${mdl.getVersionlessMavenIdentifier()}" class="settingsBaseMod settings${submodules ? 'Sub' : ''}Mod" ${val ? 'enabled' : ''}>
<div class="settingsModContent"> <div class="settingsModContent">
<div class="settingsModMainWrapper"> <div class="settingsModMainWrapper">
<div class="settingsModStatus"></div> <div class="settingsModStatus"></div>
<div class="settingsModDetails"> <div class="settingsModDetails">
<span class="settingsModName">${mdl.getName()}</span> <span class="settingsModName">${mdl.rawModule.name}</span>
<span class="settingsModVersion">v${mdl.getVersion()}</span> <span class="settingsModVersion">v${mdl.mavenComponents.version}</span>
</div> </div>
</div> </div>
<label class="toggleSwitch"> <label class="toggleSwitch">
<input type="checkbox" formod="${mdl.getVersionlessID()}" ${val ? 'checked' : ''}> <input type="checkbox" formod="${mdl.getVersionlessMavenIdentifier()}" ${val ? 'checked' : ''}>
<span class="toggleSwitchSlider"></span> <span class="toggleSwitchSlider"></span>
</label> </label>
</div> </div>
${mdl.hasSubModules() ? `<div class="settingsSubModContainer"> ${mdl.subModules.length > 0 ? `<div class="settingsSubModContainer">
${Object.values(parseModulesForUI(mdl.getSubModules(), true, conf.mods)).join('')} ${Object.values(parseModulesForUI(mdl.subModules, true, conf.mods)).join('')}
</div>` : ''} </div>` : ''}
</div>` </div>`
@ -858,10 +858,10 @@ let CACHE_DROPIN_MODS
* Resolve any located drop-in mods for this server and * Resolve any located drop-in mods for this server and
* populate the results onto the UI. * populate the results onto the UI.
*/ */
function resolveDropinModsForUI(){ async function resolveDropinModsForUI(){
const serv = DistroManager.getDistribution().getServer(ConfigManager.getSelectedServer()) const serv = (await DistroAPI.getDistribution()).getServerById(ConfigManager.getSelectedServer())
CACHE_SETTINGS_MODS_DIR = path.join(ConfigManager.getInstanceDirectory(), serv.getID(), 'mods') CACHE_SETTINGS_MODS_DIR = path.join(ConfigManager.getInstanceDirectory(), serv.rawServer.id, 'mods')
CACHE_DROPIN_MODS = DropinModUtil.scanForDropinMods(CACHE_SETTINGS_MODS_DIR, serv.getMinecraftVersion()) CACHE_DROPIN_MODS = DropinModUtil.scanForDropinMods(CACHE_SETTINGS_MODS_DIR, serv.rawServer.minecraftVersion)
let dropinMods = '' let dropinMods = ''
@ -934,12 +934,12 @@ function bindDropinModFileSystemButton(){
fsBtn.removeAttribute('drag') fsBtn.removeAttribute('drag')
} }
fsBtn.ondrop = e => { fsBtn.ondrop = async e => {
fsBtn.removeAttribute('drag') fsBtn.removeAttribute('drag')
e.preventDefault() e.preventDefault()
DropinModUtil.addDropinMods(e.dataTransfer.files, CACHE_SETTINGS_MODS_DIR) DropinModUtil.addDropinMods(e.dataTransfer.files, CACHE_SETTINGS_MODS_DIR)
reloadDropinMods() await reloadDropinMods()
} }
} }
@ -971,18 +971,18 @@ function saveDropinModConfiguration(){
// Refresh the drop-in mods when F5 is pressed. // Refresh the drop-in mods when F5 is pressed.
// Only active on the mods tab. // Only active on the mods tab.
document.addEventListener('keydown', (e) => { document.addEventListener('keydown', async (e) => {
if(getCurrentView() === VIEWS.settings && selectedSettingsTab === 'settingsTabMods'){ if(getCurrentView() === VIEWS.settings && selectedSettingsTab === 'settingsTabMods'){
if(e.key === 'F5'){ if(e.key === 'F5'){
reloadDropinMods() await reloadDropinMods()
saveShaderpackSettings() saveShaderpackSettings()
resolveShaderpacksForUI() await resolveShaderpacksForUI()
} }
} }
}) })
function reloadDropinMods(){ async function reloadDropinMods(){
resolveDropinModsForUI() await resolveDropinModsForUI()
bindDropinModsRemoveButton() bindDropinModsRemoveButton()
bindDropinModFileSystemButton() bindDropinModFileSystemButton()
bindModsToggleSwitch() bindModsToggleSwitch()
@ -997,9 +997,9 @@ let CACHE_SELECTED_SHADERPACK
/** /**
* Load shaderpack information. * Load shaderpack information.
*/ */
function resolveShaderpacksForUI(){ async function resolveShaderpacksForUI(){
const serv = DistroManager.getDistribution().getServer(ConfigManager.getSelectedServer()) const serv = (await DistroAPI.getDistribution()).getServerById(ConfigManager.getSelectedServer())
CACHE_SETTINGS_INSTANCE_DIR = path.join(ConfigManager.getInstanceDirectory(), serv.getID()) CACHE_SETTINGS_INSTANCE_DIR = path.join(ConfigManager.getInstanceDirectory(), serv.rawServer.id)
CACHE_SHADERPACKS = DropinModUtil.scanForShaderpacks(CACHE_SETTINGS_INSTANCE_DIR) CACHE_SHADERPACKS = DropinModUtil.scanForShaderpacks(CACHE_SETTINGS_INSTANCE_DIR)
CACHE_SELECTED_SHADERPACK = DropinModUtil.getEnabledShaderpack(CACHE_SETTINGS_INSTANCE_DIR) CACHE_SELECTED_SHADERPACK = DropinModUtil.getEnabledShaderpack(CACHE_SETTINGS_INSTANCE_DIR)
@ -1058,13 +1058,13 @@ function bindShaderpackButton() {
spBtn.removeAttribute('drag') spBtn.removeAttribute('drag')
} }
spBtn.ondrop = e => { spBtn.ondrop = async e => {
spBtn.removeAttribute('drag') spBtn.removeAttribute('drag')
e.preventDefault() e.preventDefault()
DropinModUtil.addShaderpacks(e.dataTransfer.files, CACHE_SETTINGS_INSTANCE_DIR) DropinModUtil.addShaderpacks(e.dataTransfer.files, CACHE_SETTINGS_INSTANCE_DIR)
saveShaderpackSettings() saveShaderpackSettings()
resolveShaderpacksForUI() await resolveShaderpacksForUI()
} }
} }
@ -1073,19 +1073,19 @@ function bindShaderpackButton() {
/** /**
* Load the currently selected server information onto the mods tab. * Load the currently selected server information onto the mods tab.
*/ */
function loadSelectedServerOnModsTab(){ async function loadSelectedServerOnModsTab(){
const serv = DistroManager.getDistribution().getServer(ConfigManager.getSelectedServer()) const serv = (await DistroAPI.getDistribution()).getServerById(ConfigManager.getSelectedServer())
for(const el of document.getElementsByClassName('settingsSelServContent')) { for(const el of document.getElementsByClassName('settingsSelServContent')) {
el.innerHTML = ` el.innerHTML = `
<img class="serverListingImg" src="${serv.getIcon()}"/> <img class="serverListingImg" src="${serv.rawServer.icon}"/>
<div class="serverListingDetails"> <div class="serverListingDetails">
<span class="serverListingName">${serv.getName()}</span> <span class="serverListingName">${serv.rawServer.name}</span>
<span class="serverListingDescription">${serv.getDescription()}</span> <span class="serverListingDescription">${serv.rawServer.description}</span>
<div class="serverListingInfo"> <div class="serverListingInfo">
<div class="serverListingVersion">${serv.getMinecraftVersion()}</div> <div class="serverListingVersion">${serv.rawServer.minecraftVersion}</div>
<div class="serverListingRevision">${serv.getVersion()}</div> <div class="serverListingRevision">${serv.rawServer.version}</div>
${serv.isMainServer() ? `<div class="serverListingStarWrapper"> ${serv.rawServer.mainServer ? `<div class="serverListingStarWrapper">
<svg id="Layer_1" viewBox="0 0 107.45 104.74" width="20px" height="20px"> <svg id="Layer_1" viewBox="0 0 107.45 104.74" width="20px" height="20px">
<defs> <defs>
<style>.cls-1{fill:#fff;}.cls-2{fill:none;stroke:#fff;stroke-miterlimit:10;}</style> <style>.cls-1{fill:#fff;}.cls-2{fill:none;stroke:#fff;stroke-miterlimit:10;}</style>
@ -1103,9 +1103,9 @@ function loadSelectedServerOnModsTab(){
// Bind functionality to the server switch button. // Bind functionality to the server switch button.
Array.from(document.getElementsByClassName('settingsSwitchServerButton')).forEach(el => { Array.from(document.getElementsByClassName('settingsSwitchServerButton')).forEach(el => {
el.addEventListener('click', (e) => { el.addEventListener('click', async e => {
e.target.blur() e.target.blur()
toggleServerSelection(true) await toggleServerSelection(true)
}) })
}) })
@ -1123,8 +1123,8 @@ function saveAllModConfigurations(){
* server is changed. * server is changed.
*/ */
function animateSettingsTabRefresh(){ function animateSettingsTabRefresh(){
$(`#${selectedSettingsTab}`).fadeOut(500, () => { $(`#${selectedSettingsTab}`).fadeOut(500, async () => {
prepareSettings() await prepareSettings()
$(`#${selectedSettingsTab}`).fadeIn(500) $(`#${selectedSettingsTab}`).fadeIn(500)
}) })
} }
@ -1132,15 +1132,15 @@ function animateSettingsTabRefresh(){
/** /**
* Prepare the Mods tab for display. * Prepare the Mods tab for display.
*/ */
function prepareModsTab(first){ async function prepareModsTab(first){
resolveModsForUI() await resolveModsForUI()
resolveDropinModsForUI() await resolveDropinModsForUI()
resolveShaderpacksForUI() await resolveShaderpacksForUI()
bindDropinModsRemoveButton() bindDropinModsRemoveButton()
bindDropinModFileSystemButton() bindDropinModFileSystemButton()
bindShaderpackButton() bindShaderpackButton()
bindModsToggleSwitch() bindModsToggleSwitch()
loadSelectedServerOnModsTab() await loadSelectedServerOnModsTab()
} }
/** /**
@ -1158,16 +1158,6 @@ const settingsJavaExecDetails = document.getElementById('settingsJavaExecDetails
const settingsJavaReqDesc = document.getElementById('settingsJavaReqDesc') const settingsJavaReqDesc = document.getElementById('settingsJavaReqDesc')
const settingsJvmOptsLink = document.getElementById('settingsJvmOptsLink') const settingsJvmOptsLink = document.getElementById('settingsJvmOptsLink')
// Store maximum memory values.
const SETTINGS_MAX_MEMORY = ConfigManager.getAbsoluteMaxRAM()
const SETTINGS_MIN_MEMORY = ConfigManager.getAbsoluteMinRAM()
// Set the max and min values for the ranged sliders.
settingsMaxRAMRange.setAttribute('max', SETTINGS_MAX_MEMORY)
settingsMaxRAMRange.setAttribute('min', SETTINGS_MIN_MEMORY)
settingsMinRAMRange.setAttribute('max', SETTINGS_MAX_MEMORY)
settingsMinRAMRange.setAttribute('min', SETTINGS_MIN_MEMORY )
// Bind on change event for min memory container. // Bind on change event for min memory container.
settingsMinRAMRange.onchange = (e) => { settingsMinRAMRange.onchange = (e) => {
@ -1178,7 +1168,7 @@ settingsMinRAMRange.onchange = (e) => {
// Get reference to range bar. // Get reference to range bar.
const bar = e.target.getElementsByClassName('rangeSliderBar')[0] const bar = e.target.getElementsByClassName('rangeSliderBar')[0]
// Calculate effective total memory. // Calculate effective total memory.
const max = (os.totalmem()-1000000000)/1000000000 const max = os.totalmem()/1073741824
// Change range bar color based on the selected value. // Change range bar color based on the selected value.
if(sMinV >= max/2){ if(sMinV >= max/2){
@ -1210,7 +1200,7 @@ settingsMaxRAMRange.onchange = (e) => {
// Get reference to range bar. // Get reference to range bar.
const bar = e.target.getElementsByClassName('rangeSliderBar')[0] const bar = e.target.getElementsByClassName('rangeSliderBar')[0]
// Calculate effective total memory. // Calculate effective total memory.
const max = (os.totalmem()-1000000000)/1000000000 const max = os.totalmem()/1073741824
// Change range bar color based on the selected value. // Change range bar color based on the selected value.
if(sMaxV >= max/2){ if(sMaxV >= max/2){
@ -1338,8 +1328,8 @@ function updateRangedSlider(element, value, notch){
* Display the total and available RAM. * Display the total and available RAM.
*/ */
function populateMemoryStatus(){ function populateMemoryStatus(){
settingsMemoryTotal.innerHTML = Number((os.totalmem()-1000000000)/1000000000).toFixed(1) + 'G' settingsMemoryTotal.innerHTML = Number((os.totalmem()-1073741824)/1073741824).toFixed(1) + 'G'
settingsMemoryAvail.innerHTML = Number(os.freemem()/1000000000).toFixed(1) + 'G' settingsMemoryAvail.innerHTML = Number(os.freemem()/1073741824).toFixed(1) + 'G'
} }
/** /**
@ -1348,50 +1338,61 @@ function populateMemoryStatus(){
* *
* @param {string} execPath The executable path to populate against. * @param {string} execPath The executable path to populate against.
*/ */
function populateJavaExecDetails(execPath){ async function populateJavaExecDetails(execPath){
const jg = new JavaGuard(DistroManager.getDistribution().getServer(ConfigManager.getSelectedServer()).getMinecraftVersion()) const server = (await DistroAPI.getDistribution()).getServerById(ConfigManager.getSelectedServer())
jg._validateJavaBinary(execPath).then(v => {
if(v.valid){ const details = await validateSelectedJvm(ensureJavaDirIsRoot(execPath), server.effectiveJavaOptions.supported)
const vendor = v.vendor != null ? ` (${v.vendor})` : ''
if(v.version.major < 9) { if(details != null) {
settingsJavaExecDetails.innerHTML = `Selected: Java ${v.version.major} Update ${v.version.update} (x${v.arch})${vendor}` settingsJavaExecDetails.innerHTML = `Selected: Java ${details.semverStr} (${details.vendor})`
} else {
settingsJavaExecDetails.innerHTML = `Selected: Java ${v.version.major}.${v.version.minor}.${v.version.revision} (x${v.arch})${vendor}`
}
} else { } else {
settingsJavaExecDetails.innerHTML = 'Invalid Selection' settingsJavaExecDetails.innerHTML = 'Invalid Selection'
} }
})
} }
function populateJavaReqDesc() { function populateJavaReqDesc(server) {
const mcVer = DistroManager.getDistribution().getServer(ConfigManager.getSelectedServer()).getMinecraftVersion() settingsJavaReqDesc.innerHTML = `Requires Java ${server.effectiveJavaOptions.suggestedMajor} x64.`
if(Util.mcVersionAtLeast('1.17', mcVer)) { }
settingsJavaReqDesc.innerHTML = 'Requires Java 17 x64.'
} else { function populateJvmOptsLink(server) {
settingsJavaReqDesc.innerHTML = 'Requires Java 8 x64.' const major = server.effectiveJavaOptions.suggestedMajor
settingsJvmOptsLink.innerHTML = `Available Options for Java ${major} (HotSpot VM)`
if(major >= 12) {
settingsJvmOptsLink.href = `https://docs.oracle.com/en/java/javase/${major}/docs/specs/man/java.html#extra-options-for-java`
}
else if(major >= 11) {
settingsJvmOptsLink.href = 'https://docs.oracle.com/en/java/javase/11/tools/java.html#GUID-3B1CE181-CD30-4178-9602-230B800D4FAE'
}
else if(major >= 9) {
settingsJvmOptsLink.href = `https://docs.oracle.com/javase/${major}/tools/java.htm`
}
else {
settingsJvmOptsLink.href = `https://docs.oracle.com/javase/${major}/docs/technotes/tools/${process.platform === 'win32' ? 'windows' : 'unix'}/java.html`
} }
} }
function populateJvmOptsLink() { function bindMinMaxRam(server) {
const mcVer = DistroManager.getDistribution().getServer(ConfigManager.getSelectedServer()).getMinecraftVersion() // Store maximum memory values.
if(Util.mcVersionAtLeast('1.17', mcVer)) { const SETTINGS_MAX_MEMORY = ConfigManager.getAbsoluteMaxRAM(server.rawServer.javaOptions?.ram)
settingsJvmOptsLink.innerHTML = 'Available Options for Java 17 (HotSpot VM)' const SETTINGS_MIN_MEMORY = ConfigManager.getAbsoluteMinRAM(server.rawServer.javaOptions?.ram)
settingsJvmOptsLink.href = 'https://docs.oracle.com/en/java/javase/17/docs/specs/man/java.html#extra-options-for-java'
} else { // Set the max and min values for the ranged sliders.
settingsJvmOptsLink.innerHTML = 'Available Options for Java 8 (HotSpot VM)' settingsMaxRAMRange.setAttribute('max', SETTINGS_MAX_MEMORY)
settingsJvmOptsLink.href = `https://docs.oracle.com/javase/8/docs/technotes/tools/${process.platform === 'win32' ? 'windows' : 'unix'}/java.html` settingsMaxRAMRange.setAttribute('min', SETTINGS_MIN_MEMORY)
} settingsMinRAMRange.setAttribute('max', SETTINGS_MAX_MEMORY)
settingsMinRAMRange.setAttribute('min', SETTINGS_MIN_MEMORY)
} }
/** /**
* Prepare the Java tab for display. * Prepare the Java tab for display.
*/ */
function prepareJavaTab(){ async function prepareJavaTab(){
bindRangeSlider() const server = (await DistroAPI.getDistribution()).getServerById(ConfigManager.getSelectedServer())
bindMinMaxRam(server)
bindRangeSlider(server)
populateMemoryStatus() populateMemoryStatus()
populateJavaReqDesc() populateJavaReqDesc(server)
populateJvmOptsLink() populateJvmOptsLink(server)
} }
/** /**
@ -1567,17 +1568,17 @@ function prepareUpdateTab(data = null){
* *
* @param {boolean} first Whether or not it is the first load. * @param {boolean} first Whether or not it is the first load.
*/ */
function prepareSettings(first = false) { async function prepareSettings(first = false) {
if(first){ if(first){
setupSettingsTabs() setupSettingsTabs()
initSettingsValidators() initSettingsValidators()
prepareUpdateTab() prepareUpdateTab()
} else { } else {
prepareModsTab() await prepareModsTab()
} }
initSettingsValues() await initSettingsValues()
prepareAccountsTab() prepareAccountsTab()
prepareJavaTab() await prepareJavaTab()
prepareAboutTab() prepareAboutTab()
} }

View File

@ -4,10 +4,11 @@
*/ */
// Requirements // Requirements
const path = require('path') const path = require('path')
const { Type } = require('helios-distribution-types')
const AuthManager = require('./assets/js/authmanager') const AuthManager = require('./assets/js/authmanager')
const ConfigManager = require('./assets/js/configmanager') const ConfigManager = require('./assets/js/configmanager')
const DistroManager = require('./assets/js/distromanager') const { DistroAPI } = require('./assets/js/distromanager')
const Lang = require('./assets/js/langloader') const Lang = require('./assets/js/langloader')
let rscShouldLoad = false let rscShouldLoad = false
@ -40,10 +41,10 @@ let currentView
*/ */
function switchView(current, next, currentFadeTime = 500, nextFadeTime = 500, onCurrentFade = () => {}, onNextFade = () => {}){ function switchView(current, next, currentFadeTime = 500, nextFadeTime = 500, onCurrentFade = () => {}, onNextFade = () => {}){
currentView = next currentView = next
$(`${current}`).fadeOut(currentFadeTime, () => { $(`${current}`).fadeOut(currentFadeTime, async () => {
onCurrentFade() await onCurrentFade()
$(`${next}`).fadeIn(nextFadeTime, () => { $(`${next}`).fadeIn(nextFadeTime, async () => {
onNextFade() await onNextFade()
}) })
}) })
} }
@ -57,15 +58,15 @@ function getCurrentView(){
return currentView return currentView
} }
function showMainUI(data){ async function showMainUI(data){
if(!isDev){ if(!isDev){
loggerAutoUpdater.info('Initializing..') loggerAutoUpdater.info('Initializing..')
ipcRenderer.send('autoUpdateAction', 'initAutoUpdater', ConfigManager.getAllowPrerelease()) ipcRenderer.send('autoUpdateAction', 'initAutoUpdater', ConfigManager.getAllowPrerelease())
} }
prepareSettings(true) await prepareSettings(true)
updateSelectedServer(data.getServer(ConfigManager.getSelectedServer())) updateSelectedServer(data.getServerById(ConfigManager.getSelectedServer()))
refreshServerStatus() refreshServerStatus()
setTimeout(() => { setTimeout(() => {
document.getElementById('frameBar').style.backgroundColor = 'rgba(0, 0, 0, 0.5)' document.getElementById('frameBar').style.backgroundColor = 'rgba(0, 0, 0, 0.5)'
@ -133,7 +134,7 @@ function showFatalStartupError(){
* @param {Object} data The distro index object. * @param {Object} data The distro index object.
*/ */
function onDistroRefresh(data){ function onDistroRefresh(data){
updateSelectedServer(data.getServer(ConfigManager.getSelectedServer())) updateSelectedServer(data.getServerById(ConfigManager.getSelectedServer()))
refreshServerStatus() refreshServerStatus()
initNews() initNews()
syncModConfigurations(data) syncModConfigurations(data)
@ -149,10 +150,10 @@ function syncModConfigurations(data){
const syncedCfgs = [] const syncedCfgs = []
for(let serv of data.getServers()){ for(let serv of data.servers){
const id = serv.getID() const id = serv.rawServer.id
const mdls = serv.getModules() const mdls = serv.modules
const cfg = ConfigManager.getModConfiguration(id) const cfg = ConfigManager.getModConfiguration(id)
if(cfg != null){ if(cfg != null){
@ -161,20 +162,20 @@ function syncModConfigurations(data){
const mods = {} const mods = {}
for(let mdl of mdls){ for(let mdl of mdls){
const type = mdl.getType() const type = mdl.rawModule.type
if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){ if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader){
if(!mdl.getRequired().isRequired()){ if(!mdl.getRequired().value){
const mdlID = mdl.getVersionlessID() const mdlID = mdl.getVersionlessMavenIdentifier()
if(modsOld[mdlID] == null){ if(modsOld[mdlID] == null){
mods[mdlID] = scanOptionalSubModules(mdl.getSubModules(), mdl) mods[mdlID] = scanOptionalSubModules(mdl.subModules, mdl)
} else { } else {
mods[mdlID] = mergeModConfiguration(modsOld[mdlID], scanOptionalSubModules(mdl.getSubModules(), mdl), false) mods[mdlID] = mergeModConfiguration(modsOld[mdlID], scanOptionalSubModules(mdl.subModules, mdl), false)
} }
} else { } else {
if(mdl.hasSubModules()){ if(mdl.subModules.length > 0){
const mdlID = mdl.getVersionlessID() const mdlID = mdl.getVersionlessMavenIdentifier()
const v = scanOptionalSubModules(mdl.getSubModules(), mdl) const v = scanOptionalSubModules(mdl.subModules, mdl)
if(typeof v === 'object'){ if(typeof v === 'object'){
if(modsOld[mdlID] == null){ if(modsOld[mdlID] == null){
mods[mdlID] = v mods[mdlID] = v
@ -197,15 +198,15 @@ function syncModConfigurations(data){
const mods = {} const mods = {}
for(let mdl of mdls){ for(let mdl of mdls){
const type = mdl.getType() const type = mdl.rawModule.type
if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){ if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader){
if(!mdl.getRequired().isRequired()){ if(!mdl.getRequired().value){
mods[mdl.getVersionlessID()] = scanOptionalSubModules(mdl.getSubModules(), mdl) mods[mdl.getVersionlessMavenIdentifier()] = scanOptionalSubModules(mdl.subModules, mdl)
} else { } else {
if(mdl.hasSubModules()){ if(mdl.subModules.length > 0){
const v = scanOptionalSubModules(mdl.getSubModules(), mdl) const v = scanOptionalSubModules(mdl.subModules, mdl)
if(typeof v === 'object'){ if(typeof v === 'object'){
mods[mdl.getVersionlessID()] = v mods[mdl.getVersionlessMavenIdentifier()] = v
} }
} }
} }
@ -232,8 +233,8 @@ function syncModConfigurations(data){
function ensureJavaSettings(data) { function ensureJavaSettings(data) {
// Nothing too fancy for now. // Nothing too fancy for now.
for(const serv of data.getServers()){ for(const serv of data.servers){
ConfigManager.ensureJavaConfig(serv.getID(), serv.getMinecraftVersion()) ConfigManager.ensureJavaConfig(serv.rawServer.id, serv.effectiveJavaOptions, serv.rawServer.javaOptions?.ram)
} }
ConfigManager.save() ConfigManager.save()
@ -251,17 +252,17 @@ function scanOptionalSubModules(mdls, origin){
const mods = {} const mods = {}
for(let mdl of mdls){ for(let mdl of mdls){
const type = mdl.getType() const type = mdl.rawModule.type
// Optional types. // Optional types.
if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){ if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader){
// It is optional. // It is optional.
if(!mdl.getRequired().isRequired()){ if(!mdl.getRequired().value){
mods[mdl.getVersionlessID()] = scanOptionalSubModules(mdl.getSubModules(), mdl) mods[mdl.getVersionlessMavenIdentifier()] = scanOptionalSubModules(mdl.subModules, mdl)
} else { } else {
if(mdl.hasSubModules()){ if(mdl.hasSubModules()){
const v = scanOptionalSubModules(mdl.getSubModules(), mdl) const v = scanOptionalSubModules(mdl.subModules, mdl)
if(typeof v === 'object'){ if(typeof v === 'object'){
mods[mdl.getVersionlessID()] = v mods[mdl.getVersionlessMavenIdentifier()] = v
} }
} }
} }
@ -272,13 +273,13 @@ function scanOptionalSubModules(mdls, origin){
const ret = { const ret = {
mods mods
} }
if(!origin.getRequired().isRequired()){ if(!origin.getRequired().value){
ret.value = origin.getRequired().isDefault() ret.value = origin.getRequired().def
} }
return ret return ret
} }
} }
return origin.getRequired().isDefault() return origin.getRequired().def
} }
/** /**
@ -323,18 +324,6 @@ function mergeModConfiguration(o, n, nReq = false){
return n return n
} }
function refreshDistributionIndex(remote, onSuccess, onError){
if(remote){
DistroManager.pullRemote()
.then(onSuccess)
.catch(onError)
} else {
DistroManager.pullLocal()
.then(onSuccess)
.catch(onError)
}
}
async function validateSelectedAccount(){ async function validateSelectedAccount(){
const selectedAcc = ConfigManager.getSelectedAccount() const selectedAcc = ConfigManager.getSelectedAccount()
if(selectedAcc != null){ if(selectedAcc != null){
@ -429,14 +418,14 @@ function setSelectedAccount(uuid){
} }
// Synchronous Listener // Synchronous Listener
document.addEventListener('readystatechange', function(){ document.addEventListener('readystatechange', async () => {
if (document.readyState === 'interactive' || document.readyState === 'complete'){ if (document.readyState === 'interactive' || document.readyState === 'complete'){
if(rscShouldLoad){ if(rscShouldLoad){
rscShouldLoad = false rscShouldLoad = false
if(!fatalStartupError){ if(!fatalStartupError){
const data = DistroManager.getDistribution() const data = await DistroAPI.getDistribution()
showMainUI(data) await showMainUI(data)
} else { } else {
showFatalStartupError() showFatalStartupError()
} }
@ -446,13 +435,13 @@ document.addEventListener('readystatechange', function(){
}, false) }, false)
// Actions that must be performed after the distribution index is downloaded. // Actions that must be performed after the distribution index is downloaded.
ipcRenderer.on('distributionIndexDone', (event, res) => { ipcRenderer.on('distributionIndexDone', async (event, res) => {
if(res) { if(res) {
const data = DistroManager.getDistribution() const data = await DistroAPI.getDistribution()
syncModConfigurations(data) syncModConfigurations(data)
ensureJavaSettings(data) ensureJavaSettings(data)
if(document.readyState === 'interactive' || document.readyState === 'complete'){ if(document.readyState === 'interactive' || document.readyState === 'complete'){
showMainUI(data) await showMainUI(data)
} else { } else {
rscShouldLoad = true rscShouldLoad = true
} }
@ -467,11 +456,10 @@ ipcRenderer.on('distributionIndexDone', (event, res) => {
}) })
// Util for development // Util for development
function devModeToggle() { async function devModeToggle() {
DistroManager.setDevMode(true) DistroAPI.toggleDevMode(true)
DistroManager.pullLocal().then((data) => { const data = await DistroAPI.refreshDistributionOrFallback()
ensureJavaSettings(data) ensureJavaSettings(data)
updateSelectedServer(data.getServers()[0]) updateSelectedServer(data.servers[0])
syncModConfigurations(data) syncModConfigurations(data)
})
} }

View File

@ -2,6 +2,8 @@
You can use [Nebula](https://github.com/dscalzi/Nebula) to automate the generation of a distribution index. You can use [Nebula](https://github.com/dscalzi/Nebula) to automate the generation of a distribution index.
The most up to date and accurate descriptions of the distribution spec can be viewed in [helios-distribution-types](https://github.com/dscalzi/helios-distribution-types).
The distribution index is written in JSON. The general format of the index is as posted below. The distribution index is written in JSON. The general format of the index is as posted below.
```json ```json
@ -143,12 +145,122 @@ Only one server in the array should have the `mainServer` property enabled. This
Whether or not the server can be autoconnected to. If false, the server will not be autoconnected to even when the user has the autoconnect setting enabled. Whether or not the server can be autoconnected to. If false, the server will not be autoconnected to even when the user has the autoconnect setting enabled.
### `Server.javaOptions: JavaOptions`
**OPTIONAL**
Sever-specific Java options. If not provided, defaults are used by the client.
### `Server.modules: Module[]` ### `Server.modules: Module[]`
An array of module objects. An array of module objects.
--- ---
## JavaOptions Object
Server-specific Java options.
#### Example
```JSON
{
"supported": ">=17",
"suggestedMajor": 17,
"platformOptions": [
{
"platform": "darwin",
"architecture": "arm64",
"distribution": "CORRETTO"
}
],
"ram": {
"recommended": 3072,
"minimum": 2048
}
}
```
### `JavaOptions.platformOptions: JavaPlatformOptions[]`
**OPTIONAL**
Platform-specific java rules for this server configuration. Validation rules will be delegated to the client for any undefined properties. Java validation can be configured for specific platforms and architectures. The most specific ruleset will be applied.
Maxtrix Precedence (Highest - Lowest)
- Current platform, current architecture (ex. win32 x64).
- Current platform, any architecture (ex. win32).
- Java Options base properties.
- Client logic (default logic in the client).
Properties:
- `platformOptions.platform: string` - The platform that this validation matrix applies to.
- `platformOptions.architecture: string` - Optional. The architecture that this validation matrix applies to. If omitted, applies to all architectures.
- `platformOptions.distribution: string` - Optional. See `JavaOptions.distribution`.
- `platformOptions.supported: string` - Optional. See `JavaOptions.supported`.
- `platformOptions.suggestedMajor: number` - Optional. See `JavaOptions.suggestedMajor`.
### `JavaOptions.ram: object`
**OPTIONAL**
This allows you to require a minimum and recommended amount of RAM per server instance. The minimum is the smallest value the user can select in the settings slider. The recommended value will be the default value selected for that server. These values are specified in megabytes and must be an interval of 512. This allows configuration in intervals of half gigabytes. In the above example, the recommended ram value is 3 GB (3072 MB) and the minimum is 2 GB (2048 MB).
- `ram.recommended: number` - The recommended amount of RAM in megabytes. Must be an interval of 512.
- `ram.minimum: number` - The absolute minimum amount of RAM in megabytes. Must be an interval of 512.
### `JavaOptions.distribution: string`
**OPTIONAL**
Preferred JDK distribution to download if no applicable installation could be found. If omitted, the client will decide (decision may be platform-specific).
### `JavaOptions.supported: string`
**OPTIONAL**
A semver range of supported JDK versions.
Java version syntax is platform dependent.
JDK 8 and prior
```
1.{major}.{minor}_{patch}-b{build}
Ex. 1.8.0_152-b16
```
JDK 9+
```
{major}.{minor}.{patch}+{build}
Ex. 11.0.12+7
```
For processing, all versions will be translated into a semver compliant string. JDK 9+ is already semver. For versions 8 and below, `1.{major}.{minor}_{patch}-b{build}` will be translated to `{major}.{minor}.{patch}+{build}`.
If specified, you must also specify suggestedMajor.
If omitted, the client will decide based on the game version.
### `JavaOptions.suggestedMajor: number`
**OPTIONAL**
The suggested major Java version. The suggested major should comply with the version range specified by supported, if defined. This will be used in messages displayed to the end user, and to automatically fetch a Java version.
NOTE If supported is specified, suggestedMajor must be set. The launcher's default value may not comply with your custom major supported range.
Common use case:
- supported: '>=17.x'
- suggestedMajor: 17
More involved:
- supported: '>=16 <20'
- suggestedMajor: 17
Given a wider support range, it becomes necessary to specify which major version in the range is the suggested.
---
## Module Object ## Module Object
A module is a generic representation of a file required to run the minecraft client. A module is a generic representation of a file required to run the minecraft client.

562
package-lock.json generated
View File

@ -1,37 +1,32 @@
{ {
"name": "helioslauncher", "name": "helioslauncher",
"version": "1.10.0", "version": "2.0.0-rc.3",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "helioslauncher", "name": "helioslauncher",
"version": "1.10.0", "version": "2.0.0-rc.3",
"license": "UNLICENSED", "license": "UNLICENSED",
"dependencies": { "dependencies": {
"@electron/remote": "^2.0.8", "@electron/remote": "^2.0.8",
"adm-zip": "^0.5.9", "adm-zip": "^0.5.9",
"async": "^3.2.4",
"discord-rpc-patch": "^4.0.1", "discord-rpc-patch": "^4.0.1",
"ejs": "^3.1.8", "ejs": "^3.1.9",
"ejs-electron": "^2.1.1", "ejs-electron": "^2.1.1",
"electron-updater": "^5.3.0", "electron-updater": "^5.3.0",
"fs-extra": "^11.1.0", "fs-extra": "^11.1.1",
"github-syntax-dark": "^0.5.0", "github-syntax-dark": "^0.5.0",
"got": "^11.8.5", "got": "^11.8.5",
"helios-core": "~0.1.2", "helios-core": "~2.0.0",
"jquery": "^3.6.1", "helios-distribution-types": "^1.2.0",
"node-disk-info": "^1.3.0", "jquery": "^3.6.4",
"node-stream-zip": "^1.15.0", "semver": "^7.3.8"
"request": "^2.88.2",
"semver": "^7.3.8",
"tar-fs": "^2.1.1",
"winreg": "^1.2.4"
}, },
"devDependencies": { "devDependencies": {
"electron": "^23.0.0", "electron": "^23.2.0",
"electron-builder": "^23.6.0", "electron-builder": "^23.6.0",
"eslint": "^8.34.0" "eslint": "^8.36.0"
}, },
"engines": { "engines": {
"node": "18.x.x" "node": "18.x.x"
@ -170,15 +165,39 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/@eslint-community/eslint-utils": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.3.0.tgz",
"integrity": "sha512-v3oplH6FYCULtFuCeqyuTd9D2WKO937Dxdq+GmHOLL72TTRriLxz2VLlNfkZRsvj6PKnOPAtuT6dwrs/pA5DvA==",
"dev": true,
"dependencies": {
"eslint-visitor-keys": "^3.3.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"peerDependencies": {
"eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
}
},
"node_modules/@eslint-community/regexpp": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.4.0.tgz",
"integrity": "sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==",
"dev": true,
"engines": {
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
}
},
"node_modules/@eslint/eslintrc": { "node_modules/@eslint/eslintrc": {
"version": "1.4.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.1.tgz",
"integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", "integrity": "sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"ajv": "^6.12.4", "ajv": "^6.12.4",
"debug": "^4.3.2", "debug": "^4.3.2",
"espree": "^9.4.0", "espree": "^9.5.0",
"globals": "^13.19.0", "globals": "^13.19.0",
"ignore": "^5.2.0", "ignore": "^5.2.0",
"import-fresh": "^3.2.1", "import-fresh": "^3.2.1",
@ -193,6 +212,15 @@
"url": "https://opencollective.com/eslint" "url": "https://opencollective.com/eslint"
} }
}, },
"node_modules/@eslint/js": {
"version": "8.36.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.36.0.tgz",
"integrity": "sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/@humanwhocodes/config-array": { "node_modules/@humanwhocodes/config-array": {
"version": "0.11.8", "version": "0.11.8",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
@ -411,9 +439,9 @@
"dev": true "dev": true
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "16.18.12", "version": "16.18.16",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.12.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.16.tgz",
"integrity": "sha512-vzLe5NaNMjIE3mcddFVGlAXN1LEWueUsMsOJWaT6wWMJGyljHAWHznqfnKUQWGzu7TLPrGvWdNAsvQYW+C0xtw==" "integrity": "sha512-ZOzvDRWp8dCVBmgnkIqYCArgdFOO9YzocZp8Ra25N/RStKiWvMOXHMz+GjSeVNe5TstaTmTWPucGJkDw0XXJWA=="
}, },
"node_modules/@types/plist": { "node_modules/@types/plist": {
"version": "3.0.2", "version": "3.0.2",
@ -526,6 +554,7 @@
"version": "6.12.6", "version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.1", "fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0", "fast-json-stable-stringify": "^2.0.0",
@ -653,18 +682,12 @@
"@types/glob": "^7.1.1" "@types/glob": "^7.1.1"
} }
}, },
"node_modules/asn1": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
"integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
"dependencies": {
"safer-buffer": "~2.1.0"
}
},
"node_modules/assert-plus": { "node_modules/assert-plus": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==",
"dev": true,
"optional": true,
"engines": { "engines": {
"node": ">=0.8" "node": ">=0.8"
} }
@ -696,7 +719,8 @@
"node_modules/asynckit": { "node_modules/asynckit": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"dev": true
}, },
"node_modules/at-least-node": { "node_modules/at-least-node": {
"version": "1.0.0", "version": "1.0.0",
@ -707,19 +731,6 @@
"node": ">= 4.0.0" "node": ">= 4.0.0"
} }
}, },
"node_modules/aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
"integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==",
"engines": {
"node": "*"
}
},
"node_modules/aws4": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz",
"integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg=="
},
"node_modules/balanced-match": { "node_modules/balanced-match": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -744,14 +755,6 @@
} }
] ]
}, },
"node_modules/bcrypt-pbkdf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
"dependencies": {
"tweetnacl": "^0.14.3"
}
},
"node_modules/bl": { "node_modules/bl": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
@ -945,11 +948,6 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw=="
},
"node_modules/chalk": { "node_modules/chalk": {
"version": "4.1.2", "version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@ -1106,6 +1104,7 @@
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dev": true,
"dependencies": { "dependencies": {
"delayed-stream": "~1.0.0" "delayed-stream": "~1.0.0"
}, },
@ -1139,7 +1138,9 @@
"node_modules/core-util-is": { "node_modules/core-util-is": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==",
"dev": true,
"optional": true
}, },
"node_modules/crc": { "node_modules/crc": {
"version": "3.8.0", "version": "3.8.0",
@ -1165,17 +1166,6 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/dashdash": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==",
"dependencies": {
"assert-plus": "^1.0.0"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/debug": { "node_modules/debug": {
"version": "4.3.4", "version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@ -1251,6 +1241,7 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"dev": true,
"engines": { "engines": {
"node": ">=0.4.0" "node": ">=0.4.0"
} }
@ -1393,19 +1384,10 @@
"integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==",
"dev": true "dev": true
}, },
"node_modules/ecc-jsbn": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
"integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==",
"dependencies": {
"jsbn": "~0.1.0",
"safer-buffer": "^2.1.0"
}
},
"node_modules/ejs": { "node_modules/ejs": {
"version": "3.1.8", "version": "3.1.9",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz",
"integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==", "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==",
"dependencies": { "dependencies": {
"jake": "^10.8.5" "jake": "^10.8.5"
}, },
@ -1426,9 +1408,9 @@
} }
}, },
"node_modules/electron": { "node_modules/electron": {
"version": "23.0.0", "version": "23.2.0",
"resolved": "https://registry.npmjs.org/electron/-/electron-23.0.0.tgz", "resolved": "https://registry.npmjs.org/electron/-/electron-23.2.0.tgz",
"integrity": "sha512-S6hVtTAjauMiiWP9sBVR5RpcUC464cNZ06I2EMUjeZBq+KooS6tLmNsfw0zLpAXDp1qosjlBP3v71NTZ3gd9iA==", "integrity": "sha512-De9e21cri0QYct/w6tTNOnKyCt9RVKUw5F8PEN4FPzGR9tr6IT53uyt42uH754uJWrZeLMCAdoXy6/0GmMmYZA==",
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"@electron/get": "^2.0.0", "@electron/get": "^2.0.0",
@ -1645,12 +1627,15 @@
} }
}, },
"node_modules/eslint": { "node_modules/eslint": {
"version": "8.34.0", "version": "8.36.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.36.0.tgz",
"integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", "integrity": "sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@eslint/eslintrc": "^1.4.1", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.4.0",
"@eslint/eslintrc": "^2.0.1",
"@eslint/js": "8.36.0",
"@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/config-array": "^0.11.8",
"@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8", "@nodelib/fs.walk": "^1.2.8",
@ -1661,10 +1646,9 @@
"doctrine": "^3.0.0", "doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0", "escape-string-regexp": "^4.0.0",
"eslint-scope": "^7.1.1", "eslint-scope": "^7.1.1",
"eslint-utils": "^3.0.0",
"eslint-visitor-keys": "^3.3.0", "eslint-visitor-keys": "^3.3.0",
"espree": "^9.4.0", "espree": "^9.5.0",
"esquery": "^1.4.0", "esquery": "^1.4.2",
"esutils": "^2.0.2", "esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3", "fast-deep-equal": "^3.1.3",
"file-entry-cache": "^6.0.1", "file-entry-cache": "^6.0.1",
@ -1685,7 +1669,6 @@
"minimatch": "^3.1.2", "minimatch": "^3.1.2",
"natural-compare": "^1.4.0", "natural-compare": "^1.4.0",
"optionator": "^0.9.1", "optionator": "^0.9.1",
"regexpp": "^3.2.0",
"strip-ansi": "^6.0.1", "strip-ansi": "^6.0.1",
"strip-json-comments": "^3.1.0", "strip-json-comments": "^3.1.0",
"text-table": "^0.2.0" "text-table": "^0.2.0"
@ -1713,33 +1696,6 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0" "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
} }
}, },
"node_modules/eslint-utils": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
"integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
"dev": true,
"dependencies": {
"eslint-visitor-keys": "^2.0.0"
},
"engines": {
"node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
},
"funding": {
"url": "https://github.com/sponsors/mysticatea"
},
"peerDependencies": {
"eslint": ">=5"
}
},
"node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
"integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
"dev": true,
"engines": {
"node": ">=10"
}
},
"node_modules/eslint-visitor-keys": { "node_modules/eslint-visitor-keys": {
"version": "3.3.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
@ -1750,9 +1706,9 @@
} }
}, },
"node_modules/espree": { "node_modules/espree": {
"version": "9.4.1", "version": "9.5.0",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.0.tgz",
"integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", "integrity": "sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"acorn": "^8.8.0", "acorn": "^8.8.0",
@ -1767,9 +1723,9 @@
} }
}, },
"node_modules/esquery": { "node_modules/esquery": {
"version": "1.4.0", "version": "1.5.0",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
"integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"estraverse": "^5.1.0" "estraverse": "^5.1.0"
@ -1808,11 +1764,6 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
},
"node_modules/extract-zip": { "node_modules/extract-zip": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
@ -1833,22 +1784,26 @@
} }
}, },
"node_modules/extsprintf": { "node_modules/extsprintf": {
"version": "1.3.0", "version": "1.4.1",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz",
"integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", "integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==",
"dev": true,
"engines": [ "engines": [
"node >=0.6.0" "node >=0.6.0"
] ],
"optional": true
}, },
"node_modules/fast-deep-equal": { "node_modules/fast-deep-equal": {
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
}, },
"node_modules/fast-json-stable-stringify": { "node_modules/fast-json-stable-stringify": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
"dev": true
}, },
"node_modules/fast-levenshtein": { "node_modules/fast-levenshtein": {
"version": "2.0.6", "version": "2.0.6",
@ -1860,7 +1815,6 @@
"version": "1.15.0", "version": "1.15.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
"integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
"dev": true,
"dependencies": { "dependencies": {
"reusify": "^1.0.4" "reusify": "^1.0.4"
} }
@ -1957,14 +1911,6 @@
"resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
"integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="
}, },
"node_modules/forever-agent": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
"integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==",
"engines": {
"node": "*"
}
},
"node_modules/form-data": { "node_modules/form-data": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
@ -1985,9 +1931,9 @@
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
}, },
"node_modules/fs-extra": { "node_modules/fs-extra": {
"version": "11.1.0", "version": "11.1.1",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz",
"integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==", "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==",
"dependencies": { "dependencies": {
"graceful-fs": "^4.2.0", "graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1", "jsonfile": "^6.0.1",
@ -2070,14 +2016,6 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/getpass": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==",
"dependencies": {
"assert-plus": "^1.0.0"
}
},
"node_modules/github-syntax-dark": { "node_modules/github-syntax-dark": {
"version": "0.5.0", "version": "0.5.0",
"resolved": "https://registry.npmjs.org/github-syntax-dark/-/github-syntax-dark-0.5.0.tgz", "resolved": "https://registry.npmjs.org/github-syntax-dark/-/github-syntax-dark-0.5.0.tgz",
@ -2187,9 +2125,9 @@
} }
}, },
"node_modules/graceful-fs": { "node_modules/graceful-fs": {
"version": "4.2.10", "version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
}, },
"node_modules/graceful-readlink": { "node_modules/graceful-readlink": {
"version": "1.0.1", "version": "1.0.1",
@ -2203,27 +2141,6 @@
"integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
"dev": true "dev": true
}, },
"node_modules/har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
"integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==",
"engines": {
"node": ">=4"
}
},
"node_modules/har-validator": {
"version": "5.1.5",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
"integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
"deprecated": "this library is no longer supported",
"dependencies": {
"ajv": "^6.12.3",
"har-schema": "^2.0.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/has": { "node_modules/has": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
@ -2269,29 +2186,27 @@
} }
}, },
"node_modules/helios-core": { "node_modules/helios-core": {
"version": "0.1.2", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/helios-core/-/helios-core-0.1.2.tgz", "resolved": "https://registry.npmjs.org/helios-core/-/helios-core-2.0.0.tgz",
"integrity": "sha512-xM3+nZcymy9iS36Z5odmuFZAsrSuyviQUh+dffXc+utXOP/Ox7m2HUo76t86cN8R1tLjJ/OzQJLzILACVaRryg==", "integrity": "sha512-KmObKL9JZutHzTp9Pv344Ab7CdYvf0pOhwxjuxw+/QdtJQlmCIrPF7eX9J6I1CUSheIM4lRk76LQbG28H7zqeg==",
"dependencies": { "dependencies": {
"fs-extra": "^10.1.0", "fastq": "^1.15.0",
"got": "^11.8.5", "fs-extra": "^11.1.1",
"luxon": "^3.1.0", "got": "^11.8.6",
"luxon": "^3.3.0",
"node-disk-info": "^1.3.0",
"node-stream-zip": "^1.15.0",
"semver": "^7.3.8",
"tar-fs": "^2.1.1",
"triple-beam": "^1.3.0", "triple-beam": "^1.3.0",
"winreg": "^1.2.4",
"winston": "^3.8.2" "winston": "^3.8.2"
} }
}, },
"node_modules/helios-core/node_modules/fs-extra": { "node_modules/helios-distribution-types": {
"version": "10.1.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", "resolved": "https://registry.npmjs.org/helios-distribution-types/-/helios-distribution-types-1.2.0.tgz",
"integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "integrity": "sha512-C8mRJGK0zAc7rRnA06Sj0LYwVqhY445UYNTmXU876AmfBirRR2F+A3LsD3osdgTxRMzrgkxBXvYZ0QbYW6j+6Q=="
"dependencies": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
"universalify": "^2.0.0"
},
"engines": {
"node": ">=12"
}
}, },
"node_modules/hosted-git-info": { "node_modules/hosted-git-info": {
"version": "4.1.0", "version": "4.1.0",
@ -2324,20 +2239,6 @@
"node": ">= 6" "node": ">= 6"
} }
}, },
"node_modules/http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
"integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==",
"dependencies": {
"assert-plus": "^1.0.0",
"jsprim": "^1.2.2",
"sshpk": "^1.7.0"
},
"engines": {
"node": ">=0.8",
"npm": ">=1.3.7"
}
},
"node_modules/http2-wrapper": { "node_modules/http2-wrapper": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz",
@ -2526,11 +2427,6 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
},
"node_modules/isbinaryfile": { "node_modules/isbinaryfile": {
"version": "4.0.10", "version": "4.0.10",
"resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz",
@ -2549,11 +2445,6 @@
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"dev": true "dev": true
}, },
"node_modules/isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g=="
},
"node_modules/jake": { "node_modules/jake": {
"version": "10.8.5", "version": "10.8.5",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz",
@ -2572,9 +2463,9 @@
} }
}, },
"node_modules/jquery": { "node_modules/jquery": {
"version": "3.6.3", "version": "3.6.4",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.3.tgz", "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.4.tgz",
"integrity": "sha512-bZ5Sy3YzKo9Fyc8wH2iIQK4JImJ6R0GWI9kL1/k7Z91ZBNgkRXE6U0JfHIizZbort8ZunhSI3jw9I6253ahKfg==" "integrity": "sha512-v28EW9DWDFpzcD9O5iyJXg3R3+q+mET5JhnjJzQUZMHOv67bpSIHq81GEYpPNZHG+XXHsfSme3nxp/hndKEcsQ=="
}, },
"node_modules/js-sdsl": { "node_modules/js-sdsl": {
"version": "4.3.0", "version": "4.3.0",
@ -2597,25 +2488,16 @@
"js-yaml": "bin/js-yaml.js" "js-yaml": "bin/js-yaml.js"
} }
}, },
"node_modules/jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg=="
},
"node_modules/json-buffer": { "node_modules/json-buffer": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="
}, },
"node_modules/json-schema": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
"integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
},
"node_modules/json-schema-traverse": { "node_modules/json-schema-traverse": {
"version": "0.4.1", "version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true
}, },
"node_modules/json-stable-stringify-without-jsonify": { "node_modules/json-stable-stringify-without-jsonify": {
"version": "1.0.1", "version": "1.0.1",
@ -2626,7 +2508,8 @@
"node_modules/json-stringify-safe": { "node_modules/json-stringify-safe": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
"optional": true
}, },
"node_modules/json5": { "node_modules/json5": {
"version": "2.2.3", "version": "2.2.3",
@ -2651,33 +2534,6 @@
"graceful-fs": "^4.1.6" "graceful-fs": "^4.1.6"
} }
}, },
"node_modules/jsprim": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
"integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
"dependencies": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
"json-schema": "0.4.0",
"verror": "1.10.0"
},
"engines": {
"node": ">=0.6.0"
}
},
"node_modules/jsprim/node_modules/verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==",
"engines": [
"node >=0.6.0"
],
"dependencies": {
"assert-plus": "^1.0.0",
"core-util-is": "1.0.2",
"extsprintf": "^1.2.0"
}
},
"node_modules/keyv": { "node_modules/keyv": {
"version": "4.5.2", "version": "4.5.2",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz",
@ -2779,9 +2635,9 @@
} }
}, },
"node_modules/luxon": { "node_modules/luxon": {
"version": "3.2.1", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.2.1.tgz", "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.3.0.tgz",
"integrity": "sha512-QrwPArQCNLAKGO/C+ZIilgIuDnEnKx5QYODdDtbFaxzsbZcc/a7WFq7MhsVYgRlwawLtvOUESTlfJ+hc/USqPg==", "integrity": "sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg==",
"engines": { "engines": {
"node": ">=12" "node": ">=12"
} }
@ -2813,6 +2669,7 @@
"version": "1.52.0", "version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"dev": true,
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
} }
@ -2821,6 +2678,7 @@
"version": "2.1.35", "version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dev": true,
"dependencies": { "dependencies": {
"mime-db": "1.52.0" "mime-db": "1.52.0"
}, },
@ -2857,9 +2715,9 @@
} }
}, },
"node_modules/minipass": { "node_modules/minipass": {
"version": "4.0.3", "version": "4.2.5",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.3.tgz", "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz",
"integrity": "sha512-OW2r4sQ0sI+z5ckEt5c1Tri4xTgZwYDxpE54eqWlQloQRoWtXjqt9udJ5Z4dSv7wK+nfFI7FRXyCpBSft+gpFw==", "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=8" "node": ">=8"
@ -2978,14 +2836,6 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/oauth-sign": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
"engines": {
"node": "*"
}
},
"node_modules/object-keys": { "node_modules/object-keys": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
@ -3110,11 +2960,6 @@
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
"integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="
}, },
"node_modules/performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
},
"node_modules/plist": { "node_modules/plist": {
"version": "3.0.6", "version": "3.0.6",
"resolved": "https://registry.npmjs.org/plist/-/plist-3.0.6.tgz", "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.6.tgz",
@ -3145,11 +2990,6 @@
"node": ">=0.4.0" "node": ">=0.4.0"
} }
}, },
"node_modules/psl": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
"integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag=="
},
"node_modules/pump": { "node_modules/pump": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
@ -3163,18 +3003,11 @@
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
"integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
"dev": true,
"engines": { "engines": {
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/qs": {
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz",
"integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==",
"engines": {
"node": ">=0.6"
}
},
"node_modules/queue-microtask": { "node_modules/queue-microtask": {
"version": "1.2.3", "version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@ -3223,9 +3056,9 @@
} }
}, },
"node_modules/readable-stream": { "node_modules/readable-stream": {
"version": "3.6.0", "version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"dependencies": { "dependencies": {
"inherits": "^2.0.3", "inherits": "^2.0.3",
"string_decoder": "^1.1.1", "string_decoder": "^1.1.1",
@ -3235,62 +3068,6 @@
"node": ">= 6" "node": ">= 6"
} }
}, },
"node_modules/regexpp": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
"integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
"dev": true,
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/mysticatea"
}
},
"node_modules/request": {
"version": "2.88.2",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
"integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
"deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142",
"dependencies": {
"aws-sign2": "~0.7.0",
"aws4": "^1.8.0",
"caseless": "~0.12.0",
"combined-stream": "~1.0.6",
"extend": "~3.0.2",
"forever-agent": "~0.6.1",
"form-data": "~2.3.2",
"har-validator": "~5.1.3",
"http-signature": "~1.2.0",
"is-typedarray": "~1.0.0",
"isstream": "~0.1.2",
"json-stringify-safe": "~5.0.1",
"mime-types": "~2.1.19",
"oauth-sign": "~0.9.0",
"performance-now": "^2.1.0",
"qs": "~6.5.2",
"safe-buffer": "^5.1.2",
"tough-cookie": "~2.5.0",
"tunnel-agent": "^0.6.0",
"uuid": "^3.3.2"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/request/node_modules/form-data": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 0.12"
}
},
"node_modules/require-directory": { "node_modules/require-directory": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@ -3329,7 +3106,6 @@
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
"dev": true,
"engines": { "engines": {
"iojs": ">=1.0.0", "iojs": ">=1.0.0",
"node": ">=0.10.0" "node": ">=0.10.0"
@ -3419,9 +3195,9 @@
] ]
}, },
"node_modules/safe-stable-stringify": { "node_modules/safe-stable-stringify": {
"version": "2.4.2", "version": "2.4.3",
"resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz",
"integrity": "sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==", "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==",
"engines": { "engines": {
"node": ">=10" "node": ">=10"
} }
@ -3593,30 +3369,6 @@
"integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==",
"optional": true "optional": true
}, },
"node_modules/sshpk": {
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz",
"integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==",
"dependencies": {
"asn1": "~0.2.3",
"assert-plus": "^1.0.0",
"bcrypt-pbkdf": "^1.0.0",
"dashdash": "^1.12.0",
"ecc-jsbn": "~0.1.1",
"getpass": "^0.1.1",
"jsbn": "~0.1.0",
"safer-buffer": "^2.0.2",
"tweetnacl": "~0.14.0"
},
"bin": {
"sshpk-conv": "bin/sshpk-conv",
"sshpk-sign": "bin/sshpk-sign",
"sshpk-verify": "bin/sshpk-verify"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/stack-trace": { "node_modules/stack-trace": {
"version": "0.0.10", "version": "0.0.10",
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
@ -3806,18 +3558,6 @@
"tmp": "^0.2.0" "tmp": "^0.2.0"
} }
}, },
"node_modules/tough-cookie": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
"dependencies": {
"psl": "^1.1.28",
"punycode": "^2.1.1"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/tr46": { "node_modules/tr46": {
"version": "0.0.3", "version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
@ -3843,22 +3583,6 @@
"integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==",
"optional": true "optional": true
}, },
"node_modules/tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
"dependencies": {
"safe-buffer": "^5.0.1"
},
"engines": {
"node": "*"
}
},
"node_modules/tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="
},
"node_modules/type-check": { "node_modules/type-check": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@ -3903,6 +3627,7 @@
"version": "4.4.1", "version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"dev": true,
"dependencies": { "dependencies": {
"punycode": "^2.1.0" "punycode": "^2.1.0"
} }
@ -3918,15 +3643,6 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
}, },
"node_modules/uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
"bin": {
"uuid": "bin/uuid"
}
},
"node_modules/verror": { "node_modules/verror": {
"version": "1.10.1", "version": "1.10.1",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz",
@ -4085,9 +3801,9 @@
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}, },
"node_modules/yargs": { "node_modules/yargs": {
"version": "17.6.2", "version": "17.7.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz",
"integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"cliui": "^8.0.1", "cliui": "^8.0.1",

View File

@ -1,6 +1,6 @@
{ {
"name": "helioslauncher", "name": "helioslauncher",
"version": "1.10.0", "version": "2.0.0-rc.3",
"productName": "Helios Launcher", "productName": "Helios Launcher",
"description": "Modded Minecraft Launcher", "description": "Modded Minecraft Launcher",
"author": "Daniel Scalzi (https://github.com/dscalzi/)", "author": "Daniel Scalzi (https://github.com/dscalzi/)",
@ -25,27 +25,22 @@
"dependencies": { "dependencies": {
"@electron/remote": "^2.0.8", "@electron/remote": "^2.0.8",
"adm-zip": "^0.5.9", "adm-zip": "^0.5.9",
"async": "^3.2.4",
"discord-rpc-patch": "^4.0.1", "discord-rpc-patch": "^4.0.1",
"ejs": "^3.1.8", "ejs": "^3.1.9",
"ejs-electron": "^2.1.1", "ejs-electron": "^2.1.1",
"electron-updater": "^5.3.0", "electron-updater": "^5.3.0",
"fs-extra": "^11.1.0", "fs-extra": "^11.1.1",
"github-syntax-dark": "^0.5.0", "github-syntax-dark": "^0.5.0",
"got": "^11.8.5", "got": "^11.8.5",
"helios-core": "~0.1.2", "helios-core": "~2.0.0",
"jquery": "^3.6.1", "helios-distribution-types": "^1.2.0",
"node-disk-info": "^1.3.0", "jquery": "^3.6.4",
"node-stream-zip": "^1.15.0", "semver": "^7.3.8"
"request": "^2.88.2",
"semver": "^7.3.8",
"tar-fs": "^2.1.1",
"winreg": "^1.2.4"
}, },
"devDependencies": { "devDependencies": {
"electron": "^23.0.0", "electron": "^23.2.0",
"electron-builder": "^23.6.0", "electron-builder": "^23.6.0",
"eslint": "^8.34.0" "eslint": "^8.36.0"
}, },
"repository": { "repository": {
"type": "git", "type": "git",