distillate 0.6.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.
@@ -267,3 +267,5 @@ function fillBlock(key, numBlocks, seed, outWords, outBits) {
267
267
  exports.BlockedBloomFilter = BlockedBloomFilter;
268
268
  exports.BlockedBloomParamMismatchError = BlockedBloomParamMismatchError;
269
269
  exports.ParamError = require_params.ParamError;
270
+ exports.blockedBitsPerKey = blockedBitsPerKey;
271
+ exports.blockedFprAt = blockedFprAt;
@@ -1,6 +1,21 @@
1
1
  import { n as BytesLike, t as FilterJSON } from "../serialize-DRKh6QOr.cjs";
2
2
  import { t as ParamError } from "../params-DnqJBqLS.cjs";
3
3
  //#region src/blocked/blocked.d.ts
4
+ /**
5
+ * Modeled false-positive rate of a split-block filter at `bitsPerKey`. A block
6
+ * holding `j` keys has FPR `(1 - (1 - 1/32)^j)^8` (8 lanes of 32 bits, one probe
7
+ * each); the filter's rate averages that over the Poisson block load
8
+ * `lambda = 256 / bitsPerKey`. This clustering average is why the blocked curve
9
+ * is not linear in `log10(1/epsilon)`.
10
+ */
11
+ declare function blockedFprAt(bitsPerKey: number): number;
12
+ /**
13
+ * Minimal integer bits-per-key whose modeled split-block FPR is at or below
14
+ * `epsilon`. Throws {@link ParamError} when even the densest supported filter
15
+ * cannot reach the target, so callers get a typed rejection instead of a
16
+ * silently under-provisioned filter.
17
+ */
18
+ declare function blockedBitsPerKey(epsilon: number): number;
4
19
  /** Thrown when an operation requires two filters built with identical parameters. */
5
20
  declare class BlockedBloomParamMismatchError extends Error {
6
21
  /** Discriminates this error from other `Error`s. */
@@ -127,4 +142,4 @@ declare class BlockedBloomFilter {
127
142
  has(key: BytesLike): boolean;
128
143
  }
129
144
  //#endregion
130
- export { BlockedBloomFilter, BlockedBloomParamMismatchError, type BlockedBloomParams, type FilterJSON, ParamError };
145
+ export { BlockedBloomFilter, BlockedBloomParamMismatchError, type BlockedBloomParams, type FilterJSON, ParamError, blockedBitsPerKey, blockedFprAt };
@@ -1,6 +1,21 @@
1
1
  import { n as BytesLike, t as FilterJSON } from "../serialize-DRKh6QOr.js";
2
2
  import { t as ParamError } from "../params-DnqJBqLS.js";
3
3
  //#region src/blocked/blocked.d.ts
4
+ /**
5
+ * Modeled false-positive rate of a split-block filter at `bitsPerKey`. A block
6
+ * holding `j` keys has FPR `(1 - (1 - 1/32)^j)^8` (8 lanes of 32 bits, one probe
7
+ * each); the filter's rate averages that over the Poisson block load
8
+ * `lambda = 256 / bitsPerKey`. This clustering average is why the blocked curve
9
+ * is not linear in `log10(1/epsilon)`.
10
+ */
11
+ declare function blockedFprAt(bitsPerKey: number): number;
12
+ /**
13
+ * Minimal integer bits-per-key whose modeled split-block FPR is at or below
14
+ * `epsilon`. Throws {@link ParamError} when even the densest supported filter
15
+ * cannot reach the target, so callers get a typed rejection instead of a
16
+ * silently under-provisioned filter.
17
+ */
18
+ declare function blockedBitsPerKey(epsilon: number): number;
4
19
  /** Thrown when an operation requires two filters built with identical parameters. */
5
20
  declare class BlockedBloomParamMismatchError extends Error {
6
21
  /** Discriminates this error from other `Error`s. */
@@ -127,4 +142,4 @@ declare class BlockedBloomFilter {
127
142
  has(key: BytesLike): boolean;
128
143
  }
129
144
  //#endregion
130
- export { BlockedBloomFilter, BlockedBloomParamMismatchError, type BlockedBloomParams, type FilterJSON, ParamError };
145
+ export { BlockedBloomFilter, BlockedBloomParamMismatchError, type BlockedBloomParams, type FilterJSON, ParamError, blockedBitsPerKey, blockedFprAt };
@@ -263,4 +263,4 @@ function fillBlock(key, numBlocks, seed, outWords, outBits) {
263
263
  }
264
264
  }
265
265
  //#endregion
266
- export { BlockedBloomFilter, BlockedBloomParamMismatchError, ParamError };
266
+ export { BlockedBloomFilter, BlockedBloomParamMismatchError, ParamError, blockedBitsPerKey, blockedFprAt };
@@ -34,7 +34,7 @@ var BitSet = class {
34
34
  //#endregion
35
35
  //#region src/core/sizing.ts
36
36
  /** Optimal Bloom-filter sizing: `m` bits and `k` hashes for `n` items at target FPR `epsilon`. */
37
- function optimal(n, epsilon) {
37
+ function bloomSizing(n, epsilon) {
38
38
  const m = Math.ceil(-n * Math.log(epsilon) / (Math.LN2 * Math.LN2));
39
39
  return {
40
40
  m,
@@ -79,7 +79,7 @@ var BloomFilter = class BloomFilter {
79
79
  require_params.assertPositiveInt(n, "n");
80
80
  require_params.assertUint32(n, "n");
81
81
  require_params.assertProbability(epsilon, "epsilon");
82
- return BloomFilter.#withN(optimal(n, epsilon), n);
82
+ return BloomFilter.#withN(bloomSizing(n, epsilon), n);
83
83
  }
84
84
  /**
85
85
  * Builds a filter from `keys`, sized for their count at the target
@@ -266,3 +266,4 @@ var BloomFilter = class BloomFilter {
266
266
  exports.BloomFilter = BloomFilter;
267
267
  exports.BloomParamMismatchError = BloomParamMismatchError;
268
268
  exports.ParamError = require_params.ParamError;
269
+ exports.bloomSizing = bloomSizing;
@@ -128,4 +128,15 @@ declare class BloomFilter {
128
128
  has(key: BytesLike): boolean;
129
129
  }
130
130
  //#endregion
131
- export { BloomFilter, BloomParamMismatchError, type BloomParams, type FilterJSON, ParamError };
131
+ //#region src/core/sizing.d.ts
132
+ /** Bloom filter geometry: the `BloomParams` fields a sizing solve determines. */
133
+ interface BloomSizing {
134
+ /** Number of bits in the filter. */
135
+ m: number;
136
+ /** Number of hash probes per key. */
137
+ k: number;
138
+ }
139
+ /** Optimal Bloom-filter sizing: `m` bits and `k` hashes for `n` items at target FPR `epsilon`. */
140
+ declare function bloomSizing(n: number, epsilon: number): BloomSizing;
141
+ //#endregion
142
+ export { BloomFilter, BloomParamMismatchError, type BloomParams, type BloomSizing, type FilterJSON, ParamError, bloomSizing };
@@ -128,4 +128,15 @@ declare class BloomFilter {
128
128
  has(key: BytesLike): boolean;
129
129
  }
130
130
  //#endregion
131
- export { BloomFilter, BloomParamMismatchError, type BloomParams, type FilterJSON, ParamError };
131
+ //#region src/core/sizing.d.ts
132
+ /** Bloom filter geometry: the `BloomParams` fields a sizing solve determines. */
133
+ interface BloomSizing {
134
+ /** Number of bits in the filter. */
135
+ m: number;
136
+ /** Number of hash probes per key. */
137
+ k: number;
138
+ }
139
+ /** Optimal Bloom-filter sizing: `m` bits and `k` hashes for `n` items at target FPR `epsilon`. */
140
+ declare function bloomSizing(n: number, epsilon: number): BloomSizing;
141
+ //#endregion
142
+ export { BloomFilter, BloomParamMismatchError, type BloomParams, type BloomSizing, type FilterJSON, ParamError, bloomSizing };
@@ -33,7 +33,7 @@ var BitSet = class {
33
33
  //#endregion
34
34
  //#region src/core/sizing.ts
35
35
  /** Optimal Bloom-filter sizing: `m` bits and `k` hashes for `n` items at target FPR `epsilon`. */
36
- function optimal(n, epsilon) {
36
+ function bloomSizing(n, epsilon) {
37
37
  const m = Math.ceil(-n * Math.log(epsilon) / (Math.LN2 * Math.LN2));
38
38
  return {
39
39
  m,
@@ -78,7 +78,7 @@ var BloomFilter = class BloomFilter {
78
78
  assertPositiveInt(n, "n");
79
79
  assertUint32(n, "n");
80
80
  assertProbability(epsilon, "epsilon");
81
- return BloomFilter.#withN(optimal(n, epsilon), n);
81
+ return BloomFilter.#withN(bloomSizing(n, epsilon), n);
82
82
  }
83
83
  /**
84
84
  * Builds a filter from `keys`, sized for their count at the target
@@ -262,4 +262,4 @@ var BloomFilter = class BloomFilter {
262
262
  }
263
263
  };
264
264
  //#endregion
265
- export { BloomFilter, BloomParamMismatchError, ParamError };
265
+ export { BloomFilter, BloomParamMismatchError, ParamError, bloomSizing };
@@ -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.
@@ -367,3 +380,4 @@ var BinaryFuse16 = class BinaryFuse16 extends BinaryFuse {
367
380
  exports.BinaryFuse16 = BinaryFuse16;
368
381
  exports.BinaryFuse8 = BinaryFuse8;
369
382
  exports.BinaryFuseBuildError = BinaryFuseBuildError;
383
+ exports.fuseBitsPerKey = fuseBitsPerKey;
@@ -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;
@@ -130,4 +140,4 @@ declare class BinaryFuse16 extends BinaryFuse {
130
140
  static fromJSON(value: unknown): BinaryFuse16;
131
141
  }
132
142
  //#endregion
133
- export { BinaryFuse16, BinaryFuse8, BinaryFuseBuildError, type FilterJSON };
143
+ export { BinaryFuse16, BinaryFuse8, BinaryFuseBuildError, type FilterJSON, fuseBitsPerKey };
@@ -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;
@@ -130,4 +140,4 @@ declare class BinaryFuse16 extends BinaryFuse {
130
140
  static fromJSON(value: unknown): BinaryFuse16;
131
141
  }
132
142
  //#endregion
133
- export { BinaryFuse16, BinaryFuse8, BinaryFuseBuildError, type FilterJSON };
143
+ export { BinaryFuse16, BinaryFuse8, BinaryFuseBuildError, type FilterJSON, fuseBitsPerKey };
@@ -59,6 +59,19 @@ function computeParams(size) {
59
59
  };
60
60
  }
61
61
  /**
62
+ * Bits stored per key by a binary fuse filter over `n` keys at a fingerprint
63
+ * width, without building one. Counts `n` as distinct keys, since a built
64
+ * filter sizes on its deduped hash count.
65
+ *
66
+ * @param n - Number of distinct keys.
67
+ * @param width - Fingerprint width in bits: `8` for {@link BinaryFuse8}, `16` for {@link BinaryFuse16}.
68
+ * @returns Bits per key (`0` for an empty filter).
69
+ */
70
+ function fuseBitsPerKey(n, width) {
71
+ if (n === 0) return 0;
72
+ return computeParams(n).arrayLength * width / n;
73
+ }
74
+ /**
62
75
  * Peel the 3-hypergraph and assign fingerprints so every key's XOR of its 3
63
76
  * lanes equals its fingerprint. Retries with a bumped seed on a stall; returns
64
77
  * the seed that succeeded.
@@ -363,4 +376,4 @@ var BinaryFuse16 = class BinaryFuse16 extends BinaryFuse {
363
376
  }
364
377
  };
365
378
  //#endregion
366
- export { BinaryFuse16, BinaryFuse8, BinaryFuseBuildError };
379
+ export { BinaryFuse16, BinaryFuse8, BinaryFuseBuildError, fuseBitsPerKey };
package/dist/index.cjs CHANGED
@@ -2,6 +2,6 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#endregion
3
3
  //#region src/index.ts
4
4
  /** The installed `distillate` package version. */
5
- const VERSION = "0.6.0";
5
+ const VERSION = "0.7.0";
6
6
  //#endregion
7
7
  exports.VERSION = VERSION;
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  //#endregion
2
2
  //#region src/index.ts
3
3
  /** The installed `distillate` package version. */
4
- const VERSION = "0.6.0";
4
+ const VERSION = "0.7.0";
5
5
  //#endregion
6
6
  export { VERSION };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "distillate",
3
- "version": "0.6.0",
3
+ "version": "0.7.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",
@@ -66,13 +66,13 @@
66
66
  "devDependencies": {
67
67
  "@arethetypeswrong/cli": "^0.18.5",
68
68
  "@microsoft/api-extractor": "^7.58.12",
69
- "@types/node": "^26.1.2",
69
+ "@types/node": "^22.0.0",
70
70
  "@vitest/coverage-v8": "^4.1.10",
71
71
  "fast-check": "^4.9.0",
72
72
  "mitata": "^1.0.34",
73
- "publint": "^0.3.22",
73
+ "publint": "^0.3.23",
74
74
  "tsdown": "^0.22.14",
75
- "tsx": "^4.23.1",
75
+ "tsx": "^4.23.12",
76
76
  "typedoc": "^0.28.20",
77
77
  "typedoc-plugin-markdown": "^4.12.0",
78
78
  "typescript": "^5.9.3",