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.

123 lines (107 loc) 3.46 kB
/** * In-memory storage adapter for waitlist-mailer. * Perfect for development, testing, and small-scale applications. * Data is lost when the process terminates. */ import { StorageProvider, WaitlistEntry, SearchOptions } from '../../types'; /** * Memory-based storage provider implementation. * No external dependencies required. Ideal for development and testing. * @template T - Optional metadata type */ export class MemoryStorage<T = any> implements StorageProvider<T> { private storage: Map<string, WaitlistEntry<T>> = new Map(); /** * Add an email to memory storage. * @param email - The email to add * @param data - Optional metadata * @throws {Error} If the email already exists */ async add(email: string, data?: T): Promise<void> { const normalized = email.toLowerCase(); if (this.storage.has(normalized)) { throw new Error(`Email already exists: ${email}`); } this.storage.set(normalized, { email, metadata: data, createdAt: new Date(), }); } /** * Remove an email from memory storage. * @param email - The email to remove * @returns true if the email was found and removed */ async remove(email: string): Promise<boolean> { return this.storage.delete(email.toLowerCase()); } /** * Check if an email exists in storage. * @param email - The email to check * @returns true if the email exists */ async exists(email: string): Promise<boolean> { return this.storage.has(email.toLowerCase()); } /** * Retrieve all entries from storage. * @returns Array of all WaitlistEntry objects */ async getAll(): Promise<WaitlistEntry<T>[]> { return Array.from(this.storage.values()); } /** * Count total entries in storage. * @returns Number of entries */ async count(): Promise<number> { return this.storage.size; } /** * Clear all entries from storage. */ async clear(): Promise<void> { this.storage.clear(); } /** * Search entries by email pattern. * For MemoryStorage, this filters the in-memory Map. * @param pattern - The pattern to search for * @param options - Optional search options * @returns Matching entries */ async search(pattern: string, options: SearchOptions = {}): Promise<WaitlistEntry<T>[]> { const { limit, offset = 0, caseInsensitive = true } = options; const searchPattern = caseInsensitive ? pattern.toLowerCase() : pattern; let results: WaitlistEntry<T>[] = []; for (const entry of this.storage.values()) { const emailToMatch = caseInsensitive ? entry.email.toLowerCase() : entry.email; if (emailToMatch.includes(searchPattern)) { results.push(entry); } } // Apply pagination if (offset > 0) { results = results.slice(offset); } if (limit !== undefined && limit > 0) { results = results.slice(0, limit); } return results; } /** * Iterate over entries in batches. * For MemoryStorage, yields entries from the in-memory Map. * @param batchSize - Number of entries per batch (default: 100) */ async *iterate(batchSize: number = 100): AsyncIterableIterator<WaitlistEntry<T>> { const entries = Array.from(this.storage.values()); for (let i = 0; i < entries.length; i += batchSize) { const batch = entries.slice(i, i + batchSize); for (const entry of batch) { yield entry; } } } }