UNPKG

@xmcl/installer

Version:

The installers of Minecraft/Forge/Fabric/Liteloader/Quilt

4 lines 239 kB
{ "version": 3, "sources": ["../../../node_modules/.pnpm/buffer-crc32@0.2.13/node_modules/buffer-crc32/index.js", "../../../node_modules/.pnpm/yazl@2.5.1/node_modules/yazl/index.js", "../fabric.ts", "../utils.ts", "../liteloader.ts", "../forge.ts", "../downloadTask.ts", "../minecraft.ts", "../zipValdiator.ts", "../profile.ts", "../manifest.ts", "../neoForged.ts", "../optifine.ts", "../java.ts", "../java-runtime.ts", "../diagnose.ts", "../quilt.ts", "../unzip.ts", "../labymod.ts"], "sourcesContent": ["var Buffer = require('buffer').Buffer;\n\nvar CRC_TABLE = [\n 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,\n 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,\n 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,\n 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,\n 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,\n 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,\n 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,\n 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,\n 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,\n 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,\n 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,\n 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,\n 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,\n 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,\n 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,\n 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,\n 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,\n 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,\n 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,\n 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,\n 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,\n 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,\n 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,\n 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,\n 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,\n 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,\n 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,\n 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,\n 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,\n 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,\n 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,\n 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,\n 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,\n 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,\n 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,\n 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,\n 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,\n 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,\n 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,\n 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,\n 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,\n 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,\n 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,\n 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,\n 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,\n 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,\n 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,\n 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,\n 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,\n 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,\n 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,\n 0x2d02ef8d\n];\n\nif (typeof Int32Array !== 'undefined') {\n CRC_TABLE = new Int32Array(CRC_TABLE);\n}\n\nfunction ensureBuffer(input) {\n if (Buffer.isBuffer(input)) {\n return input;\n }\n\n var hasNewBufferAPI =\n typeof Buffer.alloc === \"function\" &&\n typeof Buffer.from === \"function\";\n\n if (typeof input === \"number\") {\n return hasNewBufferAPI ? Buffer.alloc(input) : new Buffer(input);\n }\n else if (typeof input === \"string\") {\n return hasNewBufferAPI ? Buffer.from(input) : new Buffer(input);\n }\n else {\n throw new Error(\"input must be buffer, number, or string, received \" +\n typeof input);\n }\n}\n\nfunction bufferizeInt(num) {\n var tmp = ensureBuffer(4);\n tmp.writeInt32BE(num, 0);\n return tmp;\n}\n\nfunction _crc32(buf, previous) {\n buf = ensureBuffer(buf);\n if (Buffer.isBuffer(previous)) {\n previous = previous.readUInt32BE(0);\n }\n var crc = ~~previous ^ -1;\n for (var n = 0; n < buf.length; n++) {\n crc = CRC_TABLE[(crc ^ buf[n]) & 0xff] ^ (crc >>> 8);\n }\n return (crc ^ -1);\n}\n\nfunction crc32() {\n return bufferizeInt(_crc32.apply(null, arguments));\n}\ncrc32.signed = function () {\n return _crc32.apply(null, arguments);\n};\ncrc32.unsigned = function () {\n return _crc32.apply(null, arguments) >>> 0;\n};\n\nmodule.exports = crc32;\n", "var fs = require(\"fs\");\nvar Transform = require(\"stream\").Transform;\nvar PassThrough = require(\"stream\").PassThrough;\nvar zlib = require(\"zlib\");\nvar util = require(\"util\");\nvar EventEmitter = require(\"events\").EventEmitter;\nvar crc32 = require(\"buffer-crc32\");\n\nexports.ZipFile = ZipFile;\nexports.dateToDosDateTime = dateToDosDateTime;\n\nutil.inherits(ZipFile, EventEmitter);\nfunction ZipFile() {\n this.outputStream = new PassThrough();\n this.entries = [];\n this.outputStreamCursor = 0;\n this.ended = false; // .end() sets this\n this.allDone = false; // set when we've written the last bytes\n this.forceZip64Eocd = false; // configurable in .end()\n}\n\nZipFile.prototype.addFile = function(realPath, metadataPath, options) {\n var self = this;\n metadataPath = validateMetadataPath(metadataPath, false);\n if (options == null) options = {};\n\n var entry = new Entry(metadataPath, false, options);\n self.entries.push(entry);\n fs.stat(realPath, function(err, stats) {\n if (err) return self.emit(\"error\", err);\n if (!stats.isFile()) return self.emit(\"error\", new Error(\"not a file: \" + realPath));\n entry.uncompressedSize = stats.size;\n if (options.mtime == null) entry.setLastModDate(stats.mtime);\n if (options.mode == null) entry.setFileAttributesMode(stats.mode);\n entry.setFileDataPumpFunction(function() {\n var readStream = fs.createReadStream(realPath);\n entry.state = Entry.FILE_DATA_IN_PROGRESS;\n readStream.on(\"error\", function(err) {\n self.emit(\"error\", err);\n });\n pumpFileDataReadStream(self, entry, readStream);\n });\n pumpEntries(self);\n });\n};\n\nZipFile.prototype.addReadStream = function(readStream, metadataPath, options) {\n var self = this;\n metadataPath = validateMetadataPath(metadataPath, false);\n if (options == null) options = {};\n var entry = new Entry(metadataPath, false, options);\n self.entries.push(entry);\n entry.setFileDataPumpFunction(function() {\n entry.state = Entry.FILE_DATA_IN_PROGRESS;\n pumpFileDataReadStream(self, entry, readStream);\n });\n pumpEntries(self);\n};\n\nZipFile.prototype.addBuffer = function(buffer, metadataPath, options) {\n var self = this;\n metadataPath = validateMetadataPath(metadataPath, false);\n if (buffer.length > 0x3fffffff) throw new Error(\"buffer too large: \" + buffer.length + \" > \" + 0x3fffffff);\n if (options == null) options = {};\n if (options.size != null) throw new Error(\"options.size not allowed\");\n var entry = new Entry(metadataPath, false, options);\n entry.uncompressedSize = buffer.length;\n entry.crc32 = crc32.unsigned(buffer);\n entry.crcAndFileSizeKnown = true;\n self.entries.push(entry);\n if (!entry.compress) {\n setCompressedBuffer(buffer);\n } else {\n zlib.deflateRaw(buffer, function(err, compressedBuffer) {\n setCompressedBuffer(compressedBuffer);\n });\n }\n function setCompressedBuffer(compressedBuffer) {\n entry.compressedSize = compressedBuffer.length;\n entry.setFileDataPumpFunction(function() {\n writeToOutputStream(self, compressedBuffer);\n writeToOutputStream(self, entry.getDataDescriptor());\n entry.state = Entry.FILE_DATA_DONE;\n\n // don't call pumpEntries() recursively.\n // (also, don't call process.nextTick recursively.)\n setImmediate(function() {\n pumpEntries(self);\n });\n });\n pumpEntries(self);\n }\n};\n\nZipFile.prototype.addEmptyDirectory = function(metadataPath, options) {\n var self = this;\n metadataPath = validateMetadataPath(metadataPath, true);\n if (options == null) options = {};\n if (options.size != null) throw new Error(\"options.size not allowed\");\n if (options.compress != null) throw new Error(\"options.compress not allowed\");\n var entry = new Entry(metadataPath, true, options);\n self.entries.push(entry);\n entry.setFileDataPumpFunction(function() {\n writeToOutputStream(self, entry.getDataDescriptor());\n entry.state = Entry.FILE_DATA_DONE;\n pumpEntries(self);\n });\n pumpEntries(self);\n};\n\nvar eocdrSignatureBuffer = bufferFrom([0x50, 0x4b, 0x05, 0x06]);\n\nZipFile.prototype.end = function(options, finalSizeCallback) {\n if (typeof options === \"function\") {\n finalSizeCallback = options;\n options = null;\n }\n if (options == null) options = {};\n if (this.ended) return;\n this.ended = true;\n this.finalSizeCallback = finalSizeCallback;\n this.forceZip64Eocd = !!options.forceZip64Format;\n if (options.comment) {\n if (typeof options.comment === \"string\") {\n this.comment = encodeCp437(options.comment);\n } else {\n // It should be a Buffer\n this.comment = options.comment;\n }\n if (this.comment.length > 0xffff) throw new Error(\"comment is too large\");\n // gotta check for this, because the zipfile format is actually ambiguous.\n if (bufferIncludes(this.comment, eocdrSignatureBuffer)) throw new Error(\"comment contains end of central directory record signature\");\n } else {\n // no comment.\n this.comment = EMPTY_BUFFER;\n }\n pumpEntries(this);\n};\n\nfunction writeToOutputStream(self, buffer) {\n self.outputStream.write(buffer);\n self.outputStreamCursor += buffer.length;\n}\n\nfunction pumpFileDataReadStream(self, entry, readStream) {\n var crc32Watcher = new Crc32Watcher();\n var uncompressedSizeCounter = new ByteCounter();\n var compressor = entry.compress ? new zlib.DeflateRaw() : new PassThrough();\n var compressedSizeCounter = new ByteCounter();\n readStream.pipe(crc32Watcher)\n .pipe(uncompressedSizeCounter)\n .pipe(compressor)\n .pipe(compressedSizeCounter)\n .pipe(self.outputStream, {end: false});\n compressedSizeCounter.on(\"end\", function() {\n entry.crc32 = crc32Watcher.crc32;\n if (entry.uncompressedSize == null) {\n entry.uncompressedSize = uncompressedSizeCounter.byteCount;\n } else {\n if (entry.uncompressedSize !== uncompressedSizeCounter.byteCount) return self.emit(\"error\", new Error(\"file data stream has unexpected number of bytes\"));\n }\n entry.compressedSize = compressedSizeCounter.byteCount;\n self.outputStreamCursor += entry.compressedSize;\n writeToOutputStream(self, entry.getDataDescriptor());\n entry.state = Entry.FILE_DATA_DONE;\n pumpEntries(self);\n });\n}\n\nfunction pumpEntries(self) {\n if (self.allDone) return;\n // first check if finalSize is finally known\n if (self.ended && self.finalSizeCallback != null) {\n var finalSize = calculateFinalSize(self);\n if (finalSize != null) {\n // we have an answer\n self.finalSizeCallback(finalSize);\n self.finalSizeCallback = null;\n }\n }\n\n // pump entries\n var entry = getFirstNotDoneEntry();\n function getFirstNotDoneEntry() {\n for (var i = 0; i < self.entries.length; i++) {\n var entry = self.entries[i];\n if (entry.state < Entry.FILE_DATA_DONE) return entry;\n }\n return null;\n }\n if (entry != null) {\n // this entry is not done yet\n if (entry.state < Entry.READY_TO_PUMP_FILE_DATA) return; // input file not open yet\n if (entry.state === Entry.FILE_DATA_IN_PROGRESS) return; // we'll get there\n // start with local file header\n entry.relativeOffsetOfLocalHeader = self.outputStreamCursor;\n var localFileHeader = entry.getLocalFileHeader();\n writeToOutputStream(self, localFileHeader);\n entry.doFileDataPump();\n } else {\n // all cought up on writing entries\n if (self.ended) {\n // head for the exit\n self.offsetOfStartOfCentralDirectory = self.outputStreamCursor;\n self.entries.forEach(function(entry) {\n var centralDirectoryRecord = entry.getCentralDirectoryRecord();\n writeToOutputStream(self, centralDirectoryRecord);\n });\n writeToOutputStream(self, getEndOfCentralDirectoryRecord(self));\n self.outputStream.end();\n self.allDone = true;\n }\n }\n}\n\nfunction calculateFinalSize(self) {\n var pretendOutputCursor = 0;\n var centralDirectorySize = 0;\n for (var i = 0; i < self.entries.length; i++) {\n var entry = self.entries[i];\n // compression is too hard to predict\n if (entry.compress) return -1;\n if (entry.state >= Entry.READY_TO_PUMP_FILE_DATA) {\n // if addReadStream was called without providing the size, we can't predict the final size\n if (entry.uncompressedSize == null) return -1;\n } else {\n // if we're still waiting for fs.stat, we might learn the size someday\n if (entry.uncompressedSize == null) return null;\n }\n // we know this for sure, and this is important to know if we need ZIP64 format.\n entry.relativeOffsetOfLocalHeader = pretendOutputCursor;\n var useZip64Format = entry.useZip64Format();\n\n pretendOutputCursor += LOCAL_FILE_HEADER_FIXED_SIZE + entry.utf8FileName.length;\n pretendOutputCursor += entry.uncompressedSize;\n if (!entry.crcAndFileSizeKnown) {\n // use a data descriptor\n if (useZip64Format) {\n pretendOutputCursor += ZIP64_DATA_DESCRIPTOR_SIZE;\n } else {\n pretendOutputCursor += DATA_DESCRIPTOR_SIZE;\n }\n }\n\n centralDirectorySize += CENTRAL_DIRECTORY_RECORD_FIXED_SIZE + entry.utf8FileName.length + entry.fileComment.length;\n if (useZip64Format) {\n centralDirectorySize += ZIP64_EXTENDED_INFORMATION_EXTRA_FIELD_SIZE;\n }\n }\n\n var endOfCentralDirectorySize = 0;\n if (self.forceZip64Eocd ||\n self.entries.length >= 0xffff ||\n centralDirectorySize >= 0xffff ||\n pretendOutputCursor >= 0xffffffff) {\n // use zip64 end of central directory stuff\n endOfCentralDirectorySize += ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIZE + ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIZE;\n }\n endOfCentralDirectorySize += END_OF_CENTRAL_DIRECTORY_RECORD_SIZE + self.comment.length;\n return pretendOutputCursor + centralDirectorySize + endOfCentralDirectorySize;\n}\n\nvar ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIZE = 56;\nvar ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIZE = 20;\nvar END_OF_CENTRAL_DIRECTORY_RECORD_SIZE = 22;\nfunction getEndOfCentralDirectoryRecord(self, actuallyJustTellMeHowLongItWouldBe) {\n var needZip64Format = false;\n var normalEntriesLength = self.entries.length;\n if (self.forceZip64Eocd || self.entries.length >= 0xffff) {\n normalEntriesLength = 0xffff;\n needZip64Format = true;\n }\n var sizeOfCentralDirectory = self.outputStreamCursor - self.offsetOfStartOfCentralDirectory;\n var normalSizeOfCentralDirectory = sizeOfCentralDirectory;\n if (self.forceZip64Eocd || sizeOfCentralDirectory >= 0xffffffff) {\n normalSizeOfCentralDirectory = 0xffffffff;\n needZip64Format = true;\n }\n var normalOffsetOfStartOfCentralDirectory = self.offsetOfStartOfCentralDirectory;\n if (self.forceZip64Eocd || self.offsetOfStartOfCentralDirectory >= 0xffffffff) {\n normalOffsetOfStartOfCentralDirectory = 0xffffffff;\n needZip64Format = true;\n }\n if (actuallyJustTellMeHowLongItWouldBe) {\n if (needZip64Format) {\n return (\n ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIZE +\n ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIZE +\n END_OF_CENTRAL_DIRECTORY_RECORD_SIZE\n );\n } else {\n return END_OF_CENTRAL_DIRECTORY_RECORD_SIZE;\n }\n }\n\n var eocdrBuffer = bufferAlloc(END_OF_CENTRAL_DIRECTORY_RECORD_SIZE + self.comment.length);\n // end of central dir signature 4 bytes (0x06054b50)\n eocdrBuffer.writeUInt32LE(0x06054b50, 0);\n // number of this disk 2 bytes\n eocdrBuffer.writeUInt16LE(0, 4);\n // number of the disk with the start of the central directory 2 bytes\n eocdrBuffer.writeUInt16LE(0, 6);\n // total number of entries in the central directory on this disk 2 bytes\n eocdrBuffer.writeUInt16LE(normalEntriesLength, 8);\n // total number of entries in the central directory 2 bytes\n eocdrBuffer.writeUInt16LE(normalEntriesLength, 10);\n // size of the central directory 4 bytes\n eocdrBuffer.writeUInt32LE(normalSizeOfCentralDirectory, 12);\n // offset of start of central directory with respect to the starting disk number 4 bytes\n eocdrBuffer.writeUInt32LE(normalOffsetOfStartOfCentralDirectory, 16);\n // .ZIP file comment length 2 bytes\n eocdrBuffer.writeUInt16LE(self.comment.length, 20);\n // .ZIP file comment (variable size)\n self.comment.copy(eocdrBuffer, 22);\n\n if (!needZip64Format) return eocdrBuffer;\n\n // ZIP64 format\n // ZIP64 End of Central Directory Record\n var zip64EocdrBuffer = bufferAlloc(ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIZE);\n // zip64 end of central dir signature 4 bytes (0x06064b50)\n zip64EocdrBuffer.writeUInt32LE(0x06064b50, 0);\n // size of zip64 end of central directory record 8 bytes\n writeUInt64LE(zip64EocdrBuffer, ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIZE - 12, 4);\n // version made by 2 bytes\n zip64EocdrBuffer.writeUInt16LE(VERSION_MADE_BY, 12);\n // version needed to extract 2 bytes\n zip64EocdrBuffer.writeUInt16LE(VERSION_NEEDED_TO_EXTRACT_ZIP64, 14);\n // number of this disk 4 bytes\n zip64EocdrBuffer.writeUInt32LE(0, 16);\n // number of the disk with the start of the central directory 4 bytes\n zip64EocdrBuffer.writeUInt32LE(0, 20);\n // total number of entries in the central directory on this disk 8 bytes\n writeUInt64LE(zip64EocdrBuffer, self.entries.length, 24);\n // total number of entries in the central directory 8 bytes\n writeUInt64LE(zip64EocdrBuffer, self.entries.length, 32);\n // size of the central directory 8 bytes\n writeUInt64LE(zip64EocdrBuffer, sizeOfCentralDirectory, 40);\n // offset of start of central directory with respect to the starting disk number 8 bytes\n writeUInt64LE(zip64EocdrBuffer, self.offsetOfStartOfCentralDirectory, 48);\n // zip64 extensible data sector (variable size)\n // nothing in the zip64 extensible data sector\n\n\n // ZIP64 End of Central Directory Locator\n var zip64EocdlBuffer = bufferAlloc(ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIZE);\n // zip64 end of central dir locator signature 4 bytes (0x07064b50)\n zip64EocdlBuffer.writeUInt32LE(0x07064b50, 0);\n // number of the disk with the start of the zip64 end of central directory 4 bytes\n zip64EocdlBuffer.writeUInt32LE(0, 4);\n // relative offset of the zip64 end of central directory record 8 bytes\n writeUInt64LE(zip64EocdlBuffer, self.outputStreamCursor, 8);\n // total number of disks 4 bytes\n zip64EocdlBuffer.writeUInt32LE(1, 16);\n\n\n return Buffer.concat([\n zip64EocdrBuffer,\n zip64EocdlBuffer,\n eocdrBuffer,\n ]);\n}\n\nfunction validateMetadataPath(metadataPath, isDirectory) {\n if (metadataPath === \"\") throw new Error(\"empty metadataPath\");\n metadataPath = metadataPath.replace(/\\\\/g, \"/\");\n if (/^[a-zA-Z]:/.test(metadataPath) || /^\\//.test(metadataPath)) throw new Error(\"absolute path: \" + metadataPath);\n if (metadataPath.split(\"/\").indexOf(\"..\") !== -1) throw new Error(\"invalid relative path: \" + metadataPath);\n var looksLikeDirectory = /\\/$/.test(metadataPath);\n if (isDirectory) {\n // append a trailing '/' if necessary.\n if (!looksLikeDirectory) metadataPath += \"/\";\n } else {\n if (looksLikeDirectory) throw new Error(\"file path cannot end with '/': \" + metadataPath);\n }\n return metadataPath;\n}\n\nvar EMPTY_BUFFER = bufferAlloc(0);\n\n// this class is not part of the public API\nfunction Entry(metadataPath, isDirectory, options) {\n this.utf8FileName = bufferFrom(metadataPath);\n if (this.utf8FileName.length > 0xffff) throw new Error(\"utf8 file name too long. \" + utf8FileName.length + \" > \" + 0xffff);\n this.isDirectory = isDirectory;\n this.state = Entry.WAITING_FOR_METADATA;\n this.setLastModDate(options.mtime != null ? options.mtime : new Date());\n if (options.mode != null) {\n this.setFileAttributesMode(options.mode);\n } else {\n this.setFileAttributesMode(isDirectory ? 0o40775 : 0o100664);\n }\n if (isDirectory) {\n this.crcAndFileSizeKnown = true;\n this.crc32 = 0;\n this.uncompressedSize = 0;\n this.compressedSize = 0;\n } else {\n // unknown so far\n this.crcAndFileSizeKnown = false;\n this.crc32 = null;\n this.uncompressedSize = null;\n this.compressedSize = null;\n if (options.size != null) this.uncompressedSize = options.size;\n }\n if (isDirectory) {\n this.compress = false;\n } else {\n this.compress = true; // default\n if (options.compress != null) this.compress = !!options.compress;\n }\n this.forceZip64Format = !!options.forceZip64Format;\n if (options.fileComment) {\n if (typeof options.fileComment === \"string\") {\n this.fileComment = bufferFrom(options.fileComment, \"utf-8\");\n } else {\n // It should be a Buffer\n this.fileComment = options.fileComment;\n }\n if (this.fileComment.length > 0xffff) throw new Error(\"fileComment is too large\");\n } else {\n // no comment.\n this.fileComment = EMPTY_BUFFER;\n }\n}\nEntry.WAITING_FOR_METADATA = 0;\nEntry.READY_TO_PUMP_FILE_DATA = 1;\nEntry.FILE_DATA_IN_PROGRESS = 2;\nEntry.FILE_DATA_DONE = 3;\nEntry.prototype.setLastModDate = function(date) {\n var dosDateTime = dateToDosDateTime(date);\n this.lastModFileTime = dosDateTime.time;\n this.lastModFileDate = dosDateTime.date;\n};\nEntry.prototype.setFileAttributesMode = function(mode) {\n if ((mode & 0xffff) !== mode) throw new Error(\"invalid mode. expected: 0 <= \" + mode + \" <= \" + 0xffff);\n // http://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute/14727#14727\n this.externalFileAttributes = (mode << 16) >>> 0;\n};\n// doFileDataPump() should not call pumpEntries() directly. see issue #9.\nEntry.prototype.setFileDataPumpFunction = function(doFileDataPump) {\n this.doFileDataPump = doFileDataPump;\n this.state = Entry.READY_TO_PUMP_FILE_DATA;\n};\nEntry.prototype.useZip64Format = function() {\n return (\n (this.forceZip64Format) ||\n (this.uncompressedSize != null && this.uncompressedSize > 0xfffffffe) ||\n (this.compressedSize != null && this.compressedSize > 0xfffffffe) ||\n (this.relativeOffsetOfLocalHeader != null && this.relativeOffsetOfLocalHeader > 0xfffffffe)\n );\n}\nvar LOCAL_FILE_HEADER_FIXED_SIZE = 30;\nvar VERSION_NEEDED_TO_EXTRACT_UTF8 = 20;\nvar VERSION_NEEDED_TO_EXTRACT_ZIP64 = 45;\n// 3 = unix. 63 = spec version 6.3\nvar VERSION_MADE_BY = (3 << 8) | 63;\nvar FILE_NAME_IS_UTF8 = 1 << 11;\nvar UNKNOWN_CRC32_AND_FILE_SIZES = 1 << 3;\nEntry.prototype.getLocalFileHeader = function() {\n var crc32 = 0;\n var compressedSize = 0;\n var uncompressedSize = 0;\n if (this.crcAndFileSizeKnown) {\n crc32 = this.crc32;\n compressedSize = this.compressedSize;\n uncompressedSize = this.uncompressedSize;\n }\n\n var fixedSizeStuff = bufferAlloc(LOCAL_FILE_HEADER_FIXED_SIZE);\n var generalPurposeBitFlag = FILE_NAME_IS_UTF8;\n if (!this.crcAndFileSizeKnown) generalPurposeBitFlag |= UNKNOWN_CRC32_AND_FILE_SIZES;\n\n // local file header signature 4 bytes (0x04034b50)\n fixedSizeStuff.writeUInt32LE(0x04034b50, 0);\n // version needed to extract 2 bytes\n fixedSizeStuff.writeUInt16LE(VERSION_NEEDED_TO_EXTRACT_UTF8, 4);\n // general purpose bit flag 2 bytes\n fixedSizeStuff.writeUInt16LE(generalPurposeBitFlag, 6);\n // compression method 2 bytes\n fixedSizeStuff.writeUInt16LE(this.getCompressionMethod(), 8);\n // last mod file time 2 bytes\n fixedSizeStuff.writeUInt16LE(this.lastModFileTime, 10);\n // last mod file date 2 bytes\n fixedSizeStuff.writeUInt16LE(this.lastModFileDate, 12);\n // crc-32 4 bytes\n fixedSizeStuff.writeUInt32LE(crc32, 14);\n // compressed size 4 bytes\n fixedSizeStuff.writeUInt32LE(compressedSize, 18);\n // uncompressed size 4 bytes\n fixedSizeStuff.writeUInt32LE(uncompressedSize, 22);\n // file name length 2 bytes\n fixedSizeStuff.writeUInt16LE(this.utf8FileName.length, 26);\n // extra field length 2 bytes\n fixedSizeStuff.writeUInt16LE(0, 28);\n return Buffer.concat([\n fixedSizeStuff,\n // file name (variable size)\n this.utf8FileName,\n // extra field (variable size)\n // no extra fields\n ]);\n};\nvar DATA_DESCRIPTOR_SIZE = 16;\nvar ZIP64_DATA_DESCRIPTOR_SIZE = 24;\nEntry.prototype.getDataDescriptor = function() {\n if (this.crcAndFileSizeKnown) {\n // the Mac Archive Utility requires this not be present unless we set general purpose bit 3\n return EMPTY_BUFFER;\n }\n if (!this.useZip64Format()) {\n var buffer = bufferAlloc(DATA_DESCRIPTOR_SIZE);\n // optional signature (required according to Archive Utility)\n buffer.writeUInt32LE(0x08074b50, 0);\n // crc-32 4 bytes\n buffer.writeUInt32LE(this.crc32, 4);\n // compressed size 4 bytes\n buffer.writeUInt32LE(this.compressedSize, 8);\n // uncompressed size 4 bytes\n buffer.writeUInt32LE(this.uncompressedSize, 12);\n return buffer;\n } else {\n // ZIP64 format\n var buffer = bufferAlloc(ZIP64_DATA_DESCRIPTOR_SIZE);\n // optional signature (unknown if anyone cares about this)\n buffer.writeUInt32LE(0x08074b50, 0);\n // crc-32 4 bytes\n buffer.writeUInt32LE(this.crc32, 4);\n // compressed size 8 bytes\n writeUInt64LE(buffer, this.compressedSize, 8);\n // uncompressed size 8 bytes\n writeUInt64LE(buffer, this.uncompressedSize, 16);\n return buffer;\n }\n};\nvar CENTRAL_DIRECTORY_RECORD_FIXED_SIZE = 46;\nvar ZIP64_EXTENDED_INFORMATION_EXTRA_FIELD_SIZE = 28;\nEntry.prototype.getCentralDirectoryRecord = function() {\n var fixedSizeStuff = bufferAlloc(CENTRAL_DIRECTORY_RECORD_FIXED_SIZE);\n var generalPurposeBitFlag = FILE_NAME_IS_UTF8;\n if (!this.crcAndFileSizeKnown) generalPurposeBitFlag |= UNKNOWN_CRC32_AND_FILE_SIZES;\n\n var normalCompressedSize = this.compressedSize;\n var normalUncompressedSize = this.uncompressedSize;\n var normalRelativeOffsetOfLocalHeader = this.relativeOffsetOfLocalHeader;\n var versionNeededToExtract;\n var zeiefBuffer;\n if (this.useZip64Format()) {\n normalCompressedSize = 0xffffffff;\n normalUncompressedSize = 0xffffffff;\n normalRelativeOffsetOfLocalHeader = 0xffffffff;\n versionNeededToExtract = VERSION_NEEDED_TO_EXTRACT_ZIP64;\n\n // ZIP64 extended information extra field\n zeiefBuffer = bufferAlloc(ZIP64_EXTENDED_INFORMATION_EXTRA_FIELD_SIZE);\n // 0x0001 2 bytes Tag for this \"extra\" block type\n zeiefBuffer.writeUInt16LE(0x0001, 0);\n // Size 2 bytes Size of this \"extra\" block\n zeiefBuffer.writeUInt16LE(ZIP64_EXTENDED_INFORMATION_EXTRA_FIELD_SIZE - 4, 2);\n // Original Size 8 bytes Original uncompressed file size\n writeUInt64LE(zeiefBuffer, this.uncompressedSize, 4);\n // Compressed Size 8 bytes Size of compressed data\n writeUInt64LE(zeiefBuffer, this.compressedSize, 12);\n // Relative Header Offset 8 bytes Offset of local header record\n writeUInt64LE(zeiefBuffer, this.relativeOffsetOfLocalHeader, 20);\n // Disk Start Number 4 bytes Number of the disk on which this file starts\n // (omit)\n } else {\n versionNeededToExtract = VERSION_NEEDED_TO_EXTRACT_UTF8;\n zeiefBuffer = EMPTY_BUFFER;\n }\n\n // central file header signature 4 bytes (0x02014b50)\n fixedSizeStuff.writeUInt32LE(0x02014b50, 0);\n // version made by 2 bytes\n fixedSizeStuff.writeUInt16LE(VERSION_MADE_BY, 4);\n // version needed to extract 2 bytes\n fixedSizeStuff.writeUInt16LE(versionNeededToExtract, 6);\n // general purpose bit flag 2 bytes\n fixedSizeStuff.writeUInt16LE(generalPurposeBitFlag, 8);\n // compression method 2 bytes\n fixedSizeStuff.writeUInt16LE(this.getCompressionMethod(), 10);\n // last mod file time 2 bytes\n fixedSizeStuff.writeUInt16LE(this.lastModFileTime, 12);\n // last mod file date 2 bytes\n fixedSizeStuff.writeUInt16LE(this.lastModFileDate, 14);\n // crc-32 4 bytes\n fixedSizeStuff.writeUInt32LE(this.crc32, 16);\n // compressed size 4 bytes\n fixedSizeStuff.writeUInt32LE(normalCompressedSize, 20);\n // uncompressed size 4 bytes\n fixedSizeStuff.writeUInt32LE(normalUncompressedSize, 24);\n // file name length 2 bytes\n fixedSizeStuff.writeUInt16LE(this.utf8FileName.length, 28);\n // extra field length 2 bytes\n fixedSizeStuff.writeUInt16LE(zeiefBuffer.length, 30);\n // file comment length 2 bytes\n fixedSizeStuff.writeUInt16LE(this.fileComment.length, 32);\n // disk number start 2 bytes\n fixedSizeStuff.writeUInt16LE(0, 34);\n // internal file attributes 2 bytes\n fixedSizeStuff.writeUInt16LE(0, 36);\n // external file attributes 4 bytes\n fixedSizeStuff.writeUInt32LE(this.externalFileAttributes, 38);\n // relative offset of local header 4 bytes\n fixedSizeStuff.writeUInt32LE(normalRelativeOffsetOfLocalHeader, 42);\n\n return Buffer.concat([\n fixedSizeStuff,\n // file name (variable size)\n this.utf8FileName,\n // extra field (variable size)\n zeiefBuffer,\n // file comment (variable size)\n this.fileComment,\n ]);\n};\nEntry.prototype.getCompressionMethod = function() {\n var NO_COMPRESSION = 0;\n var DEFLATE_COMPRESSION = 8;\n return this.compress ? DEFLATE_COMPRESSION : NO_COMPRESSION;\n};\n\nfunction dateToDosDateTime(jsDate) {\n var date = 0;\n date |= jsDate.getDate() & 0x1f; // 1-31\n date |= ((jsDate.getMonth() + 1) & 0xf) << 5; // 0-11, 1-12\n date |= ((jsDate.getFullYear() - 1980) & 0x7f) << 9; // 0-128, 1980-2108\n\n var time = 0;\n time |= Math.floor(jsDate.getSeconds() / 2); // 0-59, 0-29 (lose odd numbers)\n time |= (jsDate.getMinutes() & 0x3f) << 5; // 0-59\n time |= (jsDate.getHours() & 0x1f) << 11; // 0-23\n\n return {date: date, time: time};\n}\n\nfunction writeUInt64LE(buffer, n, offset) {\n // can't use bitshift here, because JavaScript only allows bitshifting on 32-bit integers.\n var high = Math.floor(n / 0x100000000);\n var low = n % 0x100000000;\n buffer.writeUInt32LE(low, offset);\n buffer.writeUInt32LE(high, offset + 4);\n}\n\nfunction defaultCallback(err) {\n if (err) throw err;\n}\n\nutil.inherits(ByteCounter, Transform);\nfunction ByteCounter(options) {\n Transform.call(this, options);\n this.byteCount = 0;\n}\nByteCounter.prototype._transform = function(chunk, encoding, cb) {\n this.byteCount += chunk.length;\n cb(null, chunk);\n};\n\nutil.inherits(Crc32Watcher, Transform);\nfunction Crc32Watcher(options) {\n Transform.call(this, options);\n this.crc32 = 0;\n}\nCrc32Watcher.prototype._transform = function(chunk, encoding, cb) {\n this.crc32 = crc32.unsigned(chunk, this.crc32);\n cb(null, chunk);\n};\n\nvar cp437 = '\\u0000\u263A\u263B\u2665\u2666\u2663\u2660\u2022\u25D8\u25CB\u25D9\u2642\u2640\u266A\u266B\u263C\u25BA\u25C4\u2195\u203C\u00B6\u00A7\u25AC\u21A8\u2191\u2193\u2192\u2190\u221F\u2194\u25B2\u25BC !\"#$%&\\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u2302\u00C7\u00FC\u00E9\u00E2\u00E4\u00E0\u00E5\u00E7\u00EA\u00EB\u00E8\u00EF\u00EE\u00EC\u00C4\u00C5\u00C9\u00E6\u00C6\u00F4\u00F6\u00F2\u00FB\u00F9\u00FF\u00D6\u00DC\u00A2\u00A3\u00A5\u20A7\u0192\u00E1\u00ED\u00F3\u00FA\u00F1\u00D1\u00AA\u00BA\u00BF\u2310\u00AC\u00BD\u00BC\u00A1\u00AB\u00BB\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255D\u255C\u255B\u2510\u2514\u2534\u252C\u251C\u2500\u253C\u255E\u255F\u255A\u2554\u2569\u2566\u2560\u2550\u256C\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256B\u256A\u2518\u250C\u2588\u2584\u258C\u2590\u2580\u03B1\u00DF\u0393\u03C0\u03A3\u03C3\u00B5\u03C4\u03A6\u0398\u03A9\u03B4\u221E\u03C6\u03B5\u2229\u2261\u00B1\u2265\u2264\u2320\u2321\u00F7\u2248\u00B0\u2219\u00B7\u221A\u207F\u00B2\u25A0\u00A0';\nif (cp437.length !== 256) throw new Error(\"assertion failure\");\nvar reverseCp437 = null;\n\nfunction encodeCp437(string) {\n if (/^[\\x20-\\x7e]*$/.test(string)) {\n // CP437, ASCII, and UTF-8 overlap in this range.\n return bufferFrom(string, \"utf-8\");\n }\n\n // This is the slow path.\n if (reverseCp437 == null) {\n // cache this once\n reverseCp437 = {};\n for (var i = 0; i < cp437.length; i++) {\n reverseCp437[cp437[i]] = i;\n }\n }\n\n var result = bufferAlloc(string.length);\n for (var i = 0; i < string.length; i++) {\n var b = reverseCp437[string[i]];\n if (b == null) throw new Error(\"character not encodable in CP437: \" + JSON.stringify(string[i]));\n result[i] = b;\n }\n\n return result;\n}\n\nfunction bufferAlloc(size) {\n bufferAlloc = modern;\n try {\n return bufferAlloc(size);\n } catch (e) {\n bufferAlloc = legacy;\n return bufferAlloc(size);\n }\n function modern(size) {\n return Buffer.allocUnsafe(size);\n }\n function legacy(size) {\n return new Buffer(size);\n }\n}\nfunction bufferFrom(something, encoding) {\n bufferFrom = modern;\n try {\n return bufferFrom(something, encoding);\n } catch (e) {\n bufferFrom = legacy;\n return bufferFrom(something, encoding);\n }\n function modern(something, encoding) {\n return Buffer.from(something, encoding);\n }\n function legacy(something, encoding) {\n return new Buffer(something, encoding);\n }\n}\nfunction bufferIncludes(buffer, content) {\n bufferIncludes = modern;\n try {\n return bufferIncludes(buffer, content);\n } catch (e) {\n bufferIncludes = legacy;\n return bufferIncludes(buffer, content);\n }\n function modern(buffer, content) {\n return buffer.includes(content);\n }\n function legacy(buffer, content) {\n for (var i = 0; i <= buffer.length - content.length; i++) {\n for (var j = 0;; j++) {\n if (j === content.length) return true;\n if (buffer[i + j] !== content[j]) break;\n }\n }\n return false;\n }\n}\n", "import { MinecraftFolder, MinecraftLocation } from '@xmcl/core'\nimport type { Version } from '@xmcl/core'\nimport { writeFile } from 'fs/promises'\nimport { FetchOptions, InstallOptions, doFetch, ensureFile } from './utils'\n\nexport interface FabricArtifactVersion {\n gameVersion?: string // \"20w10a\",\n separator?: string\n build?: number\n maven: string // \"net.fabricmc:yarn:20w10a+build.7\",\n version: string // \"20w10a+build.7\",\n stable: boolean\n}\n\nexport interface FabricArtifacts {\n mappings: FabricArtifactVersion[]\n loader: FabricArtifactVersion[]\n}\n\nexport interface FabricLoaderArtifact {\n loader: FabricArtifactVersion\n intermediary: FabricArtifactVersion\n launcherMeta: {\n version: number\n libraries: {\n client: { name: string; url: string }[]\n common: { name: string; url: string }[]\n server: { name: string; url: string }[]\n }\n mainClass: {\n client: string\n server: string\n }\n }\n}\n\n/**\n * Get supported fabric game versions\n */\nexport async function getFabricGames(options?: FetchOptions): Promise<string[]> {\n const response = await doFetch(options, `${DEFAULT_META_URL_FABRIC}/v2/game`)\n const body = await response.json() as Array<{ version: string }>\n return body.map((g) => g.version)\n}\n\n/**\n * Get fabric-loader artifact list\n */\nexport async function getFabricLoaders(options?: FetchOptions): Promise<FabricArtifactVersion[]> {\n const response = await doFetch(options, `${DEFAULT_META_URL_FABRIC}/v2/versions/loader`)\n const body = response.json()\n return body\n}\n\n/**\n * Get fabric-loader artifact list by Minecraft version\n * @param minecraft The minecraft version\n */\nexport async function getLoaderArtifactListFor(minecraft: string, options?: FetchOptions): Promise<FabricLoaderArtifact[]> {\n const response = await doFetch(options, `${DEFAULT_META_URL_FABRIC}/v2/versions/loader/` + minecraft)\n const body = response.json()\n return body\n}\n/**\n * Get fabric-loader artifact list by Minecraft version\n * @param minecraft The minecraft version\n * @param loader The yarn-loader version\n */\nexport async function getFabricLoaderArtifact(minecraft: string, loader: string, options?: FetchOptions): Promise<FabricLoaderArtifact> {\n const response = await doFetch(options, `${DEFAULT_META_URL_FABRIC}/v2/versions/loader/` + minecraft + '/' + loader)\n const body = response.json()\n return body\n}\n\nexport interface FabricInstallOptions extends InstallOptions {\n side?: 'client' | 'server'\n}\n\n/**\n * Generate fabric version json from loader artifact.\n * @param loader The fabric loader artifact\n * @param side The side of the fabric\n * @param options\n * @returns The generated version json\n */\nexport function getVersionJsonFromLoaderArtifact(loader: FabricLoaderArtifact, side: 'client' | 'server', options: FabricInstallOptions = {}) {\n const mcversion = loader.intermediary.version\n const id = options.versionId || `${mcversion}-fabric${loader.loader.version}`\n const libraries = [\n { name: loader.loader.maven, url: 'https://maven.fabricmc.net/' },\n { name: loader.intermediary.maven, url: 'https://maven.fabricmc.net/' },\n ...loader.launcherMeta.libraries.common,\n ...loader.launcherMeta.libraries[side],\n ]\n const mainClass = loader.launcherMeta.mainClass[side]\n const inheritsFrom = options.inheritsFrom || mcversion\n\n return {\n id,\n inheritsFrom,\n mainClass,\n libraries,\n arguments: {\n game: [],\n jvm: [],\n },\n releaseTime: new Date().toJSON(),\n time: new Date().toJSON(),\n }\n}\n\n/**\n * Install fabric version json.\n *\n * If side is `server`, it requires the Minecraft version json to be installed.\n *\n * @returns The installed version id\n */\nexport async function installFabricByLoaderArtifact(loader: FabricLoaderArtifact, minecraft: MinecraftLocation, options: FabricInstallOptions = {}) {\n const folder = MinecraftFolder.from(minecraft)\n\n const side = options.side || 'client'\n const version = getVersionJsonFromLoaderArtifact(loader, side, options)\n\n const jsonFile = side === 'client' ? folder.getVersionJson(version.id) : folder.getVersionServerJson(version.id)\n await ensureFile(jsonFile)\n await writeFile(jsonFile, JSON.stringify(version, null, 4))\n\n return version.id\n}\n\nexport interface InstallFabricVersionOptions extends FetchOptions {\n minecraftVersion: string\n version: string\n minecraft: MinecraftLocation\n side?: 'client' | 'server'\n}\n\nexport const DEFAULT_META_URL_FABRIC = 'https://meta.fabricmc.net'\n\nexport async function installFabric(options: InstallFabricVersionOptions) {\n const side = options.side ?? 'client'\n const url = side === 'client'\n ? `${DEFAULT_META_URL_FABRIC}/v2/versions/loader/${options.minecraftVersion}/${options.version}/profile/json`\n : `${DEFAULT_META_URL_FABRIC}/v2/versions/loader/${options.minecraftVersion}/${options.version}/server/json`\n const response = await doFetch(options, url)\n const content: Version = await response.json() as any\n\n const minecraft = MinecraftFolder.from(options.minecraft)\n const versionName = `${options.minecraftVersion}-fabric${options.version}`\n content.id = versionName\n\n const jsonPath = side === 'client' ? minecraft.getVersionJson(versionName) : minecraft.getVersionServerJson(versionName)\n\n await ensureFile(jsonPath)\n await writeFile(jsonPath, JSON.stringify(content))\n\n return versionName\n}\n", "/* eslint-disable n/no-unsupported-features/node-builtins */\nimport { ChildProcess, ExecOptions, spawn, SpawnOptions } from 'child_process'\nimport { Abortable } from 'events'\nimport { access, mkdir, stat } from 'fs/promises'\nimport { dirname } from 'path'\n\nexport { checksum } from '@xmcl/core'\n\nexport function missing(target: string) {\n return access(target).then(() => false, () => true)\n}\n\nexport async function ensureDir(target: string) {\n try {\n await mkdir(target)\n } catch (err) {\n const e: any = err\n if (await stat(target).then((s) => s.isDirectory()).catch(() => false)) { return }\n if (e.code === 'EEXIST') { return }\n if (e.code === 'ENOENT') {\n if (dirname(target) === target) {\n throw e\n }\n try {\n await ensureDir(dirname(target))\n await mkdir(target)\n } catch {\n if (await stat(target).then((s) => s.isDirectory()).catch((e) => false)) { return }\n throw e\n }\n return\n }\n throw e\n }\n}\n\nexport interface SpawnJavaOptions {\n /**\n * The java exectable path. It will use `java` by default.\n *\n * @defaults \"java\"\n */\n java?: string\n\n /**\n * The spawn process function. Used for spawn the java process at the end.\n *\n * By default, it will be the spawn function from \"child_process\" module. You can use this option to change the 3rd party spawn like [cross-spawn](https://www.npmjs.com/package/cross-spawn)\n */\n spawn?: (command: string, args?: ReadonlyArray<string>, options?: SpawnOptions) => ChildProcess\n}\n\nexport function ensureFile(target: string) {\n return ensureDir(dirname(target))\n}\nexport function normalizeArray<T>(arr: T | T[] = []): T[] {\n return arr instanceof Array ? arr : [arr]\n}\nexport function spawnProcess(spawnJavaOptions: SpawnJavaOptions, args: string[], options?: ExecOptions) {\n const process = (spawnJavaOptions?.spawn ?? spawn)(spawnJavaOptions.java ?? 'java', args, options)\n return waitProcess(process)\n}\n\nexport function waitProcess(process: ChildProcess) {\n return new Promise<void>((resolve, reject) => {\n const errorMsg: string[] = []\n process.on('error', (err) => {\n reject(err)\n })\n process.on('close', (code) => {\n if (code !== 0) { reject(new Error(errorMsg.join(''))) } else { resolve() }\n })\n process.on('exit', (code) => {\n if (code !== 0) { reject(new Error(errorMsg.join(''))) } else { resolve() }\n })\n process.stdout?.setEncoding('utf-8')\n process.stdout?.on('data', (buf) => { })\n process.stderr?.setEncoding('utf-8')\n process.stderr?.on('data', (buf) => { errorMsg.push(buf.toString()) })\n })\n}\n\n/**\n * Join two urls\n */\nexport function joinUrl(a: string, b: string) {\n if (a.endsWith('/') && b.startsWith('/')) {\n return a + b.substring(1)\n }\n if (!a.endsWith('/') && !b.startsWith('/')) {\n return a + '/' + b\n }\n return a + b\n}\n\nexport interface ParallelTaskOptions {\n throwErrorImmediately?: boolean\n}\n/**\n * Shared install options\n */\nexport interface InstallOptions {\n /**\n * When you want to install a version over another one.\n *\n * Like, you want to install liteloader over a forge version.\n * You should fill this with that forge version id.\n */\n inheritsFrom?: string\n\n /**\n * Override the newly installed version id.\n *\n * If this is absent, the installed version id will be either generated or provided by installer.\n */\n versionId?: string\n}\n\nexport function errorToString(e: any) {\n if (e instanceof Error) {\n return e.stack ? e.stack : e.message\n }\n return e.toString()\n}\n\nexport interface FetchOptions extends Abortable {\n fetch?: (url: string, init?: RequestInit) => Promise<Response>\n}\n\nexport function doFetch(o: FetchOptions | undefined, url: string, init?: RequestInit) {\n if (init) {\n init.signal = o?.signal\n } else {\n init = { signal: o?.signal }\n }\n return o?.fetch ? o.fetch(url, init) : fetch(url, init)\n}\n", "import { MinecraftFolder, MinecraftLocation } from '@xmcl/core'\nimport { Task, task } from '@xmcl/task'\nimport { readFile, writeFile } from 'fs/promises'\nimport { join } from 'path'\nimport { Dispatcher, request } from 'undici'\nimport { ensureDir, InstallOptions, missing } from './utils'\n\nexport const DEFAULT_VERSION_MANIFEST = 'http://dl.liteloader.com/versions/versions.json'\n/**\n * The liteloader version list. Containing the minecraft version -> liteloader version info mapping.\n */\nexport interface LiteloaderVersionList {\n meta: {\n description: string\n authors: string\n url: string\n updated: string\n updatedTime: number\n }\n versions: { [version: string]: { snapshot?: LiteloaderVersion; release?: LiteloaderVersion } }\n}\nfunction processLibraries(lib: { name: string; url?: string }) {\n if (Object.keys(lib).length === 1 && lib.name) {\n if (lib.name.startsWith('org.ow2.asm')) {\n lib.url = 'https://files.minecraftforge.net/maven/'\n }\n }\n return lib\n}\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace LiteloaderVersionList {\n export function parse(content: string) {\n const result = JSON.parse(content)\n const metalist = { meta: result.meta, versions: {} }\n for (const mcversion in result.versions) {\n const versions: { release?: LiteloaderVersion; snapshot?: LiteloaderVersion } =\n (metalist.versions as any)[mcversion] = {}\n const snapshots = result.versions[mcversion].snapshots\n const artifacts = result.versions[mcversion].artefacts // that's right, artefact\n const url = result.versions[mcversion].repo.url\n if (snapshots) {\n const { stream, file, version, md5, timestamp, tweakClass, libraries } = snapshots['com.mumfrey:liteloader'].latest\n const type = (stream === 'RELEASE' ? 'RELEASE' : 'SNAPSHOT')\n versions.snapshot = {\n url,\n type,\n file,\n version,\n md5,\n timestamp,\n mcversion,\n tweakClass,\n libraries: libraries.map(processLibraries),\n }\n }\n if (artifacts) {\n const { stream, file, version, md5, timestamp, tweakClass, libraries } = artifacts['com.mumfrey:liteloader'].latest\n const type = (stream === 'RELEASE' ? 'RELEASE' : 'SNAPSHOT')\n versions.release = {\n url,\n type,\n file,\n version,\n md5,\n timestamp,\n mcversion,\n tweakClass,\n libraries: libraries.map(processLibraries),\n }\n }\n }\n return metalist\n }\n}\n\n/**\n * A liteloader remote version information\n */\nexport interface LiteloaderVersion {\n version: string\n url: string\n file: string\n mcversion: string\n type: 'RELEASE' | 'SNAPSHOT'\n md5: string\n timestamp: string\n libraries: Array<{ name: string; url?: string }>\n tweakClass: string\n}\n\nconst snapshotRoot = 'http://dl.liteloader.com/versions/'\nconst releaseRoot = 'http://repo.mumfrey.com/content/repositories/liteloader/'\n\n/**\n * This error is only thrown from liteloader install currently.\n */\nexport class MissingVersionJsonError extends Error {\n constructor(public version: string,\n /**\n * The path of version json\n */\n public path: string) {\n super()\n this.name = 'MissingVersionJson'\n }\n}\n/**\n * Get or update the LiteLoader version list.\n *\n * This will request liteloader offical json by default. You can replace the request by assigning the remote option.\n */\nexport async function getLiteloaderVersionList(options: {\n /**\n * The request dispatcher\n */\n dispatcher?: Dispatcher\n} = {}): Promise<LiteloaderVersionList> {\n const response = await request(DEFAULT_VERSION_MANIFEST, { dispatcher: options.dispatcher, throwOnError: true })\n const body = await response.body.text()\n return LiteloaderVersionList.parse(body)\n}\n\n/**\n * Install the liteloader to specific minecraft location.\n *\n * This will install the liteloader amount on the corresponded Minecraft version by default.\n * If you want to install over the forge. You should first install forge and pass the installed forge version id to the third param,\n * like `1.12-forge-xxxx`\n *\n * @param versionMeta The liteloader version met