{"id":11348,"library":"modern-tar","title":"Modern Tar Archiver","description":"modern-tar is a zero-dependency, cross-platform JavaScript library designed for efficient streaming of tar archives. It supports both parsing and writing tar files, leveraging the browser-native Web Streams API for optimal performance and memory efficiency across diverse JavaScript runtimes, including Node.js (requiring version 18.0.0 or higher), web browsers, and Cloudflare Workers. The library is currently at stable version 0.7.6, with a consistent release cadence that introduces bug fixes, performance optimizations, and crucial security patches. Its key differentiators include a robust streaming architecture capable of handling large archives without full memory loading, full compliance with USTAR format and PAX extensions, built-in helpers for gzip compression, a TypeScript-first design ensuring strong type safety, and a minimal footprint due to its zero external dependencies.","status":"active","version":"0.7.6","language":"javascript","source_language":"en","source_url":"https://github.com/ayuhito/modern-tar","tags":["javascript","typescript"],"install":[{"cmd":"npm install modern-tar","lang":"bash","label":"npm"},{"cmd":"yarn add modern-tar","lang":"bash","label":"yarn"},{"cmd":"pnpm add modern-tar","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"The library primarily uses ES Modules and ships types. CommonJS `require` is not the recommended or idiomatic way to import.","wrong":"const { packTar } = require('modern-tar')","symbol":"packTar","correct":"import { packTar } from 'modern-tar'"},{"note":"This is a named export, not a default export.","wrong":"import unpackTar from 'modern-tar'","symbol":"unpackTar","correct":"import { unpackTar } from 'modern-tar'"},{"note":"Used for streaming tar creation, leveraging Web Streams.","symbol":"createTarPacker","correct":"import { createTarPacker } from 'modern-tar'"},{"note":"Utility for compressing streams with gzip.","symbol":"createGzipEncoder","correct":"import { createGzipEncoder } from 'modern-tar'"}],"quickstart":{"code":"import { createTarPacker, createTarDecoder } from 'modern-tar';\n\nasync function processTarStream() {\n  // Create a tar packer\n  const { readable, controller } = createTarPacker();\n\n  // Add entries dynamically\n  const fileStream = controller.add({\n    name: \"dynamic.txt\",\n    size: 5,\n    type: \"file\"\n  });\n\n  // Write content to the stream\n  const writer = fileStream.getWriter();\n  await writer.write(new TextEncoder().encode(\"hello\"));\n  await writer.close();\n\n  // Add another entry, maybe a directory\n  controller.add({ name: \"my-dir/\", type: \"directory\", size: 0 });\n\n  // When done adding entries, finalize the archive\n  controller.finalize();\n\n  // Pipe the archive right into a decoder\n  const decodedStream = readable.pipeThrough(createTarDecoder());\n  for await (const entry of decodedStream) {\n    console.log(`Decoded: ${entry.header.name}`);\n\n    const shouldSkip = entry.header.name.endsWith(\".md\");\n    if (shouldSkip) {\n      // You MUST drain the body with cancel() to proceed to the next entry or read it fully,\n      // otherwise the stream will stall.\n      await entry.body.cancel();\n      continue;\n    }\n\n    // Example: Read the content for non-skipped files\n    if (entry.header.type === 'file') {\n      const reader = entry.body.getReader();\n      let chunk = '';\n      while (true) {\n        const { done, value } = await reader.read();\n        if (done) break;\n        chunk += new TextDecoder().decode(value);\n      }\n      console.log(`Content of ${entry.header.name}: ${chunk}`);\n    }\n  }\n  console.log('Tar stream processing complete.');\n}\n\nprocessTarStream().catch(console.error);","lang":"typescript","description":"Demonstrates streaming tar creation with `createTarPacker` and subsequent decoding with `createTarDecoder`, highlighting dynamic entry addition and the necessity of draining entry bodies."},"warnings":[{"fix":"Remove the `streamTimeout` option from your `UnpackOptions` configuration.","message":"The `streamTimeout` option has been removed from `UnpackOptions` due to a new performance architecture.","severity":"breaking","affected_versions":">=0.7.0"},{"fix":"Update your code to explicitly check for `undefined` when accessing the `data` property for entries, especially for non-file types.","message":"The `data` property returned by the `packTar` function for bodyless entries (like directories or symlinks) can now be `undefined` instead of an empty `Uint8Array`. For empty files, it will be `Uint8Array(0)`.","severity":"breaking","affected_versions":">=0.6.0"},{"fix":"Upgrade to version 0.7.4 or later to mitigate the prototype pollution vulnerability.","message":"A prototype pollution vulnerability in PAX headers was fixed. Archives crafted to exploit this could modify object prototypes, potentially leading to security issues.","severity":"breaking","affected_versions":"<0.7.4"},{"fix":"Upgrade to version 0.7.6 or later to ensure correct and secure handling of tar archives, particularly those with large headers or complex unicode paths.","message":"Security fixes were implemented to prevent a 32-bit integer overflow on meta header sizes and address issues with unicode path handling, which could lead to data corruption or unexpected behavior.","severity":"breaking","affected_versions":"<0.7.6"},{"fix":"After processing an `entry.body` (or if you choose to skip it), ensure you call `await entry.body.cancel()` or fully read its content (e.g., `await new Response(entry.body).arrayBuffer()`) before attempting to retrieve the next entry.","message":"When consuming a decoded tar stream (e.g., from `createTarDecoder`), you *must* explicitly drain or cancel the `body` of each `entry` before iterating to the next entry. Failure to do so will cause the stream to stall indefinitely.","severity":"gotcha","affected_versions":">=0.5.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Change your import statement from `const { packTar } = require('modern-tar')` to `import { packTar } from 'modern-tar'`.","cause":"Attempting to use CommonJS `require` syntax in an ES Module environment (e.g., modern Node.js or bundlers) for a library that exports named ES Modules.","error":"TypeError: (0 , modern_tar__WEBPACK_IMPORTED_MODULE_0__.packTar) is not a function"},{"fix":"Ensure that after processing each entry, you either fully consume its `entry.body` stream or explicitly call `await entry.body.cancel()` to signal that you are done with it and allow the decoder to proceed.","cause":"The `body` ReadableStream of a tar entry was not fully read or explicitly cancelled before attempting to access the next entry from the decoder.","error":"Stream stalled or hangs indefinitely after processing a few entries."}],"ecosystem":"npm"}