rar-stream
Fast RAR archive streaming for Rust, Node.js, and browsers. Zero dependencies core.
What's New in v5.1.0
- โก Parallel RAR5 pipeline: Beats the official C
unrarin all 24 benchmark scenarios - ๐ WASM RAR5 support: Full RAR5 decompression in the browser via
WasmRar5Decoder - ๐ NAPI pipeline: Node.js users get 40% faster decompression automatically
- ๐งช E2E browser tests: Full Playwright tests for upload โ decompress โ verify workflow
Features
- ๐ Fast: Native Rust implementation with NAPI bindings
- ๐ฆ Zero dependencies: Core library has no external dependencies
- ๐ Cross-platform: Works on Linux, macOS, Windows
- ๐ Streaming: Stream files directly from RAR archives
- ๐ Multi-volume: Supports split archives (.rar, .r00, .r01, ...)
- ๐๏ธ Full decompression: LZSS, PPMd, and filters
- ๐ Encrypted archives: AES-256/AES-128 decryption for RAR4 & RAR5
- ๐ RAR4 + RAR5: Full support for both RAR formats
- ๐ Browser support: WASM build available
Installation
Rust
[]
= { = "5", = ["async", "crypto"] }
Node.js
# or
# or
Quick Start
import from 'rar-stream';
// Open a RAR archive
const media = ;
const pkg = ;
// Parse and list inner files
const files = await pkg.;
Rust Quick Start
use ;
use Arc;
async
Examples
Extract a File to Disk
import from 'rar-stream';
import fs from 'fs';
const media = ;
const pkg = ;
const files = await pkg.;
// Find a specific file
const targetFile = files.;
if
Stream Video from RAR (Node.js Readable Stream)
import from 'rar-stream';
import fs from 'fs';
const media = ;
const pkg = ;
const files = await pkg.;
const video = files.;
if
WebTorrent Integration
Use rar-stream with WebTorrent to stream video from RAR archives inside torrents:
import WebTorrent from 'webtorrent';
import from 'rar-stream';
const client = ;
client.;
HTTP Range Request Handler (Express)
import express from 'express';
import from 'rar-stream';
const app = ;
// Pre-parse the RAR archive
const media = ;
const pkg = ;
const files = await pkg.;
const video = files.;
app.;
app.;
Multi-Volume Archives
import from 'rar-stream';
import fs from 'fs';
import path from 'path';
// Find all volumes in a directory
const dir = './my-archive';
const volumeFiles = fs.
.
.
.;
console.log;
const pkg = ;
const files = await pkg.;
// Files spanning multiple volumes are handled automatically
Check if a File is a RAR Archive
import from 'rar-stream';
import fs from 'fs';
// Read first 300 bytes (enough for header detection)
const buffer = Buffer.;
const fd = fs.;
fs.;
fs.;
if else
Limit Number of Files Parsed
import from 'rar-stream';
const media = ;
const pkg = ;
// Only parse first 10 files (useful for previewing large archives)
const files = await pkg.;
console.log;
API Reference
LocalFileMedia
Represents a local RAR file.
class LocalFileMedia {
constructor(path: string);
readonly name: string; // Filename (basename)
readonly length: number; // File size in bytes
// Read a byte range into a Buffer
// Create a Readable stream for a byte range
createReadStream(opts: { start: number; end: number }): Readable;
}
FileMedia Interface
Custom data sources (WebTorrent, S3, HTTP, etc.) must implement this interface:
interface FileMedia {
readonly name: string;
readonly length: number;
createReadStream(opts: { start: number; end: number }): Readable;
}
RarFilesPackage
Parses single or multi-volume RAR archives.
class RarFilesPackage {
constructor(files: FileMedia[]); // LocalFileMedia or custom FileMedia
parse(opts?: {
maxFiles?: number; // Limit number of files to parse
}): Promise<InnerFile[]>;
}
InnerFile
Represents a file inside the RAR archive.
import { Readable } from 'stream';
class InnerFile {
readonly name: string; // Full path inside archive
readonly length: number; // Uncompressed size in bytes
// Read entire file into memory
readToEnd(): Promise<Buffer>;
// Create a Readable stream for the entire file or a byte range
createReadStream(opts?: {
start?: number; // Default: 0
end?: number; // Default: length - 1
}): Readable;
}
Utility Functions
// Check if buffer starts with RAR signature
function isRarArchive(buffer: Buffer): boolean;
// Parse RAR header from buffer (needs ~300 bytes)
function parseRarHeader(buffer: Buffer): RarFileInfo | null;
// Convert a Readable stream to a Buffer
function streamToBuffer(stream: Readable): Promise<Buffer>;
// Create a FileMedia from any source with createReadStream
function createFileMedia(source: FileMedia): FileMedia;
interface RarFileInfo {
name: string;
packedSize: number;
unpackedSize: number;
method: number;
continuesInNext: boolean;
}
Compression Support
RAR Format Compatibility
| Format | Signature | Support |
|---|---|---|
| RAR 1.5-4.x (RAR4) | Rar!\x1a\x07\x00 |
โ Full |
| RAR 5.0+ (RAR5) | Rar!\x1a\x07\x01\x00 |
โ Full |
Compression Methods
| Method | RAR4 | RAR5 | Description |
|---|---|---|---|
| Store | โ | โ | No compression |
| LZSS | โ | โ | Huffman + LZ77 sliding window |
| PPMd | โ | โ | Context-based (RAR4 only) |
Filter Support
| Filter | RAR4 | RAR5 | Description |
|---|---|---|---|
| E8 | โ | โ | x86 CALL preprocessing |
| E8E9 | โ | โ | x86 CALL/JMP preprocessing |
| Delta | โ | โ | Byte delta per channel |
| ARM | โ | โ | ARM branch preprocessing |
| Itanium | โ | โ | IA-64 preprocessing |
| RGB | โ | โ | Predictive color filter |
| Audio | โ | โ | Audio sample predictor |
Encryption Support
| Feature | RAR4 | RAR5 | Notes |
|---|---|---|---|
| Encrypted files | โ | โ | crypto feature |
| Encrypted headers | โ | โ | RAR5 -hp archives |
| Algorithm | AES-128-CBC | AES-256-CBC | โ |
| Key derivation | SHA-1 (262k rounds) | PBKDF2-HMAC-SHA256 | โ |
To enable encryption support:
Node.js/npm: Encryption is always available.
Rust:
[]
= { = "5", = ["async", "crypto"] }
Performance
RAR5 Decompression: Faster Than unrar
rar-stream's parallel pipeline beats the official C unrar (v7.0, multi-threaded) across all tested workloads.
Benchmark on AMD Ryzen 5 7640HS (6 cores):
| Archive | Size | rar-stream (pipeline) | unrar | Ratio |
|---|---|---|---|---|
| ISO (binary) | 200 MB | 422ms | 453ms | 0.93ร |
| Text | 200 MB | 144ms | 202ms | 0.71ร |
| Mixed | 200 MB | 342ms | 527ms | 0.65ร |
| Binary | 500 MB | 824ms | 1149ms | 0.72ร |
| Text | 500 MB | 424ms | 604ms | 0.70ร |
| Mixed | 1 GB | 1953ms | 2550ms | 0.77ร |
Wins 24 out of 24 benchmark scenarios across 6 data types ร 4 compression settings.
Best case: 1.9ร faster than unrar (ISO 200MB, -m5 -md128m).
Archive Single Pipeline Unrar Pipe/Unrar
----------------------------------------------------------------
bin-500_m3_32m 1278ms 884ms 1187ms 0.74x
bin-500_m5_128m 1200ms 824ms 1149ms 0.72x
bin-500_m5_32m 1247ms 852ms 1162ms 0.73x
bin-500_m5_4m 1378ms 942ms 1770ms 0.53x
iso-200_m3_32m 715ms 426ms 760ms 0.56x
iso-200_m5_128m 720ms 423ms 811ms 0.52x
iso-200_m5_32m 721ms 422ms 453ms 0.93x
iso-200_m5_4m 717ms 422ms 442ms 0.95x
mixed-1g_m3_32m 2974ms 2109ms 2775ms 0.76x
mixed-1g_m5_128m 3177ms 2213ms 2984ms 0.74x
mixed-1g_m5_32m 2979ms 2086ms 2731ms 0.76x
mixed-1g_m5_4m 2761ms 1953ms 2550ms 0.77x
mixed-200_m3_32m 499ms 385ms 547ms 0.70x
mixed-200_m5_128m 438ms 342ms 527ms 0.65x
mixed-200_m5_32m 495ms 384ms 539ms 0.71x
mixed-200_m5_4m 511ms 395ms 538ms 0.73x
text-200_m3_32m 209ms 145ms 202ms 0.72x
text-200_m5_128m 205ms 144ms 239ms 0.60x
text-200_m5_32m 209ms 144ms 202ms 0.71x
text-200_m5_4m 227ms 153ms 207ms 0.74x
text-500_m3_32m 606ms 432ms 613ms 0.70x
text-500_m5_128m 601ms 431ms 644ms 0.67x
text-500_m5_32m 604ms 424ms 604ms 0.70x
text-500_m5_4m 659ms 455ms 643ms 0.71x
Node.js (NAPI) Performance
| Configuration | Time (200MB) | vs unrar |
|---|---|---|
| v5.0.0 (single-threaded) | 1127ms | 2.73ร slower |
| v5.1.0 (pipeline) | 673ms | 1.53ร slower |
The remaining NAPI gap vs native is I/O + buffer copy overhead, not decompression.
Optimization Features
- Parallel pipeline: Decode + apply in parallel using rayon worker threads
- Split-buffer decode: Separates literals from commands for cache-friendly apply
- LTO (Link-Time Optimization): Enabled by default in release builds
- SIMD: Automatic vectorization for E8/E9 filter scanning and memcpy
- Zero-copy streaming: Direct buffer access without intermediate copies
Migrating from v3.x
rar-stream v4 is a complete Rust rewrite with the same API. It's a drop-in replacement:
// Works the same in v3.x and v4.x
import from 'rar-stream';
const media = ;
const pkg = ;
const files = await pkg.;
Breaking Changes
- Node.js 18+ required (was 14+)
- Native Rust implementation (faster, lower memory)
License
MIT
Credits
- Based on unrar reference implementation
- PPMd algorithm by Dmitry Shkarin