UNPKG

waitlist-mailer

Version:

Modern, modular TypeScript library for managing waitlists with pluggable storage and mail providers. Supports MongoDB, SQL databases, and custom adapters with zero required dependencies for basic usage.

187 lines (183 loc) 6.43 kB
import { EventEmitter } from 'events'; import { WaitlistManagerConfig, JoinResult, WaitlistEntry, EmailContext, SearchOptions } from '../types.mjs'; /** * @fileoverview WaitlistManager - The core orchestrator for the waitlist-mailer library. * * This class implements clean architecture principles: * - Dependency Injection: Storage and mail providers are injected * - Single Responsibility: Only orchestrates business logic * - Open/Closed: Extensible through adapters without modification * - Interface Segregation: Depends on interfaces, not concrete implementations */ /** * Main WaitlistManager class. * Orchestrates storage and mail providers to manage a waitlist. * * @template T - Metadata type for custom fields * * @example * ```typescript * // Default memory storage * const manager = new WaitlistManager({ companyName: 'My App' }); * * // Custom storage and mailer * const manager = new WaitlistManager({ * storage: new MongooseStorage(...), * mailer: new NodemailerProvider(...) * }); * ``` */ declare class WaitlistManager<T = any> extends EventEmitter { private storage; private mailer?; private companyName; private initialized; /** * Create a new WaitlistManager instance. * @param config - Configuration object with storage, optional mailer, etc. */ constructor(config: WaitlistManagerConfig<T>); /** * Initialize connections to storage and mail providers. * @returns Promise that resolves when initialization is complete */ connect(): Promise<void>; /** * Wait for the manager to be fully initialized. * @returns Promise that resolves when initialized */ waitForInitialization(): Promise<void>; /** * Check if the manager is initialized. * @returns true if initialized */ isInitialized(): boolean; /** * Add an email to the waitlist. * * Validates the email and checks for duplicates before adding. * Optionally sends a confirmation email. * * @param email - The email address to add * @param metadata - Optional custom metadata * @returns Result object with success status and message * * @example * ```typescript * const result = await manager.join('user@example.com', { * name: 'Alice', * referralSource: 'ProductHunt' * }); * * if (result.success) { * console.log('User added:', result.email); * } * ``` */ join(email: string, metadata?: T): Promise<JoinResult>; /** * Remove an email from the waitlist. * @param email - The email address to remove * @returns true if the email was found and removed */ leave(email: string): Promise<boolean>; /** * Check if an email is in the waitlist. * @param email - The email to check * @returns true if the email exists */ has(email: string): Promise<boolean>; /** * Get all waitlist entries. * @returns Array of WaitlistEntry objects */ getAll(): Promise<WaitlistEntry<T>[]>; /** * Get count of waitlist entries. * @returns Number of entries */ count(): Promise<number>; /** * Clear all entries from the waitlist. * @returns true if successful */ clear(): Promise<boolean>; /** * Send a custom email to an address. * Useful for sending emails to users who aren't on the waitlist. * * @param email - Recipient email * @param context - Email context with template variables * @returns true if sent successfully */ sendEmail(email: string, context: EmailContext): Promise<boolean>; /** * Send emails to all waitlist members. * Processes emails concurrently with configurable concurrency limit. * Uses streaming when available to avoid loading all entries into memory. * * @param contextBuilder - Function to build context for each email * @param concurrency - Maximum concurrent emails to send (1 = sequential, Infinity = all at once) * Default: 5 for balance between speed and resource usage * @returns Object with statistics * * @example * ```typescript * // Send with default concurrency (5 at a time) * const result = await manager.sendBulkEmails((email) => ({ * subject: 'Welcome!' * })); * * // Send slowly (1 at a time) * const result = await manager.sendBulkEmails( * (email) => ({ subject: 'Welcome!' }), * 1 * ); * * // Send fast (all at once - use with caution) * const result = await manager.sendBulkEmails( * (email) => ({ subject: 'Welcome!' }), * Infinity * ); * ``` */ sendBulkEmails(contextBuilder: (email: string, metadata?: T) => EmailContext, concurrency?: number): Promise<{ sent: number; failed: number; total: number; }>; /** * Send bulk emails using streaming to avoid memory issues. * Processes entries in batches using the storage iterator. * @private */ private sendBulkEmailsWithStreaming; /** * Legacy bulk email method that loads all entries into memory. * Used as fallback when storage doesn't support streaming. * @private */ private sendBulkEmailsLegacy; /** * Internal method to send a single bulk email. * @private */ private sendSingleBulkEmail; /** * Get entries matching a search pattern. * Delegates to storage provider for efficient database-level filtering when available. * Falls back to in-memory filtering if storage doesn't support search. * * @param pattern - Pattern to search for (partial email match) * @param options - Optional search options (limit, offset, caseInsensitive) * @returns Matching entries * * @example * ```typescript * // Simple search * const gmailUsers = await manager.search('gmail.com'); * * // Paginated search * const page1 = await manager.search('example', { limit: 10, offset: 0 }); * const page2 = await manager.search('example', { limit: 10, offset: 10 }); * ``` */ search(pattern: string, options?: SearchOptions): Promise<WaitlistEntry<T>[]>; /** * Disconnect from storage and mail providers. * Should be called before shutting down the application. */ disconnect(): Promise<void>; } export { WaitlistManager };