ruvector-router-wasm

Crates.ioruvector-router-wasm
lib.rsruvector-router-wasm
version0.1.29
created_at2025-11-21 15:11:25.153696+00
updated_at2025-12-29 19:17:45.713761+00
descriptionWASM bindings for ruvector-router-core
homepage
repositoryhttps://github.com/ruvnet/ruvector
max_upload_size
id1943707
size56,748
rUv (ruvnet)

documentation

README

Router WASM

License: MIT npm version Bundle Size WebAssembly

WebAssembly bindings for intelligent neural routing and vector search in the browser.

Bring powerful vector database capabilities to the client-side. Run sub-millisecond vector search entirely in the browser with zero server dependencies. Perfect for edge computing, offline AI, and privacy-first applications.

🌟 Why Router WASM?

Traditional vector databases require backend infrastructure and constant network connectivity. Router WASM changes that.

The Browser-First Advantage

  • ⚑ Zero Latency: No network roundtripsβ€”search happens entirely in the browser
  • πŸ”’ Privacy First: User data never leaves the device
  • 🌐 Offline Capable: Full functionality without internet connection
  • πŸ’° Cost Effective: Eliminate backend infrastructure and API costs
  • πŸš€ Edge Computing: Deploy intelligent routing to CDN edge nodes
  • πŸ“¦ Small Bundle: Optimized WASM binary for fast page loads

πŸš€ Features

Core Capabilities

  • Client-Side Vector Search: Sub-millisecond similarity search in the browser
  • Neural Routing: Intelligent request routing and pattern matching
  • Multiple Distance Metrics: Euclidean, Cosine, Dot Product, Manhattan
  • HNSW Indexing: Fast approximate nearest neighbor search
  • Memory Efficient: Optimized for browser memory constraints
  • TypeScript Support: Full type definitions included
  • Framework Agnostic: Works with React, Vue, Svelte, vanilla JS
  • Web Worker Ready: Run computations off the main thread

Browser-Specific Optimizations

  • SIMD Acceleration: Hardware-accelerated vector operations where available
  • Progressive Loading: Load and initialize asynchronously
  • Lazy Initialization: Initialize only when needed
  • Small Footprint: <100KB gzipped WASM binary
  • Memory Pooling: Efficient memory management for long-running sessions
  • IndexedDB Integration: Persist vector data locally

πŸ“¦ Installation

NPM/Yarn

# Using npm
npm install router-wasm

# Using yarn
yarn add router-wasm

# Using pnpm
pnpm add router-wasm

CDN (Unpkg)

<script type="module">
  import init, { VectorDB } from 'https://unpkg.com/router-wasm/router_wasm.js';

  await init();
  const db = new VectorDB(128);
</script>

⚑ Quick Start

Basic Usage (ES Modules)

import init, { VectorDB, DistanceMetric } from 'router-wasm';

// Initialize WASM module (only once)
await init();

// Create a vector database with 128 dimensions
const db = new VectorDB(128);

// Insert vectors
db.insert('doc1', new Float32Array([0.1, 0.2, 0.3, /* ... 125 more */]));
db.insert('doc2', new Float32Array([0.4, 0.5, 0.6, /* ... 125 more */]));
db.insert('doc3', new Float32Array([0.7, 0.8, 0.9, /* ... 125 more */]));

// Search for similar vectors
const query = new Float32Array([0.15, 0.25, 0.35, /* ... 125 more */]);
const results = db.search(query, 5);  // Top 5 results

// Process results
for (const result of results) {
  console.log(`ID: ${result.id}, Score: ${result.score}`);
}

// Get collection size
console.log(`Total vectors: ${db.count()}`);

// Delete a vector
db.delete('doc2');

TypeScript Support

import init, { VectorDB, DistanceMetric } from 'router-wasm';

interface SearchResult {
  id: string;
  score: number;
}

async function initializeVectorSearch(): Promise<VectorDB> {
  // Initialize WASM
  await init();

  // Create database with 384 dimensions (e.g., for sentence embeddings)
  const db = new VectorDB(384);

  return db;
}

async function semanticSearch(
  db: VectorDB,
  queryEmbedding: Float32Array,
  topK: number = 10
): Promise<SearchResult[]> {
  const results = db.search(queryEmbedding, topK);
  return results;
}

React Integration

import React, { useState, useEffect } from 'react';
import init, { VectorDB } from 'router-wasm';

function VectorSearchApp() {
  const [db, setDb] = useState(null);
  const [loading, setLoading] = useState(true);
  const [results, setResults] = useState([]);

  useEffect(() => {
    async function initialize() {
      await init();
      const vectorDb = new VectorDB(128);

      // Populate with sample data
      vectorDb.insert('item1', new Float32Array(128).fill(0.1));
      vectorDb.insert('item2', new Float32Array(128).fill(0.5));

      setDb(vectorDb);
      setLoading(false);
    }

    initialize();
  }, []);

  const handleSearch = async (queryVector) => {
    if (!db) return;

    const searchResults = db.search(queryVector, 10);
    setResults(searchResults);
  };

  if (loading) return <div>Loading vector database...</div>;

  return (
    <div>
      <h1>Client-Side Vector Search</h1>
      <button onClick={() => handleSearch(new Float32Array(128).fill(0.2))}>
        Search
      </button>
      <ul>
        {results.map(r => (
          <li key={r.id}>
            {r.id}: {r.score.toFixed(4)}
          </li>
        ))}
      </ul>
    </div>
  );
}

export default VectorSearchApp;

Vue 3 Integration

<template>
  <div>
    <h1>Vector Search</h1>
    <input v-model="searchQuery" @input="handleSearch" placeholder="Search..." />
    <ul>
      <li v-for="result in results" :key="result.id">
        {{ result.id }}: {{ result.score.toFixed(4) }}
      </li>
    </ul>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import init, { VectorDB } from 'router-wasm';

const db = ref(null);
const searchQuery = ref('');
const results = ref([]);

onMounted(async () => {
  await init();
  db.value = new VectorDB(128);

  // Populate database
  db.value.insert('doc1', new Float32Array(128).fill(0.1));
  db.value.insert('doc2', new Float32Array(128).fill(0.5));
});

const handleSearch = () => {
  if (!db.value || !searchQuery.value) return;

  // Convert query to embedding (simplified example)
  const queryVector = new Float32Array(128).fill(parseFloat(searchQuery.value) || 0);
  results.value = db.value.search(queryVector, 5);
};
</script>

🎯 Use Cases

Client-Side AI Applications

Semantic Search in the Browser

// RAG (Retrieval Augmented Generation) in the browser
import init, { VectorDB } from 'router-wasm';
import { generateEmbedding } from './embeddings';  // Your embedding model

await init();
const knowledgeBase = new VectorDB(384);

// Index documents
const docs = [
  { id: 'doc1', text: 'Rust is a systems programming language' },
  { id: 'doc2', text: 'WebAssembly enables near-native performance' },
  { id: 'doc3', text: 'Vector databases power semantic search' }
];

for (const doc of docs) {
  const embedding = await generateEmbedding(doc.text);
  knowledgeBase.insert(doc.id, embedding);
}

// Query with natural language
const queryEmbedding = await generateEmbedding('What is WASM?');
const relevantDocs = knowledgeBase.search(queryEmbedding, 3);

Offline Recommender System

// Product recommendations without backend
const productDb = new VectorDB(256);

// Index product features
products.forEach(product => {
  const featureVector = extractFeatures(product);
  productDb.insert(product.id, featureVector);
});

// Get recommendations based on user preferences
const userPreferences = getUserPreferenceVector();
const recommendations = productDb.search(userPreferences, 10);

Privacy-First Search

// Search user data without sending to server
const privateDb = new VectorDB(512);

// User data stays in browser
userDocuments.forEach(doc => {
  const embedding = embedDocument(doc);
  privateDb.insert(doc.id, embedding);
});

// All searches happen locally
const results = privateDb.search(queryEmbedding, 20);

Edge Computing & CDN

Cloudflare Workers

// Deploy to Cloudflare Workers
import init, { VectorDB } from 'router-wasm';

export default {
  async fetch(request, env, ctx) {
    await init();

    const db = new VectorDB(128);
    // Load pre-computed vectors from KV store
    const vectors = await env.VECTORS.get('index', 'json');

    for (const [id, vector] of Object.entries(vectors)) {
      db.insert(id, new Float32Array(vector));
    }

    // Handle search at edge
    const { query } = await request.json();
    const results = db.search(new Float32Array(query), 10);

    return new Response(JSON.stringify(results), {
      headers: { 'content-type': 'application/json' }
    });
  }
};

Deno Deploy

// Edge function with vector search
import init, { VectorDB } from 'https://esm.sh/router-wasm';

Deno.serve(async (req) => {
  await init();

  const db = new VectorDB(256);
  // Your edge routing logic

  return new Response('OK');
});

Web Workers

// worker.js - Run vector search off main thread
import init, { VectorDB } from 'router-wasm';

let db = null;

self.addEventListener('message', async (e) => {
  const { type, payload } = e.data;

  if (type === 'init') {
    await init();
    db = new VectorDB(payload.dimensions);
    self.postMessage({ type: 'ready' });
  }

  if (type === 'insert') {
    db.insert(payload.id, new Float32Array(payload.vector));
    self.postMessage({ type: 'inserted', id: payload.id });
  }

  if (type === 'search') {
    const results = db.search(new Float32Array(payload.query), payload.k);
    self.postMessage({ type: 'results', data: results });
  }
});
// main.js - Use the worker
const worker = new Worker('worker.js', { type: 'module' });

worker.postMessage({ type: 'init', payload: { dimensions: 128 } });

worker.addEventListener('message', (e) => {
  if (e.data.type === 'ready') {
    console.log('Vector DB ready in worker');

    // Insert data
    worker.postMessage({
      type: 'insert',
      payload: { id: 'doc1', vector: new Array(128).fill(0.1) }
    });

    // Search
    worker.postMessage({
      type: 'search',
      payload: { query: new Array(128).fill(0.2), k: 5 }
    });
  }

  if (e.data.type === 'results') {
    console.log('Search results:', e.data.data);
  }
});

πŸ”§ Advanced Features

Persistent Storage (IndexedDB)

import init, { VectorDB } from 'router-wasm';

// Initialize with persistent storage path
await init();
const db = new VectorDB(128, 'my-vector-store');

// Data persists across sessions
db.insert('doc1', new Float32Array(128));

// Reload in future session
const db2 = new VectorDB(128, 'my-vector-store');
console.log(db2.count());  // Previously inserted data is available

Distance Metrics

import { VectorDB, DistanceMetric } from 'router-wasm';

const db = new VectorDB(128);

// Different similarity measures available:
// - DistanceMetric.Euclidean (L2 distance)
// - DistanceMetric.Cosine (cosine similarity)
// - DistanceMetric.DotProduct (dot product)
// - DistanceMetric.Manhattan (L1 distance)

// Note: Distance metric is set at index build time in router-core

Batch Operations

// Efficient bulk insertion
const vectors = [
  { id: 'doc1', vector: new Float32Array(128).fill(0.1) },
  { id: 'doc2', vector: new Float32Array(128).fill(0.2) },
  { id: 'doc3', vector: new Float32Array(128).fill(0.3) },
];

vectors.forEach(({ id, vector }) => db.insert(id, vector));

// Batch search (multiple queries)
const queries = [
  new Float32Array(128).fill(0.15),
  new Float32Array(128).fill(0.25),
];

const allResults = queries.map(query => db.search(query, 5));

Memory Management

// Check collection size
const count = db.count();
console.log(`Vectors in database: ${count}`);

// Clean up when done (especially important in SPAs)
// Note: Drop the reference and let garbage collector handle it
db = null;

// For explicit cleanup in long-running apps
function cleanupVectorDb(db) {
  const ids = getAllIds();  // Your tracking logic
  ids.forEach(id => db.delete(id));
}

πŸ“Š Performance Optimization

Bundle Size Optimization

Tree Shaking

// Import only what you need
import init, { VectorDB } from 'router-wasm';
// Don't import unused distance metrics or types

Code Splitting

// Lazy load WASM module
const loadVectorDB = async () => {
  const { default: init, VectorDB } = await import('router-wasm');
  await init();
  return VectorDB;
};

// Use when needed
button.addEventListener('click', async () => {
  const VectorDB = await loadVectorDB();
  const db = new VectorDB(128);
});

Webpack Configuration

// webpack.config.js
module.exports = {
  experiments: {
    asyncWebAssembly: true,
  },
  optimization: {
    splitChunks: {
      chunks: 'all',
    },
  },
};

Runtime Performance

Pre-compute Embeddings

// Generate embeddings server-side or during build
// Ship pre-computed vectors to reduce client computation
const precomputedVectors = await fetch('/vectors.json').then(r => r.json());

await init();
const db = new VectorDB(128);

for (const [id, vector] of Object.entries(precomputedVectors)) {
  db.insert(id, new Float32Array(vector));
}

Dimension Reduction

// Use lower dimensions for faster search
// 128 or 256 dimensions often sufficient for many use cases
const db = new VectorDB(128);  // Instead of 384 or 768

// Consider PCA or other dimensionality reduction techniques

Limit Result Sets

// Request only what you need
const results = db.search(query, 10);  // Top 10, not 100

// Implement pagination if needed
function paginatedSearch(query, page = 0, pageSize = 10) {
  const allResults = db.search(query, (page + 1) * pageSize);
  return allResults.slice(page * pageSize, (page + 1) * pageSize);
}

πŸ”¨ Building from Source

Prerequisites

  • Rust: 1.77 or higher
  • wasm-pack: cargo install wasm-pack
  • Node.js: 18.0 or higher (for testing)

Build Commands

# Clone repository
git clone https://github.com/ruvnet/ruvector.git
cd ruvector/crates/router-wasm

# Build for web (ES modules)
wasm-pack build --target web --release

# Build for Node.js
wasm-pack build --target nodejs --release

# Build for bundlers (webpack, etc.)
wasm-pack build --target bundler --release

# Build with optimizations
wasm-pack build --target web --release -- --features simd

# Run tests
wasm-pack test --headless --chrome

Build Output

After building, the pkg/ directory contains:

pkg/
β”œβ”€β”€ router_wasm.js          # JavaScript bindings
β”œβ”€β”€ router_wasm.d.ts        # TypeScript definitions
β”œβ”€β”€ router_wasm_bg.wasm     # WebAssembly binary
β”œβ”€β”€ router_wasm_bg.wasm.d.ts
└── package.json            # NPM package metadata

Custom Build Profiles

# Cargo.toml - Already optimized for size
[profile.release]
opt-level = "z"              # Optimize for size
lto = true                   # Link-time optimization
codegen-units = 1            # Better optimization
panic = "abort"              # Smaller binary

🌐 Browser Compatibility

Browser Version WASM SIMD Notes
Chrome 87+ βœ… βœ… Full support
Firefox 89+ βœ… βœ… Full support
Safari 15+ βœ… ⚠️ WASM SIMD in 16.4+
Edge 87+ βœ… βœ… Full support
Opera 73+ βœ… βœ… Full support
Mobile Safari 15+ βœ… ⚠️ Limited SIMD
Mobile Chrome 87+ βœ… βœ… Full support

Notes:

  • βœ… Full support
  • ⚠️ Partial support (SIMD acceleration may not be available)
  • All modern browsers support WebAssembly
  • SIMD provides 2-4x performance boost where available

πŸ”— Integration with Ruvector Ecosystem

With ruvector-wasm

import initRouter, { VectorDB as RouterDB } from 'router-wasm';
import initRuvector, { VectorDB } from 'ruvector-wasm';

// Initialize both modules
await Promise.all([initRouter(), initRuvector()]);

// Router WASM: Intelligent routing and pattern matching
const router = new RouterDB(128);

// Ruvector WASM: Full-featured vector database
const vectorDb = new VectorDB(128);

// Use together for advanced use cases

With Node.js Backend

// Frontend (router-wasm)
import init, { VectorDB } from 'router-wasm';
await init();
const clientDb = new VectorDB(128);

// Backend (ruvector Node.js bindings)
const { VectorDB } = require('ruvector');
const serverDb = new VectorDB();

// Hybrid architecture: Local search + server sync

πŸ“š API Reference

VectorDB

class VectorDB {
  /**
   * Create a new vector database
   * @param dimensions - Vector dimensionality (e.g., 128, 256, 384, 768)
   * @param storage_path - Optional persistent storage path
   */
  constructor(dimensions: number, storage_path?: string);

  /**
   * Insert a vector into the database
   * @param id - Unique identifier
   * @param vector - Float32Array of specified dimensions
   * @returns The inserted ID
   */
  insert(id: string, vector: Float32Array): string;

  /**
   * Search for similar vectors
   * @param vector - Query vector
   * @param k - Number of results to return
   * @returns Array of search results with id and score
   */
  search(vector: Float32Array, k: number): SearchResult[];

  /**
   * Delete a vector by ID
   * @param id - ID to delete
   * @returns true if deleted, false if not found
   */
  delete(id: string): boolean;

  /**
   * Get total number of vectors
   * @returns Vector count
   */
  count(): number;
}

Types

interface SearchResult {
  id: string;
  score: number;
}

enum DistanceMetric {
  Euclidean,
  Cosine,
  DotProduct,
  Manhattan
}

πŸŽ“ Examples

Complete RAG Application

See examples/browser-rag for a full-featured Retrieval Augmented Generation application running entirely in the browser.

Product Search

See examples/product-search for an offline product recommendation system.

Edge Routing

See examples/edge-routing for Cloudflare Workers integration.

πŸ› Troubleshooting

WASM Module Not Loading

// Ensure init() is called before creating VectorDB
import init, { VectorDB } from 'router-wasm';

// ❌ Wrong
const db = new VectorDB(128);  // Error: WASM not initialized

// βœ… Correct
await init();
const db = new VectorDB(128);

Large Bundle Size

// Use dynamic imports for code splitting
const { default: init, VectorDB } = await import('router-wasm');
await init();

Memory Errors in Browser

// Reduce dimensions or limit database size
const db = new VectorDB(128);  // Instead of 768

// Clear vectors periodically in long-running apps
if (db.count() > 10000) {
  // Implement your pruning logic
  oldIds.forEach(id => db.delete(id));
}

TypeScript Errors

// Ensure TypeScript can find declarations
// tsconfig.json
{
  "compilerOptions": {
    "moduleResolution": "node",
    "types": ["router-wasm"]
  }
}

πŸ“– Documentation

🀝 Contributing

Contributions are welcome! See Contributing Guidelines.

Development Setup

# Clone and setup
git clone https://github.com/ruvnet/ruvector.git
cd ruvector/crates/router-wasm

# Build
wasm-pack build --target web

# Test
wasm-pack test --headless --chrome --firefox

# Format
cargo fmt

# Lint
cargo clippy -- -D warnings

πŸ“œ License

MIT License - see LICENSE for details.

πŸ™ Acknowledgments

Built with:

  • wasm-bindgen: Rust/JavaScript interop
  • router-core: High-performance vector routing engine
  • HNSW: Fast approximate nearest neighbor search
  • SIMD: Hardware-accelerated vector operations

🌐 Links


Built by rUv β€’ Part of Ruvector β€’ MIT Licensed

Star on GitHub Follow @ruvnet

Browser-First Vector Search | Zero Backend Required | Privacy First

Get Started β€’ Documentation β€’ Examples

Commit count: 729

cargo fmt