{"id":19826279,"url":"https://github.com/aternosorg/armarius","last_synced_at":"2026-05-18T17:00:56.745Z","repository":{"id":39574787,"uuid":"472863466","full_name":"aternosorg/armarius","owner":"aternosorg","description":"A JavaScript library to read, write, and merge ZIP archives in web browsers.","archived":false,"fork":false,"pushed_at":"2026-04-28T07:48:59.000Z","size":505,"stargazers_count":7,"open_issues_count":0,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-04-28T09:16:07.037Z","etag":null,"topics":["browser","javascript","unzip","zip"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/armarius","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aternosorg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-03-22T17:16:41.000Z","updated_at":"2026-04-28T07:47:02.000Z","dependencies_parsed_at":"2024-05-02T10:53:30.526Z","dependency_job_id":"410f0563-8382-4699-935c-981468f54cd8","html_url":"https://github.com/aternosorg/armarius","commit_stats":{"total_commits":94,"total_committers":2,"mean_commits":47.0,"dds":"0.021276595744680882","last_synced_commit":"c7c3ddd255a42a1e85b97a59d0948acd2d46abbb"},"previous_names":[],"tags_count":39,"template":false,"template_full_name":null,"purl":"pkg:github/aternosorg/armarius","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aternosorg%2Farmarius","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aternosorg%2Farmarius/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aternosorg%2Farmarius/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aternosorg%2Farmarius/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aternosorg","download_url":"https://codeload.github.com/aternosorg/armarius/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aternosorg%2Farmarius/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33184769,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-18T09:27:30.708Z","status":"ssl_error","status_checked_at":"2026-05-18T09:27:28.300Z","response_time":71,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["browser","javascript","unzip","zip"],"created_at":"2024-11-12T11:09:57.224Z","updated_at":"2026-05-18T17:00:56.737Z","avatar_url":"https://github.com/aternosorg.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Armarius\n\n## About\n\nArmarius is a JavaScript library to read, write, and merge ZIP archives in web browsers and Node.js.\n\nThis library mainly focuses on a low memory footprint, especially when reading archives with tens of thousands of\nentries, and the ability to merge archives without decompressing and recompressing all entries.\n\nFor deflate/inflate support, this library uses the \n[Compression Streams API](https://developer.mozilla.org/en-US/docs/Web/API/Compression_Streams_API) (if available) or \n[fflate](https://github.com/101arrowz/fflate). In Node.js environments, the built-in `zlib` module is used.\n\n## Installation\n\nArmarius can be installed using npm:\n\n```shell\nnpm install armarius\n```\n\nIt can then be loaded as an ES Module:\n\n```javascript\nimport * as armarius from 'armarius';\n```\n\nIO operations and compression are not part of the library itself, and are packaged separately as `armarius-io`:\n\n```javascript\nimport * as io from 'armarius-io';\n```\n\nFor use in web browsers, this library can be bundled using [esbuild](https://github.com/evanw/esbuild). \nOther bundlers like [webpack](https://webpack.js.org/) should work as well, \nbut are not officially supported.\n\n## Usage\n\n### Extracting, packing, and verifying ZIP archives\n\n#### Simple usage (Node.js only)\n\nSince browsers do not have access to a normal file system, these functions are only available in Node.js environments. \nIn web browsers, the advanced usage below can be used to achieve the same functionality with a custom file system implementation.\n\n```javascript\nimport {extract, pack, verify} from 'armarius';\n\nawait extract(\"./path/to/archive.zip\", \"./path/to/target/dir\");\n\nawait pack(\"./path/to/source/dir\", \"./path/to/target.zip\");\n\n// Will throw an error if the archive is invalid\nawait verify(\"./path/to/archive.zip\");\n```\n\nEach function accepts an additional options object with more fine-grained control over the operation.\nSee [node-utils.js](src/Util/node-utils.js) for more details.\n\n#### Advanced usage (Node.js and web browsers)\n\nThe above operations can also be performed using the Extractor, Packer, and Verifier classes, which give finer control\nover the operation and allow using custom IO and file system implementations.\n\nThe above helper functions can be used as a reference for how to use these classes to achieve the same functionality.\nSee [node-utils.js](src/Util/node-utils.js) for more details.\n\n### Reading a ZIP archive\n\nTo read an archive, an [IO context](https://github.com/aternosorg/armarius-io/blob/master/src/IO/IO.js) is required. \nThe `armarius-io` library provides IO implementations for `Blob`, `ArrayBuffer`, and Node.js `FileHandle`\nobjects. Other IO contexts can be implemented by extending the [IO](https://github.com/aternosorg/armarius-io/blob/master/src/IO/IO.js) class.\n\nWhile not all IO contexts need manual resource management, it is recommended to always close them at the end of their usage, \neither by using `await using`, or by calling `io[Symbol.asyncDispose]()`.\n\n```javascript\nlet fileInput = document.getElementById('file-input');\nawait using reader = new io.BlobIO(fileInput.files[0]);\n```\n\nA [ReadArchive](src/Archive/ReadArchive.js) can then be created from an IO context.\n\n```javascript\nlet archive = new armarius.ReadArchive(reader, options);\nawait archive.init();\n```\n\nThe ReadArchive constructor optionally accepts an [ReadArchiveOptions](src/Options/ReadArchiveOptions.js) object with\nthe following properties:\n\n| Name                                     | Type                                        | Description                                                                                                                                                                  |\n|------------------------------------------|---------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `centralDirectoryBufferSize`             | number                                      | Buffer size used when reading central directory contents.\u003cbr/\u003eLarger buffer sizes may improve performance, but also increase RAM usage.                                      |\n| `createEntryIndex`                       | boolean                                     | Whether an index of all central directory entries should be created the first time they are read.\u003cbr/\u003eMassively increases performance when using `findEntry` multiple times. |\n| `entryOptions`                           | [EntryOptions](src/Options/EntryOptions.js) | Options passed to each created Entry object.                                                                                                                                 |\n| `ignoreMultiDiskErrors`                  | boolean                                     | Simply ignore information about multiple disks instead of throwing an error when encountering a multi disk archive                                                           |\n| `allowTruncatedCentralDirectory`         | boolean                                     | Do not throw an error if the central directory does not contain the expected number of entries                                                                               |\n| `allowAdditionalCentralDirectoryEntries` | boolean                                     | Continue reading central directory entries even after the expected number of entries was reached                                                                             |\n\n[EntryOptions](src/Options/EntryOptions.js) can have the following properties:\n\n| Name                           | Type                              | Description                                                                                       |\n|--------------------------------|-----------------------------------|---------------------------------------------------------------------------------------------------|\n| `dataProcessors`               | Map\u003cnumber, typeof DataProcessor\u003e | Map of compressionMethod =\u003e DataProcessor\u003cbr/\u003eCan be used to implement custom compression methods |\n| `allowTrailingSlashInFileName` | boolean                           | Interpret entries with non-empty data as files, even if the file name ends on `/`.                |\n\n#### Reading all archive entries\n\n```javascript\nlet entries = await archive.getAllEntries();\n```\n\nSince this method will load all entries (not including their compressed data)\ninto memory, it is not recommended when working with large archives.\n\n#### Iterating over archive entries\n\n```javascript\nlet iterator = await archive.getEntryIterator();\n\nlet entry;\nwhile (entry = await iterator.next()) {\n    console.log(await entry.getFileNameString());\n}\n```\n\n#### Finding specific entries\n\n```javascript\nlet entry = await archive.findEntry('some/file.txt');\nconsole.log(await entry.getFileNameString());\n```\n\nIn most cases, this method is faster than iterating through all archive entries multiple times, since an internal index is used to find\nfiles quickly.\n\n### Reading entry data\n\n#### Reading a full entry\n\n```javascript\nlet entry = await archive.findEntry('example.txt');\nlet data = await entry.getData();\n\n// Decode UTF-8\nlet decoder = new TextDecoder();\nlet text = decoder.decode(data);\n\nconsole.log(text);\n```\n\n#### Reading entry data in chunks\n\n```javascript\nlet entry = await archive.findEntry('example.txt');\nlet entryReader = await entry.getDataReader();\n\nlet chunk;\nwhile (chunk = await reader.read(1024 * 64)) {\n    console.log(chunk);\n}\n```\n\nNote that the `length` parameter passed to `EntryDataReader.read` is the length of the compressed data read from the\nfile. Since this data is decompressed, the size of the returned chunk might differ.\n\nAlso note that an empty chunk returned from `EntryDataReader.read` does not necessarily indicate that all data has been read.\nAfter all data was read, `null` will be returned instead.\n\nBoth `getDataReader` and `getData` optionally accept an [EntryDataReaderOptions](src/Options/EntryDataReaderOptions.js) object with\nthe following properties:\n\n| Name                            | Type    | Description                                                                     |\n|---------------------------------|---------|---------------------------------------------------------------------------------|\n| `ignoreInvalidChecksums`        | boolean | Do not throw an error if the uncompressed data does not match the checksum      |\n| `ignoreInvalidUncompressedSize` | boolean | Do not throw an error if the uncompressed data does not match the expected size |\n\n### Writing archives\n\nNew archives can be created using a [WriteArchive](src/Archive/WriteArchive.js) object.\nThe [WriteArchive](src/Archive/WriteArchive.js) constructor needs to be passed a function, `Iterator`, or `AsyncIterator` that generates\nnew [EntrySource](src/Archive/EntrySource/EntrySource.js) objects when needed.\n\nAdditionally, a [WriteArchiveOptions](src/Options/WriteArchiveOptions.js) object can be passed:\n\n| Name           | Type    | Description                                                                                     |\n|----------------|---------|-------------------------------------------------------------------------------------------------|\n| `forceZIP64`   | boolean | Whether ZIP64 structures should always be created, even if not required by the archive content. |\n\n```javascript\nasync function *generateNextEntrySource() {\n    for (let i = 0; i \u003c 10; i++) {\n        await using entrySource = new armarius.DataStreamEntrySource(new io.ArrayBufferIO(new ArrayBuffer(0)), {fileName: `file-${i}.txt`});\n        yield entrySource;\n    }\n}\n\nlet writeArchive = new armarius.WriteArchive(generateNextEntrySource(), options);\n```\n\nThe entry source generator is also responsible for disposing of used entry sources if necessary.\nThe above example uses `await using` to automatically dispose of each generated entry source after it was used.\n\n#### Generating entries\n\nIf `nextEntryFunction` is an `Iterator` or `AsyncIterator`, the `WriteArchive` will iterate over it to generate new entries.\n\nIf it is a function, it will be called whenever a new entry needs to be written to the archive and should return a new\nInstance of [EntrySource](src/Archive/EntrySource/EntrySource.js), or `null` if no more entries should be added to the archive.\n\nThis simple example will generate an archive that contains 10 text files:\n\n```javascript\nlet encoder = new TextEncoder();\n\nasync function *generateEntrySources() {\n    for (let i = 0; i \u003c 10; i++) {\n        let fileName = `file-${i}`;\n        let fileContent = encoder.encode(`Content of file ${i}`);\n\n        await using reader = new io.ArrayBufferIO(fileContent.buffer, fileContent.byteOffset, fileContent.byteLength);\n        await using entry = new armarius.DataStreamEntrySource(reader, {fileName: fileName});\n        yield entry;\n    }\n}\n\nlet writeArchive = new armarius.WriteArchive(generateEntrySources());\n```\n\nAny [EntrySource](src/Archive/EntrySource/EntrySource.js) accepts an EntrySourceOptions object with the following\nproperties:\n\n| Name                     | Type                              | Description                                                                                                                                                                                                                                                                                                                                                                                       |\n|--------------------------|-----------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `fileComment`            | string                            | Entry file comment                                                                                                                                                                                                                                                                                                                                                                                |\n| `fileName`               | string                            | Entry file name                                                                                                                                                                                                                                                                                                                                                                                   |\n| `forceUTF8FileName`      | boolean                           | Always encode the filename and file comment in UTF-8, even if it could be encoded in CP437                                                                                                                                                                                                                                                                                                        |\n| `compressionMethod`      | number                            | Compression method that should be used for this entry. By default, this library only supports `0` (Store) and `8` (Deflate). More compression methods can be added using the `dataProcessors` option.\u003cbr/\u003e\u003cbr/\u003eWhen using an [ArchiveEntryEntrySource](src/Archive/EntrySource/ArchiveEntryEntrySource.js), this option will be ignored and the compression method of the original entry is used. |\n| `forceZIP64`             | boolean                           | Whether ZIP64 structures should always be created, even if not required by the content.                                                                                                                                                                                                                                                                                                           |\n| `minMadeByVersion`       | number                            | The minimum `madeByVersion` value to be used for this entry. If a higher version is required (e.g. because of ZIP64) is used, it will be set automatically and this option will be ignored.                                                                                                                                                                                                       |\n| `minExtractionVersion`   | number                            | The minimum `extractionVersion` value to be used for this entry. If a higher version is required (e.g. because of ZIP64) is used, it will be set automatically and this option will be ignored.                                                                                                                                                                                                   |\n| `modTime`                | Date                              | Last modified time of the entry                                                                                                                                                                                                                                                                                                                                                                   |\n| `acTime`                 | Date                              | Last access time of the entry. This option is ignored if `extendedTimeStampField` is `false`.                                                                                                                                                                                                                                                                                                     |\n| `crTime`                 | Date                              | File creation time of the entry. This option is ignored if `extendedTimeStampField` is `false`.                                                                                                                                                                                                                                                                                                   |\n| `unicodeFileNameField`   | boolean                           | Whether a Unicode Path Extra Field should be added                                                                                                                                                                                                                                                                                                                                                |\n| `unicodeCommentField`    | boolean                           | Whether a Unicode Comment Extra Field should be added                                                                                                                                                                                                                                                                                                                                             |\n| `extendedTimeStampField` | boolean                           | Whether an Extended Timestamp Extra Field should be added                                                                                                                                                                                                                                                                                                                                         |\n| `internalFileAttributes` | number                            | See https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT                                                                                                                                                                                                                                                                                                                                   |\n| `externalFileAttributes` | number                            | See https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT                                                                                                                                                                                                                                                                                                                                   |\n| `dataProcessors`         | Map\u003cnumber, typeof DataProcessor\u003e | Map of compressionMethod =\u003e DataProcessor\u003cbr/\u003eCan be used to implement custom compression methods                                                                                                                                                                                                                                                                                                 |\n\n#### Reading output chunks\n\nThe generated archive can be read using the `getNextChunk` function.\n\n```javascript\nlet chunk;\nwhile (chunk = await writeArchive.getNextChunk()) {\n    console.log('New archive chunk:', chunk);\n}\n```\n\nIt can also be written directly to an IO object.\n\n```javascript\nimport {NodeFileIO} from 'armarius-io';\n\nawait using io = NodeFileIO.open('path/to/archive.zip', 'w');\nawait writeArchive.writeTo(io);\n```\n\n### Merging ZIP archives\n\nArmarius supports merging ZIP archives without decompressing and recompressing individual entries.\n\n```javascript\nlet archies = [myReadArchive1, myReadArchive2];\n\nlet merger = new armarius.ArchiveMerger(archives, options);\nlet outputWriteArchive = merger.getOutputArchive();\n\nlet chunk;\nwhile (chunk = await outputWriteArchive.getNextChunk()) {\n    console.log('New archive chunk:', chunk);\n}\n```\n\nThe [ArchiveMerger](src/Archive/Merge/ArchiveMerger.js) constructor accepts a list\nof [ReadArchive](src/Archive/ReadArchive.js) or [MergeSource](src/Archive/Merge/MergeSource.js) objects and\na [MergeOptions](src/Archive/Merge/MergeSource.js) object with the following properties:\n\n| Name                          | Type                                                      | Description                                                                                                                                                      |\n|-------------------------------|-----------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `entrySourceOptions`          | [EntrySourceOptions](src/Options/EntrySourceOptions.js)   | Options passed to each created [EntrySource](src/Archive/EntrySource/EntrySource.js) object                                                                      |\n| `writeArchiveOptions`         | [WriteArchiveOptions](src/Options/WriteArchiveOptions.js) | Options passed to the output WriteArchive                                                                                                                        |\n| `nextPrependingEntryFunction` | Function                                                  | Function generating [EntrySource](src/Archive/EntrySource/EntrySource.js) objects that are added to the output archive before the contents of the input archives |\n\n#### MergeSource objects\n\nA [MergeSource](src/Archive/Merge/MergeSource.js) object allows greater control over how a source archive is merged into the\ndestination archive.\n\n```javascript\nlet mergeSource = new armarius.MergeSource(readArchive);\nmergeSource\n    .setBasePath('base/path/within/the/source/archive')\n    .setDestinationPath('path/within/the/destination/archive')\n    .setFilter((entry) =\u003e {\n        if (entry.getFileNameString().endsWith('.rar')) {\n            return false; //Filter entry\n        } else {\n            return true; //Allow entry\n        }\n    });\n```\n\n### Node.js\n\nWhile mainly intended for use in web browsers, this library can also be used in Node.js.\n\nTo read data from files, a [NodeFileIO](https://github.com/aternosorg/armarius-io/blob/master/src/IO/NodeFileIO.js) object can be used:\n\n```javascript\nimport {NodeFileIO} from 'armarius-io';\n\nawait using io = await NodeFileIO.open('path/to/file.zip', 'r');\n```\n\nArmarius will automatically recognize that it is running in a Node.js environment and use the appropriate \ncompression implementation based on the Node.js built-in `zlib` module.\n\n## License\n\nArmarius is open source software released under the MIT license, see [license](LICENSE).\n\n### Contributing\n\nYou can contribute to this project by [forking](https://docs.github.com/en/github/getting-started-with-github/fork-a-repo)\nthe repository, adding your changes to your fork, and creating\na [pull request](https://github.com/aternosorg/armarius/compare).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faternosorg%2Farmarius","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faternosorg%2Farmarius","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faternosorg%2Farmarius/lists"}