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
Markdown
# 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