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

@molecule/api-search-typesense

v1.0.1

Published

Typesense search provider for molecule.dev

Downloads

533

Readme

@molecule/api-search-typesense

Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit src/index.ts JSDoc, not this file.

Typesense search provider for molecule.dev.

Implements the SearchProvider interface using the typesense client. Supports full-text search, faceted filtering, bulk indexing, and autocomplete suggestions.

Quick Start

import { setProvider } from '@molecule/api-search'
import { provider } from '@molecule/api-search-typesense'

setProvider(provider)

Type

provider

Installation

npm install @molecule/api-search-typesense @molecule/api-search @molecule/api-secrets typesense

API

Interfaces

BulkIndexResult

Result of a bulk index operation.

interface BulkIndexResult {
  /**
   * Number of documents successfully indexed.
   */
  indexed: number
  /**
   * Number of documents that failed to index.
   */
  failed: number
  /**
   * Errors encountered during bulk indexing, keyed by document id.
   */
  errors: Record<string, string>
}

FacetCount

A single facet count entry.

interface FacetCount {
  /**
   * The facet value.
   */
  value: string
  /**
   * Number of documents matching this facet value.
   */
  count: number
}

IndexDocument

A document to be indexed in a bulk operation.

interface IndexDocument {
  /**
   * Unique identifier for the document.
   */
  id: string
  /**
   * The document fields and values.
   */
  document: Record<string, unknown>
}

IndexSchema

Schema definition for a search index, describing the fields and their roles.

interface IndexSchema {
  /**
   * Map of field names to their types.
   */
  fields: Record<string, FieldType>
  /**
   * Fields that are searchable via full-text queries.
   */
  searchableFields?: string[]
  /**
   * Fields that can be used in filter expressions.
   */
  filterableFields?: string[]
  /**
   * Fields that can be used for sorting results.
   */
  sortableFields?: string[]
}

SearchHit

A single search result hit.

interface SearchHit {
  /**
   * Document identifier.
   */
  id: string
  /**
   * Relevance score.
   */
  score: number
  /**
   * The matched document fields.
   */
  document: Record<string, unknown>
  /**
   * Highlighted field snippets, keyed by field name.
   */
  highlights?: Record<string, string[]>
}

SearchProvider

Search provider interface.

All search providers must implement this interface to provide full-text search, indexing, and suggestion capabilities.

interface SearchProvider {
  /**
   * Creates a search index with an optional schema.
   *
   * @param name - Index name.
   * @param schema - Optional schema describing field types and roles.
   */
  createIndex(name: string, schema?: IndexSchema): Promise<void>
  /**
   * Deletes a search index and all its documents.
   *
   * @param name - Index name to delete.
   */
  deleteIndex(name: string): Promise<void>
  /**
   * Indexes a single document.
   *
   * @param indexName - Target index name.
   * @param id - Unique document identifier.
   * @param document - The document fields and values.
   */
  index(indexName: string, id: string, document: Record<string, unknown>): Promise<void>
  /**
   * Indexes multiple documents in a single operation.
   *
   * @param indexName - Target index name.
   * @param documents - Array of documents to index.
   * @returns Result with indexed/failed counts and errors.
   */
  bulkIndex(indexName: string, documents: IndexDocument[]): Promise<BulkIndexResult>
  /**
   * Executes a full-text search query against an index.
   *
   * @param indexName - Index to search.
   * @param query - Search query with text, filters, pagination, etc.
   * @returns Search results with hits, total count, facets, and timing.
   */
  search(indexName: string, query: SearchQuery): Promise<SearchResult>
  /**
   * Deletes a document from an index by id.
   *
   * @param indexName - Index containing the document.
   * @param id - Document identifier to delete.
   */
  delete(indexName: string, id: string): Promise<void>
  /**
   * Returns typeahead/autocomplete suggestions for a partial query.
   *
   * @param indexName - Index to generate suggestions from.
   * @param query - Partial text to complete.
   * @param options - Suggestion options (limit, fields, fuzzy).
   * @returns Array of suggestions sorted by relevance.
   */
  suggest(indexName: string, query: string, options?: SuggestOptions): Promise<Suggestion[]>
  /**
   * Retrieves a single document from an index by id.
   *
   * @param indexName - Index containing the document.
   * @param id - Document identifier.
   * @returns The document fields, or `null` if not found.
   */
  getDocument(indexName: string, id: string): Promise<Record<string, unknown> | null>
}

SearchQuery

A full-text search query with optional filters, facets, sorting, and pagination.

interface SearchQuery {
  /**
   * The search text.
   *
   * Empty or whitespace-only text is "browse" mode: bond implementations
   * MUST match ALL documents (subject to `filters`, `sort`, and pagination)
   * rather than erroring or returning zero hits. Every bundled bond
   * (Elasticsearch, Meilisearch, Typesense, PostgreSQL) follows this
   * contract, so swapping providers doesn't silently change what an empty
   * search box shows.
   */
  text: string
  /**
   * Filter expressions to narrow results.
   */
  filters?: Record<string, unknown>
  /**
   * Fields to compute facet counts for.
   */
  facets?: string[]
  /**
   * Sort fields and directions.
   */
  sort?: SortField[]
  /**
   * Page number (1-based).
   */
  page?: number
  /**
   * Number of results per page.
   */
  perPage?: number
  /**
   * Whether to include highlighted snippets in results.
   */
  highlight?: boolean
}

SearchResult

The result of a search query, including hits, pagination, facets, and timing.

interface SearchResult {
  /**
   * Matched documents.
   */
  hits: SearchHit[]
  /**
   * Total number of matching documents.
   */
  total: number
  /**
   * Current page number.
   */
  page: number
  /**
   * Number of results per page.
   */
  perPage: number
  /**
   * Facet counts keyed by field name.
   */
  facets?: Record<string, FacetCount[]>
  /**
   * Time taken to process the query in milliseconds.
   */
  processingTimeMs: number
}

SortField

A field to sort search results by.

interface SortField {
  /**
   * The field name to sort on.
   */
  field: string
  /**
   * Sort direction.
   */
  direction: SortDirection
}

Suggestion

A single autocomplete suggestion.

interface Suggestion {
  /**
   * The suggested text.
   */
  text: string
  /**
   * Relevance score for ranking suggestions.
   */
  score: number
  /**
   * Optional highlighted version of the suggestion.
   */
  highlighted?: string
}

SuggestOptions

Options for typeahead / autocomplete suggestions.

interface SuggestOptions {
  /**
   * Maximum number of suggestions to return.
   */
  limit?: number
  /**
   * Fields to generate suggestions from.
   */
  fields?: string[]
  /**
   * Whether to apply fuzzy matching.
   */
  fuzzy?: boolean
}

TypesenseOptions

Configuration options for the Typesense search provider.

interface TypesenseOptions {
  /**
   * Typesense node URL(s).
   *
   * @default [{ host: process.env.TYPESENSE_HOST ?? 'localhost', port: Number(process.env.TYPESENSE_PORT ?? 8108), protocol: process.env.TYPESENSE_PROTOCOL ?? 'http' }]
   */
  nodes?: Array<{ host: string; port: number; protocol: string }>

  /**
   * Typesense API key for authentication.
   *
   * @default process.env.TYPESENSE_API_KEY
   */
  apiKey?: string

  /**
   * Connection timeout in SECONDS (not milliseconds — this is passed straight
   * to the typesense client's `connectionTimeoutSeconds`).
   *
   * @default 5
   */
  connectionTimeoutSeconds?: number

  /**
   * Number of retries for failed requests.
   *
   * @default 3
   */
  numRetries?: number
}

Types

FieldType

Field type for index schema definitions.

type FieldType = 'text' | 'keyword' | 'number' | 'boolean' | 'date' | 'geo'

SortDirection

Sort direction for search results.

type SortDirection = 'asc' | 'desc'

Functions

createProvider(options)

Creates a Typesense search provider instance.

function createProvider(options?: TypesenseOptions): SearchProvider
  • options — Provider configuration options.

Returns: A fully configured SearchProvider implementation.

Constants

provider

Default lazily-initialized Typesense search provider. Uses environment variables for configuration.

const provider: SearchProvider

searchTypesenseSecretDefinitions

Secret definitions required by the Typesense search bond.

const searchTypesenseSecretDefinitions: SecretDefinition[]

Core Interface

Implements @molecule/api-search interface.

Bond Wiring

Setup function to register this provider with the core interface:

import { setProvider } from '@molecule/api-search'
import { provider } from '@molecule/api-search-typesense'

export function setupSearchTypesense(): void {
  setProvider(provider)
}

Injection Notes

Requirements

Peer dependencies:

  • @molecule/api-search ^1.0.1
  • @molecule/api-secrets ^1.0.1

Environment Variables

  • TYPESENSE_HOST (required) — Typesense host
    • Setup: Hostname of your Typesense node (Typesense Cloud or self-hosted).
    • Example: localhost
  • TYPESENSE_API_KEY (required) — Typesense API key
    • Setup: The API key you configured when launching Typesense (or from Typesense Cloud).

Runtime Dependencies

  • @molecule/api-search
  • @molecule/api-secrets
  • typesense

Provider-specific behavior to know before debugging (verified against Typesense 29.0):

  • date fields map to int64 — index date values as epoch numbers (e.g. Date.now() or Unix seconds), NOT as Date objects or ISO strings, or the document is rejected by the collection schema.
  • When createIndex() is given a schema, only the keys of schema.fields are indexed — document fields missing from the schema are stored and returned, but not searchable or filterable. Without a schema, an auto-schema collection (.*: auto) indexes every field.
  • Filter string values are backtick-quoted so punctuation (&&, commas, parentheses) in values is safe; a literal backtick inside a filter value is not representable in Typesense filter syntax. Filtering requires the field to be faceted — declare it in filterableFields.
  • Empty search text matches ALL documents (q: '*'), per the core SearchQuery.text browse-mode contract — consistent with every bundled search bond.
  • connectionTimeoutSeconds is in seconds (default 5).

E2E Tests

Integration checklist — drive the real UI (live preview, no mocks), adapt each item to this app's actual screens/flows, and check every box off one by one. A box you can't check is an integration bug to fix — not a skip:

  • [ ] Searching a term that exists in seeded data returns the matching records in the results UI.
  • [ ] An empty search box shows the browse-everything view (empty text matches ALL documents by contract) — not zero results and not an error.
  • [ ] A term with no matches shows a clear "no results" state.
  • [ ] Index-on-write is wired: create a new record through the UI, then search for it — it must be findable without a manual reindex.
  • [ ] If autocomplete/suggestions are surfaced, typing a prefix of a known record shows relevant suggestions.
  • [ ] Search is scoped to the caller: one user's search never returns another user's private records.