{"_id":"@cjser/modern-tar__v0_7_7","name":"@cjser/modern-tar__v0_7_7","dist-tags":{"latest":"0.7.7-cjser.2"},"versions":{"0.7.7-cjser.2":{"name":"@cjser/modern-tar__v0_7_7","version":"0.7.7-cjser.2","description":"Zero dependency streaming tar parser and writer for JavaScript.","author":{"name":"Ayuhito","email":"hello@ayuhito.com"},"license":"MIT","type":"module","sideEffects":false,"main":"./dist-cjser/index.cjs","module":"./dist/web/index.js","types":"./dist/web/index.d.ts","exports":{"./package.json":"./package.json",".":{"require":"./dist-cjser/index.cjs","default":"./dist/web/index.js"},"./fs":{"require":"./dist-cjser/fs.cjs","default":"./dist/fs/index.js"}},"typesVersions":{"*":{"fs":["dist/fs/index.d.ts"],"*":["dist/web/index.d.ts"]}},"devDependencies":{"@biomejs/biome":"2.5.4","@types/node":"^26.1.1","@vitest/browser-playwright":"4.1.10","@vitest/coverage-v8":"4.1.10","miniflare":"^4.20260714.0","playwright":"^1.61.1","tsdown":"^0.22.11","unrun":"0.2.39","typescript":"^6.0.3","vite":"^8.1.5","vitest":"4.1.10"},"scripts":{"build":"tsdown","dev":"tsdown --watch","test":"vitest","test:workers":"tsdown && vitest --config vitest.workers.config.ts --run","coverage":"vitest run --coverage","check":"biome check --write","typecheck":"tsc --noEmit","test:browser":"vitest --config=vitest.browser.config.ts --browser"},"homepage":"https://github.com/ayuhito/modern-tar","bugs":{"url":"https://github.com/ayuhito/modern-tar/issues"},"repository":{"type":"git","url":"https://code.moenext.com/3rdeye/cjser.git"},"publishConfig":{"access":"public"},"engines":{"node":">=18.0.0"},"cjser":{"sourceVersion":"0.7.7","cjserVersion":2,"original":{"name":"modern-tar","version":"0.7.7","main":"./dist/web/index.js","exports":{"./package.json":"./package.json",".":"./dist/web/index.js","./fs":"./dist/fs/index.js"},"repository":{"type":"git","url":"git+https://github.com/ayuhito/modern-tar.git"},"files":["dist","README.md"],"scripts":{"build":"tsdown","dev":"tsdown --watch","test":"vitest","test:workers":"tsdown && vitest --config vitest.workers.config.ts --run","coverage":"vitest run --coverage","check":"biome check --write","typecheck":"tsc --noEmit","test:browser":"vitest --config=vitest.browser.config.ts --browser"}}},"_id":"@cjser/modern-tar__v0_7_7@0.7.7-cjser.2","gitHead":"a4bef54d7d22d3d9a6b84528457938d84cd65fe7","_nodeVersion":"20.14.0","_npmVersion":"10.7.0","dist":{"integrity":"sha512-iQ+imaUnvpUwXP+bOysEXUuA2bqHPensdY3mAaGCZOtU3+T7I6EJcOsgXqrkRY3ABCRC6d6GWmccXh9x1k4snA==","shasum":"20cb18ee452d2a8fc25fae3a45404ee175835bf7","tarball":"https://registry.npmjs.org/@cjser/modern-tar__v0_7_7/-/modern-tar__v0_7_7-0.7.7-cjser.2.tgz","fileCount":11,"unpackedSize":184887,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQD3PkvGVyev6h71IcDgRIfBNNeYi0WnkFGeeols6EJAeQIgQDTyOZPh4Ac2BPr085RBvs/wcVXeWfmkFy9P0iGZO5o="}]},"_npmUser":{"name":"nanahira","email":"nanahira@momobako.com"},"directories":{},"maintainers":[{"name":"nanahira","email":"nanahira@momobako.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/modern-tar__v0_7_7_0.7.7-cjser.2_1785085425676_0.1283602973491944"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-26T17:03:45.506Z","0.7.7-cjser.2":"2026-07-26T17:03:45.837Z","modified":"2026-07-26T17:03:46.082Z"},"maintainers":[{"name":"nanahira","email":"nanahira@momobako.com"}],"description":"Zero dependency streaming tar parser and writer for JavaScript.","homepage":"https://github.com/ayuhito/modern-tar","repository":{"type":"git","url":"https://code.moenext.com/3rdeye/cjser.git"},"author":{"name":"Ayuhito","email":"hello@ayuhito.com"},"bugs":{"url":"https://github.com/ayuhito/modern-tar/issues"},"license":"MIT","readme":"# 🗄️ modern-tar\n\nZero-dependency, cross-platform, streaming tar archive library for every JavaScript runtime. Built with the browser-native Web Streams API for performance and memory efficiency.\n\n## Features\n\n- 🚀 **Streaming Architecture** - Supports large archives without loading everything into memory.\n- 📋 **Standards Compliant** - Full USTAR format support with PAX extensions. Compatible with GNU tar, BSD tar, and other standard implementations.\n- 🗜️ **Compression** - Includes helpers for gzip compression/decompression.\n- 📝 **TypeScript First** - Full type safety with detailed TypeDoc documentation.\n- ⚡ **Zero Dependencies** - No external dependencies, minimal bundle size.\n- 🌐 **Cross-Platform** - Works in browsers, Node.js, Cloudflare Workers, and other JavaScript runtimes.\n- 📁 **Node.js Integration** - Additional high-level APIs for directory packing and extraction.\n\n## Installation\n\n```sh\nnpm install modern-tar\n```\n\n## Usage\n\nThis package provides two entry points:\n\n- `modern-tar`: The core, cross-platform streaming API (works everywhere).\n- `modern-tar/fs`: High-level filesystem utilities for Node.js.\n\n### Core Usage\n\nThese APIs use the Web Streams API and can be used in any modern JavaScript environment.\n\n#### Simple\n\n```typescript\nimport { packTar, unpackTar } from 'modern-tar';\n\n// Pack entries into a tar buffer\nconst entries = [\n\t{ header: { name: \"file.txt\", size: 5 }, body: \"hello\" },\n\t{ header: { name: \"dir/\", type: \"directory\", size: 0 } },\n\t{ header: { name: \"dir/nested.txt\", size: 3 }, body: new Uint8Array([97, 98, 99]) } // \"abc\"\n];\n\n// Accepts string, Uint8Array, Blob, ReadableStream<Uint8Array> and more...\nconst tarBuffer = await packTar(entries);\n\n// Unpack tar buffer into entries\nconst entries = await unpackTar(tarBuffer);\nfor (const entry of entries) {\n\tconsole.log(`File: ${entry.header.name}`);\n\tconst content = new TextDecoder().decode(entry.data);\n\tconsole.log(`Content: ${content}`);\n}\n```\n\n#### Streaming\n\n```typescript\nimport { createTarPacker, createTarDecoder } from 'modern-tar';\n\n// Create a tar packer\nconst { readable, controller } = createTarPacker();\n\n// Add entries dynamically\nconst fileStream = controller.add({\n\tname: \"dynamic.txt\",\n\tsize: 5,\n\ttype: \"file\"\n});\n\n// Write content to the stream\nconst writer = fileStream.getWriter();\nawait writer.write(new TextEncoder().encode(\"hello\"));\nawait writer.close();\n\n// When done adding entries, finalize the archive\ncontroller.finalize();\n\n// Pipe the archive right into a decoder\nconst decodedStream = readable.pipeThrough(createTarDecoder());\nfor await (const entry of decodedStream) {\n\tconsole.log(`Decoded: ${entry.header.name}`);\n\n\tconst shouldSkip = entry.header.name.endsWith(\".md\");\n\tif (shouldSkip) {\n\t\t// You MUST drain the body with cancel() to proceed to the next entry or read it fully,\n\t\t// otherwise the stream will stall.\n\t\tawait entry.body.cancel();\n\t\tcontinue;\n\t}\n\n\tconst reader = entry.body.getReader();\n\twhile (true) {\n\t\tconst { done, value } = await reader.read();\n\t\tif (done) break;\n\t\tprocessChunk(value);\n\t}\n}\n```\n\n#### Compression/Decompression (gzip)\n\n```typescript\nimport { createGzipEncoder, createTarPacker } from 'modern-tar';\n\n// Create and compress a tar archive\nconst { readable, controller } = createTarPacker();\nconst compressedStream = readable.pipeThrough(createGzipEncoder());\n\n// Add entries...\nconst fileStream = controller.add({ name: \"file.txt\", size: 5, type: \"file\" });\nconst writer = fileStream.getWriter();\nawait writer.write(new TextEncoder().encode(\"hello\"));\nawait writer.close();\ncontroller.finalize();\n\n// Upload compressed .tar.gz\nawait fetch('/api/upload', {\n  method: 'POST',\n  body: compressedStream,\n  headers: { 'Content-Type': 'application/gzip' }\n});\n```\n\n```typescript\nimport { createGzipDecoder, createTarDecoder, unpackTar } from 'modern-tar';\n\n// Download and process a .tar.gz file\nconst response = await fetch('https://api.example.com/archive.tar.gz');\nif (!response.body) throw new Error('No response body');\n\n// Buffer entire archive\nconst entries = await unpackTar(response.body.pipeThrough(createGzipDecoder()));\n\nfor (const entry of entries) {\n\tconsole.log(`Extracted: ${entry.header.name}`);\n\tconst content = new TextDecoder().decode(entry.data);\n\tconsole.log(`Content: ${content}`);\n}\n\n// Or chain decompression and tar parsing using streams\nconst entries = response.body\n  .pipeThrough(createGzipDecoder())\n  .pipeThrough(createTarDecoder());\n\nfor await (const entry of entries) {\n  console.log(`Extracted: ${entry.header.name}`);\n  // Process entry.body ReadableStream as needed\n}\n```\n\n### Node.js Filesystem Usage\n\nThese APIs use Node.js streams when interacting with the local filesystem.\n\n#### Simple\n\n```typescript\nimport { packTar, unpackTar } from 'modern-tar/fs';\nimport { createWriteStream, createReadStream } from 'node:fs';\nimport { pipeline } from 'node:stream/promises';\n\n// Pack a directory into a tar file\nconst tarStream = packTar('./my/project');\nconst fileStream = createWriteStream('./project.tar');\nawait pipeline(tarStream, fileStream);\n\n// Extract a tar file to a directory\nconst tarReadStream = createReadStream('./project.tar', {\n\thighWaterMark: 256 * 1024 // 256 KB for optimal performance\n});\nconst extractStream = unpackTar('./output/directory');\nawait pipeline(tarReadStream, extractStream);\n```\n\n#### Filtering and Transformation\n\n```typescript\nimport { packTar, unpackTar } from 'modern-tar/fs';\nimport { createReadStream } from 'node:fs';\nimport { pipeline } from 'node:stream/promises';\n\n// Pack with filtering\nconst packStream = packTar('./my/project', {\n\tfilter: (filePath, stats) => !filePath.includes('node_modules'),\n\tmap: (header) => ({ ...header, mode: 0o644 }), // Set all files to 644\n\tdereference: true // Follow symlinks instead of archiving them\n});\n\n// Unpack with advanced options\nconst sourceStream = createReadStream('./archive.tar', {\n\thighWaterMark: 256 * 1024 // 256 KB for optimal performance\n});\nconst extractStream = unpackTar('./output', {\n\t// Core options\n\tstrip: 1, // Remove first directory level\n\tfilter: (header) => header.name.endsWith('.js'), // Only extract JS files\n\tmap: (header) => ({ ...header, name: header.name.toLowerCase() }), // Transform names\n\n\t// Filesystem-specific options\n\tfmode: 0o644, // Override file permissions\n\tdmode: 0o755, // Override directory permissions\n\tmaxDepth: 50,  // Limit extraction depth for security (default: 1024)\n\tconcurrency: 8 // Limit concurrent filesystem operations (default: CPU cores)\n});\n\nawait pipeline(sourceStream, extractStream);\n```\n\n#### Archive Creation\n\n```typescript\nimport { packTar, type TarSource } from 'modern-tar/fs';\nimport { createWriteStream } from 'node:fs';\nimport { pipeline } from 'node:stream/promises';\n\n// Pack multiple sources\nconst sources: TarSource[] = [\n  { type: 'file', source: './package.json', target: 'project/package.json' },\n  { type: 'directory', source: './src', target: 'project/src' },\n  { type: 'content', content: 'Hello World!', target: 'project/hello.txt' },\n  { type: 'content', content: '#!/bin/bash\\necho \"Executable\"', target: 'bin/script.sh', mode: 0o755 },\n  { type: 'stream', content: createReadStream('./large-file.bin'), target: 'project/data.bin', size: 1048576 },\n  { type: 'stream', content: fetch('/api/data').then(r => r.body!), target: 'project/remote.json', size: 2048 }\n];\n\nconst archiveStream = packTar(sources);\nawait pipeline(archiveStream, createWriteStream('project.tar'));\n```\n\n#### Compression/Decompression (gzip)\n\n```typescript\nimport { packTar, unpackTar } from 'modern-tar/fs';\nimport { createWriteStream, createReadStream } from 'node:fs';\nimport { createGzip, createGunzip } from 'node:zlib';\nimport { pipeline } from 'node:stream/promises';\n\n// Pack directory and compress to .tar.gz\nconst tarStream = packTar('./my/project');\nawait pipeline(tarStream, createGzip(), createWriteStream('./project.tar.gz'));\n\n// Decompress and extract .tar.gz\nconst gzipStream = createReadStream('./project.tar.gz', {\n\thighWaterMark: 256 * 1024 // 256 KB for optimal performance\n});\nawait pipeline(gzipStream, createGunzip(), unpackTar('./output'));\n```\n\n## API Reference\n\nSee the [API Reference](./REFERENCE.md).\n\n# Benchmarks\n\nCurrent benchmarks indicate we're much faster than other popular tar libraries for small file archives (packing and unpacking). On the other hand, larger files hit an I/O bottleneck resulting in similar performance between libraries.\n\nSee the [Results](./benchmarks/README.md).\n\n## Compatibility\n\nThe core library uses the [Web Streams API](https://caniuse.com/streams) and requires:\n\n- **Node.js**: 18.0+\n- **Browsers**: Modern browsers with Web Streams support\n  - Chrome 71+\n  - Firefox 102+\n  - Safari 14.1+\n  - Edge 79+\n\n## Acknowledgements\n\n- [`tar-stream`](https://github.com/mafintosh/tar-stream) and [`tar-fs`](https://github.com/mafintosh/tar-fs) - For the inspiration and test fixtures.\n\n## License\n\nMIT\n\n## cjser\n\nThis package is a CommonJS-compatible build generated by cjser for projects that still need `require()` support. The source version matches the original npm package version, with a cjser prerelease suffix for this generated build.\nOriginal repository: https://github.com/ayuhito/modern-tar\n","readmeFilename":"README.md","_rev":"1-cffc5591353b10dd6abf3a238557887b"}