@mikkelscheike/email-provider-links 1.7.0 โ†’ 1.8.0

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
@@ -1,14 +1,14 @@
1
1
  # Email Provider Links
2
2
 
3
- ๐Ÿ”’ **Enterprise-grade secure email provider detection with advanced alias normalization**
3
+ ๐Ÿ”’ **Modern email provider detection library with concurrent DNS resolution and enterprise security**
4
4
 
5
- A TypeScript package providing direct links to **93 email providers** (180+ domains) with **email alias detection**, comprehensive security features, and international coverage for login and password reset flows.
5
+ A TypeScript library providing direct links to **93 email providers** (178 domains) with **concurrent DNS resolution**, **optimized performance**, **email alias detection**, and comprehensive security features for login and password reset flows.
6
6
 
7
7
  ## โœจ Features
8
8
 
9
9
  - ๐Ÿš€ **Fast & Lightweight**: Zero dependencies, minimal footprint
10
10
  - ๐Ÿ“ง **93 Email Providers**: Gmail, Outlook, Yahoo, ProtonMail, iCloud, and many more
11
- - ๐ŸŒ **180+ Domains Supported**: Comprehensive international coverage
11
+ - ๐ŸŒ **178 Domains Supported**: Comprehensive international coverage
12
12
  - ๐Ÿข **Business Domain Detection**: DNS-based detection for custom domains (Google Workspace, Microsoft 365, etc.)
13
13
  - ๐Ÿ”’ **Enterprise Security**: Multi-layer protection against malicious URLs and supply chain attacks
14
14
  - ๐Ÿ›ก๏ธ **URL Validation**: HTTPS-only enforcement with domain allowlisting
@@ -18,7 +18,7 @@ A TypeScript package providing direct links to **93 email providers** (180+ doma
18
18
  - ๐Ÿšฆ **Rate Limiting**: Built-in DNS query rate limiting to prevent abuse
19
19
  - ๐Ÿ”„ **Email Alias Detection**: Normalize Gmail dots, plus addressing, and provider-specific aliases
20
20
  - ๐Ÿ›ก๏ธ **Fraud Prevention**: Detect duplicate accounts through email alias manipulation
21
- - ๐Ÿงช **Thoroughly Tested**: 188+ tests with comprehensive coverage
21
+ - ๐Ÿงช **Thoroughly Tested**: 371 tests with 91.75% code coverage
22
22
 
23
23
  ## Installation
24
24
 
@@ -28,21 +28,28 @@ npm install @mikkelscheike/email-provider-links
28
28
 
29
29
  ## Quick Start
30
30
 
31
+ **One function handles everything** - consumer emails, business domains, and unknown providers:
32
+
31
33
  ```typescript
32
- import { getEmailProviderLinkWithDNS } from '@mikkelscheike/email-provider-links';
34
+ import { getEmailProvider } from '@mikkelscheike/email-provider-links';
33
35
 
34
- // Works for any email address
35
- const result = await getEmailProviderLinkWithDNS('user@gmail.com');
36
- console.log(result.loginUrl); // "https://mail.google.com/mail/"
36
+ // Works for ANY email address - the only function you need
37
+ const result = await getEmailProvider('user@gmail.com');
38
+ console.log(result.loginUrl); // "https://mail.google.com/mail/"
39
+ console.log(result.provider?.companyProvider); // "Gmail"
37
40
 
38
- // Business domains too
39
- const business = await getEmailProviderLinkWithDNS('user@mycompany.com');
41
+ // Automatically detects business domains too
42
+ const business = await getEmailProvider('user@mycompany.com');
40
43
  console.log(business.provider?.companyProvider); // "Google Workspace" (if detected)
44
+
45
+ // Gracefully handles unknown providers
46
+ const unknown = await getEmailProvider('user@unknown.com');
47
+ console.log(unknown.loginUrl); // null
41
48
  ```
42
49
 
43
50
  ## Supported Providers
44
51
 
45
- **๐Ÿ“Š Current Coverage: 93 providers supporting 180+ domains**
52
+ **๐Ÿ“Š Current Coverage: 93 providers supporting 178 domains**
46
53
 
47
54
  **Consumer Email Providers:**
48
55
  - **Gmail** (2 domains): gmail.com, googlemail.com
@@ -73,19 +80,19 @@ console.log(business.provider?.companyProvider); // "Google Workspace" (if detec
73
80
 
74
81
  ## API
75
82
 
76
- ### `getEmailProviderLinkWithDNS(email, timeout?)`
83
+ ### `getEmailProvider(email, timeout?)`
77
84
  **Recommended** - Detects any email provider including business domains.
78
85
 
79
86
  ```typescript
80
- const result = await getEmailProviderLinkWithDNS('user@gmail.com', 3000);
87
+ const result = await getEmailProvider('user@gmail.com', 3000);
81
88
  // Returns: { provider, loginUrl, detectionMethod, email }
82
89
  ```
83
90
 
84
- ### `getEmailProviderLink(email)`
91
+ ### `getEmailProviderSync(email)`
85
92
  **Synchronous** - Only checks predefined domains (no DNS lookup).
86
93
 
87
94
  ```typescript
88
- const result = getEmailProviderLink('user@gmail.com');
95
+ const result = getEmailProviderSync('user@gmail.com');
89
96
  // Returns: { provider, loginUrl, email }
90
97
  ```
91
98
 
@@ -93,7 +100,7 @@ const result = getEmailProviderLink('user@gmail.com');
93
100
 
94
101
  ```typescript
95
102
  async function handlePasswordReset(email: string) {
96
- const result = await getEmailProviderLinkWithDNS(email);
103
+ const result = await getEmailProvider(email);
97
104
 
98
105
  return {
99
106
  providerUrl: result.loginUrl,
@@ -103,57 +110,85 @@ async function handlePasswordReset(email: string) {
103
110
  }
104
111
  ```
105
112
 
106
- ## ๐Ÿ”„ Email Alias Detection
107
113
 
108
- **NEW in v1.7.0** - Advanced email alias detection and normalization to prevent duplicate accounts and improve user experience.
114
+ ## Configuration
109
115
 
110
- ### Features
116
+ ```typescript
117
+ // Custom DNS timeout (default: 5000ms)
118
+ const result = await getEmailProvider(email, 2000);
111
119
 
112
- - **Gmail Dot Normalization**: `u.s.e.r@gmail.com` โ†’ `user@gmail.com`
113
- - **Plus Addressing**: `user+newsletter@provider.com` โ†’ `user@provider.com`
114
- - **Provider-Specific Rules**: Different providers have different aliasing capabilities
115
- - **Fraud Prevention**: Detect when users try to create multiple accounts with aliases
116
- - **Email Deduplication**: Normalize email lists to get accurate unique user counts
120
+ // Rate limiting configuration
121
+ import { Config } from '@mikkelscheike/email-provider-links';
122
+ console.log('Max requests:', Config.MAX_DNS_REQUESTS_PER_MINUTE); // 10
123
+ console.log('Default timeout:', Config.DEFAULT_DNS_TIMEOUT); // 5000ms
124
+ ```
117
125
 
118
- ### Quick Start
126
+ ## Advanced Usage
127
+
128
+ <details>
129
+ <summary><strong>๐Ÿ“š Secondary Functions & Specialized Use Cases</strong></summary>
130
+
131
+ ### Synchronous Provider Detection (No DNS)
132
+
133
+ If you can't use async or don't want DNS lookups:
119
134
 
120
135
  ```typescript
121
- import {
122
- detectEmailAlias,
123
- normalizeEmail,
124
- emailsMatch
125
- } from '@mikkelscheike/email-provider-links';
136
+ import { getEmailProviderSync } from '@mikkelscheike/email-provider-links';
126
137
 
127
- // Detect and analyze aliases
128
- const result = detectEmailAlias('u.s.e.r+work@gmail.com');
129
- console.log(result.canonical); // 'user@gmail.com'
130
- console.log(result.isAlias); // true
131
- console.log(result.aliasType); // 'plus'
132
- console.log(result.aliasPart); // 'work'
138
+ // Synchronous - only checks predefined domains
139
+ const result = getEmailProviderSync('user@gmail.com');
140
+ console.log(result.loginUrl); // Works for known domains only
141
+ ```
133
142
 
134
- // Normalize any email to canonical form
135
- const canonical = normalizeEmail('U.S.E.R+Newsletter@GMAIL.COM');
136
- console.log(canonical); // 'user@gmail.com'
143
+ ### Provider Support Checking
137
144
 
138
- // Check if two emails are the same person
139
- const match = emailsMatch('user@gmail.com', 'u.s.e.r+work@gmail.com');
140
- console.log(match); // true
145
+ ```typescript
146
+ import { isEmailProviderSupported, getSupportedProviders } from '@mikkelscheike/email-provider-links';
147
+
148
+ // Check if provider is supported
149
+ const supported = isEmailProviderSupported('user@gmail.com');
150
+
151
+ // Get all supported providers
152
+ const allProviders = getSupportedProviders();
153
+ console.log(`Supports ${allProviders.length} providers`);
141
154
  ```
142
155
 
143
- ### Provider Support
156
+ ### Advanced Provider Detection
157
+
158
+ ```typescript
159
+ import { getEmailProviderFast, detectProviderConcurrent } from '@mikkelscheike/email-provider-links';
144
160
 
145
- | Provider | Plus Addressing | Dots Ignored | Example |
146
- |----------|----------------|--------------|----------|
147
- | **Gmail** | โœ… Yes | โœ… Yes | `u.s.e.r+tag@gmail.com` โ†’ `user@gmail.com` |
148
- | **Outlook** | โœ… Yes | โŒ No | `user+tag@outlook.com` โ†’ `user@outlook.com` |
149
- | **Yahoo** | โœ… Yes | โŒ No | `user+tag@yahoo.com` โ†’ `user@yahoo.com` |
150
- | **ProtonMail** | โœ… Yes | โŒ No | `user+tag@proton.me` โ†’ `user@proton.me` |
151
- | **AOL** | โŒ No | โŒ No | No aliasing support |
161
+ // High-performance detection with concurrent DNS
162
+ const fastResult = await getEmailProviderFast('user@mycompany.com', {
163
+ enableParallel: true,
164
+ collectDebugInfo: true
165
+ });
166
+ console.log(fastResult.provider?.companyProvider); // "Google Workspace"
167
+ console.log(fastResult.timing); // Performance metrics
168
+ ```
152
169
 
153
- ### Advanced Usage
170
+ ### Configuration Options
154
171
 
155
172
  ```typescript
156
- // Prevent duplicate account creation
173
+ import { Config } from '@mikkelscheike/email-provider-links';
174
+
175
+ // Access configuration constants
176
+ console.log(Config.DEFAULT_DNS_TIMEOUT); // 5000ms
177
+ console.log(Config.MAX_DNS_REQUESTS_PER_MINUTE); // 10
178
+ console.log(Config.SUPPORTED_PROVIDERS_COUNT); // 93
179
+ ```
180
+
181
+ ### ๐Ÿ”„ Email Alias Detection & Normalization
182
+
183
+ **Specialized feature** for preventing duplicate accounts and fraud detection:
184
+
185
+ ```typescript
186
+ import {
187
+ normalizeEmail,
188
+ emailsMatch
189
+ } from '@mikkelscheike/email-provider-links';
190
+
191
+ // Prevent duplicate accounts
157
192
  async function registerUser(email: string) {
158
193
  const canonical = normalizeEmail(email);
159
194
  const existingUser = await findUserByEmail(canonical);
@@ -162,53 +197,24 @@ async function registerUser(email: string) {
162
197
  throw new Error('Email already registered');
163
198
  }
164
199
 
165
- // Store canonical email to prevent future duplicates
166
200
  await createUser({ email: canonical });
167
201
  }
168
202
 
169
- // Analyze email list for duplicates
170
- import { analyzeEmailAliases } from '@mikkelscheike/email-provider-links';
171
-
172
- const emailList = [
173
- 'user@gmail.com',
174
- 'u.s.e.r@gmail.com',
175
- 'user+newsletter@gmail.com',
176
- 'different@gmail.com'
177
- ];
178
-
179
- const analysis = analyzeEmailAliases(emailList);
180
- console.log(analysis.totalEmails); // 4
181
- console.log(analysis.uniqueCanonical); // 2 (actual unique users)
182
-
183
- // Generate test aliases
184
- import { generateAliases } from '@mikkelscheike/email-provider-links';
203
+ // Check if login email matches registration
204
+ const match = emailsMatch('user@gmail.com', 'u.s.e.r+work@gmail.com');
205
+ console.log(match); // true - same person
185
206
 
186
- const aliases = generateAliases('user@gmail.com', {
187
- plusAliases: ['work', 'personal'],
188
- includeDotVariations: true,
189
- maxDotVariations: 3
190
- });
191
- // Returns: ['user+work@gmail.com', 'user+personal@gmail.com', 'u.ser@gmail.com', ...]
207
+ // Simple normalization
208
+ const canonical = normalizeEmail('u.s.e.r+work@gmail.com');
209
+ console.log(canonical); // 'user@gmail.com'
192
210
  ```
193
211
 
194
- ## Configuration
195
-
196
- ```typescript
197
- // Custom DNS timeout (default: 5000ms)
198
- const result = await getEmailProviderLinkWithDNS(email, 2000);
199
-
200
- // Check if provider is supported
201
- import { isEmailProviderSupported } from '@mikkelscheike/email-provider-links';
202
- const supported = isEmailProviderSupported('user@gmail.com');
203
-
204
- // Rate limiting configuration
205
- import { RateLimit } from '@mikkelscheike/email-provider-links';
206
- console.log('Max requests:', RateLimit.MAX_REQUESTS); // 10
207
- console.log('Time window:', RateLimit.WINDOW_MS); // 60000ms
212
+ **Supported alias types:**
213
+ - **Gmail dots**: `u.s.e.r@gmail.com` โ†’ `user@gmail.com`
214
+ - **Plus addressing**: `user+tag@provider.com` โ†’ `user@provider.com`
215
+ - **Provider-specific rules**: Different providers have different capabilities
208
216
 
209
- // Custom rate limiter for specific use cases
210
- const customLimiter = new RateLimit.SimpleRateLimiter(20, 120000); // 20 requests per 2 minutes
211
- ```
217
+ </details>
212
218
 
213
219
  ## TypeScript Support
214
220
 
@@ -221,11 +227,11 @@ interface EmailProviderResult {
221
227
  proxyService?: string;
222
228
  }
223
229
 
224
- interface RateLimitConfig {
225
- MAX_REQUESTS: number; // 10 requests
226
- WINDOW_MS: number; // 60000ms (1 minute)
227
- SimpleRateLimiter: class; // Custom rate limiter class
228
- getCurrentLimiter(): SimpleRateLimiter; // Get current global limiter
230
+ interface ConfigConstants {
231
+ DEFAULT_DNS_TIMEOUT: number; // 5000ms
232
+ MAX_DNS_REQUESTS_PER_MINUTE: number; // 10 requests
233
+ SUPPORTED_PROVIDERS_COUNT: number; // 93 providers
234
+ SUPPORTED_DOMAINS_COUNT: number; // 178 domains
229
235
  }
230
236
  ```
231
237
 
@@ -236,7 +242,7 @@ This package implements **enterprise-grade security** to protect against malicio
236
242
  ### โœ… Multi-Layer Protection
237
243
 
238
244
  - **HTTPS-Only Enforcement**: All provider URLs must use HTTPS protocol
239
- - **Domain Allowlisting**: Only pre-approved domains are allowed (64+ verified providers)
245
+ - **Domain Allowlisting**: Only pre-approved domains are allowed (93+ verified providers)
240
246
  - **Malicious Pattern Detection**: Blocks IP addresses, URL shorteners, suspicious TLDs
241
247
  - **Path Traversal Prevention**: Detects and blocks `../` and encoded variants
242
248
  - **JavaScript Injection Protection**: Prevents `javascript:`, `data:`, and script injections
@@ -256,7 +262,7 @@ Protects against common attack vectors:
256
262
  ### ๐Ÿงช Security Testing
257
263
 
258
264
  - **29 dedicated security tests** covering all attack vectors
259
- - **94% security code coverage** with edge case testing
265
+ - **96% security module coverage** with edge case testing
260
266
  - **Automated security validation** in CI/CD pipeline
261
267
  - **Regular security audits** of provider database
262
268
 
@@ -279,6 +285,7 @@ if (result.securityReport.securityLevel === 'CRITICAL') {
279
285
 
280
286
  We welcome contributions! See [CONTRIBUTING.md](docs/CONTRIBUTING.md) for guidelines on adding new email providers.
281
287
 
288
+ **Quality Assurance**: This project maintains high standards with 371 comprehensive tests achieving 91.75% code coverage.
282
289
  **Security Note**: All new providers undergo security validation and must pass our allowlist verification.
283
290
 
284
291
  ## Security
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Email Alias Detection Module
3
3
  *
4
+ * Clean, focused implementation with only essential functions.
4
5
  * Detects and normalizes email aliases across different providers.
5
- * Supports plus addressing (+), dot variations, and provider-specific aliasing.
6
6
  */
7
7
  export interface AliasDetectionResult {
8
8
  /** The normalized/canonical email address */
@@ -12,64 +12,47 @@ export interface AliasDetectionResult {
12
12
  /** Whether an alias was detected */
13
13
  isAlias: boolean;
14
14
  /** Type of alias detected */
15
- aliasType: 'plus' | 'dot' | 'subdomain' | 'none';
15
+ aliasType: 'plus' | 'dot' | 'none';
16
16
  /** The alias part (if any) */
17
17
  aliasPart?: string;
18
18
  /** The provider that supports this alias type */
19
19
  provider?: string;
20
20
  }
21
- export interface AliasRule {
22
- /** Email domains this rule applies to */
23
- domains: string[];
24
- /** Whether this provider supports plus addressing (user+alias@domain.com) */
25
- supportsPlusAddressing: boolean;
26
- /** Whether this provider ignores dots in username (user.name@domain.com = username@domain.com) */
27
- ignoresDots: boolean;
28
- /** Whether this provider supports subdomain aliases (user@alias.domain.com) */
29
- supportsSubdomainAlias: boolean;
30
- /** Custom alias patterns specific to this provider */
31
- customPatterns?: RegExp[];
32
- /** Function to normalize email for this provider */
33
- normalize?: (email: string) => string;
34
- }
35
21
  /**
36
22
  * Detects and analyzes email aliases
23
+ *
24
+ * @param email - Email address to analyze
25
+ * @returns Detailed analysis of the email alias
37
26
  */
38
27
  export declare function detectEmailAlias(email: string): AliasDetectionResult;
39
28
  /**
40
- * Normalizes an email address to its canonical form
29
+ * Normalizes an email address to its canonical form.
30
+ *
31
+ * This is the primary function for preventing duplicate accounts.
32
+ *
33
+ * @param email - Email address to normalize
34
+ * @returns Canonical email address
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * const canonical = normalizeEmail('U.S.E.R+work@GMAIL.COM');
39
+ * console.log(canonical); // 'user@gmail.com'
40
+ * ```
41
41
  */
42
42
  export declare function normalizeEmail(email: string): string;
43
43
  /**
44
- * Checks if two email addresses are the same when normalized
44
+ * Checks if two email addresses are the same when normalized.
45
+ *
46
+ * This is the primary function for matching aliases during login.
47
+ *
48
+ * @param email1 - First email address
49
+ * @param email2 - Second email address
50
+ * @returns true if the emails represent the same person
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * const match = emailsMatch('user@gmail.com', 'u.s.e.r+work@gmail.com');
55
+ * console.log(match); // true
56
+ * ```
45
57
  */
46
58
  export declare function emailsMatch(email1: string, email2: string): boolean;
47
- /**
48
- * Gets alias capabilities for a domain
49
- */
50
- export declare function getAliasCapabilities(domain: string): AliasRule | null;
51
- /**
52
- * Generates potential aliases for an email address
53
- */
54
- export declare function generateAliases(email: string, options?: {
55
- plusAliases?: string[];
56
- includeDotVariations?: boolean;
57
- maxDotVariations?: number;
58
- }): string[];
59
- /**
60
- * Analyzes email aliasing patterns in a list of emails
61
- */
62
- export declare function analyzeEmailAliases(emails: string[]): {
63
- totalEmails: number;
64
- uniqueCanonical: number;
65
- aliasGroups: Array<{
66
- canonical: string;
67
- aliases: string[];
68
- count: number;
69
- }>;
70
- providerStats: Record<string, {
71
- total: number;
72
- aliases: number;
73
- types: Record<string, number>;
74
- }>;
75
- };
@@ -2,16 +2,13 @@
2
2
  /**
3
3
  * Email Alias Detection Module
4
4
  *
5
+ * Clean, focused implementation with only essential functions.
5
6
  * Detects and normalizes email aliases across different providers.
6
- * Supports plus addressing (+), dot variations, and provider-specific aliasing.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.detectEmailAlias = detectEmailAlias;
10
10
  exports.normalizeEmail = normalizeEmail;
11
11
  exports.emailsMatch = emailsMatch;
12
- exports.getAliasCapabilities = getAliasCapabilities;
13
- exports.generateAliases = generateAliases;
14
- exports.analyzeEmailAliases = analyzeEmailAliases;
15
12
  /**
16
13
  * Email alias rules for major providers
17
14
  */
@@ -20,7 +17,6 @@ const ALIAS_RULES = [
20
17
  domains: ['gmail.com', 'googlemail.com'],
21
18
  supportsPlusAddressing: true,
22
19
  ignoresDots: true,
23
- supportsSubdomainAlias: false,
24
20
  normalize: (email) => {
25
21
  const [username, domain] = email.toLowerCase().split('@');
26
22
  // Remove dots and everything after +
@@ -32,7 +28,6 @@ const ALIAS_RULES = [
32
28
  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'],
33
29
  supportsPlusAddressing: true,
34
30
  ignoresDots: false,
35
- supportsSubdomainAlias: false,
36
31
  normalize: (email) => {
37
32
  const [username, domain] = email.toLowerCase().split('@');
38
33
  // Only remove plus addressing for Outlook
@@ -44,7 +39,6 @@ const ALIAS_RULES = [
44
39
  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'],
45
40
  supportsPlusAddressing: true,
46
41
  ignoresDots: false,
47
- supportsSubdomainAlias: false,
48
42
  normalize: (email) => {
49
43
  const [username, domain] = email.toLowerCase().split('@');
50
44
  const cleanUsername = username.split('+')[0];
@@ -55,7 +49,6 @@ const ALIAS_RULES = [
55
49
  domains: ['fastmail.com', 'fastmail.fm'],
56
50
  supportsPlusAddressing: true,
57
51
  ignoresDots: false,
58
- supportsSubdomainAlias: true,
59
52
  normalize: (email) => {
60
53
  const [username, domain] = email.toLowerCase().split('@');
61
54
  const cleanUsername = username.split('+')[0];
@@ -66,7 +59,6 @@ const ALIAS_RULES = [
66
59
  domains: ['proton.me', 'protonmail.com', 'protonmail.ch', 'pm.me'],
67
60
  supportsPlusAddressing: true,
68
61
  ignoresDots: false,
69
- supportsSubdomainAlias: false,
70
62
  normalize: (email) => {
71
63
  const [username, domain] = email.toLowerCase().split('@');
72
64
  const cleanUsername = username.split('+')[0];
@@ -77,7 +69,6 @@ const ALIAS_RULES = [
77
69
  domains: ['tutanota.com', 'tutanota.de', 'tutamail.com', 'tuta.io', 'keemail.me', 'tuta.com'],
78
70
  supportsPlusAddressing: true,
79
71
  ignoresDots: false,
80
- supportsSubdomainAlias: false,
81
72
  normalize: (email) => {
82
73
  const [username, domain] = email.toLowerCase().split('@');
83
74
  const cleanUsername = username.split('+')[0];
@@ -88,7 +79,6 @@ const ALIAS_RULES = [
88
79
  domains: ['zoho.com', 'zohomail.com', 'zoho.eu'],
89
80
  supportsPlusAddressing: true,
90
81
  ignoresDots: false,
91
- supportsSubdomainAlias: false,
92
82
  normalize: (email) => {
93
83
  const [username, domain] = email.toLowerCase().split('@');
94
84
  const cleanUsername = username.split('+')[0];
@@ -99,7 +89,6 @@ const ALIAS_RULES = [
99
89
  domains: ['icloud.com', 'me.com', 'mac.com'],
100
90
  supportsPlusAddressing: true,
101
91
  ignoresDots: false,
102
- supportsSubdomainAlias: false,
103
92
  normalize: (email) => {
104
93
  const [username, domain] = email.toLowerCase().split('@');
105
94
  const cleanUsername = username.split('+')[0];
@@ -110,7 +99,6 @@ const ALIAS_RULES = [
110
99
  domains: ['mail.com'],
111
100
  supportsPlusAddressing: true,
112
101
  ignoresDots: false,
113
- supportsSubdomainAlias: false,
114
102
  normalize: (email) => {
115
103
  const [username, domain] = email.toLowerCase().split('@');
116
104
  const cleanUsername = username.split('+')[0];
@@ -121,14 +109,12 @@ const ALIAS_RULES = [
121
109
  domains: ['aol.com', 'love.com', 'ygm.com', 'games.com', 'wow.com', 'aim.com'],
122
110
  supportsPlusAddressing: false,
123
111
  ignoresDots: false,
124
- supportsSubdomainAlias: false,
125
112
  normalize: (email) => email.toLowerCase()
126
113
  },
127
114
  {
128
115
  domains: ['mail.ru'],
129
116
  supportsPlusAddressing: true,
130
117
  ignoresDots: false,
131
- supportsSubdomainAlias: false,
132
118
  normalize: (email) => {
133
119
  const [username, domain] = email.toLowerCase().split('@');
134
120
  const cleanUsername = username.split('+')[0];
@@ -139,7 +125,6 @@ const ALIAS_RULES = [
139
125
  domains: ['yandex.com', 'yandex.ru'],
140
126
  supportsPlusAddressing: true,
141
127
  ignoresDots: false,
142
- supportsSubdomainAlias: false,
143
128
  normalize: (email) => {
144
129
  const [username, domain] = email.toLowerCase().split('@');
145
130
  const cleanUsername = username.split('+')[0];
@@ -162,6 +147,9 @@ function getAliasRule(domain) {
162
147
  }
163
148
  /**
164
149
  * Detects and analyzes email aliases
150
+ *
151
+ * @param email - Email address to analyze
152
+ * @returns Detailed analysis of the email alias
165
153
  */
166
154
  function detectEmailAlias(email) {
167
155
  if (!isValidEmail(email)) {
@@ -215,14 +203,37 @@ function detectEmailAlias(email) {
215
203
  return result;
216
204
  }
217
205
  /**
218
- * Normalizes an email address to its canonical form
206
+ * Normalizes an email address to its canonical form.
207
+ *
208
+ * This is the primary function for preventing duplicate accounts.
209
+ *
210
+ * @param email - Email address to normalize
211
+ * @returns Canonical email address
212
+ *
213
+ * @example
214
+ * ```typescript
215
+ * const canonical = normalizeEmail('U.S.E.R+work@GMAIL.COM');
216
+ * console.log(canonical); // 'user@gmail.com'
217
+ * ```
219
218
  */
220
219
  function normalizeEmail(email) {
221
220
  const result = detectEmailAlias(email);
222
221
  return result.canonical;
223
222
  }
224
223
  /**
225
- * Checks if two email addresses are the same when normalized
224
+ * Checks if two email addresses are the same when normalized.
225
+ *
226
+ * This is the primary function for matching aliases during login.
227
+ *
228
+ * @param email1 - First email address
229
+ * @param email2 - Second email address
230
+ * @returns true if the emails represent the same person
231
+ *
232
+ * @example
233
+ * ```typescript
234
+ * const match = emailsMatch('user@gmail.com', 'u.s.e.r+work@gmail.com');
235
+ * console.log(match); // true
236
+ * ```
226
237
  */
227
238
  function emailsMatch(email1, email2) {
228
239
  try {
@@ -232,89 +243,3 @@ function emailsMatch(email1, email2) {
232
243
  return false;
233
244
  }
234
245
  }
235
- /**
236
- * Gets alias capabilities for a domain
237
- */
238
- function getAliasCapabilities(domain) {
239
- const rule = getAliasRule(domain.toLowerCase());
240
- return rule ? { ...rule } : null;
241
- }
242
- /**
243
- * Generates potential aliases for an email address
244
- */
245
- function generateAliases(email, options = {}) {
246
- if (!isValidEmail(email)) {
247
- throw new Error('Invalid email format');
248
- }
249
- const [username, domain] = email.toLowerCase().split('@');
250
- const rule = getAliasRule(domain);
251
- const aliases = [];
252
- if (!rule) {
253
- return [email.toLowerCase()];
254
- }
255
- // Generate plus aliases
256
- if (rule.supportsPlusAddressing && options.plusAliases) {
257
- for (const alias of options.plusAliases) {
258
- aliases.push(`${username}+${alias}@${domain}`);
259
- }
260
- }
261
- // Generate dot variations (Gmail only)
262
- if (rule.ignoresDots && options.includeDotVariations && username.length > 1) {
263
- const maxVariations = Math.min(options.maxDotVariations ?? 5, username.length - 1);
264
- const variations = new Set();
265
- // Simple dot variations (insert dots between characters)
266
- for (let i = 1; i < username.length && variations.size < maxVariations; i++) {
267
- const withDot = username.slice(0, i) + '.' + username.slice(i);
268
- variations.add(`${withDot}@${domain}`);
269
- }
270
- aliases.push(...Array.from(variations));
271
- }
272
- return aliases.length > 0 ? aliases : [email.toLowerCase()];
273
- }
274
- /**
275
- * Analyzes email aliasing patterns in a list of emails
276
- */
277
- function analyzeEmailAliases(emails) {
278
- const canonicalMap = new Map();
279
- const providerStats = {};
280
- for (const email of emails) {
281
- try {
282
- const result = detectEmailAlias(email);
283
- const canonical = result.canonical;
284
- if (!canonicalMap.has(canonical)) {
285
- canonicalMap.set(canonical, []);
286
- }
287
- canonicalMap.get(canonical).push(email);
288
- // Update provider stats
289
- if (result.provider) {
290
- if (!providerStats[result.provider]) {
291
- providerStats[result.provider] = {
292
- total: 0,
293
- aliases: 0,
294
- types: {}
295
- };
296
- }
297
- providerStats[result.provider].total++;
298
- if (result.isAlias) {
299
- providerStats[result.provider].aliases++;
300
- const type = result.aliasType;
301
- providerStats[result.provider].types[type] = (providerStats[result.provider].types[type] || 0) + 1;
302
- }
303
- }
304
- }
305
- catch {
306
- // Skip invalid emails
307
- }
308
- }
309
- const aliasGroups = Array.from(canonicalMap.entries()).map(([canonical, aliases]) => ({
310
- canonical,
311
- aliases,
312
- count: aliases.length
313
- })).sort((a, b) => b.count - a.count);
314
- return {
315
- totalEmails: emails.length,
316
- uniqueCanonical: canonicalMap.size,
317
- aliasGroups,
318
- providerStats
319
- };
320
- }