@mikkelscheike/email-provider-links 2.7.1 β†’ 2.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,11 @@
2
2
 
3
3
  πŸ”’ **Modern email provider detection library with enhanced TypeScript support and enterprise security**
4
4
 
5
- A robust TypeScript library providing direct links to **93 email providers** (178 domains) with **concurrent DNS resolution**, **optimized performance**, **comprehensive email validation**, and advanced security features for login and password reset flows.
5
+ A robust TypeScript library providing direct links to **93 email providers** (180 domains) with **concurrent DNS resolution**, **optimized performance**, **comprehensive email validation**, and advanced security features for login and password reset flows.
6
+
7
+ ## πŸš€ Try it out
8
+
9
+ **[Live Demo](https://demo.mikkelscheike.com)** - Test the library with any email address and see it in action!
6
10
 
7
11
  ## ✨ New in Version 2.7.0
8
12
 
@@ -13,12 +17,13 @@ A robust TypeScript library providing direct links to **93 email providers** (17
13
17
  - πŸ›‘οΈ **Improved Security**: Enhanced cryptographic integrity verification
14
18
  - ⚑ **Better Performance**: Optimized concurrent DNS with smart caching
15
19
  - 🎯 **Developer Experience**: Enhanced error messages and debugging information
20
+ - πŸ“Š **Development Mode**: Memory usage tracking when NODE_ENV=development
16
21
 
17
22
  ## ✨ Core Features
18
23
 
19
- - πŸš€ **Fast & Lightweight**: Zero dependencies, ultra-low memory (~0.39MB initial, ~0.02MB per 1000 ops)
24
+ - πŸš€ **Fast & Lightweight**: Zero dependencies, ultra-low memory (~0.08MB initial, ~0.03MB per 1000 ops)
20
25
  - πŸ“§ **93 Email Providers**: Gmail, Outlook, Yahoo, ProtonMail, iCloud, and many more
21
- - 🌐 **178 Domains Supported**: Comprehensive international coverage
26
+ - 🌐 **207 Domains Supported**: Comprehensive international coverage
22
27
  - 🌍 **Full IDN Support**: International domain names with RFC compliance and Punycode
23
28
  - βœ… **Advanced Email Validation**: International email validation with detailed error reporting
24
29
  - 🏒 **Business Domain Detection**: DNS-based detection for custom domains (Google Workspace, Microsoft 365, etc.)
@@ -31,7 +36,7 @@ A robust TypeScript library providing direct links to **93 email providers** (17
31
36
  - πŸ”„ **Email Alias Detection**: Normalize Gmail dots, plus addressing, and provider-specific aliases
32
37
  - πŸ›‘οΈ **Fraud Prevention**: Detect duplicate accounts through email alias manipulation
33
38
  - πŸ“¦ **Batch Processing**: Efficiently process multiple emails with deduplication
34
- - πŸ§ͺ **Thoroughly Tested**: 396 tests with comprehensive code coverage
39
+ - πŸ§ͺ **Thoroughly Tested**: 424 tests with 93.16% code coverage
35
40
 
36
41
  ## Installation
37
42
 
@@ -54,83 +59,9 @@ Fully compatible with the latest Node.js 24.x! The library is tested on:
54
59
  - Node.js 22.x (Current)
55
60
  - **Node.js 24.x (Latest)** - Full support with latest features
56
61
 
57
- ## Quick Start
58
-
59
- **One function handles everything** - consumer emails, business domains, and unknown providers:
60
-
61
- ```typescript
62
- import { getEmailProvider } from '@mikkelscheike/email-provider-links';
63
-
64
- // Works for ANY email address - the only function you need
65
- const result = await getEmailProvider('user@gmail.com');
66
- console.log(result.loginUrl); // "https://mail.google.com/mail/"
67
- console.log(result.provider?.companyProvider); // "Gmail"
68
-
69
- // Automatically detects business domains too
70
- const business = await getEmailProvider('user@mycompany.com');
71
- console.log(business.provider?.companyProvider); // "Google Workspace" (if detected)
72
-
73
- // Gracefully handles unknown providers
74
- const unknown = await getEmailProvider('user@unknown.com');
75
- console.log(unknown.loginUrl); // null
76
- ```
77
-
78
- ## Enhanced Email Validation
79
-
80
- **New in 2.7.0**: Comprehensive email validation with international support:
81
-
82
- ```typescript
83
- import { validateEmailAddress, validateInternationalEmail } from '@mikkelscheike/email-provider-links';
84
-
85
- // Enhanced validation with detailed error reporting
86
- const result = validateEmailAddress('user@example.com');
87
- if (result.isValid) {
88
- console.log('Valid email:', result.normalizedEmail);
89
- } else {
90
- console.log('Error:', result.error?.message);
91
- console.log('Error code:', result.error?.code);
92
- }
93
-
94
- // International domain validation
95
- const intlResult = validateInternationalEmail('user@mΓΌnchen.de');
96
- if (!intlResult) {
97
- console.log('Valid international email');
98
- } else {
99
- console.log('Validation error:', intlResult.message);
100
- }
101
- ```
102
-
103
- ## Batch Processing
104
-
105
- **New in 2.7.0**: Process multiple emails efficiently with deduplication:
106
-
107
- ```typescript
108
- import { batchProcessEmails } from '@mikkelscheike/email-provider-links';
109
-
110
- const emails = [
111
- 'user@gmail.com',
112
- 'u.s.e.r+work@gmail.com', // Alias of the first email
113
- 'test@yahoo.com',
114
- 'invalid-email'
115
- ];
116
-
117
- const results = batchProcessEmails(emails, {
118
- includeProviderInfo: true,
119
- normalizeEmails: true,
120
- deduplicateAliases: true
121
- });
122
-
123
- results.forEach(result => {
124
- console.log(`${result.email}: ${result.isValid ? 'Valid' : 'Invalid'}`);
125
- if (result.isDuplicate) {
126
- console.log(' πŸ”„ Duplicate detected');
127
- }
128
- });
129
- ```
130
-
131
62
  ## Supported Providers
132
63
 
133
- **πŸ“Š Current Coverage: 93 providers supporting 178 domains**
64
+ **πŸ“Š Current Coverage: 93 providers supporting 207 domains**
134
65
 
135
66
  **Consumer Email Providers:**
136
67
  - **Gmail** (2 domains): gmail.com, googlemail.com
@@ -161,51 +92,53 @@ results.forEach(result => {
161
92
 
162
93
  ## API Reference
163
94
 
164
- ### `getEmailProvider(email, timeout?)`
165
- **Recommended** - Detects any email provider including business domains.
95
+ ### Core Functions
96
+
97
+ #### `getEmailProvider(email, timeout?)`
98
+ **Recommended** - Complete provider detection with business domain support.
166
99
 
167
100
  ```typescript
168
- // πŸš€ SAME CALL, DIFFERENT SCENARIOS:
169
-
170
- // βœ… For known providers (Gmail, Yahoo, etc.) - INSTANT response
171
- const gmail1 = await getEmailProvider('user@gmail.com'); // No timeout needed
172
- const gmail2 = await getEmailProvider('user@gmail.com', 3000); // Same speed - timeout ignored
173
- // Both return instantly: { provider: "Gmail", loginUrl: "https://mail.google.com/mail/" }
174
-
175
- // πŸ” For business domains - DNS lookup required, timeout matters
176
- const biz1 = await getEmailProvider('user@mycompany.com'); // 5000ms timeout (default)
177
- const biz2 = await getEmailProvider('user@mycompany.com', 2000); // 2000ms timeout (faster fail)
178
- const biz3 = await getEmailProvider('user@mycompany.com', 10000); // 10000ms timeout (slower networks)
179
- // All may detect: { provider: "Google Workspace", detectionMethod: "mx_record" }
180
-
181
- // 🎯 WHY USE CUSTOM TIMEOUT?
182
- // - Faster apps: Use 2000ms to fail fast on unknown domains
183
- // - Slower networks: Use 10000ms to avoid premature timeouts
184
- // - Enterprise: Use 1000ms for strict SLA requirements
101
+ // Known providers (instant response)
102
+ const result1 = await getEmailProvider('user@gmail.com');
103
+ // Returns: { provider: "Gmail", loginUrl: "https://mail.google.com/mail/" }
104
+
105
+ // Business domains (DNS lookup with timeout)
106
+ const result2 = await getEmailProvider('user@company.com', 2000);
107
+ // Returns: { provider: "Google Workspace", detectionMethod: "mx_record" }
185
108
  ```
186
109
 
187
- ### `getEmailProviderSync(email)`
188
- **Synchronous** - Only checks predefined domains (no DNS lookup).
110
+ #### `getEmailProviderSync(email)`
111
+ **Fast** - Instant checks for known providers (no DNS lookup).
189
112
 
190
113
  ```typescript
191
- const result = getEmailProviderSync('user@gmail.com');
192
- // Returns: { provider, loginUrl, email }
114
+ const result = getEmailProviderSync('user@outlook.com');
115
+ // Returns: { provider: "Outlook", loginUrl: "https://outlook.live.com/" }
193
116
  ```
194
117
 
195
- ### `getEmailProviderFast(email, options?)`
196
- **High-performance** - Concurrent DNS with detailed timing information.
118
+ ### Email Alias Support
119
+
120
+ The library handles provider-specific email alias rules:
197
121
 
198
122
  ```typescript
199
- const result = await getEmailProviderFast('user@mycompany.com', {
200
- enableParallel: true,
201
- collectDebugInfo: true,
202
- timeout: 3000
203
- });
204
-
205
- console.log(result.timing); // { mx: 120, txt: 95, total: 125 }
206
- console.log(result.confidence); // 0.9
123
+ // Gmail ignores dots and plus addressing
124
+ emailsMatch('user.name+work@gmail.com', 'username@gmail.com') // true
125
+
126
+ // Outlook preserves dots but ignores plus addressing
127
+ emailsMatch('user.name+work@outlook.com', 'username@outlook.com') // false
128
+
129
+ // Normalize emails to canonical form
130
+ const canonical = normalizeEmail('u.s.e.r+tag@gmail.com');
131
+ console.log(canonical); // 'user@gmail.com'
207
132
  ```
208
133
 
134
+ **Provider Rules Overview**:
135
+ - **Gmail**: Ignores dots, supports plus addressing
136
+ - **Outlook**: Preserves dots, supports plus addressing
137
+ - **Yahoo**: Preserves dots, supports plus addressing
138
+ - **ProtonMail**: Preserves dots, supports plus addressing
139
+ - **FastMail**: Preserves dots, supports plus addressing
140
+ - **AOL**: Preserves everything except case
141
+
209
142
  ## Real-World Example
210
143
 
211
144
  ```typescript
@@ -301,93 +234,63 @@ console.log(domain); // 'example.com'
301
234
 
302
235
  </details>
303
236
 
304
- ## TypeScript Support
305
-
306
- Full TypeScript support with comprehensive interfaces:
307
-
308
- ```typescript
309
- interface EmailProviderResult {
310
- provider: EmailProvider | null;
311
- email: string;
312
- loginUrl: string | null;
313
- detectionMethod?: 'domain_match' | 'mx_record' | 'txt_record' | 'both' | 'proxy_detected';
314
- proxyService?: string;
315
- error?: {
316
- type: 'INVALID_EMAIL' | 'DNS_TIMEOUT' | 'RATE_LIMITED' | 'UNKNOWN_DOMAIN' |
317
- 'NETWORK_ERROR' | 'IDN_VALIDATION_ERROR';
318
- message: string;
319
- retryAfter?: number; // seconds until retry allowed (for rate limiting)
320
- idnError?: string; // specific IDN validation error message
321
- };
322
- }
323
-
324
- interface ConfigConstants {
325
- DEFAULT_DNS_TIMEOUT: number; // 5000ms
326
- MAX_DNS_REQUESTS_PER_MINUTE: number; // 10 requests
327
- SUPPORTED_PROVIDERS_COUNT: number; // 93 providers
328
- SUPPORTED_DOMAINS_COUNT: number; // 178 domains
329
- }
330
- ```
331
-
332
- ## πŸ›‘οΈ Security Features
333
-
334
- This package implements **enterprise-grade security** to protect against malicious redirects and supply chain attacks:
237
+ ## Performance and Detection System
335
238
 
336
- ### βœ… Multi-Layer Protection
239
+ For detailed performance metrics and information about the detection system, refer to [Performance and Detection System](docs/PERFORMANCE.md).
337
240
 
338
- - **HTTPS-Only Enforcement**: All provider URLs must use HTTPS protocol
339
- - **Domain Allowlisting**: Only pre-approved domains are allowed (93+ verified providers)
340
- - **Malicious Pattern Detection**: Blocks IP addresses, URL shorteners, suspicious TLDs
341
- - **Path Traversal Prevention**: Detects and blocks `../` and encoded variants
342
- - **JavaScript Injection Protection**: Prevents `javascript:`, `data:`, and script injections
343
- - **File Integrity Verification**: SHA-256 hash verification for provider database
241
+ ### Development Mode Features
344
242
 
345
- ### πŸ”’ Attack Prevention
243
+ When `NODE_ENV` is set to 'development', the library provides additional insights:
346
244
 
347
- Protects against common attack vectors:
348
- - ❌ **URL Injection**: Blocked by strict allowlisting
349
- - ❌ **Typosquatting**: Blocked by domain validation
350
- - ❌ **URL Shorteners**: Blocked by pattern detection
351
- - ❌ **Protocol Downgrade**: Blocked by HTTPS enforcement
352
- - ❌ **Path Traversal**: Blocked by path validation
353
- - ❌ **Script Injection**: Blocked by content validation
354
- - ❌ **Supply Chain Attacks**: Blocked by integrity verification
355
-
356
- ### πŸ§ͺ Security Testing
245
+ ```typescript
246
+ // Memory usage is automatically logged:
247
+ // πŸš€ Current memory usage: 0.08 MB
248
+ ```
357
249
 
358
- - **396 comprehensive tests** covering all functionality and edge cases
359
- - **92+ dedicated security tests** covering all attack vectors
360
- - **Automated security validation** in CI/CD pipeline
361
- - **Regular security audits** of provider database
250
+ ### Memory Management
362
251
 
363
- ## Performance Benchmarks
252
+ The library implements careful memory management:
253
+ - Initial load: ~0.08MB heap usage
254
+ - Batch operations: ~0.03MB per 1000 operations
255
+ - Maximum load: < 25MB even under heavy concurrent operations
256
+ - Automatic garbage collection hints
257
+ - Memory usage logging in development mode
364
258
 
365
- This package is designed to be extremely memory efficient and fast:
259
+ ### Performance Benchmarks
366
260
 
367
- - **Provider loading**: ~0.39MB heap usage, <0.5ms
368
- - **Email lookups**: ~0.02MB heap usage per 100 operations
369
- - **Concurrent DNS**: ~0.03MB heap usage, ~110ms for 10 lookups
370
- - **Large scale (1000 ops)**: ~0.02MB heap usage, <3ms total
371
- - **International validation**: <1ms for complex IDN domains
261
+ Extensively optimized for both speed and memory efficiency:
372
262
 
373
- To run benchmarks locally:
374
- ```bash
375
- npm run benchmark
376
- ```
263
+ **Speed Metrics**:
264
+ - Initial provider load: ~0.5ms
265
+ - Known provider lookup: <1ms
266
+ - DNS-based detection: ~27ms average
267
+ - Batch processing: 1000 operations in ~1.1ms
268
+ - Email validation: <1ms for complex IDN domains
377
269
 
378
- ## Examples
270
+ **Memory Usage**:
271
+ - Initial footprint: ~0.08MB
272
+ - Per operation: ~0.03MB per 1000 lookups
273
+ - Peak usage: <25MB under heavy load
274
+ - Cache efficiency: >99% hit rate
275
+ - Garbage collection: Automatic optimization
379
276
 
380
- Run the modern example to see all features in action:
277
+ **Real-World Performance**:
278
+ - 50,000+ operations/second for known providers
279
+ - 100 concurrent DNS lookups in <1 second
280
+ - Average latency: <1ms for cached lookups
281
+ - Maximum latency: <5ms per lookup
381
282
 
283
+ To run benchmarks:
382
284
  ```bash
383
- npx tsx examples/modern-example.ts
285
+ npm run benchmark # Basic benchmarks
286
+ node --expose-gc benchmark/memory.ts # Detailed memory analysis
384
287
  ```
385
288
 
386
289
  ## Contributing
387
290
 
388
291
  We welcome contributions! See [CONTRIBUTING.md](docs/CONTRIBUTING.md) for guidelines on adding new email providers.
389
292
 
390
- **Quality Assurance**: This project maintains high standards with 396 comprehensive tests achieving excellent code coverage.
293
+ **Quality Assurance**: This project maintains high standards with 424 comprehensive tests achieving 93.16% code coverage (96.46% function coverage).
391
294
  **Security Note**: All new providers undergo security validation and must pass our allowlist verification.
392
295
 
393
296
  ## Security
@@ -400,4 +303,4 @@ MIT License - see [LICENSE](LICENSE) file for details.
400
303
 
401
304
  ---
402
305
 
403
- **Zero dependencies β€’ TypeScript-first β€’ Production ready β€’ International support**
306
+ **Zero dependencies β€’ TypeScript-first β€’ Production ready β€’ International support**
@@ -9,184 +9,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.detectEmailAlias = detectEmailAlias;
10
10
  exports.normalizeEmail = normalizeEmail;
11
11
  exports.emailsMatch = emailsMatch;
12
- /**
13
- * Email alias rules for major providers
14
- */
15
- const ALIAS_RULES = [
16
- {
17
- domains: ['gmail.com', 'googlemail.com'],
18
- supportsPlusAddressing: true,
19
- ignoresDots: true,
20
- normalize: (email) => {
21
- const parts = email.toLowerCase().split('@');
22
- const username = parts[0];
23
- const domain = parts[1];
24
- if (!username || !domain) {
25
- return email.toLowerCase();
26
- }
27
- // Remove dots and everything after +
28
- const cleanUsername = username.replace(/\./g, '').split('+')[0];
29
- return `${cleanUsername}@${domain}`;
30
- }
31
- },
32
- {
33
- domains: ['outlook.com', 'hotmail.com', 'live.com', 'msn.com', 'hotmail.co.uk', 'hotmail.fr', 'hotmail.it', 'hotmail.es', 'hotmail.de', 'live.co.uk', 'live.fr', 'live.it', 'live.nl', 'live.com.au', 'live.ca', 'live.jp'],
34
- supportsPlusAddressing: true,
35
- ignoresDots: false,
36
- normalize: (email) => {
37
- const parts = email.toLowerCase().split('@');
38
- const username = parts[0];
39
- const domain = parts[1];
40
- if (!username || !domain) {
41
- return email.toLowerCase();
42
- }
43
- // Only remove plus addressing for Outlook
44
- const cleanUsername = username.split('+')[0];
45
- return `${cleanUsername}@${domain}`;
46
- }
47
- },
48
- {
49
- domains: ['yahoo.com', 'yahoo.co.uk', 'yahoo.fr', 'yahoo.co.in', 'yahoo.com.br', 'yahoo.co.jp', 'yahoo.it', 'yahoo.de', 'yahoo.in', 'yahoo.es', 'yahoo.ca', 'yahoo.com.au', 'yahoo.com.ar', 'yahoo.com.mx', 'yahoo.co.id', 'yahoo.com.sg', 'ymail.com', 'rocketmail.com'],
50
- supportsPlusAddressing: true,
51
- ignoresDots: false,
52
- normalize: (email) => {
53
- const parts = email.toLowerCase().split('@');
54
- const username = parts[0];
55
- const domain = parts[1];
56
- if (!username || !domain) {
57
- return email.toLowerCase();
58
- }
59
- const cleanUsername = username.split('+')[0];
60
- return `${cleanUsername}@${domain}`;
61
- }
62
- },
63
- {
64
- domains: ['fastmail.com', 'fastmail.fm'],
65
- supportsPlusAddressing: true,
66
- ignoresDots: false,
67
- normalize: (email) => {
68
- const parts = email.toLowerCase().split('@');
69
- const username = parts[0];
70
- const domain = parts[1];
71
- if (!username || !domain) {
72
- return email.toLowerCase();
73
- }
74
- const cleanUsername = username.split('+')[0];
75
- return `${cleanUsername}@${domain}`;
76
- }
77
- },
78
- {
79
- domains: ['proton.me', 'protonmail.com', 'protonmail.ch', 'pm.me'],
80
- supportsPlusAddressing: true,
81
- ignoresDots: false,
82
- normalize: (email) => {
83
- const parts = email.toLowerCase().split('@');
84
- const username = parts[0];
85
- const domain = parts[1];
86
- if (!username || !domain) {
87
- return email.toLowerCase();
88
- }
89
- const cleanUsername = username.split('+')[0];
90
- return `${cleanUsername}@${domain}`;
91
- }
92
- },
93
- {
94
- domains: ['tutanota.com', 'tutanota.de', 'tutamail.com', 'tuta.io', 'keemail.me', 'tuta.com'],
95
- supportsPlusAddressing: true,
96
- ignoresDots: false,
97
- normalize: (email) => {
98
- const parts = email.toLowerCase().split('@');
99
- const username = parts[0];
100
- const domain = parts[1];
101
- if (!username || !domain) {
102
- return email.toLowerCase();
103
- }
104
- const cleanUsername = username.split('+')[0];
105
- return `${cleanUsername}@${domain}`;
106
- }
107
- },
108
- {
109
- domains: ['zoho.com', 'zohomail.com', 'zoho.eu'],
110
- supportsPlusAddressing: true,
111
- ignoresDots: false,
112
- normalize: (email) => {
113
- const parts = email.toLowerCase().split('@');
114
- const username = parts[0];
115
- const domain = parts[1];
116
- if (!username || !domain) {
117
- return email.toLowerCase();
118
- }
119
- const cleanUsername = username.split('+')[0];
120
- return `${cleanUsername}@${domain}`;
121
- }
122
- },
123
- {
124
- domains: ['icloud.com', 'me.com', 'mac.com'],
125
- supportsPlusAddressing: true,
126
- ignoresDots: false,
127
- normalize: (email) => {
128
- const parts = email.toLowerCase().split('@');
129
- const username = parts[0];
130
- const domain = parts[1];
131
- if (!username || !domain) {
132
- return email.toLowerCase();
133
- }
134
- const cleanUsername = username.split('+')[0];
135
- return `${cleanUsername}@${domain}`;
136
- }
137
- },
138
- {
139
- domains: ['mail.com'],
140
- supportsPlusAddressing: true,
141
- ignoresDots: false,
142
- normalize: (email) => {
143
- const parts = email.toLowerCase().split('@');
144
- const username = parts[0];
145
- const domain = parts[1];
146
- if (!username || !domain) {
147
- return email.toLowerCase();
148
- }
149
- const cleanUsername = username.split('+')[0];
150
- return `${cleanUsername}@${domain}`;
151
- }
152
- },
153
- {
154
- domains: ['aol.com', 'love.com', 'ygm.com', 'games.com', 'wow.com', 'aim.com'],
155
- supportsPlusAddressing: false,
156
- ignoresDots: false,
157
- normalize: (email) => email.toLowerCase()
158
- },
159
- {
160
- domains: ['mail.ru'],
161
- supportsPlusAddressing: true,
162
- ignoresDots: false,
163
- normalize: (email) => {
164
- const parts = email.toLowerCase().split('@');
165
- const username = parts[0];
166
- const domain = parts[1];
167
- if (!username || !domain) {
168
- return email.toLowerCase();
169
- }
170
- const cleanUsername = username.split('+')[0];
171
- return `${cleanUsername}@${domain}`;
172
- }
173
- },
174
- {
175
- domains: ['yandex.com', 'yandex.ru'],
176
- supportsPlusAddressing: true,
177
- ignoresDots: false,
178
- normalize: (email) => {
179
- const parts = email.toLowerCase().split('@');
180
- const username = parts[0];
181
- const domain = parts[1];
182
- if (!username || !domain) {
183
- return email.toLowerCase();
184
- }
185
- const cleanUsername = username.split('+')[0];
186
- return `${cleanUsername}@${domain}`;
187
- }
188
- }
189
- ];
12
+ const loader_1 = require("./loader");
190
13
  /**
191
14
  * Validates email format
192
15
  */
@@ -194,12 +17,6 @@ function isValidEmail(email) {
194
17
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
195
18
  return emailRegex.test(email);
196
19
  }
197
- /**
198
- * Gets the alias rule for a given domain
199
- */
200
- function getAliasRule(domain) {
201
- return ALIAS_RULES.find(rule => rule.domains.includes(domain.toLowerCase())) || null;
202
- }
203
20
  /**
204
21
  * Detects and analyzes email aliases
205
22
  *
@@ -217,49 +34,61 @@ function detectEmailAlias(email) {
217
34
  if (!username || !domain) {
218
35
  throw new Error('Invalid email format - missing username or domain');
219
36
  }
220
- const rule = getAliasRule(domain);
37
+ const { domainMap } = (0, loader_1.loadProviders)();
38
+ const provider = domainMap.get(domain);
221
39
  const result = {
222
40
  canonical: originalEmail.toLowerCase(),
223
41
  original: originalEmail,
224
42
  isAlias: false,
225
43
  aliasType: 'none'
226
44
  };
227
- if (!rule) {
228
- // No specific rule, just normalize case
229
- result.canonical = originalEmail.toLowerCase();
45
+ if (!provider?.alias) {
230
46
  return result;
231
47
  }
232
48
  result.provider = domain;
233
- // Check for plus addressing
234
- if (rule.supportsPlusAddressing && username.includes('+')) {
235
- const plusIndex = username.indexOf('+');
236
- const baseUsername = username.substring(0, plusIndex);
237
- const aliasPart = username.substring(plusIndex + 1);
238
- result.isAlias = true;
239
- result.aliasType = 'plus';
240
- result.aliasPart = aliasPart;
241
- result.canonical = rule.normalize ? rule.normalize(originalEmail) : `${baseUsername}@${domain}`;
242
- return result;
49
+ let normalizedUsername = username;
50
+ let isAlias = false;
51
+ let aliasType = 'none';
52
+ let aliasPart;
53
+ // Handle case sensitivity (all modern providers are case-insensitive)
54
+ if (provider.alias?.case?.ignore) {
55
+ if (provider.alias.case?.strip) {
56
+ normalizedUsername = normalizedUsername.toLowerCase();
57
+ }
243
58
  }
244
- // Check for dot variations (Gmail)
245
- if (rule.ignoresDots && username.includes('.')) {
246
- const baseUsername = username.replace(/\./g, '');
247
- if (baseUsername !== username) {
248
- result.isAlias = true;
249
- result.aliasType = 'dot';
250
- result.aliasPart = username;
251
- result.canonical = rule.normalize ? rule.normalize(originalEmail) : `${baseUsername}@${domain}`;
252
- return result;
59
+ // Handle plus addressing (common for Gmail, Outlook, Yahoo, etc.)
60
+ if (provider.alias?.plus?.ignore) {
61
+ const plusIndex = username.indexOf('+');
62
+ if (plusIndex !== -1) {
63
+ aliasPart = username.substring(plusIndex + 1);
64
+ isAlias = true;
65
+ aliasType = 'plus';
66
+ if (provider.alias.plus?.strip) {
67
+ normalizedUsername = username.slice(0, plusIndex);
68
+ }
253
69
  }
254
70
  }
255
- // Apply provider-specific normalization
256
- if (rule.normalize) {
257
- const normalized = rule.normalize(originalEmail);
258
- if (normalized !== originalEmail.toLowerCase()) {
259
- result.isAlias = true;
260
- result.canonical = normalized;
71
+ // Handle dots (primarily for Gmail)
72
+ if (provider.alias?.dots?.ignore) {
73
+ const hasDots = username.includes('.');
74
+ if (hasDots) {
75
+ if (!isAlias) {
76
+ aliasPart = username;
77
+ isAlias = true;
78
+ aliasType = 'dot';
79
+ }
80
+ if (provider.alias.dots?.strip) {
81
+ normalizedUsername = normalizedUsername.replace(/\./g, '');
82
+ }
261
83
  }
262
84
  }
85
+ // Build the canonical form
86
+ result.canonical = `${normalizedUsername}@${domain}`;
87
+ result.isAlias = isAlias;
88
+ result.aliasType = aliasType;
89
+ if (aliasPart !== undefined) {
90
+ result.aliasPart = aliasPart;
91
+ }
263
92
  return result;
264
93
  }
265
94
  /**