rapid-fuzzy 1.1.0 → 1.2.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 CHANGED
@@ -12,7 +12,7 @@ Blazing-fast fuzzy search for JavaScript — powered by Rust, works everywhere.
12
12
 
13
13
  ## Features
14
14
 
15
- - **Fast**: Up to 15,000x faster than fuse.js with FuzzyIndex (Rust + napi-rs)
15
+ - **Fast**: Up to 15,000x faster than fuse.js in indexed mode on large datasets (Rust + napi-rs) — [see benchmarks](#benchmarks)
16
16
  - **Universal**: Works in Node.js (native), browsers (WASM), Deno, and Bun
17
17
  - **Zero JS dependencies**: Pure Rust core with napi-rs bindings
18
18
  - **Type-safe**: Full TypeScript support with auto-generated type definitions
@@ -51,14 +51,110 @@ pnpm add rapid-fuzzy
51
51
  ### Runtime-specific notes
52
52
 
53
53
  - **Node.js** (>=20): Uses native bindings via napi-rs for best performance.
54
- - **Browser / Deno / Bun**: Falls back to a WASM build automatically. The WASM binary is ~660 KB raw (~230 KB gzipped).
54
+ - **Bun**: Uses native napi-rs bindings. WASM fallback also works see [Bun section](#bun) below.
55
+ - **Browser / CDN / Cloudflare Workers / Deno**: Falls back to the wasm-bindgen WASM build (~195 KB raw). No `SharedArrayBuffer` or COOP/COEP headers required.
55
56
 
56
- > **Browser WASM requirement**: The WASM build uses `SharedArrayBuffer` for threading, which requires the following HTTP headers on your page:
57
- > ```
58
- > Cross-Origin-Opener-Policy: same-origin
59
- > Cross-Origin-Embedder-Policy: require-corp
60
- > ```
61
- > Without these headers, you will see `SharedArrayBuffer is not defined`. See [MDN: SharedArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements) for details.
57
+ ### Framework Integration (SSR)
58
+
59
+ Native modules need to be externalized in SSR frameworks:
60
+
61
+ **Next.js**
62
+
63
+ ```js
64
+ // next.config.js
65
+ const nextConfig = {
66
+ serverExternalPackages: ['rapid-fuzzy'],
67
+ };
68
+ ```
69
+
70
+ **Vite SSR**
71
+
72
+ ```js
73
+ // vite.config.js
74
+ export default {
75
+ ssr: {
76
+ external: ['rapid-fuzzy'],
77
+ },
78
+ };
79
+ ```
80
+
81
+ On the client side, rapid-fuzzy automatically falls back to WASM — no additional configuration needed.
82
+
83
+ ### Browser and Edge Runtime Usage
84
+
85
+ #### CDN (no bundler required)
86
+
87
+ Import directly from [esm.sh](https://esm.sh) in any `<script type="module">`:
88
+
89
+ ```html
90
+ <script type="module">
91
+ import { search, FuzzyIndex } from 'https://esm.sh/rapid-fuzzy';
92
+
93
+ const results = search('typscript', ['TypeScript', 'JavaScript', 'Python']);
94
+ console.log(results[0].item); // 'TypeScript'
95
+
96
+ const index = new FuzzyIndex(['TypeScript', 'JavaScript', 'Python']);
97
+ console.log(index.search('typscript')[0].item); // 'TypeScript'
98
+ index.destroy();
99
+ </script>
100
+ ```
101
+
102
+ See [`examples/cdn-usage/`](examples/cdn-usage/) for a complete HTML example.
103
+
104
+ #### Cloudflare Workers
105
+
106
+ Install the package and import it in your Worker script. Wrangler bundles the WASM binary automatically:
107
+
108
+ ```bash
109
+ npm install rapid-fuzzy
110
+ ```
111
+
112
+ ```js
113
+ // worker.js
114
+ import { search, FuzzyIndex } from 'rapid-fuzzy';
115
+
116
+ // Create the index once at module scope (shared across requests)
117
+ const index = new FuzzyIndex(['hello', 'world', 'foo', 'bar']);
118
+
119
+ export default {
120
+ fetch(request) {
121
+ const { searchParams } = new URL(request.url);
122
+ const query = searchParams.get('q') ?? '';
123
+ const results = index.search(query);
124
+ return Response.json(results);
125
+ },
126
+ };
127
+ ```
128
+
129
+ ```toml
130
+ # wrangler.toml
131
+ name = "rapid-fuzzy-worker"
132
+ main = "worker.js"
133
+ compatibility_date = "2025-01-01"
134
+ ```
135
+
136
+ See [`examples/cloudflare-workers/`](examples/cloudflare-workers/) for a complete example.
137
+
138
+ #### Deno
139
+
140
+ Use rapid-fuzzy via the `npm:` specifier (Deno 1.28+):
141
+
142
+ ```ts
143
+ import { search } from 'npm:rapid-fuzzy';
144
+
145
+ const results = search('typscript', ['TypeScript', 'JavaScript', 'Python']);
146
+ console.log(results[0].item); // 'TypeScript'
147
+ ```
148
+
149
+ Or import from a CDN directly:
150
+
151
+ ```ts
152
+ import { search } from 'https://esm.sh/rapid-fuzzy';
153
+ ```
154
+
155
+ #### Bun
156
+
157
+ Bun uses the native napi-rs bindings when available (fastest). You can also use the wasm-bindgen WASM files directly if needed — see [`e2e/wasm-bun.test.ts`](e2e/wasm-bun.test.ts) for the manual initialization pattern.
62
158
 
63
159
  ## API
64
160
 
@@ -101,12 +197,25 @@ closest('xyz', items, 0.5);
101
197
  ### String Distance
102
198
 
103
199
  ```typescript
104
- import { levenshtein, jaroWinkler, sorensenDice, hamming } from 'rapid-fuzzy';
200
+ import {
201
+ levenshtein,
202
+ jaro,
203
+ jaroWinkler,
204
+ sorensenDice,
205
+ hamming,
206
+ normalizedHamming,
207
+ indel,
208
+ normalizedIndel,
209
+ } from 'rapid-fuzzy';
105
210
 
106
211
  levenshtein('kitten', 'sitting'); // 3
107
- jaroWinkler('MARTHA', 'MARHTA'); // 0.961
212
+ jaro('martha', 'marhta'); // 0.944 (similarity between 0–1)
213
+ jaroWinkler('MARTHA', 'MARHTA'); // 0.961 (jaro + prefix bonus)
108
214
  sorensenDice('night', 'nacht'); // 0.25
109
215
  hamming('karolin', 'kathrin'); // 3 (null if lengths differ)
216
+ normalizedHamming('karolin', 'kathrin'); // 0.571 (similarity 0–1, null if lengths differ)
217
+ indel('abc', 'ac'); // 1 (insertions + deletions only, no substitutions)
218
+ normalizedIndel('kitten', 'sitting'); // 0.615 (similarity 0–1)
110
219
  ```
111
220
 
112
221
  ### Query Syntax
@@ -169,6 +278,9 @@ const index = new FuzzyIndex(['TypeScript', 'JavaScript', 'Python', ...]);
169
278
  index.search('typscript', { maxResults: 5 });
170
279
  index.closest('tsc');
171
280
 
281
+ // Tip: FuzzyIndex caches results internally — extending a previous query
282
+ // (e.g. typing "app" → "apple") reuses cached candidates for faster lookups.
283
+
172
284
  // Index-only results (no string cloning — less GC pressure)
173
285
  const hits = index.searchIndices('typscript', { maxResults: 5 });
174
286
  // → [{ index: 0, score: 0.85, positions: [] }, ...]
@@ -192,6 +304,38 @@ index.destroy();
192
304
  userIndex.destroy();
193
305
  ```
194
306
 
307
+ #### Incremental Search (Autocomplete)
308
+
309
+ FuzzyIndex automatically caches matching candidates. When a new query extends the previous one, only cached candidates are re-scored:
310
+
311
+ ```typescript
312
+ const index = new FuzzyIndex(items);
313
+ index.search('app'); // scores all items, caches matches
314
+ index.search('apple'); // only re-scores cached candidates — much faster
315
+ index.search('xyz'); // different query — full scan, new cache
316
+ ```
317
+
318
+ This makes FuzzyIndex ideal for search-as-you-type UIs where each keystroke extends the query.
319
+
320
+ #### Index Serialization
321
+
322
+ Save and restore a `FuzzyIndex` to avoid rebuilding on startup:
323
+
324
+ ```typescript
325
+ import { FuzzyIndex } from 'rapid-fuzzy';
326
+
327
+ const index = new FuzzyIndex(['apple', 'banana', 'cherry']);
328
+
329
+ // Serialize to Buffer
330
+ const data = index.serialize();
331
+
332
+ // Restore from serialized data
333
+ const restored = FuzzyIndex.deserialize(data);
334
+ restored.search('aple'); // works immediately
335
+ ```
336
+
337
+ > **Note:** The serialization format is version-specific. Regenerate the index after updating rapid-fuzzy.
338
+
195
339
  ### Match Highlighting
196
340
 
197
341
  Convert matched positions into highlighted markup for UI rendering:
@@ -247,7 +391,10 @@ All token-based functions include `Batch` and `Many` variants (e.g., `tokenSortR
247
391
  <details>
248
392
  <summary><strong>Batch Operations</strong></summary>
249
393
 
250
- All distance functions have `Batch` and `Many` variants that amortize FFI overhead:
394
+ All distance functions have `Batch` and `Many` variants that amortize FFI overhead. `*Batch` functions compute metrics for multiple pairs at once, while `*Many` functions compare a single reference string against multiple candidates.
395
+
396
+ - **`*Batch`** — compute distances for an array of string pairs (many-to-many)
397
+ - **`*Many`** — compare one reference string against many candidates (one-to-many)
251
398
 
252
399
  ```typescript
253
400
  import { levenshteinBatch, levenshteinMany } from 'rapid-fuzzy';
@@ -273,13 +420,142 @@ jaroWinklerMany('MARTHA', candidates, 0.8); // minSimilarity → returns 0
273
420
 
274
421
  </details>
275
422
 
423
+ <details>
424
+ <summary><strong>TypedArray Variants</strong></summary>
425
+
426
+ All `*Many` functions have TypedArray counterparts that return `Uint32Array` or `Float64Array` instead of `Array<number>`. These avoid boxing overhead and GC pressure when processing large candidate sets.
427
+
428
+ - **`*ManyU32`** — returns `Uint32Array` (for integer distances: `levenshteinManyU32`, `damerauLevenshteinManyU32`, `indelManyU32`)
429
+ - **`*ManyF64`** — returns `Float64Array` (for similarity scores: `jaroManyF64`, `jaroWinklerManyF64`, `normalizedLevenshteinManyF64`, `normalizedIndelManyF64`, `sorensenDiceManyF64`, `tokenSortRatioManyF64`, `tokenSetRatioManyF64`, `partialRatioManyF64`, `weightedRatioManyF64`)
430
+
431
+ ```typescript
432
+ import { levenshteinManyU32, jaroWinklerManyF64 } from 'rapid-fuzzy';
433
+
434
+ const candidates = ['sitting', 'kittens', 'kitchen'];
435
+
436
+ // Returns Uint32Array instead of Array<number>
437
+ levenshteinManyU32('kitten', candidates); // Uint32Array [3, 1, 2]
438
+
439
+ // Returns Float64Array instead of Array<number>
440
+ jaroWinklerManyF64('kitten', candidates); // Float64Array [0.746, 0.976, 0.933]
441
+ ```
442
+
443
+ > **When to use**: Prefer TypedArray variants when comparing against thousands of candidates. The returned typed arrays can also be passed directly to WebGL, WASM, or worker threads without copying.
444
+
445
+ </details>
446
+
447
+ ## Framework Integration
448
+
449
+ `FuzzyIndex` and `FuzzyObjectIndex` are designed for repeated search on the same data — build the index once, search many times. The examples below show the recommended pattern for each major framework.
450
+
451
+ ### React
452
+
453
+ ```tsx
454
+ import { useEffect, useRef, useState } from 'react';
455
+ import { FuzzyObjectIndex } from 'rapid-fuzzy/objects';
456
+
457
+ const users = [
458
+ { name: 'Alice', email: 'alice@example.com' },
459
+ { name: 'Bob', email: 'bob@example.com' },
460
+ ];
461
+
462
+ function UserSearch() {
463
+ const indexRef = useRef<FuzzyObjectIndex<typeof users[number]> | null>(null);
464
+ const [query, setQuery] = useState('');
465
+ const [results, setResults] = useState(users);
466
+
467
+ useEffect(() => {
468
+ indexRef.current = new FuzzyObjectIndex(users, {
469
+ keys: [{ name: 'name', weight: 2.0 }, 'email'],
470
+ });
471
+ return () => indexRef.current?.destroy();
472
+ }, []); // rebuild only when data changes — pass `users` as dependency if dynamic
473
+
474
+ useEffect(() => {
475
+ if (!indexRef.current) return;
476
+ if (!query) { setResults(users); return; }
477
+ setResults(indexRef.current.search(query).map((r) => r.item));
478
+ }, [query]);
479
+
480
+ return (
481
+ <>
482
+ <input value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Search…" />
483
+ <ul>{results.map((u) => <li key={u.email}>{u.name}</li>)}</ul>
484
+ </>
485
+ );
486
+ }
487
+ ```
488
+
489
+ ### Vue
490
+
491
+ ```vue
492
+ <script setup lang="ts">
493
+ import { ref, watch, onUnmounted } from 'vue';
494
+ import { FuzzyObjectIndex } from 'rapid-fuzzy/objects';
495
+
496
+ const users = [
497
+ { name: 'Alice', email: 'alice@example.com' },
498
+ { name: 'Bob', email: 'bob@example.com' },
499
+ ];
500
+
501
+ const query = ref('');
502
+ const results = ref(users);
503
+
504
+ const index = new FuzzyObjectIndex(users, {
505
+ keys: [{ name: 'name', weight: 2.0 }, 'email'],
506
+ });
507
+
508
+ watch(query, (q) => {
509
+ results.value = q ? index.search(q).map((r) => r.item) : users;
510
+ });
511
+
512
+ onUnmounted(() => index.destroy());
513
+ </script>
514
+
515
+ <template>
516
+ <input v-model="query" placeholder="Search…" />
517
+ <ul><li v-for="u in results" :key="u.email">{{ u.name }}</li></ul>
518
+ </template>
519
+ ```
520
+
521
+ ### Svelte
522
+
523
+ ```svelte
524
+ <script lang="ts">
525
+ import { onDestroy } from 'svelte';
526
+ import { FuzzyObjectIndex } from 'rapid-fuzzy/objects';
527
+
528
+ const users = [
529
+ { name: 'Alice', email: 'alice@example.com' },
530
+ { name: 'Bob', email: 'bob@example.com' },
531
+ ];
532
+
533
+ let query = '';
534
+
535
+ const index = new FuzzyObjectIndex(users, {
536
+ keys: [{ name: 'name', weight: 2.0 }, 'email'],
537
+ });
538
+
539
+ $: results = query ? index.search(query).map((r) => r.item) : users;
540
+
541
+ onDestroy(() => index.destroy());
542
+ </script>
543
+
544
+ <input bind:value={query} placeholder="Search…" />
545
+ <ul>{#each results as u}<li>{u.name}</li>{/each}</ul>
546
+ ```
547
+
548
+ > **Note**: Always call `index.destroy()` in your cleanup handler (`useEffect` return, `onUnmounted`, `onDestroy`) to free Rust-side memory.
549
+
276
550
  ## Choosing an Algorithm
277
551
 
278
552
  | Use case | Recommended | Why |
279
553
  |---|---|---|
280
554
  | Typo detection / spell check | `levenshtein`, `damerauLevenshtein` | Counts edits; Damerau adds transposition support |
281
- | Fixed-length comparison | `hamming` | Counts differing positions; only for equal-length strings |
555
+ | Insertion/deletion only edits | `indel`, `normalizedIndel` | No substitutions useful for diff-like or DNA alignment scenarios |
556
+ | Fixed-length comparison | `hamming`, `normalizedHamming` | Counts differing positions; only for equal-length strings |
282
557
  | Name / address matching | `jaroWinkler`, `tokenSortRatio` | Prefix-weighted or order-independent matching |
558
+ | Character-level similarity | `jaro` | Good baseline similarity without prefix weighting |
283
559
  | Document / text similarity | `sorensenDice` | Bigram-based; handles longer text well |
284
560
  | Normalized comparison (0–1) | `normalizedLevenshtein` | Length-independent similarity score |
285
561
  | Reordered words / messy data | `tokenSortRatio`, `tokenSetRatio` | Handles word order differences and extra tokens |
@@ -290,8 +566,9 @@ jaroWinklerMany('MARTHA', candidates, 0.8); // minSimilarity → returns 0
290
566
 
291
567
  **Return types:**
292
568
 
293
- - `levenshtein`, `damerauLevenshtein`, `hamming` → integer (edit/difference count; `hamming` returns `null` if lengths differ)
294
- - `jaro`, `jaroWinkler`, `sorensenDice`, `normalizedLevenshtein` → float between 0.0 (no match) and 1.0 (identical)
569
+ - `levenshtein`, `damerauLevenshtein`, `hamming`, `indel` → integer (edit/difference count; `hamming` returns `null` if lengths differ)
570
+ - `jaro`, `jaroWinkler`, `sorensenDice`, `normalizedLevenshtein`, `normalizedIndel` → float between 0.0 (no match) and 1.0 (identical)
571
+ - `normalizedHamming` → float between 0.0 and 1.0 (`null` if lengths differ)
295
572
  - `tokenSortRatio`, `tokenSetRatio`, `partialRatio`, `weightedRatio` → float between 0.0 and 1.0
296
573
  - `search` → array of `{ item, score, index, positions }` sorted by relevance (score: 0.0–1.0)
297
574
 
package/browser.js CHANGED
@@ -1,4 +1,4 @@
1
- export * from 'rapid-fuzzy-wasm32-wasi'
1
+ export * from './rapid-fuzzy-wasm-bindgen.js';
2
2
 
3
3
  // --- JS utilities (appended by scripts/patch-binding.js) ---
4
4
  export { highlight, highlightRanges } from './highlight.mjs';
@@ -0,0 +1,2 @@
1
+ export { highlight, highlightRanges } from './highlight.js';
2
+ export type { HighlightRange } from './highlight.js';
package/index.d.mts CHANGED
@@ -1,11 +1,11 @@
1
- export * from './index.d.ts';
2
- export { highlight, highlightRanges } from './highlight.d.ts';
3
- export type { HighlightRange } from './highlight.d.ts';
4
- export { searchObjects, FuzzyObjectIndex } from './objects';
1
+ export * from './index.js';
2
+ export { highlight, highlightRanges } from './highlight.js';
3
+ export type { HighlightRange } from './highlight.js';
4
+ export { searchObjects, FuzzyObjectIndex } from './objects.js';
5
5
  export type {
6
6
  KeyConfig,
7
7
  ObjectSearchOptions,
8
8
  ObjectSearchResult,
9
9
  ObjectIndexOptions,
10
10
  ObjectIndexSearchOptions,
11
- } from './objects';
11
+ } from './objects.js';
package/index.d.ts CHANGED
@@ -13,6 +13,13 @@
13
13
  export declare class FuzzyIndex {
14
14
  /** Create a new FuzzyIndex from an array of strings. */
15
15
  constructor(items: Array<string>)
16
+ /**
17
+ * Construct a FuzzyIndex on the libuv thread pool, returning a Promise.
18
+ *
19
+ * For large datasets this keeps the JavaScript event loop unblocked during
20
+ * index construction. The synchronous constructor is fine for small datasets.
21
+ */
22
+ static fromAsync(items: Array<string>): Promise<FuzzyIndex>
16
23
  /** Return the number of items in the index. */
17
24
  get size(): number
18
25
  /**
@@ -44,7 +51,7 @@ export declare class FuzzyIndex {
44
51
  /**
45
52
  * Remove the item at the given index.
46
53
  *
47
- * Returns false if the index is out of bounds.
54
+ * Uses swap-remove for O(1) performance. Returns false if out of bounds.
48
55
  */
49
56
  remove(index: number): boolean
50
57
  /** Free the internal data. After calling this, the index is empty. */
@@ -94,6 +101,15 @@ export declare class KeyedFuzzyIndex {
94
101
  * Returns results sorted by combined weighted score (best match first).
95
102
  */
96
103
  search(query: string, options?: SearchOptions | undefined | null): Array<KeySearchResult>
104
+ /**
105
+ * Find the index of the closest matching item.
106
+ *
107
+ * Returns the index of the best match, or null if no match is found.
108
+ * If `min_score` is provided, returns null when the best match scores below the threshold.
109
+ *
110
+ * Use the returned index to look up the item in your own data array.
111
+ */
112
+ closest(query: string, minScore?: number | undefined | null): number | null
97
113
  /**
98
114
  * Add a single item to the index.
99
115
  *
@@ -116,6 +132,16 @@ export declare class KeyedFuzzyIndex {
116
132
  remove(index: number): boolean
117
133
  /** Free the internal data. After calling this, the index is empty. */
118
134
  destroy(): void
135
+ /**
136
+ * Serialize the index to a compact binary format.
137
+ *
138
+ * The returned Buffer can be written to disk, stored in IndexedDB,
139
+ * or transferred over the network. Use `KeyedFuzzyIndex.deserialize()` to
140
+ * reconstruct the index.
141
+ */
142
+ serialize(): Buffer
143
+ /** Reconstruct a KeyedFuzzyIndex from a previously serialized Buffer. */
144
+ static deserialize(data: Buffer): KeyedFuzzyIndex
119
145
  }
120
146
 
121
147
  /**
@@ -178,6 +204,35 @@ export declare function hammingBatch(pairs: Array<Array<string>>): Array<number
178
204
  */
179
205
  export declare function hammingMany(reference: string, candidates: Array<string>, maxDistance?: number | undefined | null): Array<number | undefined | null>
180
206
 
207
+ /**
208
+ * Compute the Indel distance between two strings.
209
+ *
210
+ * The Indel distance counts the minimum number of insertions and deletions
211
+ * (no substitutions) required to transform one string into the other.
212
+ * It equals `len(a) + len(b) - 2 * LCS_length(a, b)`.
213
+ *
214
+ * Useful when substitutions are semantically two operations (one deletion +
215
+ * one insertion), such as in DNA sequence alignment.
216
+ */
217
+ export declare function indel(a: string, b: string): number
218
+
219
+ /**
220
+ * Compute the Indel distance for multiple pairs of strings in a single call.
221
+ *
222
+ * Returns an array of distances in the same order as the input pairs.
223
+ * Each pair must be an array of exactly two strings `[a, b]`.
224
+ */
225
+ export declare function indelBatch(pairs: Array<Array<string>>): Array<number>
226
+
227
+ /**
228
+ * Compute the Indel distance from one reference string to many candidates.
229
+ *
230
+ * Returns an array of distances, one per candidate, in the same order as the input.
231
+ * If `max_distance` is provided, candidates with distance exceeding the threshold
232
+ * will return `max_distance + 1` (enabling early termination for better performance).
233
+ */
234
+ export declare function indelMany(reference: string, candidates: Array<string>, maxDistance?: number | undefined | null): Array<number>
235
+
181
236
  /**
182
237
  * A lightweight search result containing only index and score (no item string).
183
238
  *
@@ -304,6 +359,55 @@ export declare const enum MatchType {
304
359
  Fuzzy = 'Fuzzy'
305
360
  }
306
361
 
362
+ /**
363
+ * Compute the normalized Hamming similarity between two strings.
364
+ *
365
+ * Returns `null` if the strings have different lengths.
366
+ * Returns a value between 0.0 (no matching characters) and 1.0 (identical).
367
+ */
368
+ export declare function normalizedHamming(a: string, b: string): number | null
369
+
370
+ /**
371
+ * Compute the normalized Hamming similarity for multiple pairs of strings in a single call.
372
+ *
373
+ * Returns an array of scores in the same order as the input pairs.
374
+ * Returns `null` for pairs with different lengths.
375
+ */
376
+ export declare function normalizedHammingBatch(pairs: Array<Array<string>>): Array<number | undefined | null>
377
+
378
+ /**
379
+ * Compute the normalized Hamming similarity from one reference string to many candidates.
380
+ *
381
+ * Returns an array of scores, one per candidate, in the same order as the input.
382
+ * Returns `null` for candidates with a different length than the reference.
383
+ * If `min_similarity` is provided, candidates with similarity below the threshold
384
+ * will also return `null` (enabling early termination for better performance).
385
+ */
386
+ export declare function normalizedHammingMany(reference: string, candidates: Array<string>, minSimilarity?: number | undefined | null): Array<number | undefined | null>
387
+
388
+ /**
389
+ * Compute the normalized Indel similarity between two strings.
390
+ *
391
+ * Returns a value between 0.0 (completely different) and 1.0 (identical).
392
+ */
393
+ export declare function normalizedIndel(a: string, b: string): number
394
+
395
+ /**
396
+ * Compute the normalized Indel similarity for multiple pairs of strings in a single call.
397
+ *
398
+ * Returns an array of similarity scores in the same order as the input pairs.
399
+ */
400
+ export declare function normalizedIndelBatch(pairs: Array<Array<string>>): Array<number>
401
+
402
+ /**
403
+ * Compute the normalized Indel similarity from one reference string to many candidates.
404
+ *
405
+ * Returns an array of similarity scores, one per candidate, in the same order as the input.
406
+ * If `min_similarity` is provided, candidates with similarity below the threshold
407
+ * will return `0.0` (enabling early termination for better performance).
408
+ */
409
+ export declare function normalizedIndelMany(reference: string, candidates: Array<string>, minSimilarity?: number | undefined | null): Array<number>
410
+
307
411
  /**
308
412
  * Compute the normalized Levenshtein similarity between two strings.
309
413
  *
@@ -348,8 +452,9 @@ export declare function partialRatioBatch(pairs: Array<Array<string>>): Array<nu
348
452
  * Compute the partial ratio from one reference string to many candidates.
349
453
  *
350
454
  * Returns an array of similarity scores, one per candidate, in the same order as the input.
455
+ * If `min_similarity` is provided, candidates scoring below the threshold return `0.0`.
351
456
  */
352
- export declare function partialRatioMany(reference: string, candidates: Array<string>): Array<number>
457
+ export declare function partialRatioMany(reference: string, candidates: Array<string>, minSimilarity?: number | undefined | null): Array<number>
353
458
 
354
459
  /**
355
460
  * Perform fuzzy search over a list of strings.
@@ -436,8 +541,10 @@ export declare function sorensenDiceBatch(pairs: Array<Array<string>>): Array<nu
436
541
  * Compute the Sorensen-Dice coefficient from one reference string to many candidates.
437
542
  *
438
543
  * Returns an array of similarity scores, one per candidate, in the same order as the input.
544
+ * If `min_similarity` is provided, candidates scoring below the threshold return `0.0`.
545
+ * Reference bigrams are pre-computed once and reused for all candidates.
439
546
  */
440
- export declare function sorensenDiceMany(reference: string, candidates: Array<string>): Array<number>
547
+ export declare function sorensenDiceMany(reference: string, candidates: Array<string>, minSimilarity?: number | undefined | null): Array<number>
441
548
 
442
549
  /**
443
550
  * Compute the token set ratio between two strings.
@@ -460,8 +567,9 @@ export declare function tokenSetRatioBatch(pairs: Array<Array<string>>): Array<n
460
567
  * Compute the token set ratio from one reference string to many candidates.
461
568
  *
462
569
  * Returns an array of similarity scores, one per candidate, in the same order as the input.
570
+ * If `min_similarity` is provided, candidates scoring below the threshold return `0.0`.
463
571
  */
464
- export declare function tokenSetRatioMany(reference: string, candidates: Array<string>): Array<number>
572
+ export declare function tokenSetRatioMany(reference: string, candidates: Array<string>, minSimilarity?: number | undefined | null): Array<number>
465
573
 
466
574
  /**
467
575
  * Compute the token sort ratio between two strings.
@@ -484,8 +592,9 @@ export declare function tokenSortRatioBatch(pairs: Array<Array<string>>): Array<
484
592
  * Compute the token sort ratio from one reference string to many candidates.
485
593
  *
486
594
  * Returns an array of similarity scores, one per candidate, in the same order as the input.
595
+ * If `min_similarity` is provided, candidates scoring below the threshold return `0.0`.
487
596
  */
488
- export declare function tokenSortRatioMany(reference: string, candidates: Array<string>): Array<number>
597
+ export declare function tokenSortRatioMany(reference: string, candidates: Array<string>, minSimilarity?: number | undefined | null): Array<number>
489
598
 
490
599
  /**
491
600
  * Compute the weighted ratio between two strings.
@@ -508,8 +617,22 @@ export declare function weightedRatioBatch(pairs: Array<Array<string>>): Array<n
508
617
  * Compute the weighted ratio from one reference string to many candidates.
509
618
  *
510
619
  * Returns an array of similarity scores, one per candidate, in the same order as the input.
620
+ * If `min_similarity` is provided, candidates scoring below the threshold return `0.0`.
511
621
  */
512
- export declare function weightedRatioMany(reference: string, candidates: Array<string>): Array<number>
622
+ export declare function weightedRatioMany(reference: string, candidates: Array<string>, minSimilarity?: number | undefined | null): Array<number>
513
623
 
514
624
  // --- JS utilities (appended by scripts/patch-binding.js) ---
515
625
  export { highlight, highlightRanges, HighlightRange } from './highlight';
626
+ /** TypedArray variants — identical to the `*Many` counterparts but return a typed array instead of `Array<number>`, reducing GC pressure for large candidate sets. */
627
+ export declare function levenshteinManyU32(reference: string, candidates: Array<string>, maxDistance?: number | undefined | null): Uint32Array;
628
+ export declare function damerauLevenshteinManyU32(reference: string, candidates: Array<string>, maxDistance?: number | undefined | null): Uint32Array;
629
+ export declare function indelManyU32(reference: string, candidates: Array<string>, maxDistance?: number | undefined | null): Uint32Array;
630
+ export declare function jaroManyF64(reference: string, candidates: Array<string>, minSimilarity?: number | undefined | null): Float64Array;
631
+ export declare function jaroWinklerManyF64(reference: string, candidates: Array<string>, minSimilarity?: number | undefined | null): Float64Array;
632
+ export declare function sorensenDiceManyF64(reference: string, candidates: Array<string>, minSimilarity?: number | undefined | null): Float64Array;
633
+ export declare function normalizedLevenshteinManyF64(reference: string, candidates: Array<string>, minSimilarity?: number | undefined | null): Float64Array;
634
+ export declare function normalizedIndelManyF64(reference: string, candidates: Array<string>, minSimilarity?: number | undefined | null): Float64Array;
635
+ export declare function tokenSortRatioManyF64(reference: string, candidates: Array<string>, minSimilarity?: number | undefined | null): Float64Array;
636
+ export declare function tokenSetRatioManyF64(reference: string, candidates: Array<string>, minSimilarity?: number | undefined | null): Float64Array;
637
+ export declare function partialRatioManyF64(reference: string, candidates: Array<string>, minSimilarity?: number | undefined | null): Float64Array;
638
+ export declare function weightedRatioManyF64(reference: string, candidates: Array<string>, minSimilarity?: number | undefined | null): Float64Array;