zstdify 1.0.2 → 1.1.1
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 +34 -2
- package/dist/compress.d.ts +5 -0
- package/dist/compress.js +13 -1
- package/dist/compress.js.map +1 -1
- package/dist/dictionary/generateDictionary.d.ts +59 -0
- package/dist/dictionary/generateDictionary.js +187 -0
- package/dist/dictionary/generateDictionary.js.map +1 -0
- package/dist/encode/frameWriter.d.ts +1 -1
- package/dist/encode/frameWriter.js +26 -1
- package/dist/encode/frameWriter.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/logo.webp +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
[![Tests][tests-badge]][tests-url]
|
|
6
6
|
[![Coverage][coverage-badge]][coverage-url]
|
|
7
7
|
|
|
8
|
+

|
|
9
|
+
|
|
8
10
|
Pure JavaScript/TypeScript zstd compression/decompression library. No native dependencies, works in Node.js and browsers.
|
|
9
11
|
|
|
10
12
|
## Features
|
|
@@ -19,6 +21,10 @@ Pure JavaScript/TypeScript zstd compression/decompression library. No native dep
|
|
|
19
21
|
- Raw blocks, RLE blocks, and compressed blocks.
|
|
20
22
|
- Compression-level driven behavior with automatic raw fallback when compressed output is not smaller.
|
|
21
23
|
- Optional frame content checksums.
|
|
24
|
+
- Optional dictionary-aware frame headers (`dictID`) for dictionary workflows.
|
|
25
|
+
- **Dictionary generation**:
|
|
26
|
+
- Pure TypeScript dictionary training from sample payloads.
|
|
27
|
+
- Zstd-inspired training options (`fastcover`/`cover`/`legacy` style knobs).
|
|
22
28
|
- **Interop-focused**: `zstdify` output is decoded by the official `zstd` CLI, and `zstd` CLI output is decoded by `zstdify`.
|
|
23
29
|
- **Extensively tested**:
|
|
24
30
|
- Round-trip and property-based tests.
|
|
@@ -39,8 +45,29 @@ const restored = decompress(compressed);
|
|
|
39
45
|
|
|
40
46
|
## API
|
|
41
47
|
|
|
42
|
-
- `compress(input: Uint8Array, options?: { level?: number; checksum?: boolean }): Uint8Array`
|
|
48
|
+
- `compress(input: Uint8Array, options?: { level?: number; checksum?: boolean; dictionary?: Uint8Array | { bytes: Uint8Array; id?: number }; noDictId?: boolean }): Uint8Array`
|
|
43
49
|
- `decompress(input: Uint8Array, options?: { maxSize?: number; dictionary?: Uint8Array | { bytes: Uint8Array; id?: number } }): Uint8Array`
|
|
50
|
+
- `generateDictionary(samples: Uint8Array[], options?: { maxDictSize?: number; dictId?: number; algorithm?: "fastcover" | "cover" | "legacy"; k?: number; d?: number; steps?: number; split?: number; f?: number; accel?: number; selectivity?: number; shrink?: boolean | number }): Uint8Array`
|
|
51
|
+
|
|
52
|
+
Dictionary generation outputs a raw-content dictionary. If you want a specific `dictID` written into compressed frames, pass it to `compress()` via `dictionary: { bytes, id }`.
|
|
53
|
+
|
|
54
|
+
### Dictionary workflow example
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import { compress, decompress, generateDictionary } from 'zstdify';
|
|
58
|
+
|
|
59
|
+
const encoder = new TextEncoder();
|
|
60
|
+
const samples = [
|
|
61
|
+
encoder.encode('alpha beta gamma delta'),
|
|
62
|
+
encoder.encode('header vertex texture normal index'),
|
|
63
|
+
encoder.encode('offset match literal sequence table'),
|
|
64
|
+
];
|
|
65
|
+
const dictionary = generateDictionary(samples, { maxDictSize: 2048, algorithm: 'fastcover' });
|
|
66
|
+
|
|
67
|
+
const payload = encoder.encode('header vertex texture offset match literal');
|
|
68
|
+
const compressed = compress(payload, { dictionary: { bytes: dictionary, id: 42 } });
|
|
69
|
+
const restored = decompress(compressed, { dictionary: { bytes: dictionary, id: 42 } });
|
|
70
|
+
```
|
|
44
71
|
|
|
45
72
|
## CLI Tool
|
|
46
73
|
|
|
@@ -72,7 +99,7 @@ All of the following run as part of the test suite (`pnpm test` / `pnpm vitest`)
|
|
|
72
99
|
|
|
73
100
|
- **Round-trip**: `decompress(compress(x)) === x` for a variety of payloads and levels, plus property-based tests with [fast-check](https://fast-check.dev/).
|
|
74
101
|
- **Conformance fixtures**: Pre-generated `.zst` files from the official zstd CLI (legacy fixtures and a committed decodecorpus-style **corpus** with manifest); we decompress and compare. See [packages/zstdify-tests/fixtures/README.md](packages/zstdify-tests/fixtures/README.md).
|
|
75
|
-
- **Differential (zstd ↔ zstdify)**:
|
|
102
|
+
- **Differential (zstd ↔ zstdify)**: We test zstd compress → zstdify decompress and zstdify compress → zstd decompress across payloads and levels.
|
|
76
103
|
- **Corruption**: Truncation, checksum mismatch, invalid header bits, and related error paths.
|
|
77
104
|
- **Compression regression**: Compressed sizes for fixed payloads are checked against golden values (ratio stability).
|
|
78
105
|
- **Decompress robustness**: Each corpus fixture is decompressed in its own test (one test per file), so the suite tracks decompress behavior per input. See [upstream zstd TESTING.md](https://github.com/facebook/zstd/blob/dev/TESTING.md) for comparison.
|
|
@@ -93,6 +120,11 @@ pnpm make-release:cli
|
|
|
93
120
|
- `packages/cli` - CLI tool (`zstdify-cli` on npm)
|
|
94
121
|
- `packages/cli-tests` - Tests of the CLI tool
|
|
95
122
|
|
|
123
|
+
## Acknowledgements
|
|
124
|
+
|
|
125
|
+
This project is made possible by the original [zstd](https://github.com/facebook/zstd) project by Meta and its contributors.
|
|
126
|
+
The monorepo, project, and CLI structure were bootstrapped from [hdrify](https://github.com/bhouston/hdrify), which made this project much easier to build.
|
|
127
|
+
|
|
96
128
|
# License
|
|
97
129
|
|
|
98
130
|
MIT
|
package/dist/compress.d.ts
CHANGED
|
@@ -5,5 +5,10 @@
|
|
|
5
5
|
export type CompressOptions = {
|
|
6
6
|
level?: number;
|
|
7
7
|
checksum?: boolean;
|
|
8
|
+
dictionary?: Uint8Array | {
|
|
9
|
+
bytes: Uint8Array;
|
|
10
|
+
id?: number;
|
|
11
|
+
};
|
|
12
|
+
noDictId?: boolean;
|
|
8
13
|
};
|
|
9
14
|
export declare function compress(input: Uint8Array, options?: CompressOptions): Uint8Array;
|
package/dist/compress.js
CHANGED
|
@@ -2,17 +2,29 @@
|
|
|
2
2
|
* Compress input data using zstd.
|
|
3
3
|
* Level 0: raw blocks only (no compression, fast).
|
|
4
4
|
*/
|
|
5
|
+
import { normalizeDecoderDictionary } from './dictionary/decoderDictionary.js';
|
|
5
6
|
import { writeRawBlock, writeRLEBlock } from './encode/blockWriter.js';
|
|
6
7
|
import { buildCompressedBlockPayload, writeCompressedBlock } from './encode/compressedBlock.js';
|
|
7
8
|
import { writeFrameHeader } from './encode/frameWriter.js';
|
|
8
9
|
import { buildGreedySequences } from './encode/greedySequences.js';
|
|
10
|
+
import { ZstdError } from './errors.js';
|
|
9
11
|
import { computeContentChecksum32 } from './frame/checksum.js';
|
|
10
12
|
const BLOCK_MAX = 128 * 1024;
|
|
11
13
|
export function compress(input, options) {
|
|
12
14
|
const level = options?.level ?? 0;
|
|
13
15
|
const hasChecksum = options?.checksum ?? false;
|
|
16
|
+
const dictionary = options?.dictionary;
|
|
17
|
+
const dictionaryBytes = dictionary instanceof Uint8Array ? dictionary : dictionary?.bytes;
|
|
18
|
+
const providedDictionaryId = dictionary instanceof Uint8Array ? null : (dictionary?.id ?? null);
|
|
19
|
+
const normalizedDictionary = dictionaryBytes && dictionaryBytes.length > 0
|
|
20
|
+
? normalizeDecoderDictionary(dictionaryBytes, providedDictionaryId)
|
|
21
|
+
: null;
|
|
22
|
+
const dictionaryId = options?.noDictId ? null : (normalizedDictionary?.dictionaryId ?? providedDictionaryId);
|
|
23
|
+
if (dictionaryId !== null && (!Number.isInteger(dictionaryId) || dictionaryId <= 0 || dictionaryId > 0xffff_ffff)) {
|
|
24
|
+
throw new ZstdError('dictionary.id must be a 32-bit positive integer', 'parameter_unsupported');
|
|
25
|
+
}
|
|
14
26
|
const chunks = [];
|
|
15
|
-
chunks.push(writeFrameHeader(input.length, hasChecksum));
|
|
27
|
+
chunks.push(writeFrameHeader(input.length, hasChecksum, dictionaryId));
|
|
16
28
|
let offset = 0;
|
|
17
29
|
const blockCount = input.length === 0 ? 1 : Math.ceil(input.length / BLOCK_MAX);
|
|
18
30
|
let blockIndex = 0;
|
package/dist/compress.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compress.js","sourceRoot":"","sources":["../src/compress.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,EAAE,2BAA2B,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAChG,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"compress.js","sourceRoot":"","sources":["../src/compress.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export type DictionaryTrainingAlgorithm = 'fastcover' | 'cover' | 'legacy';
|
|
2
|
+
export interface GenerateDictionaryOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Target maximum output size for dictionary bytes.
|
|
5
|
+
* Similar to zstd CLI --maxdict.
|
|
6
|
+
*/
|
|
7
|
+
maxDictSize?: number;
|
|
8
|
+
/**
|
|
9
|
+
* Included for API parity with zstd terminology.
|
|
10
|
+
* Raw-content dictionaries don't embed an ID in bytes; pass this value
|
|
11
|
+
* separately to compress/decompress options when needed.
|
|
12
|
+
*/
|
|
13
|
+
dictId?: number;
|
|
14
|
+
/**
|
|
15
|
+
* Training mode selector inspired by zstd dictionary builders.
|
|
16
|
+
* This implementation is deterministic and uses algorithm-specific scoring.
|
|
17
|
+
*/
|
|
18
|
+
algorithm?: DictionaryTrainingAlgorithm;
|
|
19
|
+
/**
|
|
20
|
+
* Candidate segment size (bytes) used while harvesting patterns.
|
|
21
|
+
*/
|
|
22
|
+
k?: number;
|
|
23
|
+
/**
|
|
24
|
+
* Distance step (bytes) between candidate probes.
|
|
25
|
+
*/
|
|
26
|
+
d?: number;
|
|
27
|
+
/**
|
|
28
|
+
* Number of score-curve refinement passes.
|
|
29
|
+
*/
|
|
30
|
+
steps?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Percent of each sample used for candidate harvesting (1-100).
|
|
33
|
+
*/
|
|
34
|
+
split?: number;
|
|
35
|
+
/**
|
|
36
|
+
* Additional fastcover-style score multiplier.
|
|
37
|
+
*/
|
|
38
|
+
f?: number;
|
|
39
|
+
/**
|
|
40
|
+
* Probe stride accelerator (1-10).
|
|
41
|
+
*/
|
|
42
|
+
accel?: number;
|
|
43
|
+
/**
|
|
44
|
+
* Legacy-style density control (1-10), where lower means denser.
|
|
45
|
+
*/
|
|
46
|
+
selectivity?: number;
|
|
47
|
+
/**
|
|
48
|
+
* Optional shrink pass. If true, applies default shrink factor.
|
|
49
|
+
* If number, interpreted as target shrink factor >= 1.
|
|
50
|
+
*/
|
|
51
|
+
shrink?: boolean | number;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Generate a deterministic raw-content dictionary from training samples.
|
|
55
|
+
*
|
|
56
|
+
* The output is intentionally a raw-content dictionary byte sequence, which is
|
|
57
|
+
* compatible with zstd's -D usage and zstdify dictionary decode paths.
|
|
58
|
+
*/
|
|
59
|
+
export declare function generateDictionary(samples: Uint8Array[], options?: GenerateDictionaryOptions): Uint8Array;
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { ZstdError } from '../errors.js';
|
|
2
|
+
const DEFAULT_MAX_DICT_SIZE = 112_640;
|
|
3
|
+
function clamp(value, min, max) {
|
|
4
|
+
return Math.min(max, Math.max(min, value));
|
|
5
|
+
}
|
|
6
|
+
function hashBytes(bytes) {
|
|
7
|
+
// FNV-1a 32-bit
|
|
8
|
+
let hash = 0x811c9dc5;
|
|
9
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
10
|
+
hash ^= bytes[i] ?? 0;
|
|
11
|
+
hash = Math.imul(hash, 0x01000193) >>> 0;
|
|
12
|
+
}
|
|
13
|
+
return hash >>> 0;
|
|
14
|
+
}
|
|
15
|
+
function normalizeOptions(sampleCount, options) {
|
|
16
|
+
const algorithm = options?.algorithm ?? 'fastcover';
|
|
17
|
+
const maxDictSize = options?.maxDictSize ?? DEFAULT_MAX_DICT_SIZE;
|
|
18
|
+
const kDefault = algorithm === 'cover' ? 64 : algorithm === 'legacy' ? 32 : 48;
|
|
19
|
+
const dDefault = algorithm === 'cover' ? 8 : algorithm === 'legacy' ? 4 : 8;
|
|
20
|
+
const stepsDefault = algorithm === 'cover' ? 6 : algorithm === 'legacy' ? 3 : 4;
|
|
21
|
+
const splitDefault = algorithm === 'legacy' ? 100 : 75;
|
|
22
|
+
const accelDefault = 1;
|
|
23
|
+
const fDefault = 20;
|
|
24
|
+
const selectivityDefault = 9;
|
|
25
|
+
const shrinkDefault = false;
|
|
26
|
+
if (!Number.isInteger(maxDictSize) || maxDictSize <= 0) {
|
|
27
|
+
throw new ZstdError('maxDictSize must be a positive integer', 'parameter_unsupported');
|
|
28
|
+
}
|
|
29
|
+
if (options?.dictId !== undefined) {
|
|
30
|
+
if (!Number.isInteger(options.dictId) || options.dictId <= 0 || options.dictId > 0xffff_ffff) {
|
|
31
|
+
throw new ZstdError('dictId must be a 32-bit positive integer', 'parameter_unsupported');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const k = clamp(Math.trunc(options?.k ?? kDefault), 8, 1024);
|
|
35
|
+
const d = clamp(Math.trunc(options?.d ?? dDefault), 1, 64);
|
|
36
|
+
const steps = clamp(Math.trunc(options?.steps ?? stepsDefault), 1, 1000);
|
|
37
|
+
const split = clamp(Math.trunc(options?.split ?? splitDefault), 1, 100);
|
|
38
|
+
const f = clamp(Math.trunc(options?.f ?? fDefault), 1, 1000);
|
|
39
|
+
const accel = clamp(Math.trunc(options?.accel ?? accelDefault), 1, 10);
|
|
40
|
+
const selectivity = clamp(Math.trunc(options?.selectivity ?? selectivityDefault), 1, 10);
|
|
41
|
+
const shrink = options?.shrink ?? shrinkDefault;
|
|
42
|
+
if (sampleCount === 0) {
|
|
43
|
+
throw new ZstdError('Training requires at least one sample', 'parameter_unsupported');
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
algorithm,
|
|
47
|
+
maxDictSize,
|
|
48
|
+
k,
|
|
49
|
+
d,
|
|
50
|
+
steps,
|
|
51
|
+
split,
|
|
52
|
+
f,
|
|
53
|
+
accel,
|
|
54
|
+
selectivity,
|
|
55
|
+
shrink,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function toHex(bytes) {
|
|
59
|
+
let out = '';
|
|
60
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
61
|
+
out += (bytes[i] ?? 0).toString(16).padStart(2, '0');
|
|
62
|
+
}
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
function preprocessSamples(samples, splitPercent) {
|
|
66
|
+
const preprocessed = [];
|
|
67
|
+
for (const sample of samples) {
|
|
68
|
+
if (!(sample instanceof Uint8Array)) {
|
|
69
|
+
throw new ZstdError('All samples must be Uint8Array', 'parameter_unsupported');
|
|
70
|
+
}
|
|
71
|
+
if (sample.length === 0)
|
|
72
|
+
continue;
|
|
73
|
+
const usable = Math.max(1, Math.floor((sample.length * splitPercent) / 100));
|
|
74
|
+
preprocessed.push(sample.subarray(0, usable));
|
|
75
|
+
}
|
|
76
|
+
if (preprocessed.length === 0) {
|
|
77
|
+
throw new ZstdError('Training requires at least one non-empty sample', 'parameter_unsupported');
|
|
78
|
+
}
|
|
79
|
+
return preprocessed;
|
|
80
|
+
}
|
|
81
|
+
function scoreWeight(algorithm, bytes, hits, step, f, selectivity) {
|
|
82
|
+
const entropyBias = 1 + (hashBytes(bytes) % 13) / 32;
|
|
83
|
+
const length = bytes.length;
|
|
84
|
+
if (algorithm === 'legacy') {
|
|
85
|
+
const density = 11 - selectivity;
|
|
86
|
+
return hits * (1 + density / 4) + length * 0.5 + entropyBias;
|
|
87
|
+
}
|
|
88
|
+
if (algorithm === 'cover') {
|
|
89
|
+
return hits * (1 + step / 10) + length * 1.1 + entropyBias;
|
|
90
|
+
}
|
|
91
|
+
// fastcover
|
|
92
|
+
return hits * (1 + f / 40) + length * 0.9 + entropyBias;
|
|
93
|
+
}
|
|
94
|
+
function harvestCandidates(samples, k, d, accel, algorithm, steps, f, selectivity) {
|
|
95
|
+
const map = new Map();
|
|
96
|
+
for (let step = 0; step < steps; step++) {
|
|
97
|
+
const size = clamp(k + step * d, 8, 2048);
|
|
98
|
+
const stride = Math.max(1, Math.floor((d * accel) / Math.max(1, step + 1)));
|
|
99
|
+
for (const sample of samples) {
|
|
100
|
+
if (sample.length < size)
|
|
101
|
+
continue;
|
|
102
|
+
for (let i = 0; i + size <= sample.length; i += stride) {
|
|
103
|
+
const bytes = sample.subarray(i, i + size);
|
|
104
|
+
const key = toHex(bytes);
|
|
105
|
+
const existing = map.get(key);
|
|
106
|
+
if (existing) {
|
|
107
|
+
existing.hits += 1;
|
|
108
|
+
existing.score = scoreWeight(algorithm, existing.bytes, existing.hits, step + 1, f, selectivity);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const cloned = bytes.slice();
|
|
112
|
+
map.set(key, {
|
|
113
|
+
key,
|
|
114
|
+
bytes: cloned,
|
|
115
|
+
hits: 1,
|
|
116
|
+
score: scoreWeight(algorithm, cloned, 1, step + 1, f, selectivity),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return [...map.values()];
|
|
122
|
+
}
|
|
123
|
+
function maybeShrink(target, shrink) {
|
|
124
|
+
if (shrink === false)
|
|
125
|
+
return target;
|
|
126
|
+
if (shrink === true)
|
|
127
|
+
return Math.max(256, Math.floor(target * 0.75));
|
|
128
|
+
if (Number.isFinite(shrink) && shrink >= 1) {
|
|
129
|
+
return Math.max(256, Math.floor(target / shrink));
|
|
130
|
+
}
|
|
131
|
+
throw new ZstdError('shrink must be boolean or number >= 1', 'parameter_unsupported');
|
|
132
|
+
}
|
|
133
|
+
function buildDictionaryBytes(candidates, maxDictSize) {
|
|
134
|
+
const sorted = [...candidates].sort((a, b) => {
|
|
135
|
+
if (b.score !== a.score)
|
|
136
|
+
return b.score - a.score;
|
|
137
|
+
if (b.hits !== a.hits)
|
|
138
|
+
return b.hits - a.hits;
|
|
139
|
+
if (b.bytes.length !== a.bytes.length)
|
|
140
|
+
return b.bytes.length - a.bytes.length;
|
|
141
|
+
return a.key.localeCompare(b.key);
|
|
142
|
+
});
|
|
143
|
+
const chunks = [];
|
|
144
|
+
let total = 0;
|
|
145
|
+
for (const candidate of sorted) {
|
|
146
|
+
if (total >= maxDictSize)
|
|
147
|
+
break;
|
|
148
|
+
if (candidate.hits <= 1 && candidate.bytes.length < 24)
|
|
149
|
+
continue;
|
|
150
|
+
const remaining = maxDictSize - total;
|
|
151
|
+
if (remaining < 8)
|
|
152
|
+
break;
|
|
153
|
+
const piece = candidate.bytes.length <= remaining ? candidate.bytes : candidate.bytes.subarray(0, remaining);
|
|
154
|
+
if (piece.length < 8)
|
|
155
|
+
break;
|
|
156
|
+
chunks.push(piece.slice());
|
|
157
|
+
total += piece.length;
|
|
158
|
+
}
|
|
159
|
+
if (chunks.length === 0) {
|
|
160
|
+
// Fallback: ensure at least one deterministic dictionary segment exists.
|
|
161
|
+
const fallback = new Uint8Array(Math.min(256, maxDictSize));
|
|
162
|
+
for (let i = 0; i < fallback.length; i++)
|
|
163
|
+
fallback[i] = i & 0xff;
|
|
164
|
+
return fallback;
|
|
165
|
+
}
|
|
166
|
+
const out = new Uint8Array(total);
|
|
167
|
+
let offset = 0;
|
|
168
|
+
for (const chunk of chunks) {
|
|
169
|
+
out.set(chunk, offset);
|
|
170
|
+
offset += chunk.length;
|
|
171
|
+
}
|
|
172
|
+
return out;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Generate a deterministic raw-content dictionary from training samples.
|
|
176
|
+
*
|
|
177
|
+
* The output is intentionally a raw-content dictionary byte sequence, which is
|
|
178
|
+
* compatible with zstd's -D usage and zstdify dictionary decode paths.
|
|
179
|
+
*/
|
|
180
|
+
export function generateDictionary(samples, options) {
|
|
181
|
+
const normalized = normalizeOptions(samples.length, options);
|
|
182
|
+
const preprocessed = preprocessSamples(samples, normalized.split);
|
|
183
|
+
const candidates = harvestCandidates(preprocessed, normalized.k, normalized.d, normalized.accel, normalized.algorithm, normalized.steps, normalized.f, normalized.selectivity);
|
|
184
|
+
const targetSize = maybeShrink(normalized.maxDictSize, normalized.shrink);
|
|
185
|
+
return buildDictionaryBytes(candidates, targetSize);
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=generateDictionary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateDictionary.js","sourceRoot":"","sources":["../../src/dictionary/generateDictionary.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,18 @@
|
|
|
2
2
|
* Write zstd frame header.
|
|
3
3
|
*/
|
|
4
4
|
const ZSTD_MAGIC = 0xfd2fb528;
|
|
5
|
-
|
|
5
|
+
function writeDictionaryId(chunks, dictionaryId) {
|
|
6
|
+
if (dictionaryId <= 0xff) {
|
|
7
|
+
chunks.push(dictionaryId & 0xff);
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
if (dictionaryId <= 0xffff) {
|
|
11
|
+
chunks.push(dictionaryId & 0xff, (dictionaryId >>> 8) & 0xff);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
chunks.push(dictionaryId & 0xff, (dictionaryId >>> 8) & 0xff, (dictionaryId >>> 16) & 0xff, (dictionaryId >>> 24) & 0xff);
|
|
15
|
+
}
|
|
16
|
+
export function writeFrameHeader(contentSize, hasChecksum, dictionaryId = null) {
|
|
6
17
|
const chunks = [];
|
|
7
18
|
chunks.push(ZSTD_MAGIC & 0xff, (ZSTD_MAGIC >> 8) & 0xff, (ZSTD_MAGIC >> 16) & 0xff, (ZSTD_MAGIC >> 24) & 0xff);
|
|
8
19
|
let fhd = 0;
|
|
@@ -18,8 +29,22 @@ export function writeFrameHeader(contentSize, hasChecksum) {
|
|
|
18
29
|
fhd |= 2 << 6;
|
|
19
30
|
fhd |= 1 << 5;
|
|
20
31
|
}
|
|
32
|
+
if (dictionaryId !== null) {
|
|
33
|
+
if (!Number.isInteger(dictionaryId) || dictionaryId <= 0 || dictionaryId > 0xffff_ffff) {
|
|
34
|
+
throw new Error('Invalid dictionaryId in frame header');
|
|
35
|
+
}
|
|
36
|
+
if (dictionaryId <= 0xff)
|
|
37
|
+
fhd |= 1;
|
|
38
|
+
else if (dictionaryId <= 0xffff)
|
|
39
|
+
fhd |= 2;
|
|
40
|
+
else
|
|
41
|
+
fhd |= 3;
|
|
42
|
+
}
|
|
21
43
|
fhd |= (hasChecksum ? 1 : 0) << 2;
|
|
22
44
|
chunks.push(fhd);
|
|
45
|
+
if (dictionaryId !== null) {
|
|
46
|
+
writeDictionaryId(chunks, dictionaryId >>> 0);
|
|
47
|
+
}
|
|
23
48
|
if (contentSize <= 255) {
|
|
24
49
|
chunks.push(contentSize & 0xff);
|
|
25
50
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frameWriter.js","sourceRoot":"","sources":["../../src/encode/frameWriter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,UAAU,GAAG,UAAU,CAAC;AAE9B,MAAM,UAAU,gBAAgB,
|
|
1
|
+
{"version":3,"file":"frameWriter.js","sourceRoot":"","sources":["../../src/encode/frameWriter.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
export { type CompressOptions, compress } from './compress.js';
|
|
2
2
|
export { type DecompressOptions, decompress } from './decompress.js';
|
|
3
|
+
export { type DictionaryTrainingAlgorithm, type GenerateDictionaryOptions, generateDictionary, } from './dictionary/generateDictionary.js';
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAA0B,UAAU,EAAE,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAA0B,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAGL,kBAAkB,GACnB,MAAM,oCAAoC,CAAC"}
|
package/logo.webp
ADDED
|
Binary file
|