distillate 0.9.0 → 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.
- package/README.md +19 -0
- package/dist/blocked/index.cjs +14 -9
- package/dist/blocked/index.d.cts +7 -6
- package/dist/blocked/index.d.ts +7 -6
- package/dist/blocked/index.js +12 -8
- package/dist/bloom/index.cjs +14 -9
- package/dist/bloom/index.d.cts +5 -4
- package/dist/bloom/index.d.ts +5 -4
- package/dist/bloom/index.js +12 -8
- package/dist/bytes-DCuYtUVS.d.cts +4 -0
- package/dist/bytes-DCuYtUVS.d.ts +4 -0
- package/dist/frame/index.cjs +9 -0
- package/dist/frame/index.d.cts +2 -0
- package/dist/frame/index.d.ts +2 -0
- package/dist/frame/index.js +2 -0
- package/dist/fuse/index.cjs +26 -22
- package/dist/fuse/index.d.cts +7 -6
- package/dist/fuse/index.d.ts +7 -6
- package/dist/fuse/index.js +14 -11
- package/dist/hasher-D8LCBTOM.cjs +276 -0
- package/dist/hasher-DVWXS_vJ.js +229 -0
- package/dist/hll/index.cjs +12 -8
- package/dist/hll/index.d.cts +4 -3
- package/dist/hll/index.d.ts +4 -3
- package/dist/hll/index.js +11 -8
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +2 -3
- package/dist/index.d.ts +2 -3
- package/dist/index.js +1 -1
- package/dist/{serialize-Bv1zWzrh.d.cts → serialize--xR6vGSW.d.cts} +44 -8
- package/dist/{serialize-Bv1zWzrh.d.ts → serialize--xR6vGSW.d.ts} +44 -8
- package/dist/serialize-CHikZ4GH.cjs +296 -0
- package/dist/serialize-CMSYFym-.js +201 -0
- package/package.json +17 -9
- package/dist/serialize-D59Ri81a.js +0 -392
- package/dist/serialize-Ul2LKFJU.cjs +0 -517
package/dist/hll/index.d.cts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as BytesLike } from "../bytes-DCuYtUVS.cjs";
|
|
2
|
+
import { a as ReservedBitsError, c as UnknownHashVariantError, l as UnknownVersionError, n as ChecksumError, o as SerializationError, r as FilterJSON, s as TruncatedError, t as BadMagicError } from "../serialize--xR6vGSW.cjs";
|
|
2
3
|
import { t as ParamError } from "../params-DnqJBqLS.cjs";
|
|
3
4
|
import { i as hllSizing, n as HllSizing } from "../sizing-wYOW27eY.cjs";
|
|
4
5
|
//#region src/hll/hll.d.ts
|
|
@@ -19,7 +20,7 @@ interface HllParams {
|
|
|
19
20
|
* sketch.add("alice");
|
|
20
21
|
* ```
|
|
21
22
|
*/
|
|
22
|
-
declare class HyperLogLog {
|
|
23
|
+
export declare class HyperLogLog {
|
|
23
24
|
#private;
|
|
24
25
|
/**
|
|
25
26
|
* Creates a sketch at an explicit precision.
|
|
@@ -116,4 +117,4 @@ declare class HyperLogLog {
|
|
|
116
117
|
count(): number;
|
|
117
118
|
}
|
|
118
119
|
//#endregion
|
|
119
|
-
export { BadMagicError, ChecksumError, type FilterJSON, type HllParams, type HllSizing,
|
|
120
|
+
export { BadMagicError, ChecksumError, type FilterJSON, type HllParams, type HllSizing, ParamError, ReservedBitsError, SerializationError, TruncatedError, UnknownHashVariantError, UnknownVersionError, hllSizing };
|
package/dist/hll/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as BytesLike } from "../bytes-DCuYtUVS.js";
|
|
2
|
+
import { a as ReservedBitsError, c as UnknownHashVariantError, l as UnknownVersionError, n as ChecksumError, o as SerializationError, r as FilterJSON, s as TruncatedError, t as BadMagicError } from "../serialize--xR6vGSW.js";
|
|
2
3
|
import { t as ParamError } from "../params-DnqJBqLS.js";
|
|
3
4
|
import { i as hllSizing, n as HllSizing } from "../sizing-wYOW27eY.js";
|
|
4
5
|
//#region src/hll/hll.d.ts
|
|
@@ -19,7 +20,7 @@ interface HllParams {
|
|
|
19
20
|
* sketch.add("alice");
|
|
20
21
|
* ```
|
|
21
22
|
*/
|
|
22
|
-
declare class HyperLogLog {
|
|
23
|
+
export declare class HyperLogLog {
|
|
23
24
|
#private;
|
|
24
25
|
/**
|
|
25
26
|
* Creates a sketch at an explicit precision.
|
|
@@ -116,4 +117,4 @@ declare class HyperLogLog {
|
|
|
116
117
|
count(): number;
|
|
117
118
|
}
|
|
118
119
|
//#endregion
|
|
119
|
-
export { BadMagicError, ChecksumError, type FilterJSON, type HllParams, type HllSizing,
|
|
120
|
+
export { BadMagicError, ChecksumError, type FilterJSON, type HllParams, type HllSizing, ParamError, ReservedBitsError, SerializationError, TruncatedError, UnknownHashVariantError, UnknownVersionError, hllSizing };
|
package/dist/hll/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as hash128KeyInto } from "../hasher-DVWXS_vJ.js";
|
|
2
|
+
import { a as TruncatedError, c as assertBodyLength, f as fromJSONEnvelope, g as writeFrame, h as toJSONEnvelope, i as SerializationError, l as assertMinBodyLength, m as readHeader, n as ChecksumError, o as UnknownHashVariantError, r as ReservedBitsError, s as UnknownVersionError, t as BadMagicError, u as assertParamsPadding } from "../serialize-CMSYFym-.js";
|
|
2
3
|
import { o as assertUint32, t as ParamError } from "../params-CeajSrwv.js";
|
|
3
4
|
import { n as hllSizing } from "../sizing-BtUrtvF_.js";
|
|
4
5
|
//#region src/hll/estimate.ts
|
|
@@ -99,7 +100,7 @@ var Registers = class {
|
|
|
99
100
|
}
|
|
100
101
|
};
|
|
101
102
|
const RHO_BITS = 6;
|
|
102
|
-
const RHO_MASK =
|
|
103
|
+
const RHO_MASK = 63;
|
|
103
104
|
function encodeSparse(index, rho) {
|
|
104
105
|
return index << RHO_BITS | rho;
|
|
105
106
|
}
|
|
@@ -137,7 +138,8 @@ function compact(buf, len) {
|
|
|
137
138
|
//#region src/hll/hll.ts
|
|
138
139
|
const ERROR_CONSTANT = 1.04;
|
|
139
140
|
const TYPE = 5;
|
|
140
|
-
const PARAMS_SIZE =
|
|
141
|
+
const PARAMS_SIZE = 8;
|
|
142
|
+
const PARAMS_FIELDS_END = 6;
|
|
141
143
|
const DENSE = 0;
|
|
142
144
|
const SPARSE = 1;
|
|
143
145
|
const ENTRY_SIZE = 4;
|
|
@@ -180,6 +182,7 @@ var HyperLogLog = class HyperLogLog {
|
|
|
180
182
|
if (type !== TYPE) throw new SerializationError(`expected DSTL type ${String(TYPE)}, got ${String(type)}`);
|
|
181
183
|
if ((flags & 15) !== 0) throw new UnknownHashVariantError(`unsupported hash variant ${String(flags & 15)}`);
|
|
182
184
|
assertMinBodyLength(body.length, PARAMS_SIZE, "hll");
|
|
185
|
+
assertParamsPadding(body, PARAMS_FIELDS_END, PARAMS_SIZE, "hll");
|
|
183
186
|
const dv = new DataView(body.buffer, body.byteOffset, body.byteLength);
|
|
184
187
|
const p = body[0] ?? 0;
|
|
185
188
|
const encoding = body[1] ?? 0;
|
|
@@ -220,10 +223,10 @@ var HyperLogLog = class HyperLogLog {
|
|
|
220
223
|
const entries = compact(sparse, this.#len);
|
|
221
224
|
this.#len = entries;
|
|
222
225
|
return writeFrame({
|
|
223
|
-
version:
|
|
226
|
+
version: 5,
|
|
224
227
|
type: TYPE,
|
|
225
228
|
flags: 0
|
|
226
|
-
}, PARAMS_SIZE
|
|
229
|
+
}, PARAMS_SIZE, entries * ENTRY_SIZE, (body, dv) => {
|
|
227
230
|
body[0] = this.#p;
|
|
228
231
|
body[1] = SPARSE;
|
|
229
232
|
dv.setUint32(2, this.#seed, true);
|
|
@@ -232,10 +235,10 @@ var HyperLogLog = class HyperLogLog {
|
|
|
232
235
|
}
|
|
233
236
|
const payload = this.#registers.bytes;
|
|
234
237
|
return writeFrame({
|
|
235
|
-
version:
|
|
238
|
+
version: 5,
|
|
236
239
|
type: TYPE,
|
|
237
240
|
flags: 0
|
|
238
|
-
}, PARAMS_SIZE
|
|
241
|
+
}, PARAMS_SIZE, payload.length, (body, dv) => {
|
|
239
242
|
body[0] = this.#p;
|
|
240
243
|
body[1] = DENSE;
|
|
241
244
|
dv.setUint32(2, this.#seed, true);
|
|
@@ -350,4 +353,4 @@ var HyperLogLog = class HyperLogLog {
|
|
|
350
353
|
}
|
|
351
354
|
};
|
|
352
355
|
//#endregion
|
|
353
|
-
export { BadMagicError, ChecksumError, HyperLogLog, ParamError, SerializationError, TruncatedError, UnknownHashVariantError, UnknownVersionError, hllSizing };
|
|
356
|
+
export { BadMagicError, ChecksumError, HyperLogLog, ParamError, ReservedBitsError, SerializationError, TruncatedError, UnknownHashVariantError, UnknownVersionError, hllSizing };
|
package/dist/index.cjs
CHANGED
package/dist/index.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
//#region src/core/bytes.d.ts
|
|
2
|
-
type BytesLike = string | Uint8Array | ArrayBuffer;
|
|
3
|
-
//#endregion
|
|
4
1
|
//#region src/core/serialize.d.ts
|
|
5
2
|
/**
|
|
6
3
|
* Base class for every defect `fromBytes` and `fromJSON` reject. Thrown
|
|
@@ -38,22 +35,36 @@ declare class BadMagicError extends SerializationError {
|
|
|
38
35
|
}
|
|
39
36
|
/**
|
|
40
37
|
* Thrown when a frame or JSON envelope declares a format version this release
|
|
41
|
-
* does not read.
|
|
42
|
-
* `distillate`
|
|
38
|
+
* does not read. The remedy depends on which side is older. A frame newer than
|
|
39
|
+
* this release needs `distillate` upgraded on the reading side. A frame older
|
|
40
|
+
* than it is readable by no current release, since each reads exactly one
|
|
41
|
+
* format version; rebuild it from the source keys. Being at least as new as
|
|
42
|
+
* the producer is necessary, not sufficient.
|
|
43
43
|
*/
|
|
44
44
|
declare class UnknownVersionError extends SerializationError {
|
|
45
45
|
/** Discriminates this error from other `Error`s. */
|
|
46
46
|
override readonly name = "UnknownVersionError";
|
|
47
47
|
}
|
|
48
48
|
/**
|
|
49
|
-
* Thrown when a frame's flags nibble names a hash
|
|
50
|
-
* reproduce, so its stored bits are unreadable. Rebuild the filter from the
|
|
49
|
+
* Thrown when a frame's flags nibble names a hash or index mapping this
|
|
50
|
+
* release cannot reproduce, so its stored bits are unreadable. Rebuild the filter from the
|
|
51
51
|
* source keys with the version you run.
|
|
52
52
|
*/
|
|
53
53
|
declare class UnknownHashVariantError extends SerializationError {
|
|
54
54
|
/** Discriminates this error from other `Error`s. */
|
|
55
55
|
override readonly name = "UnknownHashVariantError";
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Thrown when a frame sets a header bit this format reserves: the flags high
|
|
59
|
+
* nibble, the byte at offset 7, or the word at offset 12. Only a newer writer
|
|
60
|
+
* puts anything there, and reading its frame under this release's meaning
|
|
61
|
+
* would give a wrong answer with no error. Upgrade `distillate` on the reading
|
|
62
|
+
* side; a reader must be at least as new as the producer.
|
|
63
|
+
*/
|
|
64
|
+
declare class ReservedBitsError extends SerializationError {
|
|
65
|
+
/** Discriminates this error from other `Error`s. */
|
|
66
|
+
override readonly name = "ReservedBitsError";
|
|
67
|
+
}
|
|
57
68
|
/**
|
|
58
69
|
* Thrown when a frame's CRC32 trailer does not match its contents, so the
|
|
59
70
|
* bytes were corrupted after they were written. Discard them and re-fetch;
|
|
@@ -72,5 +83,30 @@ interface FilterJSON {
|
|
|
72
83
|
/** Base64 of the `toBytes` frame. */
|
|
73
84
|
data: string;
|
|
74
85
|
}
|
|
86
|
+
/** One frame read in place from a larger buffer by {@link readFrameAt}. */
|
|
87
|
+
interface Frame {
|
|
88
|
+
/** Binary format version. */
|
|
89
|
+
version: number;
|
|
90
|
+
/** Structure type code; one this release does not implement still reads. */
|
|
91
|
+
type: number;
|
|
92
|
+
/** Header flags byte; the low nibble is the hash variant. */
|
|
93
|
+
flags: number;
|
|
94
|
+
/** The body, a view into the source buffer rather than a copy. */
|
|
95
|
+
body: Uint8Array;
|
|
96
|
+
/** Bytes the whole frame occupies, so `offset + byteLength` is the next one. */
|
|
97
|
+
byteLength: number;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Reads and validates the frame starting at `offset` in `bytes`, which may
|
|
101
|
+
* hold further frames after it: magic, version, declared length, CRC32 and
|
|
102
|
+
* reserved bits, without needing to know the structure type. Advance by the
|
|
103
|
+
* returned `byteLength` to walk a buffer of concatenated frames.
|
|
104
|
+
*
|
|
105
|
+
* @throws TruncatedError when the frame runs past the end of `bytes`.
|
|
106
|
+
* @throws BadMagicError, UnknownVersionError, ChecksumError or
|
|
107
|
+
* ReservedBitsError when the frame at `offset` is not one this release reads.
|
|
108
|
+
* @throws RangeError when `offset` is not a non-negative integer.
|
|
109
|
+
*/
|
|
110
|
+
declare function readFrameAt(bytes: Uint8Array, offset: number): Frame;
|
|
75
111
|
//#endregion
|
|
76
|
-
export {
|
|
112
|
+
export { ReservedBitsError as a, UnknownHashVariantError as c, Frame as i, UnknownVersionError as l, ChecksumError as n, SerializationError as o, FilterJSON as r, TruncatedError as s, BadMagicError as t, readFrameAt as u };
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
//#region src/core/bytes.d.ts
|
|
2
|
-
type BytesLike = string | Uint8Array | ArrayBuffer;
|
|
3
|
-
//#endregion
|
|
4
1
|
//#region src/core/serialize.d.ts
|
|
5
2
|
/**
|
|
6
3
|
* Base class for every defect `fromBytes` and `fromJSON` reject. Thrown
|
|
@@ -38,22 +35,36 @@ declare class BadMagicError extends SerializationError {
|
|
|
38
35
|
}
|
|
39
36
|
/**
|
|
40
37
|
* Thrown when a frame or JSON envelope declares a format version this release
|
|
41
|
-
* does not read.
|
|
42
|
-
* `distillate`
|
|
38
|
+
* does not read. The remedy depends on which side is older. A frame newer than
|
|
39
|
+
* this release needs `distillate` upgraded on the reading side. A frame older
|
|
40
|
+
* than it is readable by no current release, since each reads exactly one
|
|
41
|
+
* format version; rebuild it from the source keys. Being at least as new as
|
|
42
|
+
* the producer is necessary, not sufficient.
|
|
43
43
|
*/
|
|
44
44
|
declare class UnknownVersionError extends SerializationError {
|
|
45
45
|
/** Discriminates this error from other `Error`s. */
|
|
46
46
|
override readonly name = "UnknownVersionError";
|
|
47
47
|
}
|
|
48
48
|
/**
|
|
49
|
-
* Thrown when a frame's flags nibble names a hash
|
|
50
|
-
* reproduce, so its stored bits are unreadable. Rebuild the filter from the
|
|
49
|
+
* Thrown when a frame's flags nibble names a hash or index mapping this
|
|
50
|
+
* release cannot reproduce, so its stored bits are unreadable. Rebuild the filter from the
|
|
51
51
|
* source keys with the version you run.
|
|
52
52
|
*/
|
|
53
53
|
declare class UnknownHashVariantError extends SerializationError {
|
|
54
54
|
/** Discriminates this error from other `Error`s. */
|
|
55
55
|
override readonly name = "UnknownHashVariantError";
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Thrown when a frame sets a header bit this format reserves: the flags high
|
|
59
|
+
* nibble, the byte at offset 7, or the word at offset 12. Only a newer writer
|
|
60
|
+
* puts anything there, and reading its frame under this release's meaning
|
|
61
|
+
* would give a wrong answer with no error. Upgrade `distillate` on the reading
|
|
62
|
+
* side; a reader must be at least as new as the producer.
|
|
63
|
+
*/
|
|
64
|
+
declare class ReservedBitsError extends SerializationError {
|
|
65
|
+
/** Discriminates this error from other `Error`s. */
|
|
66
|
+
override readonly name = "ReservedBitsError";
|
|
67
|
+
}
|
|
57
68
|
/**
|
|
58
69
|
* Thrown when a frame's CRC32 trailer does not match its contents, so the
|
|
59
70
|
* bytes were corrupted after they were written. Discard them and re-fetch;
|
|
@@ -72,5 +83,30 @@ interface FilterJSON {
|
|
|
72
83
|
/** Base64 of the `toBytes` frame. */
|
|
73
84
|
data: string;
|
|
74
85
|
}
|
|
86
|
+
/** One frame read in place from a larger buffer by {@link readFrameAt}. */
|
|
87
|
+
interface Frame {
|
|
88
|
+
/** Binary format version. */
|
|
89
|
+
version: number;
|
|
90
|
+
/** Structure type code; one this release does not implement still reads. */
|
|
91
|
+
type: number;
|
|
92
|
+
/** Header flags byte; the low nibble is the hash variant. */
|
|
93
|
+
flags: number;
|
|
94
|
+
/** The body, a view into the source buffer rather than a copy. */
|
|
95
|
+
body: Uint8Array;
|
|
96
|
+
/** Bytes the whole frame occupies, so `offset + byteLength` is the next one. */
|
|
97
|
+
byteLength: number;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Reads and validates the frame starting at `offset` in `bytes`, which may
|
|
101
|
+
* hold further frames after it: magic, version, declared length, CRC32 and
|
|
102
|
+
* reserved bits, without needing to know the structure type. Advance by the
|
|
103
|
+
* returned `byteLength` to walk a buffer of concatenated frames.
|
|
104
|
+
*
|
|
105
|
+
* @throws TruncatedError when the frame runs past the end of `bytes`.
|
|
106
|
+
* @throws BadMagicError, UnknownVersionError, ChecksumError or
|
|
107
|
+
* ReservedBitsError when the frame at `offset` is not one this release reads.
|
|
108
|
+
* @throws RangeError when `offset` is not a non-negative integer.
|
|
109
|
+
*/
|
|
110
|
+
declare function readFrameAt(bytes: Uint8Array, offset: number): Frame;
|
|
75
111
|
//#endregion
|
|
76
|
-
export {
|
|
112
|
+
export { ReservedBitsError as a, UnknownHashVariantError as c, Frame as i, UnknownVersionError as l, ChecksumError as n, SerializationError as o, FilterJSON as r, TruncatedError as s, BadMagicError as t, readFrameAt as u };
|
|
@@ -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
|
+
});
|