npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@moss-dev/moss

v1.7.1

Published

Readme

Moss client library for JavaScript

@moss-dev/moss enables private, on-device semantic search in your web, mobile, and edge applications - without cloud dependencies.

Built for developers who want instant, memory-efficient, privacy-first AI features inside their apps.

✨ Features

  • On-Device Vector Search - Sub-millisecond retrieval with zero network latency
  • 🔍 Semantic Search & Hybrid Search - Beyond keyword matching
  • 📦 Multi-Index Support - Manage multiple isolated search spaces
  • 🛠️ Tiny SDK - Optimized for edge deployments
  • 🛡️ Privacy-First by Design - No server-side cloud calls required to perform searches

📦 Installation

npm install @moss-dev/moss

🚀 Quick Start

import { MossClient, DocumentInfo } from "@moss-dev/moss";

async function main() {
  // Initialize search client with project credentials
  const mossClient = new MossClient(
    "your-project-id",
    "your-project-key"
  );

  // Prepare documents to index
  const documents: DocumentInfo[] = [
    {
      id: "doc1",
      text: "How do I track my order? You can track your order by logging into your account.",
    },
    {
      id: "doc2", 
      text: "What is your return policy? We offer a 30-day return policy for most items.",
    },
    {
      id: "doc3",
      text: "How can I change my shipping address? Contact our customer service team.",
    },
    // Add more documents here
    // .
    // .
    // .
  ];

  try {
    // Create an index with documents and model
    const indexName = "faqs";
    const created = await mossClient.createIndex(
      indexName,
      documents
    ); // Defaults to the service's `moss-minilm` model when omitted
    console.log("Index created:", created);

    // Load the index before searching
    await mossClient.loadIndex(indexName);

    // Search the index
    const result = await mossClient.query(indexName, "How do I return a damaged product?", {
      topK: 3,
    });

    // Display results
    console.log(`Query: ${result.query}`);
    result.docs.forEach((match) => {
      console.log(`Score: ${match.score.toFixed(4)}`);
      console.log(`ID: ${match.id}`);
      console.log(`Text: ${match.text}`);
      console.log("---");
    });
  } finally {
    // Release the client's underlying resources once you're done with it
    await mossClient.close();
  }
}

main().catch(console.error);

To use a host-managed stable id for MAD billing while retaining Moss's own device UUID for correlation:

const mossClient = new MossClient("project", "key", {
  identity: { deviceId: "host-installation-id", userId: "optional-user-id" },
});

deviceId is billable. userId is optional and non-billable. Telemetry also includes Moss's file-backed UUID as mossDeviceId; without a host id, both device fields contain that Moss UUID.

Resource cleanup

MossClient and sessions returned by client.session(...) hold native resources that must be released explicitly. Call close() on each one when you are done with it, in a finally block or equivalent. close() is idempotent, so it is safe to call more than once.

client.close() also closes every live session created from that client. Closing a session individually first is fine; close() is idempotent on both.

On Node 24 and later, both MossClient and sessions implement Symbol.asyncDispose, so you can use await using instead of a manual try/finally:

await using mossClient = new MossClient("your-project-id", "your-project-key");
// mossClient.close() is called automatically when it goes out of scope

🔥 Example Use Cases

  • Smart knowledge base search
  • Realtime Voice AI agents
  • Personal note-taking search
  • Private in-app AI features (recommendations, retrieval)
  • Local semantic search in edge devices, AR/VR, mobile apps

🧠 Providing custom embeddings

Already using your own embedding model? Supply vectors directly when managing indexes:

const documents = [
  {
    id: "doc-1",
    text: "Attach a caller-provided embedding",
    embedding: myEmbeddingModel("doc-1"),
  },
  {
    id: "doc-2",
    text: "Fallback to the built-in model when the field is omitted.",
  },
];

await mossClient.createIndex("custom-embeddings", documents);

await mossClient.loadIndex("custom-embeddings");

const results = await mossClient.query("custom-embeddings", "", {
  embedding: myEmbeddingModel("query"),
  topK: 10,
});

Leaving modelId undefined defaults to moss-minilm. You can still pass { modelId: "moss-mediumlm" } or another supported identifier if you want the service to generate embeddings for documents without the optional embedding field.

Foundation model identity

Moss generates local query embeddings for a foundation-model index only when the service supplies the exact immutable model artifact identity used to build that index. This prevents a query from being embedded with different model bytes than the stored document vectors.

Fresh local sessions using moss-minilm, moss-mediumlm, or moss-litelm bind that model's official current artifact automatically before model warmup. Caller-supplied artifact identities are validated and kept, while custom models are never auto-bound. saveToDisk records the exact model id, artifact version, and manifest SHA-256, so the same session can be restored and queried with raw text:

const first = await mossClient.session("memory");
await first.addDocs([{ id: "refund", text: "Customer requested a refund" }]);
await first.saveToDisk(cachePath);
await first.close();

const restored = await mossClient.session("memory");
await restored.loadFromDisk(cachePath);
const results = await restored.query("refund");

Session caches created by older SDKs without an artifact version and manifest SHA-256 load as custom sessions through the legacy fail-closed path. Their raw text queries require an explicit caller-generated embedding. Rebuild those caches from their source documents with the current SDK, then save them again so the automatically bound foundation identity is persisted.

Older indexes without that identity still load and remain queryable, but the query must include a caller-generated vector of the correct dimension:

const results = await mossClient.query("legacy-index", "search text", {
  embedding: myEmbeddingModel("search text"),
  topK: 10,
});

If the vector is omitted, the query fails closed with an error stating that an explicit query embedding is required. Moss does not silently fall back to an unverified local model or send the query to the cloud.

Metadata filtering

You can pass a metadata filter in query options after loading an index locally:

const results = await mossClient.query("my-docs", "running shoes", {
  topK: 5,
  alpha: 0.6,
  filter: {
    $and: [
      { field: "category", condition: { $eq: "shoes" } },
      { field: "price", condition: { $lt: "100" } },
    ],
  },
});

For a complete runnable example, see javascript/user-facing-sdk/samples/metadata-filtering.ts.

📄 License

This package is licensed under the PolyForm Shield License 1.0.0.

  • ✅ Free for testing, evaluation, internal use, and modifications.
  • ❌ Not permitted for production or competing commercial use.
  • 📩 For commercial licenses, contact: [email protected]

📬 Contact

For support, commercial licensing, or partnership inquiries, contact us: [email protected]