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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@goatlab/typesense

v0.1.3

Published

Modern TypeScript wrapper for Typesense search engine API

Readme

@goatlab/typesense

A modern, type-safe TypeScript wrapper for the Typesense search engine API. This package provides a comprehensive client with built-in resilience, multi-tenancy support, and a clean, grouped API interface.

Installation

npm install @goatlab/typesense
# or
pnpm add @goatlab/typesense
# or
yarn add @goatlab/typesense

Basic Usage

import { TypesenseApi } from '@goatlab/typesense'

// Initialize the client
const typesense = new TypesenseApi({
  prefixUrl: 'http://localhost:8108',
  token: 'your-api-key',
  collectionName: 'products' // default collection name
})

// Create a collection
await typesense.collections.create({
  name: 'products',
  fields: [
    { name: 'id', type: 'string' },
    { name: 'title', type: 'string' },
    { name: 'price', type: 'float' },
    { name: 'description', type: 'string' }
  ]
})

// Insert a document
await typesense.documents.insert({
  id: '1',
  title: 'iPhone 15',
  price: 999.99,
  description: 'Latest Apple smartphone'
})

// Search documents
const results = await typesense.search.query({
  q: 'iphone',
  query_by: 'title,description'
})

Key Features

  • Grouped API Interface: Organized methods under logical namespaces (collections, documents, search, admin)
  • Full Type Safety: Generic type support for document operations with compile-time checking
  • Multi-tenancy Support: Built-in tenant isolation with automatic collection name prefixing
  • Resilience Features: Circuit breaker pattern, rate limiting, and automatic retries
  • Schema Management: Automatic schema caching and version compatibility checks
  • Stream Support: Efficient document export with streaming capabilities
  • Advanced Search: Support for text search, vector search, and multi-search operations

Available Methods

Collections

  • collections.create() - Create a new collection
  • collections.get() - Retrieve collection details
  • collections.update() - Update collection schema
  • collections.delete() - Delete a collection
  • collections.list() - List all collections
  • collections.getOrCreate() - Get existing or create new collection

Documents

  • documents.insert() - Insert a single document
  • documents.upsert() - Insert or update a document
  • documents.update() - Update an existing document
  • documents.delete() - Delete a document by ID
  • documents.getById() - Retrieve a document by ID
  • documents.import() - Bulk import documents
  • documents.export() - Export documents (with optional filtering)
  • documents.exportStream() - Export documents as a stream
  • documents.deleteByFilter() - Delete documents matching a filter
  • documents.clear() - Clear all documents in a collection

Search

  • search.query() - Perform a search query
  • search.text() - Text-based search
  • search.vector() - Vector similarity search
  • search.multi() - Execute multiple searches in one request

Admin

  • admin.health() - Check server health
  • admin.waitForHealth() - Wait for server to be healthy
  • admin.getMetrics() - Get server metrics
  • admin.getStats() - Get server statistics
  • admin.getCollectionStats() - Get collection-specific statistics

Additional Features (v29+)

  • Aliases: Create and manage collection aliases
  • Synonyms: Define search synonyms
  • Overrides: Set up search result overrides
  • Presets: Configure search presets

Type Safety

The TypesenseApi supports full type safety for document operations:

Basic Typed API

import { createTypedApi } from '@goatlab/typesense'

// Define your document type
interface Product {
  id: string
  title: string
  price: number
  inStock: boolean
}

// Create a typed API instance
const productApi = createTypedApi<Product>()({
  prefixUrl: 'http://localhost:8108',
  token: 'your-api-key',
  collectionName: 'products'
})

// All document operations are now type-safe
await productApi.documents.insert({
  id: '1',
  title: 'Widget',
  price: 99.99,
  inStock: true
}) // ✅ Typed

// TypeScript will catch errors at compile time
// await productApi.documents.insert({ id: '2', title: 'Gadget' })
// ❌ Error: missing 'price' and 'inStock'

Direct Generic Usage

const api = new TypesenseApi<Product>({
  prefixUrl: 'http://localhost:8108',
  token: 'your-api-key',
  collectionName: 'products'
})

Multi-tenancy

The TypesenseApi provides built-in multi-tenancy support through collection-level isolation:

Basic Tenant Setup

// Create API instance with tenant ID
const api = new TypesenseApi({
  prefixUrl: 'http://localhost:8108',
  token: 'your-api-key',
  tenantId: 'acme',  // Tenant ID
  collectionName: 'products'
})

// All operations use tenant-prefixed collections automatically
// Collection name becomes: 'acme__products'
await api.documents.insert({ id: '1', name: 'Product' })

Type-Safe Tenant APIs

import { forTenant } from '@goatlab/typesense'

interface Customer {
  id: string
  name: string
  email: string
}

// Create tenant-specific APIs with compile-time safety
const tenant1Api = forTenant<Customer, 'tenant1'>('tenant1', {
  prefixUrl: 'http://localhost:8108',
  token: 'your-api-key',
  collectionName: 'customers'
})

// Tenant ID is preserved in the type
const tenantId: 'tenant1' = tenant1Api.tenantId // ✅ Type-safe

Tenant Admin Operations

// List all collections for a tenant
const collections = await api.listTenantCollections()
// Returns: ['acme__products', 'acme__users', ...]

// Get base collection names (without prefix)
const baseNames = await api.listTenantBaseCollectionNames()
// Returns: ['products', 'users', ...]

// Check if a collection exists
const exists = await api.tenantCollectionExists('products')

// Delete all tenant collections (use with caution!)
await api.deleteAllTenantCollections()

Collection Naming Convention

Tenant collections follow the pattern: <tenantId>__<baseCollectionName>

  • Tenant IDs are automatically sanitized (lowercase, alphanumeric + hyphens/underscores)
  • Maximum tenant ID length: 128 characters
  • Examples: acme__products, tenant-123__users

Schema-based Type Safety

The TypesenseApi provides compile-time type safety for your collections using TypeScript's advanced type system:

Define Collections with Type Inference

import { TypesenseApi } from '@goatlab/typesense'

// Define your collection schema with proper const assertions
const ProductCollection = TypesenseApi.defineCollection({
  name: 'products',
  fields: [
    { name: 'id', type: 'string' as const },
    { name: 'title', type: 'string' as const },
    { name: 'description', type: 'string' as const, optional: true },
    { name: 'price', type: 'float' as const },
    { name: 'inStock', type: 'bool' as const },
    { name: 'tags', type: 'string[]' as const, optional: true },
    { name: 'rating', type: 'int32' as const, optional: true }
  ] as const
} as const)

// Create a strongly-typed API instance
const api = TypesenseApi.createSchemaTypedApi(ProductCollection)({
  prefixUrl: 'http://localhost:8108',
  token: 'your-api-key'
})

// All operations are now fully typed with autocomplete
await api.documents.insert({
  id: 'prod-001',
  title: 'Laptop',           // ✅ Required, must be string
  price: 999.99,            // ✅ Required, must be number
  inStock: true,            // ✅ Required, must be boolean
  description: 'Gaming laptop', // ✅ Optional, can be omitted
  tags: ['gaming', 'laptop']   // ✅ Optional, must be string[]
})

// TypeScript will catch these errors at compile time:
// ❌ Missing required field
// await api.documents.insert({
//   id: 'prod-002',
//   price: 99.99,
//   inStock: true
//   // Error: Property 'title' is missing
// })

// ❌ Wrong type
// await api.documents.insert({
//   id: 'prod-003',
//   title: 'Product',
//   price: '99.99',  // Error: Type 'string' is not assignable to type 'number'
//   inStock: true
// })

One-Step API Creation

For simpler cases, you can define and create the API in one step:

const api = TypesenseApi.createFromSchema({
  name: 'products',
  fields: [
    { name: 'id', type: 'string' as const },
    { name: 'title', type: 'string' as const },
    { name: 'price', type: 'float' as const },
    { name: 'inStock', type: 'bool' as const }
  ] as const
} as const)({
  prefixUrl: 'http://localhost:8108',
  token: 'your-api-key'
})

Complex Field Types

The type inference supports all Typesense field types:

const EventCollection = TypesenseApi.defineCollection({
  name: 'events',
  fields: [
    { name: 'id', type: 'string' as const },
    { name: 'name', type: 'string' as const },
    { name: 'timestamp', type: 'int64' as const },
    { name: 'location', type: 'geopoint' as const },      // [lat, lon] tuple
    { name: 'attendees', type: 'int32[]' as const, optional: true },
    { name: 'metadata', type: 'object' as const, optional: true },
    { name: 'tags', type: 'auto' as const, optional: true }  // string | string[]
  ] as const
} as const)

const api = TypesenseApi.createSchemaTypedApi(EventCollection)({
  prefixUrl: 'http://localhost:8108',
  token: 'your-api-key'
})

// Properly typed document
await api.documents.insert({
  id: 'evt-001',
  name: 'Tech Conference',
  timestamp: Date.now(),
  location: [37.7749, -122.4194],  // Geopoint as [lat, lon]
  attendees: [100, 200, 300],      // Optional int32 array
  metadata: { venue: 'Moscone Center' }  // Optional object
})

Key Features

  • Compile-time type checking - No runtime overhead
  • Full autocomplete support - Your IDE knows all field names and types
  • Optional field handling - Correctly distinguishes between required and optional fields
  • All Typesense types supported - Including arrays, objects, geopoints, and auto fields
  • Zero runtime validation - Pure TypeScript type inference

Alternative Import Methods

The utility functions are also available as direct imports:

import { defineCollection, createSchemaTypedApi } from '@goatlab/typesense'

const collection = defineCollection({...})
const api = createSchemaTypedApi(collection)({...})

Type Mapping Reference

| Typesense Type | TypeScript Type | |----------------|----------------| | string | string | | string[] | string[] | | int32, int64 | number | | int32[], int64[] | number[] | | float | number | | float[] | number[] | | bool | boolean | | bool[] | boolean[] | | geopoint | [number, number] | | geopoint[] | [number, number][] | | object | Record<string, any> | | object[] | Record<string, any>[] | | auto | string \| string[] |

Note: The id field is excluded from the document type for insert() operations, as it's handled separately by the TypesenseApi with WithRequiredId<T> type.

Advanced Configuration

const typesense = new TypesenseApi({
  prefixUrl: 'https://typesense.example.com',
  token: 'your-api-key',
  
  // Multi-tenancy
  tenantId: 'customer-123',
  
  // Timeouts
  searchTimeout: 5000,
  importTimeout: 60000,
  defaultTimeout: 10000,
  
  // Resilience settings
  resilience: {
    maxFailures: 5,
    resetTimeout: 60000,
    halfOpenRequests: 3
  },
  
  // Other options
  autoCreateCollection: true,
  enableVersionCheck: true,
  suppressLogs: false
})

Components

The package includes several utility components that can be used independently:

  • TypesenseHttpClient - HTTP client with built-in authentication
  • ResiliencePolicy - Circuit breaker and rate limiting implementation
  • CollectionSchemaManager - Schema caching and management
  • TypesenseFilterBuilder - Fluent filter query builder
  • ExportFormatter - Document export formatting utilities