roxify 1.2.4 → 1.2.5

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/dist/cli.js CHANGED
@@ -3,7 +3,7 @@ import cliProgress from 'cli-progress';
3
3
  import { mkdirSync, readFileSync, statSync, writeFileSync } from 'fs';
4
4
  import { basename, dirname, join, resolve } from 'path';
5
5
  import { DataFormatError, decodePngToBinary, encodeBinaryToPng, hasPassphraseInPng, IncorrectPassphraseError, listFilesInPng, PassphraseRequiredError, } from './index.js';
6
- import { packPaths, unpackBuffer } from './pack.js';
6
+ import { packPathsGenerator, unpackBuffer } from './pack.js';
7
7
  const VERSION = '1.2.4';
8
8
  function showHelp() {
9
9
  console.log(`
@@ -20,8 +20,7 @@ Commands:
20
20
 
21
21
  Options:
22
22
  -p, --passphrase <pass> Use passphrase (AES-256-GCM)
23
- -m, --mode <mode> Mode: compact|chunk|pixel|screenshot (default: screenshot)
24
- -q, --quality <0-11> Brotli quality (default: 11)
23
+ -m, --mode <mode> Mode: screenshot (default)
25
24
  -e, --encrypt <type> auto|aes|xor|none
26
25
  --no-compress Disable compression
27
26
  -o, --output <path> Output file path
@@ -79,11 +78,6 @@ function parseArgs(args) {
79
78
  i += 2;
80
79
  break;
81
80
  case 'm':
82
- parsed.mode = value;
83
- i += 2;
84
- break;
85
- case 'q':
86
- parsed.quality = parseInt(value, 10);
87
81
  i += 2;
88
82
  break;
89
83
  case 'e':
@@ -144,8 +138,6 @@ async function encodeCommand(args) {
144
138
  const resolvedOutput = parsed.output || outputPath || outputName;
145
139
  let options = {};
146
140
  try {
147
- let inputBuffer;
148
- let displayName;
149
141
  const encodeBar = new cliProgress.SingleBar({
150
142
  format: ' {bar} {percentage}% | {step} | {elapsed}s',
151
143
  }, cliProgress.Presets.shades_classic);
@@ -176,69 +168,63 @@ async function encodeCommand(args) {
176
168
  elapsed: String(Math.floor(elapsed / 1000)),
177
169
  });
178
170
  }, TICK_MS);
171
+ const mode = 'screenshot';
172
+ Object.assign(options, {
173
+ mode,
174
+ name: parsed.outputName || 'archive',
175
+ });
176
+ if (parsed.verbose)
177
+ options.verbose = true;
178
+ if (parsed.noCompress)
179
+ options.compression = 'none';
180
+ if (parsed.passphrase) {
181
+ options.passphrase = parsed.passphrase;
182
+ options.encrypt = parsed.encrypt || 'aes';
183
+ }
184
+ console.log(`Encoding to ${resolvedOutput} (Mode: ${mode})\n`);
185
+ let inputData;
186
+ let inputSizeVal = 0;
187
+ let displayName;
179
188
  let totalBytes = 0;
180
- let lastShownFile;
181
189
  const onProgress = (readBytes, total, currentFile) => {
182
190
  if (totalBytes === 0)
183
191
  totalBytes = total;
184
192
  const packPct = Math.floor((readBytes / totalBytes) * 25);
185
193
  targetPct = Math.max(targetPct, packPct);
186
- if (currentFile && currentFile !== lastShownFile) {
187
- lastShownFile = currentFile;
188
- }
189
194
  currentEncodeStep = currentFile
190
195
  ? `Reading files: ${currentFile}`
191
196
  : 'Reading files';
192
197
  };
193
198
  if (inputPaths.length > 1) {
194
199
  currentEncodeStep = 'Reading files';
195
- const packResult = packPaths(inputPaths, undefined, onProgress);
196
- inputBuffer = packResult.buf;
197
- console.log('');
198
- console.log(`Packed ${packResult.list.length} files -> ${(inputBuffer.length /
199
- 1024 /
200
- 1024).toFixed(2)} MB`);
200
+ const { index, stream, totalSize } = await packPathsGenerator(inputPaths, undefined, onProgress);
201
+ inputData = stream;
202
+ inputSizeVal = totalSize;
201
203
  displayName = parsed.outputName || 'archive';
202
204
  options.includeFileList = true;
203
- options.fileList = packResult.list;
205
+ options.fileList = index.map((e) => e.path);
204
206
  }
205
207
  else {
206
208
  const resolvedInput = resolvedInputs[0];
207
209
  const st = statSync(resolvedInput);
208
210
  if (st.isDirectory()) {
209
- console.log(`Packing directory...`);
210
211
  currentEncodeStep = 'Reading files';
211
- const packResult = packPaths([resolvedInput], dirname(resolvedInput), onProgress);
212
- inputBuffer = packResult.buf;
213
- console.log('');
214
- console.log(`Packed ${packResult.list.length} files -> ${(inputBuffer.length /
215
- 1024 /
216
- 1024).toFixed(2)} MB`);
212
+ const { index, stream, totalSize } = await packPathsGenerator([resolvedInput], dirname(resolvedInput), onProgress);
213
+ inputData = stream;
214
+ inputSizeVal = totalSize;
217
215
  displayName = parsed.outputName || basename(resolvedInput);
218
216
  options.includeFileList = true;
219
- options.fileList = packResult.list;
217
+ options.fileList = index.map((e) => e.path);
220
218
  }
221
219
  else {
222
- inputBuffer = readFileSync(resolvedInput);
223
- console.log('');
220
+ inputData = readFileSync(resolvedInput);
221
+ inputSizeVal = inputData.length;
224
222
  displayName = basename(resolvedInput);
225
223
  options.includeFileList = true;
226
224
  options.fileList = [basename(resolvedInput)];
227
225
  }
228
226
  }
229
- Object.assign(options, {
230
- mode: parsed.mode || 'screenshot',
231
- name: displayName,
232
- brQuality: parsed.quality !== undefined ? parsed.quality : 11,
233
- });
234
- if (parsed.noCompress) {
235
- options.compression = 'none';
236
- }
237
- if (parsed.passphrase) {
238
- options.passphrase = parsed.passphrase;
239
- options.encrypt = parsed.encrypt || 'aes';
240
- }
241
- console.log(`Encoding ${displayName} -> ${resolvedOutput}\n`);
227
+ options.name = displayName;
242
228
  options.onProgress = (info) => {
243
229
  let stepLabel = 'Processing';
244
230
  let pct = 0;
@@ -291,6 +277,17 @@ async function encodeCommand(args) {
291
277
  targetPct = Math.max(targetPct, pct);
292
278
  currentEncodeStep = stepLabel;
293
279
  };
280
+ let inputBuffer;
281
+ if (typeof inputData[Symbol.asyncIterator] === 'function') {
282
+ const chunks = [];
283
+ for await (const chunk of inputData) {
284
+ chunks.push(chunk);
285
+ }
286
+ inputBuffer = Buffer.concat(chunks);
287
+ }
288
+ else {
289
+ inputBuffer = inputData;
290
+ }
294
291
  const output = await encodeBinaryToPng(inputBuffer, options);
295
292
  const encodeTime = Date.now() - startEncode;
296
293
  clearInterval(encodeHeartbeat);
@@ -303,8 +300,8 @@ async function encodeCommand(args) {
303
300
  }
304
301
  writeFileSync(resolvedOutput, output);
305
302
  const outputSize = (output.length / 1024 / 1024).toFixed(2);
306
- const inputSize = (inputBuffer.length / 1024 / 1024).toFixed(2);
307
- const ratio = ((output.length / inputBuffer.length) * 100).toFixed(1);
303
+ const inputSize = (inputSizeVal / 1024 / 1024).toFixed(2);
304
+ const ratio = ((output.length / inputSizeVal) * 100).toFixed(1);
308
305
  console.log(`\nSuccess!`);
309
306
  console.log(` Input: ${inputSize} MB`);
310
307
  console.log(` Output: ${outputSize} MB (${ratio}% of original)`);
@@ -483,8 +480,7 @@ async function decodeCommand(args) {
483
480
  (err.message.includes('decompression failed') ||
484
481
  err.message.includes('missing ROX1') ||
485
482
  err.message.includes('Pixel payload truncated') ||
486
- err.message.includes('Marker START not found') ||
487
- err.message.includes('Brotli decompression failed')))) {
483
+ err.message.includes('Marker START not found')))) {
488
484
  console.log(' ');
489
485
  console.error('Data corrupted or unsupported format. Use --verbose for details.');
490
486
  }
package/dist/index.d.ts CHANGED
@@ -1,134 +1,13 @@
1
- /// <reference types="node" />
2
- /// <reference types="node" />
3
- import { PackedFile } from './pack.js';
4
- export declare class PassphraseRequiredError extends Error {
5
- constructor(message?: string);
6
- }
7
- export declare class IncorrectPassphraseError extends Error {
8
- constructor(message?: string);
9
- }
10
- export declare class DataFormatError extends Error {
11
- constructor(message?: string);
12
- }
13
- /**
14
- * Options for encoding binary data into PNG format.
15
- * @public
16
- */
17
- export interface EncodeOptions {
18
- compression?: 'zstd';
19
- passphrase?: string;
20
- name?: string;
21
- mode?: 'compact' | 'pixel' | 'screenshot';
22
- encrypt?: 'auto' | 'aes' | 'xor' | 'none';
23
- _skipAuto?: boolean;
24
- output?: 'auto' | 'png' | 'rox';
25
- includeName?: boolean;
26
- includeFileList?: boolean;
27
- fileList?: string[];
28
- brQuality?: number;
29
- onProgress?: (info: {
30
- phase: string;
31
- loaded?: number;
32
- total?: number;
33
- }) => void;
34
- showProgress?: boolean;
35
- }
36
- /**
37
- * Result of decoding a PNG back to binary data.
38
- * @public
39
- */
40
- export interface DecodeResult {
41
- buf?: Buffer;
42
- meta?: {
43
- name?: string;
44
- };
45
- files?: PackedFile[];
46
- }
47
- export declare function optimizePngBuffer(pngBuf: Buffer, fast?: boolean): Promise<Buffer>;
48
- /**
49
- * Path to write decoded output directly to disk (streamed) to avoid high memory usage.
50
- */
51
- export interface DecodeOptions {
52
- /**
53
- * Passphrase for encrypted inputs.
54
- */
55
- passphrase?: string;
56
- /**
57
- * Directory to save debug images (doubled.png, reconstructed.png).
58
- */
59
- debugDir?: string;
60
- /**
61
- * Path to write decoded output directly to disk (streamed) to avoid high memory usage.
62
- */
63
- outPath?: string;
64
- /**
65
- * List of files to extract selectively from archives.
66
- */
67
- files?: string[];
68
- /**
69
- * Progress callback for decoding phases.
70
- */
71
- onProgress?: (info: {
72
- phase: string;
73
- loaded?: number;
74
- total?: number;
75
- }) => void;
76
- /**
77
- * Whether to display a progress bar in the console.
78
- * @defaultValue `false`
79
- */
80
- showProgress?: boolean;
81
- }
82
- export declare function cropAndReconstitute(input: Buffer, debugDir?: string): Promise<Buffer>;
83
- /**
84
- * Encode a Buffer into a PNG wrapper. Supports optional compression and
85
- * encryption. Defaults are chosen for a good balance between speed and size.
86
- *
87
- * @param input - Data to encode
88
- * @param opts - Encoding options
89
- * @public
90
- * @example
91
- * ```typescript
92
- * import { readFileSync, writeFileSync } from 'fs';
93
- * import { encodeBinaryToPng } from 'roxify';
94
- *
95
- * const fileName = 'input.bin'; //Path of your input file here
96
- * const inputBuffer = readFileSync(fileName);
97
- * const pngBuffer = await encodeBinaryToPng(inputBuffer, {
98
- * name: fileName,
99
- * });
100
- * writeFileSync('output.png', pngBuffer);
101
-
102
- * ```
103
- */
104
- export declare function encodeBinaryToPng(input: Buffer, opts?: EncodeOptions): Promise<Buffer>;
105
- /**
106
- * Decode a PNG produced by this library back to the original Buffer.
107
- * Supports the ROX binary format, rXDT chunk, and pixel encodings.
108
- *
109
- * @param pngBuf - PNG data
110
- * @param opts - Options (passphrase for encrypted inputs)
111
- * @public
112
- * @example
113
- * import { readFileSync, writeFileSync } from 'fs';
114
- * import { decodePngToBinary } from 'roxify';
115
- *
116
- * const pngFromDisk = readFileSync('output.png'); //Path of the encoded PNG here
117
- * const { buf, meta } = await decodePngToBinary(pngFromDisk);
118
- * writeFileSync(meta?.name ?? 'decoded.txt', buf);
119
- */
120
- export declare function decodePngToBinary(pngBuf: Buffer, opts?: DecodeOptions): Promise<DecodeResult>;
1
+ export * from './utils/constants.js';
2
+ export * from './utils/crc.js';
3
+ export * from './utils/decoder.js';
4
+ export * from './utils/encoder.js';
5
+ export * from './utils/errors.js';
6
+ export * from './utils/helpers.js';
7
+ export * from './utils/inspection.js';
8
+ export * from './utils/optimization.js';
9
+ export * from './utils/reconstitution.js';
10
+ export * from './utils/types.js';
11
+ export * from './utils/zstd.js';
121
12
  export { decodeMinPng, encodeMinPng } from './minpng.js';
122
13
  export { packPaths, unpackBuffer } from './pack.js';
123
- /**
124
- * List files in a Rox PNG archive without decoding the full payload.
125
- * Returns the file list if available, otherwise null.
126
- * @param pngBuf - PNG data
127
- * @public
128
- */
129
- export declare function listFilesInPng(pngBuf: Buffer): Promise<string[] | null>;
130
- /**
131
- * Detect if a PNG/ROX buffer contains an encrypted payload (requires passphrase)
132
- * Returns true if encryption flag indicates AES or XOR.
133
- */
134
- export declare function hasPassphraseInPng(pngBuf: Buffer): Promise<boolean>;