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

@beignet/provider-search-meilisearch

v0.0.48

Published

Meilisearch-backed search provider for Beignet

Readme

@beignet/provider-search-meilisearch

Meilisearch-backed SearchPort provider for Beignet applications.

The provider installs ctx.ports.search and adapts Beignet's provider-neutral search API to Meilisearch indexes, documents, filters, sorting, facets, and offset pagination.

createMeilisearchSearchProvider(...) returns the stable MeilisearchSearchProvider type. MeilisearchConfig describes its validated config; the Zod schema remains internal.

Install

bun add @beignet/provider-search-meilisearch @beignet/core

Register

// server/providers.ts
import { createMeilisearchSearchProvider } from "@beignet/provider-search-meilisearch";

export const providers = [
  createMeilisearchSearchProvider({
    indexPrefix: "my_app",
  }),
];

Set MEILISEARCH_HOST for the default env-backed provider. Set MEILISEARCH_API_KEY when your Meilisearch instance requires one. Environment variables:

  • MEILISEARCH_HOST (required unless you pass host or client)
  • MEILISEARCH_API_KEY
  • MEILISEARCH_INDEX_PREFIX
  • MEILISEARCH_TIMEOUT_MS

beignet doctor --strict checks that installed Meilisearch providers are registered in server/providers.ts and that MEILISEARCH_HOST is present in app env examples or config when the env-backed provider is used.

You can also pass an existing client or direct connection options:

createMeilisearchSearchProvider({
  host: "https://search.example.com",
  apiKey: process.env.MEILISEARCH_API_KEY,
});

Use

import { defineSearchIndex } from "@beignet/core/search";

type IssueSearchDocument = {
  id: string;
  tenantId: string;
  key: string;
  title: string;
  status: "open" | "resolved";
  createdAt: string;
};

export const issueSearchIndex = defineSearchIndex<IssueSearchDocument>(
  "issues",
  {
    searchableAttributes: ["key", "title"],
    filterableAttributes: ["tenantId", "status"],
    sortableAttributes: ["createdAt"],
  },
);

await ctx.ports.search.indexDocuments(issueSearchIndex, {
  id: issue.id,
  tenantId: issue.tenantId,
  key: issue.key,
  title: issue.title,
  status: issue.status,
  createdAt: issue.createdAt,
});

const results = await ctx.ports.search.search(issueSearchIndex, {
  query: "billing",
  filters: { tenantId },
  sort: ["createdAt:desc"],
  limit: 20,
});

The Meilisearch adapter validates query fields before sending a request: filters and facets must use fields declared in filterableAttributes, sort must use fields declared in sortableAttributes, and field names must be simple identifiers or dotted paths. Map raw request input to app-owned allow-listed field names before passing it to SearchPort.

API

createMeilisearchSearch(options)

Creates a SearchPort from a Meilisearch-compatible client. Use this for tests or custom provider composition.

createMeilisearchClient(options)

Creates the small fetch-backed client used by the provider. It sends JSON requests to Meilisearch and throws MeilisearchHttpError for non-2xx responses.

createMeilisearchSearchProvider(options)

Creates a Beignet lifecycle provider that contributes:

  • ctx.ports.search, the standard Beignet SearchPort
  • ctx.ports.meilisearch, an escape hatch with the raw client, index prefix, and checkHealth() helper

createMeilisearchSearchProvider()

Ready-to-register provider using MEILISEARCH_* environment variables.

Devtools

When @beignet/devtools or another provider instrumentation sink is installed before this provider, indexing, deleting, search, and settings operations appear under the Search watcher. Events include the index, operation, document count, duration, and success or failure status; document bodies are not recorded.

Failure behavior

The env-backed provider throws during startup when MEILISEARCH_HOST is missing. Meilisearch non-2xx responses throw MeilisearchHttpError, including the request path, response status, and parsed or raw response body when available. Plain-text or HTML proxy responses are preserved on the error's body instead of surfacing as an unrelated JSON parse failure. Indexing operations in Meilisearch are asynchronous: a successful write means the task was accepted, not that the document is immediately searchable. Use ctx.ports.meilisearch.checkHealth() from app-owned readiness endpoints to call Meilisearch's /health endpoint without indexing or searching documents.

Local and tests

Use a fake or in-memory SearchPort in use-case tests so tests can assert search intent without depending on Meilisearch task timing. Use the direct createMeilisearchSearch(...) factory with a test client for provider adapter tests.

Deployment notes

Treat Meilisearch as a read model. Feed it from committed app state through outbox, listeners, jobs, or backfill tasks, and make stale-search behavior acceptable in the UI and API.

Correctness note

Search indexes are read models. Keep transactional truth in your database and use search for discovery, filtering, ranking, and faceted browsing. For durable indexing, pair this port with Beignet outbox/listener workflows or operational backfill tasks.