UNPKG

@goatlab/typesense

Version:

Modern TypeScript wrapper for Typesense search engine API

274 lines (273 loc) 10.9 kB
import type { TypesenseRateLimitInfo, WithRequiredId, TypesenseDocument, TypesenseCollectionOptions, TypesenseCollection } from './typesense.model'; import { defineCollection as defineCollectionUtil, type InferFromCollection } from './utils/schema-to-types'; import { createSchemaTypedApi as createSchemaTypedApiUtil } from './utils/schema-typed-api'; import { TypesenseHttpClient, type HttpClientOptions } from './components/http-client'; import { ResiliencePolicy, type ResiliencePolicyOptions } from './components/resilience-policy'; import { CollectionSchemaManager } from './components/schema-manager'; export interface TypesenseApiOptions extends Omit<HttpClientOptions, 'prefixUrl' | 'token'> { prefixUrl: string; token: string; tenantId?: string; collectionName?: string; suppressLogs?: boolean; appName?: string; appVersion?: string; autoCreateCollection?: boolean; enableVersionCheck?: boolean; schemaCacheSize?: number; schemaCacheTtl?: number; resilience?: ResiliencePolicyOptions; typesenseVersion?: string; onCircuitBreakerStateChange?: (state: 'open' | 'closed' | 'half-open', metadata?: any) => void; onRateLimitUpdate?: (info: TypesenseRateLimitInfo) => void; } /** * Modern, modular Typesense API client with grouped functionality * * @example * ```typescript * const api = new TypesenseApi({ * prefixUrl: 'http://localhost:8108', * token: 'xyz', * collectionName: 'products' * }) * * // Collections * await api.collections.create({ name: 'products', fields: [...] }) * await api.collections.getOrCreate({ name: 'products', fields: [...] }) * * // Documents * await api.documents.insert({ id: '1', title: 'Product 1' }) * await api.documents.search({ q: 'product', query_by: 'title' }) * * // Admin * await api.admin.health() * await api.admin.getMetrics() * ``` */ /** * Factory helper for creating typed TypesenseApi instances * @example * ```typescript * interface Product { id: string; title: string; price: number; } * const productApi = createTypedApi<Product>()({ * prefixUrl: 'http://localhost:8108', * token: 'xyz', * collectionName: 'products' * }) * * // Now all document operations are typed * await productApi.documents.insert({ id: "1", title: "Foo", price: 42 }) // ✅ typed * ``` */ export declare const createTypedApi: <TDoc extends Record<string, any>>() => (options: TypesenseApiOptions) => TypesenseApi<TDoc>; /** * Type-safe multitenant API wrapper */ export type TenantApi<TDoc, TenantId extends string> = TypesenseApi<TDoc> & { readonly tenantId: TenantId; }; export declare class TypesenseApi<TDoc extends Record<string, any> = Record<string, any>> { private readonly ctx; private withCtx; private readonly options; readonly httpClient: TypesenseHttpClient; readonly resilience: ResiliencePolicy; readonly schemaManager: CollectionSchemaManager; /** * Define a strongly-typed collection schema * @example * ```typescript * const ProductCollection = TypesenseApi.defineCollection({ * 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) * ``` */ static defineCollection: typeof defineCollectionUtil; /** * Create a strongly-typed API instance from a collection schema * @example * ```typescript * const ProductCollection = TypesenseApi.defineCollection({...}) * * const api = TypesenseApi.createSchemaTypedApi(ProductCollection)({ * prefixUrl: 'http://localhost:8108', * token: 'xyz' * }) * * // Now all document operations are fully typed * await api.documents.insert({ * id: '1', * title: 'Product', * price: 99.99, * inStock: true * }) * ``` */ static createSchemaTypedApi: typeof createSchemaTypedApiUtil; /** * Create a typed API from an inline collection definition (convenience method) * @example * ```typescript * 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 } * ] as const * } as const)({ * prefixUrl: 'http://localhost:8108', * token: 'xyz' * }) * ``` */ static createFromSchema<const C extends TypesenseCollection>(collection: C): (options: Omit<TypesenseApiOptions, "collectionName">) => TypesenseApi<InferFromCollection<C>>; constructor(options: TypesenseApiOptions); private checkVersion; /** * Collection management operations */ get collections(): { create: (collection: TypesenseCollection) => any; get: (collectionName?: string) => any; update: (collection: Partial<TypesenseCollection>, options?: TypesenseCollectionOptions) => any; delete: (collectionName?: string) => any; list: () => any; getOrCreate: (collection: TypesenseCollection) => any; }; /** * Document CRUD operations */ get documents(): { insert: (document: WithRequiredId<TDoc>, options?: TypesenseCollectionOptions) => Promise<TypesenseDocument<TDoc>>; upsert: (document: WithRequiredId<TDoc>, options?: TypesenseCollectionOptions) => Promise<TypesenseDocument<TDoc>>; update: (document: Partial<TypesenseDocument<TDoc>> & { id: string | number; }, options?: TypesenseCollectionOptions) => Promise<TypesenseDocument<TDoc>>; delete: (id: string | number, options?: TypesenseCollectionOptions) => any; getById: (id: string | number, options?: TypesenseCollectionOptions) => any; import: (documents: string | import("stream").Readable | TypesenseDocument<Record<string, any>>[], format?: import("./typesense.model").TypesenseImportFormat, importOptions?: import("./typesense.model").TypesenseImportOptions, collectionOptions?: TypesenseCollectionOptions) => any; export: (format?: import("./typesense.model").TypesenseExportFormat, options?: import("./typesense.model").TypesenseExportOptions & TypesenseCollectionOptions) => any; exportStream: (options?: import("./typesense.model").TypesenseExportOptions & TypesenseCollectionOptions) => any; deleteByFilter: (filter: string, options?: import("./typesense.model").TypesenseDeleteByFilterOptions & TypesenseCollectionOptions) => any; clear: (options?: TypesenseCollectionOptions) => any; search: (query: import("./typesense.model").TypesenseQuery, options?: TypesenseCollectionOptions) => any; searchText: (query: import("./typesense.model").TypesenseTextQuery, options?: TypesenseCollectionOptions) => any; searchVector: (query: import("./typesense.model").TypesenseVectorQuery, options?: TypesenseCollectionOptions) => any; }; /** * Search operations (alias for documents.search*) */ get search(): { query: (query: import("./typesense.model").TypesenseQuery, options?: TypesenseCollectionOptions) => any; text: (query: import("./typesense.model").TypesenseTextQuery, options?: TypesenseCollectionOptions) => any; vector: (query: import("./typesense.model").TypesenseVectorQuery, options?: TypesenseCollectionOptions) => any; multi: (request: import("./typesense.model").TypesenseMultiSearchRequest) => any; }; /** * Admin operations */ get admin(): { health: () => any; waitForHealth: (maxRetries?: number, delayMs?: number) => any; getMetrics: () => any; getStats: () => any; getCollectionStats: (collectionName?: string) => any; }; /** * Alias management (v29+) */ get aliases(): { createOrUpdate: (aliasName: string, collectionName: string) => any; get: (aliasName: string) => any; list: () => any; delete: (aliasName: string) => any; }; /** * Synonym management (v29+) */ get synonyms(): { upsert: (synonym: import("./typesense.model").TypesenseSynonym, options?: TypesenseCollectionOptions) => any; get: (synonymId: string, options?: TypesenseCollectionOptions) => any; list: (options?: TypesenseCollectionOptions) => any; delete: (synonymId: string, options?: TypesenseCollectionOptions) => any; }; /** * Search override management (v29+) */ get overrides(): { upsert: (override: import("./typesense.model").TypesenseOverride, options?: TypesenseCollectionOptions) => any; get: (overrideId: string, options?: TypesenseCollectionOptions) => any; list: (options?: TypesenseCollectionOptions) => any; delete: (overrideId: string, options?: TypesenseCollectionOptions) => any; }; /** * Preset management (v29+) */ get presets(): { upsert: (preset: import("./typesense.model").TypesensePreset) => any; get: (presetName: string) => any; list: () => any; delete: (presetName: string) => any; }; /** * Get current resilience status */ getResilienceStatus(): { failures: number; circuitOpen: boolean; circuitOpenUntil: number; rateLimited: boolean; retryAfterUntil: number; rateLimit: TypesenseRateLimitInfo | null; }; /** * Get current rate limit info */ getRateLimit(): TypesenseRateLimitInfo; /** * Get cache statistics */ getCacheStats(): { size: number; maxSize: number; }; /** * Get client version */ getVersion(): string; /** * Get Typesense server version */ getTypesenseVersion(): string; /** * Admin helper: List all collections for the current tenant * Returns only collections that belong to the configured tenant */ listTenantCollections(): Promise<string[]>; /** * Admin helper: Get base collection names for the current tenant * Returns collection names without the tenant prefix */ listTenantBaseCollectionNames(): Promise<string[]>; /** * Admin helper: Delete all collections for the current tenant * Use with caution - this will permanently delete all tenant data */ deleteAllTenantCollections(): Promise<void>; /** * Admin helper: Check if a collection exists for the current tenant */ tenantCollectionExists(baseCollectionName?: string): Promise<boolean>; /** * Destroy the client and clean up resources */ destroy(): void; }