distillate 0.9.0 → 0.11.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 +44 -6
  2. package/dist/bitset-Cf2jwRJX.js +32 -0
  3. package/dist/bitset-QYGqxnEf.cjs +37 -0
  4. package/dist/blocked/index.cjs +14 -9
  5. package/dist/blocked/index.d.cts +7 -6
  6. package/dist/blocked/index.d.ts +7 -6
  7. package/dist/blocked/index.js +12 -8
  8. package/dist/bloom/index.cjs +16 -41
  9. package/dist/bloom/index.d.cts +5 -4
  10. package/dist/bloom/index.d.ts +5 -4
  11. package/dist/bloom/index.js +13 -39
  12. package/dist/bytes-DCuYtUVS.d.cts +4 -0
  13. package/dist/bytes-DCuYtUVS.d.ts +4 -0
  14. package/dist/frame/index.cjs +9 -0
  15. package/dist/frame/index.d.cts +2 -0
  16. package/dist/frame/index.d.ts +2 -0
  17. package/dist/frame/index.js +2 -0
  18. package/dist/fuse/index.cjs +26 -22
  19. package/dist/fuse/index.d.cts +7 -6
  20. package/dist/fuse/index.d.ts +7 -6
  21. package/dist/fuse/index.js +14 -11
  22. package/dist/hasher-3Cyn7Yg-.js +230 -0
  23. package/dist/hasher-MhY7aQ8F.cjs +289 -0
  24. package/dist/hll/index.cjs +12 -8
  25. package/dist/hll/index.d.cts +4 -3
  26. package/dist/hll/index.d.ts +4 -3
  27. package/dist/hll/index.js +11 -8
  28. package/dist/index.cjs +1 -1
  29. package/dist/index.d.cts +2 -3
  30. package/dist/index.d.ts +2 -3
  31. package/dist/index.js +1 -1
  32. package/dist/scalable/index.cjs +340 -0
  33. package/dist/scalable/index.d.cts +173 -0
  34. package/dist/scalable/index.d.ts +173 -0
  35. package/dist/scalable/index.js +330 -0
  36. package/dist/{serialize-Bv1zWzrh.d.cts → serialize--xR6vGSW.d.cts} +44 -8
  37. package/dist/{serialize-Bv1zWzrh.d.ts → serialize--xR6vGSW.d.ts} +44 -8
  38. package/dist/serialize-CHikZ4GH.cjs +296 -0
  39. package/dist/serialize-CMSYFym-.js +201 -0
  40. package/package.json +25 -9
  41. package/dist/serialize-D59Ri81a.js +0 -392
  42. package/dist/serialize-Ul2LKFJU.cjs +0 -517
@@ -0,0 +1,340 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_bitset = require("../bitset-QYGqxnEf.cjs");
3
+ const require_hasher = require("../hasher-MhY7aQ8F.cjs");
4
+ const require_serialize = require("../serialize-CHikZ4GH.cjs");
5
+ const require_params = require("../params-UTZbJ22c.cjs");
6
+ const require_sizing = require("../sizing-BLzZk2zr.cjs");
7
+ //#region src/scalable/scalable.ts
8
+ const MAX_BITS = 4294967295;
9
+ const TYPE = 6;
10
+ const PARAMS_SIZE = 40;
11
+ const ENTRY_SIZE = 16;
12
+ const padded8 = (bytes) => Math.ceil(bytes / 8) * 8;
13
+ let restoring;
14
+ var ScalableParamMismatchError = class extends Error {
15
+ name = "ScalableParamMismatchError";
16
+ };
17
+ function readTable(view, stageCount) {
18
+ const entries = [];
19
+ for (let i = 0; i < stageCount; i++) {
20
+ const at = PARAMS_SIZE + ENTRY_SIZE * i;
21
+ const entry = {
22
+ m: view.getUint32(at, true),
23
+ k: view.getUint16(at + 4, true),
24
+ capacity: view.getUint32(at + 8, true),
25
+ count: view.getUint32(at + 12, true)
26
+ };
27
+ if (view.getUint16(at + 6, true) !== 0) throw new require_serialize.SerializationError(`scalable: stage ${String(i)} table padding is not zero`);
28
+ if (entry.m === 0 || entry.k === 0 || entry.capacity === 0) throw new require_serialize.SerializationError(`scalable: stage ${String(i)} declares m=${String(entry.m)}, k=${String(entry.k)}, capacity=${String(entry.capacity)}; all must be positive`);
29
+ if (entry.count > entry.capacity) throw new require_serialize.SerializationError(`scalable: stage ${String(i)} holds ${String(entry.count)} keys, above its capacity of ${String(entry.capacity)}`);
30
+ entries.push(entry);
31
+ }
32
+ return entries;
33
+ }
34
+ function readStages(body, entries, start) {
35
+ let at = start;
36
+ return entries.map((entry, i) => {
37
+ const length = Math.ceil(entry.m / 8);
38
+ const bits = new require_bitset.BitSet(entry.m);
39
+ bits.bytes.set(body.subarray(at, at + length));
40
+ for (let j = at + length; j < at + padded8(length); j++) if (body[j] !== 0) throw new require_serialize.SerializationError(`scalable: stage ${String(i)} bit padding is not zero`);
41
+ at += padded8(length);
42
+ return {
43
+ ...entry,
44
+ bits
45
+ };
46
+ });
47
+ }
48
+ var ScalableBloomFilter = class ScalableBloomFilter {
49
+ #n;
50
+ #epsilon;
51
+ #growth;
52
+ #tightening;
53
+ #seed;
54
+ #stages = [];
55
+ #hash = {
56
+ w0: 0,
57
+ w1: 0,
58
+ w2: 0,
59
+ w3: 0
60
+ };
61
+ #probes = new Uint32Array(0);
62
+ #newest;
63
+ static create(n, epsilon, options = {}) {
64
+ return new ScalableBloomFilter({
65
+ ...options,
66
+ n,
67
+ epsilon
68
+ });
69
+ }
70
+ static from(keys, epsilon, options = {}) {
71
+ const arr = [...keys];
72
+ const f = ScalableBloomFilter.create(Math.max(1, arr.length), epsilon, options);
73
+ for (const key of arr) f.add(key);
74
+ return f;
75
+ }
76
+ constructor({ n, epsilon, growth = 2, tightening = .85, seed = 0 }) {
77
+ require_params.assertPositiveInt(n, "n");
78
+ require_params.assertUint32(n, "n");
79
+ require_params.assertProbability(epsilon, "epsilon");
80
+ if (!Number.isFinite(growth) || growth <= 1) throw new require_params.ParamError(`growth must be a finite number greater than 1, got ${String(growth)}`);
81
+ require_params.assertProbability(tightening, "tightening");
82
+ require_params.assertUint32(seed, "seed");
83
+ this.#n = n;
84
+ this.#epsilon = epsilon;
85
+ this.#growth = growth;
86
+ this.#tightening = tightening;
87
+ this.#seed = seed;
88
+ if (restoring) {
89
+ this.#newest = this.#adopt(restoring);
90
+ return;
91
+ }
92
+ const first = this.#geometry(0);
93
+ if (first.m > MAX_BITS) throw new require_params.ParamError(`the first stage needs ${String(first.m)} bits, more than ${String(MAX_BITS)}`);
94
+ this.#newest = this.#open(first);
95
+ }
96
+ #geometry(i) {
97
+ const capacity = Math.ceil(this.#n * this.#growth ** i);
98
+ const target = this.#epsilon * (1 - this.#tightening) * this.#tightening ** i;
99
+ return {
100
+ capacity,
101
+ ...require_sizing.bloomSizing(capacity, target)
102
+ };
103
+ }
104
+ #open({ capacity, m, k }) {
105
+ const stage = {
106
+ bits: new require_bitset.BitSet(m),
107
+ m,
108
+ k,
109
+ capacity,
110
+ count: 0
111
+ };
112
+ this.#stages.push(stage);
113
+ if (k > this.#probes.length) this.#probes = new Uint32Array(k);
114
+ return stage;
115
+ }
116
+ #settingPairs(other) {
117
+ return [
118
+ [
119
+ "n",
120
+ this.#n,
121
+ other.#n
122
+ ],
123
+ [
124
+ "epsilon",
125
+ this.#epsilon,
126
+ other.#epsilon
127
+ ],
128
+ [
129
+ "growth",
130
+ this.#growth,
131
+ other.#growth
132
+ ],
133
+ [
134
+ "tightening",
135
+ this.#tightening,
136
+ other.#tightening
137
+ ],
138
+ [
139
+ "seed",
140
+ this.#seed,
141
+ other.#seed
142
+ ]
143
+ ];
144
+ }
145
+ #assertMergeable(other) {
146
+ for (const [name, a, b] of this.#settingPairs(other)) if (a !== b) throw new ScalableParamMismatchError(`cannot union scalable Bloom filters whose ${name} differs (${String(a)} vs ${String(b)})`);
147
+ this.#stages.forEach((s, i) => {
148
+ const t = other.#stages[i];
149
+ if (!t) return;
150
+ for (const field of [
151
+ "m",
152
+ "k",
153
+ "capacity"
154
+ ]) if (s[field] !== t[field]) throw new ScalableParamMismatchError(`cannot union scalable Bloom filters whose stage ${String(i)} ${field} differs (${String(s[field])} vs ${String(t[field])})`);
155
+ });
156
+ }
157
+ #adopt(stages) {
158
+ this.#stages.length = 0;
159
+ this.#stages.push(...stages);
160
+ const k = Math.max(...stages.map((s) => s.k));
161
+ if (k > this.#probes.length) this.#probes = new Uint32Array(k);
162
+ return stages.reduce((_, s) => s);
163
+ }
164
+ #probe(stage) {
165
+ require_hasher.probeLanesInto(this.#hash.w0, this.#hash.w1, stage.k, stage.m, this.#probes);
166
+ }
167
+ #holds(stage) {
168
+ const { w0, w1 } = this.#hash;
169
+ for (let i = 0; i < stage.k; i++) if (!stage.bits.get(require_hasher.probeAt(w0, w1, i, stage.m))) return false;
170
+ return true;
171
+ }
172
+ #anyHolds() {
173
+ for (let i = this.#stages.length - 1; i >= 0; i--) {
174
+ const stage = this.#stages[i];
175
+ if (stage && this.#holds(stage)) return true;
176
+ }
177
+ return false;
178
+ }
179
+ add(key) {
180
+ require_hasher.hash128KeyInto(key, this.#seed, this.#hash);
181
+ if (this.#anyHolds()) return;
182
+ if (this.#newest.count >= this.#newest.capacity) {
183
+ const i = this.#stages.length;
184
+ const next = this.#geometry(i);
185
+ if (next.m > MAX_BITS) throw new RangeError(`stage ${String(i)} needs ${String(next.m)} bits, more than ${String(MAX_BITS)}; the filter cannot grow further`);
186
+ this.#newest = this.#open(next);
187
+ }
188
+ const stage = this.#newest;
189
+ this.#probe(stage);
190
+ for (let i = 0; i < stage.k; i++) stage.bits.set(this.#probes[i] ?? 0);
191
+ stage.count++;
192
+ }
193
+ has(key) {
194
+ require_hasher.hash128KeyInto(key, this.#seed, this.#hash);
195
+ return this.#anyHolds();
196
+ }
197
+ rate() {
198
+ let miss = 1;
199
+ for (const s of this.#stages) miss *= 1 - (s.bits.count() / s.m) ** s.k;
200
+ return 1 - miss;
201
+ }
202
+ union(other) {
203
+ this.#assertMergeable(other);
204
+ const result = new ScalableBloomFilter({
205
+ n: this.#n,
206
+ epsilon: this.#epsilon,
207
+ growth: this.#growth,
208
+ tightening: this.#tightening,
209
+ seed: this.#seed
210
+ });
211
+ const [longer, shorter] = this.#stages.length >= other.#stages.length ? [this.#stages, other.#stages] : [other.#stages, this.#stages];
212
+ const stages = longer.map((stage, i) => {
213
+ const bits = new require_bitset.BitSet(stage.m);
214
+ bits.bytes.set(stage.bits.bytes);
215
+ const twin = shorter[i];
216
+ if (twin) {
217
+ const out = bits.bytes;
218
+ const bytes = twin.bits.bytes;
219
+ for (let j = 0; j < out.length; j++) out[j] = (out[j] ?? 0) | (bytes[j] ?? 0);
220
+ }
221
+ return {
222
+ bits,
223
+ m: stage.m,
224
+ k: stage.k,
225
+ capacity: stage.capacity,
226
+ count: Math.min(stage.capacity, stage.count + (twin?.count ?? 0))
227
+ };
228
+ });
229
+ result.#newest = result.#adopt(stages);
230
+ return result;
231
+ }
232
+ equals(other) {
233
+ if (this.#settingPairs(other).some(([, a, b]) => a !== b)) return false;
234
+ if (this.#stages.length !== other.#stages.length) return false;
235
+ return this.#stages.every((s, i) => {
236
+ const t = other.#stages[i];
237
+ if (!t) return false;
238
+ return s.m === t.m && s.k === t.k && s.capacity === t.capacity && s.count === t.count && require_serialize.bytesEqual(s.bits.bytes, t.bits.bytes);
239
+ });
240
+ }
241
+ static fromBytes(bytes) {
242
+ const { type, flags, body } = require_serialize.readHeader(bytes);
243
+ if (type !== TYPE) throw new require_serialize.SerializationError(`expected DSTL type ${String(TYPE)}, got ${String(type)}`);
244
+ if ((flags & 15) !== 0) throw new require_serialize.UnknownHashVariantError(`unsupported hash variant ${String(flags & 15)}`);
245
+ require_serialize.assertMinBodyLength(body.length, PARAMS_SIZE, "scalable");
246
+ require_serialize.assertParamsPadding(body, 36, PARAMS_SIZE, "scalable");
247
+ const view = new DataView(body.buffer, body.byteOffset, body.byteLength);
248
+ const stageCount = view.getUint32(32, true);
249
+ if (stageCount === 0) throw new require_serialize.SerializationError("scalable: frame declares no stages");
250
+ const tableEnd = PARAMS_SIZE + ENTRY_SIZE * stageCount;
251
+ require_serialize.assertMinBodyLength(body.length, tableEnd, "scalable");
252
+ const entries = readTable(view, stageCount);
253
+ const expected = entries.reduce((sum, e) => sum + padded8(Math.ceil(e.m / 8)), tableEnd);
254
+ require_serialize.assertBodyLength(body.length, expected, "scalable");
255
+ restoring = readStages(body, entries, tableEnd);
256
+ try {
257
+ return new ScalableBloomFilter({
258
+ n: view.getUint32(0, true),
259
+ seed: view.getUint32(4, true),
260
+ epsilon: view.getFloat64(8, true),
261
+ growth: view.getFloat64(16, true),
262
+ tightening: view.getFloat64(24, true)
263
+ });
264
+ } catch (err) {
265
+ if (err instanceof require_params.ParamError) throw new require_serialize.SerializationError(`scalable: ${err.message}`);
266
+ throw err;
267
+ } finally {
268
+ restoring = void 0;
269
+ }
270
+ }
271
+ toBytes() {
272
+ const payload = this.#stages.reduce((sum, s) => sum + ENTRY_SIZE + padded8(s.bits.bytes.length), 0);
273
+ return require_serialize.writeFrame({
274
+ version: 5,
275
+ type: TYPE,
276
+ flags: 0
277
+ }, PARAMS_SIZE, payload, (body, view) => {
278
+ view.setUint32(0, this.#n, true);
279
+ view.setUint32(4, this.#seed, true);
280
+ view.setFloat64(8, this.#epsilon, true);
281
+ view.setFloat64(16, this.#growth, true);
282
+ view.setFloat64(24, this.#tightening, true);
283
+ view.setUint32(32, this.#stages.length, true);
284
+ let at = PARAMS_SIZE + ENTRY_SIZE * this.#stages.length;
285
+ this.#stages.forEach((s, i) => {
286
+ const entry = PARAMS_SIZE + ENTRY_SIZE * i;
287
+ view.setUint32(entry, s.m, true);
288
+ view.setUint16(entry + 4, s.k, true);
289
+ view.setUint32(entry + 8, s.capacity, true);
290
+ view.setUint32(entry + 12, s.count, true);
291
+ body.set(s.bits.bytes, at);
292
+ at += padded8(s.bits.bytes.length);
293
+ });
294
+ });
295
+ }
296
+ toJSON() {
297
+ return require_serialize.toJSONEnvelope(this.toBytes());
298
+ }
299
+ static fromJSON(value) {
300
+ return ScalableBloomFilter.fromBytes(require_serialize.fromJSONEnvelope(value));
301
+ }
302
+ get count() {
303
+ return this.#stages.reduce((sum, s) => sum + s.count, 0);
304
+ }
305
+ get capacity() {
306
+ return this.#stages.reduce((sum, s) => sum + s.capacity, 0);
307
+ }
308
+ get stages() {
309
+ return this.#stages.length;
310
+ }
311
+ get m() {
312
+ return this.#stages.reduce((sum, s) => sum + s.m, 0);
313
+ }
314
+ get bitsPerKey() {
315
+ return this.m / this.capacity;
316
+ }
317
+ get seed() {
318
+ return this.#seed;
319
+ }
320
+ get epsilon() {
321
+ return this.#epsilon;
322
+ }
323
+ get growth() {
324
+ return this.#growth;
325
+ }
326
+ get tightening() {
327
+ return this.#tightening;
328
+ }
329
+ };
330
+ //#endregion
331
+ exports.BadMagicError = require_serialize.BadMagicError;
332
+ exports.ChecksumError = require_serialize.ChecksumError;
333
+ exports.ParamError = require_params.ParamError;
334
+ exports.ReservedBitsError = require_serialize.ReservedBitsError;
335
+ exports.ScalableBloomFilter = ScalableBloomFilter;
336
+ exports.ScalableParamMismatchError = ScalableParamMismatchError;
337
+ exports.SerializationError = require_serialize.SerializationError;
338
+ exports.TruncatedError = require_serialize.TruncatedError;
339
+ exports.UnknownHashVariantError = require_serialize.UnknownHashVariantError;
340
+ exports.UnknownVersionError = require_serialize.UnknownVersionError;
@@ -0,0 +1,173 @@
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";
3
+ import { t as ParamError } from "../params-DnqJBqLS.cjs";
4
+ //#region src/scalable/scalable.d.ts
5
+ /**
6
+ * Thrown by {@link ScalableBloomFilter.union} when the two filters were built
7
+ * with different settings. Stage `i` has the same geometry in both only when
8
+ * every setting matches, so no stage-by-stage merge exists otherwise.
9
+ */
10
+ export declare class ScalableParamMismatchError extends Error {
11
+ /** Discriminates this error from other `Error`s. */
12
+ override readonly name = "ScalableParamMismatchError";
13
+ }
14
+ /** Settings for a {@link ScalableBloomFilter}. */
15
+ interface ScalableBloomParams {
16
+ /** Keys the first stage holds before the next one opens. */
17
+ n: number;
18
+ /** Target false-positive rate for the whole chain, e.g. `0.01` for 1%. */
19
+ epsilon: number;
20
+ /** Capacity multiplier from one stage to the next; defaults to `2`. */
21
+ growth?: number;
22
+ /**
23
+ * Multiplier on each stage's false-positive target relative to the one
24
+ * before; defaults to `0.85`. Lower spends more bits per stage to open
25
+ * fewer of them.
26
+ */
27
+ tightening?: number;
28
+ /** Hash seed; defaults to `0`. */
29
+ seed?: number;
30
+ }
31
+ /** The optional {@link ScalableBloomParams}, as `create` and `from` take them. */
32
+ type ScalableBloomOptions = Omit<ScalableBloomParams, "n" | "epsilon">;
33
+ /**
34
+ * A Bloom filter that grows with its key count and keeps its false-positive
35
+ * rate under `epsilon`, for when the number of keys is not known up front.
36
+ *
37
+ * It is a chain of Bloom stages. Stage `i` holds `n * growth ** i` keys at a
38
+ * false-positive target of `epsilon * (1 - tightening) * tightening ** i`;
39
+ * those targets sum to at most `epsilon`, however many stages open.
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * const seen = ScalableBloomFilter.create(1000, 0.01);
44
+ * seen.add("alice");
45
+ * seen.has("alice"); // true
46
+ * ```
47
+ */
48
+ export declare class ScalableBloomFilter {
49
+ #private;
50
+ /**
51
+ * Creates a filter whose first stage holds `n` keys, for a chain-wide
52
+ * false-positive target.
53
+ *
54
+ * @param n - Keys the first stage holds.
55
+ * @param epsilon - Target false-positive rate for the whole chain.
56
+ * @param options - Optional growth, tightening and seed.
57
+ * @returns A new, empty filter.
58
+ */
59
+ static create(n: number, epsilon: number, options?: ScalableBloomOptions): ScalableBloomFilter;
60
+ /**
61
+ * Builds a filter from `keys`, with the first stage sized for their count;
62
+ * it keeps growing as more keys arrive. Duplicates only oversize the first
63
+ * stage, since a key already held is not counted again.
64
+ *
65
+ * @param keys - The keys to insert.
66
+ * @param epsilon - Target false-positive rate for the whole chain.
67
+ * @param options - Optional growth, tightening and seed.
68
+ * @returns A new filter containing every key.
69
+ */
70
+ static from(keys: Iterable<BytesLike>, epsilon: number, options?: ScalableBloomOptions): ScalableBloomFilter;
71
+ /**
72
+ * @param params - The filter's settings.
73
+ * @throws {@link ParamError} if a setting is out of range, or the first
74
+ * stage would need more than `2^32 - 1` bits.
75
+ */
76
+ constructor({ n, epsilon, growth, tightening, seed }: ScalableBloomParams);
77
+ /**
78
+ * Adds a key. A key the filter already holds is not counted again, so
79
+ * duplicates never use up a stage's capacity.
80
+ *
81
+ * @param key - The key to insert, as a string or bytes.
82
+ * @throws RangeError if the next stage would need more than `2^32 - 1`
83
+ * bits; the filter is left unchanged and still answers queries.
84
+ */
85
+ add(key: BytesLike): void;
86
+ /**
87
+ * Tests whether a key is in the set.
88
+ *
89
+ * @param key - The key to test.
90
+ * @returns `true` if present (possibly a false positive); `false` guarantees absence.
91
+ */
92
+ has(key: BytesLike): boolean;
93
+ /**
94
+ * Estimates the chain's current false-positive rate from each stage's actual
95
+ * fill: a key is a false positive if any stage wrongly holds it, so this is
96
+ * `1 - prod(1 - (setBits / m) ** k)`. It rises as keys are added and stays
97
+ * under `epsilon` while every stage is within its capacity.
98
+ *
99
+ * @returns The estimated false-positive rate, in `[0, 1]`.
100
+ */
101
+ rate(): number;
102
+ /**
103
+ * Returns a new filter holding every key of this filter and `other`. Stage
104
+ * `i` of the result is the OR of both inputs' stage `i`, and the result has
105
+ * the longer of the two chains. Each stage's count becomes the smaller of
106
+ * its capacity and the two counts summed: an upper bound, so the merged
107
+ * chain opens its next stage early rather than late.
108
+ *
109
+ * @param other - A filter built with identical settings.
110
+ * @returns A new filter; neither input is changed.
111
+ * @throws {@link ScalableParamMismatchError} if any setting, or the
112
+ * geometry of a stage both filters have, differs.
113
+ */
114
+ union(other: ScalableBloomFilter): ScalableBloomFilter;
115
+ /**
116
+ * Tests structural equality: identical settings, the same stages with the
117
+ * same counts, and identical bits, which is exactly when the two serialize
118
+ * to the same bytes. Which stage a key lands in depends on when it arrived,
119
+ * so two filters given the same keys in a different order can be unequal.
120
+ *
121
+ * @param other - The filter to compare against.
122
+ * @returns `true` if the two filters are identical.
123
+ */
124
+ equals(other: ScalableBloomFilter): boolean;
125
+ /**
126
+ * Restores a filter from its {@link ScalableBloomFilter.toBytes} serialization.
127
+ *
128
+ * @param bytes - A frame produced by `toBytes`.
129
+ * @returns The reconstructed filter.
130
+ * @throws {@link SerializationError} (or a subclass) if the frame is malformed.
131
+ */
132
+ static fromBytes(bytes: Uint8Array): ScalableBloomFilter;
133
+ /**
134
+ * Serializes the filter to a portable little-endian frame, DSTL type 6.
135
+ *
136
+ * @returns The serialized filter, readable by {@link ScalableBloomFilter.fromBytes}.
137
+ */
138
+ toBytes(): Uint8Array;
139
+ /**
140
+ * Serializes the filter to a JSON-friendly envelope wrapping the base64 of
141
+ * {@link ScalableBloomFilter.toBytes}.
142
+ *
143
+ * @returns The JSON envelope.
144
+ */
145
+ toJSON(): FilterJSON;
146
+ /**
147
+ * Restores a filter from its {@link ScalableBloomFilter.toJSON} envelope.
148
+ *
149
+ * @param value - The JSON envelope.
150
+ * @returns The reconstructed filter.
151
+ */
152
+ static fromJSON(value: unknown): ScalableBloomFilter;
153
+ /** Keys added that the filter did not already hold. */
154
+ get count(): number;
155
+ /** Keys the open stages hold between them before the next one opens. */
156
+ get capacity(): number;
157
+ /** Number of open stages. */
158
+ get stages(): number;
159
+ /** Total bits across every stage. */
160
+ get m(): number;
161
+ /** Analytic design bits-per-key, `m / capacity`. */
162
+ get bitsPerKey(): number;
163
+ /** Hash seed shared by every stage. */
164
+ get seed(): number;
165
+ /** Target false-positive rate for the whole chain. */
166
+ get epsilon(): number;
167
+ /** Capacity multiplier from one stage to the next. */
168
+ get growth(): number;
169
+ /** False-positive target multiplier from one stage to the next. */
170
+ get tightening(): number;
171
+ }
172
+ //#endregion
173
+ export { BadMagicError, ChecksumError, type FilterJSON, ParamError, ReservedBitsError, type ScalableBloomOptions, type ScalableBloomParams, SerializationError, TruncatedError, UnknownHashVariantError, UnknownVersionError };
@@ -0,0 +1,173 @@
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";
3
+ import { t as ParamError } from "../params-DnqJBqLS.js";
4
+ //#region src/scalable/scalable.d.ts
5
+ /**
6
+ * Thrown by {@link ScalableBloomFilter.union} when the two filters were built
7
+ * with different settings. Stage `i` has the same geometry in both only when
8
+ * every setting matches, so no stage-by-stage merge exists otherwise.
9
+ */
10
+ export declare class ScalableParamMismatchError extends Error {
11
+ /** Discriminates this error from other `Error`s. */
12
+ override readonly name = "ScalableParamMismatchError";
13
+ }
14
+ /** Settings for a {@link ScalableBloomFilter}. */
15
+ interface ScalableBloomParams {
16
+ /** Keys the first stage holds before the next one opens. */
17
+ n: number;
18
+ /** Target false-positive rate for the whole chain, e.g. `0.01` for 1%. */
19
+ epsilon: number;
20
+ /** Capacity multiplier from one stage to the next; defaults to `2`. */
21
+ growth?: number;
22
+ /**
23
+ * Multiplier on each stage's false-positive target relative to the one
24
+ * before; defaults to `0.85`. Lower spends more bits per stage to open
25
+ * fewer of them.
26
+ */
27
+ tightening?: number;
28
+ /** Hash seed; defaults to `0`. */
29
+ seed?: number;
30
+ }
31
+ /** The optional {@link ScalableBloomParams}, as `create` and `from` take them. */
32
+ type ScalableBloomOptions = Omit<ScalableBloomParams, "n" | "epsilon">;
33
+ /**
34
+ * A Bloom filter that grows with its key count and keeps its false-positive
35
+ * rate under `epsilon`, for when the number of keys is not known up front.
36
+ *
37
+ * It is a chain of Bloom stages. Stage `i` holds `n * growth ** i` keys at a
38
+ * false-positive target of `epsilon * (1 - tightening) * tightening ** i`;
39
+ * those targets sum to at most `epsilon`, however many stages open.
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * const seen = ScalableBloomFilter.create(1000, 0.01);
44
+ * seen.add("alice");
45
+ * seen.has("alice"); // true
46
+ * ```
47
+ */
48
+ export declare class ScalableBloomFilter {
49
+ #private;
50
+ /**
51
+ * Creates a filter whose first stage holds `n` keys, for a chain-wide
52
+ * false-positive target.
53
+ *
54
+ * @param n - Keys the first stage holds.
55
+ * @param epsilon - Target false-positive rate for the whole chain.
56
+ * @param options - Optional growth, tightening and seed.
57
+ * @returns A new, empty filter.
58
+ */
59
+ static create(n: number, epsilon: number, options?: ScalableBloomOptions): ScalableBloomFilter;
60
+ /**
61
+ * Builds a filter from `keys`, with the first stage sized for their count;
62
+ * it keeps growing as more keys arrive. Duplicates only oversize the first
63
+ * stage, since a key already held is not counted again.
64
+ *
65
+ * @param keys - The keys to insert.
66
+ * @param epsilon - Target false-positive rate for the whole chain.
67
+ * @param options - Optional growth, tightening and seed.
68
+ * @returns A new filter containing every key.
69
+ */
70
+ static from(keys: Iterable<BytesLike>, epsilon: number, options?: ScalableBloomOptions): ScalableBloomFilter;
71
+ /**
72
+ * @param params - The filter's settings.
73
+ * @throws {@link ParamError} if a setting is out of range, or the first
74
+ * stage would need more than `2^32 - 1` bits.
75
+ */
76
+ constructor({ n, epsilon, growth, tightening, seed }: ScalableBloomParams);
77
+ /**
78
+ * Adds a key. A key the filter already holds is not counted again, so
79
+ * duplicates never use up a stage's capacity.
80
+ *
81
+ * @param key - The key to insert, as a string or bytes.
82
+ * @throws RangeError if the next stage would need more than `2^32 - 1`
83
+ * bits; the filter is left unchanged and still answers queries.
84
+ */
85
+ add(key: BytesLike): void;
86
+ /**
87
+ * Tests whether a key is in the set.
88
+ *
89
+ * @param key - The key to test.
90
+ * @returns `true` if present (possibly a false positive); `false` guarantees absence.
91
+ */
92
+ has(key: BytesLike): boolean;
93
+ /**
94
+ * Estimates the chain's current false-positive rate from each stage's actual
95
+ * fill: a key is a false positive if any stage wrongly holds it, so this is
96
+ * `1 - prod(1 - (setBits / m) ** k)`. It rises as keys are added and stays
97
+ * under `epsilon` while every stage is within its capacity.
98
+ *
99
+ * @returns The estimated false-positive rate, in `[0, 1]`.
100
+ */
101
+ rate(): number;
102
+ /**
103
+ * Returns a new filter holding every key of this filter and `other`. Stage
104
+ * `i` of the result is the OR of both inputs' stage `i`, and the result has
105
+ * the longer of the two chains. Each stage's count becomes the smaller of
106
+ * its capacity and the two counts summed: an upper bound, so the merged
107
+ * chain opens its next stage early rather than late.
108
+ *
109
+ * @param other - A filter built with identical settings.
110
+ * @returns A new filter; neither input is changed.
111
+ * @throws {@link ScalableParamMismatchError} if any setting, or the
112
+ * geometry of a stage both filters have, differs.
113
+ */
114
+ union(other: ScalableBloomFilter): ScalableBloomFilter;
115
+ /**
116
+ * Tests structural equality: identical settings, the same stages with the
117
+ * same counts, and identical bits, which is exactly when the two serialize
118
+ * to the same bytes. Which stage a key lands in depends on when it arrived,
119
+ * so two filters given the same keys in a different order can be unequal.
120
+ *
121
+ * @param other - The filter to compare against.
122
+ * @returns `true` if the two filters are identical.
123
+ */
124
+ equals(other: ScalableBloomFilter): boolean;
125
+ /**
126
+ * Restores a filter from its {@link ScalableBloomFilter.toBytes} serialization.
127
+ *
128
+ * @param bytes - A frame produced by `toBytes`.
129
+ * @returns The reconstructed filter.
130
+ * @throws {@link SerializationError} (or a subclass) if the frame is malformed.
131
+ */
132
+ static fromBytes(bytes: Uint8Array): ScalableBloomFilter;
133
+ /**
134
+ * Serializes the filter to a portable little-endian frame, DSTL type 6.
135
+ *
136
+ * @returns The serialized filter, readable by {@link ScalableBloomFilter.fromBytes}.
137
+ */
138
+ toBytes(): Uint8Array;
139
+ /**
140
+ * Serializes the filter to a JSON-friendly envelope wrapping the base64 of
141
+ * {@link ScalableBloomFilter.toBytes}.
142
+ *
143
+ * @returns The JSON envelope.
144
+ */
145
+ toJSON(): FilterJSON;
146
+ /**
147
+ * Restores a filter from its {@link ScalableBloomFilter.toJSON} envelope.
148
+ *
149
+ * @param value - The JSON envelope.
150
+ * @returns The reconstructed filter.
151
+ */
152
+ static fromJSON(value: unknown): ScalableBloomFilter;
153
+ /** Keys added that the filter did not already hold. */
154
+ get count(): number;
155
+ /** Keys the open stages hold between them before the next one opens. */
156
+ get capacity(): number;
157
+ /** Number of open stages. */
158
+ get stages(): number;
159
+ /** Total bits across every stage. */
160
+ get m(): number;
161
+ /** Analytic design bits-per-key, `m / capacity`. */
162
+ get bitsPerKey(): number;
163
+ /** Hash seed shared by every stage. */
164
+ get seed(): number;
165
+ /** Target false-positive rate for the whole chain. */
166
+ get epsilon(): number;
167
+ /** Capacity multiplier from one stage to the next. */
168
+ get growth(): number;
169
+ /** False-positive target multiplier from one stage to the next. */
170
+ get tightening(): number;
171
+ }
172
+ //#endregion
173
+ export { BadMagicError, ChecksumError, type FilterJSON, ParamError, ReservedBitsError, type ScalableBloomOptions, type ScalableBloomParams, SerializationError, TruncatedError, UnknownHashVariantError, UnknownVersionError };