mirror of
https://github.com/noothenoot/crafty-mod-installer.git
synced 2026-07-21 21:37:00 +00:00
Enhancement: Added multi-mod loop and game version display; Fixed remote upload final
This commit is contained in:
@@ -1,4 +1,8 @@
|
||||
const axios = require('axios');
|
||||
const https = require('https');
|
||||
const FormData = require('form-data');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
class CraftyClient {
|
||||
constructor(baseUrl, token) {
|
||||
@@ -9,16 +13,25 @@ class CraftyClient {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${this.token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
},
|
||||
httpsAgent: new https.Agent({
|
||||
rejectUnauthorized: false
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
async testConnection() {
|
||||
try {
|
||||
const resp = await this.client.get('/stats');
|
||||
const resp = await this.client.get('/servers');
|
||||
return resp.status === 200;
|
||||
} catch (err) {
|
||||
console.error('Crafty Connection Error:', err.message);
|
||||
if (err.response) {
|
||||
console.error(`Crafty Connection Error: ${err.response.status} - ${JSON.stringify(err.response.data)}`);
|
||||
} else if (err.request) {
|
||||
console.error(`Crafty Connection Error: No response received. Check if your CRAFTY_URL is correct and reachable.`);
|
||||
} else {
|
||||
console.error('Crafty Connection Error:', err.message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -44,6 +57,30 @@ class CraftyClient {
|
||||
const resp = await this.client.post('/servers', payload);
|
||||
return resp.data.data;
|
||||
}
|
||||
|
||||
async uploadFile(serverId, localFilePath, remotePath = 'mods') {
|
||||
const stats = fs.statSync(localFilePath);
|
||||
const fileName = path.basename(localFilePath);
|
||||
const fileId = Math.random().toString(36).substring(2, 15);
|
||||
|
||||
// Remove leading slash for 'location' header
|
||||
const targetLocation = remotePath.replace(/^\//, '');
|
||||
|
||||
console.log(` Sending raw binary to Crafty (${(stats.size / 1024 / 1024).toFixed(2)} MB)...`);
|
||||
|
||||
const resp = await this.client.post(`/servers/${serverId}/files/upload`, fs.createReadStream(localFilePath), {
|
||||
headers: {
|
||||
'Content-Type': 'application/octet-stream',
|
||||
'location': targetLocation,
|
||||
'fileName': fileName,
|
||||
'fileSize': stats.size.toString(),
|
||||
'fileId': fileId
|
||||
},
|
||||
maxContentLength: Infinity,
|
||||
maxBodyLength: Infinity
|
||||
});
|
||||
return resp.data;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CraftyClient;
|
||||
|
||||
+11
-4
@@ -11,13 +11,20 @@ class CurseForgeHandler {
|
||||
}
|
||||
|
||||
async getMod(id) {
|
||||
// identifier can be numeric ID or slug (though the library might need specific search for slug)
|
||||
if (isNaN(id)) {
|
||||
const results = await this.client.searchMods({ slug: id });
|
||||
// Extract ID/slug from URL if needed
|
||||
let identifier = id;
|
||||
if (id.includes('curseforge.com')) {
|
||||
const parts = id.split('/');
|
||||
identifier = parts[parts.length - 1] || parts[parts.length - 2];
|
||||
}
|
||||
|
||||
if (isNaN(identifier)) {
|
||||
// 432 is the ID for Minecraft
|
||||
const results = await this.client.searchMods(432, { slug: identifier });
|
||||
if (results.data.length === 0) throw new Error('Mod not found');
|
||||
return results.data[0];
|
||||
}
|
||||
return await this.client.getMod(id);
|
||||
return await this.client.getMod(identifier);
|
||||
}
|
||||
|
||||
async getFiles(id) {
|
||||
|
||||
@@ -80,74 +80,100 @@ async function main() {
|
||||
targetServerId = selection;
|
||||
}
|
||||
|
||||
// 4. Mod Selection
|
||||
const { platform } = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'platform',
|
||||
message: 'Which platform are you using?',
|
||||
choices: ['Modrinth', 'CurseForge']
|
||||
}
|
||||
]);
|
||||
|
||||
const { identifier } = await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'identifier',
|
||||
message: `Enter ${platform} Link or ID:`
|
||||
}
|
||||
]);
|
||||
|
||||
// 5. Installation
|
||||
console.log('🔄 Preparing installation...');
|
||||
|
||||
// Determine final target directory
|
||||
let targetDir = '';
|
||||
if (isLocal) {
|
||||
const serverInfo = await crafty.getServerDetails(targetServerId);
|
||||
// Crafty stores servers in folders named by their UUID or name
|
||||
// We assume the folder is in the base serverPath
|
||||
targetDir = path.join(serverPath, serverInfo.server_id);
|
||||
// Note: Crafty 4 might use specific naming, we should verify info.path
|
||||
if (serverInfo.path) targetDir = serverInfo.path;
|
||||
} else {
|
||||
targetDir = path.join(process.cwd(), 'temp_server_files');
|
||||
await fs.ensureDir(targetDir);
|
||||
}
|
||||
|
||||
if (platform === 'Modrinth') {
|
||||
const project = await modrinth.getProject(identifier);
|
||||
const versions = await modrinth.getVersions(project.id);
|
||||
const { versionSelection } = await inquirer.prompt([
|
||||
// 4. Mod Selection Loop
|
||||
let keepInstalling = true;
|
||||
while (keepInstalling) {
|
||||
const { platform } = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'versionSelection',
|
||||
message: 'Select a version to install:',
|
||||
choices: versions.slice(0, 10).map(v => ({ name: `${v.version_number} (${v.loaders.join(', ')})`, value: v.id }))
|
||||
name: 'platform',
|
||||
message: 'Which platform are you using?',
|
||||
choices: ['Modrinth', 'CurseForge']
|
||||
}
|
||||
]);
|
||||
await modrinth.installModpack(versionSelection, targetDir);
|
||||
} else {
|
||||
const mod = await curseforge.getMod(identifier);
|
||||
const files = await curseforge.getFiles(mod.id);
|
||||
const { fileSelection } = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'fileSelection',
|
||||
message: 'Select a file to install:',
|
||||
choices: files.slice(0, 10).map(f => ({ name: f.displayName, value: f.id }))
|
||||
}
|
||||
]);
|
||||
await curseforge.installModpack(mod.id, fileSelection, targetDir);
|
||||
}
|
||||
|
||||
if (!isLocal) {
|
||||
console.log('🚀 Remote mode: Files are in ./temp_server_files. Please upload them to Crafty.');
|
||||
} else {
|
||||
console.log(`✅ Success! Files installed to: ${targetDir}`);
|
||||
const { identifier } = await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'identifier',
|
||||
message: `Enter ${platform} Link or ID:`
|
||||
}
|
||||
]);
|
||||
|
||||
// 5. Installation
|
||||
console.log('🔄 Preparing installation...');
|
||||
|
||||
// Determine final target directory
|
||||
let targetDir = '';
|
||||
if (isLocal) {
|
||||
const serverInfo = await crafty.getServerDetails(targetServerId);
|
||||
targetDir = serverInfo.path || path.join(serverPath, serverInfo.server_id);
|
||||
} else {
|
||||
targetDir = path.join(process.cwd(), 'temp_server_files');
|
||||
await fs.ensureDir(targetDir);
|
||||
}
|
||||
|
||||
if (platform === 'Modrinth') {
|
||||
const project = await modrinth.getProject(identifier);
|
||||
const versions = await modrinth.getVersions(project.id);
|
||||
const { versionSelection } = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'versionSelection',
|
||||
message: 'Select a version to install:',
|
||||
choices: versions.slice(0, 10).map(v => ({
|
||||
name: `${v.version_number} [MC: ${v.game_versions.join(', ')}] (${v.loaders.join(', ')})`,
|
||||
value: v.id
|
||||
}))
|
||||
}
|
||||
]);
|
||||
await modrinth.installMod(versionSelection, targetDir);
|
||||
} else {
|
||||
const mod = await curseforge.getMod(identifier);
|
||||
const files = await curseforge.getFiles(mod.id);
|
||||
const { fileSelection } = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'fileSelection',
|
||||
message: 'Select a file to install:',
|
||||
choices: files.slice(0, 10).map(f => ({
|
||||
name: `${f.displayName} [MC: ${f.gameVersions.join(', ')}]`,
|
||||
value: f.id
|
||||
}))
|
||||
}
|
||||
]);
|
||||
await curseforge.installModpack(mod.id, fileSelection, targetDir);
|
||||
}
|
||||
|
||||
if (!isLocal) {
|
||||
console.log('🚀 Remote mode: Syncing files to Crafty...');
|
||||
const modsDir = path.join(targetDir, 'mods');
|
||||
if (await fs.pathExists(modsDir)) {
|
||||
const files = await fs.readdir(modsDir);
|
||||
for (const file of files) {
|
||||
console.log(` Uploading ${file} to Crafty...`);
|
||||
await crafty.uploadFile(targetServerId, path.join(modsDir, file), 'mods');
|
||||
}
|
||||
}
|
||||
console.log('✅ Remote sync complete!');
|
||||
await fs.remove(targetDir);
|
||||
} else {
|
||||
console.log(`✅ Success! Files installed to: ${targetDir}`);
|
||||
}
|
||||
|
||||
const { another } = await inquirer.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'another',
|
||||
message: 'Do you want to install another mod?',
|
||||
default: false
|
||||
}
|
||||
]);
|
||||
keepInstalling = another;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('❌ Error:', err.message);
|
||||
if (err.response) console.log(JSON.stringify(err.response.data));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+50
-13
@@ -12,7 +12,13 @@ class ModrinthHandler {
|
||||
}
|
||||
|
||||
async getProject(id) {
|
||||
const resp = await this.client.get(`/project/${id}`);
|
||||
// Extract slug from URL if needed
|
||||
let slug = id;
|
||||
if (id.includes('modrinth.com')) {
|
||||
const parts = id.split('/');
|
||||
slug = parts[parts.length - 1] || parts[parts.length - 2];
|
||||
}
|
||||
const resp = await this.client.get(`/project/${slug}`);
|
||||
return resp.data;
|
||||
}
|
||||
|
||||
@@ -21,6 +27,11 @@ class ModrinthHandler {
|
||||
return resp.data;
|
||||
}
|
||||
|
||||
async getVersions(projectId) {
|
||||
const resp = await this.client.get(`/project/${projectId}/version`);
|
||||
return resp.data;
|
||||
}
|
||||
|
||||
async downloadFile(url, targetPath) {
|
||||
const response = await axios({
|
||||
url,
|
||||
@@ -35,13 +46,29 @@ class ModrinthHandler {
|
||||
});
|
||||
}
|
||||
|
||||
async installModpack(versionId, targetDir) {
|
||||
console.log(`Downloading Modrinth pack version: ${versionId}...`);
|
||||
async installMod(versionId, targetDir) {
|
||||
console.log(`Downloading Modrinth file version: ${versionId}...`);
|
||||
const version = await this.getVersion(versionId);
|
||||
const mrpackFile = version.files.find(f => f.filename.endsWith('.mrpack'));
|
||||
|
||||
if (!mrpackFile) throw new Error('No .mrpack file found in this version');
|
||||
// Find .mrpack for modpacks or the primary .jar for mods
|
||||
const packFile = version.files.find(f => f.filename.endsWith('.mrpack'));
|
||||
if (packFile) {
|
||||
return await this.installModpack(version, packFile, targetDir);
|
||||
}
|
||||
|
||||
const jarFile = version.files.find(f => f.primary) || version.files[0];
|
||||
if (!jarFile) throw new Error('No files found for this version');
|
||||
|
||||
const modsDir = path.join(targetDir, 'mods');
|
||||
await fs.ensureDir(modsDir);
|
||||
const destPath = path.join(modsDir, jarFile.filename);
|
||||
|
||||
console.log(` Downloading ${jarFile.filename}...`);
|
||||
await this.downloadFile(jarFile.url, destPath);
|
||||
console.log('✅ Mod installation complete!');
|
||||
}
|
||||
|
||||
async installModpack(version, mrpackFile, targetDir) {
|
||||
const tempPath = path.join(process.cwd(), 'temp_pack.mrpack');
|
||||
await this.downloadFile(mrpackFile.url, tempPath);
|
||||
|
||||
@@ -51,11 +78,7 @@ class ModrinthHandler {
|
||||
|
||||
const index = JSON.parse(zip.readAsText(indexEntry));
|
||||
|
||||
// Ensure mods directory exists
|
||||
const modsDir = path.join(targetDir, 'mods');
|
||||
await fs.ensureDir(modsDir);
|
||||
|
||||
console.log(`Downloading ${index.files.length} mods...`);
|
||||
console.log(`Downloading ${index.files.length} mods from pack...`);
|
||||
for (const file of index.files) {
|
||||
const destPath = path.join(targetDir, file.path);
|
||||
await fs.ensureDir(path.dirname(destPath));
|
||||
@@ -65,11 +88,25 @@ class ModrinthHandler {
|
||||
|
||||
// Handle overrides
|
||||
console.log('Applying overrides...');
|
||||
zip.extractAllTo(targetDir, true); // This is a simplification; should only extract 'overrides' folder
|
||||
// TODO: Properly merge overrides folder contents into root
|
||||
const overridesDir = 'overrides';
|
||||
const zipEntries = zip.getEntries();
|
||||
zipEntries.forEach(entry => {
|
||||
if (entry.entryName.startsWith(overridesDir + '/')) {
|
||||
const relativePath = entry.entryName.substring(overridesDir.length + 1);
|
||||
if (relativePath) {
|
||||
const dest = path.join(targetDir, relativePath);
|
||||
if (entry.isDirectory) {
|
||||
fs.ensureDirSync(dest);
|
||||
} else {
|
||||
fs.ensureDirSync(path.dirname(dest));
|
||||
fs.writeFileSync(dest, entry.getData());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await fs.remove(tempPath);
|
||||
console.log('Modpack installation complete!');
|
||||
console.log('✅ Modpack installation complete!');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Generated
+115
-86
@@ -12,38 +12,9 @@
|
||||
"axios": "^1.6.0",
|
||||
"curseforge-api": "^1.2.0",
|
||||
"dotenv": "^16.3.1",
|
||||
"fs-extra": "^11.1.1",
|
||||
"inquirer": "^9.2.11"
|
||||
}
|
||||
},
|
||||
"node_modules/@inquirer/external-editor": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz",
|
||||
"integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chardet": "^2.1.1",
|
||||
"iconv-lite": "^0.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": ">=18"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@inquirer/figures": {
|
||||
"version": "1.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz",
|
||||
"integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
"form-data": "^4.0.5",
|
||||
"fs-extra": "^11.3.4",
|
||||
"inquirer": "^8.2.5"
|
||||
}
|
||||
},
|
||||
"node_modules/adm-zip": {
|
||||
@@ -196,9 +167,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/chardet": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz",
|
||||
"integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==",
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
|
||||
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cli-cursor": {
|
||||
@@ -226,12 +197,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/cli-width": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz",
|
||||
"integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
|
||||
"integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/clone": {
|
||||
@@ -377,6 +348,44 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/external-editor": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
|
||||
"integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chardet": "^0.7.0",
|
||||
"iconv-lite": "^0.4.24",
|
||||
"tmp": "^0.0.33"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/figures": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
|
||||
"integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"escape-string-regexp": "^1.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.16.0",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz",
|
||||
@@ -540,19 +549,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
|
||||
"integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
|
||||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
"safer-buffer": ">= 2.1.2 < 3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/ieee754": {
|
||||
@@ -582,26 +587,29 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/inquirer": {
|
||||
"version": "9.3.8",
|
||||
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.3.8.tgz",
|
||||
"integrity": "sha512-pFGGdaHrmRKMh4WoDDSowddgjT1Vkl90atobmTeSmcPGdYiwikch/m/Ef5wRaiamHejtw0cUUMMerzDUXCci2w==",
|
||||
"version": "8.2.5",
|
||||
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz",
|
||||
"integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@inquirer/external-editor": "^1.0.2",
|
||||
"@inquirer/figures": "^1.0.3",
|
||||
"ansi-escapes": "^4.3.2",
|
||||
"cli-width": "^4.1.0",
|
||||
"mute-stream": "1.0.0",
|
||||
"ansi-escapes": "^4.2.1",
|
||||
"chalk": "^4.1.1",
|
||||
"cli-cursor": "^3.1.0",
|
||||
"cli-width": "^3.0.0",
|
||||
"external-editor": "^3.0.3",
|
||||
"figures": "^3.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"mute-stream": "0.0.8",
|
||||
"ora": "^5.4.1",
|
||||
"run-async": "^3.0.0",
|
||||
"rxjs": "^7.8.1",
|
||||
"string-width": "^4.2.3",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"wrap-ansi": "^6.2.0",
|
||||
"yoctocolors-cjs": "^2.1.2"
|
||||
"run-async": "^2.4.0",
|
||||
"rxjs": "^7.5.5",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"through": "^2.3.6",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-fullwidth-code-point": {
|
||||
@@ -646,6 +654,12 @@
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.18.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
|
||||
"integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/log-symbols": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
|
||||
@@ -702,13 +716,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/mute-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
||||
}
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
|
||||
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/onetime": {
|
||||
"version": "5.1.2",
|
||||
@@ -748,6 +759,15 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/os-tmpdir": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||
"integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz",
|
||||
@@ -785,9 +805,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/run-async": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz",
|
||||
"integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==",
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
|
||||
"integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.12.0"
|
||||
@@ -881,6 +901,24 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/through": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
||||
"integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tmp": {
|
||||
"version": "0.0.33",
|
||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
|
||||
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"os-tmpdir": "~1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
@@ -924,9 +962,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
|
||||
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
@@ -934,19 +972,10 @@
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/yoctocolors-cjs": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz",
|
||||
"integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -7,11 +7,12 @@
|
||||
"start": "node index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"adm-zip": "^0.5.10",
|
||||
"axios": "^1.6.0",
|
||||
"curseforge-api": "^1.2.0",
|
||||
"dotenv": "^16.3.1",
|
||||
"inquirer": "^9.2.11",
|
||||
"adm-zip": "^0.5.10",
|
||||
"fs-extra": "^11.1.1"
|
||||
"form-data": "^4.0.5",
|
||||
"fs-extra": "^11.3.4",
|
||||
"inquirer": "^8.2.5"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user