Filesystem bindings for tar-stream providing directory packing/extraction capabilities
npx @tessl/cli install tessl/npm-tar-fs@3.1.0tar-fs provides filesystem bindings for tar-stream, enabling developers to pack directories into tarballs and extract tarballs into directories with a simple streaming API. It offers comprehensive tar file manipulation capabilities including selective file packing/extraction, header modification, stream transformation, and permission control.
npm install tar-fsconst tar = require('tar-fs');For ES modules:
import tar from 'tar-fs';const tar = require('tar-fs');
const fs = require('fs');
// Pack a directory into a tarball
tar.pack('./my-directory').pipe(fs.createWriteStream('my-tarball.tar'));
// Extract a tarball into a directory
fs.createReadStream('my-other-tarball.tar').pipe(tar.extract('./my-other-directory'));
// Copy a directory (with permissions and timestamps intact)
tar.pack('source-directory').pipe(tar.extract('dest-directory'));tar-fs is built around two core streaming functions that work with tar-stream instances:
Packs a directory into a tar stream with extensive filtering and transformation options.
/**
* Packs a directory into a tar stream
* @param cwd - Directory to pack (defaults to '.')
* @param opts - Packing options
* @returns tar-stream pack instance (readable stream)
*/
function pack(cwd, opts);Options:
interface PackOptions {
/** Custom filesystem implementation */
fs?: object;
/** Function to ignore/filter files: (name) => boolean */
ignore?: (name: string) => boolean;
/** Alias for ignore */
filter?: (name: string) => boolean;
/** Function to transform file streams: (stream, header) => stream */
mapStream?: (stream: ReadableStream, header: object) => ReadableStream;
/** Dereference symlinks (pack contents instead of links) */
dereference?: boolean;
/** Array of specific entries to pack */
entries?: string[];
/** Sort entries alphabetically */
sort?: boolean;
/** Strict mode - fail on unsupported file types (default: true) */
strict?: boolean;
/** Permission umask */
umask?: number;
/** Existing pack stream to use */
pack?: object;
/** Callback function on completion */
finish?: (pack: object) => void;
/** Function to modify tar headers: (header) => header */
map?: (header: object) => object;
/** Directory mode permissions */
dmode?: number;
/** File mode permissions */
fmode?: number;
/** Number of path levels to strip */
strip?: number;
/** Make files readable (adds 444 to files, 555 to directories) */
readable?: boolean;
/** Make files writable (adds 222 to files, 333 to directories) */
writable?: boolean;
/** Finalize pack when done (default: true) */
finalize?: boolean;
}Usage Examples:
// Pack with file filtering
const pack = tar.pack('./my-directory', {
ignore(name) {
return path.extname(name) === '.bin'; // ignore .bin files
}
});
// Pack specific entries only
const pack = tar.pack('./my-directory', {
entries: ['file1.txt', 'subdir/file2.txt']
});
// Pack with header modification
const pack = tar.pack('./my-directory', {
map(header) {
header.name = 'prefixed/' + header.name;
return header;
}
});
// Pack with stream transformation
const pack = tar.pack('./my-directory', {
mapStream(fileStream, header) {
if (path.extname(header.name) === '.js') {
return fileStream.pipe(someTransform);
}
return fileStream;
}
});
// Pack with custom permissions
const pack = tar.pack('./my-directory', {
dmode: parseInt('755', 8), // directory permissions
fmode: parseInt('644', 8), // file permissions
readable: true,
writable: false
});Extracts a tar stream into a directory with extensive filtering and transformation options.
/**
* Extracts a tar stream into a directory
* @param cwd - Directory to extract to (defaults to '.')
* @param opts - Extraction options
* @returns tar-stream extract instance (writable stream)
*/
function extract(cwd, opts);Options:
interface ExtractOptions {
/** Custom filesystem implementation */
fs?: object;
/** Function to ignore/filter files: (name, header) => boolean */
ignore?: (name: string, header?: object) => boolean;
/** Alias for ignore */
filter?: (name: string, header?: object) => boolean;
/** Function to transform file streams: (stream, header) => stream */
mapStream?: (stream: ReadableStream, header: object) => ReadableStream;
/** Change file ownership (default: true on Unix as root) */
chown?: boolean;
/** Existing extract stream to use */
extract?: object;
/** Function to modify tar headers: (header) => header */
map?: (header: object) => object;
/** Directory mode permissions */
dmode?: number;
/** File mode permissions */
fmode?: number;
/** Number of path levels to strip */
strip?: number;
/** Make files readable (adds 444 to files, 555 to directories) */
readable?: boolean;
/** Make files writable (adds 222 to files, 333 to directories) */
writable?: boolean;
/** Strict mode - fail on unsupported entry types (default: true) */
strict?: boolean;
/** Validate symlinks are within extraction directory (default: true) */
validateSymlinks?: boolean;
/** Set file modification times (default: true) */
utimes?: boolean;
/** Permission umask */
umask?: number;
/** Callback function on completion */
finish?: () => void;
/** Fallback hard links as file copies on permission errors */
hardlinkAsFilesFallback?: boolean;
}Usage Examples:
// Extract with file filtering
const extract = tar.extract('./my-directory', {
ignore(name) {
return path.extname(name) === '.bin'; // ignore .bin files
}
});
// Extract with type filtering using header
const extract = tar.extract('./my-directory', {
ignore(name, header) {
// Only extract files and directories, ignore symlinks
return header.type !== 'file' && header.type !== 'directory';
}
});
// Extract with header modification
const extract = tar.extract('./my-directory', {
map(header) {
header.name = 'another-prefix/' + header.name;
return header;
}
});
// Extract with stream transformation
const extract = tar.extract('./my-directory', {
mapStream(fileStream, header) {
if (path.extname(header.name) === '.js') {
return fileStream.pipe(someTransform);
}
return fileStream;
}
});
// Extract with custom permissions
const extract = tar.extract('./my-directory', {
dmode: parseInt('755', 8), // directory permissions
fmode: parseInt('644', 8), // file permissions
readable: true,
writable: true
});For advanced use cases, tar-fs integrates seamlessly with tar-stream instances.
// Using custom pack stream
const mypack = tar.pack('./my-directory', {
finalize: false,
finish(pack) {
// Add custom entry
pack.entry({name: 'generated-file.txt'}, 'Hello World');
// Pack another directory into same stream
tar.pack('./other-directory', { pack: pack });
}
});
// Using custom extract stream
const tarStream = require('tar-stream');
const extract = tarStream.extract();
extract.on('entry', (header, stream, next) => {
// Custom entry processing
console.log('Extracting:', header.name);
stream.resume();
next();
});
tar.extract('./output', { extract: extract });interface TarHeader {
/** File/directory name */
name: string;
/** File mode/permissions */
mode: number;
/** User ID */
uid: number;
/** Group ID */
gid: number;
/** File size in bytes */
size: number;
/** Modification time */
mtime: Date;
/** Entry type: 'file', 'directory', 'symlink', 'link' */
type: string;
/** Link target for symlinks and hard links */
linkname?: string;
}Common error scenarios: