roxify 1.6.4 → 1.6.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,377 +1,514 @@
1
- # RoxCompressor Transform
1
+ # Roxify
2
2
 
3
- > Encode binary data into PNG images and decode them back. Fast, efficient, with optional encryption and native Rust acceleration.
3
+ > Encode binary data into PNG images and decode them back, losslessly. Roxify combines native Rust acceleration, multi-threaded Zstd compression, and AES-256-GCM encryption into a single, portable Node.js module.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/roxify.svg)](https://www.npmjs.com/package/roxify)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
7
7
 
8
- ## Features
8
+ ---
9
9
 
10
- - **Blazing Fast**: Native Rust acceleration via N-API — **1GB/s** throughput on modern hardware
11
- - 🚀 **Optimized Compression**: Multi-threaded Zstd compression (level 19) with parallel processing
12
- - 🔒 **Secure**: AES-256-GCM encryption support with PBKDF2 key derivation
13
- - 🎨 **Multiple modes**: Compact, chunk, pixel, and screenshot modes
14
- - 📦 **CLI & API**: Use as command-line tool or JavaScript library
15
- - 🔄 **Lossless**: Perfect roundtrip encoding/decoding
16
- - 📖 **Full TSDoc**: Complete TypeScript documentation
17
- - 🦀 **Rust Powered**: Optional native module for extreme performance (falls back to pure JS)
10
+ ## Table of Contents
18
11
 
19
- ## Real-world benchmarks 🔧
12
+ - [Overview](#overview)
13
+ - [Features](#features)
14
+ - [Benchmarks](#benchmarks)
15
+ - [Installation](#installation)
16
+ - [CLI Usage](#cli-usage)
17
+ - [JavaScript API](#javascript-api)
18
+ - [Encoding Modes](#encoding-modes)
19
+ - [Encryption](#encryption)
20
+ - [Performance Tuning](#performance-tuning)
21
+ - [Cross-Platform Support](#cross-platform-support)
22
+ - [Building from Source](#building-from-source)
23
+ - [Architecture](#architecture)
24
+ - [Error Handling](#error-handling)
25
+ - [Security Considerations](#security-considerations)
26
+ - [Contributing](#contributing)
27
+ - [License](#license)
20
28
 
21
- **Highlights**
29
+ ---
22
30
 
23
- - Practical benchmarks on large codebase datasets showing significant compression and high throughput while handling many small files efficiently.
31
+ ## Overview
24
32
 
25
- **Results**
33
+ Roxify is a PNG steganography toolkit. It packs arbitrary binary data -- files, directories, or raw buffers -- into standard PNG images that can be shared, uploaded, and stored anywhere images are accepted. The data is compressed with multi-threaded Zstd, optionally encrypted with AES-256-GCM, and embedded in valid PNG structures that survive re-uploads and screenshots.
26
34
 
27
- | Dataset | Files | Original | Compressed | Ratio | Time | Throughput | Notes |
28
- | -------- | ------: | -------: | ---------: | --------: | -----: | ---------: | ------------------------------------------- |
29
- | 4,000 MB | 731,340 | 3.93 GB | 111.42 MB | **2.8%** | 26.9 s | 149.4 MB/s | gzip: 2.26 GB (57.5%); 7z: 1.87 GB (47.6%) |
30
- | 1,000 MB | 141,522 | 1.03 GB | 205 MB | **19.4%** | ~6.2 s | ≈170 MB/s | shows benefits for many-small-file datasets |
35
+ The core compression and image-processing logic is written in Rust and exposed to Node.js through N-API. When the native module is unavailable, Roxify falls back to a pure TypeScript implementation transparently.
31
36
 
32
- ### Methodology
37
+ ---
33
38
 
34
- - Compression: multithreaded Zstd (level 19) and Brotli (configurable).
35
- - Setup: parallel I/O and multithreaded compression on modern SSD-backed systems.
36
- - Measurements: wall-clock time; throughput = original size / time; comparisons against gzip and 7z with typical defaults.
37
- - Reproducibility: full benchmark details, commands and raw data are available in `docs/BENCHMARK_FINAL_REPORT.md`.
39
+ ## Features
38
40
 
39
- These results demonstrate Roxify's strength for packaging large codebases and many-small-file archives where speed and a good compression/throughput trade-off matter.
41
+ - **Native Rust acceleration** via N-API with automatic fallback to pure JavaScript
42
+ - **Multi-threaded Zstd compression** (level 19) with parallel chunk processing via Rayon
43
+ - **AES-256-GCM encryption** with PBKDF2 key derivation (100,000 iterations)
44
+ - **Lossless roundtrip** -- encoded data is recovered byte-for-byte
45
+ - **Directory packing** -- encode entire directory trees into a single PNG
46
+ - **Screenshot reconstitution** -- recover data from photographed or screenshotted PNGs
47
+ - **CLI and programmatic API** -- use from the terminal or import as a library
48
+ - **Cross-platform** -- prebuilt binaries for Linux x64, macOS x64/ARM64, and Windows x64
49
+ - **Full TypeScript support** with exported types and TSDoc annotations
50
+ - **mimalloc allocator** for reduced memory fragmentation under heavy workloads
40
51
 
41
- ## Documentation
52
+ ---
42
53
 
43
- - 📘 **[CLI Documentation](./docs/CLI.md)** - Complete command-line usage guide
44
- - 📗 **[JavaScript SDK](./docs/JAVASCRIPT_SDK.md)** - Programmatic API reference with examples
45
- - 📙 **[Quick Start](#quick-start)** - Get started in 2 minutes
54
+ ## Benchmarks
46
55
 
47
- ## Installation
56
+ All measurements were taken on Linux x64 with Node.js v20. Each tool was run with default settings (zip deflate, gzip via `tar czf`, 7z LZMA2 at level 5, Roxify in compact mode with Zstd level 19). Roxify produces a valid PNG file rather than a raw archive.
48
57
 
49
- ### As CLI tool (npx)
58
+ ### Compression Ratio and Speed
50
59
 
51
- No installation needed! Use directly with npx:
60
+ | Dataset | Files | Original | zip | tar.gz | 7z | Roxify (PNG) |
61
+ |---|---:|---|---|---|---|---|
62
+ | Text files (1 MB) | 128 | 1.00 MB | 259 KB (25.3%) 52 ms | 196 KB (19.2%) 78 ms | 162 KB (15.8%) 347 ms | 203 KB (19.9%) 534 ms |
63
+ | JSON files (1 MB) | 1 183 | 1.00 MB | 700 KB (68.3%) 78 ms | 270 KB (26.4%) 43 ms | 212 KB (20.7%) 191 ms | 339 KB (33.0%) 766 ms |
64
+ | Binary (random, 1 MB) | 33 | 1.00 MB | 1.00 MB (100.5%) 29 ms | 1.00 MB (100.4%) 47 ms | 1.00 MB (100.1%) 128 ms | 1.00 MB (100.5%) 689 ms |
65
+ | Mixed (text+JSON+bin, 5 MB) | 2 241 | 5.00 MB | 3.26 MB (65.2%) 253 ms | 2.43 MB (48.7%) 228 ms | 2.27 MB (45.5%) 1.21 s | 2.59 MB (51.7%) 2.04 s |
66
+ | Text files (10 MB) | 1 285 | 10.00 MB | 2.54 MB (25.4%) 357 ms | 1.91 MB (19.1%) 657 ms | 1.53 MB (15.3%) 4.70 s | 1.98 MB (19.8%) 2.15 s |
67
+ | Mixed (text+JSON+bin, 10 MB) | 4 467 | 10.00 MB | 6.52 MB (65.2%) 461 ms | 4.86 MB (48.6%) 452 ms | 4.54 MB (45.4%) 2.51 s | 5.16 MB (51.6%) 3.77 s |
52
68
 
53
- ```bash
54
- npx rox encode input.zip output.png
55
- npx rox decode output.png original.zip
56
- ```
69
+ ### Key Observations
57
70
 
58
- ### As library
71
+ - **On compressible data** (text, JSON), Roxify achieves ratios comparable to tar.gz (19--33%) while producing a standard PNG image instead of an archive file. The output can be shared on platforms that only accept images.
72
+ - **On incompressible data** (random bytes), all tools converge to approximately 100% as expected. No compression algorithm can shrink truly random data.
73
+ - **7z (LZMA2)** achieves the best ratios overall but is significantly slower. Roxify finishes faster than 7z on the 10 MB text dataset (2.15 s vs 4.70 s).
74
+ - **zip** is the fastest tool but offers the weakest compression, especially on many small files (68.3% on JSON vs Roxify's 33.0%).
75
+ - The overhead of PNG framing and Zstd's higher compression level adds latency on small datasets. On larger inputs, Roxify's multi-threaded pipeline narrows the gap.
59
76
 
60
- ```bash
61
- npm install roxify
62
- ```
63
-
64
- ## CLI Usage
77
+ ### Methodology
65
78
 
66
- ### Quick Start
79
+ Benchmarks were generated using `test/benchmark.mjs`. Datasets consist of procedurally generated text, JSON, and random binary files. Each tool was invoked via its standard CLI with default or documented settings:
67
80
 
68
- ```bash
69
- # Encode a file
70
- npx rox encode document.pdf document.png
81
+ | Tool | Command |
82
+ |---|---|
83
+ | zip | `zip -r -q` |
84
+ | tar.gz | `tar czf` |
85
+ | 7z | `7z a -mx=5` |
86
+ | Roxify | `rox encode <dir> <output.png> -m compact` |
71
87
 
72
- # Decode it back
73
- npx rox decode document.png document.pdf
88
+ To reproduce:
74
89
 
75
- # With encryption
76
- npx rox encode secret.zip secret.png -p mypassword
77
- npx rox decode secret.png secret.zip -p mypassword
90
+ ```bash
91
+ node test/benchmark.mjs
78
92
  ```
79
93
 
80
- ### CLI Commands
94
+ ---
95
+
96
+ ## Installation
81
97
 
82
- #### `encode` - Encode file to PNG
98
+ ### As a CLI tool (no installation required)
83
99
 
84
100
  ```bash
85
- npx rox encode <input> [output] [options]
101
+ npx rox encode input.zip output.png
102
+ npx rox decode output.png original.zip
86
103
  ```
87
104
 
88
- **Options:**
105
+ ### As a library
89
106
 
90
- - `-p, --passphrase <pass>` - Encrypt with passphrase (AES-256-GCM)
91
- - `-m, --mode <mode>` - Encoding mode: `compact|chunk|pixel|screenshot` (default: `screenshot`)
92
- - `-q, --quality <0-11>` - Brotli compression quality (default: `1`)
93
- - `0` = fastest, largest
94
- - `11` = slowest, smallest
95
- - `-e, --encrypt <type>` - Encryption: `auto|aes|xor|none` (default: `aes` if passphrase)
96
- - `--no-compress` - Disable compression
97
- - `-o, --output <path>` - Output file path
107
+ ```bash
108
+ npm install roxify
109
+ ```
98
110
 
99
- **Examples:**
111
+ ### Global installation
100
112
 
101
113
  ```bash
102
- # Basic encoding
103
- npx rox encode data.bin output.png
104
-
105
- # Fast compression for large files
106
- npx rox encode large-video.mp4 output.png -q 0
114
+ npm install -g roxify
115
+ rox encode input.zip output.png
116
+ ```
107
117
 
108
- # High compression for small files
109
- npx rox encode config.json output.png -q 11
118
+ ---
110
119
 
111
- # With encryption
112
- npx rox encode secret.pdf secure.png -p "my secure password"
120
+ ## CLI Usage
113
121
 
114
- # Compact mode (smallest PNG)
115
- npx rox encode data.bin tiny.png -m compact
122
+ ### Encoding
116
123
 
117
- # Screenshot mode (recommended, looks like a real image)
118
- npx rox encode archive.tar.gz screenshot.png -m screenshot
124
+ ```bash
125
+ rox encode <input> [output] [options]
119
126
  ```
120
127
 
121
- #### `decode` - Decode PNG to file
128
+ | Option | Description | Default |
129
+ |---|---|---|
130
+ | `-p, --passphrase <pass>` | Encrypt with AES-256-GCM | none |
131
+ | `-m, --mode <mode>` | Encoding mode: `screenshot`, `compact` | `screenshot` |
132
+ | `-q, --quality <0-11>` | Compression effort (0 = fastest, 11 = smallest) | `1` |
133
+ | `-e, --encrypt <type>` | Encryption method: `auto`, `aes`, `xor`, `none` | `aes` if passphrase is set |
134
+ | `--no-compress` | Disable compression entirely | false |
135
+ | `-o, --output <path>` | Explicit output file path | auto-generated |
136
+
137
+ ### Decoding
122
138
 
123
139
  ```bash
124
- npx rox decode <input> [output] [options]
140
+ rox decode <input> [output] [options]
125
141
  ```
126
142
 
127
- **Options:**
128
-
129
- - `-p, --passphrase <pass>` - Decryption passphrase
130
- - `-o, --output <path>` - Output file path (auto-detected from metadata if not provided)
143
+ | Option | Description | Default |
144
+ |---|---|---|
145
+ | `-p, --passphrase <pass>` | Decryption passphrase | none |
146
+ | `-o, --output <path>` | Output file path | auto-detected from metadata |
147
+ | `--dict <file>` | Zstd dictionary for improved decompression | none |
131
148
 
132
- **Examples:**
149
+ ### Examples
133
150
 
134
151
  ```bash
135
- # Basic decoding
136
- npx rox decode encoded.png output.bin
152
+ # Encode a single file
153
+ rox encode document.pdf document.png
137
154
 
138
- # Auto-detect filename from metadata
139
- npx rox decode encoded.png
155
+ # Encode with encryption
156
+ rox encode secret.zip secret.png -p "strong passphrase"
140
157
 
141
- # With decryption
142
- npx rox decode encrypted.png output.pdf -p "my secure password"
158
+ # Decode back to original
159
+ rox decode secret.png secret.zip -p "strong passphrase"
160
+
161
+ # Fast compression for large files
162
+ rox encode video.mp4 output.png -q 0
163
+
164
+ # Best compression for small files
165
+ rox encode config.json output.png -q 11 -m compact
166
+
167
+ # Encode an entire directory
168
+ rox encode ./my-project project.png
143
169
  ```
144
170
 
171
+ ---
172
+
145
173
  ## JavaScript API
146
174
 
147
- ### Basic Usage
175
+ ### Basic Encode and Decode
148
176
 
149
177
  ```typescript
150
178
  import { encodeBinaryToPng, decodePngToBinary } from 'roxify';
151
179
  import { readFileSync, writeFileSync } from 'fs';
152
180
 
153
- const input = readFileSync('input.zip');
154
- const png = await encodeBinaryToPng(input, {
155
- mode: 'screenshot',
156
- name: 'input.zip',
157
- });
158
- writeFileSync('output.png', png);
181
+ // Encode
182
+ const input = readFileSync('document.pdf');
183
+ const png = await encodeBinaryToPng(input, { name: 'document.pdf' });
184
+ writeFileSync('document.png', png);
159
185
 
160
- const encoded = readFileSync('output.png');
186
+ // Decode
187
+ const encoded = readFileSync('document.png');
161
188
  const result = await decodePngToBinary(encoded);
162
189
  writeFileSync(result.meta?.name || 'output.bin', result.buf);
163
190
  ```
164
191
 
165
- ### With Encryption
192
+ ### Encrypted Roundtrip
166
193
 
167
194
  ```typescript
168
195
  const png = await encodeBinaryToPng(input, {
169
- mode: 'screenshot',
170
- passphrase: 'my-secret-password',
196
+ passphrase: 'my-secret',
171
197
  encrypt: 'aes',
172
- name: 'secret.zip',
198
+ name: 'confidential.pdf',
173
199
  });
174
200
 
175
- const result = await decodePngToBinary(encoded, {
176
- passphrase: 'my-secret-password',
201
+ const result = await decodePngToBinary(png, {
202
+ passphrase: 'my-secret',
177
203
  });
178
204
  ```
179
205
 
180
- ### Fast Compression
206
+ ### Directory Packing
207
+
208
+ ```typescript
209
+ import { packPaths, unpackBuffer } from 'roxify';
210
+
211
+ // Pack files into a buffer
212
+ const { buf, list } = packPaths(['./src', './README.md'], process.cwd());
213
+
214
+ // Encode the packed buffer into a PNG
215
+ const png = await encodeBinaryToPng(buf, { name: 'project.tar' });
216
+
217
+ // Later: decode and unpack
218
+ const decoded = await decodePngToBinary(png);
219
+ const unpacked = unpackBuffer(decoded.buf);
220
+ for (const file of unpacked.files) {
221
+ console.log(file.name, file.buf.length);
222
+ }
223
+ ```
224
+
225
+ ### Progress Reporting
181
226
 
182
227
  ```typescript
183
228
  const png = await encodeBinaryToPng(largeBuffer, {
184
- mode: 'screenshot',
185
- brQuality: 0,
186
229
  name: 'large-file.bin',
187
- });
188
-
189
- const png = await encodeBinaryToPng(smallBuffer, {
190
- mode: 'compact',
191
- brQuality: 11,
192
- name: 'config.json',
230
+ onProgress: ({ phase, loaded, total }) => {
231
+ console.log(`${phase}: ${loaded}/${total}`);
232
+ },
193
233
  });
194
234
  ```
195
235
 
196
- ### Encoding Modes
236
+ ### EncodeOptions
197
237
 
198
- #### `screenshot` (Recommended)
238
+ ```typescript
239
+ interface EncodeOptions {
240
+ compression?: 'zstd'; // Compression algorithm
241
+ compressionLevel?: number; // Zstd compression level (0-19)
242
+ passphrase?: string; // Encryption passphrase
243
+ dict?: Buffer; // Zstd dictionary for improved ratios
244
+ name?: string; // Original filename stored in metadata
245
+ mode?: 'screenshot'; // Encoding mode
246
+ encrypt?: 'auto' | 'aes' | 'xor' | 'none';
247
+ output?: 'auto' | 'png' | 'rox'; // Output format
248
+ includeName?: boolean; // Include filename in PNG metadata
249
+ includeFileList?: boolean; // Include file manifest in PNG
250
+ fileList?: Array<string | { name: string; size: number }>;
251
+ skipOptimization?: boolean; // Skip PNG optimization pass
252
+ onProgress?: (info: ProgressInfo) => void;
253
+ showProgress?: boolean;
254
+ verbose?: boolean;
255
+ }
256
+ ```
199
257
 
200
- Encodes data as RGB pixel values, optimized for screenshot-like appearance. Best balance of size and compatibility.
258
+ ### DecodeOptions
201
259
 
202
260
  ```typescript
203
- const png = await encodeBinaryToPng(data, { mode: 'screenshot' });
261
+ interface DecodeOptions {
262
+ passphrase?: string; // Decryption passphrase
263
+ outPath?: string; // Output directory for unpacked files
264
+ files?: string[]; // Extract only specific files from archive
265
+ onProgress?: (info: ProgressInfo) => void;
266
+ showProgress?: boolean;
267
+ verbose?: boolean;
268
+ }
204
269
  ```
205
270
 
206
- #### `compact` (Smallest)
207
-
208
- Minimal 1x1 PNG with data in custom chunk. Fastest and smallest.
271
+ ### DecodeResult
209
272
 
210
273
  ```typescript
211
- const png = await encodeBinaryToPng(data, { mode: 'compact' });
274
+ interface DecodeResult {
275
+ buf?: Buffer; // Decoded binary payload
276
+ meta?: { name?: string }; // Metadata (original filename)
277
+ files?: PackedFile[]; // Unpacked directory entries, if applicable
278
+ }
212
279
  ```
213
280
 
214
- #### `pixel`
281
+ ---
215
282
 
216
- Encodes data as RGB pixel values without screenshot optimization.
283
+ ## Encoding Modes
217
284
 
218
- ```typescript
219
- const png = await encodeBinaryToPng(data, { mode: 'pixel' });
220
- ```
285
+ | Mode | Description | Use Case |
286
+ |---|---|---|
287
+ | `screenshot` | Encodes data as RGB pixels in a standard PNG. The image looks like a gradient or noise pattern and survives re-uploads and social media processing. | Sharing on image-only platforms, bypassing file-type filters |
288
+ | `compact` | Minimal 1x1 PNG with data embedded in a custom ancillary chunk (`rXDT`). Produces the smallest possible output. | Programmatic use, archival, maximum compression ratio |
221
289
 
222
- #### `chunk`
290
+ ---
223
291
 
224
- Standard PNG with data in custom rXDT chunk.
292
+ ## Encryption
225
293
 
226
- ```typescript
227
- const png = await encodeBinaryToPng(data, { mode: 'chunk' });
228
- ```
294
+ Roxify supports two encryption methods:
229
295
 
230
- ## API Reference
296
+ | Method | Algorithm | Strength | Use Case |
297
+ |---|---|---|---|
298
+ | `aes` | AES-256-GCM with PBKDF2 (100,000 iterations) | Cryptographically secure, authenticated | Sensitive data, confidential documents |
299
+ | `xor` | XOR cipher with passphrase-derived key | Obfuscation only, not cryptographically secure | Casual deterrent against inspection |
231
300
 
232
- ### `encodeBinaryToPng(input, options)`
301
+ When `encrypt` is set to `auto` (the default when a passphrase is provided), AES is selected.
233
302
 
234
- Encodes binary data into a PNG image.
303
+ ---
235
304
 
236
- **Parameters:**
305
+ ## Performance Tuning
237
306
 
238
- - `input: Buffer` - The binary data to encode
239
- - `options?: EncodeOptions` - Encoding options
307
+ ### Compression Level
240
308
 
241
- **Returns:** `Promise<Buffer>` - The encoded PNG
309
+ The `compressionLevel` option (CLI: `-q`) controls the trade-off between speed and output size:
242
310
 
243
- **Options:**
311
+ | Level | Speed | Ratio | Recommendation |
312
+ |---|---|---|---|
313
+ | 0 | Fastest | Largest | Files over 100 MB, real-time workflows |
314
+ | 1 | Fast | Good | Default; general-purpose use |
315
+ | 5 | Moderate | Better | Archival of medium-sized datasets |
316
+ | 11 | Slowest | Smallest | Small files under 1 MB, long-term storage |
244
317
 
245
- ```typescript
246
- interface EncodeOptions {
247
- compression?: 'br' | 'none';
318
+ ### Native Module
248
319
 
249
- passphrase?: string;
320
+ The Rust native module provides 10--50x throughput improvement over the pure JavaScript fallback. It is loaded automatically when present. To verify availability:
250
321
 
251
- name?: string;
322
+ ```typescript
323
+ import { native } from 'roxify';
324
+ console.log('Native module loaded:', !!native);
325
+ ```
252
326
 
253
- mode?: 'compact' | 'chunk' | 'pixel' | 'screenshot';
327
+ If the native module is not found for the current platform, Roxify falls back to TypeScript transparently. No code changes are needed.
254
328
 
255
- encrypt?: 'auto' | 'aes' | 'xor' | 'none';
329
+ ### Zstd Dictionary
256
330
 
257
- output?: 'auto' | 'png' | 'rox';
331
+ For datasets consisting of many similar small files (e.g., JSON API responses, log entries), a Zstd dictionary can improve compression ratios by 20--40%:
258
332
 
259
- includeName?: boolean;
333
+ ```typescript
334
+ import { readFileSync } from 'fs';
260
335
 
261
- brQuality?: number;
262
- }
336
+ const dict = readFileSync('my-dictionary.zdict');
337
+ const png = await encodeBinaryToPng(data, { dict });
263
338
  ```
264
339
 
265
- ### `decodePngToBinary(pngBuf, options)`
340
+ ---
266
341
 
267
- Decodes a PNG image back to binary data.
342
+ ## Cross-Platform Support
268
343
 
269
- **Parameters:**
344
+ Roxify ships prebuilt native modules for the following targets:
270
345
 
271
- - `pngBuf: Buffer` - The PNG image to decode
272
- - `options?: DecodeOptions` - Decoding options
346
+ | Platform | Architecture | Binary Name |
347
+ |---|---|---|
348
+ | Linux | x86_64 | `libroxify_native-x86_64-unknown-linux-gnu.node` |
349
+ | macOS | x86_64 | `libroxify_native-x86_64-apple-darwin.node` |
350
+ | macOS | ARM64 (Apple Silicon) | `libroxify_native-aarch64-apple-darwin.node` |
351
+ | Windows | x86_64 | `roxify_native-x86_64-pc-windows-msvc.node` |
273
352
 
274
- **Returns:** `Promise<DecodeResult>` - The decoded data and metadata
353
+ The correct binary is resolved automatically at runtime. If no binary is found for the current platform, Roxify falls back silently to the pure JavaScript implementation.
275
354
 
276
- **Options:**
355
+ ### Building Native Modules for Specific Targets
277
356
 
278
- ```typescript
279
- interface DecodeOptions {
280
- passphrase?: string;
281
- }
357
+ ```bash
358
+ # Current platform
359
+ npm run build:native
360
+
361
+ # Specific platform
362
+ npm run build:native:linux
363
+ npm run build:native:macos-x64
364
+ npm run build:native:macos-arm
365
+ npm run build:native:windows
366
+
367
+ # All configured targets
368
+ npm run build:native:targets
282
369
  ```
283
370
 
284
- **Result:**
371
+ ---
285
372
 
286
- ```typescript
287
- interface DecodeResult {
288
- buf: Buffer;
373
+ ## Building from Source
289
374
 
290
- meta?: {
291
- name?: string;
292
- };
293
- }
294
- ```
375
+ ### Prerequisites
295
376
 
296
- ## Performance Tips
377
+ - Node.js 18 or later
378
+ - Rust 1.70 or later (install via [rustup](https://rustup.rs))
297
379
 
298
- ### For Large Files (>10 MB)
380
+ ### Commands
299
381
 
300
382
  ```bash
301
- # Use quality 0 for fastest encoding
302
- npx rox encode large.bin output.png -q 0
303
- ```
383
+ # Install dependencies
384
+ npm install
304
385
 
305
- ```typescript
306
- const png = await encodeBinaryToPng(largeFile, {
307
- mode: 'screenshot',
308
- brQuality: 0,
309
- });
386
+ # Build TypeScript only
387
+ npm run build
388
+
389
+ # Build native Rust module
390
+ npm run build:native
391
+
392
+ # Build everything (Rust + TypeScript + CLI binary)
393
+ npm run build:all
394
+
395
+ # Run the full test suite
396
+ npm test
310
397
  ```
311
398
 
312
- ### For Small Files (<1 MB)
399
+ ### Project Structure
313
400
 
314
- ```bash
315
- # Use quality 11 for best compression
316
- npx rox encode small.json output.png -q 11 -m compact
401
+ ```
402
+ roxify/
403
+ native/ Rust source code (N-API module and CLI binary)
404
+ src/ TypeScript source code (library and CLI entry point)
405
+ dist/ Compiled JavaScript output
406
+ test/ Test suite and benchmarks
407
+ docs/ Additional documentation
408
+ scripts/ Build, release, and CI helper scripts
317
409
  ```
318
410
 
319
- ```typescript
320
- const png = await encodeBinaryToPng(smallFile, {
321
- mode: 'compact',
322
- brQuality: 11,
323
- });
411
+ ---
412
+
413
+ ## Architecture
414
+
415
+ Roxify is a hybrid Rust and TypeScript module. The performance-critical paths -- compression, CRC computation, pixel scanning, encryption -- are implemented in Rust and exposed through N-API bindings. The TypeScript layer handles PNG construction, CLI argument parsing, and high-level orchestration.
416
+
417
+ ### Compression Pipeline
418
+
419
+ ```
420
+ Input --> Zstd Compress (multi-threaded, Rayon) --> AES-256-GCM Encrypt (optional) --> PNG Encode --> Output
324
421
  ```
325
422
 
326
- ### Benchmark Results
423
+ ### Decompression Pipeline
327
424
 
328
- File: 3.8 MB binary
425
+ ```
426
+ Input --> PNG Parse --> AES-256-GCM Decrypt (optional) --> Zstd Decompress --> Output
427
+ ```
329
428
 
330
- - **Quality 0**: ~500-800ms, output ~1.2 MB
331
- - **Quality 1** (default): ~1-2s, output ~800 KB
332
- - **Quality 5**: ~8-12s, output ~750 KB
333
- - **Quality 11**: ~20-30s, output ~720 KB
429
+ ### Rust Modules
430
+
431
+ | Module | Responsibility |
432
+ |---|---|
433
+ | `core.rs` | Pixel scanning, CRC32, Adler32, delta coding, Zstd compress/decompress |
434
+ | `encoder.rs` | PNG payload encoding with marker pixels and metadata chunks |
435
+ | `packer.rs` | Directory tree serialization and streaming deserialization |
436
+ | `crypto.rs` | AES-256-GCM encryption and PBKDF2 key derivation |
437
+ | `archive.rs` | Tar-based archiving with optional Zstd compression |
438
+ | `reconstitution.rs` | Screenshot detection and automatic crop to recover encoded data |
439
+ | `bwt.rs` | Parallel Burrows-Wheeler Transform |
440
+ | `rans.rs` | rANS (Asymmetric Numeral Systems) entropy coder |
441
+ | `hybrid.rs` | Block-based orchestration of BWT, context mixing, and rANS |
442
+ | `pool.rs` | Buffer pooling and zero-copy memory management |
443
+ | `image_utils.rs` | Image resizing, pixel format conversion, metadata extraction |
444
+ | `png_utils.rs` | Low-level PNG chunk read/write operations |
445
+ | `progress.rs` | Progress tracking for long-running compression/decompression |
446
+
447
+ ---
334
448
 
335
449
  ## Error Handling
336
450
 
451
+ Roxify throws descriptive errors for common failure modes:
452
+
337
453
  ```typescript
454
+ import { decodePngToBinary } from 'roxify';
455
+
338
456
  try {
339
- const result = await decodePngToBinary(encoded, {
457
+ const result = await decodePngToBinary(pngBuffer, {
340
458
  passphrase: 'wrong-password',
341
459
  });
342
460
  } catch (err) {
343
461
  if (err.message.includes('Incorrect passphrase')) {
344
- console.error('Wrong password!');
345
- } else if (err.message.includes('Invalid ROX format')) {
346
- console.error('Not a valid RoxCompressor PNG');
347
- } else {
348
- console.error('Decode failed:', err.message);
462
+ // Wrong decryption key
463
+ } else if (err.message.includes('not a valid PNG')) {
464
+ // Input is not a valid roxified PNG
465
+ } else if (err.message.includes('corrupted')) {
466
+ // Data integrity check failed
349
467
  }
350
468
  }
351
469
  ```
352
470
 
353
- ## Security
471
+ | Error | Cause |
472
+ |---|---|
473
+ | `Incorrect passphrase` | Wrong password provided for decryption |
474
+ | `not a valid PNG` | Input buffer is not a PNG or lacks Roxify markers |
475
+ | `Passphrase required` | File is encrypted but no passphrase was supplied |
476
+ | `Image too large to decode` | PNG dimensions exceed the in-process memory limit |
354
477
 
355
- - **AES-256-GCM**: Authenticated encryption with 100,000 PBKDF2 iterations
356
- - **XOR cipher**: Simple obfuscation (not cryptographically secure)
357
- - **No encryption**: Data is compressed but not encrypted
478
+ ---
358
479
 
359
- ⚠️ **Warning**: Use strong passphrases for sensitive data. The `xor` encryption mode is not secure and should only be used for obfuscation.
480
+ ## Security Considerations
360
481
 
361
- ## License
482
+ - **AES-256-GCM** provides authenticated encryption. Tampered ciphertext is detected and rejected.
483
+ - **PBKDF2** with 100,000 iterations is used for key derivation, making brute-force attacks computationally expensive.
484
+ - **XOR encryption** is not cryptographically secure. Use it only for casual obfuscation.
485
+ - Passphrases are never stored in the output file. There is no recovery mechanism for a lost passphrase.
486
+ - The PNG output does not visually reveal whether data is encrypted. An observer cannot distinguish an encrypted Roxify PNG from an unencrypted one by inspection.
362
487
 
363
- MIT © RoxCompressor
488
+ ---
364
489
 
365
490
  ## Contributing
366
491
 
367
- Contributions welcome! Please open an issue or PR on GitHub.
492
+ Contributions are welcome. Please open an issue to discuss proposed changes before submitting a pull request.
368
493
 
369
- ## Links
494
+ 1. Fork the repository
495
+ 2. Create a feature branch (`git checkout -b feature/my-change`)
496
+ 3. Run the test suite (`npm test`)
497
+ 4. Submit a pull request
370
498
 
371
- - [GitHub Repository](https://github.com/RoxasYTB/roxify)
372
- - [npm Package](https://www.npmjs.com/package/roxify)
373
- - [Report Issues](https://github.com/RoxasYTB/roxify/issues)
499
+ ---
374
500
 
375
- ## CI / Multi-platform builds
501
+ ## License
376
502
 
377
- This project runs continuous integration on Linux, Windows and macOS via GitHub Actions. Native modules are built on each platform and attached to the workflow (and release) as artifacts. On releases we also publish platform artifacts to GitHub Releases. For npm publishing, set the `NPM_TOKEN` secret in your repository settings to allow automated publishes on release.
503
+ MIT. See [LICENSE](LICENSE) for details.
504
+
505
+ ---
506
+
507
+ ## Links
508
+
509
+ - [npm Package](https://www.npmjs.com/package/roxify)
510
+ - [GitHub Repository](https://github.com/RoxasYTB/roxify)
511
+ - [Issue Tracker](https://github.com/RoxasYTB/roxify/issues)
512
+ - [CLI Documentation](./docs/CLI.md)
513
+ - [JavaScript SDK Reference](./docs/JAVASCRIPT_SDK.md)
514
+ - [Cross-Platform Build Guide](./docs/CROSS_PLATFORM.md)