Sorex - TypeScript API
This is the complete reference for Sorex's browser API. The surface is intentionally small: one loader function, one searcher class with four methods. Everything else is handled internally.
The key design choice is callback-based progressive search. Instead of awaiting a single result, you receive updates after each search tier completes. This lets you show fast exact matches immediately while slower fuzzy matches continue in the background. The SearchResult type includes tier information so you can style results differently by match quality.
For how the loader works internally (streaming compilation, thread pool setup), see Runtime. For framework patterns and race condition handling, see Integration.
Installation
The WASM module is embedded in .sorex files built with sorex index. The generated sorex.js handles initialization:
import { loadSorex } from './sorex.js';
const searcher = await loadSorex('/search/index.sorex');
// Search with callbacks for progressive updates
searcher.search('query', 10, {
onUpdate: (results) => renderResults(results), // Called after each tier
onFinish: (results) => renderResults(results) // Called when complete
});Public API
The loader exports only what you need:
export { loadSorex, type SorexSearcher, type SearchResult };loadSorex
Loads a .sorex file and returns a ready-to-use searcher.
async function loadSorex(url: string): Promise<SorexSearcher>Features:
- Extracts embedded WASM from
.sorexfile - Compiles WASM during download (streaming compilation)
- Initializes thread pool for parallel search (when available)
- Falls back gracefully to single-threaded mode in Safari
Example:
const searcher = await loadSorex('/search/index.sorex');SorexSearcher
The main search interface.
search
Three-tier progressive search: exact -> prefix -> fuzzy.
search(
query: string,
limit: number,
callback?: {
onUpdate?: (results: SearchResult[]) => void,
onFinish?: (results: SearchResult[]) => void
}
): voidsearchSync
Synchronous search returning all results at once. Supports optional SearchOptions.
searchSync(query: string, limit: number, options?: SearchOptions): SearchResult[]Parameters:
query- Search query stringlimit- Maximum number of resultsoptions- Optional search configuration (see SearchOptions below)
Example:
// Default: deduplicate sections (one result per document)
const results = searcher.searchSync('kernel', 10);
// Show all matching sections within documents
const allSections = searcher.searchSync('kernel', 10, { dedupSections: false });search Parameters:
query- Search query stringlimit- Maximum number of resultscallback.onUpdate- Called after each tier completes with accumulated resultscallback.onFinish- Called when all tiers complete with final sorted results
Example:
// Basic usage - just get final results
searcher.search('auto-tuning', 10, {
onFinish: (results) => console.log(results)
});
// Progressive UI updates
searcher.search('kernel', 10, {
onUpdate: (results) => {
// Called after T1, T2, T3 with accumulated results
renderResults(results);
},
onFinish: (results) => {
// Final sorted results
renderResults(results);
}
});docCount
Returns the number of indexed documents.
docCount(): numbervocabSize
Returns the number of unique terms in the vocabulary.
vocabSize(): numberfree
Releases WASM memory. Call when done with the searcher (important in SPAs).
free(): voidSearchResult
interface SearchResult {
href: string; // URL path (e.g., "/posts/2024/01/my-post")
title: string; // Document title
excerpt: string; // Short description
sectionId: string | null; // Section ID for deep linking
tier: 1 | 2 | 3; // Match tier (1=exact, 2=prefix, 3=fuzzy)
matchType: number; // Match type (0=title, 1=section, 2+=content)
score: number; // Relevance score (higher is better)
matchedTerm: string | null; // Vocabulary term that matched (for highlighting)
}matchedTerm: The actual vocabulary term that matched the query. Useful for:
- Highlighting the matched term in results
- Showing what the fuzzy search matched against (e.g., query "ruts" → matchedTerm "rust")
- Prefix expansion display (e.g., query "typ" → matchedTerm "typescript")
SearchOptions
interface SearchOptions {
dedupSections?: boolean; // Whether to deduplicate sections (default: true)
}dedupSections (default: true):
- When
true: Returns one result per document. The best matching section (by match type, then score) is used for deep linking viasectionId. - When
false: Returns multiple results per document if different sections match. Useful for showing all matching locations within a document.
Complete Example
import { loadSorex } from './sorex.js';
class SearchController {
private searcher: SorexSearcher | null = null;
private currentSearchId = 0;
async init(indexUrl: string) {
this.searcher = await loadSorex(indexUrl);
console.log(`Loaded ${this.searcher.docCount()} documents`);
}
search(query: string) {
if (!this.searcher || query.length < 2) {
this.renderResults([]);
return;
}
// Increment search ID to handle race conditions
const searchId = ++this.currentSearchId;
this.searcher.search(query, 10, {
onUpdate: (results) => {
if (searchId !== this.currentSearchId) return;
this.renderResults(results);
},
onFinish: (results) => {
if (searchId !== this.currentSearchId) return;
this.renderResults(results);
}
});
}
private renderResults(results: SearchResult[]) {
const html = results.map(r => {
const url = r.sectionId ? `${r.href}#${r.sectionId}` : r.href;
return `<a href="${url}"><h3>${r.title}</h3><p>${r.excerpt}</p></a>`;
}).join('');
document.getElementById('results')!.innerHTML = html;
}
destroy() {
this.searcher?.free();
this.searcher = null;
}
}API Summary
| Method | Description |
|---|---|
loadSorex(url) |
Load .sorex file, returns Promise |
search(query, limit, callback?) |
Progressive search with callbacks |
searchSync(query, limit, options?) |
Synchronous search with optional dedup control |
docCount() |
Number of indexed documents |
vocabSize() |
Number of vocabulary terms |
free() |
Release WASM memory |
See Also
- Runtime - Streaming compilation, threading, progressive search internals
- Integration - React, Svelte, vanilla JS examples
- CLI Reference - Building indexes with
sorex index - Troubleshooting - Common issues