@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/typesenseBasic 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 collectioncollections.get()- Retrieve collection detailscollections.update()- Update collection schemacollections.delete()- Delete a collectioncollections.list()- List all collectionscollections.getOrCreate()- Get existing or create new collection
Documents
documents.insert()- Insert a single documentdocuments.upsert()- Insert or update a documentdocuments.update()- Update an existing documentdocuments.delete()- Delete a document by IDdocuments.getById()- Retrieve a document by IDdocuments.import()- Bulk import documentsdocuments.export()- Export documents (with optional filtering)documents.exportStream()- Export documents as a streamdocuments.deleteByFilter()- Delete documents matching a filterdocuments.clear()- Clear all documents in a collection
Search
search.query()- Perform a search querysearch.text()- Text-based searchsearch.vector()- Vector similarity searchsearch.multi()- Execute multiple searches in one request
Admin
admin.health()- Check server healthadmin.waitForHealth()- Wait for server to be healthyadmin.getMetrics()- Get server metricsadmin.getStats()- Get server statisticsadmin.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-safeTenant 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 authenticationResiliencePolicy- Circuit breaker and rate limiting implementationCollectionSchemaManager- Schema caching and managementTypesenseFilterBuilder- Fluent filter query builderExportFormatter- Document export formatting utilities
