Description
Since v4.10.0, box folders:download <id> --zip writes a 0-byte .zip and puts the downloaded files loose next to it (or hangs), instead of producing an archive. v4.8.2 produces a valid archive for the same folder.
Root cause
#686 moved folders:download to archiver 8, which is ESM-only, so _setupZip() became async and now awaits a dynamic import('archiver') before assigning this.zip:
// src/commands/folders/download.js (v4.10.0)
outputFinalized = this._setupZip(path.join(destinationPath, fileName)); // not awaited
...
for await (let item of this._getItems(id, '')) {
if (item.type === 'folder' && !this.zip) { ... mkdirp ... }
else if (item.type === 'file') {
if (this.zip) { this.zip.append(stream, { name: item.path }); }
else { await saveFileToDisk(destinationPath, item, stream); }
}
}
if (this.zip) { this.zip.finalize(); }
await outputFinalized;
run() starts traversing the folder without waiting for the import, so whenever the first folder listing comes back before the module has loaded, this.zip is still undefined: the items take the non-zip path (folders are created on disk, files are saved to disk), finalize() is skipped because this.zip is checked before the import resolves, and the write stream for the archive is never finalized. Depending on timing the process either exits with an empty .zip or waits forever on outputFinalized.
Simply awaiting _setupZip() is not a fix: it returns the promise that resolves when the output stream closes, so awaiting it before traversal deadlocks.
box files:zip is not affected (it uses the server-side zip download API).
Steps to reproduce
- Point the CLI at a local mock of the API (
apiRootURL in ~/.box/settings.json) that serves one folder containing one file, or use a real small folder.
box folders:download <folder-id> --zip --destination out -t <token>
- Inspect
out/.
Observed with v4.10.0 on Node 20.20.1 (5/5 runs): folders-download-<id>-....zip is 0 bytes, and out/<folder>/<file> exists on disk. Same steps with v4.8.2: valid archive containing <folder>/<file>, no loose files. On Node 24 the import happens to win the race, so the bug can look intermittent across environments.
Versions
@box/cli 4.10.0 (archiver 8.0.0, box-node-sdk 4.14.0)
- Node 20.20.1, macOS arm64 (on Node 24 the import happens to win the race and the command succeeds)
Fix
Load the archiver module before starting traversal, and keep _setupZip() synchronous so this.zip is assigned before the first item is processed. I have a PR with this change plus a regression test that asserts this.zip is set before _getItems() runs and that the archive contains the expected entries.
Description
Since v4.10.0,
box folders:download <id> --zipwrites a 0-byte.zipand puts the downloaded files loose next to it (or hangs), instead of producing an archive. v4.8.2 produces a valid archive for the same folder.Root cause
#686 moved
folders:downloadtoarchiver8, which is ESM-only, so_setupZip()becameasyncand now awaits a dynamicimport('archiver')before assigningthis.zip:run()starts traversing the folder without waiting for the import, so whenever the first folder listing comes back before the module has loaded,this.zipis stillundefined: the items take the non-zip path (folders are created on disk, files are saved to disk),finalize()is skipped becausethis.zipis checked before the import resolves, and the write stream for the archive is never finalized. Depending on timing the process either exits with an empty.zipor waits forever onoutputFinalized.Simply awaiting
_setupZip()is not a fix: it returns the promise that resolves when the output stream closes, so awaiting it before traversal deadlocks.box files:zipis not affected (it uses the server-side zip download API).Steps to reproduce
apiRootURLin~/.box/settings.json) that serves one folder containing one file, or use a real small folder.box folders:download <folder-id> --zip --destination out -t <token>out/.Observed with v4.10.0 on Node 20.20.1 (5/5 runs):
folders-download-<id>-....zipis 0 bytes, andout/<folder>/<file>exists on disk. Same steps with v4.8.2: valid archive containing<folder>/<file>, no loose files. On Node 24 the import happens to win the race, so the bug can look intermittent across environments.Versions
@box/cli4.10.0 (archiver8.0.0,box-node-sdk4.14.0)Fix
Load the archiver module before starting traversal, and keep
_setupZip()synchronous sothis.zipis assigned before the first item is processed. I have a PR with this change plus a regression test that assertsthis.zipis set before_getItems()runs and that the archive contains the expected entries.