@moss-dev/moss-web
v1.2.0
Published
Moss browser SDK — in-browser semantic search powered by WASM
Readme
Moss client library for the browser
@moss-dev/moss-web enables private, in-browser semantic search — no server round-trips for queries.
Built on WebAssembly for near-native performance in any modern browser.
Features
- In-Browser Vector Search — Sub-millisecond retrieval with zero network latency
- Semantic & Hybrid Search — Beyond keyword matching
- Multi-Index Support — Manage multiple isolated search spaces
- Full CRUD — Create, update, and delete indexes and documents from the browser
- Privacy-First — Queries run entirely in the browser, no data leaves the device
Installation
npm install @moss-dev/moss-webVersion 1.2.0 resolves @moss-dev/[email protected]. Text query() loads its
model through the Moss service using the client's credentials, so the service
must be reachable the first time a model is loaded; there is no offline
fallback. The only published npm versions before this are 1.0.0 and 1.0.1,
where queryWithEmbedding() remains available for caller-supplied embeddings.
Quick Start
import { MossClient } from "@moss-dev/moss-web";
// Initialize client (WASM loads on first use; the exact model artifact loads on first query)
const client = new MossClient("your-project-id", "your-project-key");
// Create an index with documents
await client.createIndex("knowledge-base", [
{ id: "1", text: "Machine learning fundamentals" },
{ id: "2", text: "Deep learning neural networks" },
]);
// Load the index into browser memory for fast local queries
await client.loadIndex("knowledge-base");
// Query — runs entirely in-browser
const results = await client.query("knowledge-base", "AI and neural networks");
results.docs.forEach((doc) => {
console.log(`${doc.id}: ${doc.text} (score: ${doc.score})`);
});API
Creating a Client
// Simple: lazy WASM initialization
const client = new MossClient(projectId, projectKey, options?);
// Alternative: eager WASM initialization
const client = await MossClient.create(projectId, projectKey, options?);
// Production frontends: keep the project key on your server and pass an
// IAuthenticator that fetches short-lived tokens from your backend
const client = new MossClient(projectId, authenticator, options?);
const client = await MossClient.create(projectId, authenticator, options?);Custom authenticator:
import type { IAuthenticator, AuthToken } from "@moss-dev/moss-web";
class MyBackendAuthenticator implements IAuthenticator {
async getAuthToken(): Promise<AuthToken> {
const res = await fetch("/api/moss-token", { method: "POST" });
return res.json(); // { token, expiresIn }
}
async getAuthHeader(): Promise<string> {
const { token } = await this.getAuthToken();
return `Bearer ${token}`;
}
}
const client = new MossClient(projectId, new MyBackendAuthenticator());
await client.getAuthToken(); // cached AuthTokenTokens are cached until 60 seconds before expiry and refetched after a 401.
Options:
model—"moss-minilm"(default, fast, for most use-cases) or"moss-mediumlm"baseUrl— Custom API base URL (for self-hosted Moss instances)
Index Management
// Create index with documents
await client.createIndex(name, docs, options?);
// Create index from files
await client.createIndexFromFiles(name, files, options?);
// Add or update documents
await client.addDocs(name, docs, options?);
// Delete documents by ID
await client.deleteDocs(name, docIds, options?);
// Get index metadata
await client.getIndex(name);
// List all indexes
await client.listIndexes();
// Delete an index
await client.deleteIndex(name);
// Get documents from an index
await client.getDocs(name, options?);
// Check job status for async operations
await client.getJobStatus(jobId);Local Search
// Load index into browser memory for querying
await client.loadIndex(name, options?);
// Load several indexes; failures are reported per name, successes are kept
await client.loadIndexes(names, options?);
// Check if index is loaded locally
await client.hasIndex(name);
// Get local index info
await client.getIndexInfo(name);
// Query a foundation-model index using its server-bound immutable artifact
await client.query(name, queryText, options?);
// Query a custom index with a caller-supplied embedding
await client.queryWithEmbedding(name, queryText, embedding, options?);
// Search several loaded indexes at once; results carry their source indexName
await client.queryMultiIndex(names, queryText, options?);
// Multi-index search with a caller-supplied embedding
await client.queryMultiIndexWithEmbedding(names, queryText, embedding, options?);
// Refresh index from server
await client.refreshIndex(name);
// Unload index from browser memory
await client.unloadIndex(name);
// Unload several indexes; names that are not loaded are ignored
await client.unloadIndexes(names);loadIndex and loadIndexes accept LoadIndexOptions (autoRefresh,
pollingIntervalInSeconds) for parity with the Node SDK, but the browser SDK
does not honor them yet; use refreshIndex to pull server updates.
Multi-index search
All named indexes must already be loaded and share one embedding model
artifact. topK is the global cap across the union, not a per-index cap
(default 10, matching the Node SDK; single-index query defaults to 5), and
alpha behaves as it does for a single index: 1.0 embedding-only, 0.0
keyword-only, values in between fuse both rankings (default 0.8). Every
returned document carries the indexName it came from; single-index results
leave indexName unset.
const { loaded, failed } = await client.loadIndexes(["handbook", "changelog"]);
console.log(loaded, failed); // ["handbook", "changelog"] {}
const results = await client.queryMultiIndex(loaded, "refund policy", {
topK: 5,
alpha: 0.8,
});
results.docs.forEach((doc) => {
console.log(`${doc.indexName}/${doc.id}: ${doc.score}`);
});
await client.unloadIndexes(loaded);Multi-index search needs a @moss-dev/moss-wasm that exposes
queryMultiIndexWithModelIdentity; older packages fail fast with an upgrade
error.
Cleanup
client.dispose();License
See LICENSE.
