distillate 0.8.2 → 0.10.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.
Files changed (42) hide show
  1. package/README.md +53 -6
  2. package/dist/blocked/index.cjs +15 -10
  3. package/dist/blocked/index.d.cts +7 -6
  4. package/dist/blocked/index.d.ts +7 -6
  5. package/dist/blocked/index.js +13 -9
  6. package/dist/bloom/index.cjs +35 -34
  7. package/dist/bloom/index.d.cts +22 -17
  8. package/dist/bloom/index.d.ts +22 -17
  9. package/dist/bloom/index.js +32 -32
  10. package/dist/bytes-DCuYtUVS.d.cts +4 -0
  11. package/dist/bytes-DCuYtUVS.d.ts +4 -0
  12. package/dist/frame/index.cjs +9 -0
  13. package/dist/frame/index.d.cts +2 -0
  14. package/dist/frame/index.d.ts +2 -0
  15. package/dist/frame/index.js +2 -0
  16. package/dist/fuse/index.cjs +27 -23
  17. package/dist/fuse/index.d.cts +7 -6
  18. package/dist/fuse/index.d.ts +7 -6
  19. package/dist/fuse/index.js +15 -12
  20. package/dist/hasher-D8LCBTOM.cjs +276 -0
  21. package/dist/hasher-DVWXS_vJ.js +229 -0
  22. package/dist/hll/index.cjs +366 -0
  23. package/dist/hll/index.d.cts +120 -0
  24. package/dist/hll/index.d.ts +120 -0
  25. package/dist/hll/index.js +356 -0
  26. package/dist/index.cjs +1 -1
  27. package/dist/index.d.cts +2 -3
  28. package/dist/index.d.ts +2 -3
  29. package/dist/index.js +1 -1
  30. package/dist/serialize--xR6vGSW.d.cts +112 -0
  31. package/dist/serialize--xR6vGSW.d.ts +112 -0
  32. package/dist/serialize-CHikZ4GH.cjs +296 -0
  33. package/dist/serialize-CMSYFym-.js +201 -0
  34. package/dist/sizing-BLzZk2zr.cjs +28 -0
  35. package/dist/sizing-BtUrtvF_.js +17 -0
  36. package/dist/sizing-wYOW27eY.d.cts +22 -0
  37. package/dist/sizing-wYOW27eY.d.ts +22 -0
  38. package/package.json +26 -10
  39. package/dist/serialize-BqIcsR2J.js +0 -388
  40. package/dist/serialize-CXnRWItH.cjs +0 -513
  41. package/dist/serialize-ChyWpB9F.d.cts +0 -73
  42. package/dist/serialize-ChyWpB9F.d.ts +0 -73
@@ -0,0 +1,296 @@
1
+ //#region src/core/base64.ts
2
+ const ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
3
+ const DECODE = new Int16Array(128).fill(-1);
4
+ for (let i = 0; i < 64; i++) DECODE[ALPHABET.charCodeAt(i)] = i;
5
+ const sym = (n) => ALPHABET.charAt(n & 63);
6
+ function toBase64(bytes) {
7
+ let out = "";
8
+ let i = 0;
9
+ for (; i + 3 <= bytes.length; i += 3) {
10
+ const n = (bytes[i] ?? 0) << 16 | (bytes[i + 1] ?? 0) << 8 | (bytes[i + 2] ?? 0);
11
+ out += sym(n >>> 18) + sym(n >>> 12) + sym(n >>> 6) + sym(n);
12
+ }
13
+ const rem = bytes.length - i;
14
+ if (rem === 1) {
15
+ const n = (bytes[i] ?? 0) << 16;
16
+ out += sym(n >>> 18) + sym(n >>> 12) + "==";
17
+ } else if (rem === 2) {
18
+ const n = (bytes[i] ?? 0) << 16 | (bytes[i + 1] ?? 0) << 8;
19
+ out += sym(n >>> 18) + sym(n >>> 12) + sym(n >>> 6) + "=";
20
+ }
21
+ return out;
22
+ }
23
+ function fromBase64(s) {
24
+ let len = s.length;
25
+ while (len > 0 && s.charCodeAt(len - 1) === 61) len--;
26
+ if (len % 4 === 1) throw new RangeError(`invalid base64 length ${String(len)}`);
27
+ const out = new Uint8Array(len * 3 >> 2);
28
+ let acc = 0;
29
+ let bits = 0;
30
+ let o = 0;
31
+ for (let i = 0; i < len; i++) {
32
+ const v = DECODE[s.charCodeAt(i)] ?? -1;
33
+ if (v < 0) throw new RangeError(`invalid base64 character at index ${String(i)}`);
34
+ acc = acc << 6 | v;
35
+ bits += 6;
36
+ if (bits >= 8) {
37
+ bits -= 8;
38
+ out[o++] = acc >>> bits & 255;
39
+ }
40
+ }
41
+ return out;
42
+ }
43
+ //#endregion
44
+ //#region src/core/crc32.ts
45
+ const T1 = 256;
46
+ const T2 = 512;
47
+ const T3 = 768;
48
+ const T4 = 1024;
49
+ const T5 = 1280;
50
+ const T6 = 1536;
51
+ const T7 = 1792;
52
+ const at = (a, i) => a[i] ?? 0;
53
+ let tables;
54
+ function buildTables() {
55
+ const t = new Uint32Array(2048);
56
+ for (let n = 0; n < 256; n++) {
57
+ let c = n;
58
+ for (let k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
59
+ t[n] = c >>> 0;
60
+ }
61
+ for (let k = 1; k < 8; k++) for (let n = 0; n < 256; n++) {
62
+ const p = at(t, (k - 1) * 256 + n);
63
+ t[k * 256 + n] = (at(t, p & 255) ^ p >>> 8) >>> 0;
64
+ }
65
+ return t;
66
+ }
67
+ function crc32(bytes) {
68
+ const t = tables ??= buildTables();
69
+ const len = bytes.length;
70
+ const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
71
+ let crc = 4294967295;
72
+ let i = 0;
73
+ const last = len - 8;
74
+ while (i <= last) {
75
+ const one = (dv.getUint32(i, true) ^ crc) >>> 0;
76
+ const two = dv.getUint32(i + 4, true);
77
+ crc = (at(t, T7 + (one & 255)) ^ at(t, T6 + (one >>> 8 & 255)) ^ at(t, T5 + (one >>> 16 & 255)) ^ at(t, T4 + (one >>> 24 & 255)) ^ at(t, T3 + (two & 255)) ^ at(t, T2 + (two >>> 8 & 255)) ^ at(t, T1 + (two >>> 16 & 255)) ^ at(t, two >>> 24 & 255)) >>> 0;
78
+ i += 8;
79
+ }
80
+ for (; i < len; i++) crc = (at(t, (crc ^ dv.getUint8(i)) & 255) ^ crc >>> 8) >>> 0;
81
+ return (crc ^ 4294967295) >>> 0;
82
+ }
83
+ const MAGIC = Uint8Array.of(68, 83, 84, 76);
84
+ const HEADER_SIZE = 16;
85
+ const BODY_LENGTH_OFFSET = 8;
86
+ const RESERVED_BYTE_OFFSET = 7;
87
+ const RESERVED_WORD_OFFSET = 12;
88
+ const TRAILER_SIZE = 4;
89
+ const PAYLOAD_ALIGNMENT = 8;
90
+ function writeFrame(header, paramsSize, payloadLength, fill) {
91
+ if ((HEADER_SIZE + paramsSize) % PAYLOAD_ALIGNMENT !== 0) throw new RangeError(`a ${String(paramsSize)}-byte params block puts the payload at ${String(HEADER_SIZE + paramsSize)}, which is not a multiple of ${String(PAYLOAD_ALIGNMENT)}`);
92
+ const bodyLength = paramsSize + payloadLength;
93
+ const frame = new Uint8Array(HEADER_SIZE + bodyLength + TRAILER_SIZE);
94
+ const frameView = new DataView(frame.buffer, frame.byteOffset, frame.byteLength);
95
+ frame.set(MAGIC, 0);
96
+ frame[4] = header.version;
97
+ frame[5] = header.type;
98
+ frame[6] = header.flags;
99
+ frame[RESERVED_BYTE_OFFSET] = 0;
100
+ frameView.setUint32(BODY_LENGTH_OFFSET, bodyLength, true);
101
+ fill(frame.subarray(HEADER_SIZE, HEADER_SIZE + bodyLength), new DataView(frame.buffer, HEADER_SIZE, bodyLength));
102
+ const crc = crc32(frame.subarray(0, HEADER_SIZE + bodyLength));
103
+ frameView.setUint32(HEADER_SIZE + bodyLength, crc, true);
104
+ return frame;
105
+ }
106
+ var SerializationError = class extends Error {
107
+ name = "SerializationError";
108
+ };
109
+ var TruncatedError = class extends SerializationError {
110
+ name = "TruncatedError";
111
+ };
112
+ var BadMagicError = class extends SerializationError {
113
+ name = "BadMagicError";
114
+ };
115
+ var UnknownVersionError = class extends SerializationError {
116
+ name = "UnknownVersionError";
117
+ };
118
+ var UnknownHashVariantError = class extends SerializationError {
119
+ name = "UnknownHashVariantError";
120
+ };
121
+ var ReservedBitsError = class extends SerializationError {
122
+ name = "ReservedBitsError";
123
+ };
124
+ var ChecksumError = class extends SerializationError {
125
+ name = "ChecksumError";
126
+ };
127
+ const JSON_TAG = "distillate";
128
+ function toJSONEnvelope(bytes) {
129
+ return {
130
+ $: JSON_TAG,
131
+ v: 5,
132
+ data: toBase64(bytes)
133
+ };
134
+ }
135
+ function fromJSONEnvelope(value) {
136
+ if (value === null || typeof value !== "object") throw new SerializationError("not a distillate filter JSON object");
137
+ const o = value;
138
+ if (o.$ !== JSON_TAG) throw new SerializationError(`expected "$":"${JSON_TAG}"`);
139
+ if (o.v !== 5) throw new UnknownVersionError(`unsupported JSON version ${String(o.v)}, expected ${String(5)}`);
140
+ if (typeof o.data !== "string") throw new SerializationError("missing string \"data\"");
141
+ try {
142
+ return fromBase64(o.data);
143
+ } catch {
144
+ throw new SerializationError("envelope data is not valid base64");
145
+ }
146
+ }
147
+ function bytesEqual(a, b) {
148
+ if (a.length !== b.length) return false;
149
+ for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
150
+ return true;
151
+ }
152
+ function assertMinBodyLength(actual, min, context) {
153
+ if (actual < min) throw new TruncatedError(`${context}: body of ${String(actual)} bytes is shorter than the ${String(min)}-byte params block`);
154
+ }
155
+ function assertParamsPadding(body, fieldsEnd, paramsSize, context) {
156
+ for (let at = fieldsEnd; at < paramsSize; at++) if (body[at] !== 0) throw new SerializationError(`${context}: params padding at byte ${String(at)} is not zero`);
157
+ }
158
+ function assertBodyLength(actual, expected, context) {
159
+ if (actual !== expected) throw new TruncatedError(`${context}: body of ${String(actual)} bytes does not match the declared params (expected ${String(expected)})`);
160
+ }
161
+ function readFrameAt(bytes, offset) {
162
+ if (!Number.isInteger(offset) || offset < 0) throw new RangeError(`frame offset must be a non-negative integer, got ${String(offset)}`);
163
+ return readFrame(bytes, offset, false);
164
+ }
165
+ function readFrame(bytes, offset, exact) {
166
+ const available = bytes.length - offset;
167
+ if (available < 20) throw new TruncatedError(`${String(available)} bytes remain at offset ${String(offset)}, fewer than the minimum frame of ${String(20)}`);
168
+ const frame = bytes.subarray(offset);
169
+ for (let i = 0; i < MAGIC.length; i++) if (frame[i] !== MAGIC[i]) throw new BadMagicError("frame does not start with the DSTL magic");
170
+ const version = frame[4] ?? 0;
171
+ if (version !== 5) throw new UnknownVersionError(`unsupported format version ${String(version)}`);
172
+ const view = new DataView(frame.buffer, frame.byteOffset, frame.byteLength);
173
+ const bodyLength = view.getUint32(BODY_LENGTH_OFFSET, true);
174
+ const byteLength = HEADER_SIZE + bodyLength + TRAILER_SIZE;
175
+ if (exact ? byteLength !== available : byteLength > available) throw new TruncatedError(`frame declares a ${String(bodyLength)}-byte body but ${String(available - HEADER_SIZE - TRAILER_SIZE)} remain`);
176
+ const trailerAt = byteLength - TRAILER_SIZE;
177
+ if (view.getUint32(trailerAt, true) !== crc32(frame.subarray(0, trailerAt))) throw new ChecksumError("frame CRC32 does not match its contents");
178
+ const flags = frame[6] ?? 0;
179
+ if ((flags & 240) !== 0) throw new ReservedBitsError(`frame sets reserved flags bits 4-7 (flags 0x${flags.toString(16)})`);
180
+ if (frame[RESERVED_BYTE_OFFSET] !== 0) throw new ReservedBitsError(`frame sets reserved byte 7 (0x${(frame[RESERVED_BYTE_OFFSET] ?? 0).toString(16)})`);
181
+ const reservedWord = view.getUint32(RESERVED_WORD_OFFSET, true);
182
+ if (reservedWord !== 0) throw new ReservedBitsError(`frame sets the reserved u32 at offset 12 (0x${reservedWord.toString(16)})`);
183
+ return {
184
+ version,
185
+ type: frame[5] ?? 0,
186
+ flags,
187
+ body: frame.subarray(HEADER_SIZE, HEADER_SIZE + bodyLength),
188
+ byteLength
189
+ };
190
+ }
191
+ function readHeader(frame) {
192
+ const { version, type, flags, body } = readFrame(frame, 0, true);
193
+ return {
194
+ version,
195
+ type,
196
+ flags,
197
+ body
198
+ };
199
+ }
200
+ //#endregion
201
+ Object.defineProperty(exports, "BadMagicError", {
202
+ enumerable: true,
203
+ get: function() {
204
+ return BadMagicError;
205
+ }
206
+ });
207
+ Object.defineProperty(exports, "ChecksumError", {
208
+ enumerable: true,
209
+ get: function() {
210
+ return ChecksumError;
211
+ }
212
+ });
213
+ Object.defineProperty(exports, "ReservedBitsError", {
214
+ enumerable: true,
215
+ get: function() {
216
+ return ReservedBitsError;
217
+ }
218
+ });
219
+ Object.defineProperty(exports, "SerializationError", {
220
+ enumerable: true,
221
+ get: function() {
222
+ return SerializationError;
223
+ }
224
+ });
225
+ Object.defineProperty(exports, "TruncatedError", {
226
+ enumerable: true,
227
+ get: function() {
228
+ return TruncatedError;
229
+ }
230
+ });
231
+ Object.defineProperty(exports, "UnknownHashVariantError", {
232
+ enumerable: true,
233
+ get: function() {
234
+ return UnknownHashVariantError;
235
+ }
236
+ });
237
+ Object.defineProperty(exports, "UnknownVersionError", {
238
+ enumerable: true,
239
+ get: function() {
240
+ return UnknownVersionError;
241
+ }
242
+ });
243
+ Object.defineProperty(exports, "assertBodyLength", {
244
+ enumerable: true,
245
+ get: function() {
246
+ return assertBodyLength;
247
+ }
248
+ });
249
+ Object.defineProperty(exports, "assertMinBodyLength", {
250
+ enumerable: true,
251
+ get: function() {
252
+ return assertMinBodyLength;
253
+ }
254
+ });
255
+ Object.defineProperty(exports, "assertParamsPadding", {
256
+ enumerable: true,
257
+ get: function() {
258
+ return assertParamsPadding;
259
+ }
260
+ });
261
+ Object.defineProperty(exports, "bytesEqual", {
262
+ enumerable: true,
263
+ get: function() {
264
+ return bytesEqual;
265
+ }
266
+ });
267
+ Object.defineProperty(exports, "fromJSONEnvelope", {
268
+ enumerable: true,
269
+ get: function() {
270
+ return fromJSONEnvelope;
271
+ }
272
+ });
273
+ Object.defineProperty(exports, "readFrameAt", {
274
+ enumerable: true,
275
+ get: function() {
276
+ return readFrameAt;
277
+ }
278
+ });
279
+ Object.defineProperty(exports, "readHeader", {
280
+ enumerable: true,
281
+ get: function() {
282
+ return readHeader;
283
+ }
284
+ });
285
+ Object.defineProperty(exports, "toJSONEnvelope", {
286
+ enumerable: true,
287
+ get: function() {
288
+ return toJSONEnvelope;
289
+ }
290
+ });
291
+ Object.defineProperty(exports, "writeFrame", {
292
+ enumerable: true,
293
+ get: function() {
294
+ return writeFrame;
295
+ }
296
+ });
@@ -0,0 +1,201 @@
1
+ //#region src/core/base64.ts
2
+ const ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
3
+ const DECODE = new Int16Array(128).fill(-1);
4
+ for (let i = 0; i < 64; i++) DECODE[ALPHABET.charCodeAt(i)] = i;
5
+ const sym = (n) => ALPHABET.charAt(n & 63);
6
+ function toBase64(bytes) {
7
+ let out = "";
8
+ let i = 0;
9
+ for (; i + 3 <= bytes.length; i += 3) {
10
+ const n = (bytes[i] ?? 0) << 16 | (bytes[i + 1] ?? 0) << 8 | (bytes[i + 2] ?? 0);
11
+ out += sym(n >>> 18) + sym(n >>> 12) + sym(n >>> 6) + sym(n);
12
+ }
13
+ const rem = bytes.length - i;
14
+ if (rem === 1) {
15
+ const n = (bytes[i] ?? 0) << 16;
16
+ out += sym(n >>> 18) + sym(n >>> 12) + "==";
17
+ } else if (rem === 2) {
18
+ const n = (bytes[i] ?? 0) << 16 | (bytes[i + 1] ?? 0) << 8;
19
+ out += sym(n >>> 18) + sym(n >>> 12) + sym(n >>> 6) + "=";
20
+ }
21
+ return out;
22
+ }
23
+ function fromBase64(s) {
24
+ let len = s.length;
25
+ while (len > 0 && s.charCodeAt(len - 1) === 61) len--;
26
+ if (len % 4 === 1) throw new RangeError(`invalid base64 length ${String(len)}`);
27
+ const out = new Uint8Array(len * 3 >> 2);
28
+ let acc = 0;
29
+ let bits = 0;
30
+ let o = 0;
31
+ for (let i = 0; i < len; i++) {
32
+ const v = DECODE[s.charCodeAt(i)] ?? -1;
33
+ if (v < 0) throw new RangeError(`invalid base64 character at index ${String(i)}`);
34
+ acc = acc << 6 | v;
35
+ bits += 6;
36
+ if (bits >= 8) {
37
+ bits -= 8;
38
+ out[o++] = acc >>> bits & 255;
39
+ }
40
+ }
41
+ return out;
42
+ }
43
+ //#endregion
44
+ //#region src/core/crc32.ts
45
+ const T1 = 256;
46
+ const T2 = 512;
47
+ const T3 = 768;
48
+ const T4 = 1024;
49
+ const T5 = 1280;
50
+ const T6 = 1536;
51
+ const T7 = 1792;
52
+ const at = (a, i) => a[i] ?? 0;
53
+ let tables;
54
+ function buildTables() {
55
+ const t = new Uint32Array(2048);
56
+ for (let n = 0; n < 256; n++) {
57
+ let c = n;
58
+ for (let k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
59
+ t[n] = c >>> 0;
60
+ }
61
+ for (let k = 1; k < 8; k++) for (let n = 0; n < 256; n++) {
62
+ const p = at(t, (k - 1) * 256 + n);
63
+ t[k * 256 + n] = (at(t, p & 255) ^ p >>> 8) >>> 0;
64
+ }
65
+ return t;
66
+ }
67
+ function crc32(bytes) {
68
+ const t = tables ??= buildTables();
69
+ const len = bytes.length;
70
+ const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
71
+ let crc = 4294967295;
72
+ let i = 0;
73
+ const last = len - 8;
74
+ while (i <= last) {
75
+ const one = (dv.getUint32(i, true) ^ crc) >>> 0;
76
+ const two = dv.getUint32(i + 4, true);
77
+ crc = (at(t, T7 + (one & 255)) ^ at(t, T6 + (one >>> 8 & 255)) ^ at(t, T5 + (one >>> 16 & 255)) ^ at(t, T4 + (one >>> 24 & 255)) ^ at(t, T3 + (two & 255)) ^ at(t, T2 + (two >>> 8 & 255)) ^ at(t, T1 + (two >>> 16 & 255)) ^ at(t, two >>> 24 & 255)) >>> 0;
78
+ i += 8;
79
+ }
80
+ for (; i < len; i++) crc = (at(t, (crc ^ dv.getUint8(i)) & 255) ^ crc >>> 8) >>> 0;
81
+ return (crc ^ 4294967295) >>> 0;
82
+ }
83
+ const MAGIC = Uint8Array.of(68, 83, 84, 76);
84
+ const HEADER_SIZE = 16;
85
+ const BODY_LENGTH_OFFSET = 8;
86
+ const RESERVED_BYTE_OFFSET = 7;
87
+ const RESERVED_WORD_OFFSET = 12;
88
+ const TRAILER_SIZE = 4;
89
+ const PAYLOAD_ALIGNMENT = 8;
90
+ function writeFrame(header, paramsSize, payloadLength, fill) {
91
+ if ((HEADER_SIZE + paramsSize) % PAYLOAD_ALIGNMENT !== 0) throw new RangeError(`a ${String(paramsSize)}-byte params block puts the payload at ${String(HEADER_SIZE + paramsSize)}, which is not a multiple of ${String(PAYLOAD_ALIGNMENT)}`);
92
+ const bodyLength = paramsSize + payloadLength;
93
+ const frame = new Uint8Array(HEADER_SIZE + bodyLength + TRAILER_SIZE);
94
+ const frameView = new DataView(frame.buffer, frame.byteOffset, frame.byteLength);
95
+ frame.set(MAGIC, 0);
96
+ frame[4] = header.version;
97
+ frame[5] = header.type;
98
+ frame[6] = header.flags;
99
+ frame[RESERVED_BYTE_OFFSET] = 0;
100
+ frameView.setUint32(BODY_LENGTH_OFFSET, bodyLength, true);
101
+ fill(frame.subarray(HEADER_SIZE, HEADER_SIZE + bodyLength), new DataView(frame.buffer, HEADER_SIZE, bodyLength));
102
+ const crc = crc32(frame.subarray(0, HEADER_SIZE + bodyLength));
103
+ frameView.setUint32(HEADER_SIZE + bodyLength, crc, true);
104
+ return frame;
105
+ }
106
+ var SerializationError = class extends Error {
107
+ name = "SerializationError";
108
+ };
109
+ var TruncatedError = class extends SerializationError {
110
+ name = "TruncatedError";
111
+ };
112
+ var BadMagicError = class extends SerializationError {
113
+ name = "BadMagicError";
114
+ };
115
+ var UnknownVersionError = class extends SerializationError {
116
+ name = "UnknownVersionError";
117
+ };
118
+ var UnknownHashVariantError = class extends SerializationError {
119
+ name = "UnknownHashVariantError";
120
+ };
121
+ var ReservedBitsError = class extends SerializationError {
122
+ name = "ReservedBitsError";
123
+ };
124
+ var ChecksumError = class extends SerializationError {
125
+ name = "ChecksumError";
126
+ };
127
+ const JSON_TAG = "distillate";
128
+ function toJSONEnvelope(bytes) {
129
+ return {
130
+ $: JSON_TAG,
131
+ v: 5,
132
+ data: toBase64(bytes)
133
+ };
134
+ }
135
+ function fromJSONEnvelope(value) {
136
+ if (value === null || typeof value !== "object") throw new SerializationError("not a distillate filter JSON object");
137
+ const o = value;
138
+ if (o.$ !== JSON_TAG) throw new SerializationError(`expected "$":"${JSON_TAG}"`);
139
+ if (o.v !== 5) throw new UnknownVersionError(`unsupported JSON version ${String(o.v)}, expected ${String(5)}`);
140
+ if (typeof o.data !== "string") throw new SerializationError("missing string \"data\"");
141
+ try {
142
+ return fromBase64(o.data);
143
+ } catch {
144
+ throw new SerializationError("envelope data is not valid base64");
145
+ }
146
+ }
147
+ function bytesEqual(a, b) {
148
+ if (a.length !== b.length) return false;
149
+ for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
150
+ return true;
151
+ }
152
+ function assertMinBodyLength(actual, min, context) {
153
+ if (actual < min) throw new TruncatedError(`${context}: body of ${String(actual)} bytes is shorter than the ${String(min)}-byte params block`);
154
+ }
155
+ function assertParamsPadding(body, fieldsEnd, paramsSize, context) {
156
+ for (let at = fieldsEnd; at < paramsSize; at++) if (body[at] !== 0) throw new SerializationError(`${context}: params padding at byte ${String(at)} is not zero`);
157
+ }
158
+ function assertBodyLength(actual, expected, context) {
159
+ if (actual !== expected) throw new TruncatedError(`${context}: body of ${String(actual)} bytes does not match the declared params (expected ${String(expected)})`);
160
+ }
161
+ function readFrameAt(bytes, offset) {
162
+ if (!Number.isInteger(offset) || offset < 0) throw new RangeError(`frame offset must be a non-negative integer, got ${String(offset)}`);
163
+ return readFrame(bytes, offset, false);
164
+ }
165
+ function readFrame(bytes, offset, exact) {
166
+ const available = bytes.length - offset;
167
+ if (available < 20) throw new TruncatedError(`${String(available)} bytes remain at offset ${String(offset)}, fewer than the minimum frame of ${String(20)}`);
168
+ const frame = bytes.subarray(offset);
169
+ for (let i = 0; i < MAGIC.length; i++) if (frame[i] !== MAGIC[i]) throw new BadMagicError("frame does not start with the DSTL magic");
170
+ const version = frame[4] ?? 0;
171
+ if (version !== 5) throw new UnknownVersionError(`unsupported format version ${String(version)}`);
172
+ const view = new DataView(frame.buffer, frame.byteOffset, frame.byteLength);
173
+ const bodyLength = view.getUint32(BODY_LENGTH_OFFSET, true);
174
+ const byteLength = HEADER_SIZE + bodyLength + TRAILER_SIZE;
175
+ if (exact ? byteLength !== available : byteLength > available) throw new TruncatedError(`frame declares a ${String(bodyLength)}-byte body but ${String(available - HEADER_SIZE - TRAILER_SIZE)} remain`);
176
+ const trailerAt = byteLength - TRAILER_SIZE;
177
+ if (view.getUint32(trailerAt, true) !== crc32(frame.subarray(0, trailerAt))) throw new ChecksumError("frame CRC32 does not match its contents");
178
+ const flags = frame[6] ?? 0;
179
+ if ((flags & 240) !== 0) throw new ReservedBitsError(`frame sets reserved flags bits 4-7 (flags 0x${flags.toString(16)})`);
180
+ if (frame[RESERVED_BYTE_OFFSET] !== 0) throw new ReservedBitsError(`frame sets reserved byte 7 (0x${(frame[RESERVED_BYTE_OFFSET] ?? 0).toString(16)})`);
181
+ const reservedWord = view.getUint32(RESERVED_WORD_OFFSET, true);
182
+ if (reservedWord !== 0) throw new ReservedBitsError(`frame sets the reserved u32 at offset 12 (0x${reservedWord.toString(16)})`);
183
+ return {
184
+ version,
185
+ type: frame[5] ?? 0,
186
+ flags,
187
+ body: frame.subarray(HEADER_SIZE, HEADER_SIZE + bodyLength),
188
+ byteLength
189
+ };
190
+ }
191
+ function readHeader(frame) {
192
+ const { version, type, flags, body } = readFrame(frame, 0, true);
193
+ return {
194
+ version,
195
+ type,
196
+ flags,
197
+ body
198
+ };
199
+ }
200
+ //#endregion
201
+ export { TruncatedError as a, assertBodyLength as c, bytesEqual as d, fromJSONEnvelope as f, writeFrame as g, toJSONEnvelope as h, SerializationError as i, assertMinBodyLength as l, readHeader as m, ChecksumError as n, UnknownHashVariantError as o, readFrameAt as p, ReservedBitsError as r, UnknownVersionError as s, BadMagicError as t, assertParamsPadding as u };
@@ -0,0 +1,28 @@
1
+ const require_params = require("./params-UTZbJ22c.cjs");
2
+ //#region src/core/sizing.ts
3
+ function bloomSizing(n, epsilon) {
4
+ const m = Math.ceil(-n * Math.log(epsilon) / (Math.LN2 * Math.LN2));
5
+ return {
6
+ m,
7
+ k: Math.max(1, Math.round(m / n * Math.LN2))
8
+ };
9
+ }
10
+ function hllSizing(relativeError) {
11
+ require_params.assertProbability(relativeError, "relativeError");
12
+ const p = Math.max(4, Math.ceil(2 * Math.log2(1.04 / relativeError)));
13
+ if (p > 18) throw new require_params.ParamError(`relativeError ${String(relativeError)} needs precision ${String(p)}, above the maximum ${String(18)}`);
14
+ return { p };
15
+ }
16
+ //#endregion
17
+ Object.defineProperty(exports, "bloomSizing", {
18
+ enumerable: true,
19
+ get: function() {
20
+ return bloomSizing;
21
+ }
22
+ });
23
+ Object.defineProperty(exports, "hllSizing", {
24
+ enumerable: true,
25
+ get: function() {
26
+ return hllSizing;
27
+ }
28
+ });
@@ -0,0 +1,17 @@
1
+ import { i as assertProbability, t as ParamError } from "./params-CeajSrwv.js";
2
+ //#region src/core/sizing.ts
3
+ function bloomSizing(n, epsilon) {
4
+ const m = Math.ceil(-n * Math.log(epsilon) / (Math.LN2 * Math.LN2));
5
+ return {
6
+ m,
7
+ k: Math.max(1, Math.round(m / n * Math.LN2))
8
+ };
9
+ }
10
+ function hllSizing(relativeError) {
11
+ assertProbability(relativeError, "relativeError");
12
+ const p = Math.max(4, Math.ceil(2 * Math.log2(1.04 / relativeError)));
13
+ if (p > 18) throw new ParamError(`relativeError ${String(relativeError)} needs precision ${String(p)}, above the maximum ${String(18)}`);
14
+ return { p };
15
+ }
16
+ //#endregion
17
+ export { hllSizing as n, bloomSizing as t };
@@ -0,0 +1,22 @@
1
+ //#region src/core/sizing.d.ts
2
+ /** Bloom filter geometry: the `BloomParams` fields a sizing solve determines. */
3
+ interface BloomSizing {
4
+ /** Number of bits in the filter. */
5
+ m: number;
6
+ /** Number of hash probes per key. */
7
+ k: number;
8
+ }
9
+ /** Optimal Bloom-filter sizing: `m` bits and `k` hashes for `n` items at target FPR `epsilon`. */
10
+ declare function bloomSizing(n: number, epsilon: number): BloomSizing;
11
+ /** HyperLogLog geometry: the `HllParams` fields a sizing solve determines. */
12
+ interface HllSizing {
13
+ /** Precision: the sketch holds `2 ** p` registers. */
14
+ p: number;
15
+ }
16
+ /**
17
+ * Smallest precision whose standard error `1.04 / sqrt(2 ** p)` meets
18
+ * `relativeError`. Throws {@link ParamError} when even `HLL_MAX_P` cannot.
19
+ */
20
+ declare function hllSizing(relativeError: number): HllSizing;
21
+ //#endregion
22
+ export { hllSizing as i, HllSizing as n, bloomSizing as r, BloomSizing as t };
@@ -0,0 +1,22 @@
1
+ //#region src/core/sizing.d.ts
2
+ /** Bloom filter geometry: the `BloomParams` fields a sizing solve determines. */
3
+ interface BloomSizing {
4
+ /** Number of bits in the filter. */
5
+ m: number;
6
+ /** Number of hash probes per key. */
7
+ k: number;
8
+ }
9
+ /** Optimal Bloom-filter sizing: `m` bits and `k` hashes for `n` items at target FPR `epsilon`. */
10
+ declare function bloomSizing(n: number, epsilon: number): BloomSizing;
11
+ /** HyperLogLog geometry: the `HllParams` fields a sizing solve determines. */
12
+ interface HllSizing {
13
+ /** Precision: the sketch holds `2 ** p` registers. */
14
+ p: number;
15
+ }
16
+ /**
17
+ * Smallest precision whose standard error `1.04 / sqrt(2 ** p)` meets
18
+ * `relativeError`. Throws {@link ParamError} when even `HLL_MAX_P` cannot.
19
+ */
20
+ declare function hllSizing(relativeError: number): HllSizing;
21
+ //#endregion
22
+ export { hllSizing as i, HllSizing as n, bloomSizing as r, BloomSizing as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "distillate",
3
- "version": "0.8.2",
3
+ "version": "0.10.0",
4
4
  "description": "Probabilistic data structures for JavaScript. Space-efficient, approximate-membership filters (Bloom, Blocked Bloom, Binary Fuse) with tunable error and a portable binary format; zero dependencies, universal.",
5
5
  "keywords": [
6
6
  "bloom-filter",
@@ -55,6 +55,22 @@
55
55
  "import": "./dist/fuse/index.js",
56
56
  "require": "./dist/fuse/index.cjs"
57
57
  },
58
+ "./hll": {
59
+ "types": {
60
+ "import": "./dist/hll/index.d.ts",
61
+ "require": "./dist/hll/index.d.cts"
62
+ },
63
+ "import": "./dist/hll/index.js",
64
+ "require": "./dist/hll/index.cjs"
65
+ },
66
+ "./frame": {
67
+ "types": {
68
+ "import": "./dist/frame/index.d.ts",
69
+ "require": "./dist/frame/index.d.cts"
70
+ },
71
+ "import": "./dist/frame/index.js",
72
+ "require": "./dist/frame/index.cjs"
73
+ },
58
74
  "./package.json": "./package.json"
59
75
  },
60
76
  "main": "./dist/index.cjs",
@@ -65,17 +81,17 @@
65
81
  ],
66
82
  "devDependencies": {
67
83
  "@arethetypeswrong/cli": "^0.18.5",
68
- "@microsoft/api-extractor": "^7.58.12",
69
- "@types/node": "^22.0.0",
70
- "@vitest/coverage-v8": "^4.1.10",
71
- "fast-check": "^4.9.0",
84
+ "@microsoft/api-extractor": "^7.59.1",
85
+ "@types/node": "^22.20.3",
86
+ "@vitest/coverage-v8": "^5.0.1",
87
+ "fast-check": "^4.10.1",
72
88
  "mitata": "^1.0.34",
73
- "publint": "^0.3.23",
74
- "tsdown": "^0.22.14",
75
- "tsx": "^4.23.12",
89
+ "publint": "^0.3.24",
90
+ "tsdown": "^0.23.0",
91
+ "tsx": "^4.23.13",
76
92
  "typedoc": "^0.28.20",
77
93
  "typescript": "^5.9.3",
78
- "vitest": "^4.1.10"
94
+ "vitest": "^5.0.1"
79
95
  },
80
96
  "engines": {
81
97
  "node": ">=22"
@@ -92,7 +108,7 @@
92
108
  "docs:check": "typedoc --emit none",
93
109
  "golden:gen": "tsx scripts/gen-golden.ts",
94
110
  "size:check": "node scripts/size-check.mjs",
95
- "bench": "tsx bench/core.bench.ts && tsx bench/bloom.bench.ts && tsx bench/blocked.bench.ts && tsx bench/fuse.bench.ts && tsx bench/accuracy.bench.ts",
111
+ "bench": "tsx bench/core.bench.ts && tsx bench/bloom.bench.ts && tsx bench/blocked.bench.ts && tsx bench/fuse.bench.ts && tsx bench/hll.bench.ts && tsx bench/accuracy.bench.ts",
96
112
  "typecheck": "tsc --noEmit"
97
113
  }
98
114
  }