@mikkelscheike/email-provider-links 2.8.1 โ†’ 3.0.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
@@ -8,20 +8,21 @@ A robust TypeScript library providing direct links to **93 email providers** (18
8
8
 
9
9
  **[Live Demo](https://demo.mikkelscheike.com)** - Test the library with any email address and see it in action!
10
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
11
+ ## โœจ New in Version 3.0.0
12
+
13
+ - ๐Ÿš€ **Performance Optimizations**: Further improved DNS resolution and caching
14
+ - ๐ŸŽฏ **Enhanced Precision**: Adjusted performance thresholds based on real-world metrics
15
+ - ๐Ÿ›ก๏ธ **Security Updates**: Removed legacy detection methods and updated security hashes
16
+ - ๐Ÿ“ **TypeScript Improvements**: Resolved TypeScript errors and enhanced type safety
17
+ - ๐Ÿ“š **Documentation**: Consolidated and improved documentation for better clarity
18
+ - โšก **Infrastructure**: Optimized build process and development workflow
19
+ - ๐Ÿงช **Testing**: Expanded test coverage to 445 comprehensive tests
20
+ - ๐Ÿ”„ **Provider Updates**: Added support for 23 new email providers
21
+ - ๐Ÿ” **Advanced Alias Detection**: Refined provider-specific email alias handling for dots, plus addressing, and case sensitivity
21
22
 
22
23
  ## โœจ Core Features
23
24
 
24
- - ๐Ÿš€ **Fast & Lightweight**: Zero dependencies, ultra-low memory (~0.08MB initial, ~0.03MB per 1000 ops)
25
+ - ๐Ÿš€ **Fast & Lightweight**: Zero dependencies, ultra-low memory (0.10MB initial, 0.00004MB per 1000 ops), small footprint (~39.5KB compressed)
25
26
  - ๐Ÿ“ง **93 Email Providers**: Gmail, Outlook, Yahoo, ProtonMail, iCloud, and many more
26
27
  - ๐ŸŒ **207 Domains Supported**: Comprehensive international coverage
27
28
  - ๐ŸŒ **Full IDN Support**: International domain names with RFC compliance and Punycode
@@ -36,7 +37,7 @@ A robust TypeScript library providing direct links to **93 email providers** (18
36
37
  - ๐Ÿ”„ **Email Alias Detection**: Normalize Gmail dots, plus addressing, and provider-specific aliases
37
38
  - ๐Ÿ›ก๏ธ **Fraud Prevention**: Detect duplicate accounts through email alias manipulation
38
39
  - ๐Ÿ“ฆ **Batch Processing**: Efficiently process multiple emails with deduplication
39
- - ๐Ÿงช **Thoroughly Tested**: 424 tests with 93.16% code coverage
40
+ - ๐Ÿงช **Thoroughly Tested**: 445 tests with 94.65% code coverage
40
41
 
41
42
  ## Installation
42
43
 
@@ -236,8 +237,6 @@ console.log(domain); // 'example.com'
236
237
 
237
238
  ## Performance and Detection System
238
239
 
239
- For detailed performance metrics and information about the detection system, refer to [Performance and Detection System](docs/PERFORMANCE.md).
240
-
241
240
  ### Development Mode Features
242
241
 
243
242
  When `NODE_ENV` is set to 'development', the library provides additional insights:
@@ -247,15 +246,6 @@ When `NODE_ENV` is set to 'development', the library provides additional insight
247
246
  // ๐Ÿš€ Current memory usage: 0.08 MB
248
247
  ```
249
248
 
250
- ### Memory Management
251
-
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
258
-
259
249
  ### Performance Benchmarks
260
250
 
261
251
  Extensively optimized for both speed and memory efficiency:
@@ -267,10 +257,10 @@ Extensively optimized for both speed and memory efficiency:
267
257
  - Batch processing: 1000 operations in ~1.1ms
268
258
  - Email validation: <1ms for complex IDN domains
269
259
 
270
- **Memory Usage**:
271
- - Initial footprint: ~0.08MB
272
- - Per operation: ~0.03MB per 1000 lookups
273
- - Peak usage: <25MB under heavy load
260
+ **Memory Management**:
261
+ - Initial load: ~0.10MB heap usage
262
+ - Batch operations: ~0.00004MB per 1000 operations
263
+ - Maximum load: < 25MB under heavy concurrent operations
274
264
  - Cache efficiency: >99% hit rate
275
265
  - Garbage collection: Automatic optimization
276
266
 
@@ -282,15 +272,21 @@ Extensively optimized for both speed and memory efficiency:
282
272
 
283
273
  To run benchmarks:
284
274
  ```bash
285
- npm run benchmark # Basic benchmarks
286
- node --expose-gc benchmark/memory.ts # Detailed memory analysis
275
+ # Memory usage benchmark
276
+ npm run benchmark:memory
277
+
278
+ # DNS performance benchmark
279
+ npm run benchmark:dns
280
+
281
+ # Both scripts are available in the scripts/ directory
282
+ # and can be modified for custom performance testing
287
283
  ```
288
284
 
289
285
  ## Contributing
290
286
 
291
287
  We welcome contributions! See [CONTRIBUTING.md](docs/CONTRIBUTING.md) for guidelines on adding new email providers.
292
288
 
293
- **Quality Assurance**: This project maintains high standards with 424 comprehensive tests achieving 93.16% code coverage (96.46% function coverage).
289
+ **Quality Assurance**: This project maintains high standards with 445 comprehensive tests achieving 94.65% code coverage (95.95% function coverage).
294
290
  **Security Note**: All new providers undergo security validation and must pass our allowlist verification.
295
291
 
296
292
  ## Security
@@ -3,6 +3,43 @@
3
3
  *
4
4
  * Clean, focused implementation with only essential functions.
5
5
  * Detects and normalizes email aliases across different providers.
6
+ *
7
+ * Alias Configuration Behavior:
8
+ * ---------------------------
9
+ * The module handles email aliases based on provider-specific configurations.
10
+ * Each provider can specify how to handle three types of email variations:
11
+ *
12
+ * 1. Case sensitivity ("case")
13
+ * 2. Plus addressing ("plus")
14
+ * 3. Dots in username ("dots")
15
+ *
16
+ * Important: For each of these properties, modifications are only applied if
17
+ * explicitly configured in the provider's settings:
18
+ *
19
+ * - If a property is defined (e.g., "case": {"ignore": true, "strip": true}),
20
+ * the specified behavior is applied
21
+ *
22
+ * - If a property is missing from the provider's alias configuration,
23
+ * the original value is preserved without modification
24
+ *
25
+ * Example:
26
+ * ```json
27
+ * {
28
+ * "alias": {
29
+ * "dots": { "ignore": false, "strip": false },
30
+ * "plus": { "ignore": true, "strip": true }
31
+ * // case is not defined, so case will be preserved
32
+ * }
33
+ * }
34
+ * ```
35
+ *
36
+ * In this example:
37
+ * - Dots will be preserved (configured to not ignore/strip)
38
+ * - Plus addressing will be stripped (configured to ignore/strip)
39
+ * - Case will be preserved (not configured)
40
+ *
41
+ * Note: The domain part of email addresses is always converted to lowercase
42
+ * as per RFC 5321 standard, regardless of provider configuration.
6
43
  */
7
44
  export interface AliasDetectionResult {
8
45
  /** The normalized/canonical email address */
@@ -21,8 +58,26 @@ export interface AliasDetectionResult {
21
58
  /**
22
59
  * Detects and analyzes email aliases
23
60
  *
61
+ * This function processes email addresses according to provider-specific rules.
62
+ * Case is always lowercased in the canonical form for consistency and safety.
63
+ * It only applies additional modifications (plus, dots) that are explicitly
64
+ * defined in the provider's configuration.
65
+ *
24
66
  * @param email - Email address to analyze
25
67
  * @returns Detailed analysis of the email alias
68
+ *
69
+ * @example
70
+ * Provider with no case handling defined:
71
+ * ```typescript
72
+ * detectEmailAlias('User.Name@example.com')
73
+ * // Preserves case: User.Name@example.com
74
+ * ```
75
+ *
76
+ * Provider with case handling defined:
77
+ * ```typescript
78
+ * detectEmailAlias('User.Name@gmail.com')
79
+ * // Converts to lowercase: user.name@gmail.com
80
+ * ```
26
81
  */
27
82
  export declare function detectEmailAlias(email: string): AliasDetectionResult;
28
83
  /**
@@ -4,6 +4,43 @@
4
4
  *
5
5
  * Clean, focused implementation with only essential functions.
6
6
  * Detects and normalizes email aliases across different providers.
7
+ *
8
+ * Alias Configuration Behavior:
9
+ * ---------------------------
10
+ * The module handles email aliases based on provider-specific configurations.
11
+ * Each provider can specify how to handle three types of email variations:
12
+ *
13
+ * 1. Case sensitivity ("case")
14
+ * 2. Plus addressing ("plus")
15
+ * 3. Dots in username ("dots")
16
+ *
17
+ * Important: For each of these properties, modifications are only applied if
18
+ * explicitly configured in the provider's settings:
19
+ *
20
+ * - If a property is defined (e.g., "case": {"ignore": true, "strip": true}),
21
+ * the specified behavior is applied
22
+ *
23
+ * - If a property is missing from the provider's alias configuration,
24
+ * the original value is preserved without modification
25
+ *
26
+ * Example:
27
+ * ```json
28
+ * {
29
+ * "alias": {
30
+ * "dots": { "ignore": false, "strip": false },
31
+ * "plus": { "ignore": true, "strip": true }
32
+ * // case is not defined, so case will be preserved
33
+ * }
34
+ * }
35
+ * ```
36
+ *
37
+ * In this example:
38
+ * - Dots will be preserved (configured to not ignore/strip)
39
+ * - Plus addressing will be stripped (configured to ignore/strip)
40
+ * - Case will be preserved (not configured)
41
+ *
42
+ * Note: The domain part of email addresses is always converted to lowercase
43
+ * as per RFC 5321 standard, regardless of provider configuration.
7
44
  */
8
45
  Object.defineProperty(exports, "__esModule", { value: true });
9
46
  exports.detectEmailAlias = detectEmailAlias;
@@ -20,24 +57,44 @@ function isValidEmail(email) {
20
57
  /**
21
58
  * Detects and analyzes email aliases
22
59
  *
60
+ * This function processes email addresses according to provider-specific rules.
61
+ * Case is always lowercased in the canonical form for consistency and safety.
62
+ * It only applies additional modifications (plus, dots) that are explicitly
63
+ * defined in the provider's configuration.
64
+ *
23
65
  * @param email - Email address to analyze
24
66
  * @returns Detailed analysis of the email alias
67
+ *
68
+ * @example
69
+ * Provider with no case handling defined:
70
+ * ```typescript
71
+ * detectEmailAlias('User.Name@example.com')
72
+ * // Preserves case: User.Name@example.com
73
+ * ```
74
+ *
75
+ * Provider with case handling defined:
76
+ * ```typescript
77
+ * detectEmailAlias('User.Name@gmail.com')
78
+ * // Converts to lowercase: user.name@gmail.com
79
+ * ```
25
80
  */
26
81
  function detectEmailAlias(email) {
27
82
  if (!isValidEmail(email)) {
28
83
  throw new Error('Invalid email format');
29
84
  }
30
85
  const originalEmail = email.trim();
86
+ // Split normally, lowering case both for username and domain by default
31
87
  const emailParts = originalEmail.toLowerCase().split('@');
32
88
  const username = emailParts[0];
33
- const domain = emailParts[1];
89
+ const domain = emailParts[1]; // domain is always case-insensitive per RFC 5321
34
90
  if (!username || !domain) {
35
91
  throw new Error('Invalid email format - missing username or domain');
36
92
  }
37
93
  const { domainMap } = (0, loader_1.loadProviders)();
38
94
  const provider = domainMap.get(domain);
39
95
  const result = {
40
- canonical: originalEmail.toLowerCase(),
96
+ // Only lowercase domain part by default
97
+ canonical: `${username}@${domain}`,
41
98
  original: originalEmail,
42
99
  isAlias: false,
43
100
  aliasType: 'none'
@@ -50,13 +107,15 @@ function detectEmailAlias(email) {
50
107
  let isAlias = false;
51
108
  let aliasType = 'none';
52
109
  let aliasPart;
53
- // Handle case sensitivity (all modern providers are case-insensitive)
110
+ // Canonical form is always lowercased to ensure consistent and
111
+ // reliable email handling across different providers.
54
112
  if (provider.alias?.case?.ignore) {
55
113
  if (provider.alias.case?.strip) {
56
114
  normalizedUsername = normalizedUsername.toLowerCase();
57
115
  }
58
116
  }
59
- // Handle plus addressing (common for Gmail, Outlook, Yahoo, etc.)
117
+ // Handle plus addressing if defined in provider settings
118
+ // If plus handling is not defined, preserve plus addressing
60
119
  if (provider.alias?.plus?.ignore) {
61
120
  const plusIndex = username.indexOf('+');
62
121
  if (plusIndex !== -1) {
@@ -68,7 +127,8 @@ function detectEmailAlias(email) {
68
127
  }
69
128
  }
70
129
  }
71
- // Handle dots (primarily for Gmail)
130
+ // Handle dots if defined in provider settings
131
+ // If dots handling is not defined, preserve dots
72
132
  if (provider.alias?.dots?.ignore) {
73
133
  const hasDots = username.includes('.');
74
134
  if (hasDots) {
@@ -367,18 +367,14 @@ class ConcurrentDNSDetector {
367
367
  const mxQuery = queries.find(q => q.type === 'mx' && q.success);
368
368
  if (!mxQuery?.records)
369
369
  return null;
370
- // Get proxy services from provider data
371
- const proxyProviders = this.providers.filter(p => p.type === 'proxy_service');
372
- const proxyPatterns = proxyProviders.map(provider => ({
373
- service: provider.companyProvider,
374
- patterns: [...(provider.customDomainDetection?.mxPatterns || []), ...(provider.domains || [])].map(p => p.toLowerCase())
375
- }));
376
370
  for (const record of mxQuery.records) {
377
371
  const exchange = record.exchange?.toLowerCase() || '';
378
- for (const proxy of proxyPatterns) {
379
- for (const pattern of proxy.patterns) {
380
- if (exchange.includes(pattern)) {
381
- return proxy.service;
372
+ for (const provider of this.providers) {
373
+ if (provider.type === 'proxy_service' && provider.customDomainDetection?.mxPatterns) {
374
+ for (const pattern of provider.customDomainDetection.mxPatterns) {
375
+ if (exchange.includes(pattern.toLowerCase())) {
376
+ return provider.companyProvider;
377
+ }
382
378
  }
383
379
  }
384
380
  }
@@ -27,9 +27,9 @@ const path_1 = require("path");
27
27
  */
28
28
  const KNOWN_GOOD_HASHES = {
29
29
  // SHA-256 hash of the legitimate emailproviders.json
30
- 'emailproviders.json': 'c9c3cb1590820989071ec2bea8a7560496188031f8fa6367153e642315824cdb',
30
+ 'emailproviders.json': '65c136a13cbcd31507241b7ddc8850f81b98196d2e57fcd9ce6060825a010cef',
31
31
  // You can add hashes for other critical files
32
- 'package.json': 'da08eadfe33e8a5c5bcc3db0f0dccc402b4d8ab8440ff57d2e9aa986921ac66d'
32
+ 'package.json': '75ed1f7fb74a7be7002700358232660b0c2aa1da82499466d83b049687e74de9',
33
33
  };
34
34
  /**
35
35
  * Calculates SHA-256 hash of a file or string content
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mikkelscheike/email-provider-links",
3
- "version": "2.8.1",
4
- "description": "TypeScript library for email provider detection with 93 providers (207 domains), concurrent DNS resolution, optimized performance, 91.75% test coverage, and enterprise security for login and password reset flows",
3
+ "version": "3.0.0",
4
+ "description": "TypeScript library for email provider detection with 93 providers (207 domains), concurrent DNS resolution, optimized performance, 94.65% test coverage, and enterprise security for login and password reset flows",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "files": [
@@ -26,7 +26,8 @@
26
26
  "release:major": "tsx scripts/prepare-release.ts",
27
27
  "release:minor": "tsx scripts/prepare-release.ts",
28
28
  "release:patch": "tsx scripts/prepare-release.ts",
29
- "benchmark": "tsx --expose-gc benchmark/memory.ts"
29
+ "benchmark:memory": "tsx --expose-gc scripts/benchmark-memory.ts",
30
+ "benchmark:dns": "tsx scripts/benchmark-concurrent-dns.ts"
30
31
  },
31
32
  "keywords": [
32
33
  "email",
@@ -5,9 +5,9 @@
5
5
  "id": "cloudflare",
6
6
  "mx": [
7
7
  "mx.cloudflare.com",
8
- "cloudflare.com",
9
- "mxrecord.io",
10
- "mxrecord.mx"
8
+ "route1.mx.cloudflare.net",
9
+ "route2.mx.cloudflare.net",
10
+ "route3.mx.cloudflare.net"
11
11
  ],
12
12
  "txt": [
13
13
  "spf:_spf.cloudflare.com",
@@ -349,7 +349,7 @@
349
349
  "loginUrl": "https://www.hushmail.com/signin/"
350
350
  },
351
351
  {
352
- "id": "icloud",
352
+ "id": "icloud",
353
353
  "domains": [
354
354
  "icloud.com",
355
355
  "me.com",
@@ -484,7 +484,7 @@
484
484
  "loginUrl": "https://www.mail.bg"
485
485
  },
486
486
  {
487
- "id": "com",
487
+ "id": "com",
488
488
  "domains": [
489
489
  "mail.com"
490
490
  ],
@@ -937,7 +937,7 @@
937
937
  "loginUrl": "https://app.titan.email"
938
938
  },
939
939
  {
940
- "id": "tutano",
940
+ "id": "tutano",
941
941
  "domains": [
942
942
  "tutanota.com",
943
943
  "tutanota.de",
@@ -1058,7 +1058,7 @@
1058
1058
  }
1059
1059
  },
1060
1060
  {
1061
- "id": "yandex",
1061
+ "id": "yandex",
1062
1062
  "domains": [
1063
1063
  "yandex.ru",
1064
1064
  "yandex.com"
@@ -1106,7 +1106,7 @@
1106
1106
  }
1107
1107
  },
1108
1108
  {
1109
- "id": "zohoeu",
1109
+ "id": "zohoeu",
1110
1110
  "domains": [
1111
1111
  "zoho.eu"
1112
1112
  ],