diff --git a/BUILD.md b/BUILD.md index 5292289..5b76df4 100644 --- a/BUILD.md +++ b/BUILD.md @@ -36,19 +36,4 @@ npm run build:mac npm run build:all ``` -## Output - -Built executables will be in the `dist/` directory: - -- **Windows**: `Hytale F2P Launcher Setup.exe` (NSIS installer) and `Hytale F2P Launcher.exe` (portable) -- **Linux**: `Hytale F2P Launcher.AppImage` and `Hytale F2P Launcher.deb` -- **macOS**: `Hytale F2P Launcher.dmg` and `Hytale F2P Launcher.zip` - -## Notes - -- Icons need to be placed in `build/` directory: - - `icon.ico` for Windows - - `icon.png` for Linux - - `icon.icns` for macOS -- To build for macOS on non-Mac systems, you'll need to run it on a Mac or use a CI/CD service - +Built executables will be in the `dist/` directory diff --git a/SERVER.md b/SERVER.md index 510edb5..bde93b6 100644 --- a/SERVER.md +++ b/SERVER.md @@ -4,7 +4,7 @@ **Download server file:** ``` -http://3.10.208.30:3002/server +https://files.hytalef2p.com/server ``` **Replace the file here:** diff --git a/backend/core/config.js b/backend/core/config.js new file mode 100644 index 0000000..9857b70 --- /dev/null +++ b/backend/core/config.js @@ -0,0 +1,163 @@ +const fs = require('fs'); +const path = require('path'); +const os = require('os'); + +function getAppDir() { + const home = os.homedir(); + if (process.platform === 'win32') { + return path.join(home, 'AppData', 'Local', 'HytaleF2P'); + } else if (process.platform === 'darwin') { + return path.join(home, 'Library', 'Application Support', 'HytaleF2P'); + } else { + return path.join(home, '.hytalef2p'); + } +} + +const CONFIG_FILE = path.join(getAppDir(), 'config.json'); + +function loadConfig() { + try { + if (fs.existsSync(CONFIG_FILE)) { + return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); + } + } catch (err) { + console.log('Notice: could not load config:', err.message); + } + return {}; +} + +function saveConfig(update) { + try { + const configDir = path.dirname(CONFIG_FILE); + if (!fs.existsSync(configDir)) { + fs.mkdirSync(configDir, { recursive: true }); + } + const config = loadConfig(); + const next = { ...config, ...update }; + fs.writeFileSync(CONFIG_FILE, JSON.stringify(next, null, 2), 'utf8'); + } catch (err) { + console.log('Notice: could not save config:', err.message); + } +} + +function saveUsername(username) { + saveConfig({ username: username || 'Player' }); +} + +function loadUsername() { + const config = loadConfig(); + return config.username || 'Player'; +} + +function saveChatUsername(chatUsername) { + saveConfig({ chatUsername: chatUsername || '' }); +} + +function loadChatUsername() { + const config = loadConfig(); + return config.chatUsername || ''; +} + +function getUuidForUser(username) { + const { v4: uuidv4 } = require('uuid'); + const config = loadConfig(); + const userUuids = config.userUuids || {}; + + if (userUuids[username]) { + return userUuids[username]; + } + + const newUuid = uuidv4(); + userUuids[username] = newUuid; + saveConfig({ userUuids }); + + return newUuid; +} + +function saveJavaPath(javaPath) { + const trimmed = (javaPath || '').trim(); + saveConfig({ javaPath: trimmed }); +} + +function loadJavaPath() { + const config = loadConfig(); + return config.javaPath || ''; +} + +function saveInstallPath(installPath) { + const trimmed = (installPath || '').trim(); + saveConfig({ installPath: trimmed }); +} + +function loadInstallPath() { + const config = loadConfig(); + return config.installPath || ''; +} + +function saveModsToConfig(mods) { + try { + let config = loadConfig(); + config.installedMods = mods; + + const configDir = path.dirname(CONFIG_FILE); + if (!fs.existsSync(configDir)) { + fs.mkdirSync(configDir, { recursive: true }); + } + + fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2)); + console.log('Mods saved to config.json'); + } catch (error) { + console.error('Error saving mods to config:', error); + } +} + +function loadModsFromConfig() { + try { + const config = loadConfig(); + return config.installedMods || []; + } catch (error) { + console.error('Error loading mods from config:', error); + return []; + } +} + +function isFirstLaunch() { + const config = loadConfig(); + + if ('hasLaunchedBefore' in config) { + return !config.hasLaunchedBefore; + } + + const hasUserData = config.installPath || config.username || config.javaPath || + config.chatUsername || config.userUuids || + Object.keys(config).length > 0; + + if (!hasUserData) { + return true; + } + + return true; +} + +function markAsLaunched() { + saveConfig({ hasLaunchedBefore: true, firstLaunchDate: new Date().toISOString() }); +} + +module.exports = { + loadConfig, + saveConfig, + saveUsername, + loadUsername, + saveChatUsername, + loadChatUsername, + getUuidForUser, + saveJavaPath, + loadJavaPath, + saveInstallPath, + loadInstallPath, + saveModsToConfig, + loadModsFromConfig, + isFirstLaunch, + markAsLaunched, + CONFIG_FILE +}; diff --git a/backend/core/paths.js b/backend/core/paths.js new file mode 100644 index 0000000..8d49462 --- /dev/null +++ b/backend/core/paths.js @@ -0,0 +1,197 @@ +const fs = require('fs'); +const path = require('path'); +const os = require('os'); + +function getAppDir() { + const home = os.homedir(); + if (process.platform === 'win32') { + return path.join(home, 'AppData', 'Local', 'HytaleF2P'); + } else if (process.platform === 'darwin') { + return path.join(home, 'Library', 'Application Support', 'HytaleF2P'); + } else { + return path.join(home, '.hytalef2p'); + } +} + +const DEFAULT_APP_DIR = getAppDir(); + +function getResolvedAppDir(customPath) { + if (customPath && customPath.trim()) { + return path.join(customPath.trim(), 'HytaleF2P'); + } + try { + const configFile = path.join(DEFAULT_APP_DIR, 'config.json'); + if (fs.existsSync(configFile)) { + const config = JSON.parse(fs.readFileSync(configFile, 'utf8')); + if (config.installPath && config.installPath.trim()) { + return path.join(config.installPath.trim(), 'HytaleF2P'); + } + } + } catch (err) { + } + return DEFAULT_APP_DIR; +} + +function expandHome(inputPath) { + if (!inputPath) { + return inputPath; + } + if (inputPath === '~') { + return os.homedir(); + } + if (inputPath.startsWith('~/') || inputPath.startsWith('~\\')) { + return path.join(os.homedir(), inputPath.slice(2)); + } + return inputPath; +} + +const APP_DIR = DEFAULT_APP_DIR; +const CACHE_DIR = path.join(APP_DIR, 'cache'); +const TOOLS_DIR = path.join(APP_DIR, 'butler'); +const GAME_DIR = path.join(APP_DIR, 'release', 'package', 'game', 'latest'); +const JRE_DIR = path.join(APP_DIR, 'release', 'package', 'jre', 'latest'); +const PLAYER_ID_FILE = path.join(APP_DIR, 'player_id.json'); + +function getClientCandidates(gameLatest) { + const candidates = []; + if (process.platform === 'win32') { + candidates.push(path.join(gameLatest, 'Client', 'HytaleClient.exe')); + } else if (process.platform === 'darwin') { + candidates.push(path.join(gameLatest, 'Client', 'Hytale.app', 'Contents', 'MacOS', 'HytaleClient')); + candidates.push(path.join(gameLatest, 'Client', 'HytaleClient')); + } else { + candidates.push(path.join(gameLatest, 'Client', 'HytaleClient')); + } + return candidates; +} + +function findClientPath(gameLatest) { + const candidates = getClientCandidates(gameLatest); + for (const candidate of candidates) { + if (fs.existsSync(candidate)) { + return candidate; + } + } + return null; +} + +function findUserDataPath(gameLatest) { + const candidates = []; + + candidates.push(path.join(gameLatest, 'Client', 'UserData')); + + candidates.push(path.join(gameLatest, 'Client', 'Hytale.app', 'Contents', 'UserData')); + candidates.push(path.join(gameLatest, 'Hytale.app', 'Contents', 'UserData')); + candidates.push(path.join(gameLatest, 'UserData')); + + candidates.push(path.join(gameLatest, 'Client', 'UserData')); + + for (const candidate of candidates) { + if (fs.existsSync(candidate)) { + return candidate; + } + } + + let defaultPath; + if (process.platform === 'darwin') { + defaultPath = path.join(gameLatest, 'Client', 'UserData'); + } else { + defaultPath = path.join(gameLatest, 'Client', 'UserData'); + } + + if (!fs.existsSync(defaultPath)) { + fs.mkdirSync(defaultPath, { recursive: true }); + } + + return defaultPath; +} + +function findUserDataRecursive(gameLatest) { + function searchDirectory(dir) { + try { + const items = fs.readdirSync(dir, { withFileTypes: true }); + + for (const item of items) { + if (item.isDirectory()) { + const fullPath = path.join(dir, item.name); + + if (item.name === 'UserData') { + return fullPath; + } + + const found = searchDirectory(fullPath); + if (found) { + return found; + } + } + } + } catch (error) { + } + + return null; + } + + if (!fs.existsSync(gameLatest)) { + return null; + } + + const found = searchDirectory(gameLatest); + return found; +} + +async function getModsPath(customInstallPath = null) { + try { + let installPath = customInstallPath; + + if (!installPath) { + const configFile = path.join(DEFAULT_APP_DIR, 'config.json'); + if (fs.existsSync(configFile)) { + const config = JSON.parse(fs.readFileSync(configFile, 'utf8')); + installPath = config.installPath || ''; + } + } + + if (!installPath) { + const localAppData = process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local'); + installPath = path.join(localAppData, 'HytaleF2P'); + } else { + installPath = path.join(installPath, 'HytaleF2P'); + } + + const gameLatest = path.join(installPath, 'release', 'package', 'game', 'latest'); + + const userDataPath = findUserDataPath(gameLatest); + + const modsPath = path.join(userDataPath, 'Mods'); + const disabledModsPath = path.join(userDataPath, 'DisabledMods'); + + if (!fs.existsSync(modsPath)) { + fs.mkdirSync(modsPath, { recursive: true }); + } + if (!fs.existsSync(disabledModsPath)) { + fs.mkdirSync(disabledModsPath, { recursive: true }); + } + + return modsPath; + } catch (error) { + console.error('Error getting mods path:', error); + throw error; + } +} + +module.exports = { + getAppDir, + getResolvedAppDir, + expandHome, + APP_DIR, + CACHE_DIR, + TOOLS_DIR, + GAME_DIR, + JRE_DIR, + PLAYER_ID_FILE, + getClientCandidates, + findClientPath, + findUserDataPath, + findUserDataRecursive, + getModsPath +}; diff --git a/backend/launcher.js b/backend/launcher.js index f7692c3..e7deed7 100644 --- a/backend/launcher.js +++ b/backend/launcher.js @@ -1,2192 +1,8 @@ -const fs = require('fs'); -const path = require('path'); -const os = require('os'); -const { exec, execFile, spawn } = require('child_process'); -const { promisify } = require('util'); -const axios = require('axios'); -const AdmZip = require('adm-zip'); -const { v4: uuidv4 } = require('uuid'); -const crypto = require('crypto'); -const logger = require('./logger'); +// Main launcher module - orchestrates all launcher functionality +// This file serves as the main entry point and re-exports all necessary functions -const execAsync = promisify(exec); -const execFileAsync = promisify(execFile); -const JAVA_EXECUTABLE = 'java' + (process.platform === 'win32' ? '.exe' : ''); - -function isWaylandSession() { - if (process.platform !== 'linux') { - return false; - } - - const sessionType = process.env.XDG_SESSION_TYPE; - if (sessionType && sessionType.toLowerCase() === 'wayland') { - return true; - } - - if (process.env.WAYLAND_DISPLAY) { - return true; - } - - try { - const execSync = require('child_process').execSync; - const sessionId = process.env.XDG_SESSION_ID; - if (sessionId) { - const output = execSync(`loginctl show-session ${sessionId} -p Type`, { encoding: 'utf8' }); - if (output && output.toLowerCase().includes('wayland')) { - return true; - } - } - } catch (err) { - } - - return false; -} - -function setupWaylandEnvironment() { - if (process.platform !== 'linux') { - return {}; - } - - if (!isWaylandSession()) { - console.log('Detected X11 session, using default environment'); - return {}; - } - - console.log('Detected Wayland session, configuring environment...'); - - const envVars = { - SDL_VIDEODRIVER: 'wayland', - GDK_BACKEND: 'wayland', - QT_QPA_PLATFORM: 'wayland', - MOZ_ENABLE_WAYLAND: '1', - _JAVA_AWT_WM_NONREPARENTING: '1' - }; - - envVars.ELECTRON_OZONE_PLATFORM_HINT = 'wayland'; - - console.log('Wayland environment variables:', envVars); - return envVars; -} - -function getAppDir() { - const home = os.homedir(); - if (process.platform === 'win32') { - return path.join(home, 'AppData', 'Local', 'HytaleF2P'); - } else if (process.platform === 'darwin') { - return path.join(home, 'Library', 'Application Support', 'HytaleF2P'); - } else { - return path.join(home, '.hytalef2p'); - } -} - -const DEFAULT_APP_DIR = getAppDir(); -const CONFIG_FILE = path.join(DEFAULT_APP_DIR, 'config.json'); - -function getResolvedAppDir(customPath) { - if (customPath && customPath.trim()) { - return path.join(customPath.trim(), 'HytaleF2P'); - } - try { - if (fs.existsSync(CONFIG_FILE)) { - const config = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); - if (config.installPath && config.installPath.trim()) { - return path.join(config.installPath.trim(), 'HytaleF2P'); - } - } - } catch (err) { - } - return DEFAULT_APP_DIR; -} - -const APP_DIR = DEFAULT_APP_DIR; -const CACHE_DIR = path.join(APP_DIR, 'cache'); -const TOOLS_DIR = path.join(APP_DIR, 'butler'); -const GAME_DIR = path.join(APP_DIR, 'release', 'package', 'game', 'latest'); -const JRE_DIR = path.join(APP_DIR, 'release', 'package', 'jre', 'latest'); -const PLAYER_ID_FILE = path.join(APP_DIR, 'player_id.json'); - -function getOrCreatePlayerId() { - try { - if (!fs.existsSync(APP_DIR)) { - fs.mkdirSync(APP_DIR, { recursive: true }); - } - - if (fs.existsSync(PLAYER_ID_FILE)) { - const data = JSON.parse(fs.readFileSync(PLAYER_ID_FILE, 'utf8')); - if (data.playerId) { - return data.playerId; - } - } - - const newPlayerId = uuidv4(); - fs.writeFileSync(PLAYER_ID_FILE, JSON.stringify({ - playerId: newPlayerId, - createdAt: new Date().toISOString() - }, null, 2)); - - return newPlayerId; - } catch (error) { - console.error('Error managing player ID:', error); - return uuidv4(); - } -} - -function expandHome(inputPath) { - if (!inputPath) { - return inputPath; - } - if (inputPath === '~') { - return os.homedir(); - } - if (inputPath.startsWith('~/') || inputPath.startsWith('~\\')) { - return path.join(os.homedir(), inputPath.slice(2)); - } - return inputPath; -} - -function loadConfig() { - try { - if (fs.existsSync(CONFIG_FILE)) { - return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); - } - } catch (err) { - console.log('Notice: could not load config:', err.message); - } - return {}; -} - -function saveConfig(update) { - try { - createFolders(); - const config = loadConfig(); - const next = { ...config, ...update }; - fs.writeFileSync(CONFIG_FILE, JSON.stringify(next, null, 2), 'utf8'); - } catch (err) { - console.log('Notice: could not save config:', err.message); - } -} - -async function findJavaOnPath(commandName = 'java') { - const lookupCmd = process.platform === 'win32' ? 'where' : 'which'; - try { - const { stdout } = await execFileAsync(lookupCmd, [commandName]); - const line = stdout.split(/\r?\n/).map(lineItem => lineItem.trim()).find(Boolean); - return line || null; - } catch (err) { - return null; - } -} - -async function getMacJavaHome() { - if (process.platform !== 'darwin') { - return null; - } - try { - const { stdout } = await execFileAsync('/usr/libexec/java_home'); - const home = stdout.trim(); - if (!home) { - return null; - } - return path.join(home, 'bin', JAVA_EXECUTABLE); - } catch (err) { - return null; - } -} - -async function resolveJavaPath(inputPath) { - const trimmed = (inputPath || '').trim(); - if (!trimmed) { - return null; - } - - const expanded = expandHome(trimmed); - if (fs.existsSync(expanded)) { - const stat = fs.statSync(expanded); - if (stat.isDirectory()) { - const candidate = path.join(expanded, 'bin', JAVA_EXECUTABLE); - return fs.existsSync(candidate) ? candidate : null; - } - return expanded; - } - - if (!path.isAbsolute(expanded)) { - return await findJavaOnPath(trimmed); - } - - return null; -} - -async function detectSystemJava() { - const envHome = process.env.JAVA_HOME; - if (envHome) { - const envJava = path.join(envHome, 'bin', JAVA_EXECUTABLE); - if (fs.existsSync(envJava)) { - return envJava; - } - } - - const macJava = await getMacJavaHome(); - if (macJava && fs.existsSync(macJava)) { - return macJava; - } - - const pathJava = await findJavaOnPath('java'); - if (pathJava && fs.existsSync(pathJava)) { - return pathJava; - } - - return null; -} - -async function getJavaDetection() { - const candidates = []; - const bundledJava = getBundledJavaPath() || path.join(JRE_DIR, 'bin', JAVA_EXECUTABLE); - - candidates.push({ - label: 'Bundled JRE', - path: bundledJava, - exists: fs.existsSync(bundledJava) - }); - - const javaHomeEnv = process.env.JAVA_HOME; - if (javaHomeEnv) { - const envJava = path.join(javaHomeEnv, 'bin', JAVA_EXECUTABLE); - candidates.push({ - label: 'JAVA_HOME', - path: envJava, - exists: fs.existsSync(envJava), - note: fs.existsSync(envJava) ? '' : 'Not found' - }); - } else { - candidates.push({ - label: 'JAVA_HOME', - path: '', - exists: false, - note: 'Not set' - }); - } - - if (process.platform === 'darwin') { - const macJava = await getMacJavaHome(); - if (macJava) { - candidates.push({ - label: 'java_home', - path: macJava, - exists: fs.existsSync(macJava), - note: fs.existsSync(macJava) ? '' : 'Not found' - }); - } else { - candidates.push({ - label: 'java_home', - path: '', - exists: false, - note: 'Not found' - }); - } - } - - const pathJava = await findJavaOnPath('java'); - if (pathJava) { - candidates.push({ - label: 'PATH', - path: pathJava, - exists: true - }); - } else { - candidates.push({ - label: 'PATH', - path: '', - exists: false, - note: 'java not found' - }); - } - - return { - javaPath: loadJavaPath(), - candidates - }; -} - -function getOS() { - if (process.platform === 'win32') return 'windows'; - if (process.platform === 'darwin') return 'darwin'; - if (process.platform === 'linux') return 'linux'; - return 'unknown'; -} - -function getArch() { - return process.arch === 'x64' ? 'amd64' : process.arch; -} - -function createFolders() { - const configDir = path.dirname(CONFIG_FILE); - if (!fs.existsSync(configDir)) { - fs.mkdirSync(configDir, { recursive: true }); - } -} - -async function downloadFile(url, dest, progressCallback) { - const response = await axios({ - method: 'GET', - url: url, - responseType: 'stream', - headers: { - 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', - 'Accept': '*/*', - 'Accept-Language': 'en-US,en;q=0.9', - 'Referer': 'https://launcher.hytale.com/' - } - }); - - const totalSize = parseInt(response.headers['content-length'], 10); - let downloaded = 0; - const startTime = Date.now(); - - const writer = fs.createWriteStream(dest); - - response.data.on('data', (chunk) => { - downloaded += chunk.length; - if (progressCallback && totalSize > 0) { - const percent = Math.min(100, Math.max(0, (downloaded / totalSize) * 100)); - const elapsed = (Date.now() - startTime) / 1000; - const speed = elapsed > 0 ? downloaded / elapsed : 0; - progressCallback(null, percent, speed, downloaded, totalSize); - } - }); - - response.data.pipe(writer); - - return new Promise((resolve, reject) => { - writer.on('finish', resolve); - writer.on('error', reject); - response.data.on('error', reject); - }); -} - -async function getLatestClientVersion() { - try { - console.log('Fetching latest client version from API...'); - const response = await axios.get('http://3.10.208.30:3002/api/version_client', { - timeout: 5000, - headers: { - 'User-Agent': 'Hytale-F2P-Launcher' - } - }); - - if (response.data && response.data.client_version) { - const version = response.data.client_version; - console.log(`Latest client version: ${version}`); - return version; - } else { - console.log('Warning: Invalid API response, falling back to default version'); - return '4.pwr'; - } - } catch (error) { - console.error('Error fetching client version:', error.message); - console.log('Warning: API unavailable, falling back to default version'); - return '4.pwr'; - } -} - -async function downloadAndReplaceHomePageUI(gameDir, progressCallback) { - try { - console.log('Downloading HomePage.ui from server...'); - - if (progressCallback) { - progressCallback('Downloading HomePage.ui...', null, null, null, null); - } - - const homeUIUrl = 'http://3.10.208.30:3002/api/HomeUI'; - const tempHomePath = path.join(path.dirname(gameDir), 'HomePage_temp.ui'); - - await downloadFile(homeUIUrl, tempHomePath); - - const existingHomePath = findHomePageUIPath(gameDir); - - if (existingHomePath && fs.existsSync(existingHomePath)) { - console.log('Found existing HomePage.ui at:', existingHomePath); - - const backupPath = existingHomePath + '.backup'; - if (!fs.existsSync(backupPath)) { - fs.copyFileSync(existingHomePath, backupPath); - console.log('Original HomePage.ui backed up'); - } - - fs.copyFileSync(tempHomePath, existingHomePath); - console.log('HomePage.ui replaced successfully'); - } else { - console.log('No existing HomePage.ui found, skipping replacement'); - } - - if (fs.existsSync(tempHomePath)) { - fs.unlinkSync(tempHomePath); - } - - if (progressCallback) { - progressCallback('HomePage.ui updated', null, null, null, null); - } - - return { success: true, updated: true }; - - } catch (error) { - console.error('Error downloading/replacing HomePage.ui:', error); - - const tempHomePath = path.join(path.dirname(gameDir), 'HomePage_temp.ui'); - if (fs.existsSync(tempHomePath)) { - fs.unlinkSync(tempHomePath); - } - - console.log('HomePage.ui update failed, continuing...'); - return { success: false, error: error.message }; - } -} - -function findHomePageUIPath(gameLatest) { - function searchDirectory(dir) { - try { - const items = fs.readdirSync(dir, { withFileTypes: true }); - - for (const item of items) { - if (item.isFile() && item.name === 'HomePage.ui') { - return path.join(dir, item.name); - } else if (item.isDirectory()) { - const found = searchDirectory(path.join(dir, item.name)); - if (found) { - return found; - } - } - } - } catch (error) { - } - - return null; - } - - if (!fs.existsSync(gameLatest)) { - return null; - } - - return searchDirectory(gameLatest); -} - -async function downloadAndReplaceLogo(gameDir, progressCallback) { - try { - console.log('Downloading Logo@2x.png from server...'); - - if (progressCallback) { - progressCallback('Downloading Logo@2x.png...', null, null, null, null); - } - - const logoUrl = 'http://3.10.208.30:3002/api/Logo'; - const tempLogoPath = path.join(path.dirname(gameDir), 'Logo@2x_temp.png'); - - await downloadFile(logoUrl, tempLogoPath); - - const existingLogoPath = findLogoPath(gameDir); - - if (existingLogoPath && fs.existsSync(existingLogoPath)) { - console.log('Found existing Logo@2x.png at:', existingLogoPath); - - const backupPath = existingLogoPath + '.backup'; - if (!fs.existsSync(backupPath)) { - fs.copyFileSync(existingLogoPath, backupPath); - console.log('Original Logo@2x.png backed up'); - } - - fs.copyFileSync(tempLogoPath, existingLogoPath); - console.log('Logo@2x.png replaced successfully'); - } else { - console.log('No existing Logo@2x.png found, skipping replacement'); - } - - if (fs.existsSync(tempLogoPath)) { - fs.unlinkSync(tempLogoPath); - } - - if (progressCallback) { - progressCallback('Logo@2x.png updated', null, null, null, null); - } - - return { success: true, updated: true }; - - } catch (error) { - console.error('Error downloading/replacing Logo@2x.png:', error); - - const tempLogoPath = path.join(path.dirname(gameDir), 'Logo@2x_temp.png'); - if (fs.existsSync(tempLogoPath)) { - fs.unlinkSync(tempLogoPath); - } - - console.log('Logo@2x.png update failed, continuing...'); - return { success: false, error: error.message }; - } -} - -function findLogoPath(gameLatest) { - function searchDirectory(dir) { - try { - const items = fs.readdirSync(dir, { withFileTypes: true }); - - for (const item of items) { - if (item.isFile() && item.name === 'Logo@2x.png') { - return path.join(dir, item.name); - } else if (item.isDirectory()) { - const found = searchDirectory(path.join(dir, item.name)); - if (found) { - return found; - } - } - } - } catch (error) { - } - - return null; - } - - if (!fs.existsSync(gameLatest)) { - return null; - } - - return searchDirectory(gameLatest); -} - -async function getMultiClientVersion() { - try { - console.log('Fetching Multiplayer version from API...'); - const response = await axios.get('http://3.10.208.30:3002/api/multi', { - timeout: 5000, - headers: { - 'User-Agent': 'Hytale-F2P-Launcher' - } - }); - - if (response.data && response.data.multi_version) { - const version = response.data.multi_version; - console.log(`Multiplayer version: ${version}`); - return version; - } else { - console.log('Warning: Invalid multi API response'); - return null; - } - } catch (error) { - console.error('Error fetching Multiplayer version:', error.message); - console.log('Multiplayer not available'); - return null; - } -} - -async function getInstalledClientVersion() { - try { - console.log('Fetching installed client version from API...'); - const response = await axios.get('http://3.10.208.30:3002/api/clientCheck', { - timeout: 5000, - headers: { - 'User-Agent': 'Hytale-F2P-Launcher' - } - }); - - if (response.data && response.data.client_version) { - const version = response.data.client_version; - console.log(`Installed client version: ${version}`); - return version; - } else { - console.log('Warning: Invalid clientCheck API response'); - return null; - } - } catch (error) { - console.error('Error fetching installed client version:', error.message); - console.log('Warning: clientCheck API unavailable'); - return null; - } -} - -async function downloadMultiClient(gameDir, progressCallback) { - try { - if (process.platform !== 'win32') { - console.log('Multiplayer-client is only available for Windows'); - return { success: false, reason: 'Platform not supported' }; - } - - const clientPath = findClientPath(gameDir); - if (!clientPath) { - throw new Error('Game client not found. Install game first.'); - } - - console.log('Downloading Multiplayer from server...'); - if (progressCallback) { - progressCallback('Downloading Multiplayer...', null, null, null, null); - } - - const clientUrl = 'http://3.10.208.30:3002/client'; - const tempClientPath = path.join(path.dirname(clientPath), 'HytaleClient_temp.exe'); - - await downloadFile(clientUrl, tempClientPath, progressCallback); - - const backupPath = path.join(path.dirname(clientPath), 'HytaleClient_original.exe'); - if (!fs.existsSync(backupPath)) { - fs.copyFileSync(clientPath, backupPath); - console.log('Original client backed up'); - } - - fs.renameSync(tempClientPath, clientPath); - - if (progressCallback) { - progressCallback('Multiplayer installed', 100, null, null, null); - } - console.log('Multiplayer installed successfully'); - - return { success: true, installed: true }; - - } catch (error) { - console.error('Error installing Multiplayer:', error); - throw new Error(`Failed to install Multiplayer: ${error.message}`); - } -} - -async function checkAndInstallMultiClient(gameDir, progressCallback) { - try { - if (process.platform !== 'win32') { - console.log('Multiplayer check skipped (Windows only)'); - return { success: true, skipped: true, reason: 'Windows only' }; - } - - console.log('Checking for Multiplayer availability...'); - - const [clientVersion, multiVersion] = await Promise.all([ - getLatestClientVersion(), - getMultiClientVersion() - ]); - - if (!multiVersion) { - console.log('Multiplayer not available'); - return { success: true, skipped: true, reason: 'Multiplayer not available' }; - } - - if (clientVersion === multiVersion) { - console.log(`Versions match (${clientVersion}), installing Multiplayer...`); - return await downloadMultiClient(gameDir, progressCallback); - } else { - console.log(`Version mismatch: client=${clientVersion}, multi=${multiVersion}`); - return { success: true, skipped: true, reason: 'Version mismatch' }; - } - - } catch (error) { - console.error('Error checking Multiplayer:', error); - return { success: false, error: error.message }; - } -} - -async function installButler(toolsDir = TOOLS_DIR) { - if (!fs.existsSync(toolsDir)) { - fs.mkdirSync(toolsDir, { recursive: true }); - } - - const butlerName = process.platform === 'win32' ? 'butler.exe' : 'butler'; - const butlerPath = path.join(toolsDir, butlerName); - const zipPath = path.join(toolsDir, 'butler.zip'); - - if (fs.existsSync(butlerPath)) { - return butlerPath; - } - - let urls = []; - const osName = getOS(); - const arch = getArch(); - if (osName === 'windows') { - urls = ['https://broth.itch.zone/butler/windows-amd64/LATEST/archive/default']; - } else if (osName === 'darwin') { - if (arch === 'arm64') { - urls = [ - 'https://broth.itch.zone/butler/darwin-arm64/LATEST/archive/default', - 'https://broth.itch.zone/butler/darwin-amd64/LATEST/archive/default' - ]; - } else { - urls = ['https://broth.itch.zone/butler/darwin-amd64/LATEST/archive/default']; - } - } else if (osName === 'linux') { - urls = ['https://broth.itch.zone/butler/linux-amd64/LATEST/archive/default']; - } else { - throw new Error('Operating system not supported'); - } - - console.log('Fetching Butler tool...'); - let lastError = null; - for (const url of urls) { - try { - await downloadFile(url, zipPath); - lastError = null; - break; - } catch (error) { - lastError = error; - } - } - if (lastError) { - throw lastError; - } - - console.log('Unpacking Butler...'); - const zip = new AdmZip(zipPath); - zip.extractAllTo(toolsDir, true); - - if (process.platform !== 'win32') { - fs.chmodSync(butlerPath, 0o755); - } - - try { - fs.unlinkSync(zipPath); - } catch (err) { - console.log('Notice: could not delete butler.zip'); - } - - return butlerPath; -} - -async function updateGameFiles(newVersion, progressCallback, gameDir = GAME_DIR, toolsDir = TOOLS_DIR, cacheDir = CACHE_DIR) { - let tempUpdateDir; - try { - if (progressCallback) { - progressCallback('Updating game files...', 0, null, null, null); - } - console.log(`Updating game files to version: ${newVersion}`); - - tempUpdateDir = path.join(gameDir, '..', 'temp_update'); - - if (fs.existsSync(tempUpdateDir)) { - fs.rmSync(tempUpdateDir, { recursive: true, force: true }); - } - fs.mkdirSync(tempUpdateDir, { recursive: true }); - - if (progressCallback) { - progressCallback('Downloading new game version...', 10, null, null, null); - } - - const pwrFile = await downloadPWR('release', newVersion, progressCallback, cacheDir); - - if (progressCallback) { - progressCallback('Extracting new files...', 50, null, null, null); - } - - await applyPWR(pwrFile, progressCallback, tempUpdateDir, toolsDir); - - if (progressCallback) { - progressCallback('Replacing game files...', 80, null, null, null); - } - - let userDataBackup = null; - const userDataPath = findUserDataRecursive(gameDir); - - if (userDataPath && fs.existsSync(userDataPath)) { - userDataBackup = path.join(gameDir, '..', 'UserData_backup_' + Date.now()); - console.log(`Backing up UserData from ${userDataPath} to: ${userDataBackup}`); - - function copyRecursive(src, dest) { - const stat = fs.statSync(src); - if (stat.isDirectory()) { - if (!fs.existsSync(dest)) { - fs.mkdirSync(dest, { recursive: true }); - } - const files = fs.readdirSync(src); - for (const file of files) { - copyRecursive(path.join(src, file), path.join(dest, file)); - } - } else { - fs.copyFileSync(src, dest); - } - } - - copyRecursive(userDataPath, userDataBackup); - } else { - console.log('No UserData folder found in game directory'); - } - - if (fs.existsSync(gameDir)) { - console.log('Removing old game files...'); - fs.rmSync(gameDir, { recursive: true, force: true }); - } - - fs.renameSync(tempUpdateDir, gameDir); - - const multiResult = await checkAndInstallMultiClient(gameDir, progressCallback); - console.log('Multiplayer-client check result after update:', multiResult); - - const homeUIResult = await downloadAndReplaceHomePageUI(gameDir, progressCallback); - console.log('HomePage.ui update result after update:', homeUIResult); - - const logoResult = await downloadAndReplaceLogo(gameDir, progressCallback); - console.log('Logo@2x.png update result after update:', logoResult); - - if (userDataBackup && fs.existsSync(userDataBackup)) { - const newUserDataPath = findUserDataPath(gameDir); - const userDataParent = path.dirname(newUserDataPath); - - if (!fs.existsSync(userDataParent)) { - fs.mkdirSync(userDataParent, { recursive: true }); - } - - console.log(`Restoring UserData to: ${newUserDataPath}`); - - function copyRecursive(src, dest) { - const stat = fs.statSync(src); - if (stat.isDirectory()) { - if (!fs.existsSync(dest)) { - fs.mkdirSync(dest, { recursive: true }); - } - const files = fs.readdirSync(src); - for (const file of files) { - copyRecursive(path.join(src, file), path.join(dest, file)); - } - } else { - fs.copyFileSync(src, dest); - } - } - - copyRecursive(userDataBackup, newUserDataPath); - } - - console.log(`Game files updated successfully to version: ${newVersion}`); - - if (userDataBackup && fs.existsSync(userDataBackup)) { - try { - fs.rmSync(userDataBackup, { recursive: true, force: true }); - console.log('UserData backup cleaned up'); - } catch (cleanupError) { - console.warn('Could not clean up UserData backup:', cleanupError.message); - } - } - - console.log('Waiting for file system sync...'); - await new Promise(resolve => setTimeout(resolve, 2000)); - - if (progressCallback) { - progressCallback('Game update completed', 100, null, null, null); - } - - return { success: true, updated: true, version: newVersion }; - } catch (error) { - console.error('Error updating game files:', error); - - if (userDataBackup && fs.existsSync(userDataBackup)) { - try { - fs.rmSync(userDataBackup, { recursive: true, force: true }); - console.log('UserData backup cleaned up after error'); - } catch (cleanupError) { - console.warn('Could not clean up UserData backup:', cleanupError.message); - } - } - - if (tempUpdateDir && fs.existsSync(tempUpdateDir)) { - fs.rmSync(tempUpdateDir, { recursive: true, force: true }); - } - - throw new Error(`Failed to update game files: ${error.message}`); - } -} - -async function downloadPWR(version = 'release', fileName = '4.pwr', progressCallback, cacheDir = CACHE_DIR) { - const osName = getOS(); - const arch = getArch(); - const url = `https://game-patches.hytale.com/patches/${osName}/${arch}/${version}/0/${fileName}`; - - const dest = path.join(cacheDir, fileName); - - if (fs.existsSync(dest)) { - console.log('PWR file found in cache:', dest); - return dest; - } - - console.log('Fetching PWR patch file:', url); - await downloadFile(url, dest, progressCallback); - console.log('PWR saved to:', dest); - - return dest; -} - -async function applyPWR(pwrFile, progressCallback, gameDir = GAME_DIR, toolsDir = TOOLS_DIR) { - const butlerPath = await installButler(toolsDir); - const gameLatest = gameDir; - const stagingDir = path.join(gameLatest, 'staging-temp'); - - const clientPath = findClientPath(gameLatest); - - if (clientPath) { - console.log('Game files detected, skipping patch installation.'); - return; - } - - if (!fs.existsSync(gameLatest)) { - fs.mkdirSync(gameLatest, { recursive: true }); - } - if (!fs.existsSync(stagingDir)) { - fs.mkdirSync(stagingDir, { recursive: true }); - } - - if (progressCallback) { - progressCallback('Installing game patch...', null, null, null, null); - } - - console.log('Installing game patch...'); - - if (!fs.existsSync(butlerPath)) { - throw new Error(`Butler tool not found at: ${butlerPath}`); - } - - if (!fs.existsSync(pwrFile)) { - throw new Error(`PWR file not found at: ${pwrFile}`); - } - - const args = [ - 'apply', - '--staging-dir', - stagingDir, - pwrFile, - gameLatest - ]; - - try { - await new Promise((resolve, reject) => { - const child = execFile(butlerPath, args, { - maxBuffer: 1024 * 1024 * 10, - timeout: 600000 - }, (error, stdout, stderr) => { - if (error) { - console.error('Butler stderr:', stderr); - console.error('Butler stdout:', stdout); - reject(new Error(`Patch installation failed: ${error.message}${stderr ? '\n' + stderr : ''}`)); - } else { - resolve(); - } - }); - }); - } catch (error) { - throw error; - } - - if (fs.existsSync(stagingDir)) { - fs.rmSync(stagingDir, { recursive: true, force: true }); - } - - if (progressCallback) { - progressCallback('Installation complete', null, null, null, null); - } - console.log('Installation complete'); -} - -async function downloadJRE(progressCallback, cacheDir = CACHE_DIR, jreDir = JRE_DIR) { - if (!fs.existsSync(cacheDir)) { - fs.mkdirSync(cacheDir, { recursive: true }); - } - - const osName = getOS(); - const arch = getArch(); - - const bundledJava = getBundledJavaPath(jreDir); - if (bundledJava) { - console.log('Java runtime found, skipping download'); - return; - } - - console.log('Requesting Java runtime information...'); - const response = await axios.get('https://launcher.hytale.com/version/release/jre.json', { - headers: { - 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', - 'Accept': 'application/json', - 'Accept-Language': 'en-US,en;q=0.9' - } - }); - const jreData = response.data; - - const osData = jreData.download_url[osName]; - if (!osData) { - throw new Error(`Java runtime unavailable for platform: ${osName}`); - } - - const platform = osData[arch]; - if (!platform) { - throw new Error(`Java runtime unavailable for architecture ${arch} on ${osName}`); - } - - const fileName = path.basename(platform.url); - const cacheFile = path.join(cacheDir, fileName); - - if (!fs.existsSync(cacheFile)) { - if (progressCallback) { - progressCallback('Fetching Java runtime...', null, null, null, null); - } - console.log('Fetching Java runtime...'); - await downloadFile(platform.url, cacheFile, progressCallback); - console.log('Download finished'); - } - - if (progressCallback) { - progressCallback('Validating files...', null, null, null, null); - } - console.log('Validating files...'); - const fileBuffer = fs.readFileSync(cacheFile); - const hashSum = crypto.createHash('sha256'); - hashSum.update(fileBuffer); - const hex = hashSum.digest('hex'); - - if (hex !== platform.sha256) { - fs.unlinkSync(cacheFile); - throw new Error(`File validation failed: expected ${platform.sha256} but got ${hex}`); - } - - if (progressCallback) { - progressCallback('Unpacking Java runtime...', null, null, null, null); - } - console.log('Unpacking Java runtime...'); - await extractJRE(cacheFile, jreDir); - - if (process.platform !== 'win32') { - const javaCandidates = [ - path.join(jreDir, 'bin', JAVA_EXECUTABLE), - path.join(jreDir, 'Contents', 'Home', 'bin', JAVA_EXECUTABLE) - ]; - for (const javaPath of javaCandidates) { - if (fs.existsSync(javaPath)) { - fs.chmodSync(javaPath, 0o755); - } - } - } - - flattenJREDir(jreDir); - - try { - fs.unlinkSync(cacheFile); - } catch (err) { - console.log('Notice: could not delete cached Java files:', err.message); - } - - console.log('Java runtime ready'); -} - -async function extractJRE(archivePath, destDir) { - if (fs.existsSync(destDir)) { - fs.rmSync(destDir, { recursive: true, force: true }); - } - fs.mkdirSync(destDir, { recursive: true }); - - if (archivePath.endsWith('.zip')) { - return extractZip(archivePath, destDir); - } else if (archivePath.endsWith('.tar.gz')) { - return extractTarGz(archivePath, destDir); - } else { - throw new Error(`Archive type not supported: ${archivePath}`); - } -} - -function extractZip(zipPath, dest) { - const zip = new AdmZip(zipPath); - const entries = zip.getEntries(); - - for (const entry of entries) { - const entryPath = path.join(dest, entry.entryName); - - const resolvedPath = path.resolve(entryPath); - const resolvedDest = path.resolve(dest); - if (!resolvedPath.startsWith(resolvedDest)) { - throw new Error(`Invalid file path detected: ${entryPath}`); - } - - if (entry.isDirectory) { - fs.mkdirSync(entryPath, { recursive: true }); - } else { - fs.mkdirSync(path.dirname(entryPath), { recursive: true }); - fs.writeFileSync(entryPath, entry.getData()); - if (process.platform !== 'win32') { - fs.chmodSync(entryPath, entry.header.attr >>> 16); - } - } - } -} - -function extractTarGz(tarGzPath, dest) { - const tar = require('tar'); - return tar.extract({ - file: tarGzPath, - cwd: dest, - strip: 0 - }); -} - -function flattenJREDir(jreLatest) { - try { - const entries = fs.readdirSync(jreLatest, { withFileTypes: true }); - - if (entries.length !== 1 || !entries[0].isDirectory()) { - return; - } - - const nested = path.join(jreLatest, entries[0].name); - const files = fs.readdirSync(nested, { withFileTypes: true }); - - for (const file of files) { - const oldPath = path.join(nested, file.name); - const newPath = path.join(jreLatest, file.name); - fs.renameSync(oldPath, newPath); - } - - fs.rmSync(nested, { recursive: true, force: true }); - } catch (err) { - console.log('Notice: could not restructure Java directory:', err.message); - } -} - -function getBundledJavaPath(jreDir = JRE_DIR) { - const candidates = [ - path.join(jreDir, 'bin', JAVA_EXECUTABLE) - ]; - - if (process.platform === 'darwin') { - candidates.push(path.join(jreDir, 'Contents', 'Home', 'bin', JAVA_EXECUTABLE)); - } - - for (const candidate of candidates) { - if (fs.existsSync(candidate)) { - return candidate; - } - } - - return null; -} - -function getJavaExec(jreDir = JRE_DIR) { - const bundledJava = getBundledJavaPath(jreDir); - if (bundledJava) { - return bundledJava; - } - - console.log('Notice: Java runtime not found, using system default'); - return 'java'; -} - -function getClientCandidates(gameLatest) { - const candidates = []; - if (process.platform === 'win32') { - candidates.push(path.join(gameLatest, 'Client', 'HytaleClient.exe')); - } else if (process.platform === 'darwin') { - candidates.push(path.join(gameLatest, 'Client', 'Hytale.app', 'Contents', 'MacOS', 'HytaleClient')); - candidates.push(path.join(gameLatest, 'Client', 'HytaleClient')); - } else { - candidates.push(path.join(gameLatest, 'Client', 'HytaleClient')); - } - return candidates; -} - -function findClientPath(gameLatest) { - const candidates = getClientCandidates(gameLatest); - for (const candidate of candidates) { - if (fs.existsSync(candidate)) { - return candidate; - } - } - return null; -} - -function isGameInstalled() { - const appDir = getResolvedAppDir(); - const gameDir = path.join(appDir, 'release', 'package', 'game', 'latest'); - const clientPath = findClientPath(gameDir); - return clientPath !== null; -} - -function isFirstLaunch() { - const config = loadConfig(); - - if ('hasLaunchedBefore' in config) { - return !config.hasLaunchedBefore; - } - - const hasUserData = config.installPath || config.username || config.javaPath || - config.chatUsername || config.userUuids || - Object.keys(config).length > 0; - - if (!hasUserData) { - return true; - } - - return true; -} - -function markAsLaunched() { - saveConfig({ hasLaunchedBefore: true, firstLaunchDate: new Date().toISOString() }); -} - -function checkExistingGameInstallation() { - try { - const config = loadConfig(); - - if (!config.installPath || !config.installPath.trim()) { - return null; - } - - const installPath = config.installPath.trim(); - const gameDir = path.join(installPath, 'HytaleF2P', 'release', 'package', 'game', 'latest'); - - if (!fs.existsSync(gameDir)) { - return null; - } - - const clientPath = findClientPath(gameDir); - if (!clientPath) { - return null; - } - - const userDataPath = findUserDataRecursive(gameDir); - - return { - gameDir: gameDir, - clientPath: clientPath, - userDataPath: userDataPath, - installPath: installPath, - hasUserData: userDataPath && fs.existsSync(userDataPath) - }; - } catch (error) { - console.error('Error checking existing game installation:', error); - return null; - } -} - -async function proposeGameUpdate(existingGame, progressCallback) { - try { - console.log('Proposing game update for existing installation...'); - - if (progressCallback) { - progressCallback('Checking for game updates...', 0, null, null, null); - } - - const [installedVersion, latestVersion] = await Promise.all([ - getInstalledClientVersion(), - getLatestClientVersion() - ]); - - console.log(`Existing installation - Installed: ${installedVersion}, Latest: ${latestVersion}`); - - const customAppDir = path.join(existingGame.installPath, 'HytaleF2P'); - const customCacheDir = path.join(customAppDir, 'cache'); - const customToolsDir = path.join(customAppDir, 'butler'); - - [customCacheDir, customToolsDir].forEach(dir => { - if (!fs.existsSync(dir)) { - fs.mkdirSync(dir, { recursive: true }); - } - }); - - if (progressCallback) { - progressCallback('Updating existing game installation...', 20, null, null, null); - } - - await updateGameFiles(latestVersion, progressCallback, existingGame.gameDir, customToolsDir, customCacheDir); - - if (progressCallback) { - progressCallback('Game update completed successfully', 100, null, null, null); - } - - console.log('Existing game installation updated successfully'); - return { success: true, updated: true }; - - } catch (error) { - console.error('Error updating existing game:', error); - if (progressCallback) { - progressCallback(`Update failed: ${error.message}`, -1, null, null, null); - } - throw error; - } -} - -async function handleFirstLaunchCheck(progressCallback) { - try { - const config = loadConfig(); - - if (config.hasLaunchedBefore === true) { - return { isFirstLaunch: false, needsUpdate: false }; - } - - console.log('First launch detected, checking for existing game installation...'); - - const existingGame = checkExistingGameInstallation(); - - if (!existingGame) { - console.log('No existing game installation found'); - - const hasUserData = config.installPath || config.username || config.javaPath || - config.chatUsername || config.userUuids || - Object.keys(config).length > 0; - - if (hasUserData) { - console.log('Detected existing user data but no game, marking as launched'); - markAsLaunched(); - return { isFirstLaunch: false, needsUpdate: false }; - } else { - markAsLaunched(); - return { isFirstLaunch: true, needsUpdate: false, existingGame: null }; - } - } - - console.log('Existing game installation found:', { - gameDir: existingGame.gameDir, - hasUserData: existingGame.hasUserData - }); - - return { - isFirstLaunch: true, - needsUpdate: true, - existingGame: existingGame - }; - - } catch (error) { - console.error('Error in first launch check:', error); - markAsLaunched(); - return { isFirstLaunch: true, needsUpdate: false, error: error.message }; - } -} - -async function uninstallGame() { - const appDir = getResolvedAppDir(); - - if (!fs.existsSync(appDir)) { - throw new Error('Game is not installed'); - } - - try { - fs.rmSync(appDir, { recursive: true, force: true }); - console.log('Game uninstalled successfully - removed entire HytaleF2P folder'); - - if (fs.existsSync(CONFIG_FILE)) { - const config = loadConfig(); - delete config.installPath; - fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf8'); - } - } catch (error) { - throw new Error(`Failed to uninstall game: ${error.message}`); - } -} - -async function installGame(playerName = 'Player', progressCallback, javaPathOverride, installPathOverride) { - const customAppDir = getResolvedAppDir(installPathOverride); - const customCacheDir = path.join(customAppDir, 'cache'); - const customToolsDir = path.join(customAppDir, 'butler'); - const customGameDir = path.join(customAppDir, 'release', 'package', 'game', 'latest'); - const customJreDir = path.join(customAppDir, 'release', 'package', 'jre', 'latest'); - const userDataDir = path.join(customGameDir, 'Client', 'UserData'); - - [customAppDir, customCacheDir, customToolsDir].forEach(dir => { - if (!fs.existsSync(dir)) { - fs.mkdirSync(dir, { recursive: true }); - } - }); - - if (!fs.existsSync(userDataDir)) { - fs.mkdirSync(userDataDir, { recursive: true }); - } - - saveUsername(playerName); - if (installPathOverride) { - saveInstallPath(installPathOverride); - } - - const gameLatest = customGameDir; - let clientPath = findClientPath(gameLatest); - - if (clientPath) { - if (progressCallback) { - progressCallback('Game already installed', 100, null, null, null); - } - console.log('Game is already installed'); - return { success: true, alreadyInstalled: true }; - } - - const configuredJava = (javaPathOverride !== undefined && javaPathOverride !== null - ? javaPathOverride - : loadJavaPath() || '').trim(); - let javaBin = null; - - if (configuredJava) { - javaBin = await resolveJavaPath(configuredJava); - if (!javaBin) { - throw new Error(`Configured Java path not found: ${configuredJava}`); - } - } else { - try { - await downloadJRE(progressCallback, customCacheDir, customJreDir); - } catch (error) { - const fallback = await detectSystemJava(); - if (fallback) { - javaBin = fallback; - } else { - throw error; - } - } - - if (!javaBin) { - javaBin = getJavaExec(customJreDir); - } - } - - if (progressCallback) { - progressCallback('Fetching game files...', null, null, null, null); - } - console.log('Installing game files...'); - - const latestVersion = await getLatestClientVersion(); - const pwrFile = await downloadPWR('release', latestVersion, progressCallback, customCacheDir); - await applyPWR(pwrFile, progressCallback, customGameDir, customToolsDir); - - const multiResult = await checkAndInstallMultiClient(customGameDir, progressCallback); - console.log('Multiplayer check result:', multiResult); - - const homeUIResult = await downloadAndReplaceHomePageUI(customGameDir, progressCallback); - console.log('HomePage.ui update result after installation:', homeUIResult); - - const logoResult = await downloadAndReplaceLogo(customGameDir, progressCallback); - console.log('Logo@2x.png update result after installation:', logoResult); - - if (progressCallback) { - progressCallback('Installation complete', 100, null, null, null); - } - console.log('Game installation completed successfully'); - - return { - success: true, - installed: true, - multiClient: multiResult - }; -} - -async function launchGameWithVersionCheck(playerName = 'Player', progressCallback, javaPathOverride, installPathOverride) { - try { - if (progressCallback) { - progressCallback('Checking for updates...', 0, null, null, null); - } - - const [installedVersion, latestVersion] = await Promise.all([ - getInstalledClientVersion(), - getLatestClientVersion() - ]); - - console.log(`Installed version: ${installedVersion}, Latest version: ${latestVersion}`); - - let needsUpdate = false; - if (installedVersion && latestVersion && installedVersion !== latestVersion) { - needsUpdate = true; - console.log('Version mismatch detected, update required'); - } - - if (needsUpdate) { - if (progressCallback) { - progressCallback('Game update required, starting update process...', 10, null, null, null); - } - - const customAppDir = getResolvedAppDir(installPathOverride); - const customGameDir = path.join(customAppDir, 'release', 'package', 'game', 'latest'); - const customToolsDir = path.join(customAppDir, 'tools'); - const customCacheDir = path.join(customAppDir, 'cache'); - - try { - await updateGameFiles(latestVersion, progressCallback, customGameDir, customToolsDir, customCacheDir); - console.log('Game updated successfully, waiting before launch...'); - - if (progressCallback) { - progressCallback('Preparing game launch...', 90, null, null, null); - } - await new Promise(resolve => setTimeout(resolve, 3000)); - - } catch (updateError) { - console.error('Update failed:', updateError); - if (progressCallback) { - progressCallback(`Update failed: ${updateError.message}`, -1, null, null, null); - } - throw updateError; - } - } - - if (progressCallback) { - progressCallback('Launching game...', 80, null, null, null); - } - - return await launchGame(playerName, progressCallback, javaPathOverride, installPathOverride); - } catch (error) { - console.error('Error in version check and launch:', error); - if (progressCallback) { - progressCallback(`Error: ${error.message}`, -1, null, null, null); - } - throw error; - } -} - -async function launchGame(playerName = 'Player', progressCallback, javaPathOverride, installPathOverride) { - const customAppDir = getResolvedAppDir(installPathOverride); - const customGameDir = path.join(customAppDir, 'release', 'package', 'game', 'latest'); - const customJreDir = path.join(customAppDir, 'release', 'package', 'jre', 'latest'); - const userDataDir = path.join(customGameDir, 'Client', 'UserData'); - - const gameLatest = customGameDir; - let clientPath = findClientPath(gameLatest); - - if (!clientPath) { - throw new Error('Game is not installed. Please install the game first.'); - } - - saveUsername(playerName); - if (installPathOverride) { - saveInstallPath(installPathOverride); - } - - const configuredJava = (javaPathOverride !== undefined && javaPathOverride !== null - ? javaPathOverride - : loadJavaPath() || '').trim(); - let javaBin = null; - - if (configuredJava) { - javaBin = await resolveJavaPath(configuredJava); - if (!javaBin) { - throw new Error(`Configured Java path not found: ${configuredJava}`); - } - } else { - javaBin = getJavaExec(customJreDir); - - if (!getBundledJavaPath(customJreDir)) { - const fallback = await detectSystemJava(); - if (fallback) { - javaBin = fallback; - } else { - throw new Error('Java runtime not found. Please install the game first or configure Java path.'); - } - } - } - - if (process.platform === 'darwin') { - try { - const appBundle = path.join(gameLatest, 'Client', 'Hytale.app'); - const serverDir = path.join(gameLatest, 'Server'); - - const signPath = async (targetPath, deep = false) => { - await execAsync(`xattr -cr "${targetPath}"`).catch(() => {}); - const deepFlag = deep ? '--deep ' : ''; - await execAsync(`codesign --force ${deepFlag}--sign - "${targetPath}"`).catch(() => {}); - }; - - if (fs.existsSync(appBundle)) { - await signPath(appBundle, true); - console.log('Signed macOS app bundle'); - } else { - await signPath(path.dirname(clientPath), true); - console.log('Signed macOS client binary'); - } - - if (javaBin && fs.existsSync(javaBin)) { - let jreRoot = path.dirname(path.dirname(javaBin)); - if (jreRoot.endsWith('Home')) { - jreRoot = path.dirname(path.dirname(jreRoot)); - } - await signPath(jreRoot, true); - await signPath(javaBin, false); - console.log('Signed Java runtime'); - } - - if (fs.existsSync(serverDir)) { - await execAsync(`xattr -cr "${serverDir}"`).catch(() => {}); - await execAsync(`find "${serverDir}" -type f -perm +111 -exec codesign --force --sign - {} \\;`).catch(() => {}); - console.log('Signed server binaries'); - } - - if (javaBin && fs.existsSync(javaBin)) { - const javaWrapperPath = path.join(path.dirname(javaBin), 'java-wrapper'); - const wrapperScript = `#!/bin/bash -# Java wrapper for macOS - adds --disable-sentry to fix Sentry hang issue -REAL_JAVA="${javaBin}" -ARGS=("$@") -for i in "\${!ARGS[@]}"; do - if [[ "\${ARGS[$i]}" == *"HytaleServer.jar"* ]]; then - ARGS=("\${ARGS[@]:0:$((i+1))}" "--disable-sentry" "\${ARGS[@]:$((i+1))}") - break - fi -done -exec "$REAL_JAVA" "\${ARGS[@]}" -`; - fs.writeFileSync(javaWrapperPath, wrapperScript, { mode: 0o755 }); - await signPath(javaWrapperPath, false); - console.log('Created java wrapper with --disable-sentry fix'); - javaBin = javaWrapperPath; - } - } catch (signError) { - console.log('Notice: macOS signing step failed:', signError.message); - console.log('The game may still launch if Gatekeeper allows it'); - } - } - - const uuid = getUuidForUser(playerName); - const args = [ - '--app-dir', gameLatest, - '--java-exec', javaBin, - '--auth-mode', 'offline', - '--uuid', uuid, - '--name', playerName, - '--user-dir', userDataDir - ]; - - if (progressCallback) { - progressCallback('Starting game...', null, null, null, null); - } - console.log('Starting game...'); - console.log(`Command: "${clientPath}" ${args.join(' ')}`); - - const env = { ...process.env }; - - const waylandEnv = setupWaylandEnvironment(); - Object.assign(env, waylandEnv); - - try { - let spawnOptions = { - stdio: ['ignore', 'pipe', 'pipe'], - detached: true, - env: env - }; - - if (process.platform === 'win32') { - spawnOptions.shell = false; - spawnOptions.windowsHide = true; - } - - const child = spawn(clientPath, args, spawnOptions); - - console.log(`Game process started with PID: ${child.pid}`); - - let hasExited = false; - let outputReceived = false; - - child.stdout.on('data', (data) => { - outputReceived = true; - console.log(`Game output: ${data.toString().trim()}`); - }); - - child.stderr.on('data', (data) => { - outputReceived = true; - console.error(`Game error: ${data.toString().trim()}`); - }); - - child.on('error', (error) => { - hasExited = true; - console.error(`Failed to start game process: ${error.message}`); - if (progressCallback) { - progressCallback(`Failed to start game: ${error.message}`, -1, null, null, null); - } - }); - - child.on('exit', (code, signal) => { - hasExited = true; - if (code !== null) { - console.log(`Game process exited with code ${code}`); - if (code !== 0 && progressCallback) { - progressCallback(`Game exited with error code ${code}`, -1, null, null, null); - } - } else if (signal) { - console.log(`Game process terminated by signal ${signal}`); - } - }); - - setTimeout(() => { - if (!hasExited) { - console.log('Game appears to be running successfully'); - child.unref(); - if (progressCallback) { - progressCallback('Game launched successfully', 100, null, null, null); - } - } else if (!outputReceived) { - console.warn('Game process exited immediately with no output - possible issue with game files or dependencies'); - } - }, 3000); - - return { success: true, installed: true, launched: true, pid: child.pid }; - } catch (spawnError) { - console.error(`Error spawning game process: ${spawnError.message}`); - if (progressCallback) { - progressCallback(`Error launching game: ${spawnError.message}`, -1, null, null, null); - } - throw spawnError; - } -} - -function saveUsername(username) { - saveConfig({ username: username || 'Player' }); -} - -function loadUsername() { - const config = loadConfig(); - return config.username || 'Player'; -} - -function saveChatUsername(chatUsername) { - saveConfig({ chatUsername: chatUsername || '' }); -} - -function loadChatUsername() { - const config = loadConfig(); - return config.chatUsername || ''; -} - -function getUuidForUser(username) { - const config = loadConfig(); - const userUuids = config.userUuids || {}; - - if (userUuids[username]) { - return userUuids[username]; - } - - const newUuid = uuidv4(); - userUuids[username] = newUuid; - saveConfig({ userUuids }); - - return newUuid; -} - -function saveJavaPath(javaPath) { - const trimmed = (javaPath || '').trim(); - saveConfig({ javaPath: trimmed }); -} - -function loadJavaPath() { - const config = loadConfig(); - return config.javaPath || ''; -} - -function saveInstallPath(installPath) { - const trimmed = (installPath || '').trim(); - saveConfig({ installPath: trimmed }); -} - -function loadInstallPath() { - const config = loadConfig(); - return config.installPath || ''; -} - -async function getHytaleNews() { - try { - const response = await axios.get('https://launcher.hytale.com/launcher-feed/release/feed.json', { - headers: { - 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' - }, - timeout: 10000 - }); - - const articles = response.data.articles || []; - return articles.map(article => ({ - title: article.title || '', - description: article.description || '', - destUrl: article.dest_url || '', - imageUrl: article.image_url ? - (article.image_url.startsWith('http') ? - article.image_url : - `https://launcher.hytale.com/launcher-feed/release/${article.image_url}` - ) : '' - })); - } catch (error) { - console.error('Failed to fetch news:', error.message); - return []; - } -} - -function findUserDataPath(gameLatest) { - const candidates = []; - - candidates.push(path.join(gameLatest, 'Client', 'UserData')); - - candidates.push(path.join(gameLatest, 'Client', 'Hytale.app', 'Contents', 'UserData')); - candidates.push(path.join(gameLatest, 'Hytale.app', 'Contents', 'UserData')); - candidates.push(path.join(gameLatest, 'UserData')); - - candidates.push(path.join(gameLatest, 'Client', 'UserData')); - - for (const candidate of candidates) { - if (fs.existsSync(candidate)) { - return candidate; - } - } - - let defaultPath; - if (process.platform === 'darwin') { - defaultPath = path.join(gameLatest, 'Client', 'UserData'); - } else { - defaultPath = path.join(gameLatest, 'Client', 'UserData'); - } - - if (!fs.existsSync(defaultPath)) { - fs.mkdirSync(defaultPath, { recursive: true }); - } - - return defaultPath; -} - -function findUserDataRecursive(gameLatest) { - function searchDirectory(dir) { - try { - const items = fs.readdirSync(dir, { withFileTypes: true }); - - for (const item of items) { - if (item.isDirectory()) { - const fullPath = path.join(dir, item.name); - - if (item.name === 'UserData') { - return fullPath; - } - - const found = searchDirectory(fullPath); - if (found) { - return found; - } - } - } - } catch (error) { - } - - return null; - } - - if (!fs.existsSync(gameLatest)) { - return null; - } - - const found = searchDirectory(gameLatest); - return found; -} - -async function getModsPath(customInstallPath = null) { - try { - let installPath = customInstallPath; - - if (!installPath) { - if (fs.existsSync(CONFIG_FILE)) { - const config = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); - installPath = config.installPath || ''; - } - } - - if (!installPath) { - const localAppData = process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local'); - installPath = path.join(localAppData, 'HytaleF2P'); - } else { - installPath = path.join(installPath, 'HytaleF2P'); - } - - const gameLatest = path.join(installPath, 'release', 'package', 'game', 'latest'); - - const userDataPath = findUserDataPath(gameLatest); - - const modsPath = path.join(userDataPath, 'Mods'); - const disabledModsPath = path.join(userDataPath, 'DisabledMods'); - - if (!fs.existsSync(modsPath)) { - fs.mkdirSync(modsPath, { recursive: true }); - } - if (!fs.existsSync(disabledModsPath)) { - fs.mkdirSync(disabledModsPath, { recursive: true }); - } - - return modsPath; - } catch (error) { - console.error('Error getting mods path:', error); - throw error; - } -} - -function saveModsToConfig(mods) { - try { - let config = {}; - - if (fs.existsSync(CONFIG_FILE)) { - config = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); - } - - config.installedMods = mods; - - if (!fs.existsSync(path.dirname(CONFIG_FILE))) { - fs.mkdirSync(path.dirname(CONFIG_FILE), { recursive: true }); - } - - fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2)); - console.log('Mods saved to config.json'); - } catch (error) { - console.error('Error saving mods to config:', error); - } -} - -function loadModsFromConfig() { - try { - if (fs.existsSync(CONFIG_FILE)) { - const config = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); - return config.installedMods || []; - } - return []; - } catch (error) { - console.error('Error loading mods from config:', error); - return []; - } -} - -async function loadInstalledMods(modsPath) { - try { - const configMods = loadModsFromConfig(); - const modsMap = new Map(); - - configMods.forEach(mod => { - modsMap.set(mod.fileName, mod); - }); - - if (fs.existsSync(modsPath)) { - const files = fs.readdirSync(modsPath); - - for (const file of files) { - const filePath = path.join(modsPath, file); - const stats = fs.statSync(filePath); - - if (stats.isFile() && (file.endsWith('.jar') || file.endsWith('.zip'))) { - const configMod = modsMap.get(file); - - const modInfo = { - id: configMod?.id || generateModId(file), - name: configMod?.name || extractModName(file), - version: configMod?.version || extractVersion(file) || '1.0.0', - description: configMod?.description || 'Installed mod', - author: configMod?.author || 'Unknown', - enabled: true, - filePath: filePath, - fileName: file, - fileSize: configMod?.fileSize || stats.size, - dateInstalled: configMod?.dateInstalled || stats.birthtime || stats.mtime, - curseForgeId: configMod?.curseForgeId, - curseForgeFileId: configMod?.curseForgeFileId - }; - - modsMap.set(file, modInfo); - } - } - } - - const disabledModsPath = path.join(path.dirname(modsPath), 'DisabledMods'); - if (fs.existsSync(disabledModsPath)) { - const files = fs.readdirSync(disabledModsPath); - - for (const file of files) { - const filePath = path.join(disabledModsPath, file); - const stats = fs.statSync(filePath); - - if (stats.isFile() && (file.endsWith('.jar') || file.endsWith('.zip'))) { - const configMod = modsMap.get(file); - - const modInfo = { - id: configMod?.id || generateModId(file), - name: configMod?.name || extractModName(file), - version: configMod?.version || extractVersion(file) || '1.0.0', - description: configMod?.description || 'Disabled mod', - author: configMod?.author || 'Unknown', - enabled: false, - filePath: filePath, - fileName: file, - fileSize: configMod?.fileSize || stats.size, - dateInstalled: configMod?.dateInstalled || stats.birthtime || stats.mtime, - curseForgeId: configMod?.curseForgeId, - curseForgeFileId: configMod?.curseForgeFileId - }; - - modsMap.set(file, modInfo); - } - } - } - - return Array.from(modsMap.values()); - } catch (error) { - console.error('Error loading installed mods:', error); - return []; - } -} - -function generateModId(filename) { - return crypto.createHash('md5').update(filename).digest('hex').substring(0, 8); -} - -function extractModName(filename) { - let name = path.parse(filename).name; - - name = name.replace(/-v?\d+\.[\d\.]+.*$/i, ''); - name = name.replace(/-\d+\.[\d\.]+.*$/i, ''); - - name = name.replace(/[-_]/g, ' '); - name = name.replace(/\b\w/g, l => l.toUpperCase()); - - return name || 'Unknown Mod'; -} - -function extractVersion(filename) { - const versionMatch = filename.match(/v?(\d+\.[\d\.]+)/); - return versionMatch ? versionMatch[1] : null; -} - -async function downloadMod(modInfo) { - try { - const modsPath = await getModsPath(); - - if (!modInfo.downloadUrl && !modInfo.fileId) { - throw new Error('No download URL or file ID provided'); - } - - let downloadUrl = modInfo.downloadUrl; - - if (!downloadUrl && modInfo.fileId && modInfo.modId) { - const response = await axios.get(`https://api.curseforge.com/v1/mods/${modInfo.modId}/files/${modInfo.fileId}`, { - headers: { - 'x-api-key': modInfo.apiKey, - 'Accept': 'application/json' - } - }); - - downloadUrl = response.data.data.downloadUrl; - } - - if (!downloadUrl) { - throw new Error('Could not determine download URL'); - } - - const fileName = modInfo.fileName || `mod-${modInfo.modId}.jar`; - const filePath = path.join(modsPath, fileName); - - const response = await axios({ - method: 'get', - url: downloadUrl, - responseType: 'stream' - }); - - const writer = fs.createWriteStream(filePath); - response.data.pipe(writer); - - return new Promise((resolve, reject) => { - writer.on('finish', () => { - const configMods = loadModsFromConfig(); - const newMod = { - id: modInfo.id || generateModId(fileName), - name: modInfo.name || extractModName(fileName), - version: modInfo.version || '1.0.0', - description: modInfo.summary || modInfo.description || 'Downloaded from CurseForge', - author: modInfo.author || 'Unknown', - enabled: true, - fileName: fileName, - fileSize: fs.statSync(filePath).size, - dateInstalled: new Date().toISOString(), - curseForgeId: modInfo.modId, - curseForgeFileId: modInfo.fileId - }; - - configMods.push(newMod); - saveModsToConfig(configMods); - - resolve({ - success: true, - filePath: filePath, - fileName: fileName, - modInfo: newMod - }); - }); - writer.on('error', reject); - }); - - } catch (error) { - console.error('Error downloading mod:', error); - return { - success: false, - error: error.message - }; - } -} - -async function uninstallMod(modId, modsPath) { - try { - const configMods = loadModsFromConfig(); - const mod = configMods.find(m => m.id === modId); - - if (!mod) { - throw new Error('Mod not found in config'); - } - - const disabledModsPath = path.join(path.dirname(modsPath), 'DisabledMods'); - const enabledPath = path.join(modsPath, mod.fileName); - const disabledPath = path.join(disabledModsPath, mod.fileName); - - let fileRemoved = false; - if (fs.existsSync(enabledPath)) { - fs.unlinkSync(enabledPath); - fileRemoved = true; - console.log('Removed mod from Mods folder:', enabledPath); - } else if (fs.existsSync(disabledPath)) { - fs.unlinkSync(disabledPath); - fileRemoved = true; - console.log('Removed mod from DisabledMods folder:', disabledPath); - } - - if (!fileRemoved) { - console.warn('Mod file not found on filesystem, removing from config anyway'); - } - - const updatedMods = configMods.filter(m => m.id !== modId); - saveModsToConfig(updatedMods); - console.log('Mod removed from config.json'); - - return { success: true }; - } catch (error) { - console.error('Error uninstalling mod:', error); - return { - success: false, - error: error.message - }; - } -} - -async function toggleMod(modId, modsPath) { - try { - const mods = await loadInstalledMods(modsPath); - const mod = mods.find(m => m.id === modId); - - if (!mod) { - throw new Error('Mod not found'); - } - - const disabledModsPath = path.join(path.dirname(modsPath), 'DisabledMods'); - if (!fs.existsSync(disabledModsPath)) { - fs.mkdirSync(disabledModsPath, { recursive: true }); - } - - const currentPath = mod.filePath; - let newPath, newEnabled; - - if (mod.enabled) { - newPath = path.join(disabledModsPath, path.basename(currentPath)); - newEnabled = false; - } else { - newPath = path.join(modsPath, path.basename(currentPath)); - newEnabled = true; - } - - fs.renameSync(currentPath, newPath); - - const configMods = loadModsFromConfig(); - const configModIndex = configMods.findIndex(m => m.id === modId); - if (configModIndex !== -1) { - configMods[configModIndex].enabled = newEnabled; - saveModsToConfig(configMods); - } - - return { success: true, enabled: newEnabled }; - } catch (error) { - console.error('Error toggling mod:', error); - return { - success: false, - error: error.message - }; - } -} - -module.exports = { - launchGame, - launchGameWithVersionCheck, - installGame, +// Core modules +const { saveUsername, loadUsername, saveChatUsername, @@ -2195,12 +11,105 @@ module.exports = { loadJavaPath, saveInstallPath, loadInstallPath, + saveModsToConfig, + loadModsFromConfig, + getUuidForUser, + isFirstLaunch, + markAsLaunched, + CONFIG_FILE +} = require('./core/config'); + +const { getResolvedAppDir, getModsPath } = require('./core/paths'); + +// Managers +const { + isGameInstalled, + installGame, + uninstallGame, + updateGameFiles, + checkExistingGameInstallation +} = require('./managers/gameManager'); + +const { + launchGame, + launchGameWithVersionCheck +} = require('./managers/gameLauncher'); + +const { getJavaDetection } = require('./managers/javaManager'); + +const { checkAndInstallMultiClient } = require('./managers/multiClientManager'); + +const { + downloadAndReplaceHomePageUI, + findHomePageUIPath, + downloadAndReplaceLogo, + findLogoPath +} = require('./managers/uiFileManager'); + +const { + loadInstalledMods, + downloadMod, + uninstallMod, + toggleMod +} = require('./managers/modManager'); + +// Services +const { + getInstalledClientVersion, + getLatestClientVersion +} = require('./services/versionManager'); + +const { getHytaleNews } = require('./services/newsManager'); + +const { getOrCreatePlayerId } = require('./services/playerManager'); + +const { + proposeGameUpdate, + handleFirstLaunchCheck +} = require('./services/firstLaunch'); + +// Re-export all functions to maintain backward compatibility +module.exports = { + // Game launch functions + launchGame, + launchGameWithVersionCheck, + + // Game installation functions + installGame, isGameInstalled, uninstallGame, - getHytaleNews, + updateGameFiles, + + // User configuration functions + saveUsername, + loadUsername, + saveChatUsername, + loadChatUsername, + getUuidForUser, + + // Java configuration functions + saveJavaPath, + loadJavaPath, getJavaDetection, + + // Installation path functions + saveInstallPath, + loadInstallPath, + + // Version functions + getInstalledClientVersion, + getLatestClientVersion, + + // News functions + getHytaleNews, + + // Player ID functions getOrCreatePlayerId, + + // Multi-client functions checkAndInstallMultiClient, + + // Mod management functions getModsPath, loadInstalledMods, downloadMod, @@ -2208,17 +117,20 @@ module.exports = { toggleMod, saveModsToConfig, loadModsFromConfig, - getInstalledClientVersion, - getLatestClientVersion, - updateGameFiles, + + // UI file management functions downloadAndReplaceHomePageUI, findHomePageUIPath, downloadAndReplaceLogo, findLogoPath, + + // First launch functions isFirstLaunch, markAsLaunched, checkExistingGameInstallation, proposeGameUpdate, handleFirstLaunchCheck, + + // Path functions getResolvedAppDir }; diff --git a/backend/managers/butlerManager.js b/backend/managers/butlerManager.js new file mode 100644 index 0000000..8aec3c9 --- /dev/null +++ b/backend/managers/butlerManager.js @@ -0,0 +1,75 @@ +const fs = require('fs'); +const path = require('path'); +const AdmZip = require('adm-zip'); +const { TOOLS_DIR } = require('../core/paths'); +const { getOS, getArch } = require('../utils/platformUtils'); +const { downloadFile } = require('../utils/fileManager'); + +async function installButler(toolsDir = TOOLS_DIR) { + if (!fs.existsSync(toolsDir)) { + fs.mkdirSync(toolsDir, { recursive: true }); + } + + const butlerName = process.platform === 'win32' ? 'butler.exe' : 'butler'; + const butlerPath = path.join(toolsDir, butlerName); + const zipPath = path.join(toolsDir, 'butler.zip'); + + if (fs.existsSync(butlerPath)) { + return butlerPath; + } + + let urls = []; + const osName = getOS(); + const arch = getArch(); + if (osName === 'windows') { + urls = ['https://broth.itch.zone/butler/windows-amd64/LATEST/archive/default']; + } else if (osName === 'darwin') { + if (arch === 'arm64') { + urls = [ + 'https://broth.itch.zone/butler/darwin-arm64/LATEST/archive/default', + 'https://broth.itch.zone/butler/darwin-amd64/LATEST/archive/default' + ]; + } else { + urls = ['https://broth.itch.zone/butler/darwin-amd64/LATEST/archive/default']; + } + } else if (osName === 'linux') { + urls = ['https://broth.itch.zone/butler/linux-amd64/LATEST/archive/default']; + } else { + throw new Error('Operating system not supported'); + } + + console.log('Fetching Butler tool...'); + let lastError = null; + for (const url of urls) { + try { + await downloadFile(url, zipPath); + lastError = null; + break; + } catch (error) { + lastError = error; + } + } + if (lastError) { + throw lastError; + } + + console.log('Unpacking Butler...'); + const zip = new AdmZip(zipPath); + zip.extractAllTo(toolsDir, true); + + if (process.platform !== 'win32') { + fs.chmodSync(butlerPath, 0o755); + } + + try { + fs.unlinkSync(zipPath); + } catch (err) { + console.log('Notice: could not delete butler.zip'); + } + + return butlerPath; +} + +module.exports = { + installButler +}; diff --git a/backend/managers/gameLauncher.js b/backend/managers/gameLauncher.js new file mode 100644 index 0000000..60c32ba --- /dev/null +++ b/backend/managers/gameLauncher.js @@ -0,0 +1,272 @@ +const fs = require('fs'); +const path = require('path'); +const { exec } = require('child_process'); +const { promisify } = require('util'); +const { spawn } = require('child_process'); +const { getResolvedAppDir, findClientPath } = require('../core/paths'); +const { setupWaylandEnvironment } = require('../utils/platformUtils'); +const { saveUsername, saveInstallPath, loadJavaPath, getUuidForUser } = require('../core/config'); +const { resolveJavaPath, getJavaExec, getBundledJavaPath, detectSystemJava, JAVA_EXECUTABLE } = require('./javaManager'); +const { getInstalledClientVersion, getLatestClientVersion } = require('../services/versionManager'); +const { updateGameFiles } = require('./gameManager'); + +const execAsync = promisify(exec); + +async function launchGame(playerName = 'Player', progressCallback, javaPathOverride, installPathOverride) { + const customAppDir = getResolvedAppDir(installPathOverride); + const customGameDir = path.join(customAppDir, 'release', 'package', 'game', 'latest'); + const customJreDir = path.join(customAppDir, 'release', 'package', 'jre', 'latest'); + const userDataDir = path.join(customGameDir, 'Client', 'UserData'); + + const gameLatest = customGameDir; + let clientPath = findClientPath(gameLatest); + + if (!clientPath) { + throw new Error('Game is not installed. Please install the game first.'); + } + + saveUsername(playerName); + if (installPathOverride) { + saveInstallPath(installPathOverride); + } + + const configuredJava = (javaPathOverride !== undefined && javaPathOverride !== null + ? javaPathOverride + : loadJavaPath() || '').trim(); + let javaBin = null; + + if (configuredJava) { + javaBin = await resolveJavaPath(configuredJava); + if (!javaBin) { + throw new Error(`Configured Java path not found: ${configuredJava}`); + } + } else { + javaBin = getJavaExec(customJreDir); + + if (!getBundledJavaPath(customJreDir)) { + const fallback = await detectSystemJava(); + if (fallback) { + javaBin = fallback; + } else { + throw new Error('Java runtime not found. Please install the game first or configure Java path.'); + } + } + } + + if (process.platform === 'darwin') { + try { + const appBundle = path.join(gameLatest, 'Client', 'Hytale.app'); + const serverDir = path.join(gameLatest, 'Server'); + + const signPath = async (targetPath, deep = false) => { + await execAsync(`xattr -cr "${targetPath}"`).catch(() => {}); + const deepFlag = deep ? '--deep ' : ''; + await execAsync(`codesign --force ${deepFlag}--sign - "${targetPath}"`).catch(() => {}); + }; + + if (fs.existsSync(appBundle)) { + await signPath(appBundle, true); + console.log('Signed macOS app bundle'); + } else { + await signPath(path.dirname(clientPath), true); + console.log('Signed macOS client binary'); + } + + if (javaBin && fs.existsSync(javaBin)) { + let jreRoot = path.dirname(path.dirname(javaBin)); + if (jreRoot.endsWith('Home')) { + jreRoot = path.dirname(path.dirname(jreRoot)); + } + await signPath(jreRoot, true); + await signPath(javaBin, false); + console.log('Signed Java runtime'); + } + + if (fs.existsSync(serverDir)) { + await execAsync(`xattr -cr "${serverDir}"`).catch(() => {}); + await execAsync(`find "${serverDir}" -type f -perm +111 -exec codesign --force --sign - {} \\;`).catch(() => {}); + console.log('Signed server binaries'); + } + + if (javaBin && fs.existsSync(javaBin)) { + const javaWrapperPath = path.join(path.dirname(javaBin), 'java-wrapper'); + const wrapperScript = `#!/bin/bash +# Java wrapper for macOS - adds --disable-sentry to fix Sentry hang issue +REAL_JAVA="${javaBin}" +ARGS=("$@") +for i in "\${!ARGS[@]}"; do + if [[ "\${ARGS[$i]}" == *"HytaleServer.jar"* ]]; then + ARGS=("\${ARGS[@]:0:$((i+1))}" "--disable-sentry" "\${ARGS[@]:$((i+1))}") + break + fi +done +exec "$REAL_JAVA" "\${ARGS[@]}" +`; + fs.writeFileSync(javaWrapperPath, wrapperScript, { mode: 0o755 }); + await signPath(javaWrapperPath, false); + console.log('Created java wrapper with --disable-sentry fix'); + javaBin = javaWrapperPath; + } + } catch (signError) { + console.log('Notice: macOS signing step failed:', signError.message); + console.log('The game may still launch if Gatekeeper allows it'); + } + } + + const uuid = getUuidForUser(playerName); + const args = [ + '--app-dir', gameLatest, + '--java-exec', javaBin, + '--auth-mode', 'offline', + '--uuid', uuid, + '--name', playerName, + '--user-dir', userDataDir + ]; + + if (progressCallback) { + progressCallback('Starting game...', null, null, null, null); + } + console.log('Starting game...'); + console.log(`Command: "${clientPath}" ${args.join(' ')}`); + + const env = { ...process.env }; + + const waylandEnv = setupWaylandEnvironment(); + Object.assign(env, waylandEnv); + + try { + let spawnOptions = { + stdio: ['ignore', 'pipe', 'pipe'], + detached: true, + env: env + }; + + if (process.platform === 'win32') { + spawnOptions.shell = false; + spawnOptions.windowsHide = true; + } + + const child = spawn(clientPath, args, spawnOptions); + + console.log(`Game process started with PID: ${child.pid}`); + + let hasExited = false; + let outputReceived = false; + + child.stdout.on('data', (data) => { + outputReceived = true; + console.log(`Game output: ${data.toString().trim()}`); + }); + + child.stderr.on('data', (data) => { + outputReceived = true; + console.error(`Game error: ${data.toString().trim()}`); + }); + + child.on('error', (error) => { + hasExited = true; + console.error(`Failed to start game process: ${error.message}`); + if (progressCallback) { + progressCallback(`Failed to start game: ${error.message}`, -1, null, null, null); + } + }); + + child.on('exit', (code, signal) => { + hasExited = true; + if (code !== null) { + console.log(`Game process exited with code ${code}`); + if (code !== 0 && progressCallback) { + progressCallback(`Game exited with error code ${code}`, -1, null, null, null); + } + } else if (signal) { + console.log(`Game process terminated by signal ${signal}`); + } + }); + + setTimeout(() => { + if (!hasExited) { + console.log('Game appears to be running successfully'); + child.unref(); + if (progressCallback) { + progressCallback('Game launched successfully', 100, null, null, null); + } + } else if (!outputReceived) { + console.warn('Game process exited immediately with no output - possible issue with game files or dependencies'); + } + }, 3000); + + return { success: true, installed: true, launched: true, pid: child.pid }; + } catch (spawnError) { + console.error(`Error spawning game process: ${spawnError.message}`); + if (progressCallback) { + progressCallback(`Error launching game: ${spawnError.message}`, -1, null, null, null); + } + throw spawnError; + } +} + +async function launchGameWithVersionCheck(playerName = 'Player', progressCallback, javaPathOverride, installPathOverride) { + try { + if (progressCallback) { + progressCallback('Checking for updates...', 0, null, null, null); + } + + const [installedVersion, latestVersion] = await Promise.all([ + getInstalledClientVersion(), + getLatestClientVersion() + ]); + + console.log(`Installed version: ${installedVersion}, Latest version: ${latestVersion}`); + + let needsUpdate = false; + if (installedVersion && latestVersion && installedVersion !== latestVersion) { + needsUpdate = true; + console.log('Version mismatch detected, update required'); + } + + if (needsUpdate) { + if (progressCallback) { + progressCallback('Game update required, starting update process...', 10, null, null, null); + } + + const customAppDir = getResolvedAppDir(installPathOverride); + const customGameDir = path.join(customAppDir, 'release', 'package', 'game', 'latest'); + const customToolsDir = path.join(customAppDir, 'butler'); + const customCacheDir = path.join(customAppDir, 'cache'); + + try { + await updateGameFiles(latestVersion, progressCallback, customGameDir, customToolsDir, customCacheDir); + console.log('Game updated successfully, waiting before launch...'); + + if (progressCallback) { + progressCallback('Preparing game launch...', 90, null, null, null); + } + await new Promise(resolve => setTimeout(resolve, 3000)); + + } catch (updateError) { + console.error('Update failed:', updateError); + if (progressCallback) { + progressCallback(`Update failed: ${updateError.message}`, -1, null, null, null); + } + throw updateError; + } + } + + if (progressCallback) { + progressCallback('Launching game...', 80, null, null, null); + } + + return await launchGame(playerName, progressCallback, javaPathOverride, installPathOverride); + } catch (error) { + console.error('Error in version check and launch:', error); + if (progressCallback) { + progressCallback(`Error: ${error.message}`, -1, null, null, null); + } + throw error; + } +} + +module.exports = { + launchGame, + launchGameWithVersionCheck +}; diff --git a/backend/managers/gameManager.js b/backend/managers/gameManager.js new file mode 100644 index 0000000..5b313eb --- /dev/null +++ b/backend/managers/gameManager.js @@ -0,0 +1,406 @@ +const fs = require('fs'); +const path = require('path'); +const { execFile } = require('child_process'); +const { getResolvedAppDir, findClientPath, findUserDataPath, findUserDataRecursive, GAME_DIR, CACHE_DIR, TOOLS_DIR } = require('../core/paths'); +const { getOS, getArch } = require('../utils/platformUtils'); +const { downloadFile } = require('../utils/fileManager'); +const { getLatestClientVersion, getInstalledClientVersion } = require('../services/versionManager'); +const { installButler } = require('./butlerManager'); +const { checkAndInstallMultiClient } = require('./multiClientManager'); +const { downloadAndReplaceHomePageUI, downloadAndReplaceLogo } = require('./uiFileManager'); +const { saveUsername, saveInstallPath, loadJavaPath, CONFIG_FILE, loadConfig } = require('../core/config'); +const { resolveJavaPath, detectSystemJava, downloadJRE, getJavaExec, getBundledJavaPath } = require('./javaManager'); + +async function downloadPWR(version = 'release', fileName = '4.pwr', progressCallback, cacheDir = CACHE_DIR) { + const osName = getOS(); + const arch = getArch(); + const url = `https://game-patches.hytale.com/patches/${osName}/${arch}/${version}/0/${fileName}`; + + const dest = path.join(cacheDir, fileName); + + if (fs.existsSync(dest)) { + console.log('PWR file found in cache:', dest); + return dest; + } + + console.log('Fetching PWR patch file:', url); + await downloadFile(url, dest, progressCallback); + console.log('PWR saved to:', dest); + + return dest; +} + +async function applyPWR(pwrFile, progressCallback, gameDir = GAME_DIR, toolsDir = TOOLS_DIR) { + const butlerPath = await installButler(toolsDir); + const gameLatest = gameDir; + const stagingDir = path.join(gameLatest, 'staging-temp'); + + const clientPath = findClientPath(gameLatest); + + if (clientPath) { + console.log('Game files detected, skipping patch installation.'); + return; + } + + if (!fs.existsSync(gameLatest)) { + fs.mkdirSync(gameLatest, { recursive: true }); + } + if (!fs.existsSync(stagingDir)) { + fs.mkdirSync(stagingDir, { recursive: true }); + } + + if (progressCallback) { + progressCallback('Installing game patch...', null, null, null, null); + } + + console.log('Installing game patch...'); + + if (!fs.existsSync(butlerPath)) { + throw new Error(`Butler tool not found at: ${butlerPath}`); + } + + if (!fs.existsSync(pwrFile)) { + throw new Error(`PWR file not found at: ${pwrFile}`); + } + + const args = [ + 'apply', + '--staging-dir', + stagingDir, + pwrFile, + gameLatest + ]; + + try { + await new Promise((resolve, reject) => { + const child = execFile(butlerPath, args, { + maxBuffer: 1024 * 1024 * 10, + timeout: 600000 + }, (error, stdout, stderr) => { + if (error) { + console.error('Butler stderr:', stderr); + console.error('Butler stdout:', stdout); + reject(new Error(`Patch installation failed: ${error.message}${stderr ? '\n' + stderr : ''}`)); + } else { + resolve(); + } + }); + }); + } catch (error) { + throw error; + } + + if (fs.existsSync(stagingDir)) { + fs.rmSync(stagingDir, { recursive: true, force: true }); + } + + if (progressCallback) { + progressCallback('Installation complete', null, null, null, null); + } + console.log('Installation complete'); +} + +async function updateGameFiles(newVersion, progressCallback, gameDir = GAME_DIR, toolsDir = TOOLS_DIR, cacheDir = CACHE_DIR) { + let tempUpdateDir; + try { + if (progressCallback) { + progressCallback('Updating game files...', 0, null, null, null); + } + console.log(`Updating game files to version: ${newVersion}`); + + tempUpdateDir = path.join(gameDir, '..', 'temp_update'); + + if (fs.existsSync(tempUpdateDir)) { + fs.rmSync(tempUpdateDir, { recursive: true, force: true }); + } + fs.mkdirSync(tempUpdateDir, { recursive: true }); + + if (progressCallback) { + progressCallback('Downloading new game version...', 10, null, null, null); + } + + const pwrFile = await downloadPWR('release', newVersion, progressCallback, cacheDir); + + if (progressCallback) { + progressCallback('Extracting new files...', 50, null, null, null); + } + + await applyPWR(pwrFile, progressCallback, tempUpdateDir, toolsDir); + + if (progressCallback) { + progressCallback('Replacing game files...', 80, null, null, null); + } + + let userDataBackup = null; + const userDataPath = findUserDataRecursive(gameDir); + + if (userDataPath && fs.existsSync(userDataPath)) { + userDataBackup = path.join(gameDir, '..', 'UserData_backup_' + Date.now()); + console.log(`Backing up UserData from ${userDataPath} to: ${userDataBackup}`); + + function copyRecursive(src, dest) { + const stat = fs.statSync(src); + if (stat.isDirectory()) { + if (!fs.existsSync(dest)) { + fs.mkdirSync(dest, { recursive: true }); + } + const files = fs.readdirSync(src); + for (const file of files) { + copyRecursive(path.join(src, file), path.join(dest, file)); + } + } else { + fs.copyFileSync(src, dest); + } + } + + copyRecursive(userDataPath, userDataBackup); + } else { + console.log('No UserData folder found in game directory'); + } + + if (fs.existsSync(gameDir)) { + console.log('Removing old game files...'); + fs.rmSync(gameDir, { recursive: true, force: true }); + } + + fs.renameSync(tempUpdateDir, gameDir); + + const multiResult = await checkAndInstallMultiClient(gameDir, progressCallback); + console.log('Multiplayer-client check result after update:', multiResult); + + const homeUIResult = await downloadAndReplaceHomePageUI(gameDir, progressCallback); + console.log('HomePage.ui update result after update:', homeUIResult); + + const logoResult = await downloadAndReplaceLogo(gameDir, progressCallback); + console.log('Logo@2x.png update result after update:', logoResult); + + if (userDataBackup && fs.existsSync(userDataBackup)) { + const newUserDataPath = findUserDataPath(gameDir); + const userDataParent = path.dirname(newUserDataPath); + + if (!fs.existsSync(userDataParent)) { + fs.mkdirSync(userDataParent, { recursive: true }); + } + + console.log(`Restoring UserData to: ${newUserDataPath}`); + + function copyRecursive(src, dest) { + const stat = fs.statSync(src); + if (stat.isDirectory()) { + if (!fs.existsSync(dest)) { + fs.mkdirSync(dest, { recursive: true }); + } + const files = fs.readdirSync(src); + for (const file of files) { + copyRecursive(path.join(src, file), path.join(dest, file)); + } + } else { + fs.copyFileSync(src, dest); + } + } + + copyRecursive(userDataBackup, newUserDataPath); + } + + console.log(`Game files updated successfully to version: ${newVersion}`); + + if (userDataBackup && fs.existsSync(userDataBackup)) { + try { + fs.rmSync(userDataBackup, { recursive: true, force: true }); + console.log('UserData backup cleaned up'); + } catch (cleanupError) { + console.warn('Could not clean up UserData backup:', cleanupError.message); + } + } + + console.log('Waiting for file system sync...'); + await new Promise(resolve => setTimeout(resolve, 2000)); + + if (progressCallback) { + progressCallback('Game update completed', 100, null, null, null); + } + + return { success: true, updated: true, version: newVersion }; + } catch (error) { + console.error('Error updating game files:', error); + + if (userDataBackup && fs.existsSync(userDataBackup)) { + try { + fs.rmSync(userDataBackup, { recursive: true, force: true }); + console.log('UserData backup cleaned up after error'); + } catch (cleanupError) { + console.warn('Could not clean up UserData backup:', cleanupError.message); + } + } + + if (tempUpdateDir && fs.existsSync(tempUpdateDir)) { + fs.rmSync(tempUpdateDir, { recursive: true, force: true }); + } + + throw new Error(`Failed to update game files: ${error.message}`); + } +} + +function isGameInstalled() { + const appDir = getResolvedAppDir(); + const gameDir = path.join(appDir, 'release', 'package', 'game', 'latest'); + const clientPath = findClientPath(gameDir); + return clientPath !== null; +} + +async function installGame(playerName = 'Player', progressCallback, javaPathOverride, installPathOverride) { + const customAppDir = getResolvedAppDir(installPathOverride); + const customCacheDir = path.join(customAppDir, 'cache'); + const customToolsDir = path.join(customAppDir, 'butler'); + const customGameDir = path.join(customAppDir, 'release', 'package', 'game', 'latest'); + const customJreDir = path.join(customAppDir, 'release', 'package', 'jre', 'latest'); + const userDataDir = path.join(customGameDir, 'Client', 'UserData'); + + [customAppDir, customCacheDir, customToolsDir].forEach(dir => { + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } + }); + + if (!fs.existsSync(userDataDir)) { + fs.mkdirSync(userDataDir, { recursive: true }); + } + + saveUsername(playerName); + if (installPathOverride) { + saveInstallPath(installPathOverride); + } + + const gameLatest = customGameDir; + let clientPath = findClientPath(gameLatest); + + if (clientPath) { + if (progressCallback) { + progressCallback('Game already installed', 100, null, null, null); + } + console.log('Game is already installed'); + return { success: true, alreadyInstalled: true }; + } + + const configuredJava = (javaPathOverride !== undefined && javaPathOverride !== null + ? javaPathOverride + : loadJavaPath() || '').trim(); + let javaBin = null; + + if (configuredJava) { + javaBin = await resolveJavaPath(configuredJava); + if (!javaBin) { + throw new Error(`Configured Java path not found: ${configuredJava}`); + } + } else { + try { + await downloadJRE(progressCallback, customCacheDir, customJreDir); + } catch (error) { + const fallback = await detectSystemJava(); + if (fallback) { + javaBin = fallback; + } else { + throw error; + } + } + + if (!javaBin) { + javaBin = getJavaExec(customJreDir); + } + } + + if (progressCallback) { + progressCallback('Fetching game files...', null, null, null, null); + } + console.log('Installing game files...'); + + const latestVersion = await getLatestClientVersion(); + const pwrFile = await downloadPWR('release', latestVersion, progressCallback, customCacheDir); + await applyPWR(pwrFile, progressCallback, customGameDir, customToolsDir); + + const multiResult = await checkAndInstallMultiClient(customGameDir, progressCallback); + console.log('Multiplayer check result:', multiResult); + + const homeUIResult = await downloadAndReplaceHomePageUI(customGameDir, progressCallback); + console.log('HomePage.ui update result after installation:', homeUIResult); + + const logoResult = await downloadAndReplaceLogo(customGameDir, progressCallback); + console.log('Logo@2x.png update result after installation:', logoResult); + + if (progressCallback) { + progressCallback('Installation complete', 100, null, null, null); + } + console.log('Game installation completed successfully'); + + return { + success: true, + installed: true, + multiClient: multiResult + }; +} + +async function uninstallGame() { + const appDir = getResolvedAppDir(); + + if (!fs.existsSync(appDir)) { + throw new Error('Game is not installed'); + } + + try { + fs.rmSync(appDir, { recursive: true, force: true }); + console.log('Game uninstalled successfully - removed entire HytaleF2P folder'); + + if (fs.existsSync(CONFIG_FILE)) { + const config = loadConfig(); + delete config.installPath; + fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf8'); + } + } catch (error) { + throw new Error(`Failed to uninstall game: ${error.message}`); + } +} + +function checkExistingGameInstallation() { + try { + const config = loadConfig(); + + if (!config.installPath || !config.installPath.trim()) { + return null; + } + + const installPath = config.installPath.trim(); + const gameDir = path.join(installPath, 'HytaleF2P', 'release', 'package', 'game', 'latest'); + + if (!fs.existsSync(gameDir)) { + return null; + } + + const clientPath = findClientPath(gameDir); + if (!clientPath) { + return null; + } + + const userDataPath = findUserDataRecursive(gameDir); + + return { + gameDir: gameDir, + clientPath: clientPath, + userDataPath: userDataPath, + installPath: installPath, + hasUserData: userDataPath && fs.existsSync(userDataPath) + }; + } catch (error) { + console.error('Error checking existing game installation:', error); + return null; + } +} + +module.exports = { + downloadPWR, + applyPWR, + updateGameFiles, + isGameInstalled, + installGame, + uninstallGame, + checkExistingGameInstallation +}; diff --git a/backend/managers/javaManager.js b/backend/managers/javaManager.js new file mode 100644 index 0000000..c7b48ac --- /dev/null +++ b/backend/managers/javaManager.js @@ -0,0 +1,363 @@ +const fs = require('fs'); +const path = require('path'); +const { execFile } = require('child_process'); +const { promisify } = require('util'); +const axios = require('axios'); +const AdmZip = require('adm-zip'); +const crypto = require('crypto'); +const tar = require('tar'); +const { expandHome, JRE_DIR } = require('../core/paths'); +const { getOS, getArch } = require('../utils/platformUtils'); +const { loadConfig } = require('../core/config'); +const { downloadFile } = require('../utils/fileManager'); + +const execFileAsync = promisify(execFile); +const JAVA_EXECUTABLE = 'java' + (process.platform === 'win32' ? '.exe' : ''); + +async function findJavaOnPath(commandName = 'java') { + const lookupCmd = process.platform === 'win32' ? 'where' : 'which'; + try { + const { stdout } = await execFileAsync(lookupCmd, [commandName]); + const line = stdout.split(/\r?\n/).map(lineItem => lineItem.trim()).find(Boolean); + return line || null; + } catch (err) { + return null; + } +} + +async function getMacJavaHome() { + if (process.platform !== 'darwin') { + return null; + } + try { + const { stdout } = await execFileAsync('/usr/libexec/java_home'); + const home = stdout.trim(); + if (!home) { + return null; + } + return path.join(home, 'bin', JAVA_EXECUTABLE); + } catch (err) { + return null; + } +} + +async function resolveJavaPath(inputPath) { + const trimmed = (inputPath || '').trim(); + if (!trimmed) { + return null; + } + + const expanded = expandHome(trimmed); + if (fs.existsSync(expanded)) { + const stat = fs.statSync(expanded); + if (stat.isDirectory()) { + const candidate = path.join(expanded, 'bin', JAVA_EXECUTABLE); + return fs.existsSync(candidate) ? candidate : null; + } + return expanded; + } + + if (!path.isAbsolute(expanded)) { + return await findJavaOnPath(trimmed); + } + + return null; +} + +async function detectSystemJava() { + const envHome = process.env.JAVA_HOME; + if (envHome) { + const envJava = path.join(envHome, 'bin', JAVA_EXECUTABLE); + if (fs.existsSync(envJava)) { + return envJava; + } + } + + const macJava = await getMacJavaHome(); + if (macJava && fs.existsSync(macJava)) { + return macJava; + } + + const pathJava = await findJavaOnPath('java'); + if (pathJava && fs.existsSync(pathJava)) { + return pathJava; + } + + return null; +} + +function loadJavaPath() { + const config = loadConfig(); + return config.javaPath || ''; +} + +function getBundledJavaPath(jreDir = JRE_DIR) { + const candidates = [ + path.join(jreDir, 'bin', JAVA_EXECUTABLE) + ]; + + if (process.platform === 'darwin') { + candidates.push(path.join(jreDir, 'Contents', 'Home', 'bin', JAVA_EXECUTABLE)); + } + + for (const candidate of candidates) { + if (fs.existsSync(candidate)) { + return candidate; + } + } + + return null; +} + +function getJavaExec(jreDir = JRE_DIR) { + const bundledJava = getBundledJavaPath(jreDir); + if (bundledJava) { + return bundledJava; + } + + console.log('Notice: Java runtime not found, using system default'); + return 'java'; +} + +async function getJavaDetection() { + const candidates = []; + const bundledJava = getBundledJavaPath() || path.join(JRE_DIR, 'bin', JAVA_EXECUTABLE); + + candidates.push({ + label: 'Bundled JRE', + path: bundledJava, + exists: fs.existsSync(bundledJava) + }); + + const javaHomeEnv = process.env.JAVA_HOME; + if (javaHomeEnv) { + const envJava = path.join(javaHomeEnv, 'bin', JAVA_EXECUTABLE); + candidates.push({ + label: 'JAVA_HOME', + path: envJava, + exists: fs.existsSync(envJava), + note: fs.existsSync(envJava) ? '' : 'Not found' + }); + } else { + candidates.push({ + label: 'JAVA_HOME', + path: '', + exists: false, + note: 'Not set' + }); + } + + if (process.platform === 'darwin') { + const macJava = await getMacJavaHome(); + if (macJava) { + candidates.push({ + label: 'java_home', + path: macJava, + exists: fs.existsSync(macJava), + note: fs.existsSync(macJava) ? '' : 'Not found' + }); + } else { + candidates.push({ + label: 'java_home', + path: '', + exists: false, + note: 'Not found' + }); + } + } + + const pathJava = await findJavaOnPath('java'); + if (pathJava) { + candidates.push({ + label: 'PATH', + path: pathJava, + exists: true + }); + } else { + candidates.push({ + label: 'PATH', + path: '', + exists: false, + note: 'java not found' + }); + } + + return { + javaPath: loadJavaPath(), + candidates + }; +} + +async function downloadJRE(progressCallback, cacheDir, jreDir = JRE_DIR) { + if (!fs.existsSync(cacheDir)) { + fs.mkdirSync(cacheDir, { recursive: true }); + } + + const osName = getOS(); + const arch = getArch(); + + const bundledJava = getBundledJavaPath(jreDir); + if (bundledJava) { + console.log('Java runtime found, skipping download'); + return; + } + + console.log('Requesting Java runtime information...'); + const response = await axios.get('https://launcher.hytale.com/version/release/jre.json', { + headers: { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', + 'Accept': 'application/json', + 'Accept-Language': 'en-US,en;q=0.9' + } + }); + const jreData = response.data; + + const osData = jreData.download_url[osName]; + if (!osData) { + throw new Error(`Java runtime unavailable for platform: ${osName}`); + } + + const platform = osData[arch]; + if (!platform) { + throw new Error(`Java runtime unavailable for architecture ${arch} on ${osName}`); + } + + const fileName = path.basename(platform.url); + const cacheFile = path.join(cacheDir, fileName); + + if (!fs.existsSync(cacheFile)) { + if (progressCallback) { + progressCallback('Fetching Java runtime...', null, null, null, null); + } + console.log('Fetching Java runtime...'); + await downloadFile(platform.url, cacheFile, progressCallback); + console.log('Download finished'); + } + + if (progressCallback) { + progressCallback('Validating files...', null, null, null, null); + } + console.log('Validating files...'); + const fileBuffer = fs.readFileSync(cacheFile); + const hashSum = crypto.createHash('sha256'); + hashSum.update(fileBuffer); + const hex = hashSum.digest('hex'); + + if (hex !== platform.sha256) { + fs.unlinkSync(cacheFile); + throw new Error(`File validation failed: expected ${platform.sha256} but got ${hex}`); + } + + if (progressCallback) { + progressCallback('Unpacking Java runtime...', null, null, null, null); + } + console.log('Unpacking Java runtime...'); + await extractJRE(cacheFile, jreDir); + + if (process.platform !== 'win32') { + const javaCandidates = [ + path.join(jreDir, 'bin', JAVA_EXECUTABLE), + path.join(jreDir, 'Contents', 'Home', 'bin', JAVA_EXECUTABLE) + ]; + for (const javaPath of javaCandidates) { + if (fs.existsSync(javaPath)) { + fs.chmodSync(javaPath, 0o755); + } + } + } + + flattenJREDir(jreDir); + + try { + fs.unlinkSync(cacheFile); + } catch (err) { + console.log('Notice: could not delete cached Java files:', err.message); + } + + console.log('Java runtime ready'); +} + +async function extractJRE(archivePath, destDir) { + if (fs.existsSync(destDir)) { + fs.rmSync(destDir, { recursive: true, force: true }); + } + fs.mkdirSync(destDir, { recursive: true }); + + if (archivePath.endsWith('.zip')) { + return extractZip(archivePath, destDir); + } else if (archivePath.endsWith('.tar.gz')) { + return extractTarGz(archivePath, destDir); + } else { + throw new Error(`Archive type not supported: ${archivePath}`); + } +} + +function extractZip(zipPath, dest) { + const zip = new AdmZip(zipPath); + const entries = zip.getEntries(); + + for (const entry of entries) { + const entryPath = path.join(dest, entry.entryName); + + const resolvedPath = path.resolve(entryPath); + const resolvedDest = path.resolve(dest); + if (!resolvedPath.startsWith(resolvedDest)) { + throw new Error(`Invalid file path detected: ${entryPath}`); + } + + if (entry.isDirectory) { + fs.mkdirSync(entryPath, { recursive: true }); + } else { + fs.mkdirSync(path.dirname(entryPath), { recursive: true }); + fs.writeFileSync(entryPath, entry.getData()); + if (process.platform !== 'win32') { + fs.chmodSync(entryPath, entry.header.attr >>> 16); + } + } + } +} + +function extractTarGz(tarGzPath, dest) { + return tar.extract({ + file: tarGzPath, + cwd: dest, + strip: 0 + }); +} + +function flattenJREDir(jreLatest) { + try { + const entries = fs.readdirSync(jreLatest, { withFileTypes: true }); + + if (entries.length !== 1 || !entries[0].isDirectory()) { + return; + } + + const nested = path.join(jreLatest, entries[0].name); + const files = fs.readdirSync(nested, { withFileTypes: true }); + + for (const file of files) { + const oldPath = path.join(nested, file.name); + const newPath = path.join(jreLatest, file.name); + fs.renameSync(oldPath, newPath); + } + + fs.rmSync(nested, { recursive: true, force: true }); + } catch (err) { + console.log('Notice: could not restructure Java directory:', err.message); + } +} + +module.exports = { + findJavaOnPath, + getMacJavaHome, + resolveJavaPath, + detectSystemJava, + loadJavaPath, + getBundledJavaPath, + getJavaExec, + getJavaDetection, + downloadJRE, + extractJRE, + JAVA_EXECUTABLE +}; diff --git a/backend/managers/modManager.js b/backend/managers/modManager.js new file mode 100644 index 0000000..42e39d9 --- /dev/null +++ b/backend/managers/modManager.js @@ -0,0 +1,276 @@ +const fs = require('fs'); +const path = require('path'); +const crypto = require('crypto'); +const axios = require('axios'); +const { getModsPath } = require('../core/paths'); +const { saveModsToConfig, loadModsFromConfig } = require('../core/config'); + +function generateModId(filename) { + return crypto.createHash('md5').update(filename).digest('hex').substring(0, 8); +} + +function extractModName(filename) { + let name = path.parse(filename).name; + + name = name.replace(/-v?\d+\.[\d\.]+.*$/i, ''); + name = name.replace(/-\d+\.[\d\.]+.*$/i, ''); + + name = name.replace(/[-_]/g, ' '); + name = name.replace(/\b\w/g, l => l.toUpperCase()); + + return name || 'Unknown Mod'; +} + +function extractVersion(filename) { + const versionMatch = filename.match(/v?(\d+\.[\d\.]+)/); + return versionMatch ? versionMatch[1] : null; +} + +async function loadInstalledMods(modsPath) { + try { + const configMods = loadModsFromConfig(); + const modsMap = new Map(); + + configMods.forEach(mod => { + modsMap.set(mod.fileName, mod); + }); + + if (fs.existsSync(modsPath)) { + const files = fs.readdirSync(modsPath); + + for (const file of files) { + const filePath = path.join(modsPath, file); + const stats = fs.statSync(filePath); + + if (stats.isFile() && (file.endsWith('.jar') || file.endsWith('.zip'))) { + const configMod = modsMap.get(file); + + const modInfo = { + id: configMod?.id || generateModId(file), + name: configMod?.name || extractModName(file), + version: configMod?.version || extractVersion(file) || '1.0.0', + description: configMod?.description || 'Installed mod', + author: configMod?.author || 'Unknown', + enabled: true, + filePath: filePath, + fileName: file, + fileSize: configMod?.fileSize || stats.size, + dateInstalled: configMod?.dateInstalled || stats.birthtime || stats.mtime, + curseForgeId: configMod?.curseForgeId, + curseForgeFileId: configMod?.curseForgeFileId + }; + + modsMap.set(file, modInfo); + } + } + } + + const disabledModsPath = path.join(path.dirname(modsPath), 'DisabledMods'); + if (fs.existsSync(disabledModsPath)) { + const files = fs.readdirSync(disabledModsPath); + + for (const file of files) { + const filePath = path.join(disabledModsPath, file); + const stats = fs.statSync(filePath); + + if (stats.isFile() && (file.endsWith('.jar') || file.endsWith('.zip'))) { + const configMod = modsMap.get(file); + + const modInfo = { + id: configMod?.id || generateModId(file), + name: configMod?.name || extractModName(file), + version: configMod?.version || extractVersion(file) || '1.0.0', + description: configMod?.description || 'Disabled mod', + author: configMod?.author || 'Unknown', + enabled: false, + filePath: filePath, + fileName: file, + fileSize: configMod?.fileSize || stats.size, + dateInstalled: configMod?.dateInstalled || stats.birthtime || stats.mtime, + curseForgeId: configMod?.curseForgeId, + curseForgeFileId: configMod?.curseForgeFileId + }; + + modsMap.set(file, modInfo); + } + } + } + + return Array.from(modsMap.values()); + } catch (error) { + console.error('Error loading installed mods:', error); + return []; + } +} + +async function downloadMod(modInfo) { + try { + const modsPath = await getModsPath(); + + if (!modInfo.downloadUrl && !modInfo.fileId) { + throw new Error('No download URL or file ID provided'); + } + + let downloadUrl = modInfo.downloadUrl; + + if (!downloadUrl && modInfo.fileId && modInfo.modId) { + const response = await axios.get(`https://api.curseforge.com/v1/mods/${modInfo.modId}/files/${modInfo.fileId}`, { + headers: { + 'x-api-key': modInfo.apiKey, + 'Accept': 'application/json' + } + }); + + downloadUrl = response.data.data.downloadUrl; + } + + if (!downloadUrl) { + throw new Error('Could not determine download URL'); + } + + const fileName = modInfo.fileName || `mod-${modInfo.modId}.jar`; + const filePath = path.join(modsPath, fileName); + + const response = await axios({ + method: 'get', + url: downloadUrl, + responseType: 'stream' + }); + + const writer = fs.createWriteStream(filePath); + response.data.pipe(writer); + + return new Promise((resolve, reject) => { + writer.on('finish', () => { + const configMods = loadModsFromConfig(); + const newMod = { + id: modInfo.id || generateModId(fileName), + name: modInfo.name || extractModName(fileName), + version: modInfo.version || '1.0.0', + description: modInfo.summary || modInfo.description || 'Downloaded from CurseForge', + author: modInfo.author || 'Unknown', + enabled: true, + fileName: fileName, + fileSize: fs.statSync(filePath).size, + dateInstalled: new Date().toISOString(), + curseForgeId: modInfo.modId, + curseForgeFileId: modInfo.fileId + }; + + configMods.push(newMod); + saveModsToConfig(configMods); + + resolve({ + success: true, + filePath: filePath, + fileName: fileName, + modInfo: newMod + }); + }); + writer.on('error', reject); + }); + + } catch (error) { + console.error('Error downloading mod:', error); + return { + success: false, + error: error.message + }; + } +} + +async function uninstallMod(modId, modsPath) { + try { + const configMods = loadModsFromConfig(); + const mod = configMods.find(m => m.id === modId); + + if (!mod) { + throw new Error('Mod not found in config'); + } + + const disabledModsPath = path.join(path.dirname(modsPath), 'DisabledMods'); + const enabledPath = path.join(modsPath, mod.fileName); + const disabledPath = path.join(disabledModsPath, mod.fileName); + + let fileRemoved = false; + if (fs.existsSync(enabledPath)) { + fs.unlinkSync(enabledPath); + fileRemoved = true; + console.log('Removed mod from Mods folder:', enabledPath); + } else if (fs.existsSync(disabledPath)) { + fs.unlinkSync(disabledPath); + fileRemoved = true; + console.log('Removed mod from DisabledMods folder:', disabledPath); + } + + if (!fileRemoved) { + console.warn('Mod file not found on filesystem, removing from config anyway'); + } + + const updatedMods = configMods.filter(m => m.id !== modId); + saveModsToConfig(updatedMods); + console.log('Mod removed from config.json'); + + return { success: true }; + } catch (error) { + console.error('Error uninstalling mod:', error); + return { + success: false, + error: error.message + }; + } +} + +async function toggleMod(modId, modsPath) { + try { + const mods = await loadInstalledMods(modsPath); + const mod = mods.find(m => m.id === modId); + + if (!mod) { + throw new Error('Mod not found'); + } + + const disabledModsPath = path.join(path.dirname(modsPath), 'DisabledMods'); + if (!fs.existsSync(disabledModsPath)) { + fs.mkdirSync(disabledModsPath, { recursive: true }); + } + + const currentPath = mod.filePath; + let newPath, newEnabled; + + if (mod.enabled) { + newPath = path.join(disabledModsPath, path.basename(currentPath)); + newEnabled = false; + } else { + newPath = path.join(modsPath, path.basename(currentPath)); + newEnabled = true; + } + + fs.renameSync(currentPath, newPath); + + const configMods = loadModsFromConfig(); + const configModIndex = configMods.findIndex(m => m.id === modId); + if (configModIndex !== -1) { + configMods[configModIndex].enabled = newEnabled; + saveModsToConfig(configMods); + } + + return { success: true, enabled: newEnabled }; + } catch (error) { + console.error('Error toggling mod:', error); + return { + success: false, + error: error.message + }; + } +} + +module.exports = { + loadInstalledMods, + downloadMod, + uninstallMod, + toggleMod, + generateModId, + extractModName, + extractVersion +}; diff --git a/backend/managers/multiClientManager.js b/backend/managers/multiClientManager.js new file mode 100644 index 0000000..b2baaf6 --- /dev/null +++ b/backend/managers/multiClientManager.js @@ -0,0 +1,86 @@ +const fs = require('fs'); +const path = require('path'); +const { findClientPath } = require('../core/paths'); +const { downloadFile } = require('../utils/fileManager'); +const { getLatestClientVersion, getMultiClientVersion } = require('../services/versionManager'); + +async function downloadMultiClient(gameDir, progressCallback) { + try { + if (process.platform !== 'win32') { + console.log('Multiplayer-client is only available for Windows'); + return { success: false, reason: 'Platform not supported' }; + } + + const clientPath = findClientPath(gameDir); + if (!clientPath) { + throw new Error('Game client not found. Install game first.'); + } + + console.log('Downloading Multiplayer from server...'); + if (progressCallback) { + progressCallback('Downloading Multiplayer...', null, null, null, null); + } + + const clientUrl = 'http://3.10.208.30:3002/client'; + const tempClientPath = path.join(path.dirname(clientPath), 'HytaleClient_temp.exe'); + + await downloadFile(clientUrl, tempClientPath, progressCallback); + + const backupPath = path.join(path.dirname(clientPath), 'HytaleClient_original.exe'); + if (!fs.existsSync(backupPath)) { + fs.copyFileSync(clientPath, backupPath); + console.log('Original client backed up'); + } + + fs.renameSync(tempClientPath, clientPath); + + if (progressCallback) { + progressCallback('Multiplayer installed', 100, null, null, null); + } + console.log('Multiplayer installed successfully'); + + return { success: true, installed: true }; + + } catch (error) { + console.error('Error installing Multiplayer:', error); + throw new Error(`Failed to install Multiplayer: ${error.message}`); + } +} + +async function checkAndInstallMultiClient(gameDir, progressCallback) { + try { + if (process.platform !== 'win32') { + console.log('Multiplayer check skipped (Windows only)'); + return { success: true, skipped: true, reason: 'Windows only' }; + } + + console.log('Checking for Multiplayer availability...'); + + const [clientVersion, multiVersion] = await Promise.all([ + getLatestClientVersion(), + getMultiClientVersion() + ]); + + if (!multiVersion) { + console.log('Multiplayer not available'); + return { success: true, skipped: true, reason: 'Multiplayer not available' }; + } + + if (clientVersion === multiVersion) { + console.log(`Versions match (${clientVersion}), installing Multiplayer...`); + return await downloadMultiClient(gameDir, progressCallback); + } else { + console.log(`Version mismatch: client=${clientVersion}, multi=${multiVersion}`); + return { success: true, skipped: true, reason: 'Version mismatch' }; + } + + } catch (error) { + console.error('Error checking Multiplayer:', error); + return { success: false, error: error.message }; + } +} + +module.exports = { + downloadMultiClient, + checkAndInstallMultiClient +}; diff --git a/backend/managers/uiFileManager.js b/backend/managers/uiFileManager.js new file mode 100644 index 0000000..3a169fb --- /dev/null +++ b/backend/managers/uiFileManager.js @@ -0,0 +1,116 @@ +const fs = require('fs'); +const path = require('path'); +const { downloadFile, findHomePageUIPath, findLogoPath } = require('../utils/fileManager'); + +async function downloadAndReplaceHomePageUI(gameDir, progressCallback) { + try { + console.log('Downloading HomePage.ui from server...'); + + if (progressCallback) { + progressCallback('Downloading HomePage.ui...', null, null, null, null); + } + + const homeUIUrl = 'http://3.10.208.30:3002/api/HomeUI'; + const tempHomePath = path.join(path.dirname(gameDir), 'HomePage_temp.ui'); + + await downloadFile(homeUIUrl, tempHomePath); + + const existingHomePath = findHomePageUIPath(gameDir); + + if (existingHomePath && fs.existsSync(existingHomePath)) { + console.log('Found existing HomePage.ui at:', existingHomePath); + + const backupPath = existingHomePath + '.backup'; + if (!fs.existsSync(backupPath)) { + fs.copyFileSync(existingHomePath, backupPath); + console.log('Original HomePage.ui backed up'); + } + + fs.copyFileSync(tempHomePath, existingHomePath); + console.log('HomePage.ui replaced successfully'); + } else { + console.log('No existing HomePage.ui found, skipping replacement'); + } + + if (fs.existsSync(tempHomePath)) { + fs.unlinkSync(tempHomePath); + } + + if (progressCallback) { + progressCallback('HomePage.ui updated', null, null, null, null); + } + + return { success: true, updated: true }; + + } catch (error) { + console.error('Error downloading/replacing HomePage.ui:', error); + + const tempHomePath = path.join(path.dirname(gameDir), 'HomePage_temp.ui'); + if (fs.existsSync(tempHomePath)) { + fs.unlinkSync(tempHomePath); + } + + console.log('HomePage.ui update failed, continuing...'); + return { success: false, error: error.message }; + } +} + +async function downloadAndReplaceLogo(gameDir, progressCallback) { + try { + console.log('Downloading Logo@2x.png from server...'); + + if (progressCallback) { + progressCallback('Downloading Logo@2x.png...', null, null, null, null); + } + + const logoUrl = 'http://3.10.208.30:3002/api/Logo'; + const tempLogoPath = path.join(path.dirname(gameDir), 'Logo@2x_temp.png'); + + await downloadFile(logoUrl, tempLogoPath); + + const existingLogoPath = findLogoPath(gameDir); + + if (existingLogoPath && fs.existsSync(existingLogoPath)) { + console.log('Found existing Logo@2x.png at:', existingLogoPath); + + const backupPath = existingLogoPath + '.backup'; + if (!fs.existsSync(backupPath)) { + fs.copyFileSync(existingLogoPath, backupPath); + console.log('Original Logo@2x.png backed up'); + } + + fs.copyFileSync(tempLogoPath, existingLogoPath); + console.log('Logo@2x.png replaced successfully'); + } else { + console.log('No existing Logo@2x.png found, skipping replacement'); + } + + if (fs.existsSync(tempLogoPath)) { + fs.unlinkSync(tempLogoPath); + } + + if (progressCallback) { + progressCallback('Logo@2x.png updated', null, null, null, null); + } + + return { success: true, updated: true }; + + } catch (error) { + console.error('Error downloading/replacing Logo@2x.png:', error); + + const tempLogoPath = path.join(path.dirname(gameDir), 'Logo@2x_temp.png'); + if (fs.existsSync(tempLogoPath)) { + fs.unlinkSync(tempLogoPath); + } + + console.log('Logo@2x.png update failed, continuing...'); + return { success: false, error: error.message }; + } +} + +module.exports = { + downloadAndReplaceHomePageUI, + findHomePageUIPath, + downloadAndReplaceLogo, + findLogoPath +}; diff --git a/backend/services/firstLaunch.js b/backend/services/firstLaunch.js new file mode 100644 index 0000000..103b04f --- /dev/null +++ b/backend/services/firstLaunch.js @@ -0,0 +1,105 @@ +const path = require('path'); +const fs = require('fs'); +const { markAsLaunched, loadConfig } = require('../core/config'); +const { checkExistingGameInstallation, updateGameFiles } = require('../managers/gameManager'); +const { getInstalledClientVersion, getLatestClientVersion } = require('./versionManager'); + +async function proposeGameUpdate(existingGame, progressCallback) { + try { + console.log('Proposing game update for existing installation...'); + + if (progressCallback) { + progressCallback('Checking for game updates...', 0, null, null, null); + } + + const [installedVersion, latestVersion] = await Promise.all([ + getInstalledClientVersion(), + getLatestClientVersion() + ]); + + console.log(`Existing installation - Installed: ${installedVersion}, Latest: ${latestVersion}`); + + const customAppDir = path.join(existingGame.installPath, 'HytaleF2P'); + const customCacheDir = path.join(customAppDir, 'cache'); + const customToolsDir = path.join(customAppDir, 'butler'); + + [customCacheDir, customToolsDir].forEach(dir => { + const fs = require('fs'); + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } + }); + + if (progressCallback) { + progressCallback('Updating existing game installation...', 20, null, null, null); + } + + await updateGameFiles(latestVersion, progressCallback, existingGame.gameDir, customToolsDir, customCacheDir); + + if (progressCallback) { + progressCallback('Game update completed successfully', 100, null, null, null); + } + + console.log('Existing game installation updated successfully'); + return { success: true, updated: true }; + + } catch (error) { + console.error('Error updating existing game:', error); + if (progressCallback) { + progressCallback(`Update failed: ${error.message}`, -1, null, null, null); + } + throw error; + } +} + +async function handleFirstLaunchCheck(progressCallback) { + try { + const config = loadConfig(); + + if (config.hasLaunchedBefore === true) { + return { isFirstLaunch: false, needsUpdate: false }; + } + + console.log('First launch detected, checking for existing game installation...'); + + const existingGame = checkExistingGameInstallation(); + + if (!existingGame) { + console.log('No existing game installation found'); + + const hasUserData = config.installPath || config.username || config.javaPath || + config.chatUsername || config.userUuids || + Object.keys(config).length > 0; + + if (hasUserData) { + console.log('Detected existing user data but no game, marking as launched'); + markAsLaunched(); + return { isFirstLaunch: false, needsUpdate: false }; + } else { + markAsLaunched(); + return { isFirstLaunch: true, needsUpdate: false, existingGame: null }; + } + } + + console.log('Existing game installation found:', { + gameDir: existingGame.gameDir, + hasUserData: existingGame.hasUserData + }); + + return { + isFirstLaunch: true, + needsUpdate: true, + existingGame: existingGame + }; + + } catch (error) { + console.error('Error in first launch check:', error); + markAsLaunched(); + return { isFirstLaunch: true, needsUpdate: false, error: error.message }; + } +} + +module.exports = { + proposeGameUpdate, + handleFirstLaunchCheck +}; diff --git a/backend/services/newsManager.js b/backend/services/newsManager.js new file mode 100644 index 0000000..81b3d25 --- /dev/null +++ b/backend/services/newsManager.js @@ -0,0 +1,31 @@ +const axios = require('axios'); + +async function getHytaleNews() { + try { + const response = await axios.get('https://launcher.hytale.com/launcher-feed/release/feed.json', { + headers: { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' + }, + timeout: 10000 + }); + + const articles = response.data.articles || []; + return articles.map(article => ({ + title: article.title || '', + description: article.description || '', + destUrl: article.dest_url || '', + imageUrl: article.image_url ? + (article.image_url.startsWith('http') ? + article.image_url : + `https://launcher.hytale.com/launcher-feed/release/${article.image_url}` + ) : '' + })); + } catch (error) { + console.error('Failed to fetch news:', error.message); + return []; + } +} + +module.exports = { + getHytaleNews +}; diff --git a/backend/services/playerManager.js b/backend/services/playerManager.js new file mode 100644 index 0000000..f038fa7 --- /dev/null +++ b/backend/services/playerManager.js @@ -0,0 +1,34 @@ +const fs = require('fs'); +const path = require('path'); +const { v4: uuidv4 } = require('uuid'); +const { PLAYER_ID_FILE, APP_DIR } = require('../core/paths'); + +function getOrCreatePlayerId() { + try { + if (!fs.existsSync(APP_DIR)) { + fs.mkdirSync(APP_DIR, { recursive: true }); + } + + if (fs.existsSync(PLAYER_ID_FILE)) { + const data = JSON.parse(fs.readFileSync(PLAYER_ID_FILE, 'utf8')); + if (data.playerId) { + return data.playerId; + } + } + + const newPlayerId = uuidv4(); + fs.writeFileSync(PLAYER_ID_FILE, JSON.stringify({ + playerId: newPlayerId, + createdAt: new Date().toISOString() + }, null, 2)); + + return newPlayerId; + } catch (error) { + console.error('Error managing player ID:', error); + return uuidv4(); + } +} + +module.exports = { + getOrCreatePlayerId +}; diff --git a/backend/services/versionManager.js b/backend/services/versionManager.js new file mode 100644 index 0000000..709b74c --- /dev/null +++ b/backend/services/versionManager.js @@ -0,0 +1,82 @@ +const axios = require('axios'); + +async function getLatestClientVersion() { + try { + console.log('Fetching latest client version from API...'); + const response = await axios.get('http://3.10.208.30:3002/api/version_client', { + timeout: 5000, + headers: { + 'User-Agent': 'Hytale-F2P-Launcher' + } + }); + + if (response.data && response.data.client_version) { + const version = response.data.client_version; + console.log(`Latest client version: ${version}`); + return version; + } else { + console.log('Warning: Invalid API response, falling back to default version'); + return '4.pwr'; + } + } catch (error) { + console.error('Error fetching client version:', error.message); + console.log('Warning: API unavailable, falling back to default version'); + return '4.pwr'; + } +} + +async function getInstalledClientVersion() { + try { + console.log('Fetching installed client version from API...'); + const response = await axios.get('http://3.10.208.30:3002/api/clientCheck', { + timeout: 5000, + headers: { + 'User-Agent': 'Hytale-F2P-Launcher' + } + }); + + if (response.data && response.data.client_version) { + const version = response.data.client_version; + console.log(`Installed client version: ${version}`); + return version; + } else { + console.log('Warning: Invalid clientCheck API response'); + return null; + } + } catch (error) { + console.error('Error fetching installed client version:', error.message); + console.log('Warning: clientCheck API unavailable'); + return null; + } +} + +async function getMultiClientVersion() { + try { + console.log('Fetching Multiplayer version from API...'); + const response = await axios.get('http://3.10.208.30:3002/api/multi', { + timeout: 5000, + headers: { + 'User-Agent': 'Hytale-F2P-Launcher' + } + }); + + if (response.data && response.data.multi_version) { + const version = response.data.multi_version; + console.log(`Multiplayer version: ${version}`); + return version; + } else { + console.log('Warning: Invalid multi API response'); + return null; + } + } catch (error) { + console.error('Error fetching Multiplayer version:', error.message); + console.log('Multiplayer not available'); + return null; + } +} + +module.exports = { + getLatestClientVersion, + getInstalledClientVersion, + getMultiClientVersion +}; diff --git a/backend/utils/fileManager.js b/backend/utils/fileManager.js new file mode 100644 index 0000000..492c0c8 --- /dev/null +++ b/backend/utils/fileManager.js @@ -0,0 +1,103 @@ +const fs = require('fs'); +const path = require('path'); +const axios = require('axios'); + +async function downloadFile(url, dest, progressCallback) { + const response = await axios({ + method: 'GET', + url: url, + responseType: 'stream', + headers: { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', + 'Accept': '*/*', + 'Accept-Language': 'en-US,en;q=0.9', + 'Referer': 'https://launcher.hytale.com/' + } + }); + + const totalSize = parseInt(response.headers['content-length'], 10); + let downloaded = 0; + const startTime = Date.now(); + + const writer = fs.createWriteStream(dest); + + response.data.on('data', (chunk) => { + downloaded += chunk.length; + if (progressCallback && totalSize > 0) { + const percent = Math.min(100, Math.max(0, (downloaded / totalSize) * 100)); + const elapsed = (Date.now() - startTime) / 1000; + const speed = elapsed > 0 ? downloaded / elapsed : 0; + progressCallback(null, percent, speed, downloaded, totalSize); + } + }); + + response.data.pipe(writer); + + return new Promise((resolve, reject) => { + writer.on('finish', resolve); + writer.on('error', reject); + response.data.on('error', reject); + }); +} + +function findHomePageUIPath(gameLatest) { + function searchDirectory(dir) { + try { + const items = fs.readdirSync(dir, { withFileTypes: true }); + + for (const item of items) { + if (item.isFile() && item.name === 'HomePage.ui') { + return path.join(dir, item.name); + } else if (item.isDirectory()) { + const found = searchDirectory(path.join(dir, item.name)); + if (found) { + return found; + } + } + } + } catch (error) { + } + + return null; + } + + if (!fs.existsSync(gameLatest)) { + return null; + } + + return searchDirectory(gameLatest); +} + +function findLogoPath(gameLatest) { + function searchDirectory(dir) { + try { + const items = fs.readdirSync(dir, { withFileTypes: true }); + + for (const item of items) { + if (item.isFile() && item.name === 'Logo@2x.png') { + return path.join(dir, item.name); + } else if (item.isDirectory()) { + const found = searchDirectory(path.join(dir, item.name)); + if (found) { + return found; + } + } + } + } catch (error) { + } + + return null; + } + + if (!fs.existsSync(gameLatest)) { + return null; + } + + return searchDirectory(gameLatest); +} + +module.exports = { + downloadFile, + findHomePageUIPath, + findLogoPath +}; diff --git a/backend/utils/platformUtils.js b/backend/utils/platformUtils.js new file mode 100644 index 0000000..6460eb8 --- /dev/null +++ b/backend/utils/platformUtils.js @@ -0,0 +1,73 @@ +const { execSync } = require('child_process'); + +function getOS() { + if (process.platform === 'win32') return 'windows'; + if (process.platform === 'darwin') return 'darwin'; + if (process.platform === 'linux') return 'linux'; + return 'unknown'; +} + +function getArch() { + return process.arch === 'x64' ? 'amd64' : process.arch; +} + +function isWaylandSession() { + if (process.platform !== 'linux') { + return false; + } + + const sessionType = process.env.XDG_SESSION_TYPE; + if (sessionType && sessionType.toLowerCase() === 'wayland') { + return true; + } + + if (process.env.WAYLAND_DISPLAY) { + return true; + } + + try { + const sessionId = process.env.XDG_SESSION_ID; + if (sessionId) { + const output = execSync(`loginctl show-session ${sessionId} -p Type`, { encoding: 'utf8' }); + if (output && output.toLowerCase().includes('wayland')) { + return true; + } + } + } catch (err) { + } + + return false; +} + +function setupWaylandEnvironment() { + if (process.platform !== 'linux') { + return {}; + } + + if (!isWaylandSession()) { + console.log('Detected X11 session, using default environment'); + return {}; + } + + console.log('Detected Wayland session, configuring environment...'); + + const envVars = { + SDL_VIDEODRIVER: 'wayland', + GDK_BACKEND: 'wayland', + QT_QPA_PLATFORM: 'wayland', + MOZ_ENABLE_WAYLAND: '1', + _JAVA_AWT_WM_NONREPARENTING: '1' + }; + + envVars.ELECTRON_OZONE_PLATFORM_HINT = 'wayland'; + + console.log('Wayland environment variables:', envVars); + return envVars; +} + +module.exports = { + getOS, + getArch, + isWaylandSession, + setupWaylandEnvironment +}; diff --git a/package-lock.json b/package-lock.json index 8b13789..d9fa2b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1 +1,4955 @@ - +{ + "name": "hytale-f2p-launcher", + "version": "2.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "hytale-f2p-launcher", + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "adm-zip": "^0.5.10", + "axios": "^1.6.0", + "discord-rpc": "^4.0.1", + "tar": "^6.2.1", + "uuid": "^9.0.1" + }, + "devDependencies": { + "electron": "^40.0.0", + "electron-builder": "^26.4.0" + } + }, + "node_modules/@develar/schema-utils": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz", + "integrity": "sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.0", + "ajv-keywords": "^3.4.1" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/@electron/asar": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.4.1.tgz", + "integrity": "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^5.0.0", + "glob": "^7.1.6", + "minimatch": "^3.0.4" + }, + "bin": { + "asar": "bin/asar.js" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/@electron/asar/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@electron/fuses": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@electron/fuses/-/fuses-1.8.0.tgz", + "integrity": "sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.1", + "fs-extra": "^9.0.1", + "minimist": "^1.2.5" + }, + "bin": { + "electron-fuses": "dist/bin.js" + } + }, + "node_modules/@electron/fuses/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/fuses/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/fuses/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/get": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz", + "integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "env-paths": "^2.2.0", + "fs-extra": "^8.1.0", + "got": "^11.8.5", + "progress": "^2.0.3", + "semver": "^6.2.0", + "sumchecker": "^3.0.1" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "global-agent": "^3.0.0" + } + }, + "node_modules/@electron/notarize": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.5.0.tgz", + "integrity": "sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.1", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/notarize/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/notarize/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/notarize/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/osx-sign": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@electron/osx-sign/-/osx-sign-1.3.3.tgz", + "integrity": "sha512-KZ8mhXvWv2rIEgMbWZ4y33bDHyUKMXnx4M0sTyPNK/vcB81ImdeY9Ggdqy0SWbMDgmbqyQ+phgejh6V3R2QuSg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "compare-version": "^0.1.2", + "debug": "^4.3.4", + "fs-extra": "^10.0.0", + "isbinaryfile": "^4.0.8", + "minimist": "^1.2.6", + "plist": "^3.0.5" + }, + "bin": { + "electron-osx-flat": "bin/electron-osx-flat.js", + "electron-osx-sign": "bin/electron-osx-sign.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@electron/osx-sign/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@electron/osx-sign/node_modules/isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/@electron/osx-sign/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/osx-sign/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/rebuild": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-4.0.1.tgz", + "integrity": "sha512-iMGXb6Ib7H/Q3v+BKZJoETgF9g6KMNZVbsO4b7Dmpgb5qTFqyFTzqW9F3TOSHdybv2vKYKzSS9OiZL+dcJb+1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@malept/cross-spawn-promise": "^2.0.0", + "chalk": "^4.0.0", + "debug": "^4.1.1", + "detect-libc": "^2.0.1", + "got": "^11.7.0", + "graceful-fs": "^4.2.11", + "node-abi": "^4.2.0", + "node-api-version": "^0.2.1", + "node-gyp": "^11.2.0", + "ora": "^5.1.0", + "read-binary-file-arch": "^1.0.6", + "semver": "^7.3.5", + "tar": "^6.0.5", + "yargs": "^17.0.1" + }, + "bin": { + "electron-rebuild": "lib/cli.js" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@electron/rebuild/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/universal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@electron/universal/-/universal-2.0.3.tgz", + "integrity": "sha512-Wn9sPYIVFRFl5HmwMJkARCCf7rqK/EurkfQ/rJZ14mHP3iYTjZSIOSVonEAnhWeAXwtw7zOekGRlc6yTtZ0t+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron/asar": "^3.3.1", + "@malept/cross-spawn-promise": "^2.0.0", + "debug": "^4.3.1", + "dir-compare": "^4.2.0", + "fs-extra": "^11.1.1", + "minimatch": "^9.0.3", + "plist": "^3.1.0" + }, + "engines": { + "node": ">=16.4" + } + }, + "node_modules/@electron/universal/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@electron/universal/node_modules/fs-extra": { + "version": "11.3.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.3.tgz", + "integrity": "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@electron/universal/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/universal/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@electron/universal/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/windows-sign": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@electron/windows-sign/-/windows-sign-1.2.2.tgz", + "integrity": "sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "peer": true, + "dependencies": { + "cross-dirname": "^0.1.0", + "debug": "^4.3.4", + "fs-extra": "^11.1.1", + "minimist": "^1.2.8", + "postject": "^1.0.0-alpha.6" + }, + "bin": { + "electron-windows-sign": "bin/electron-windows-sign.js" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@electron/windows-sign/node_modules/fs-extra": { + "version": "11.3.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.3.tgz", + "integrity": "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@electron/windows-sign/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/windows-sign/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@malept/cross-spawn-promise": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz", + "integrity": "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/malept" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" + } + ], + "license": "Apache-2.0", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/@malept/flatpak-bundler": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@malept/flatpak-bundler/-/flatpak-bundler-0.4.0.tgz", + "integrity": "sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.0", + "lodash": "^4.17.15", + "tmp-promise": "^3.0.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@malept/flatpak-bundler/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@malept/flatpak-bundler/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@malept/flatpak-bundler/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@npmcli/agent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-3.0.0.tgz", + "integrity": "sha512-S79NdEgDQd/NGCay6TCoVzXSj74skRZIKJcpJjC5lOq34SZzyI6MqtiiWoiVWoVrTcGjNeC4ipbh1VIHlpfF5Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@npmcli/fs": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-4.0.0.tgz", + "integrity": "sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/fs/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/fs-extra": { + "version": "9.0.13", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", + "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.10.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.9.tgz", + "integrity": "sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/plist": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/plist/-/plist-3.0.5.tgz", + "integrity": "sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*", + "xmlbuilder": ">=11.0.1" + } + }, + "node_modules/@types/responselike": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", + "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/verror": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.11.tgz", + "integrity": "sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.11", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz", + "integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/7zip-bin": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.2.0.tgz", + "integrity": "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/abbrev": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz", + "integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/adm-zip": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz", + "integrity": "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==", + "license": "MIT", + "engines": { + "node": ">=12.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/app-builder-bin": { + "version": "5.0.0-alpha.12", + "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-5.0.0-alpha.12.tgz", + "integrity": "sha512-j87o0j6LqPL3QRr8yid6c+Tt5gC7xNfYo6uQIQkorAC6MpeayVMZrEDzKmJJ/Hlv7EnOQpaRm53k6ktDYZyB6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/app-builder-lib": { + "version": "26.4.0", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-26.4.0.tgz", + "integrity": "sha512-Uas6hNe99KzP3xPWxh5LGlH8kWIVjZixzmMJHNB9+6hPyDpjc7NQMkVgi16rQDdpCFy22ZU5sp8ow7tvjeMgYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@develar/schema-utils": "~2.6.5", + "@electron/asar": "3.4.1", + "@electron/fuses": "^1.8.0", + "@electron/notarize": "2.5.0", + "@electron/osx-sign": "1.3.3", + "@electron/rebuild": "4.0.1", + "@electron/universal": "2.0.3", + "@malept/flatpak-bundler": "^0.4.0", + "@types/fs-extra": "9.0.13", + "async-exit-hook": "^2.0.1", + "builder-util": "26.3.4", + "builder-util-runtime": "9.5.1", + "chromium-pickle-js": "^0.2.0", + "ci-info": "4.3.1", + "debug": "^4.3.4", + "dotenv": "^16.4.5", + "dotenv-expand": "^11.0.6", + "ejs": "^3.1.8", + "electron-publish": "26.3.4", + "fs-extra": "^10.1.0", + "hosted-git-info": "^4.1.0", + "isbinaryfile": "^5.0.0", + "jiti": "^2.4.2", + "js-yaml": "^4.1.0", + "json5": "^2.2.3", + "lazy-val": "^1.0.5", + "minimatch": "^10.0.3", + "plist": "3.1.0", + "resedit": "^1.7.0", + "semver": "~7.7.3", + "tar": "^6.1.12", + "temp-file": "^3.4.0", + "tiny-async-pool": "1.3.0", + "which": "^5.0.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "dmg-builder": "26.4.0", + "electron-builder-squirrel-windows": "26.4.0" + } + }, + "node_modules/app-builder-lib/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/app-builder-lib/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/app-builder-lib/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/app-builder-lib/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-exit-hook": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", + "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/axios": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", + "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/boolean": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", + "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/builder-util": { + "version": "26.3.4", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-26.3.4.tgz", + "integrity": "sha512-aRn88mYMktHxzdqDMF6Ayj0rKoX+ZogJ75Ck7RrIqbY/ad0HBvnS2xA4uHfzrGr5D2aLL3vU6OBEH4p0KMV2XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/debug": "^4.1.6", + "7zip-bin": "~5.2.0", + "app-builder-bin": "5.0.0-alpha.12", + "builder-util-runtime": "9.5.1", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.6", + "debug": "^4.3.4", + "fs-extra": "^10.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "js-yaml": "^4.1.0", + "sanitize-filename": "^1.6.3", + "source-map-support": "^0.5.19", + "stat-mode": "^1.0.0", + "temp-file": "^3.4.0", + "tiny-async-pool": "1.3.0" + } + }, + "node_modules/builder-util-runtime": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.5.1.tgz", + "integrity": "sha512-qt41tMfgHTllhResqM5DcnHyDIWNgzHvuY2jDcYP9iaGpkWxTUzV6GQjDeLnlR1/DtdlcsWQbA7sByMpmJFTLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/builder-util/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/builder-util/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/builder-util/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/cacache": { + "version": "19.0.1", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-19.0.1.tgz", + "integrity": "sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^4.0.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^7.0.2", + "ssri": "^12.0.0", + "tar": "^7.4.3", + "unique-filename": "^4.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/cacache/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/cacache/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/cacache/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/chromium-pickle-js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz", + "integrity": "sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/compare-version": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", + "integrity": "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/crc": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", + "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "buffer": "^5.1.0" + } + }, + "node_modules/cross-dirname": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/cross-dirname/-/cross-dirname-0.1.0.tgz", + "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/dir-compare": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-4.2.0.tgz", + "integrity": "sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimatch": "^3.0.5", + "p-limit": "^3.1.0 " + } + }, + "node_modules/dir-compare/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/discord-rpc": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/discord-rpc/-/discord-rpc-4.0.1.tgz", + "integrity": "sha512-HOvHpbq5STRZJjQIBzwoKnQ0jHplbEWFWlPDwXXKm/bILh4nzjcg7mNqll0UY7RsjFoaXA7e/oYb/4lvpda2zA==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.6.1", + "ws": "^7.3.1" + }, + "optionalDependencies": { + "register-scheme": "github:devsnek/node-register-scheme" + } + }, + "node_modules/dmg-builder": { + "version": "26.4.0", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-26.4.0.tgz", + "integrity": "sha512-ce4Ogns4VMeisIuCSK0C62umG0lFy012jd8LMZ6w/veHUeX4fqfDrGe+HTWALAEwK6JwKP+dhPvizhArSOsFbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "app-builder-lib": "26.4.0", + "builder-util": "26.3.4", + "fs-extra": "^10.1.0", + "iconv-lite": "^0.6.2", + "js-yaml": "^4.1.0" + }, + "optionalDependencies": { + "dmg-license": "^1.0.11" + } + }, + "node_modules/dmg-builder/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dmg-builder/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/dmg-builder/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/dmg-license": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.11.tgz", + "integrity": "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "@types/plist": "^3.0.1", + "@types/verror": "^1.10.3", + "ajv": "^6.10.0", + "crc": "^3.8.0", + "iconv-corefoundation": "^1.1.7", + "plist": "^3.0.4", + "smart-buffer": "^4.0.2", + "verror": "^1.10.0" + }, + "bin": { + "dmg-license": "bin/dmg-license.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotenv-expand": { + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.7.tgz", + "integrity": "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dotenv": "^16.4.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron": { + "version": "40.0.0", + "resolved": "https://registry.npmjs.org/electron/-/electron-40.0.0.tgz", + "integrity": "sha512-UyBy5yJ0/wm4gNugCtNPjvddjAknMTuXR2aCHioXicH7aKRKGDBPp4xqTEi/doVcB3R+MN3wfU9o8d/9pwgK2A==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@electron/get": "^2.0.0", + "@types/node": "^24.9.0", + "extract-zip": "^2.0.1" + }, + "bin": { + "electron": "cli.js" + }, + "engines": { + "node": ">= 12.20.55" + } + }, + "node_modules/electron-builder": { + "version": "26.4.0", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-26.4.0.tgz", + "integrity": "sha512-FCUqvdq2AULL+Db2SUGgjOYTbrgkPxZtCjqIZGnjH9p29pTWyesQqBIfvQBKa6ewqde87aWl49n/WyI/NyUBog==", + "dev": true, + "license": "MIT", + "dependencies": { + "app-builder-lib": "26.4.0", + "builder-util": "26.3.4", + "builder-util-runtime": "9.5.1", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "dmg-builder": "26.4.0", + "fs-extra": "^10.1.0", + "lazy-val": "^1.0.5", + "simple-update-notifier": "2.0.0", + "yargs": "^17.6.2" + }, + "bin": { + "electron-builder": "cli.js", + "install-app-deps": "install-app-deps.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/electron-builder-squirrel-windows": { + "version": "26.4.0", + "resolved": "https://registry.npmjs.org/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-26.4.0.tgz", + "integrity": "sha512-7dvalY38xBzWNaoOJ4sqy2aGIEpl2S1gLPkkB0MHu1Hu5xKQ82il1mKSFlXs6fLpXUso/NmyjdHGlSHDRoG8/w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "app-builder-lib": "26.4.0", + "builder-util": "26.3.4", + "electron-winstaller": "5.4.0" + } + }, + "node_modules/electron-builder/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-builder/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-builder/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-publish": { + "version": "26.3.4", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-26.3.4.tgz", + "integrity": "sha512-5/ouDPb73SkKuay2EXisPG60LTFTMNHWo2WLrK5GDphnWK9UC+yzYrzVeydj078Yk4WUXi0+TaaZsNd6Zt5k/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/fs-extra": "^9.0.11", + "builder-util": "26.3.4", + "builder-util-runtime": "9.5.1", + "chalk": "^4.1.2", + "form-data": "^4.0.0", + "fs-extra": "^10.1.0", + "lazy-val": "^1.0.5", + "mime": "^2.5.2" + } + }, + "node_modules/electron-publish/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-publish/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-publish/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-winstaller": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/electron-winstaller/-/electron-winstaller-5.4.0.tgz", + "integrity": "sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@electron/asar": "^3.2.1", + "debug": "^4.1.1", + "fs-extra": "^7.0.1", + "lodash": "^4.17.21", + "temp": "^0.9.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "optionalDependencies": { + "@electron/windows-sign": "^1.1.2" + } + }, + "node_modules/electron-winstaller/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extsprintf": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz", + "integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "license": "MIT", + "optional": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "license": "MIT", + "optional": true + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/global-agent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", + "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "es6-error": "^4.1.1", + "matcher": "^3.0.0", + "roarr": "^2.15.3", + "semver": "^7.3.2", + "serialize-error": "^7.0.1" + }, + "engines": { + "node": ">=10.0" + } + }, + "node_modules/global-agent/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-corefoundation": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", + "integrity": "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "cli-truncate": "^2.1.0", + "node-addon-api": "^1.6.3" + }, + "engines": { + "node": "^8.11.2 || >=10" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ip-address": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", + "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isbinaryfile": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-5.0.7.tgz", + "integrity": "sha512-gnWD14Jh3FzS3CPhF0AxNOJ8CxqeblPTADzI38r0wt8ZyQl5edpy75myt08EG2oKvpyiqSqsx+Wkz9vtkbTqYQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jake": { + "version": "10.9.4", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.6", + "filelist": "^1.0.4", + "picocolors": "^1.1.1" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/lazy-val": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz", + "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-fetch-happen": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-14.0.3.tgz", + "integrity": "sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/agent": "^3.0.0", + "cacache": "^19.0.1", + "http-cache-semantics": "^4.1.1", + "minipass": "^7.0.2", + "minipass-fetch": "^4.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^1.0.0", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1", + "ssri": "^12.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/matcher": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", + "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "escape-string-regexp": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", + "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-fetch": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-4.0.1.tgz", + "integrity": "sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^3.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-abi": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-4.25.0.tgz", + "integrity": "sha512-BRrQZc23ljOLms7EXVds3MOpB59/x7gaORodNuIwt96JKlflUmrOgv5hSJZEEM/WkW3uXpjZ4x1wcFu8V9mTpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.6.3" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/node-abi/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", + "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==", + "license": "MIT", + "optional": true + }, + "node_modules/node-api-version": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-api-version/-/node-api-version-0.2.1.tgz", + "integrity": "sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + } + }, + "node_modules/node-api-version/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp": { + "version": "11.5.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-11.5.0.tgz", + "integrity": "sha512-ra7Kvlhxn5V9Slyus0ygMa2h+UqExPqUIkfk7Pc8QTLT956JLSy51uWFwHtIYy0vI8cB4BDhc/S03+880My/LQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^14.0.3", + "nopt": "^8.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5", + "tar": "^7.4.3", + "tinyglobby": "^0.2.12", + "which": "^5.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/node-gyp/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/nopt": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", + "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^3.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/pe-library": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/pe-library/-/pe-library-0.4.1.tgz", + "integrity": "sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jet2jet" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/plist": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", + "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + }, + "engines": { + "node": ">=10.4.0" + } + }, + "node_modules/postject": { + "version": "1.0.0-alpha.6", + "resolved": "https://registry.npmjs.org/postject/-/postject-1.0.0-alpha.6.tgz", + "integrity": "sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "commander": "^9.4.0" + }, + "bin": { + "postject": "dist/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/postject/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/proc-log": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-5.0.0.tgz", + "integrity": "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-binary-file-arch": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/read-binary-file-arch/-/read-binary-file-arch-1.0.6.tgz", + "integrity": "sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "bin": { + "read-binary-file-arch": "cli.js" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/register-scheme": { + "version": "0.0.2", + "resolved": "git+ssh://git@github.com/devsnek/node-register-scheme.git#e7cc9a63a1f512565da44cb57316d9fb10750e17", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "bindings": "^1.3.0", + "node-addon-api": "^1.3.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resedit": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/resedit/-/resedit-1.7.2.tgz", + "integrity": "sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pe-library": "^0.4.1" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jet2jet" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/roarr": { + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", + "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "detect-node": "^2.0.4", + "globalthis": "^1.0.1", + "json-stringify-safe": "^5.0.1", + "semver-compare": "^1.0.0", + "sprintf-js": "^1.1.2" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/sanitize-filename": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz", + "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==", + "dev": true, + "license": "WTFPL OR ISC", + "dependencies": { + "truncate-utf8-bytes": "^1.0.0" + } + }, + "node_modules/sax": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.4.tgz", + "integrity": "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/serialize-error": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", + "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "type-fest": "^0.13.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", + "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ip-address": "^10.0.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/ssri": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-12.0.0.tgz", + "integrity": "sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/stat-mode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-1.0.0.tgz", + "integrity": "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sumchecker": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", + "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.1.0" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/temp": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.9.4.tgz", + "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "mkdirp": "^0.5.1", + "rimraf": "~2.6.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/temp-file": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.4.0.tgz", + "integrity": "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-exit-hook": "^2.0.1", + "fs-extra": "^10.0.0" + } + }, + "node_modules/temp-file/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/temp-file/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/temp-file/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/temp/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/tiny-async-pool": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tiny-async-pool/-/tiny-async-pool-1.3.0.tgz", + "integrity": "sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^5.5.0" + } + }, + "node_modules/tiny-async-pool/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tmp": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/tmp-promise": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", + "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tmp": "^0.2.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/truncate-utf8-bytes": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", + "integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==", + "dev": true, + "license": "WTFPL", + "dependencies": { + "utf8-byte-length": "^1.0.1" + } + }, + "node_modules/type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, + "node_modules/unique-filename": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-4.0.0.tgz", + "integrity": "sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/unique-slug": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-5.0.0.tgz", + "integrity": "sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/utf8-byte-length": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz", + "integrity": "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==", + "dev": true, + "license": "(WTFPL OR MIT)" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/verror": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz", + "integrity": "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +}