@mikkelscheike/email-provider-links 2.6.1 → 2.7.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/dist/index.js CHANGED
@@ -2,24 +2,30 @@
2
2
  /**
3
3
  * Email Provider Links
4
4
  *
5
- * A clean, modern email provider detection library with:
5
+ * A modern, robust email provider detection library with:
6
6
  * - 93+ verified email providers covering 180+ domains
7
7
  * - Concurrent DNS detection for business domains
8
8
  * - Zero runtime dependencies
9
- * - Comprehensive error handling
10
- * - Email alias normalization
9
+ * - Comprehensive error handling with detailed context
10
+ * - International email validation (IDN support)
11
+ * - Email alias normalization and deduplication
12
+ * - Enterprise-grade security features
11
13
  *
12
14
  * @author Email Provider Links Team
13
15
  * @license MIT
16
+ * @version 2.7.0
14
17
  */
15
18
  Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.DOMAIN_COUNT = exports.PROVIDER_COUNT = exports.detectProviderConcurrent = exports.loadProviders = exports.Config = exports.emailsMatch = exports.normalizeEmail = exports.getEmailProviderFast = exports.getEmailProviderSync = exports.getEmailProvider = void 0;
19
+ exports.VERSION = exports.DOMAIN_COUNT = exports.PROVIDER_COUNT = exports.isValidEmailAddress = exports.domainToPunycode = exports.emailToPunycode = exports.validateInternationalEmail = exports.detectProviderConcurrent = exports.loadProviders = exports.Config = exports.emailsMatch = exports.normalizeEmail = exports.getEmailProviderFast = exports.getEmailProviderSync = exports.getEmailProvider = void 0;
20
+ exports.validateEmailAddress = validateEmailAddress;
17
21
  exports.getSupportedProviders = getSupportedProviders;
18
22
  exports.isEmailProviderSupported = isEmailProviderSupported;
19
23
  exports.extractDomain = extractDomain;
20
24
  exports.isValidEmail = isValidEmail;
25
+ exports.getLibraryStats = getLibraryStats;
26
+ exports.batchProcessEmails = batchProcessEmails;
21
27
  // ===== PRIMARY API =====
22
- // These are the functions 95% of users need
28
+ // Core functions that 95% of users need
23
29
  var api_1 = require("./api");
24
30
  Object.defineProperty(exports, "getEmailProvider", { enumerable: true, get: function () { return api_1.getEmailProvider; } });
25
31
  Object.defineProperty(exports, "getEmailProviderSync", { enumerable: true, get: function () { return api_1.getEmailProviderSync; } });
@@ -28,68 +34,340 @@ Object.defineProperty(exports, "normalizeEmail", { enumerable: true, get: functi
28
34
  Object.defineProperty(exports, "emailsMatch", { enumerable: true, get: function () { return api_1.emailsMatch; } });
29
35
  Object.defineProperty(exports, "Config", { enumerable: true, get: function () { return api_1.Config; } });
30
36
  // ===== ADVANCED FEATURES =====
31
- // Export utility functions for advanced use cases
37
+ // For power users and custom implementations
32
38
  var loader_1 = require("./loader");
33
39
  Object.defineProperty(exports, "loadProviders", { enumerable: true, get: function () { return loader_1.loadProviders; } });
34
40
  var concurrent_dns_1 = require("./concurrent-dns");
35
41
  Object.defineProperty(exports, "detectProviderConcurrent", { enumerable: true, get: function () { return concurrent_dns_1.detectProviderConcurrent; } });
42
+ var idn_1 = require("./idn");
43
+ Object.defineProperty(exports, "validateInternationalEmail", { enumerable: true, get: function () { return idn_1.validateInternationalEmail; } });
44
+ Object.defineProperty(exports, "emailToPunycode", { enumerable: true, get: function () { return idn_1.emailToPunycode; } });
45
+ Object.defineProperty(exports, "domainToPunycode", { enumerable: true, get: function () { return idn_1.domainToPunycode; } });
46
+ // ===== EMAIL VALIDATION =====
47
+ // Enhanced validation with international support
48
+ /**
49
+ * Enhanced email validation with comprehensive error reporting
50
+ *
51
+ * @param email - Email address to validate
52
+ * @returns Validation result with detailed error information
53
+ *
54
+ * @example
55
+ * ```typescript
56
+ * const result = validateEmailAddress('user@example.com');
57
+ * if (result.isValid) {
58
+ * console.log('Email is valid');
59
+ * } else {
60
+ * console.log('Error:', result.error.message);
61
+ * }
62
+ * ```
63
+ */
64
+ function validateEmailAddress(email) {
65
+ // Input validation
66
+ if (!email || typeof email !== 'string') {
67
+ return {
68
+ isValid: false,
69
+ error: {
70
+ type: 'INVALID_INPUT',
71
+ code: 'MISSING_EMAIL',
72
+ message: 'Email address is required and must be a string'
73
+ }
74
+ };
75
+ }
76
+ // Trim whitespace
77
+ const trimmedEmail = email.trim();
78
+ if (trimmedEmail.length === 0) {
79
+ return {
80
+ isValid: false,
81
+ error: {
82
+ type: 'INVALID_INPUT',
83
+ code: 'EMPTY_EMAIL',
84
+ message: 'Email address cannot be empty'
85
+ }
86
+ };
87
+ }
88
+ // Use international validation
89
+ const idnError = (0, idn_2.validateInternationalEmail)(trimmedEmail);
90
+ if (idnError) {
91
+ return {
92
+ isValid: false,
93
+ error: {
94
+ type: idnError.type,
95
+ code: idnError.code,
96
+ message: idnError.message
97
+ }
98
+ };
99
+ }
100
+ return {
101
+ isValid: true,
102
+ normalizedEmail: trimmedEmail.toLowerCase()
103
+ };
104
+ }
36
105
  // ===== UTILITY FUNCTIONS =====
37
106
  // Helper functions for common tasks
38
107
  const loader_2 = require("./loader");
39
108
  const api_2 = require("./api");
109
+ const concurrent_dns_2 = require("./concurrent-dns");
110
+ const idn_2 = require("./idn");
40
111
  /**
41
- * Get list of all supported email providers
42
- * @returns Array of all email providers in the database
112
+ * Get comprehensive list of all supported email providers
113
+ *
114
+ * @returns Array of all email providers with metadata
115
+ *
116
+ * @example
117
+ * ```typescript
118
+ * const providers = getSupportedProviders();
119
+ * console.log(`Supports ${providers.length} providers`);
120
+ *
121
+ * const gmailProvider = providers.find(p => p.domains.includes('gmail.com'));
122
+ * console.log(gmailProvider?.companyProvider); // "Gmail"
123
+ * ```
43
124
  */
44
125
  function getSupportedProviders() {
45
- const { providers } = (0, loader_2.loadProviders)();
46
- return [...providers]; // Return a copy to prevent external mutations
126
+ try {
127
+ const { providers } = (0, loader_2.loadProviders)();
128
+ return [...providers]; // Return defensive copy to prevent external mutations
129
+ }
130
+ catch (error) {
131
+ console.warn('Failed to load providers:', error);
132
+ return [];
133
+ }
47
134
  }
48
135
  /**
49
- * Check if an email provider is supported
136
+ * Check if an email provider is supported (synchronous)
137
+ *
50
138
  * @param email - Email address to check
51
139
  * @returns true if the provider is supported
140
+ *
141
+ * @example
142
+ * ```typescript
143
+ * if (isEmailProviderSupported('user@gmail.com')) {
144
+ * console.log('Gmail is supported');
145
+ * }
146
+ * ```
52
147
  */
53
148
  function isEmailProviderSupported(email) {
54
- const result = (0, api_2.getEmailProviderSync)(email);
55
- return result.provider !== null;
149
+ try {
150
+ if (!email || typeof email !== 'string') {
151
+ return false;
152
+ }
153
+ const result = (0, api_2.getEmailProviderSync)(email);
154
+ return result.provider !== null;
155
+ }
156
+ catch {
157
+ return false;
158
+ }
56
159
  }
57
160
  /**
58
- * Extract domain from email address
161
+ * Extract and normalize domain from email address
162
+ *
59
163
  * @param email - Email address
60
- * @returns Domain portion or null if invalid
164
+ * @returns Normalized domain portion or null if invalid
165
+ *
166
+ * @example
167
+ * ```typescript
168
+ * const domain = extractDomain('USER@GMAIL.COM');
169
+ * console.log(domain); // "gmail.com"
170
+ *
171
+ * const invalid = extractDomain('invalid-email');
172
+ * console.log(invalid); // null
173
+ * ```
61
174
  */
62
175
  function extractDomain(email) {
63
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
64
- if (!emailRegex.test(email)) {
176
+ try {
177
+ if (!email || typeof email !== 'string') {
178
+ return null;
179
+ }
180
+ const validation = validateEmailAddress(email);
181
+ if (!validation.isValid || !validation.normalizedEmail) {
182
+ return null;
183
+ }
184
+ const parts = validation.normalizedEmail.split('@');
185
+ return parts[1] || null;
186
+ }
187
+ catch {
65
188
  return null;
66
189
  }
67
- return email.split('@')[1]?.toLowerCase() || null;
68
190
  }
69
191
  /**
70
- * Validate email format
192
+ * Validate email format using enhanced rules
193
+ *
71
194
  * @param email - Email address to validate
72
195
  * @returns true if valid format
196
+ *
197
+ * @example
198
+ * ```typescript
199
+ * if (isValidEmail('user@example.com')) {
200
+ * console.log('Email format is valid');
201
+ * }
202
+ *
203
+ * if (isValidEmail('user@münchen.de')) {
204
+ * console.log('International domain is valid');
205
+ * }
206
+ * ```
73
207
  */
74
208
  function isValidEmail(email) {
75
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
76
- return emailRegex.test(email);
209
+ const validation = validateEmailAddress(email);
210
+ return validation.isValid;
211
+ }
212
+ /**
213
+ * Get library metadata and statistics
214
+ *
215
+ * @returns Object with current library statistics
216
+ *
217
+ * @example
218
+ * ```typescript
219
+ * const stats = getLibraryStats();
220
+ * console.log(`Supports ${stats.providerCount} providers across ${stats.domainCount} domains`);
221
+ * ```
222
+ */
223
+ function getLibraryStats() {
224
+ try {
225
+ const providers = getSupportedProviders();
226
+ const domainCount = providers.reduce((total, provider) => total + (provider.domains?.length || 0), 0);
227
+ return {
228
+ providerCount: providers.length,
229
+ domainCount,
230
+ version: '2.7.0',
231
+ supportsAsync: true,
232
+ supportsIDN: true,
233
+ supportsAliasDetection: true,
234
+ supportsConcurrentDNS: true
235
+ };
236
+ }
237
+ catch {
238
+ return {
239
+ providerCount: 0,
240
+ domainCount: 0,
241
+ version: '2.7.0',
242
+ supportsAsync: true,
243
+ supportsIDN: true,
244
+ supportsAliasDetection: true,
245
+ supportsConcurrentDNS: true
246
+ };
247
+ }
248
+ }
249
+ /**
250
+ * Batch process multiple email addresses efficiently
251
+ *
252
+ * @param emails - Array of email addresses to process
253
+ * @param options - Processing options
254
+ * @returns Array of results in the same order as input
255
+ *
256
+ * @example
257
+ * ```typescript
258
+ * const emails = ['user@gmail.com', 'test@yahoo.com', 'invalid-email'];
259
+ * const results = batchProcessEmails(emails);
260
+ *
261
+ * results.forEach((result, index) => {
262
+ * console.log(`${emails[index]}: ${result.isValid ? 'Valid' : 'Invalid'}`);
263
+ * });
264
+ * ```
265
+ */
266
+ function batchProcessEmails(emails, options = {}) {
267
+ const { includeProviderInfo = false, normalizeEmails = false, deduplicateAliases = false } = options;
268
+ const results = [];
269
+ const seenNormalized = new Set();
270
+ for (const email of emails) {
271
+ try {
272
+ const validation = validateEmailAddress(email);
273
+ const result = {
274
+ email,
275
+ isValid: validation.isValid
276
+ };
277
+ if (!validation.isValid) {
278
+ result.error = validation.error?.message;
279
+ results.push(result);
280
+ continue;
281
+ }
282
+ // Add normalized email if requested
283
+ if (normalizeEmails && validation.normalizedEmail) {
284
+ try {
285
+ result.normalized = (0, api_2.normalizeEmail)(validation.normalizedEmail);
286
+ }
287
+ catch {
288
+ result.normalized = validation.normalizedEmail;
289
+ }
290
+ }
291
+ // Check for duplicates if requested
292
+ if (deduplicateAliases && result.normalized) {
293
+ if (seenNormalized.has(result.normalized)) {
294
+ result.isDuplicate = true;
295
+ }
296
+ else {
297
+ seenNormalized.add(result.normalized);
298
+ }
299
+ }
300
+ // Add provider info if requested
301
+ if (includeProviderInfo && validation.normalizedEmail) {
302
+ try {
303
+ const providerResult = (0, api_2.getEmailProviderSync)(validation.normalizedEmail);
304
+ result.provider = providerResult.provider?.companyProvider || null;
305
+ result.loginUrl = providerResult.loginUrl;
306
+ }
307
+ catch {
308
+ result.provider = null;
309
+ }
310
+ }
311
+ results.push(result);
312
+ }
313
+ catch (error) {
314
+ results.push({
315
+ email,
316
+ isValid: false,
317
+ error: error instanceof Error ? error.message : 'Unknown error'
318
+ });
319
+ }
320
+ }
321
+ return results;
77
322
  }
323
+ // ===== LEGACY COMPATIBILITY =====
324
+ // Maintain backward compatibility
78
325
  /**
79
- * Library metadata
326
+ * @deprecated Use validateEmailAddress instead for better error handling
327
+ */
328
+ exports.isValidEmailAddress = isValidEmail;
329
+ /**
330
+ * Library metadata (legacy constants)
80
331
  */
81
332
  exports.PROVIDER_COUNT = 93;
82
333
  exports.DOMAIN_COUNT = 178;
83
334
  /**
84
335
  * Default export for convenience
336
+ *
337
+ * @example
338
+ * ```typescript
339
+ * import EmailProviderLinks from '@mikkelscheike/email-provider-links';
340
+ *
341
+ * const result = await EmailProviderLinks.getEmailProvider('user@gmail.com');
342
+ * ```
85
343
  */
86
344
  exports.default = {
345
+ // Core functions
87
346
  getEmailProvider: api_2.getEmailProvider,
88
347
  getEmailProviderSync: api_2.getEmailProviderSync,
89
348
  getEmailProviderFast: api_2.getEmailProviderFast,
349
+ // Validation
350
+ validateEmailAddress,
351
+ isValidEmail,
90
352
  normalizeEmail: api_2.normalizeEmail,
91
353
  emailsMatch: api_2.emailsMatch,
354
+ // Utilities
355
+ getSupportedProviders,
356
+ isEmailProviderSupported,
357
+ extractDomain,
358
+ getLibraryStats,
359
+ batchProcessEmails,
360
+ // Advanced
361
+ loadProviders: loader_2.loadProviders,
362
+ detectProviderConcurrent: concurrent_dns_2.detectProviderConcurrent,
363
+ validateInternationalEmail: idn_2.validateInternationalEmail,
364
+ // Constants
92
365
  Config: api_2.Config,
93
366
  PROVIDER_COUNT: exports.PROVIDER_COUNT,
94
367
  DOMAIN_COUNT: exports.DOMAIN_COUNT
95
368
  };
369
+ /**
370
+ * Version information
371
+ */
372
+ exports.VERSION = '2.7.0';
373
+ //# sourceMappingURL=index.js.map
package/dist/loader.d.ts CHANGED
@@ -42,3 +42,4 @@ export declare function loadProvidersDebug(): {
42
42
  stats: LoadingStats;
43
43
  };
44
44
  export {};
45
+ //# sourceMappingURL=loader.d.ts.map
package/dist/loader.js CHANGED
@@ -153,3 +153,4 @@ function loadProvidersDebug() {
153
153
  const domainMap = buildDomainMap(providers);
154
154
  return { providers, domainMap, stats };
155
155
  }
156
+ //# sourceMappingURL=loader.js.map
package/dist/schema.d.ts CHANGED
@@ -64,3 +64,4 @@ export declare function decompressTxtPattern(compressed: string): string;
64
64
  * Validation schema for providers
65
65
  */
66
66
  export declare function validateProvider(provider: Provider): string[];
67
+ //# sourceMappingURL=schema.d.ts.map
package/dist/schema.js CHANGED
@@ -71,3 +71,4 @@ function validateProvider(provider) {
71
71
  }
72
72
  return errors;
73
73
  }
74
+ //# sourceMappingURL=schema.js.map
@@ -46,3 +46,4 @@ declare const _default: {
46
46
  createSecurityMiddleware: typeof createSecurityMiddleware;
47
47
  };
48
48
  export default _default;
49
+ //# sourceMappingURL=secure-loader.d.ts.map
@@ -143,3 +143,4 @@ exports.default = {
143
143
  initializeSecurity,
144
144
  createSecurityMiddleware
145
145
  };
146
+ //# sourceMappingURL=secure-loader.js.map
@@ -45,3 +45,4 @@ export declare function auditProviderSecurity(providers: any[]): {
45
45
  }[];
46
46
  report: string;
47
47
  };
48
+ //# sourceMappingURL=url-validator.d.ts.map
@@ -292,3 +292,4 @@ function auditProviderSecurity(providers) {
292
292
  : `⚠️ ${invalid.length} provider(s) failed security validation`
293
293
  };
294
294
  }
295
+ //# sourceMappingURL=url-validator.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikkelscheike/email-provider-links",
3
- "version": "2.6.1",
3
+ "version": "2.7.1",
4
4
  "description": "TypeScript library for email provider detection with 93 providers (178 domains), concurrent DNS resolution, optimized performance, 91.75% test coverage, and enterprise security for login and password reset flows",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -11,11 +11,12 @@
11
11
  "!dist/**/*.map"
12
12
  ],
13
13
  "scripts": {
14
- "build": "tsc",
14
+ "verify-hashes": "tsx scripts/verify-hashes.ts",
15
+ "build": "tsx scripts/verify-hashes.ts && tsc",
15
16
  "test": "jest --silent",
16
17
  "test:watch": "jest --watch",
17
18
  "test:coverage": "jest --coverage",
18
- "prepublishOnly": "npm run build",
19
+ "prepublishOnly": "npm run verify-hashes && npm run build",
19
20
  "dev": "tsx src/index.ts",
20
21
  "sync-versions": "node scripts/sync-versions.js",
21
22
  "pretest": "node scripts/sync-versions.js",