zstdify-cli 1.0.2 → 1.1.0

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
@@ -7,6 +7,14 @@
7
7
 
8
8
  Command-line tool for compressing and decompressing files with zstd. Built on the [zstdify](https://www.npmjs.com/package/zstdify) package (pure TypeScript, no native dependencies).
9
9
 
10
+ ## Features
11
+
12
+ - **Pure JS/TS zstd CLI**: No native addon dependency, portable across Node.js environments.
13
+ - **Compression + extraction workflows**: Simple file-to-file commands with level/checksum controls.
14
+ - **Interop-focused**: Files produced by `zstdify` are decoded by the official `zstd` CLI, and `zstd` output is decoded by `zstdify`.
15
+ - **Robust command UX**: Clear subcommands, aliases, and actionable error messages.
16
+ - **Optional dictionary support**: Train dictionaries from samples and use them with `compress`/`extract` when needed.
17
+
10
18
  ## Installation
11
19
 
12
20
  ```sh
@@ -19,6 +27,7 @@ pnpm add -g zstdify-cli
19
27
  | ------- | ----------- |
20
28
  | `zstdify compress <input> <output>` | Compress a file with zstd |
21
29
  | `zstdify extract <input> <output>` | Decompress a zstd-compressed file |
30
+ | `zstdify dict train <output> --input <path>...` | Train a dictionary from sample files/directories |
22
31
 
23
32
  Aliases: `compress` / `c`, `extract` / `x`.
24
33
 
@@ -26,6 +35,23 @@ Aliases: `compress` / `c`, `extract` / `x`.
26
35
 
27
36
  - `--level`, `-l` — Compression level (0=raw, 1+=RLE, 2+=compressed blocks)
28
37
  - `--checksum` — Add content checksum to the frame
38
+ - `--dict` — Dictionary file path to use for compression
39
+ - `--dictID` — Dictionary ID to store in the frame header
40
+ - `--noDictId` — Do not write dictID in frame header
41
+
42
+ ### Options (extract)
43
+
44
+ - `--dict` — Dictionary file path for dictionary-compressed input
45
+ - `--dictID` — Expected dictionary ID for validation
46
+
47
+ ### Options (dict train)
48
+
49
+ - `--recursive` — Recursively collect files from input directories
50
+ - `--maxSamples` — Maximum number of sample files to load
51
+ - `--algorithm` — `fastcover`, `cover`, or `legacy`
52
+ - `--maxdict` — Maximum dictionary size in bytes
53
+ - `--dictID` — Optional dictionary ID metadata setting
54
+ - Advanced tuning knobs: `--k`, `--d`, `--steps`, `--split`, `--f`, `--accel`, `--selectivity`, `--shrink`
29
55
 
30
56
  ## Examples
31
57
 
@@ -33,8 +59,27 @@ Aliases: `compress` / `c`, `extract` / `x`.
33
59
  zstdify compress input.txt output.zst
34
60
  zstdify compress input.txt output.zst --level 2
35
61
  zstdify extract output.zst restored.txt
62
+ zstdify dict train my.dict --input samples/ --recursive --maxdict 2048
63
+ zstdify compress input.txt output.zst --dict my.dict --dictID 42
64
+ zstdify extract output.zst restored.txt --dict my.dict --dictID 42
36
65
  ```
37
66
 
67
+ ## How we validate
68
+
69
+ CLI behavior is covered by automated tests (`pnpm vitest`, including `packages/cli-tests`):
70
+
71
+ - **CLI round-trip**: `zstdify compress` -> `zstdify extract` restores original file bytes.
72
+ - **Core flags and aliases**: Compression levels, checksums, and command aliases are exercised.
73
+ - **Differential interop with official zstd CLI**:
74
+ - `zstd` output is extracted by `zstdify-cli`.
75
+ - `zstdify-cli` output is decompressed by `zstd`.
76
+ - These checks run across standard (non-dictionary) workflows.
77
+ - **Dictionary interop coverage**:
78
+ - `zstd -D dict` compressed streams are extracted by `zstdify-cli --dict`.
79
+ - `zstdify-cli --dict` compressed streams are decompressed by `zstd -D dict`.
80
+ - Coverage includes both zstd-trained and zstdify-trained dictionaries.
81
+ - **Error paths**: Missing files and invalid inputs produce non-zero exits and actionable messages.
82
+
38
83
  # License
39
84
 
40
85
  MIT
@@ -6,4 +6,10 @@ export declare const command: import("yargs-file-commands").DefineCommandResult<
6
6
  level: number | undefined;
7
7
  } & {
8
8
  checksum: boolean;
9
+ } & {
10
+ dict: string | undefined;
11
+ } & {
12
+ dictID: number | undefined;
13
+ } & {
14
+ noDictId: boolean;
9
15
  }>;
@@ -26,16 +26,40 @@ export const command = defineCommand({
26
26
  describe: 'Add content checksum to the frame',
27
27
  type: 'boolean',
28
28
  default: false,
29
+ })
30
+ .option('dict', {
31
+ describe: 'Dictionary file path to use for compression',
32
+ type: 'string',
33
+ })
34
+ .option('dictID', {
35
+ describe: 'Dictionary ID to store in frame header',
36
+ type: 'number',
37
+ })
38
+ .option('noDictId', {
39
+ describe: "Don't write dictID into frame header",
40
+ type: 'boolean',
41
+ default: false,
29
42
  }),
30
43
  handler: async (argv) => {
31
- const { input, output, level, checksum } = argv;
44
+ const { input, output, level, checksum, dict, dictID, noDictId } = argv;
32
45
  if (!fs.existsSync(input)) {
33
46
  console.error(`Error: Input file not found: ${input}`);
34
47
  process.exit(1);
35
48
  }
49
+ if (dict && !fs.existsSync(dict)) {
50
+ console.error(`Error: Dictionary file not found: ${dict}`);
51
+ process.exit(1);
52
+ }
36
53
  try {
37
54
  const inputBuf = fs.readFileSync(input);
38
55
  const data = new Uint8Array(inputBuf.buffer, inputBuf.byteOffset, inputBuf.byteLength);
56
+ const dictionary = dict
57
+ ? (() => {
58
+ const dictBuf = fs.readFileSync(dict);
59
+ const bytes = new Uint8Array(dictBuf.buffer, dictBuf.byteOffset, dictBuf.byteLength);
60
+ return dictID !== undefined ? { bytes, id: dictID } : bytes;
61
+ })()
62
+ : undefined;
39
63
  const outDir = path.dirname(output);
40
64
  if (outDir) {
41
65
  fs.mkdirSync(outDir, { recursive: true });
@@ -43,6 +67,8 @@ export const command = defineCommand({
43
67
  const result = compress(data, {
44
68
  level,
45
69
  checksum,
70
+ dictionary,
71
+ noDictId,
46
72
  });
47
73
  fs.writeFileSync(output, result);
48
74
  console.log(`Compressed ${input} -> ${output}`);
@@ -1 +1 @@
1
- {"version":3,"file":"compress.js","sourceRoot":"","sources":["../../src/commands/compress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,MAAM,CAAC,MAAM,OAAO,GAAG,aAAa,CAAC;IACnC,OAAO,EAAE,2BAA2B;IACpC,QAAQ,EAAE,2BAA2B;IACrC,OAAO,EAAE,CAAC,GAAG,CAAC;IACd,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CACjB,KAAK;SACF,UAAU,CAAC,OAAO,EAAE;QACnB,QAAQ,EAAE,iBAAiB;QAC3B,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,IAAI;KACnB,CAAC;SACD,UAAU,CAAC,QAAQ,EAAE;QACpB,QAAQ,EAAE,gCAAgC;QAC1C,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,IAAI;KACnB,CAAC;SACD,MAAM,CAAC,OAAO,EAAE;QACf,QAAQ,EAAE,yDAAyD;QACnE,IAAI,EAAE,QAAQ;QACd,KAAK,EAAE,GAAG;KACX,CAAC;SACD,MAAM,CAAC,UAAU,EAAE;QAClB,QAAQ,EAAE,mCAAmC;QAC7C,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,KAAK;KACf,CAAC;IACN,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC;QACvB,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;QAEhD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,CAAC,KAAK,CAAC,gCAAgC,KAAK,EAAE,CAAC,CAAC;YACvD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;YACxC,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;YAEvF,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YACpC,IAAI,MAAM,EAAE,CAAC;gBACX,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5C,CAAC;YAED,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE;gBAC5B,KAAK;gBACL,QAAQ;aACT,CAAC,CAAC;YACH,EAAE,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACjC,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,OAAO,MAAM,EAAE,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YAC3F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IAAA,CACF;CACF,CAAC,CAAC"}
1
+ {"version":3,"file":"compress.js","sourceRoot":"","sources":["../../src/commands/compress.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ export declare const command: import("yargs-file-commands").DefineCommandResult<{}, {
2
+ output: string;
3
+ } & {
4
+ input: string[];
5
+ } & {
6
+ recursive: boolean;
7
+ } & {
8
+ maxSamples: number;
9
+ } & {
10
+ algorithm: string;
11
+ } & {
12
+ maxdict: number | undefined;
13
+ } & {
14
+ dictID: number | undefined;
15
+ } & {
16
+ k: number | undefined;
17
+ } & {
18
+ d: number | undefined;
19
+ } & {
20
+ steps: number | undefined;
21
+ } & {
22
+ split: number | undefined;
23
+ } & {
24
+ f: number | undefined;
25
+ } & {
26
+ accel: number | undefined;
27
+ } & {
28
+ selectivity: number | undefined;
29
+ } & {
30
+ shrink: unknown;
31
+ }>;
@@ -0,0 +1,129 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { defineCommand } from 'yargs-file-commands';
4
+ import { generateDictionary } from 'zstdify';
5
+ function collectFiles(inputPath, recursive, out) {
6
+ const stat = fs.statSync(inputPath);
7
+ if (stat.isFile()) {
8
+ out.push(inputPath);
9
+ return;
10
+ }
11
+ if (!stat.isDirectory()) {
12
+ return;
13
+ }
14
+ const entries = fs.readdirSync(inputPath, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
15
+ for (const entry of entries) {
16
+ const fullPath = path.join(inputPath, entry.name);
17
+ if (entry.isFile()) {
18
+ out.push(fullPath);
19
+ }
20
+ else if (entry.isDirectory() && recursive) {
21
+ collectFiles(fullPath, recursive, out);
22
+ }
23
+ }
24
+ }
25
+ export const command = defineCommand({
26
+ command: 'dict train <output>',
27
+ describe: 'Train and write a dictionary from sample files',
28
+ builder: (yargs) => yargs
29
+ .positional('output', {
30
+ describe: 'Output dictionary file path',
31
+ type: 'string',
32
+ demandOption: true,
33
+ })
34
+ .option('input', {
35
+ describe: 'Input sample file or directory path (repeat for multiple)',
36
+ type: 'string',
37
+ array: true,
38
+ alias: 'i',
39
+ demandOption: true,
40
+ })
41
+ .option('recursive', {
42
+ describe: 'Recursively read files inside input directories',
43
+ type: 'boolean',
44
+ default: false,
45
+ })
46
+ .option('maxSamples', {
47
+ describe: 'Maximum number of sample files to load',
48
+ type: 'number',
49
+ default: 10_000,
50
+ })
51
+ .option('algorithm', {
52
+ describe: 'Training algorithm style',
53
+ choices: ['fastcover', 'cover', 'legacy'],
54
+ default: 'fastcover',
55
+ })
56
+ .option('maxdict', {
57
+ describe: 'Maximum dictionary size in bytes',
58
+ type: 'number',
59
+ })
60
+ .option('dictID', {
61
+ describe: 'Dictionary ID value (for metadata parity with zstd)',
62
+ type: 'number',
63
+ })
64
+ .option('k', { type: 'number', describe: 'Candidate segment size' })
65
+ .option('d', { type: 'number', describe: 'Distance step between candidate probes' })
66
+ .option('steps', { type: 'number', describe: 'Score refinement passes' })
67
+ .option('split', { type: 'number', describe: 'Percent of each sample to use (1-100)' })
68
+ .option('f', { type: 'number', describe: 'fastcover-style score multiplier' })
69
+ .option('accel', { type: 'number', describe: 'Probe stride accelerator (1-10)' })
70
+ .option('selectivity', { type: 'number', describe: 'legacy-style density control (1-10)' })
71
+ .option('shrink', {
72
+ describe: 'Optional shrink pass, true or numeric factor',
73
+ }),
74
+ handler: async (argv) => {
75
+ const { output, input, recursive, maxSamples, algorithm, maxdict, dictID, k, d, steps, split, f, accel, selectivity, shrink, } = argv;
76
+ const inputPaths = input ?? [];
77
+ const files = [];
78
+ for (const inputPath of inputPaths) {
79
+ if (!fs.existsSync(inputPath)) {
80
+ console.error(`Error: Input path not found: ${inputPath}`);
81
+ process.exit(1);
82
+ }
83
+ collectFiles(inputPath, recursive, files);
84
+ if (files.length >= maxSamples)
85
+ break;
86
+ }
87
+ if (files.length === 0) {
88
+ console.error('Error: No sample files found for dictionary training');
89
+ process.exit(1);
90
+ }
91
+ const selectedFiles = files.slice(0, maxSamples);
92
+ try {
93
+ const samples = selectedFiles
94
+ .map((filePath) => {
95
+ const buf = fs.readFileSync(filePath);
96
+ return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
97
+ })
98
+ .filter((sample) => sample.length > 0);
99
+ if (samples.length === 0) {
100
+ console.error('Error: No non-empty sample files found');
101
+ process.exit(1);
102
+ }
103
+ const dictionary = generateDictionary(samples, {
104
+ algorithm: algorithm,
105
+ maxDictSize: maxdict,
106
+ dictId: dictID,
107
+ k,
108
+ d,
109
+ steps,
110
+ split,
111
+ f,
112
+ accel,
113
+ selectivity,
114
+ shrink: typeof shrink === 'string' ? Number(shrink) : shrink,
115
+ });
116
+ const outDir = path.dirname(output);
117
+ if (outDir) {
118
+ fs.mkdirSync(outDir, { recursive: true });
119
+ }
120
+ fs.writeFileSync(output, dictionary);
121
+ console.log(`Trained dictionary (${dictionary.length} bytes) -> ${output}`);
122
+ }
123
+ catch (error) {
124
+ console.error(`Error during dictionary training:`, error instanceof Error ? error.message : error);
125
+ process.exit(1);
126
+ }
127
+ },
128
+ });
129
+ //# sourceMappingURL=dict.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dict.js","sourceRoot":"","sources":["../../src/commands/dict.ts"],"names":[],"mappings":"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"}
@@ -2,4 +2,8 @@ export declare const command: import("yargs-file-commands").DefineCommandResult<
2
2
  input: string;
3
3
  } & {
4
4
  output: string;
5
+ } & {
6
+ dict: string | undefined;
7
+ } & {
8
+ dictID: number | undefined;
5
9
  }>;
@@ -16,21 +16,40 @@ export const command = defineCommand({
16
16
  describe: 'Output file path',
17
17
  type: 'string',
18
18
  demandOption: true,
19
+ })
20
+ .option('dict', {
21
+ describe: 'Dictionary file path for dictionary-compressed input',
22
+ type: 'string',
23
+ })
24
+ .option('dictID', {
25
+ describe: 'Expected dictionary ID for validation',
26
+ type: 'number',
19
27
  }),
20
28
  handler: async (argv) => {
21
- const { input, output } = argv;
29
+ const { input, output, dict, dictID } = argv;
22
30
  if (!fs.existsSync(input)) {
23
31
  console.error(`Error: Input file not found: ${input}`);
24
32
  process.exit(1);
25
33
  }
34
+ if (dict && !fs.existsSync(dict)) {
35
+ console.error(`Error: Dictionary file not found: ${dict}`);
36
+ process.exit(1);
37
+ }
26
38
  try {
27
39
  const inputBuf = fs.readFileSync(input);
28
40
  const data = new Uint8Array(inputBuf.buffer, inputBuf.byteOffset, inputBuf.byteLength);
41
+ const dictionary = dict
42
+ ? (() => {
43
+ const dictBuf = fs.readFileSync(dict);
44
+ const bytes = new Uint8Array(dictBuf.buffer, dictBuf.byteOffset, dictBuf.byteLength);
45
+ return dictID !== undefined ? { bytes, id: dictID } : bytes;
46
+ })()
47
+ : undefined;
29
48
  const outDir = path.dirname(output);
30
49
  if (outDir) {
31
50
  fs.mkdirSync(outDir, { recursive: true });
32
51
  }
33
- const result = decompress(data);
52
+ const result = decompress(data, dictionary ? { dictionary } : undefined);
34
53
  fs.writeFileSync(output, result);
35
54
  console.log(`Decompressed ${input} -> ${output}`);
36
55
  }
@@ -1 +1 @@
1
- {"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/commands/extract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,MAAM,CAAC,MAAM,OAAO,GAAG,aAAa,CAAC;IACnC,OAAO,EAAE,0BAA0B;IACnC,QAAQ,EAAE,mCAAmC;IAC7C,OAAO,EAAE,CAAC,GAAG,CAAC;IACd,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CACjB,KAAK;SACF,UAAU,CAAC,OAAO,EAAE;QACnB,QAAQ,EAAE,4BAA4B;QACtC,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,IAAI;KACnB,CAAC;SACD,UAAU,CAAC,QAAQ,EAAE;QACpB,QAAQ,EAAE,kBAAkB;QAC5B,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,IAAI;KACnB,CAAC;IACN,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC;QACvB,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;QAE/B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,CAAC,KAAK,CAAC,gCAAgC,KAAK,EAAE,CAAC,CAAC;YACvD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;YACxC,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;YAEvF,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YACpC,IAAI,MAAM,EAAE,CAAC;gBACX,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5C,CAAC;YAED,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;YAChC,EAAE,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACjC,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,OAAO,MAAM,EAAE,CAAC,CAAC;QACpD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YAC7F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IAAA,CACF;CACF,CAAC,CAAC"}
1
+ {"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/commands/extract.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zstdify-cli",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "type": "module",
5
5
  "description": "CLI for zstd compression and decompression using zstdify",
6
6
  "license": "MIT",
@@ -17,7 +17,7 @@
17
17
  "dependencies": {
18
18
  "yargs": "^17.7.2",
19
19
  "yargs-file-commands": "^1.2.2",
20
- "zstdify": "^1.0.2"
20
+ "zstdify": "^1.1.0"
21
21
  },
22
22
  "devDependencies": {
23
23
  "@types/node": "^24",