Skip to content

Support downloading and extracting mods larger than 2GB - #2306

Open
Aaronlonin wants to merge 1 commit into
ebkr:developfrom
Aaronlonin:fix/support-mods-larger-than-2gb
Open

Aaronlonin wants to merge 1 commit into
ebkr:developfrom
Aaronlonin:fix/support-mods-larger-than-2gb

Conversation

@Aaronlonin

Copy link
Copy Markdown

Description

Resolves an issue where mod files larger than 2 GiB fail to download or import into r2modman.

Root Causes

  1. Extraction failure: adm-zip uses synchronous fs.readFileSync under the hood to read entire zip files into memory buffers. When reading files larger than 2 GiB, Node.js throws RangeError [ERR_FS_FILE_TOO_LARGE]: File size (...) is greater than 2 GiB.
  2. Download failure: In BetterThunderstoreDownloader, mod archives were downloaded in the Chromium renderer process using axios with responseType: 'arraybuffer'. Chromium's V8 engine caps ArrayBuffer allocations at 2 GB, causing large downloads to abort with an allocation or network error.

Changes

  1. Streaming extraction with unzipper:
    • Replaced adm-zip usage in src-electron/ipc/zip-hook.ts for extraction and entry enumeration with streaming unzipper (unzipper.Open.file / unzipper.Open.buffer).
    • Retained adm-zip exclusively for creating new zip archives (e.g. profile exports).
    • Added path normalization and containment checks to guard against directory traversal (zip-slip).
  2. Main-process streaming download:
    • Added downloadFile to main IPC (src-electron/ipc/node-fs-impl.ts), streaming HTTP response streams directly to the target destination on disk using stream/promises.pipeline.
    • Exposed downloadFile through the preload bridge (node-fs.ts) and FsProvider (NodeFsImplementation, NodeFs, and test stubs).
    • Updated BetterThunderstoreDownloader to stream downloads directly to disk in the cache folder rather than buffering multi-gigabyte files in renderer memory.
    • Maintained real-time download progress tracking via IPC event messages.

Testing

  • Passed npm run typecheck (vue-tsc --noEmit).
  • Passed all 203 Vitest unit tests (npm test).
  • Built and ran unpacked Electron application on Linux.
  • Successfully verified manual import of Magic_Wesley-Wesleys_Moons-7.0.17.zip (~2.58 GB).
  • Successfully verified in-app downloading and extraction of large mods.

Closes #617
Closes #1957

- Replace adm-zip with unzipper in zip-hook.ts for archive extraction and entry inspection, eliminating the Node.js 2 GiB fs.readFileSync buffer limit (ERR_FS_FILE_TOO_LARGE)
- Stream online mod downloads directly to disk in the main process via Node streams instead of buffering into memory with responseType: 'arraybuffer' in Chromium
- Expose downloadFile through FsProvider and node-fs IPC with real-time download progress tracking
@CLAassistant

CLAassistant commented Oct 8, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants