@mikkelscheike/email-provider-links 2.7.0 โ†’ 2.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,16 +1,31 @@
1
1
  # Email Provider Links
2
2
 
3
- ๐Ÿ”’ **Modern email provider detection library with concurrent DNS resolution and enterprise security**
3
+ ๐Ÿ”’ **Modern email provider detection library with enhanced TypeScript support and enterprise security**
4
4
 
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.
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
6
 
7
- ## โœจ Features
7
+ ## ๐Ÿš€ Try it out
8
8
 
9
- - ๐Ÿš€ **Fast & Lightweight**: Zero dependencies, ultra-low memory (~0.39MB initial, ~0.02MB per 1000 ops)
9
+ **[Live Demo](https://demo.mikkelscheike.com)** - Test the library with any email address and see it in action!
10
+
11
+ ## โœจ New in Version 2.7.0
12
+
13
+ - ๐Ÿš€ **Modern TypeScript**: Updated to latest TypeScript 2025 standards with strict type checking
14
+ - ๐ŸŒ **Enhanced International Support**: Improved IDN validation and Punycode handling
15
+ - ๐Ÿ“ง **Advanced Email Validation**: Comprehensive validation with detailed error reporting
16
+ - ๐Ÿ”„ **Batch Processing**: Efficiently process multiple emails with deduplication
17
+ - ๐Ÿ›ก๏ธ **Improved Security**: Enhanced cryptographic integrity verification
18
+ - โšก **Better Performance**: Optimized concurrent DNS with smart caching
19
+ - ๐ŸŽฏ **Developer Experience**: Enhanced error messages and debugging information
20
+ - ๐Ÿ“Š **Development Mode**: Memory usage tracking when NODE_ENV=development
21
+
22
+ ## โœจ Core Features
23
+
24
+ - ๐Ÿš€ **Fast & Lightweight**: Zero dependencies, ultra-low memory (~0.08MB initial, ~0.03MB per 1000 ops)
10
25
  - ๐Ÿ“ง **93 Email Providers**: Gmail, Outlook, Yahoo, ProtonMail, iCloud, and many more
11
- - ๐ŸŒ **178 Domains Supported**: Comprehensive international coverage
12
- - ๐ŸŒ **IDN Support**: Full internationalized domain name (punycode) support with RFC compliance
13
- - โœ… **Email Validation**: International email validation following RFC 5321, 5322, and 6530 standards
26
+ - ๐ŸŒ **207 Domains Supported**: Comprehensive international coverage
27
+ - ๐ŸŒ **Full IDN Support**: International domain names with RFC compliance and Punycode
28
+ - โœ… **Advanced Email Validation**: International email validation with detailed error reporting
14
29
  - ๐Ÿข **Business Domain Detection**: DNS-based detection for custom domains (Google Workspace, Microsoft 365, etc.)
15
30
  - ๐Ÿ”’ **Enterprise Security**: Multi-layer protection against malicious URLs and supply chain attacks
16
31
  - ๐Ÿ›ก๏ธ **URL Validation**: HTTPS-only enforcement with domain allowlisting
@@ -20,7 +35,8 @@ A TypeScript library providing direct links to **93 email providers** (178 domai
20
35
  - ๐Ÿšฆ **Rate Limiting**: Built-in DNS query rate limiting to prevent abuse
21
36
  - ๐Ÿ”„ **Email Alias Detection**: Normalize Gmail dots, plus addressing, and provider-specific aliases
22
37
  - ๐Ÿ›ก๏ธ **Fraud Prevention**: Detect duplicate accounts through email alias manipulation
23
- - ๐Ÿงช **Thoroughly Tested**: 370 tests with 92.89% code coverage
38
+ - ๐Ÿ“ฆ **Batch Processing**: Efficiently process multiple emails with deduplication
39
+ - ๐Ÿงช **Thoroughly Tested**: 424 tests with 93.16% code coverage
24
40
 
25
41
  ## Installation
26
42
 
@@ -32,7 +48,7 @@ npm install @mikkelscheike/email-provider-links
32
48
  ## Requirements
33
49
 
34
50
  - **Node.js**: `>=18.0.0` (Tested on 18.x, 20.x, 22.x, **24.x**)
35
- - **TypeScript**: `>=4.0.0` (optional)
51
+ - **TypeScript**: `>=4.0.0` (optional, but recommended)
36
52
  - **Zero runtime dependencies** - No external packages required
37
53
 
38
54
  ### Node.js 24 Support โœจ
@@ -43,30 +59,9 @@ Fully compatible with the latest Node.js 24.x! The library is tested on:
43
59
  - Node.js 22.x (Current)
44
60
  - **Node.js 24.x (Latest)** - Full support with latest features
45
61
 
46
- ## Quick Start
47
-
48
- **One function handles everything** - consumer emails, business domains, and unknown providers:
49
-
50
- ```typescript
51
- import { getEmailProvider } from '@mikkelscheike/email-provider-links';
52
-
53
- // Works for ANY email address - the only function you need
54
- const result = await getEmailProvider('user@gmail.com');
55
- console.log(result.loginUrl); // "https://mail.google.com/mail/"
56
- console.log(result.provider?.companyProvider); // "Gmail"
57
-
58
- // Automatically detects business domains too
59
- const business = await getEmailProvider('user@mycompany.com');
60
- console.log(business.provider?.companyProvider); // "Google Workspace" (if detected)
61
-
62
- // Gracefully handles unknown providers
63
- const unknown = await getEmailProvider('user@unknown.com');
64
- console.log(unknown.loginUrl); // null
65
- ```
66
-
67
62
  ## Supported Providers
68
63
 
69
- **๐Ÿ“Š Current Coverage: 93 providers supporting 178 domains**
64
+ **๐Ÿ“Š Current Coverage: 93 providers supporting 207 domains**
70
65
 
71
66
  **Consumer Email Providers:**
72
67
  - **Gmail** (2 domains): gmail.com, googlemail.com
@@ -95,7 +90,7 @@ console.log(unknown.loginUrl); // null
95
90
  - **Eastern Europe**: Centrum (Czech/Slovak), Interia, Onet (Poland), Rambler (Russia)
96
91
  - **Other Regions**: UOL, Terra (Brazil), Telkom (South Africa), Xtra (New Zealand)
97
92
 
98
- ## API
93
+ ## API Reference
99
94
 
100
95
  ### `getEmailProvider(email, timeout?)`
101
96
  **Recommended** - Detects any email provider including business domains.
@@ -128,21 +123,42 @@ const result = getEmailProviderSync('user@gmail.com');
128
123
  // Returns: { provider, loginUrl, email }
129
124
  ```
130
125
 
126
+ ### `getEmailProviderFast(email, options?)`
127
+ **High-performance** - Concurrent DNS with detailed timing information.
128
+
129
+ ```typescript
130
+ const result = await getEmailProviderFast('user@mycompany.com', {
131
+ enableParallel: true,
132
+ collectDebugInfo: true,
133
+ timeout: 3000
134
+ });
135
+
136
+ console.log(result.timing); // { mx: 120, txt: 95, total: 125 }
137
+ console.log(result.confidence); // 0.9
138
+ ```
139
+
131
140
  ## Real-World Example
132
141
 
133
142
  ```typescript
134
143
  async function handlePasswordReset(email: string) {
135
- const result = await getEmailProvider(email);
144
+ // Validate email first
145
+ const validation = validateEmailAddress(email);
146
+ if (!validation.isValid) {
147
+ throw new Error(`Invalid email: ${validation.error?.message}`);
148
+ }
149
+
150
+ // Get provider information
151
+ const result = await getEmailProvider(validation.normalizedEmail);
136
152
 
137
153
  return {
138
154
  providerUrl: result.loginUrl,
139
155
  providerName: result.provider?.companyProvider || null,
140
- isSupported: result.provider !== null
156
+ isSupported: result.provider !== null,
157
+ detectionMethod: result.detectionMethod
141
158
  };
142
159
  }
143
160
  ```
144
161
 
145
-
146
162
  ## Configuration
147
163
 
148
164
  ```typescript
@@ -155,97 +171,24 @@ console.log('Max requests:', Config.MAX_DNS_REQUESTS_PER_MINUTE); // 10
155
171
  console.log('Default timeout:', Config.DEFAULT_DNS_TIMEOUT); // 5000ms
156
172
  ```
157
173
 
158
- ## Email Validation
159
-
160
- The library includes comprehensive email validation following international standards:
161
-
162
- ```typescript
163
- import { validateInternationalEmail } from '@mikkelscheike/email-provider-links';
164
-
165
- // Validate any email address
166
- const result = validateInternationalEmail('user@example.com');
167
-
168
- // Returns undefined for valid emails
169
- console.log(result); // undefined
170
-
171
- // Returns detailed error information for invalid emails
172
- const invalid = validateInternationalEmail('user@mรผnchen.com');
173
- if (invalid) {
174
- console.log(invalid.code); // IDN_VALIDATION_ERROR
175
- console.log(invalid.message); // Human-readable error message
176
- }
177
- ```
178
-
179
- ### Validation Features
180
-
181
- - โœ… **RFC Compliance**: Follows RFC 5321, 5322, and 6530 standards
182
- - ๐ŸŒ **International Support**: Full IDN (Punycode) validation
183
- - ๐Ÿ“ **Detailed Errors**: Clear, translatable error messages
184
- - ๐Ÿ” **Comprehensive Checks**:
185
- - Local part validation (username)
186
- - Domain format validation
187
- - IDN encoding validation
188
- - Length limits (local part, domain, total)
189
- - TLD validation
190
-
191
174
  ## Advanced Usage
192
175
 
193
176
  <details>
194
- <summary><strong>๐Ÿ“š Secondary Functions & Specialized Use Cases</strong></summary>
177
+ <summary><strong>๐Ÿ“š Advanced Features & Specialized Use Cases</strong></summary>
195
178
 
196
- ### Synchronous Provider Detection (No DNS)
197
-
198
- If you can't use async or don't want DNS lookups:
179
+ ### Library Statistics
199
180
 
200
181
  ```typescript
201
- import { getEmailProviderSync } from '@mikkelscheike/email-provider-links';
202
-
203
- // Synchronous - only checks predefined domains
204
- const result = getEmailProviderSync('user@gmail.com');
205
- console.log(result.loginUrl); // Works for known domains only
206
- ```
182
+ import { getLibraryStats, getSupportedProviders } from '@mikkelscheike/email-provider-links';
207
183
 
208
- ### Provider Support Checking
209
-
210
- ```typescript
211
- import { isEmailProviderSupported, getSupportedProviders } from '@mikkelscheike/email-provider-links';
184
+ const stats = getLibraryStats();
185
+ console.log(`Version ${stats.version} supports ${stats.providerCount} providers`);
212
186
 
213
- // Check if provider is supported
214
- const supported = isEmailProviderSupported('user@gmail.com');
215
-
216
- // Get all supported providers
217
- const allProviders = getSupportedProviders();
218
- console.log(`Supports ${allProviders.length} providers`);
219
- ```
220
-
221
- ### Advanced Provider Detection
222
-
223
- ```typescript
224
- import { getEmailProviderFast, detectProviderConcurrent } from '@mikkelscheike/email-provider-links';
225
-
226
- // High-performance detection with concurrent DNS
227
- const fastResult = await getEmailProviderFast('user@mycompany.com', {
228
- enableParallel: true,
229
- collectDebugInfo: true
230
- });
231
- console.log(fastResult.provider?.companyProvider); // "Google Workspace"
232
- console.log(fastResult.timing); // Performance metrics
187
+ const providers = getSupportedProviders();
188
+ console.log(`Total providers: ${providers.length}`);
233
189
  ```
234
190
 
235
- ### Configuration Options
236
-
237
- ```typescript
238
- import { Config } from '@mikkelscheike/email-provider-links';
239
-
240
- // Access configuration constants
241
- console.log(Config.DEFAULT_DNS_TIMEOUT); // 5000ms
242
- console.log(Config.MAX_DNS_REQUESTS_PER_MINUTE); // 10
243
- console.log(Config.SUPPORTED_PROVIDERS_COUNT); // 93
244
- ```
245
-
246
- ### ๐Ÿ”„ Email Alias Detection & Normalization
247
-
248
- **Specialized feature** for preventing duplicate accounts and fraud detection:
191
+ ### Email Alias Detection & Normalization
249
192
 
250
193
  ```typescript
251
194
  import {
@@ -274,107 +217,63 @@ const canonical = normalizeEmail('u.s.e.r+work@gmail.com');
274
217
  console.log(canonical); // 'user@gmail.com'
275
218
  ```
276
219
 
277
- **Supported alias types:**
278
- - **Gmail dots**: `u.s.e.r@gmail.com` โ†’ `user@gmail.com`
279
- - **Plus addressing**: `user+tag@provider.com` โ†’ `user@provider.com`
280
- - **Provider-specific rules**: Different providers have different capabilities
281
-
282
- </details>
283
-
284
- ## TypeScript Support
220
+ ### Provider Support Checking
285
221
 
286
222
  ```typescript
287
- interface EmailProviderResult {
288
- provider: EmailProvider | null;
289
- email: string;
290
- loginUrl: string | null;
291
- detectionMethod?: 'domain_match' | 'mx_record' | 'txt_record' | 'proxy_detected';
292
- proxyService?: string;
293
- error?: {
294
- type: 'INVALID_EMAIL' | 'DNS_TIMEOUT' | 'RATE_LIMITED' | 'UNKNOWN_DOMAIN' |
295
- 'NETWORK_ERROR' | 'IDN_VALIDATION_ERROR';
296
- message: string;
297
- idnError?: string; // Specific IDN validation error message
298
- };
299
- }
300
-
301
- interface ConfigConstants {
302
- DEFAULT_DNS_TIMEOUT: number; // 5000ms
303
- MAX_DNS_REQUESTS_PER_MINUTE: number; // 10 requests
304
- SUPPORTED_PROVIDERS_COUNT: number; // 93 providers
305
- SUPPORTED_DOMAINS_COUNT: number; // 178 domains
306
- }
307
- ```
308
-
309
- ## ๐Ÿ›ก๏ธ Security Features
310
-
311
- This package implements **enterprise-grade security** to protect against malicious redirects and supply chain attacks:
223
+ import { isEmailProviderSupported, extractDomain } from '@mikkelscheike/email-provider-links';
312
224
 
313
- ### โœ… Multi-Layer Protection
314
-
315
- - **HTTPS-Only Enforcement**: All provider URLs must use HTTPS protocol
316
- - **Domain Allowlisting**: Only pre-approved domains are allowed (93+ verified providers)
317
- - **Malicious Pattern Detection**: Blocks IP addresses, URL shorteners, suspicious TLDs
318
- - **Path Traversal Prevention**: Detects and blocks `../` and encoded variants
319
- - **JavaScript Injection Protection**: Prevents `javascript:`, `data:`, and script injections
320
- - **File Integrity Verification**: SHA-256 hash verification for provider database
225
+ // Check if provider is supported
226
+ const supported = isEmailProviderSupported('user@gmail.com');
321
227
 
322
- ### ๐Ÿ”’ Attack Prevention
228
+ // Extract domain safely
229
+ const domain = extractDomain('USER@EXAMPLE.COM');
230
+ console.log(domain); // 'example.com'
231
+ ```
323
232
 
324
- Protects against common attack vectors:
325
- - โŒ **URL Injection**: Blocked by strict allowlisting
326
- - โŒ **Typosquatting**: Blocked by domain validation
327
- - โŒ **URL Shorteners**: Blocked by pattern detection
328
- - โŒ **Protocol Downgrade**: Blocked by HTTPS enforcement
329
- - โŒ **Path Traversal**: Blocked by path validation
330
- - โŒ **Script Injection**: Blocked by content validation
331
- - โŒ **Supply Chain Attacks**: Blocked by integrity verification
233
+ </details>
332
234
 
333
- ### ๐Ÿงช Security Testing
235
+ ## Performance and Detection System
334
236
 
335
- - **92 dedicated security tests** covering all attack vectors
336
- - **Comprehensive security module coverage** with edge case testing
337
- - **Automated security validation** in CI/CD pipeline
338
- - **Regular security audits** of provider database
237
+ For detailed performance metrics and information about the detection system, refer to [Performance and Detection System](docs/PERFORMANCE.md).
339
238
 
340
- ### ๐Ÿ” For Security Teams
239
+ ### Development Mode Features
341
240
 
342
- Security validation can be integrated into your workflow:
241
+ When `NODE_ENV` is set to 'development', the library provides additional insights:
343
242
 
344
243
  ```typescript
345
- import { secureLoadProviders } from '@mikkelscheike/email-provider-links/security';
346
-
347
- // Secure loading with integrity verification
348
- const result = secureLoadProviders();
349
- if (result.securityReport.securityLevel === 'CRITICAL') {
350
- // Handle security incident
351
- console.error('Security validation failed:', result.securityReport.issues);
352
- }
244
+ // Memory usage is automatically logged:
245
+ // ๐Ÿš€ Current memory usage: 0.08 MB
353
246
  ```
354
247
 
355
- ## Performance Benchmarks
248
+ ### Memory Management
356
249
 
357
- This package is designed to be extremely memory efficient and fast. We continuously monitor performance metrics through automated benchmarks that run on every PR and release.
250
+ The library implements careful memory management:
251
+ - Initial load: ~0.08MB heap usage
252
+ - Batch operations: ~0.03MB per 1000 operations
253
+ - Maximum load: < 25MB even under heavy concurrent operations
254
+ - Automatic garbage collection hints
255
+ - Memory usage logging in development mode
358
256
 
359
- Latest benchmark results show:
360
- - Provider loading: ~0.39MB heap usage, <0.5ms
361
- - Email lookups: ~0.02MB heap usage per 100 operations
362
- - Concurrent DNS: ~0.03MB heap usage, ~110ms for 10 lookups
363
- - Large scale (1000 ops): ~0.02MB heap usage, <3ms total
364
- - Cache effectiveness: ~0.01MB impact on subsequent loads
257
+ ### Performance Benchmarks
258
+
259
+ This package is designed to be extremely memory efficient and fast:
260
+
261
+ - **Provider loading**: ~0.08MB heap usage, ~0.5ms
262
+ - **Email lookups**: ~0.03MB heap usage per 100 operations
263
+ - **Concurrent DNS**: ~0.03MB heap usage, ~27ms for 10 lookups
264
+ - **Large scale (1000 ops)**: ~0.03MB heap usage, ~1.1ms total
265
+ - **International validation**: <1ms for complex IDN domains
365
266
 
366
267
  To run benchmarks locally:
367
268
  ```bash
368
269
  npm run benchmark
369
270
  ```
370
271
 
371
- Benchmarks are automatically run in CI to catch any performance regressions.
372
-
373
272
  ## Contributing
374
273
 
375
274
  We welcome contributions! See [CONTRIBUTING.md](docs/CONTRIBUTING.md) for guidelines on adding new email providers.
376
275
 
377
- **Quality Assurance**: This project maintains high standards with 370 comprehensive tests achieving 92.89% code coverage.
276
+ **Quality Assurance**: This project maintains high standards with 424 comprehensive tests achieving 93.16% code coverage (96.46% function coverage).
378
277
  **Security Note**: All new providers undergo security validation and must pass our allowlist verification.
379
278
 
380
279
  ## Security
@@ -387,5 +286,4 @@ MIT License - see [LICENSE](LICENSE) file for details.
387
286
 
388
287
  ---
389
288
 
390
- **Zero dependencies โ€ข TypeScript-first โ€ข Production ready**
391
-
289
+ **Zero dependencies โ€ข TypeScript-first โ€ข Production ready โ€ข International support**
@@ -56,3 +56,4 @@ export declare function normalizeEmail(email: string): string;
56
56
  * ```
57
57
  */
58
58
  export declare function emailsMatch(email1: string, email2: string): boolean;
59
+ //# sourceMappingURL=alias-detection.d.ts.map
@@ -18,7 +18,12 @@ const ALIAS_RULES = [
18
18
  supportsPlusAddressing: true,
19
19
  ignoresDots: true,
20
20
  normalize: (email) => {
21
- const [username, domain] = email.toLowerCase().split('@');
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
+ }
22
27
  // Remove dots and everything after +
23
28
  const cleanUsername = username.replace(/\./g, '').split('+')[0];
24
29
  return `${cleanUsername}@${domain}`;
@@ -29,7 +34,12 @@ const ALIAS_RULES = [
29
34
  supportsPlusAddressing: true,
30
35
  ignoresDots: false,
31
36
  normalize: (email) => {
32
- const [username, domain] = email.toLowerCase().split('@');
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
+ }
33
43
  // Only remove plus addressing for Outlook
34
44
  const cleanUsername = username.split('+')[0];
35
45
  return `${cleanUsername}@${domain}`;
@@ -40,7 +50,12 @@ const ALIAS_RULES = [
40
50
  supportsPlusAddressing: true,
41
51
  ignoresDots: false,
42
52
  normalize: (email) => {
43
- const [username, domain] = email.toLowerCase().split('@');
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
+ }
44
59
  const cleanUsername = username.split('+')[0];
45
60
  return `${cleanUsername}@${domain}`;
46
61
  }
@@ -50,7 +65,12 @@ const ALIAS_RULES = [
50
65
  supportsPlusAddressing: true,
51
66
  ignoresDots: false,
52
67
  normalize: (email) => {
53
- const [username, domain] = email.toLowerCase().split('@');
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
+ }
54
74
  const cleanUsername = username.split('+')[0];
55
75
  return `${cleanUsername}@${domain}`;
56
76
  }
@@ -60,7 +80,12 @@ const ALIAS_RULES = [
60
80
  supportsPlusAddressing: true,
61
81
  ignoresDots: false,
62
82
  normalize: (email) => {
63
- const [username, domain] = email.toLowerCase().split('@');
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
+ }
64
89
  const cleanUsername = username.split('+')[0];
65
90
  return `${cleanUsername}@${domain}`;
66
91
  }
@@ -70,7 +95,12 @@ const ALIAS_RULES = [
70
95
  supportsPlusAddressing: true,
71
96
  ignoresDots: false,
72
97
  normalize: (email) => {
73
- const [username, domain] = email.toLowerCase().split('@');
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
+ }
74
104
  const cleanUsername = username.split('+')[0];
75
105
  return `${cleanUsername}@${domain}`;
76
106
  }
@@ -80,7 +110,12 @@ const ALIAS_RULES = [
80
110
  supportsPlusAddressing: true,
81
111
  ignoresDots: false,
82
112
  normalize: (email) => {
83
- const [username, domain] = email.toLowerCase().split('@');
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
+ }
84
119
  const cleanUsername = username.split('+')[0];
85
120
  return `${cleanUsername}@${domain}`;
86
121
  }
@@ -90,7 +125,12 @@ const ALIAS_RULES = [
90
125
  supportsPlusAddressing: true,
91
126
  ignoresDots: false,
92
127
  normalize: (email) => {
93
- const [username, domain] = email.toLowerCase().split('@');
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
+ }
94
134
  const cleanUsername = username.split('+')[0];
95
135
  return `${cleanUsername}@${domain}`;
96
136
  }
@@ -100,7 +140,12 @@ const ALIAS_RULES = [
100
140
  supportsPlusAddressing: true,
101
141
  ignoresDots: false,
102
142
  normalize: (email) => {
103
- const [username, domain] = email.toLowerCase().split('@');
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
+ }
104
149
  const cleanUsername = username.split('+')[0];
105
150
  return `${cleanUsername}@${domain}`;
106
151
  }
@@ -116,7 +161,12 @@ const ALIAS_RULES = [
116
161
  supportsPlusAddressing: true,
117
162
  ignoresDots: false,
118
163
  normalize: (email) => {
119
- const [username, domain] = email.toLowerCase().split('@');
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
+ }
120
170
  const cleanUsername = username.split('+')[0];
121
171
  return `${cleanUsername}@${domain}`;
122
172
  }
@@ -126,7 +176,12 @@ const ALIAS_RULES = [
126
176
  supportsPlusAddressing: true,
127
177
  ignoresDots: false,
128
178
  normalize: (email) => {
129
- const [username, domain] = email.toLowerCase().split('@');
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
+ }
130
185
  const cleanUsername = username.split('+')[0];
131
186
  return `${cleanUsername}@${domain}`;
132
187
  }
@@ -143,7 +198,7 @@ function isValidEmail(email) {
143
198
  * Gets the alias rule for a given domain
144
199
  */
145
200
  function getAliasRule(domain) {
146
- return ALIAS_RULES.find(rule => rule.domains.includes(domain.toLowerCase()));
201
+ return ALIAS_RULES.find(rule => rule.domains.includes(domain.toLowerCase())) || null;
147
202
  }
148
203
  /**
149
204
  * Detects and analyzes email aliases
@@ -156,7 +211,12 @@ function detectEmailAlias(email) {
156
211
  throw new Error('Invalid email format');
157
212
  }
158
213
  const originalEmail = email.trim();
159
- const [username, domain] = originalEmail.toLowerCase().split('@');
214
+ const emailParts = originalEmail.toLowerCase().split('@');
215
+ const username = emailParts[0];
216
+ const domain = emailParts[1];
217
+ if (!username || !domain) {
218
+ throw new Error('Invalid email format - missing username or domain');
219
+ }
160
220
  const rule = getAliasRule(domain);
161
221
  const result = {
162
222
  canonical: originalEmail.toLowerCase(),
@@ -243,3 +303,4 @@ function emailsMatch(email1, email2) {
243
303
  return false;
244
304
  }
245
305
  }
306
+ //# sourceMappingURL=alias-detection.js.map
package/dist/api.d.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  */
7
7
  export interface EmailProvider {
8
8
  companyProvider: string;
9
- loginUrl: string;
9
+ loginUrl: string | null;
10
10
  domains: string[];
11
11
  customDomainDetection?: {
12
12
  mxPatterns?: string[];
@@ -51,13 +51,13 @@ export interface EmailProviderResult {
51
51
  * ```typescript
52
52
  * // Consumer email
53
53
  * const gmail = await getEmailProvider('user@gmail.com');
54
- * console.log(gmail.provider?.name); // "Gmail"
55
- * console.log(gmail.loginUrl); // "https://mail.google.com/mail/"
54
+ * console.log(gmail.provider?.companyProvider); // "Gmail"
55
+ * console.log(gmail.loginUrl); // "https://mail.google.com/mail/"
56
56
  *
57
57
  * // Business domain
58
58
  * const business = await getEmailProvider('user@mycompany.com');
59
- * console.log(business.provider?.name); // "Google Workspace" (if detected)
60
- * console.log(business.detectionMethod); // "mx_record"
59
+ * console.log(business.provider?.companyProvider); // "Google Workspace" (if detected)
60
+ * console.log(business.detectionMethod); // "mx_record"
61
61
  *
62
62
  * // Error handling
63
63
  * const invalid = await getEmailProvider('invalid-email');
@@ -79,7 +79,7 @@ export declare function getEmailProvider(email: string, timeout?: number): Promi
79
79
  * ```typescript
80
80
  * // Works for known domains
81
81
  * const gmail = getEmailProviderSync('user@gmail.com');
82
- * console.log(gmail.provider?.name); // "Gmail"
82
+ * console.log(gmail.provider?.companyProvider); // "Gmail"
83
83
  *
84
84
  * // Unknown domains return null
85
85
  * const unknown = getEmailProviderSync('user@mycompany.com');
@@ -171,3 +171,4 @@ export declare const Config: {
171
171
  readonly SUPPORTED_PROVIDERS_COUNT: 93;
172
172
  readonly SUPPORTED_DOMAINS_COUNT: 180;
173
173
  };
174
+ //# sourceMappingURL=api.d.ts.map