distillate 0.5.0 → 0.7.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.
@@ -1,17 +1,12 @@
1
- import { a as readHeader, i as assertMinBodyLength, n as UnknownHashVariantError, o as writeHeader, p as probeInto, r as assertBodyLength, t as SerializationError } from "../serialize-BQ2UzZqq.js";
2
- import { a as assertUint32, i as assertProbability, r as assertPositiveInt, t as ParamError } from "../params-ChTRNxM9.js";
1
+ import { a as bytesEqual, c as toJSONEnvelope, g as probeInto, i as assertMinBodyLength, l as writeFrame, n as UnknownHashVariantError, o as fromJSONEnvelope, r as assertBodyLength, s as readHeader, t as SerializationError } from "../serialize-BnwtzcMw.js";
2
+ import { a as assertUint16, i as assertProbability, o as assertUint32, r as assertPositiveInt, t as ParamError } from "../params-BrWuBC2A.js";
3
3
  //#region src/core/bitset.ts
4
4
  var BitSetRangeError = class extends RangeError {
5
5
  name = "BitSetRangeError";
6
6
  };
7
7
  const MAX_BITS = 2 ** 32;
8
- var BitSet = class BitSet {
8
+ var BitSet = class {
9
9
  #bits;
10
- static fromBytes(bytes) {
11
- const bs = new BitSet(bytes.length * 8);
12
- bs.#bits.set(bytes);
13
- return bs;
14
- }
15
10
  constructor(nbits) {
16
11
  if (nbits > MAX_BITS) throw new BitSetRangeError(`BitSet capacity ${String(nbits)} exceeds the 2^32-bit limit`);
17
12
  this.#bits = new Uint8Array(Math.ceil(nbits / 8));
@@ -38,7 +33,7 @@ var BitSet = class BitSet {
38
33
  //#endregion
39
34
  //#region src/core/sizing.ts
40
35
  /** Optimal Bloom-filter sizing: `m` bits and `k` hashes for `n` items at target FPR `epsilon`. */
41
- function optimal(n, epsilon) {
36
+ function bloomSizing(n, epsilon) {
42
37
  const m = Math.ceil(-n * Math.log(epsilon) / (Math.LN2 * Math.LN2));
43
38
  return {
44
39
  m,
@@ -81,9 +76,23 @@ var BloomFilter = class BloomFilter {
81
76
  */
82
77
  static create(n, epsilon) {
83
78
  assertPositiveInt(n, "n");
79
+ assertUint32(n, "n");
84
80
  assertProbability(epsilon, "epsilon");
85
- const f = new BloomFilter(optimal(n, epsilon));
86
- f.#n = n;
81
+ return BloomFilter.#withN(bloomSizing(n, epsilon), n);
82
+ }
83
+ /**
84
+ * Builds a filter from `keys`, sized for their count at the target
85
+ * false-positive rate. The ergonomic entry point when the key set is already
86
+ * in hand; use {@link BloomFilter.create} to size for a count known ahead.
87
+ *
88
+ * @param keys - The keys to insert.
89
+ * @param epsilon - Target false-positive rate, e.g. `0.01` for 1%.
90
+ * @returns A new filter containing every key.
91
+ */
92
+ static from(keys, epsilon) {
93
+ const arr = [...keys];
94
+ const f = BloomFilter.create(Math.max(1, arr.length), epsilon);
95
+ for (const k of arr) f.add(k);
87
96
  return f;
88
97
  }
89
98
  /**
@@ -95,7 +104,7 @@ var BloomFilter = class BloomFilter {
95
104
  static fromBytes(bytes) {
96
105
  const { type, flags, body } = readHeader(bytes);
97
106
  if (type !== TYPE) throw new SerializationError(`expected AMQF type ${String(TYPE)}, got ${String(type)}`);
98
- if ((flags & 15) !== 1) throw new UnknownHashVariantError(`unsupported hash variant ${String(flags & 15)}`);
107
+ if ((flags & 15) !== 0) throw new UnknownHashVariantError(`unsupported hash variant ${String(flags & 15)}`);
99
108
  assertMinBodyLength(body.length, 14, "bloom");
100
109
  const dv = new DataView(body.buffer, body.byteOffset, body.byteLength);
101
110
  const m = dv.getUint32(0, true);
@@ -103,12 +112,11 @@ var BloomFilter = class BloomFilter {
103
112
  const seed = dv.getUint32(6, true);
104
113
  const n = dv.getUint32(10, true);
105
114
  assertBodyLength(body.length, 14 + Math.ceil(m / 8), "bloom");
106
- const f = new BloomFilter({
115
+ const f = BloomFilter.#withN({
107
116
  m,
108
117
  k,
109
118
  seed
110
- });
111
- f.#n = n;
119
+ }, n);
112
120
  f.#bits.bytes.set(body.subarray(14));
113
121
  return f;
114
122
  }
@@ -118,7 +126,9 @@ var BloomFilter = class BloomFilter {
118
126
  */
119
127
  constructor({ m, k, seed = 0 }) {
120
128
  assertPositiveInt(m, "m");
129
+ assertUint32(m, "m");
121
130
  assertPositiveInt(k, "k");
131
+ assertUint16(k, "k");
122
132
  assertUint32(seed, "seed");
123
133
  this.#bits = new BitSet(m);
124
134
  this.#m = m;
@@ -127,6 +137,11 @@ var BloomFilter = class BloomFilter {
127
137
  this.#scratch = new Uint32Array(k);
128
138
  this.#n = Math.round(m * Math.LN2 / k);
129
139
  }
140
+ static #withN(params, n) {
141
+ const f = new BloomFilter(params);
142
+ f.#n = n;
143
+ return f;
144
+ }
130
145
  /** Number of bits in the filter. */
131
146
  get m() {
132
147
  return this.#m;
@@ -164,18 +179,45 @@ var BloomFilter = class BloomFilter {
164
179
  */
165
180
  toBytes() {
166
181
  const payload = this.#bits.bytes;
167
- const body = new Uint8Array(14 + payload.length);
168
- const dv = new DataView(body.buffer, body.byteOffset, body.byteLength);
169
- dv.setUint32(0, this.#m, true);
170
- dv.setUint16(4, this.#k, true);
171
- dv.setUint32(6, this.#seed, true);
172
- dv.setUint32(10, this.#n, true);
173
- body.set(payload, 14);
174
- return writeHeader({
175
- version: 2,
182
+ return writeFrame({
183
+ version: 3,
176
184
  type: TYPE,
177
- flags: 1
178
- }, body);
185
+ flags: 0
186
+ }, 14 + payload.length, (body, dv) => {
187
+ dv.setUint32(0, this.#m, true);
188
+ dv.setUint16(4, this.#k, true);
189
+ dv.setUint32(6, this.#seed, true);
190
+ dv.setUint32(10, this.#n, true);
191
+ body.set(payload, 14);
192
+ });
193
+ }
194
+ /**
195
+ * Tests structural equality: `true` when `other` serializes to identical
196
+ * bytes, meaning identical parameters and set bits.
197
+ *
198
+ * @param other - The filter to compare against.
199
+ * @returns `true` if the two filters are byte-for-byte identical.
200
+ */
201
+ equals(other) {
202
+ return bytesEqual(this.toBytes(), other.toBytes());
203
+ }
204
+ /**
205
+ * Serializes the filter to a JSON-friendly envelope wrapping the base64 of
206
+ * {@link BloomFilter.toBytes}.
207
+ *
208
+ * @returns The envelope, readable by {@link BloomFilter.fromJSON}.
209
+ */
210
+ toJSON() {
211
+ return toJSONEnvelope(this.toBytes());
212
+ }
213
+ /**
214
+ * Restores a filter from its {@link BloomFilter.toJSON} envelope.
215
+ *
216
+ * @param value - The JSON envelope.
217
+ * @returns The reconstructed filter.
218
+ */
219
+ static fromJSON(value) {
220
+ return BloomFilter.fromBytes(fromJSONEnvelope(value));
179
221
  }
180
222
  /**
181
223
  * Returns a new filter containing the union of this filter and `other`.
@@ -190,11 +232,11 @@ var BloomFilter = class BloomFilter {
190
232
  const b = other.#bits.bytes;
191
233
  const merged = new Uint8Array(a.length);
192
234
  for (let i = 0; i < a.length; i++) merged[i] = (a[i] ?? 0) | (b[i] ?? 0);
193
- const r = new BloomFilter({
235
+ const r = BloomFilter.#withN({
194
236
  m: this.#m,
195
237
  k: this.#k,
196
238
  seed: this.#seed
197
- });
239
+ }, this.#n);
198
240
  r.#bits.bytes.set(merged);
199
241
  return r;
200
242
  }
@@ -220,4 +262,4 @@ var BloomFilter = class BloomFilter {
220
262
  }
221
263
  };
222
264
  //#endregion
223
- export { BloomFilter, BloomParamMismatchError, ParamError };
265
+ export { BloomFilter, BloomParamMismatchError, ParamError, bloomSizing };
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_serialize = require("../serialize-fa-pEUGq.cjs");
2
+ const require_serialize = require("../serialize-BIIKUHH6.cjs");
3
3
  //#region src/fuse/fuse.ts
4
4
  const ARITY = 3;
5
5
  const TYPE_FUSE8 = 3;
@@ -10,10 +10,10 @@ var BinaryFuseBuildError = class extends Error {
10
10
  name = "BinaryFuseBuildError";
11
11
  };
12
12
  const scratchHash = {
13
- h1lo: 0,
14
- h1hi: 0,
15
- h2lo: 0,
16
- h2hi: 0
13
+ w0: 0,
14
+ w1: 0,
15
+ w2: 0,
16
+ w3: 0
17
17
  };
18
18
  function mixSeed(lo, hi, seed) {
19
19
  const l = (lo >>> 0) + (seed >>> 0);
@@ -60,6 +60,19 @@ function computeParams(size) {
60
60
  };
61
61
  }
62
62
  /**
63
+ * Bits stored per key by a binary fuse filter over `n` keys at a fingerprint
64
+ * width, without building one. Counts `n` as distinct keys, since a built
65
+ * filter sizes on its deduped hash count.
66
+ *
67
+ * @param n - Number of distinct keys.
68
+ * @param width - Fingerprint width in bits: `8` for {@link BinaryFuse8}, `16` for {@link BinaryFuse16}.
69
+ * @returns Bits per key (`0` for an empty filter).
70
+ */
71
+ function fuseBitsPerKey(n, width) {
72
+ if (n === 0) return 0;
73
+ return computeParams(n).arrayLength * width / n;
74
+ }
75
+ /**
63
76
  * Peel the 3-hypergraph and assign fingerprints so every key's XOR of its 3
64
77
  * lanes equals its fingerprint. Retries with a bumped seed on a stall; returns
65
78
  * the seed that succeeded.
@@ -136,8 +149,8 @@ function buildState(keys, alloc) {
136
149
  const seen = /* @__PURE__ */ new Set();
137
150
  for (const key of keys) {
138
151
  require_serialize.hash128KeyInto(key, 0, scratchHash);
139
- const lo = scratchHash.h1lo >>> 0;
140
- const hi = scratchHash.h1hi >>> 0;
152
+ const lo = scratchHash.w0 >>> 0;
153
+ const hi = scratchHash.w1 >>> 0;
141
154
  const id = `${String(lo)},${String(hi)}`;
142
155
  if (seen.has(id)) continue;
143
156
  seen.add(id);
@@ -161,14 +174,17 @@ function buildState(keys, alloc) {
161
174
  };
162
175
  }
163
176
  function fuseStateFromBytes(bytes, expectedType) {
164
- const { type, body } = require_serialize.readHeader(bytes);
177
+ const { type, flags, body } = require_serialize.readHeader(bytes);
165
178
  if (type !== expectedType) throw new require_serialize.SerializationError(`expected AMQF type ${String(expectedType)}, got ${String(type)}`);
179
+ if ((flags & 15) !== 0) throw new require_serialize.UnknownHashVariantError(`unsupported hash variant ${String(flags & 15)}`);
166
180
  require_serialize.assertMinBodyLength(body.length, 16, "fuse");
167
181
  const dv = new DataView(body.buffer, body.byteOffset, body.byteLength);
168
182
  const seed = dv.getUint32(0, true);
169
183
  const seg = dv.getUint32(4, true);
170
184
  const segCountLen = dv.getUint32(8, true);
171
185
  const size = dv.getUint32(12, true);
186
+ if (seg === 0 || (seg & seg - 1) !== 0 || seg > 1 << 18) throw new require_serialize.SerializationError(`invalid fuse segment length ${String(seg)}`);
187
+ if (segCountLen % seg !== 0) throw new require_serialize.SerializationError(`fuse segment count length ${String(segCountLen)} is not a multiple of segment length ${String(seg)}`);
172
188
  const bpe = expectedType === TYPE_FUSE8 ? 1 : 2;
173
189
  const expectedArrayLength = size === 0 ? 0 : segCountLen + 2 * seg;
174
190
  require_serialize.assertBodyLength(body.length, 16 + expectedArrayLength * bpe, "fuse");
@@ -212,6 +228,10 @@ var BinaryFuse = class {
212
228
  get size() {
213
229
  return this.#size;
214
230
  }
231
+ /** Hash seed selected during construction (may differ from 0 after a peel retry). */
232
+ get seed() {
233
+ return this.#seed;
234
+ }
215
235
  /** Actual bits stored per key (`0` for an empty filter). */
216
236
  get bitsPerKey() {
217
237
  return this.#size === 0 ? 0 : this.#fp.byteLength * 8 / this.#size;
@@ -223,18 +243,17 @@ var BinaryFuse = class {
223
243
  */
224
244
  toBytes() {
225
245
  const laneBytes = new Uint8Array(this.#fp.buffer, this.#fp.byteOffset, this.#fp.byteLength);
226
- const body = new Uint8Array(16 + laneBytes.length);
227
- const dv = new DataView(body.buffer);
228
- dv.setUint32(0, this.#seed, true);
229
- dv.setUint32(4, this.#seg, true);
230
- dv.setUint32(8, this.#segCountLen, true);
231
- dv.setUint32(12, this.#size, true);
232
- body.set(laneBytes, 16);
233
- return require_serialize.writeHeader({
234
- version: 2,
246
+ return require_serialize.writeFrame({
247
+ version: 3,
235
248
  type: this.#fp.BYTES_PER_ELEMENT === 1 ? TYPE_FUSE8 : TYPE_FUSE16,
236
249
  flags: 0
237
- }, body);
250
+ }, 16 + laneBytes.length, (body, dv) => {
251
+ dv.setUint32(0, this.#seed, true);
252
+ dv.setUint32(4, this.#seg, true);
253
+ dv.setUint32(8, this.#segCountLen, true);
254
+ dv.setUint32(12, this.#size, true);
255
+ body.set(laneBytes, 16);
256
+ });
238
257
  }
239
258
  /**
240
259
  * Tests whether a key is in the set.
@@ -245,7 +264,7 @@ var BinaryFuse = class {
245
264
  has(key) {
246
265
  if (this.#fp.length === 0) return false;
247
266
  require_serialize.hash128KeyInto(key, 0, scratchHash);
248
- mixSeed(scratchHash.h1lo >>> 0, scratchHash.h1hi >>> 0, this.#seed);
267
+ mixSeed(scratchHash.w0 >>> 0, scratchHash.w1 >>> 0, this.#seed);
249
268
  const mlo = require_serialize.RLO;
250
269
  const mhi = require_serialize.RHI;
251
270
  positionsInto(mlo, mhi, this.#seg, this.#segMask, this.#segCountLen, this.#pos);
@@ -255,6 +274,26 @@ var BinaryFuse = class {
255
274
  const p2 = this.#pos[2] ?? 0;
256
275
  return ((mlo ^ mhi) & mask) === (((this.#fp[p0] ?? 0) ^ (this.#fp[p1] ?? 0) ^ (this.#fp[p2] ?? 0)) & mask);
257
276
  }
277
+ /**
278
+ * Tests structural equality: `true` when `other` serializes to identical
279
+ * bytes. A {@link BinaryFuse8} and a {@link BinaryFuse16} are never equal,
280
+ * since their frames carry different type bytes.
281
+ *
282
+ * @param other - The filter to compare against.
283
+ * @returns `true` if the two filters are byte-for-byte identical.
284
+ */
285
+ equals(other) {
286
+ return require_serialize.bytesEqual(this.toBytes(), other.toBytes());
287
+ }
288
+ /**
289
+ * Serializes the filter to a JSON-friendly envelope wrapping the base64 of
290
+ * the `toBytes` frame.
291
+ *
292
+ * @returns The envelope, readable by the matching `fromJSON`.
293
+ */
294
+ toJSON() {
295
+ return require_serialize.toJSONEnvelope(this.toBytes());
296
+ }
258
297
  };
259
298
  /**
260
299
  * A static 8-bit binary fuse filter: built once from a key set, then immutable.
@@ -287,6 +326,15 @@ var BinaryFuse8 = class BinaryFuse8 extends BinaryFuse {
287
326
  static fromBytes(bytes) {
288
327
  return new BinaryFuse8(fuseStateFromBytes(bytes, TYPE_FUSE8));
289
328
  }
329
+ /**
330
+ * Restores a filter from its {@link BinaryFuse8.toJSON} envelope.
331
+ *
332
+ * @param value - The JSON envelope.
333
+ * @returns The reconstructed filter.
334
+ */
335
+ static fromJSON(value) {
336
+ return BinaryFuse8.fromBytes(require_serialize.fromJSONEnvelope(value));
337
+ }
290
338
  };
291
339
  /**
292
340
  * A static 16-bit binary fuse filter: like {@link BinaryFuse8} but twice the
@@ -318,8 +366,18 @@ var BinaryFuse16 = class BinaryFuse16 extends BinaryFuse {
318
366
  static fromBytes(bytes) {
319
367
  return new BinaryFuse16(fuseStateFromBytes(bytes, TYPE_FUSE16));
320
368
  }
369
+ /**
370
+ * Restores a filter from its {@link BinaryFuse16.toJSON} envelope.
371
+ *
372
+ * @param value - The JSON envelope.
373
+ * @returns The reconstructed filter.
374
+ */
375
+ static fromJSON(value) {
376
+ return BinaryFuse16.fromBytes(require_serialize.fromJSONEnvelope(value));
377
+ }
321
378
  };
322
379
  //#endregion
323
380
  exports.BinaryFuse16 = BinaryFuse16;
324
381
  exports.BinaryFuse8 = BinaryFuse8;
325
382
  exports.BinaryFuseBuildError = BinaryFuseBuildError;
383
+ exports.fuseBitsPerKey = fuseBitsPerKey;
@@ -1,4 +1,4 @@
1
- import { t as BytesLike } from "../bytes-DCuYtUVS.cjs";
1
+ import { n as BytesLike, t as FilterJSON } from "../serialize-DRKh6QOr.cjs";
2
2
  //#region src/fuse/fuse.d.ts
3
3
  /** Thrown when binary fuse construction fails to converge on the key set. */
4
4
  declare class BinaryFuseBuildError extends Error {
@@ -11,6 +11,16 @@ interface FuseParams {
11
11
  segCountLen: number;
12
12
  arrayLength: number;
13
13
  }
14
+ /**
15
+ * Bits stored per key by a binary fuse filter over `n` keys at a fingerprint
16
+ * width, without building one. Counts `n` as distinct keys, since a built
17
+ * filter sizes on its deduped hash count.
18
+ *
19
+ * @param n - Number of distinct keys.
20
+ * @param width - Fingerprint width in bits: `8` for {@link BinaryFuse8}, `16` for {@link BinaryFuse16}.
21
+ * @returns Bits per key (`0` for an empty filter).
22
+ */
23
+ declare function fuseBitsPerKey(n: number, width: 8 | 16): number;
14
24
  interface FuseState {
15
25
  fp: Uint8Array | Uint16Array;
16
26
  seed: number;
@@ -26,6 +36,8 @@ declare abstract class BinaryFuse {
26
36
  protected constructor(state: FuseState);
27
37
  /** Number of distinct keys the filter was built from. */
28
38
  get size(): number;
39
+ /** Hash seed selected during construction (may differ from 0 after a peel retry). */
40
+ get seed(): number;
29
41
  /** Actual bits stored per key (`0` for an empty filter). */
30
42
  get bitsPerKey(): number;
31
43
  /**
@@ -41,6 +53,22 @@ declare abstract class BinaryFuse {
41
53
  * @returns `true` if present (possibly a false positive); `false` guarantees absence.
42
54
  */
43
55
  has(key: BytesLike): boolean;
56
+ /**
57
+ * Tests structural equality: `true` when `other` serializes to identical
58
+ * bytes. A {@link BinaryFuse8} and a {@link BinaryFuse16} are never equal,
59
+ * since their frames carry different type bytes.
60
+ *
61
+ * @param other - The filter to compare against.
62
+ * @returns `true` if the two filters are byte-for-byte identical.
63
+ */
64
+ equals(other: BinaryFuse8 | BinaryFuse16): boolean;
65
+ /**
66
+ * Serializes the filter to a JSON-friendly envelope wrapping the base64 of
67
+ * the `toBytes` frame.
68
+ *
69
+ * @returns The envelope, readable by the matching `fromJSON`.
70
+ */
71
+ toJSON(): FilterJSON;
44
72
  }
45
73
  /**
46
74
  * A static 8-bit binary fuse filter: built once from a key set, then immutable.
@@ -69,6 +97,13 @@ declare class BinaryFuse8 extends BinaryFuse {
69
97
  * @returns The reconstructed filter.
70
98
  */
71
99
  static fromBytes(bytes: Uint8Array): BinaryFuse8;
100
+ /**
101
+ * Restores a filter from its {@link BinaryFuse8.toJSON} envelope.
102
+ *
103
+ * @param value - The JSON envelope.
104
+ * @returns The reconstructed filter.
105
+ */
106
+ static fromJSON(value: unknown): BinaryFuse8;
72
107
  }
73
108
  /**
74
109
  * A static 16-bit binary fuse filter: like {@link BinaryFuse8} but twice the
@@ -96,6 +131,13 @@ declare class BinaryFuse16 extends BinaryFuse {
96
131
  * @returns The reconstructed filter.
97
132
  */
98
133
  static fromBytes(bytes: Uint8Array): BinaryFuse16;
134
+ /**
135
+ * Restores a filter from its {@link BinaryFuse16.toJSON} envelope.
136
+ *
137
+ * @param value - The JSON envelope.
138
+ * @returns The reconstructed filter.
139
+ */
140
+ static fromJSON(value: unknown): BinaryFuse16;
99
141
  }
100
142
  //#endregion
101
- export { BinaryFuse16, BinaryFuse8, BinaryFuseBuildError };
143
+ export { BinaryFuse16, BinaryFuse8, BinaryFuseBuildError, type FilterJSON, fuseBitsPerKey };
@@ -1,4 +1,4 @@
1
- import { t as BytesLike } from "../bytes-DCuYtUVS.js";
1
+ import { n as BytesLike, t as FilterJSON } from "../serialize-DRKh6QOr.js";
2
2
  //#region src/fuse/fuse.d.ts
3
3
  /** Thrown when binary fuse construction fails to converge on the key set. */
4
4
  declare class BinaryFuseBuildError extends Error {
@@ -11,6 +11,16 @@ interface FuseParams {
11
11
  segCountLen: number;
12
12
  arrayLength: number;
13
13
  }
14
+ /**
15
+ * Bits stored per key by a binary fuse filter over `n` keys at a fingerprint
16
+ * width, without building one. Counts `n` as distinct keys, since a built
17
+ * filter sizes on its deduped hash count.
18
+ *
19
+ * @param n - Number of distinct keys.
20
+ * @param width - Fingerprint width in bits: `8` for {@link BinaryFuse8}, `16` for {@link BinaryFuse16}.
21
+ * @returns Bits per key (`0` for an empty filter).
22
+ */
23
+ declare function fuseBitsPerKey(n: number, width: 8 | 16): number;
14
24
  interface FuseState {
15
25
  fp: Uint8Array | Uint16Array;
16
26
  seed: number;
@@ -26,6 +36,8 @@ declare abstract class BinaryFuse {
26
36
  protected constructor(state: FuseState);
27
37
  /** Number of distinct keys the filter was built from. */
28
38
  get size(): number;
39
+ /** Hash seed selected during construction (may differ from 0 after a peel retry). */
40
+ get seed(): number;
29
41
  /** Actual bits stored per key (`0` for an empty filter). */
30
42
  get bitsPerKey(): number;
31
43
  /**
@@ -41,6 +53,22 @@ declare abstract class BinaryFuse {
41
53
  * @returns `true` if present (possibly a false positive); `false` guarantees absence.
42
54
  */
43
55
  has(key: BytesLike): boolean;
56
+ /**
57
+ * Tests structural equality: `true` when `other` serializes to identical
58
+ * bytes. A {@link BinaryFuse8} and a {@link BinaryFuse16} are never equal,
59
+ * since their frames carry different type bytes.
60
+ *
61
+ * @param other - The filter to compare against.
62
+ * @returns `true` if the two filters are byte-for-byte identical.
63
+ */
64
+ equals(other: BinaryFuse8 | BinaryFuse16): boolean;
65
+ /**
66
+ * Serializes the filter to a JSON-friendly envelope wrapping the base64 of
67
+ * the `toBytes` frame.
68
+ *
69
+ * @returns The envelope, readable by the matching `fromJSON`.
70
+ */
71
+ toJSON(): FilterJSON;
44
72
  }
45
73
  /**
46
74
  * A static 8-bit binary fuse filter: built once from a key set, then immutable.
@@ -69,6 +97,13 @@ declare class BinaryFuse8 extends BinaryFuse {
69
97
  * @returns The reconstructed filter.
70
98
  */
71
99
  static fromBytes(bytes: Uint8Array): BinaryFuse8;
100
+ /**
101
+ * Restores a filter from its {@link BinaryFuse8.toJSON} envelope.
102
+ *
103
+ * @param value - The JSON envelope.
104
+ * @returns The reconstructed filter.
105
+ */
106
+ static fromJSON(value: unknown): BinaryFuse8;
72
107
  }
73
108
  /**
74
109
  * A static 16-bit binary fuse filter: like {@link BinaryFuse8} but twice the
@@ -96,6 +131,13 @@ declare class BinaryFuse16 extends BinaryFuse {
96
131
  * @returns The reconstructed filter.
97
132
  */
98
133
  static fromBytes(bytes: Uint8Array): BinaryFuse16;
134
+ /**
135
+ * Restores a filter from its {@link BinaryFuse16.toJSON} envelope.
136
+ *
137
+ * @param value - The JSON envelope.
138
+ * @returns The reconstructed filter.
139
+ */
140
+ static fromJSON(value: unknown): BinaryFuse16;
99
141
  }
100
142
  //#endregion
101
- export { BinaryFuse16, BinaryFuse8, BinaryFuseBuildError };
143
+ export { BinaryFuse16, BinaryFuse8, BinaryFuseBuildError, type FilterJSON, fuseBitsPerKey };