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.

237 lines (173 loc) β€’ 6.74 kB
# Migrating to WaitlistMailer v2.0.0 ## πŸ“‹ Executive Summary WaitlistMailer has been transformed from a monolithic, tightly coupled library into a **professional, modular, and decoupled architecture**. Version 2.0.0 follows SOLID principles and is production-ready. ## 🎯 Problems Solved ### Before (v1.x) ❌ 1. **Monolithic**: One `WaitlistMailer` class handled DB, validation, and email logic. 2. **Rigid**: Fixed database schema (only `email` and `createdAt`). 3. **Coupled**: Forced dependencies on all DB drivers (mongoose, sequelize, pg, mysql2). 4. **Complex Config**: Constructor accepted too many mixed parameters. 5. **Inflexible**: Did not allow for custom adapters. 6. **Hard to Test**: Tightly coupled to external dependencies. ### After (v2.0) βœ… 1. **Modular**: Each component has a clear responsibility. 2. **Flexible**: Support for any data schema via generics. 3. **Zero-dependency**: Core functions work without external dependencies. 4. **Dependency Injection**: All components are injected. 5. **Extensible**: Easy to create custom adapters. 6. **Testable**: 30+ tests with 50%+ coverage. ## πŸ—οΈ New Architecture ### Adapter Pattern + Dependency Injection ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ User Code (Your App) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ WaitlistManager β”‚ ← Clean Orchestrator β”‚ (Core Business) β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β–Ό β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Storage β”‚ β”‚ Mail β”‚ β”‚ Provider β”‚ β”‚ Provider β”‚ β”‚ (Interface) β”‚ β”‚(Interface) β”‚ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”Œβ”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β–Ό β–Ό β–Ό β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚Memory β”‚ β”‚Mongoose β”‚ β”‚Nodemailer β”‚ β”‚ Console β”‚ β”‚Storage β”‚ β”‚ Storage β”‚ β”‚ Provider β”‚ β”‚ Provider β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ## πŸ“¦ Dependency Changes ### package.json v1.1.0 ``` { "dependencies": { "@types/handlebars": "^4.1.0", "handlebars": "^4.7.8", "joi": "^17.13.3", "mongoose": "^8.11.0", "mysql2": "^3.12.0", "nodemailer": "^6.10.0", "pg": "^8.13.3", "sequelize": "^6.37.5" } } ``` **Issue**: 8 required dependencies, even if you only use one. ### package.json v2.0.0 ``` { "dependencies": { "nodemailer": "^6.10.0", "validator": "^13.11.0" }, "peerDependencies": { "mongoose": "^8.0.0", "sequelize": "^6.0.0", "mysql2": "^3.0.0", "pg": "^8.0.0" }, "peerDependenciesMeta": { "mongoose": { "optional": true }, "sequelize": { "optional": true }, "mysql2": { "optional": true }, "pg": { "optional": true } } } ``` **Solution**: Only 2 required dependencies, the rest are optional peer dependencies. ## πŸš€ API Comparison ### v1.x ``` // Complex and coupled const mailer = new WaitlistMailer(StorageType.Db, { host: 'smtp.gmail.com', port: 587, user: 'email@gmail.com', pass: 'password' }, { mongoUri: 'mongodb://localhost:27017/waitlist', companyName: 'My App' }); await mailer.waitForInitialization(); await mailer.addEmail('user@example.com'); ``` ### v2.0 ``` // Clean and composable const manager = new WaitlistManager({ // storage is optional (defaults to MemoryStorage) // mailer is optional companyName: 'My App' }); // Or with explicit providers const manager = new WaitlistManager({ storage: new MongooseStorage({ model: MyModel }), mailer: new NodemailerProvider({ /* smtp config */ }), companyName: 'My App' }); await manager.waitForInitialization(); const result = await manager.join('user@example.com'); ``` ## πŸ”„ Migration Path ### From v1.x to v2.0 **Step 1**: Install v2.0 ``` npm install waitlist-mailer@2.0 ``` **Step 2**: Update Code ``` // Before const mailer = new WaitlistMailer(StorageType.Db, config, options); // After const manager = new WaitlistManager({ storage: new SequelizeStorage({ model }), mailer: new NodemailerProvider(config), companyName: options.companyName }); ``` **Step 3**: Use New API ``` // Before await mailer.addEmail('user@example.com'); // After const result = await manager.join('user@example.com'); ``` ## ✨ New Features in v2.1.0 ### πŸš€ Performance & Scalability Improvements 1. **Database-Level Search**: The `search()` method now delegates filtering to the storage layer: - **MongoDB**: Uses native `$regex` for efficient server-side filtering - **SQL (PostgreSQL/MySQL/SQLite)**: Uses `LIKE`/`ILIKE` queries - **Memory**: Optimized in-memory filtering 2. **Streaming Iterator**: New `iterate()` method for processing large datasets without OOM: - **MongoDB**: Uses native Mongoose cursors - **SQL**: Uses limit/offset pagination - Enables processing millions of entries with constant memory 3. **Pagination Support**: `SearchOptions` now supports `limit` and `offset` for paginated queries. 4. **Safe Metadata Parsing**: SQL storage now validates JSON metadata to prevent injection attacks. ### API Additions ```typescript // Search with pagination const results = await manager.search('gmail.com', { limit: 10, offset: 0 }); // Stream large datasets for await (const entry of storage.iterate(100)) { await processEntry(entry); } ``` ## ✨ New Features in v2.0+ 1. **Default Memory Storage**: You no longer need to manually instantiate `MemoryStorage` for testing or simple use cases. 2. **Generics**: Typed custom metadata support. 3. **Event System**: Rich namespaced events. 4. **Custom Adapters**: Easily create new implementations. 5. **Zero-Dependency Core**: Works without installing extra packages. **Date**: November 20, 2025 **Version**: 2.0.0