feat: rewrite entirely the modrinth installer and allow to update already installed modpack to a newer version
This commit is contained in:
parent
6bcde4cd8c
commit
82af1e947f
12 changed files with 1129 additions and 184 deletions
|
|
@ -30,7 +30,7 @@
|
|||
"eslint-config-prettier": "^10.1.8",
|
||||
"globals": "^17.4.0",
|
||||
"happy-dom": "^20.8.4",
|
||||
"p-queue": "^8.1.1",
|
||||
"p-queue": "^9.3.0",
|
||||
"prettier": "3.6.2",
|
||||
"tsup": "^8.5.1",
|
||||
"typescript-eslint": "^8.57.1",
|
||||
|
|
|
|||
318
pnpm-lock.yaml
generated
318
pnpm-lock.yaml
generated
|
|
@ -33,14 +33,14 @@ importers:
|
|||
specifier: ^20.8.4
|
||||
version: 20.8.4
|
||||
p-queue:
|
||||
specifier: ^8.1.1
|
||||
version: 8.1.1
|
||||
specifier: ^9.3.0
|
||||
version: 9.3.0
|
||||
prettier:
|
||||
specifier: 3.6.2
|
||||
version: 3.6.2
|
||||
tsup:
|
||||
specifier: ^8.5.1
|
||||
version: 8.5.1(postcss@8.5.8)(typescript@5.9.2)
|
||||
version: 8.5.1(postcss@8.5.15)(typescript@5.9.2)
|
||||
typescript-eslint:
|
||||
specifier: ^8.57.1
|
||||
version: 8.57.1(eslint@10.0.3)(typescript@5.9.2)
|
||||
|
|
@ -438,126 +438,251 @@ packages:
|
|||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.62.2':
|
||||
resolution: {integrity: sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@rollup/rollup-android-arm64@4.59.0':
|
||||
resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@rollup/rollup-android-arm64@4.62.2':
|
||||
resolution: {integrity: sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@rollup/rollup-darwin-arm64@4.59.0':
|
||||
resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@rollup/rollup-darwin-arm64@4.62.2':
|
||||
resolution: {integrity: sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@rollup/rollup-darwin-x64@4.59.0':
|
||||
resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@rollup/rollup-darwin-x64@4.62.2':
|
||||
resolution: {integrity: sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@rollup/rollup-freebsd-arm64@4.59.0':
|
||||
resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rollup/rollup-freebsd-arm64@4.62.2':
|
||||
resolution: {integrity: sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rollup/rollup-freebsd-x64@4.59.0':
|
||||
resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rollup/rollup-freebsd-x64@4.62.2':
|
||||
resolution: {integrity: sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.59.0':
|
||||
resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.62.2':
|
||||
resolution: {integrity: sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.59.0':
|
||||
resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.62.2':
|
||||
resolution: {integrity: sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.59.0':
|
||||
resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.62.2':
|
||||
resolution: {integrity: sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.59.0':
|
||||
resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.62.2':
|
||||
resolution: {integrity: sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.59.0':
|
||||
resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.62.2':
|
||||
resolution: {integrity: sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-loong64-musl@4.59.0':
|
||||
resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-loong64-musl@4.62.2':
|
||||
resolution: {integrity: sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.59.0':
|
||||
resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.62.2':
|
||||
resolution: {integrity: sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-musl@4.59.0':
|
||||
resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-musl@4.62.2':
|
||||
resolution: {integrity: sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.59.0':
|
||||
resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.62.2':
|
||||
resolution: {integrity: sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.59.0':
|
||||
resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.62.2':
|
||||
resolution: {integrity: sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.59.0':
|
||||
resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.62.2':
|
||||
resolution: {integrity: sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.59.0':
|
||||
resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.62.2':
|
||||
resolution: {integrity: sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.59.0':
|
||||
resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.62.2':
|
||||
resolution: {integrity: sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-openbsd-x64@4.59.0':
|
||||
resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@rollup/rollup-openbsd-x64@4.62.2':
|
||||
resolution: {integrity: sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@rollup/rollup-openharmony-arm64@4.59.0':
|
||||
resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@rollup/rollup-openharmony-arm64@4.62.2':
|
||||
resolution: {integrity: sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@rollup/rollup-win32-arm64-msvc@4.59.0':
|
||||
resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-arm64-msvc@4.62.2':
|
||||
resolution: {integrity: sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-ia32-msvc@4.59.0':
|
||||
resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-ia32-msvc@4.62.2':
|
||||
resolution: {integrity: sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-x64-gnu@4.59.0':
|
||||
resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-x64-gnu@4.62.2':
|
||||
resolution: {integrity: sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-x64-msvc@4.59.0':
|
||||
resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-x64-msvc@4.62.2':
|
||||
resolution: {integrity: sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@standard-schema/spec@1.1.0':
|
||||
resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
|
||||
|
||||
|
|
@ -576,6 +701,9 @@ packages:
|
|||
'@types/estree@1.0.8':
|
||||
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
||||
|
||||
'@types/estree@1.0.9':
|
||||
resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==}
|
||||
|
||||
'@types/json-schema@7.0.15':
|
||||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||
|
||||
|
|
@ -962,8 +1090,8 @@ packages:
|
|||
mz@2.7.0:
|
||||
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
|
||||
|
||||
nanoid@3.3.11:
|
||||
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
|
||||
nanoid@3.3.15:
|
||||
resolution: {integrity: sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==}
|
||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||
hasBin: true
|
||||
|
||||
|
|
@ -989,13 +1117,13 @@ packages:
|
|||
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
p-queue@8.1.1:
|
||||
resolution: {integrity: sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ==}
|
||||
engines: {node: '>=18'}
|
||||
p-queue@9.3.0:
|
||||
resolution: {integrity: sha512-7NED7xhQ74Ngp4JP/2e0VZHp7vSWfJfqeiR92jPgxsz6m0Se4P03YoTKa9dDXyZ3r6P616gUXttrB6nnHYKang==}
|
||||
engines: {node: '>=20'}
|
||||
|
||||
p-timeout@6.1.4:
|
||||
resolution: {integrity: sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==}
|
||||
engines: {node: '>=14.16'}
|
||||
p-timeout@7.0.1:
|
||||
resolution: {integrity: sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==}
|
||||
engines: {node: '>=20'}
|
||||
|
||||
path-exists@4.0.0:
|
||||
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
|
||||
|
|
@ -1015,6 +1143,10 @@ packages:
|
|||
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
picomatch@4.0.4:
|
||||
resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
pirates@4.0.7:
|
||||
resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}
|
||||
engines: {node: '>= 6'}
|
||||
|
|
@ -1040,8 +1172,8 @@ packages:
|
|||
yaml:
|
||||
optional: true
|
||||
|
||||
postcss@8.5.8:
|
||||
resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==}
|
||||
postcss@8.5.15:
|
||||
resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
prelude-ls@1.2.1:
|
||||
|
|
@ -1070,6 +1202,11 @@ packages:
|
|||
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
||||
hasBin: true
|
||||
|
||||
rollup@4.62.2:
|
||||
resolution: {integrity: sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==}
|
||||
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
||||
hasBin: true
|
||||
|
||||
semver@7.7.4:
|
||||
resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==}
|
||||
engines: {node: '>=10'}
|
||||
|
|
@ -1126,6 +1263,10 @@ packages:
|
|||
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
tinyglobby@0.2.17:
|
||||
resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
tinyrainbow@3.1.0:
|
||||
resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
|
@ -1520,78 +1661,153 @@ snapshots:
|
|||
'@rollup/rollup-android-arm-eabi@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-android-arm64@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-android-arm64@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-darwin-arm64@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-darwin-arm64@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-darwin-x64@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-darwin-x64@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-freebsd-arm64@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-freebsd-arm64@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-freebsd-x64@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-freebsd-x64@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-loong64-musl@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-loong64-musl@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-ppc64-musl@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-ppc64-musl@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-openbsd-x64@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-openbsd-x64@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-openharmony-arm64@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-openharmony-arm64@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-arm64-msvc@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-arm64-msvc@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-ia32-msvc@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-ia32-msvc@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-x64-gnu@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-x64-gnu@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-x64-msvc@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-x64-msvc@4.62.2':
|
||||
optional: true
|
||||
|
||||
'@standard-schema/spec@1.1.0': {}
|
||||
|
||||
'@types/adm-zip@0.5.8':
|
||||
|
|
@ -1609,6 +1825,8 @@ snapshots:
|
|||
|
||||
'@types/estree@1.0.8': {}
|
||||
|
||||
'@types/estree@1.0.9': {}
|
||||
|
||||
'@types/json-schema@7.0.15': {}
|
||||
|
||||
'@types/node@25.5.0':
|
||||
|
|
@ -1961,6 +2179,10 @@ snapshots:
|
|||
optionalDependencies:
|
||||
picomatch: 4.0.3
|
||||
|
||||
fdir@6.5.0(picomatch@4.0.4):
|
||||
optionalDependencies:
|
||||
picomatch: 4.0.4
|
||||
|
||||
file-entry-cache@8.0.0:
|
||||
dependencies:
|
||||
flat-cache: 4.0.1
|
||||
|
|
@ -2068,7 +2290,7 @@ snapshots:
|
|||
object-assign: 4.1.1
|
||||
thenify-all: 1.6.0
|
||||
|
||||
nanoid@3.3.11: {}
|
||||
nanoid@3.3.15: {}
|
||||
|
||||
natural-compare@1.4.0: {}
|
||||
|
||||
|
|
@ -2093,12 +2315,12 @@ snapshots:
|
|||
dependencies:
|
||||
p-limit: 3.1.0
|
||||
|
||||
p-queue@8.1.1:
|
||||
p-queue@9.3.0:
|
||||
dependencies:
|
||||
eventemitter3: 5.0.4
|
||||
p-timeout: 6.1.4
|
||||
p-timeout: 7.0.1
|
||||
|
||||
p-timeout@6.1.4: {}
|
||||
p-timeout@7.0.1: {}
|
||||
|
||||
path-exists@4.0.0: {}
|
||||
|
||||
|
|
@ -2110,6 +2332,8 @@ snapshots:
|
|||
|
||||
picomatch@4.0.3: {}
|
||||
|
||||
picomatch@4.0.4: {}
|
||||
|
||||
pirates@4.0.7: {}
|
||||
|
||||
pkg-types@1.3.1:
|
||||
|
|
@ -2118,15 +2342,15 @@ snapshots:
|
|||
mlly: 1.8.1
|
||||
pathe: 2.0.3
|
||||
|
||||
postcss-load-config@6.0.1(postcss@8.5.8):
|
||||
postcss-load-config@6.0.1(postcss@8.5.15):
|
||||
dependencies:
|
||||
lilconfig: 3.1.3
|
||||
optionalDependencies:
|
||||
postcss: 8.5.8
|
||||
postcss: 8.5.15
|
||||
|
||||
postcss@8.5.8:
|
||||
postcss@8.5.15:
|
||||
dependencies:
|
||||
nanoid: 3.3.11
|
||||
nanoid: 3.3.15
|
||||
picocolors: 1.1.1
|
||||
source-map-js: 1.2.1
|
||||
|
||||
|
|
@ -2171,6 +2395,37 @@ snapshots:
|
|||
'@rollup/rollup-win32-x64-msvc': 4.59.0
|
||||
fsevents: 2.3.3
|
||||
|
||||
rollup@4.62.2:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.9
|
||||
optionalDependencies:
|
||||
'@rollup/rollup-android-arm-eabi': 4.62.2
|
||||
'@rollup/rollup-android-arm64': 4.62.2
|
||||
'@rollup/rollup-darwin-arm64': 4.62.2
|
||||
'@rollup/rollup-darwin-x64': 4.62.2
|
||||
'@rollup/rollup-freebsd-arm64': 4.62.2
|
||||
'@rollup/rollup-freebsd-x64': 4.62.2
|
||||
'@rollup/rollup-linux-arm-gnueabihf': 4.62.2
|
||||
'@rollup/rollup-linux-arm-musleabihf': 4.62.2
|
||||
'@rollup/rollup-linux-arm64-gnu': 4.62.2
|
||||
'@rollup/rollup-linux-arm64-musl': 4.62.2
|
||||
'@rollup/rollup-linux-loong64-gnu': 4.62.2
|
||||
'@rollup/rollup-linux-loong64-musl': 4.62.2
|
||||
'@rollup/rollup-linux-ppc64-gnu': 4.62.2
|
||||
'@rollup/rollup-linux-ppc64-musl': 4.62.2
|
||||
'@rollup/rollup-linux-riscv64-gnu': 4.62.2
|
||||
'@rollup/rollup-linux-riscv64-musl': 4.62.2
|
||||
'@rollup/rollup-linux-s390x-gnu': 4.62.2
|
||||
'@rollup/rollup-linux-x64-gnu': 4.62.2
|
||||
'@rollup/rollup-linux-x64-musl': 4.62.2
|
||||
'@rollup/rollup-openbsd-x64': 4.62.2
|
||||
'@rollup/rollup-openharmony-arm64': 4.62.2
|
||||
'@rollup/rollup-win32-arm64-msvc': 4.62.2
|
||||
'@rollup/rollup-win32-ia32-msvc': 4.62.2
|
||||
'@rollup/rollup-win32-x64-gnu': 4.62.2
|
||||
'@rollup/rollup-win32-x64-msvc': 4.62.2
|
||||
fsevents: 2.3.3
|
||||
|
||||
semver@7.7.4: {}
|
||||
|
||||
shebang-command@2.0.0:
|
||||
|
|
@ -2218,6 +2473,11 @@ snapshots:
|
|||
fdir: 6.5.0(picomatch@4.0.3)
|
||||
picomatch: 4.0.3
|
||||
|
||||
tinyglobby@0.2.17:
|
||||
dependencies:
|
||||
fdir: 6.5.0(picomatch@4.0.4)
|
||||
picomatch: 4.0.4
|
||||
|
||||
tinyrainbow@3.1.0: {}
|
||||
|
||||
tree-kill@1.2.2: {}
|
||||
|
|
@ -2228,7 +2488,7 @@ snapshots:
|
|||
|
||||
ts-interface-checker@0.1.13: {}
|
||||
|
||||
tsup@8.5.1(postcss@8.5.8)(typescript@5.9.2):
|
||||
tsup@8.5.1(postcss@8.5.15)(typescript@5.9.2):
|
||||
dependencies:
|
||||
bundle-require: 5.1.0(esbuild@0.27.4)
|
||||
cac: 6.7.14
|
||||
|
|
@ -2239,7 +2499,7 @@ snapshots:
|
|||
fix-dts-default-cjs-exports: 1.0.1
|
||||
joycon: 3.1.1
|
||||
picocolors: 1.1.1
|
||||
postcss-load-config: 6.0.1(postcss@8.5.8)
|
||||
postcss-load-config: 6.0.1(postcss@8.5.15)
|
||||
resolve-from: 5.0.0
|
||||
rollup: 4.59.0
|
||||
source-map: 0.7.6
|
||||
|
|
@ -2248,7 +2508,7 @@ snapshots:
|
|||
tinyglobby: 0.2.15
|
||||
tree-kill: 1.2.2
|
||||
optionalDependencies:
|
||||
postcss: 8.5.8
|
||||
postcss: 8.5.15
|
||||
typescript: 5.9.2
|
||||
transitivePeerDependencies:
|
||||
- jiti
|
||||
|
|
@ -2286,11 +2546,11 @@ snapshots:
|
|||
vite@7.1.7(@types/node@25.5.0):
|
||||
dependencies:
|
||||
esbuild: 0.25.12
|
||||
fdir: 6.5.0(picomatch@4.0.3)
|
||||
picomatch: 4.0.3
|
||||
postcss: 8.5.8
|
||||
rollup: 4.59.0
|
||||
tinyglobby: 0.2.15
|
||||
fdir: 6.5.0(picomatch@4.0.4)
|
||||
picomatch: 4.0.4
|
||||
postcss: 8.5.15
|
||||
rollup: 4.62.2
|
||||
tinyglobby: 0.2.17
|
||||
optionalDependencies:
|
||||
'@types/node': 25.5.0
|
||||
fsevents: 2.3.3
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import path from "path";
|
||||
import { isNeeded } from "../utils/rules";
|
||||
import { Argument, Version, Config } from "../utils/types";
|
||||
import { Argument, Version, FinalConfig } from "../utils/types";
|
||||
import { getLibraries } from "./libraries";
|
||||
import { version as packageVersion } from "../../package.json";
|
||||
import { getArgument } from "./log4j";
|
||||
|
|
@ -9,7 +9,7 @@ import { getArgument } from "./log4j";
|
|||
function fillArguments(
|
||||
arg: string,
|
||||
versionManifest: Version,
|
||||
config: Config,
|
||||
config: FinalConfig,
|
||||
classPaths: string
|
||||
) {
|
||||
const argumentsToFill: { [key: string]: string } = {
|
||||
|
|
@ -51,7 +51,7 @@ function parseArg(
|
|||
this: string[],
|
||||
arg: Argument,
|
||||
versionManifest: Version,
|
||||
config: Config,
|
||||
config: FinalConfig,
|
||||
classPaths: string
|
||||
) {
|
||||
if (isNeeded(arg)) {
|
||||
|
|
@ -106,7 +106,7 @@ function generateClassPaths(
|
|||
|
||||
export async function generateLaunchArguments(
|
||||
versionManifest: Version,
|
||||
config: Config
|
||||
config: FinalConfig
|
||||
) {
|
||||
const jvm: string[] = [];
|
||||
let game: string[] = [];
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import path from "path";
|
||||
import { readJson } from "../utils/fs";
|
||||
import { Version } from "../utils/types";
|
||||
import { getVersionId, ModloaderConfig } from "./modloaders";
|
||||
import { Version, ModloaderConfig } from "../utils/types";
|
||||
import { getVersionId } from "./modloaders";
|
||||
|
||||
function mergeManifests(base: Version, layer: Version) {
|
||||
// Copy needed properties to base
|
||||
// Those properties should be enough for forge at least
|
||||
const result = { ...base }
|
||||
const result = { ...base };
|
||||
result.libraries = [];
|
||||
result.mainClass = layer.mainClass;
|
||||
|
||||
|
|
@ -24,24 +24,24 @@ function mergeManifests(base: Version, layer: Version) {
|
|||
// }
|
||||
|
||||
for (const bLib of base.libraries) {
|
||||
let isInLayer = false
|
||||
let isInLayer = false;
|
||||
for (const lLib of layer.libraries) {
|
||||
const lId = lLib.name.split(":")[1]
|
||||
const bId = bLib.name.split(":")[1]
|
||||
const lId = lLib.name.split(":")[1];
|
||||
const bId = bLib.name.split(":")[1];
|
||||
|
||||
if (lId === bId) {
|
||||
isInLayer = true
|
||||
break
|
||||
isInLayer = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isInLayer) {
|
||||
result.libraries.push(bLib)
|
||||
result.libraries.push(bLib);
|
||||
}
|
||||
}
|
||||
|
||||
for (const lLib of layer.libraries) {
|
||||
result.libraries.push(lLib)
|
||||
result.libraries.push(lLib);
|
||||
}
|
||||
|
||||
// modern versions
|
||||
|
|
@ -59,26 +59,22 @@ function mergeManifests(base: Version, layer: Version) {
|
|||
}
|
||||
} else {
|
||||
// older versions
|
||||
result.minecraftArguments = layer.minecraftArguments
|
||||
result.minecraftArguments = layer.minecraftArguments;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function prepareManifest(config: ModloaderConfig, versionManifest: Version) {
|
||||
const versionId = getVersionId(config)
|
||||
export async function prepareManifest(
|
||||
config: ModloaderConfig,
|
||||
versionManifest: Version,
|
||||
) {
|
||||
const versionId = getVersionId(config);
|
||||
const moddedVersionManifest = await readJson<Version>(
|
||||
path.join(
|
||||
config.paths.versions,
|
||||
versionId,
|
||||
`${versionId}.json`,
|
||||
),
|
||||
path.join(config.paths.versions, versionId, `${versionId}.json`),
|
||||
);
|
||||
|
||||
versionManifest = mergeManifests(
|
||||
versionManifest!,
|
||||
moddedVersionManifest,
|
||||
);
|
||||
versionManifest = mergeManifests(versionManifest!, moddedVersionManifest);
|
||||
|
||||
return versionManifest
|
||||
return versionManifest;
|
||||
}
|
||||
379
src/core/modrinth.ts
Normal file
379
src/core/modrinth.ts
Normal file
|
|
@ -0,0 +1,379 @@
|
|||
import path from "node:path";
|
||||
import {
|
||||
CopyQueue,
|
||||
DeleteQueue,
|
||||
exists,
|
||||
readJson,
|
||||
TreeMakerQueue,
|
||||
} from "../utils/fs";
|
||||
import {
|
||||
FinalConfig,
|
||||
ModrinthManifest,
|
||||
ModrinthManifestFile,
|
||||
PoolFile,
|
||||
} from "../utils/types";
|
||||
import fs from "fs/promises";
|
||||
import { DownloadPool } from "../utils/fetch";
|
||||
import { Instance } from "../launcher";
|
||||
|
||||
export async function getProjectsChanges(
|
||||
instanceFolder: string,
|
||||
manifest: ModrinthManifest,
|
||||
oldManifest?: ModrinthManifest,
|
||||
): Promise<{ addedProjects: PoolFile[]; removedProject: string[] }> {
|
||||
if (oldManifest) {
|
||||
const newFiles = new Map<string, ModrinthManifestFile>();
|
||||
const oldFiles = new Map<string, ModrinthManifestFile>();
|
||||
|
||||
const addedProjects: PoolFile[] = [];
|
||||
const removedProject: string[] = [];
|
||||
|
||||
manifest.files.forEach((f) => {
|
||||
const regex = /https:\/\/(.*)\/data\/(.*)\/versions\/(.*)\/(.*)/gm;
|
||||
|
||||
const fileInfo = regex.exec(f.downloads[0])!;
|
||||
|
||||
newFiles.set(fileInfo[2], f);
|
||||
});
|
||||
|
||||
oldManifest.files.forEach((f) => {
|
||||
const regex = /https:\/\/(.*)\/data\/(.*)\/versions\/(.*)\/(.*)/gm;
|
||||
|
||||
const fileInfo = regex.exec(f.downloads[0])!;
|
||||
|
||||
oldFiles.set(fileInfo[2], f);
|
||||
});
|
||||
|
||||
for (const [fileID, newFile] of newFiles.entries()) {
|
||||
if (!oldFiles.has(fileID)) {
|
||||
// new project
|
||||
addedProjects.push({
|
||||
url: newFile.downloads[0],
|
||||
path: path.join(instanceFolder, newFile.path),
|
||||
size: newFile.fileSize,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (const [fileID, oldFile] of oldFiles.entries()) {
|
||||
if (!newFiles.has(fileID)) {
|
||||
// has been removed in update
|
||||
removedProject.push(path.join(instanceFolder, oldFile.path));
|
||||
} else {
|
||||
// same project
|
||||
const newFile = newFiles.get(fileID)!;
|
||||
if (oldFile.downloads[0] !== newFile.downloads[0]) {
|
||||
// different version
|
||||
// mark old file for deletion
|
||||
// add new one
|
||||
removedProject.push(path.join(instanceFolder, oldFile.path));
|
||||
addedProjects.push({
|
||||
url: newFile.downloads[0],
|
||||
path: path.join(instanceFolder, newFile.path),
|
||||
size: newFile.fileSize,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
addedProjects,
|
||||
removedProject,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
addedProjects: manifest.files.map<PoolFile>((f) => {
|
||||
return {
|
||||
url: f.downloads[0],
|
||||
path: path.join(instanceFolder, f.path),
|
||||
size: f.fileSize,
|
||||
};
|
||||
}),
|
||||
removedProject: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function getOverridesChanges(
|
||||
instanceFolder: string,
|
||||
tempFolder: string,
|
||||
): Promise<{
|
||||
addedOverrides: string[];
|
||||
removedOverrides: string[];
|
||||
addedDirs: string[];
|
||||
removedDirs: string[];
|
||||
}> {
|
||||
const overridesPath = path.join(tempFolder, "pack", "overrides");
|
||||
const overridesList = await fs.readdir(overridesPath, {
|
||||
recursive: true,
|
||||
withFileTypes: true,
|
||||
});
|
||||
|
||||
if (await exists(path.join(tempFolder, "oldPack", "overrides"))) {
|
||||
const oldOverridesPath = path.join(tempFolder, "oldPack", "overrides");
|
||||
// relative path
|
||||
const addedOverrides: string[] = [];
|
||||
// absolute path
|
||||
const removedOverrides: string[] = [];
|
||||
const addedDirs: string[] = [];
|
||||
const removedDirs: string[] = [];
|
||||
|
||||
const oldOverridesList = await fs.readdir(oldOverridesPath, {
|
||||
recursive: true,
|
||||
withFileTypes: true,
|
||||
});
|
||||
|
||||
oldOverridesList.forEach((f) => {
|
||||
const relativePath = path.relative(
|
||||
oldOverridesPath,
|
||||
path.join(f.parentPath, f.name),
|
||||
);
|
||||
if (
|
||||
overridesList.find(
|
||||
(a) =>
|
||||
path.relative(overridesPath, path.join(a.parentPath, a.name)) ===
|
||||
relativePath,
|
||||
)
|
||||
) {
|
||||
// overwrite as it may be a different file
|
||||
if (f.isDirectory()) {
|
||||
removedDirs.push(path.join(instanceFolder, relativePath));
|
||||
addedDirs.push(path.join(instanceFolder, relativePath));
|
||||
} else {
|
||||
removedOverrides.push(path.join(instanceFolder, relativePath));
|
||||
addedOverrides.push(relativePath);
|
||||
}
|
||||
} else {
|
||||
// delete as it is no longer in the new version
|
||||
if (f.isDirectory()) {
|
||||
removedDirs.push(path.join(instanceFolder, relativePath));
|
||||
} else {
|
||||
removedOverrides.push(path.join(instanceFolder, relativePath));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
overridesList.forEach((newFile) => {
|
||||
const relativePath = path.relative(
|
||||
overridesPath,
|
||||
path.join(newFile.parentPath, newFile.name),
|
||||
);
|
||||
|
||||
if (
|
||||
!oldOverridesList.find(
|
||||
(oldFile) =>
|
||||
relativePath ===
|
||||
path.relative(
|
||||
oldOverridesPath,
|
||||
path.join(oldFile.parentPath, oldFile.name),
|
||||
),
|
||||
)
|
||||
) {
|
||||
// new file
|
||||
if (!newFile.isDirectory()) {
|
||||
addedOverrides.push(relativePath);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return { addedOverrides, removedOverrides, addedDirs, removedDirs };
|
||||
}
|
||||
|
||||
const addedDirs: string[] = [];
|
||||
const addedOverrides: string[] = [];
|
||||
|
||||
for (const file of overridesList) {
|
||||
if (file.isDirectory()) {
|
||||
addedDirs.push(
|
||||
path.relative(overridesPath, path.join(file.parentPath, file.name)),
|
||||
);
|
||||
} else
|
||||
addedOverrides.push(
|
||||
path.relative(overridesPath, path.join(file.parentPath, file.name)),
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
addedOverrides,
|
||||
removedOverrides: [],
|
||||
addedDirs,
|
||||
removedDirs: [],
|
||||
};
|
||||
}
|
||||
|
||||
export async function generatePackChanges(
|
||||
instanceFolder: string,
|
||||
tempFolder: string,
|
||||
config: FinalConfig,
|
||||
) {
|
||||
const manifestPath = path.join(tempFolder, "pack", "modrinth.index.json");
|
||||
const manifest = await readJson<ModrinthManifest>(manifestPath);
|
||||
let oldManifest: ModrinthManifest | undefined;
|
||||
|
||||
if (config.modrinth?.updateFrom) {
|
||||
const oldManifestPath = path.join(
|
||||
tempFolder,
|
||||
"oldPack",
|
||||
"modrinth.index.json",
|
||||
);
|
||||
oldManifest = await readJson<ModrinthManifest>(oldManifestPath);
|
||||
}
|
||||
|
||||
const modrinthChanges = await getProjectsChanges(
|
||||
instanceFolder,
|
||||
manifest,
|
||||
oldManifest,
|
||||
);
|
||||
const overridesChanges = await getOverridesChanges(
|
||||
instanceFolder,
|
||||
tempFolder,
|
||||
);
|
||||
|
||||
return { modrinthChanges, overridesChanges };
|
||||
}
|
||||
|
||||
export async function ModrinthDownloader(
|
||||
addedProjects: PoolFile[],
|
||||
emit: Instance["emit"],
|
||||
) {
|
||||
const modrinthDownloader = new DownloadPool(addedProjects, {
|
||||
pQueueOptions: {
|
||||
concurrency: 5,
|
||||
},
|
||||
});
|
||||
|
||||
modrinthDownloader.on("completed", () => {
|
||||
emit(
|
||||
"progress",
|
||||
"install-download-modrinth",
|
||||
modrinthDownloader.done,
|
||||
modrinthDownloader.total,
|
||||
modrinthDownloader.doneSize,
|
||||
modrinthDownloader.totalSize,
|
||||
);
|
||||
});
|
||||
await modrinthDownloader.run();
|
||||
}
|
||||
|
||||
export async function ProjectsDeleter(
|
||||
removedProject: string[],
|
||||
emit: Instance["emit"],
|
||||
) {
|
||||
const projectsDeleteQueue = new DeleteQueue(removedProject, {
|
||||
pQueueOptions: {
|
||||
concurrency: 5,
|
||||
},
|
||||
});
|
||||
projectsDeleteQueue.on("completed", () => {
|
||||
emit(
|
||||
"progress",
|
||||
"install-delete-modrinth",
|
||||
projectsDeleteQueue.done,
|
||||
projectsDeleteQueue.total,
|
||||
projectsDeleteQueue.doneSize,
|
||||
projectsDeleteQueue.totalSize,
|
||||
);
|
||||
});
|
||||
await projectsDeleteQueue.run();
|
||||
}
|
||||
|
||||
export async function OverridesTreeMaker(
|
||||
addedDirs: string[],
|
||||
emit: Instance["emit"],
|
||||
) {
|
||||
const overridesTreeMaker = new TreeMakerQueue(addedDirs, {
|
||||
pQueueOptions: {
|
||||
concurrency: 5,
|
||||
},
|
||||
});
|
||||
overridesTreeMaker.on("completed", () => {
|
||||
emit(
|
||||
"progress",
|
||||
"install-delete-overrides",
|
||||
overridesTreeMaker.done,
|
||||
overridesTreeMaker.total,
|
||||
overridesTreeMaker.doneSize,
|
||||
overridesTreeMaker.totalSize,
|
||||
);
|
||||
});
|
||||
await overridesTreeMaker.run();
|
||||
}
|
||||
|
||||
export async function OverridesCopier(
|
||||
addedOverrides: string[],
|
||||
overridesFolder: string,
|
||||
instancePath: string,
|
||||
emit: Instance["emit"],
|
||||
) {
|
||||
const overridesCopyQueue = new CopyQueue(
|
||||
addedOverrides,
|
||||
overridesFolder,
|
||||
instancePath,
|
||||
{
|
||||
pQueueOptions: {
|
||||
concurrency: 5,
|
||||
},
|
||||
},
|
||||
);
|
||||
overridesCopyQueue.on("completed", () => {
|
||||
emit(
|
||||
"progress",
|
||||
"install-copy-overrides",
|
||||
overridesCopyQueue.done,
|
||||
overridesCopyQueue.total,
|
||||
overridesCopyQueue.doneSize,
|
||||
overridesCopyQueue.totalSize,
|
||||
);
|
||||
});
|
||||
await overridesCopyQueue.run();
|
||||
}
|
||||
|
||||
export async function OverridesDeleter(
|
||||
overridesChanges: {
|
||||
addedOverrides: string[];
|
||||
removedOverrides: string[];
|
||||
addedDirs: string[];
|
||||
removedDirs: string[];
|
||||
},
|
||||
emit: Instance["emit"],
|
||||
) {
|
||||
const removedOverridesDeleteQueue = new DeleteQueue(
|
||||
overridesChanges.removedOverrides,
|
||||
{
|
||||
pQueueOptions: {
|
||||
concurrency: 5,
|
||||
},
|
||||
},
|
||||
);
|
||||
removedOverridesDeleteQueue.on("completed", () => {
|
||||
emit(
|
||||
"progress",
|
||||
"install-delete-overrides",
|
||||
removedOverridesDeleteQueue.done,
|
||||
removedOverridesDeleteQueue.total,
|
||||
removedOverridesDeleteQueue.doneSize,
|
||||
removedOverridesDeleteQueue.totalSize,
|
||||
);
|
||||
});
|
||||
await removedOverridesDeleteQueue.run();
|
||||
|
||||
const removedDirsDeleteQueue = new DeleteQueue(
|
||||
overridesChanges.removedOverrides,
|
||||
{
|
||||
pQueueOptions: {
|
||||
concurrency: 5,
|
||||
},
|
||||
},
|
||||
);
|
||||
removedDirsDeleteQueue.on("completed", () => {
|
||||
emit(
|
||||
"progress",
|
||||
"install-delete-overrides",
|
||||
removedDirsDeleteQueue.done,
|
||||
removedDirsDeleteQueue.total,
|
||||
removedDirsDeleteQueue.doneSize,
|
||||
removedDirsDeleteQueue.totalSize,
|
||||
);
|
||||
});
|
||||
await removedDirsDeleteQueue.run();
|
||||
}
|
||||
|
|
@ -1,15 +1,13 @@
|
|||
import { EventEmitter } from "events";
|
||||
import {
|
||||
BaseConfig,
|
||||
Config,
|
||||
InstanceEvents,
|
||||
logger,
|
||||
PoolFile,
|
||||
Version,
|
||||
FinalConfig,
|
||||
ModloaderConfig,
|
||||
} from "../utils/types";
|
||||
import path from "node:path";
|
||||
import fs from "fs/promises";
|
||||
import {
|
||||
argumentsGenerator,
|
||||
AssetsDownloader,
|
||||
|
|
@ -27,23 +25,29 @@ import {
|
|||
} from "../core/modloaders";
|
||||
import { ChildProcessWithoutNullStreams } from "node:child_process";
|
||||
import { prepareManifest } from "../core/mergeManifests";
|
||||
import { DownloadPool } from "../utils/fetch";
|
||||
import {
|
||||
generatePackChanges,
|
||||
ModrinthDownloader,
|
||||
OverridesCopier,
|
||||
OverridesDeleter,
|
||||
ProjectsDeleter,
|
||||
} from "../core/modrinth";
|
||||
|
||||
export function defineConfig(logger: logger, ...layers: Partial<BaseConfig>[]) {
|
||||
let config: Partial<BaseConfig> = {} as Partial<BaseConfig>;
|
||||
for (const layer of layers) {
|
||||
config = { ...config, ...layer };
|
||||
}
|
||||
export function defineConfig(logger: logger, config: Config) {
|
||||
if (
|
||||
!config.auth ||
|
||||
!config.paths?.root ||
|
||||
!config.paths?.instance ||
|
||||
!config.version ||
|
||||
!config.javaExecutable
|
||||
(!config.version && !config.modrinth)
|
||||
) {
|
||||
throw new ConfigError("Invalid config provided", config, logger);
|
||||
}
|
||||
|
||||
if (config.modrinth?.pack) {
|
||||
config.version = config.modrinth.version;
|
||||
config.modloader = config.modrinth.modloader;
|
||||
}
|
||||
|
||||
config.paths = {
|
||||
root: config.paths.root,
|
||||
instance: config.paths.instance,
|
||||
|
|
@ -60,26 +64,22 @@ export function defineConfig(logger: logger, ...layers: Partial<BaseConfig>[]) {
|
|||
|
||||
config.ram = { max: config.ram?.max ?? "2G", min: config.ram?.min ?? "2G" };
|
||||
|
||||
if (!config.files) {
|
||||
config.files = [];
|
||||
}
|
||||
|
||||
return config as Config;
|
||||
return config as FinalConfig;
|
||||
}
|
||||
|
||||
export class Instance extends EventEmitter<InstanceEvents> {
|
||||
ready: boolean;
|
||||
config: Config;
|
||||
config: FinalConfig;
|
||||
versionLocation: string;
|
||||
versionManifest: Version;
|
||||
logger: logger;
|
||||
|
||||
constructor(...layers: Partial<BaseConfig>[]) {
|
||||
constructor(config: Config) {
|
||||
super();
|
||||
this.logger = (step: string, message: unknown) => {
|
||||
this.emit("log", step, message);
|
||||
};
|
||||
this.config = defineConfig(this.logger, ...layers);
|
||||
this.config = defineConfig(this.logger, config);
|
||||
this.ready = false;
|
||||
this.versionManifest = {} as Version;
|
||||
this.versionLocation = "";
|
||||
|
|
@ -255,59 +255,39 @@ export class Instance extends EventEmitter<InstanceEvents> {
|
|||
this.emit("progress", "install-modloader", 1, 1, 1, 1);
|
||||
}
|
||||
|
||||
if (this.config.files.length > 0) {
|
||||
this.log("install-modpack-files", "Downloading modpack's files");
|
||||
if (this.config.modrinth?.pack) {
|
||||
try {
|
||||
const files = this.config.files.map<PoolFile>((f) => {
|
||||
return {
|
||||
url: f.url,
|
||||
path: path.join(this.config.paths.instance, f.path),
|
||||
size: f.size,
|
||||
};
|
||||
});
|
||||
const pool = new DownloadPool(files, {
|
||||
pQueueOptions: { concurrency: 5 },
|
||||
overwrite: false,
|
||||
});
|
||||
pool.on("completed", () => {
|
||||
this.emit(
|
||||
"progress",
|
||||
"install-modpack-files",
|
||||
pool.done,
|
||||
pool.total,
|
||||
pool.doneSize,
|
||||
pool.totalSize,
|
||||
);
|
||||
});
|
||||
await pool.run();
|
||||
} catch (error) {
|
||||
throw new InstallError(
|
||||
"An error occured while downloading modpack's files",
|
||||
"install-modpack-files",
|
||||
const { modrinthChanges, overridesChanges } = await generatePackChanges(
|
||||
this.config.paths.instance,
|
||||
this.config.modrinth.tempFolder,
|
||||
this.config,
|
||||
this.logger,
|
||||
{ cause: error },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.config.overridesPath) {
|
||||
this.log("install-modpack-overrides", "Copying modpack's overrides");
|
||||
this.emit("progress", "install-modpack-overrides", 0, 1, 0, 1);
|
||||
try {
|
||||
await fs.cp(this.config.overridesPath, this.config.paths.instance, {
|
||||
recursive: true,
|
||||
});
|
||||
console.log(modrinthChanges, overridesChanges);
|
||||
|
||||
// Delete before downloading
|
||||
|
||||
await ProjectsDeleter(modrinthChanges.removedProject, (...args) => this.emit(...args));
|
||||
|
||||
await ModrinthDownloader(modrinthChanges.addedProjects, (...args) => this.emit(...args));
|
||||
|
||||
await OverridesDeleter(overridesChanges, (...args) => this.emit(...args));
|
||||
|
||||
await OverridesCopier(
|
||||
overridesChanges.addedOverrides,
|
||||
path.join(this.config.modrinth.tempFolder, 'pack', 'overrides'),
|
||||
this.config.paths.instance,
|
||||
(...args) => this.emit(...args),
|
||||
);
|
||||
} catch (error) {
|
||||
throw new InstallError(
|
||||
"An error occured while copying modpack's overrides",
|
||||
"install-modpack-overrides",
|
||||
"An error occured while installing/updating the modpack",
|
||||
"install-modpack",
|
||||
this.config,
|
||||
this.logger,
|
||||
{ cause: error },
|
||||
);
|
||||
}
|
||||
this.emit("progress", "install-modpack-overrides", 1, 1, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,45 +3,73 @@ import { downloadFile } from "../utils/fetch";
|
|||
import { getTempFolder } from "../utils/temp";
|
||||
import { unzipAll } from "../utils/unzip";
|
||||
import { ensureDir, exists, readJson } from "../utils/fs";
|
||||
import { Modloader, ModrinthManifest, BaseConfig, PoolFile, ModrinthPack } from "../utils/types";
|
||||
import { Modloader, ModrinthManifest, ModrinthPack } from "../utils/types";
|
||||
import { ImportModpackError } from "../utils/errors";
|
||||
|
||||
function getModloader(manifest: ModrinthManifest): Modloader {
|
||||
if (manifest.dependencies["fabric-loader"]) {
|
||||
return { name: "fabric", version: manifest.dependencies["fabric-loader"] }
|
||||
return { name: "fabric", version: manifest.dependencies["fabric-loader"] };
|
||||
} else if (manifest.dependencies["forge"]) {
|
||||
return { name: "forge", version: manifest.dependencies["forge"] }
|
||||
return { name: "forge", version: manifest.dependencies["forge"] };
|
||||
} else if (manifest.dependencies["neoforge"]) {
|
||||
return { name: "neoforge", version: manifest.dependencies["neoforge"] }
|
||||
return { name: "neoforge", version: manifest.dependencies["neoforge"] };
|
||||
} else {
|
||||
throw new Error("Unknown modloader")
|
||||
throw new Error("Unknown modloader");
|
||||
}
|
||||
}
|
||||
|
||||
export async function importModrinthModpack(source: string, sourceType: "url" | "file"): Promise<ModrinthPack> {
|
||||
const tempFolder = await getTempFolder("modrinth")
|
||||
export async function importModrinthModpack(
|
||||
pack: string,
|
||||
updateFrom?: string,
|
||||
): Promise<ModrinthPack> {
|
||||
try {
|
||||
const tempFolder = await getTempFolder("modrinth");
|
||||
|
||||
if (sourceType === "url") {
|
||||
const outputFile = path.join(tempFolder, "pack.mrpack")
|
||||
await downloadFile({ path: outputFile, url: source })
|
||||
source = outputFile
|
||||
if (pack.startsWith("http")) {
|
||||
const outputFile = path.join(tempFolder, "pack.mrpack");
|
||||
await downloadFile({ path: outputFile, url: pack });
|
||||
pack = outputFile;
|
||||
}
|
||||
|
||||
if (!await exists(source)) {
|
||||
throw new Error("Couldn't find modpack file")
|
||||
if (updateFrom?.startsWith("http")) {
|
||||
const outputFile = path.join(tempFolder, "oldPack.mrpack");
|
||||
await downloadFile({ path: outputFile, url: updateFrom });
|
||||
updateFrom = outputFile;
|
||||
}
|
||||
|
||||
await ensureDir(path.join(tempFolder, "pack"))
|
||||
if (!(await exists(pack)) || (updateFrom && !(await exists(updateFrom)))) {
|
||||
throw new Error("Couldn't find modpack file");
|
||||
}
|
||||
|
||||
await unzipAll(source, path.join(tempFolder, "pack"), [], "overwrite")
|
||||
await ensureDir(path.join(tempFolder, "pack"), true);
|
||||
await unzipAll(pack, path.join(tempFolder, "pack"), [], "overwrite");
|
||||
const manifest = await readJson<ModrinthManifest>(
|
||||
path.join(tempFolder, "pack", "modrinth.index.json"),
|
||||
);
|
||||
|
||||
const manifest = await readJson<ModrinthManifest>(path.join(tempFolder, "pack", "modrinth.index.json"))
|
||||
if (updateFrom) {
|
||||
await ensureDir(path.join(tempFolder, "oldPack"));
|
||||
await unzipAll(
|
||||
updateFrom,
|
||||
path.join(tempFolder, "oldPack"),
|
||||
[],
|
||||
"overwrite",
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
pack,
|
||||
updateFrom,
|
||||
tempFolder,
|
||||
version: manifest.dependencies.minecraft,
|
||||
modloader: getModloader(manifest),
|
||||
files: manifest.files.map<PoolFile>(f => {
|
||||
return { url: f.downloads[0], path: f.path, size: f.fileSize }
|
||||
}),
|
||||
overridesPath: path.join(tempFolder, "pack", "overrides")
|
||||
};
|
||||
} catch (error) {
|
||||
throw new ImportModpackError(
|
||||
"An error occured while importing the modpack",
|
||||
"install-modloader",
|
||||
{ pack, updateFrom },
|
||||
{ cause: error },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +1,47 @@
|
|||
import { BaseConfig, Config } from "../launcher/instance"
|
||||
import { logger } from "./types"
|
||||
import { Config, FinalConfig } from "../utils/types";
|
||||
import { logger } from "./types";
|
||||
|
||||
export class ConfigError extends Error {
|
||||
constructor(message: string, config: Partial<BaseConfig>, logger: logger, options?: ErrorOptions) {
|
||||
super(message, options)
|
||||
logger("error", "Provided config was:")
|
||||
console.log(config)
|
||||
constructor(
|
||||
message: string,
|
||||
config: Config,
|
||||
logger: logger,
|
||||
options?: ErrorOptions,
|
||||
) {
|
||||
super(message, options);
|
||||
logger("error", "Provided config was:");
|
||||
console.log(config);
|
||||
}
|
||||
}
|
||||
|
||||
export class InstallError extends Error {
|
||||
constructor(message: string, step: string, config: Config, logger: logger, options?: ErrorOptions) {
|
||||
super(`[${step}] ${message}`, options)
|
||||
logger("error", "Provided config was:")
|
||||
console.log(config)
|
||||
constructor(
|
||||
message: string,
|
||||
step: string,
|
||||
config: FinalConfig,
|
||||
logger: logger,
|
||||
options?: ErrorOptions,
|
||||
) {
|
||||
super(`[${step}] ${message}`, options);
|
||||
logger("error", "Provided config was:");
|
||||
console.log(config);
|
||||
console.log('Original error is:')
|
||||
console.error(options?.cause)
|
||||
}
|
||||
}
|
||||
|
||||
export class LaunchError extends InstallError {}
|
||||
|
||||
export class ImportModpackError extends Error {
|
||||
constructor(
|
||||
message: string,
|
||||
step: string,
|
||||
modrinth: { pack: string; updateFrom?: string },
|
||||
options?: ErrorOptions,
|
||||
) {
|
||||
super(`[${step}] ${message}`, options);
|
||||
console.log("error", "Modpack to install was:");
|
||||
console.log(`Modpack: ${modrinth.pack}`);
|
||||
if (modrinth.updateFrom) console.log(`Update from: ${modrinth.updateFrom}`);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,9 +46,9 @@ export class DownloadPool extends PQueue {
|
|||
this.total = this.elements.length;
|
||||
this.cleanup = options.cleanup;
|
||||
if (options.overwrite) {
|
||||
this.overwrite = true
|
||||
this.overwrite = true;
|
||||
} else {
|
||||
this.overwrite = false
|
||||
this.overwrite = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -61,10 +61,11 @@ export class DownloadPool extends PQueue {
|
|||
// update status here to ensure that it is run before "completed" events listeners
|
||||
this.done++;
|
||||
this.doneSize += element.size!;
|
||||
});
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
await this.onIdle();
|
||||
await Promise.race([this.onError(), this.onIdle()]);
|
||||
|
||||
if (this.cleanup) {
|
||||
await this.cleanup();
|
||||
}
|
||||
|
|
|
|||
135
src/utils/fs.ts
135
src/utils/fs.ts
|
|
@ -1,4 +1,7 @@
|
|||
import fs from "fs/promises";
|
||||
import PQueue from "p-queue";
|
||||
import { type Options as PQueueOptions } from "p-queue";
|
||||
import path from "path";
|
||||
|
||||
export async function exists(path: string) {
|
||||
try {
|
||||
|
|
@ -19,3 +22,135 @@ export async function ensureDir(path: string, recursive = false) {
|
|||
export async function readJson<T>(destination: string): Promise<T> {
|
||||
return JSON.parse(await fs.readFile(destination, { encoding: "utf-8" }));
|
||||
}
|
||||
|
||||
export class DeleteQueue extends PQueue {
|
||||
done = 0;
|
||||
total = 0;
|
||||
doneSize = 0;
|
||||
totalSize = 0;
|
||||
elements: string[];
|
||||
cleanup?: () => Promise<void>;
|
||||
|
||||
constructor(
|
||||
elements: string[],
|
||||
options: {
|
||||
//@ts-expect-error can't figure out what to put as arguments of PQueueOptions
|
||||
pQueueOptions: PQueueOptions<null, null>;
|
||||
cleanup?: () => Promise<void>;
|
||||
} = {
|
||||
pQueueOptions: {},
|
||||
},
|
||||
) {
|
||||
//@ts-expect-error can't figure out what to put as arguments of PQueueOptions
|
||||
super(options.pQueueOptions);
|
||||
this.elements = elements;
|
||||
this.total = this.elements.length;
|
||||
this.cleanup = options.cleanup;
|
||||
}
|
||||
|
||||
async run() {
|
||||
for (const element of this.elements) {
|
||||
this.add(async () => {
|
||||
await fs.rm(element, { recursive: true, force: true });
|
||||
this.done++;
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
await Promise.race([this.onError(), this.onIdle()]);
|
||||
if (this.cleanup) {
|
||||
await this.cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class CopyQueue extends PQueue {
|
||||
done = 0;
|
||||
total = 0;
|
||||
doneSize = 0;
|
||||
totalSize = 0;
|
||||
files: string[];
|
||||
source: string;
|
||||
destination: string;
|
||||
cleanup?: () => Promise<void>;
|
||||
|
||||
constructor(
|
||||
files: string[],
|
||||
source: string,
|
||||
destination: string,
|
||||
options: {
|
||||
//@ts-expect-error can't figure out what to put as arguments of PQueueOptions
|
||||
pQueueOptions: PQueueOptions<null, null>;
|
||||
cleanup?: () => Promise<void>;
|
||||
} = {
|
||||
pQueueOptions: {},
|
||||
},
|
||||
) {
|
||||
//@ts-expect-error can't figure out what to put as arguments of PQueueOptions
|
||||
super(options.pQueueOptions);
|
||||
this.files = files;
|
||||
this.source = source;
|
||||
this.destination = destination;
|
||||
this.total = this.files.length;
|
||||
this.cleanup = options.cleanup;
|
||||
}
|
||||
|
||||
async run() {
|
||||
for (const file of this.files) {
|
||||
this.add(async () => {
|
||||
await fs.cp(
|
||||
path.join(this.source, file),
|
||||
path.join(this.destination, file),
|
||||
{
|
||||
force: true,
|
||||
},
|
||||
);
|
||||
this.done++;
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
await Promise.race([this.onError(), this.onIdle()]);
|
||||
if (this.cleanup) {
|
||||
await this.cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class TreeMakerQueue extends PQueue {
|
||||
done = 0;
|
||||
total = 0;
|
||||
doneSize = 0;
|
||||
totalSize = 0;
|
||||
addedDirs: string[];
|
||||
cleanup?: () => Promise<void>;
|
||||
|
||||
constructor(
|
||||
addedDirs: string[],
|
||||
options: {
|
||||
//@ts-expect-error can't figure out what to put as arguments of PQueueOptions
|
||||
pQueueOptions: PQueueOptions<null, null>;
|
||||
cleanup?: () => Promise<void>;
|
||||
} = {
|
||||
pQueueOptions: {},
|
||||
},
|
||||
) {
|
||||
//@ts-expect-error can't figure out what to put as arguments of PQueueOptions
|
||||
super(options.pQueueOptions);
|
||||
this.addedDirs = addedDirs;
|
||||
this.total = this.addedDirs.length;
|
||||
this.cleanup = options.cleanup;
|
||||
}
|
||||
|
||||
async run() {
|
||||
for (const dir of this.addedDirs) {
|
||||
this.add(async () => {
|
||||
await ensureDir(dir, true);
|
||||
this.done++;
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
await Promise.race([this.onError(), this.onIdle()]);
|
||||
if (this.cleanup) {
|
||||
await this.cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -196,6 +196,12 @@ export type Paths = {
|
|||
libraries?: string;
|
||||
};
|
||||
|
||||
export interface FilledPaths extends Paths {
|
||||
versions: string;
|
||||
assets: string;
|
||||
libraries: string;
|
||||
}
|
||||
|
||||
export type LaunchErrorConfig = {
|
||||
version: string;
|
||||
paths: Paths;
|
||||
|
|
@ -244,11 +250,21 @@ export type ProcessArgs = {
|
|||
java?: string;
|
||||
};
|
||||
|
||||
export interface FilledProcessArgs {
|
||||
game: string;
|
||||
java: string;
|
||||
}
|
||||
|
||||
export type ProcessRam = {
|
||||
max?: string;
|
||||
min?: string;
|
||||
};
|
||||
|
||||
export interface FilledProcessRam extends ProcessRam {
|
||||
max: string;
|
||||
min: string;
|
||||
}
|
||||
|
||||
export type logger = (step: string, message: unknown) => void;
|
||||
|
||||
export type FabricInstallerMeta = {
|
||||
|
|
@ -280,32 +296,32 @@ export type ModrinthManifest = {
|
|||
};
|
||||
};
|
||||
|
||||
export interface BaseConfig {
|
||||
export type ModrinthPack = {
|
||||
pack: string;
|
||||
updateFrom?: string;
|
||||
tempFolder: string;
|
||||
version: string;
|
||||
modloader: Modloader;
|
||||
};
|
||||
|
||||
export type Config = {
|
||||
version?: string;
|
||||
auth: Auth;
|
||||
paths: Paths;
|
||||
javaExecutable: string;
|
||||
modloader?: Modloader;
|
||||
args?: ProcessArgs;
|
||||
ram?: { max?: string; min?: string };
|
||||
files?: PoolFile[];
|
||||
overridesPath?: string;
|
||||
}
|
||||
ram?: ProcessRam;
|
||||
modrinth?: ModrinthPack;
|
||||
};
|
||||
|
||||
export interface Config extends BaseConfig {
|
||||
paths: Required<Paths>;
|
||||
args: Required<ProcessArgs>;
|
||||
ram: Required<ProcessRam>;
|
||||
files: PoolFile[];
|
||||
}
|
||||
|
||||
export interface ModloaderConfig extends Config {
|
||||
modloader: Modloader;
|
||||
}
|
||||
|
||||
export interface ModrinthPack {
|
||||
export interface FinalConfig extends Config {
|
||||
version: string;
|
||||
modloader: Modloader;
|
||||
files: PoolFile[];
|
||||
overridesPath: string;
|
||||
paths: FilledPaths;
|
||||
args: FilledProcessArgs;
|
||||
ram: FilledProcessRam;
|
||||
}
|
||||
|
||||
export interface ModloaderConfig extends FinalConfig {
|
||||
modloader: Modloader;
|
||||
}
|
||||
|
|
|
|||
123
tests/modrinth-update.test.ts
Normal file
123
tests/modrinth-update.test.ts
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
import { test } from "vitest";
|
||||
import {
|
||||
Instance,
|
||||
offlineAuth,
|
||||
RuntimeManager,
|
||||
getJavaComponent,
|
||||
importModrinthModpack,
|
||||
} from "../dist/index.js";
|
||||
import path from "path";
|
||||
import fs from "fs/promises";
|
||||
|
||||
const gameRoot = path.join(import.meta.dirname, "temp");
|
||||
await fs.rm(path.join(gameRoot, "instances", "modrinth_update"), {
|
||||
recursive: true,
|
||||
force: true,
|
||||
}); // remove instance dir each start to ensure that first launch works (else files from update will be used to start original)
|
||||
|
||||
test(
|
||||
"update modrinth modpack",
|
||||
{ timeout: 0, tags: ["modrinth"] },
|
||||
async () => {
|
||||
{
|
||||
const modpack = await importModrinthModpack(
|
||||
"https://cdn.modrinth.com/data/1KVo5zza/versions/JnvfUoIW/Fabulously.Optimized-v13.2.1.mrpack",
|
||||
);
|
||||
|
||||
const javaManager = new RuntimeManager(path.join(gameRoot, "java"));
|
||||
javaManager.on("progress", console.log);
|
||||
const java = await javaManager.use(
|
||||
await getJavaComponent(modpack.version),
|
||||
);
|
||||
|
||||
const instance = new Instance({
|
||||
auth: offlineAuth("player"),
|
||||
paths: {
|
||||
root: gameRoot,
|
||||
instance: path.join(gameRoot, "instances", "modrinth_update"),
|
||||
},
|
||||
javaExecutable: java,
|
||||
ram: { max: "4G", min: "4G" },
|
||||
modrinth: modpack,
|
||||
});
|
||||
|
||||
instance.on("progress", console.log);
|
||||
instance.on("log", (step, msg) => {
|
||||
console.log(`[${step}] ${msg}`);
|
||||
});
|
||||
|
||||
await instance.install();
|
||||
const p = await instance.launch();
|
||||
|
||||
p.stdout.on("data", (d: Buffer) => {
|
||||
console.log(d.toString());
|
||||
});
|
||||
|
||||
p.stderr.on("data", (d: Buffer) => {
|
||||
console.log(d.toString());
|
||||
});
|
||||
|
||||
await new Promise<void>((res) => {
|
||||
p.on("error", (d: Buffer) => {
|
||||
console.log(d.toString());
|
||||
res();
|
||||
});
|
||||
p.on("close", () => {
|
||||
console.log("closed");
|
||||
res();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
to test that everything works i try to fully replace fabulously optimized by a completly different modpack
|
||||
but it is intended to be used only to update from one modpack to its update
|
||||
*/
|
||||
const modpack = await importModrinthModpack(
|
||||
"https://cdn.modrinth.com/data/l9m9tuPN/versions/M8j2mfGj/Zombie%20Invade%20100%20Days%202.3.mrpack",
|
||||
"https://cdn.modrinth.com/data/1KVo5zza/versions/JnvfUoIW/Fabulously.Optimized-v13.2.1.mrpack",
|
||||
);
|
||||
const javaManager = new RuntimeManager(path.join(gameRoot, "java"));
|
||||
javaManager.on("progress", console.log);
|
||||
const java = await javaManager.use(await getJavaComponent(modpack.version));
|
||||
|
||||
const instance = new Instance({
|
||||
auth: offlineAuth("player"),
|
||||
paths: {
|
||||
root: gameRoot,
|
||||
instance: path.join(gameRoot, "instances", "modrinth_update"),
|
||||
},
|
||||
javaExecutable: java,
|
||||
ram: { max: "4G", min: "4G" },
|
||||
modrinth: modpack,
|
||||
});
|
||||
|
||||
instance.on("progress", console.log);
|
||||
instance.on("log", (step, msg) => {
|
||||
console.log(`[${step}] ${msg}`);
|
||||
});
|
||||
|
||||
await instance.install();
|
||||
|
||||
const p = await instance.launch();
|
||||
|
||||
p.stdout.on("data", (d: Buffer) => {
|
||||
console.log(d.toString());
|
||||
});
|
||||
|
||||
p.stderr.on("data", (d: Buffer) => {
|
||||
console.log(d.toString());
|
||||
});
|
||||
|
||||
await new Promise<void>((res) => {
|
||||
p.on("error", (d: Buffer) => {
|
||||
console.log(d.toString());
|
||||
res();
|
||||
});
|
||||
p.on("close", () => {
|
||||
console.log("closed");
|
||||
res();
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
Loading…
Add table
Add a link
Reference in a new issue