@mikkelscheike/email-provider-links 5.1.0 → 5.1.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 +116 -13
- package/dist/api.d.ts +81 -18
- package/dist/api.js +172 -72
- package/dist/hash-verifier.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -100,41 +100,85 @@ Fully compatible with the latest Node.js 24.x and 25.x! The library is tested on
|
|
|
100
100
|
|
|
101
101
|
### Core Functions
|
|
102
102
|
|
|
103
|
-
#### `getEmailProvider(email,
|
|
103
|
+
#### `getEmailProvider(email, options?)`
|
|
104
104
|
**Recommended** - Complete provider detection with business domain support.
|
|
105
105
|
|
|
106
106
|
**✨ Automatic Email Normalization**: The returned `email` field is automatically normalized using provider-specific alias rules. For example, `user+tag@gmail.com` returns `user@gmail.com` in the result.
|
|
107
107
|
|
|
108
|
+
**📦 Simplified Response (Default)**: By default, returns only essential fields for frontend use. Use `{ extended: true }` to get full provider details including domains array and alias configuration.
|
|
109
|
+
|
|
108
110
|
Error notes:
|
|
109
111
|
- `INVALID_EMAIL` is returned for common malformed inputs (e.g. missing `@`, missing TLD).
|
|
110
112
|
- `IDN_VALIDATION_ERROR` is reserved for true encoding issues.
|
|
111
113
|
|
|
112
114
|
```typescript
|
|
113
|
-
//
|
|
115
|
+
// Default: Simplified response (recommended for frontend)
|
|
114
116
|
const result1 = await getEmailProvider('user@gmail.com');
|
|
115
|
-
// Returns: {
|
|
117
|
+
// Returns: {
|
|
118
|
+
// provider: { companyProvider: "Gmail", loginUrl: "https://mail.google.com/mail/", type: "public_provider" },
|
|
119
|
+
// email: "user@gmail.com",
|
|
120
|
+
// detectionMethod: "domain_match"
|
|
121
|
+
// }
|
|
116
122
|
|
|
117
123
|
// Email normalization is automatic
|
|
118
124
|
const result2 = await getEmailProvider('user+tag@gmail.com');
|
|
119
|
-
// Returns: {
|
|
125
|
+
// Returns: {
|
|
126
|
+
// provider: { companyProvider: "Gmail", loginUrl: "https://mail.google.com/mail/", type: "public_provider" },
|
|
127
|
+
// email: "user@gmail.com", // Normalized
|
|
128
|
+
// detectionMethod: "domain_match"
|
|
129
|
+
// }
|
|
130
|
+
|
|
131
|
+
// Extended response (includes domains, alias config, etc.)
|
|
132
|
+
const extended = await getEmailProvider('user@gmail.com', { extended: true });
|
|
133
|
+
// Returns: {
|
|
134
|
+
// provider: {
|
|
135
|
+
// companyProvider: "Gmail",
|
|
136
|
+
// loginUrl: "https://mail.google.com/mail/",
|
|
137
|
+
// domains: ["gmail.com", "googlemail.com"], // Only in extended
|
|
138
|
+
// alias: { dots: { ignore: true, strip: false }, ... }, // Only in extended
|
|
139
|
+
// type: "public_provider"
|
|
140
|
+
// },
|
|
141
|
+
// email: "user@gmail.com",
|
|
142
|
+
// loginUrl: "https://mail.google.com/mail/", // Top-level loginUrl only in extended
|
|
143
|
+
// detectionMethod: "domain_match"
|
|
144
|
+
// }
|
|
120
145
|
|
|
121
146
|
// Business domains (DNS lookup with timeout)
|
|
122
|
-
const result3 = await getEmailProvider('user@company.com', 2000);
|
|
123
|
-
// Returns: {
|
|
147
|
+
const result3 = await getEmailProvider('user@company.com', { timeout: 2000 });
|
|
148
|
+
// Returns: {
|
|
149
|
+
// provider: { companyProvider: "Google Workspace", loginUrl: "...", type: "custom_provider" },
|
|
150
|
+
// email: "user@company.com",
|
|
151
|
+
// detectionMethod: "mx_record"
|
|
152
|
+
// }
|
|
124
153
|
```
|
|
125
154
|
|
|
126
|
-
#### `getEmailProviderSync(email)`
|
|
155
|
+
#### `getEmailProviderSync(email, options?)`
|
|
127
156
|
**Fast** - Instant checks for known providers (no DNS lookup).
|
|
128
157
|
|
|
129
158
|
**✨ Automatic Email Normalization**: The returned `email` field is automatically normalized using provider-specific alias rules.
|
|
130
159
|
|
|
160
|
+
**📦 Simplified Response (Default)**: By default, returns only essential fields. Use `{ extended: true }` to get full provider details.
|
|
161
|
+
|
|
131
162
|
```typescript
|
|
163
|
+
// Default: Simplified response
|
|
132
164
|
const result = getEmailProviderSync('user@outlook.com');
|
|
133
|
-
// Returns: {
|
|
165
|
+
// Returns: {
|
|
166
|
+
// provider: { companyProvider: "Outlook", loginUrl: "https://outlook.live.com/", type: "public_provider" },
|
|
167
|
+
// email: "user@outlook.com",
|
|
168
|
+
// detectionMethod: "domain_match"
|
|
169
|
+
// }
|
|
134
170
|
|
|
135
171
|
// Email normalization is automatic
|
|
136
172
|
const result2 = getEmailProviderSync('u.s.e.r+tag@gmail.com');
|
|
137
|
-
// Returns: {
|
|
173
|
+
// Returns: {
|
|
174
|
+
// provider: { companyProvider: "Gmail", loginUrl: "https://mail.google.com/mail/", type: "public_provider" },
|
|
175
|
+
// email: "user@gmail.com", // Normalized
|
|
176
|
+
// detectionMethod: "domain_match"
|
|
177
|
+
// }
|
|
178
|
+
|
|
179
|
+
// Extended response (includes domains, alias config, etc.)
|
|
180
|
+
const extended = getEmailProviderSync('user@gmail.com', { extended: true });
|
|
181
|
+
// Returns full provider object with domains array and alias configuration
|
|
138
182
|
```
|
|
139
183
|
|
|
140
184
|
### Email Alias Support
|
|
@@ -171,24 +215,83 @@ async function handlePasswordReset(email: string) {
|
|
|
171
215
|
throw new Error(`Invalid email: ${validation.error?.message}`);
|
|
172
216
|
}
|
|
173
217
|
|
|
174
|
-
// Get provider information (
|
|
218
|
+
// Get provider information (default: simplified response)
|
|
219
|
+
// Email is automatically normalized in result
|
|
175
220
|
const result = await getEmailProvider(email);
|
|
176
221
|
|
|
177
222
|
return {
|
|
178
|
-
providerUrl: result.loginUrl,
|
|
223
|
+
providerUrl: result.provider?.loginUrl || null, // Access loginUrl from provider object
|
|
179
224
|
providerName: result.provider?.companyProvider || null,
|
|
180
225
|
normalizedEmail: result.email, // Already normalized (e.g., 'user@gmail.com' from 'user+tag@gmail.com')
|
|
181
226
|
isSupported: result.provider !== null,
|
|
182
227
|
detectionMethod: result.detectionMethod
|
|
183
228
|
};
|
|
184
229
|
}
|
|
230
|
+
|
|
231
|
+
// If you need full provider details (domains, alias config, etc.)
|
|
232
|
+
async function analyzeEmailProvider(email: string) {
|
|
233
|
+
const result = await getEmailProvider(email, { extended: true });
|
|
234
|
+
|
|
235
|
+
// Access full provider details
|
|
236
|
+
if (result.provider) {
|
|
237
|
+
console.log('All domains:', result.provider.domains);
|
|
238
|
+
console.log('Alias rules:', result.provider.alias);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return result;
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Response Formats
|
|
246
|
+
|
|
247
|
+
### Simplified Response (Default)
|
|
248
|
+
The default response includes only essential fields needed by most applications:
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
{
|
|
252
|
+
provider: {
|
|
253
|
+
companyProvider: "Gmail", // Provider name
|
|
254
|
+
loginUrl: "https://mail.google.com/mail/", // Login URL (access via provider.loginUrl)
|
|
255
|
+
type: "public_provider" // Provider type
|
|
256
|
+
},
|
|
257
|
+
email: "user@gmail.com", // Normalized email
|
|
258
|
+
detectionMethod: "domain_match" // How provider was detected
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Extended Response
|
|
263
|
+
Use `{ extended: true }` to get full provider details including internal metadata:
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
{
|
|
267
|
+
provider: {
|
|
268
|
+
companyProvider: "Gmail",
|
|
269
|
+
loginUrl: "https://mail.google.com/mail/",
|
|
270
|
+
domains: ["gmail.com", "googlemail.com"], // All domains for this provider
|
|
271
|
+
alias: { // Alias handling configuration
|
|
272
|
+
dots: { ignore: true, strip: false },
|
|
273
|
+
plus: { ignore: true, strip: true },
|
|
274
|
+
case: { ignore: true, strip: true }
|
|
275
|
+
},
|
|
276
|
+
type: "public_provider",
|
|
277
|
+
customDomainDetection: { ... } // DNS detection patterns
|
|
278
|
+
},
|
|
279
|
+
email: "user@gmail.com",
|
|
280
|
+
loginUrl: "https://mail.google.com/mail/",
|
|
281
|
+
detectionMethod: "domain_match"
|
|
282
|
+
}
|
|
185
283
|
```
|
|
186
284
|
|
|
285
|
+
**When to use Extended**: Only use `{ extended: true }` if you need access to the `domains` array or `alias` configuration for custom email processing logic. For most frontend use cases, the default simplified response is sufficient and more efficient.
|
|
286
|
+
|
|
187
287
|
## Configuration
|
|
188
288
|
|
|
189
289
|
```typescript
|
|
190
290
|
// Custom DNS timeout (default: 5000ms)
|
|
191
|
-
const result = await getEmailProvider(email, 2000);
|
|
291
|
+
const result = await getEmailProvider(email, { timeout: 2000 });
|
|
292
|
+
|
|
293
|
+
// Extended response with custom timeout
|
|
294
|
+
const extended = await getEmailProvider(email, { timeout: 2000, extended: true });
|
|
192
295
|
|
|
193
296
|
// Rate limiting configuration
|
|
194
297
|
import { Config } from '@mikkelscheike/email-provider-links';
|
|
@@ -215,7 +318,7 @@ console.log(`Total providers: ${providers.length}`);
|
|
|
215
318
|
|
|
216
319
|
### Email Alias Detection & Normalization
|
|
217
320
|
|
|
218
|
-
**✨ Note**: `getEmailProvider()`, `getEmailProviderSync()`, and `getEmailProviderFast()` automatically normalize emails in their results. You can use `normalizeEmail()` directly when you only need normalization without provider detection.
|
|
321
|
+
**✨ Note**: `getEmailProvider()`, `getEmailProviderSync()`, and `getEmailProviderFast()` automatically normalize emails in their results and return simplified responses by default (only essential fields). Use `{ extended: true }` to get full provider details. You can use `normalizeEmail()` directly when you only need normalization without provider detection.
|
|
219
322
|
|
|
220
323
|
```typescript
|
|
221
324
|
import {
|
package/dist/api.d.ts
CHANGED
|
@@ -30,7 +30,21 @@ export interface EmailProvider {
|
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
33
|
+
* Simplified provider information for frontend use
|
|
34
|
+
* Contains only essential fields needed by consumers
|
|
35
|
+
*/
|
|
36
|
+
export interface SimplifiedProvider {
|
|
37
|
+
/** The provider name (e.g., "Gmail", "ProtonMail") */
|
|
38
|
+
companyProvider: string;
|
|
39
|
+
/** Direct URL to the email provider's login page */
|
|
40
|
+
loginUrl: string | null;
|
|
41
|
+
/** Provider type for UI differentiation */
|
|
42
|
+
type: ProviderType;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Extended result interface with full provider details
|
|
46
|
+
* Includes internal implementation details like domains array and alias configuration.
|
|
47
|
+
* Use this when you need access to all provider metadata.
|
|
34
48
|
*/
|
|
35
49
|
export interface EmailProviderResult {
|
|
36
50
|
/** The detected email provider, or null if not found */
|
|
@@ -51,6 +65,26 @@ export interface EmailProviderResult {
|
|
|
51
65
|
idnError?: string;
|
|
52
66
|
};
|
|
53
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Standard result interface (default)
|
|
70
|
+
* Contains only essential information needed by consumers.
|
|
71
|
+
* This is the default response format for all API functions.
|
|
72
|
+
*/
|
|
73
|
+
export interface SimplifiedEmailProviderResult {
|
|
74
|
+
/** The detected email provider (simplified), or null if not found */
|
|
75
|
+
provider: SimplifiedProvider | null;
|
|
76
|
+
/** The normalized email address */
|
|
77
|
+
email: string;
|
|
78
|
+
/** Method used to detect the provider */
|
|
79
|
+
detectionMethod?: 'domain_match' | 'mx_record' | 'txt_record' | 'both' | 'proxy_detected';
|
|
80
|
+
/** Error information if detection failed */
|
|
81
|
+
error?: {
|
|
82
|
+
type: 'INVALID_EMAIL' | 'DNS_TIMEOUT' | 'RATE_LIMITED' | 'UNKNOWN_DOMAIN' | 'NETWORK_ERROR' | 'IDN_VALIDATION_ERROR';
|
|
83
|
+
message: string;
|
|
84
|
+
retryAfter?: number;
|
|
85
|
+
idnError?: string;
|
|
86
|
+
};
|
|
87
|
+
}
|
|
54
88
|
/**
|
|
55
89
|
* Get email provider information for any email address.
|
|
56
90
|
*
|
|
@@ -59,16 +93,22 @@ export interface EmailProviderResult {
|
|
|
59
93
|
* - Business domains (mycompany.com using Google Workspace, etc.)
|
|
60
94
|
* - Unknown providers (graceful fallback)
|
|
61
95
|
*
|
|
96
|
+
* By default, returns a simplified response with only essential fields.
|
|
97
|
+
* Use the `extended` option to get full provider details including domains and alias configuration.
|
|
98
|
+
*
|
|
62
99
|
* @param email - The email address to analyze
|
|
63
|
-
* @param
|
|
64
|
-
* @returns Promise resolving to
|
|
100
|
+
* @param options - Optional configuration: timeout for DNS queries (default: 5000ms) and extended response flag
|
|
101
|
+
* @returns Promise resolving to SimplifiedEmailProviderResult (default) or EmailProviderResult (if extended)
|
|
65
102
|
*
|
|
66
103
|
* @example
|
|
67
104
|
* ```typescript
|
|
68
|
-
* //
|
|
69
|
-
* const result = await getEmailProvider('
|
|
70
|
-
*
|
|
71
|
-
*
|
|
105
|
+
* // Default: Simplified response (recommended for frontend)
|
|
106
|
+
* const result = await getEmailProvider('user@gmail.com');
|
|
107
|
+
* // Returns: { provider: { companyProvider, loginUrl, type }, email, loginUrl, detectionMethod }
|
|
108
|
+
*
|
|
109
|
+
* // Extended response (includes domains, alias config, etc.)
|
|
110
|
+
* const extended = await getEmailProvider('user@gmail.com', { extended: true });
|
|
111
|
+
* // Returns: { provider: { companyProvider, loginUrl, domains, alias, type, ... }, ... }
|
|
72
112
|
*
|
|
73
113
|
* // Business domain
|
|
74
114
|
* const business = await getEmailProvider('local@business.tld');
|
|
@@ -81,21 +121,32 @@ export interface EmailProviderResult {
|
|
|
81
121
|
* console.log(invalid.error?.message); // "Invalid email format"
|
|
82
122
|
* ```
|
|
83
123
|
*/
|
|
84
|
-
export declare function getEmailProvider(email: string,
|
|
124
|
+
export declare function getEmailProvider(email: string, options?: number | {
|
|
125
|
+
timeout?: number;
|
|
126
|
+
extended?: boolean;
|
|
127
|
+
}): Promise<SimplifiedEmailProviderResult | EmailProviderResult>;
|
|
85
128
|
/**
|
|
86
129
|
* Get email provider information synchronously (no DNS lookup).
|
|
87
130
|
*
|
|
88
131
|
* This function only checks predefined domains and returns immediately.
|
|
89
132
|
* Use this when you can't use async functions or don't want DNS lookups.
|
|
90
133
|
*
|
|
134
|
+
* By default, returns a simplified response with only essential fields.
|
|
135
|
+
* Use the `extended` option to get full provider details including domains and alias configuration.
|
|
136
|
+
*
|
|
91
137
|
* @param email - The email address to analyze
|
|
92
|
-
* @
|
|
138
|
+
* @param options - Optional configuration: extended response flag
|
|
139
|
+
* @returns SimplifiedEmailProviderResult (default) or EmailProviderResult (if extended) with provider info (limited to known domains)
|
|
93
140
|
*
|
|
94
141
|
* @example
|
|
95
142
|
* ```typescript
|
|
96
|
-
* //
|
|
143
|
+
* // Default: Simplified response (recommended for frontend)
|
|
97
144
|
* const gmail = getEmailProviderSync('user@gmail.com');
|
|
98
|
-
*
|
|
145
|
+
* // Returns: { provider: { companyProvider, loginUrl, type }, email, loginUrl }
|
|
146
|
+
*
|
|
147
|
+
* // Extended response (includes domains, alias config, etc.)
|
|
148
|
+
* const extended = getEmailProviderSync('user@gmail.com', { extended: true });
|
|
149
|
+
* // Returns: { provider: { companyProvider, loginUrl, domains, alias, type, ... }, ... }
|
|
99
150
|
*
|
|
100
151
|
* // Unknown domains return null
|
|
101
152
|
* const unknown = getEmailProviderSync('user@mycompany.com');
|
|
@@ -103,34 +154,46 @@ export declare function getEmailProvider(email: string, timeout?: number): Promi
|
|
|
103
154
|
* console.log(unknown.error?.type); // "UNKNOWN_DOMAIN"
|
|
104
155
|
* ```
|
|
105
156
|
*/
|
|
106
|
-
export declare function getEmailProviderSync(email: string
|
|
157
|
+
export declare function getEmailProviderSync(email: string, options?: {
|
|
158
|
+
extended?: boolean;
|
|
159
|
+
}): SimplifiedEmailProviderResult | EmailProviderResult;
|
|
107
160
|
export { normalizeEmail, emailsMatch } from './alias-detection';
|
|
108
161
|
/**
|
|
109
162
|
* Enhanced email provider detection with concurrent DNS for maximum performance.
|
|
110
163
|
* This function uses parallel MX/TXT lookups for 2x faster business domain detection.
|
|
111
164
|
*
|
|
165
|
+
* By default, returns a simplified response with only essential fields.
|
|
166
|
+
* Use the `extended` option to get full provider details including domains and alias configuration.
|
|
167
|
+
*
|
|
112
168
|
* @param email - The email address to analyze
|
|
113
169
|
* @param options - Configuration options for DNS detection
|
|
114
|
-
* @returns Promise resolving to EmailProviderResult with enhanced performance data
|
|
170
|
+
* @returns Promise resolving to SimplifiedEmailProviderResult (default) or EmailProviderResult (if extended) with enhanced performance data
|
|
115
171
|
*
|
|
116
172
|
* @example
|
|
117
173
|
* ```typescript
|
|
118
|
-
* //
|
|
174
|
+
* // Default: Simplified response with performance data
|
|
119
175
|
* const result = await getEmailProviderFast('user@mycompany.com', {
|
|
120
176
|
* enableParallel: true,
|
|
121
177
|
* collectDebugInfo: true
|
|
122
178
|
* });
|
|
179
|
+
* // Returns: { provider: { companyProvider, loginUrl, type }, email, loginUrl, detectionMethod, timing, confidence }
|
|
123
180
|
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
181
|
+
* // Extended response (includes domains, alias config, etc.)
|
|
182
|
+
* const extended = await getEmailProviderFast('user@mycompany.com', {
|
|
183
|
+
* enableParallel: true,
|
|
184
|
+
* extended: true
|
|
185
|
+
* });
|
|
186
|
+
* console.log(extended.provider?.companyProvider); // "Google Workspace"
|
|
187
|
+
* console.log(extended.detectionMethod); // "mx_record"
|
|
188
|
+
* console.log(extended.timing); // { mx: 120, txt: 95, total: 125 }
|
|
127
189
|
* ```
|
|
128
190
|
*/
|
|
129
191
|
export declare function getEmailProviderFast(email: string, options?: {
|
|
130
192
|
timeout?: number;
|
|
131
193
|
enableParallel?: boolean;
|
|
132
194
|
collectDebugInfo?: boolean;
|
|
133
|
-
|
|
195
|
+
extended?: boolean;
|
|
196
|
+
}): Promise<(SimplifiedEmailProviderResult | EmailProviderResult) & {
|
|
134
197
|
timing?: {
|
|
135
198
|
mx: number;
|
|
136
199
|
txt: number;
|
package/dist/api.js
CHANGED
|
@@ -81,6 +81,18 @@ function validateAndParseEmailForLookup(email) {
|
|
|
81
81
|
const domain = (0, idn_1.domainToPunycode)(domainRaw);
|
|
82
82
|
return { ok: true, trimmedEmail, domain };
|
|
83
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Convert a full EmailProvider to a simplified version
|
|
86
|
+
*/
|
|
87
|
+
function simplifyProvider(provider) {
|
|
88
|
+
if (!provider)
|
|
89
|
+
return null;
|
|
90
|
+
return {
|
|
91
|
+
companyProvider: provider.companyProvider,
|
|
92
|
+
loginUrl: provider.loginUrl,
|
|
93
|
+
type: provider.type
|
|
94
|
+
};
|
|
95
|
+
}
|
|
84
96
|
/**
|
|
85
97
|
* Get email provider information for any email address.
|
|
86
98
|
*
|
|
@@ -89,16 +101,22 @@ function validateAndParseEmailForLookup(email) {
|
|
|
89
101
|
* - Business domains (mycompany.com using Google Workspace, etc.)
|
|
90
102
|
* - Unknown providers (graceful fallback)
|
|
91
103
|
*
|
|
104
|
+
* By default, returns a simplified response with only essential fields.
|
|
105
|
+
* Use the `extended` option to get full provider details including domains and alias configuration.
|
|
106
|
+
*
|
|
92
107
|
* @param email - The email address to analyze
|
|
93
|
-
* @param
|
|
94
|
-
* @returns Promise resolving to
|
|
108
|
+
* @param options - Optional configuration: timeout for DNS queries (default: 5000ms) and extended response flag
|
|
109
|
+
* @returns Promise resolving to SimplifiedEmailProviderResult (default) or EmailProviderResult (if extended)
|
|
95
110
|
*
|
|
96
111
|
* @example
|
|
97
112
|
* ```typescript
|
|
98
|
-
* //
|
|
99
|
-
* const result = await getEmailProvider('
|
|
100
|
-
*
|
|
101
|
-
*
|
|
113
|
+
* // Default: Simplified response (recommended for frontend)
|
|
114
|
+
* const result = await getEmailProvider('user@gmail.com');
|
|
115
|
+
* // Returns: { provider: { companyProvider, loginUrl, type }, email, loginUrl, detectionMethod }
|
|
116
|
+
*
|
|
117
|
+
* // Extended response (includes domains, alias config, etc.)
|
|
118
|
+
* const extended = await getEmailProvider('user@gmail.com', { extended: true });
|
|
119
|
+
* // Returns: { provider: { companyProvider, loginUrl, domains, alias, type, ... }, ... }
|
|
102
120
|
*
|
|
103
121
|
* // Business domain
|
|
104
122
|
* const business = await getEmailProvider('local@business.tld');
|
|
@@ -111,7 +129,10 @@ function validateAndParseEmailForLookup(email) {
|
|
|
111
129
|
* console.log(invalid.error?.message); // "Invalid email format"
|
|
112
130
|
* ```
|
|
113
131
|
*/
|
|
114
|
-
async function getEmailProvider(email,
|
|
132
|
+
async function getEmailProvider(email, options) {
|
|
133
|
+
// Parse options - support both legacy (number) and new (object) format
|
|
134
|
+
const timeout = typeof options === 'number' ? options : options?.timeout;
|
|
135
|
+
const extended = typeof options === 'object' && options?.extended === true;
|
|
115
136
|
try {
|
|
116
137
|
const parsed = validateAndParseEmailForLookup(email);
|
|
117
138
|
if (!parsed.ok) {
|
|
@@ -123,16 +144,17 @@ async function getEmailProvider(email, timeout) {
|
|
|
123
144
|
catch {
|
|
124
145
|
// If normalization fails, use original email
|
|
125
146
|
}
|
|
126
|
-
|
|
147
|
+
const errorResult = {
|
|
127
148
|
provider: null,
|
|
128
149
|
email: normalizedEmail,
|
|
129
|
-
loginUrl: null,
|
|
150
|
+
...(extended ? { loginUrl: null } : {}),
|
|
130
151
|
error: parsed.error
|
|
131
152
|
};
|
|
153
|
+
return extended ? errorResult : errorResult;
|
|
132
154
|
}
|
|
133
155
|
const domain = parsed.domain;
|
|
134
156
|
// First try synchronous domain matching
|
|
135
|
-
const syncResult = getEmailProviderSync(email);
|
|
157
|
+
const syncResult = getEmailProviderSync(email, { extended });
|
|
136
158
|
if (syncResult.provider) {
|
|
137
159
|
// Email is already normalized in getEmailProviderSync
|
|
138
160
|
return {
|
|
@@ -143,15 +165,16 @@ async function getEmailProvider(email, timeout) {
|
|
|
143
165
|
// Fall back to DNS detection for business domains
|
|
144
166
|
const loadResult = (0, provider_loader_1.loadProviders)();
|
|
145
167
|
if (!loadResult.success) {
|
|
146
|
-
|
|
168
|
+
const errorResult = {
|
|
147
169
|
provider: null,
|
|
148
170
|
email,
|
|
149
|
-
loginUrl: null,
|
|
171
|
+
...(extended ? { loginUrl: null } : {}),
|
|
150
172
|
error: {
|
|
151
173
|
type: 'NETWORK_ERROR',
|
|
152
174
|
message: 'Service temporarily unavailable'
|
|
153
175
|
}
|
|
154
176
|
};
|
|
177
|
+
return extended ? errorResult : errorResult;
|
|
155
178
|
}
|
|
156
179
|
const providers = loadResult.providers;
|
|
157
180
|
const concurrentResult = await (0, concurrent_dns_1.detectProviderConcurrent)(domain, providers, {
|
|
@@ -168,17 +191,33 @@ async function getEmailProvider(email, timeout) {
|
|
|
168
191
|
catch {
|
|
169
192
|
// If normalization fails, use original email
|
|
170
193
|
}
|
|
194
|
+
if (extended) {
|
|
195
|
+
const result = {
|
|
196
|
+
provider: concurrentResult.provider,
|
|
197
|
+
email: normalizedEmail,
|
|
198
|
+
loginUrl: concurrentResult.provider?.loginUrl || null,
|
|
199
|
+
detectionMethod: concurrentResult.detectionMethod || 'mx_record'
|
|
200
|
+
};
|
|
201
|
+
if (concurrentResult.proxyService) {
|
|
202
|
+
result.proxyService = concurrentResult.proxyService;
|
|
203
|
+
}
|
|
204
|
+
// Add error context for null results
|
|
205
|
+
if (!result.provider && !result.proxyService) {
|
|
206
|
+
result.error = {
|
|
207
|
+
type: 'UNKNOWN_DOMAIN',
|
|
208
|
+
message: `No email provider found for domain: ${domain}`
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
return result;
|
|
212
|
+
}
|
|
213
|
+
// Default: simplified response
|
|
171
214
|
const result = {
|
|
172
|
-
provider: concurrentResult.provider,
|
|
215
|
+
provider: simplifyProvider(concurrentResult.provider),
|
|
173
216
|
email: normalizedEmail,
|
|
174
|
-
loginUrl: concurrentResult.provider?.loginUrl || null,
|
|
175
217
|
detectionMethod: concurrentResult.detectionMethod || 'mx_record'
|
|
176
218
|
};
|
|
177
|
-
if (concurrentResult.proxyService) {
|
|
178
|
-
result.proxyService = concurrentResult.proxyService;
|
|
179
|
-
}
|
|
180
219
|
// Add error context for null results
|
|
181
|
-
if (!result.provider
|
|
220
|
+
if (!result.provider) {
|
|
182
221
|
result.error = {
|
|
183
222
|
type: 'UNKNOWN_DOMAIN',
|
|
184
223
|
message: `No email provider found for domain: ${domain}`
|
|
@@ -188,40 +227,36 @@ async function getEmailProvider(email, timeout) {
|
|
|
188
227
|
}
|
|
189
228
|
catch (error) {
|
|
190
229
|
// Enhanced error handling
|
|
230
|
+
const errorResult = {
|
|
231
|
+
provider: null,
|
|
232
|
+
email,
|
|
233
|
+
error: {}
|
|
234
|
+
};
|
|
235
|
+
if (extended) {
|
|
236
|
+
errorResult.loginUrl = null;
|
|
237
|
+
}
|
|
191
238
|
if (error instanceof Error && error.message.includes('Rate limit exceeded')) {
|
|
192
239
|
const retryMatch = error.message.match(/Try again in (\d+) seconds/);
|
|
193
240
|
const retryAfter = retryMatch?.[1] ? parseInt(retryMatch[1], 10) : undefined;
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
error: {
|
|
199
|
-
type: 'RATE_LIMITED',
|
|
200
|
-
message: 'DNS query rate limit exceeded',
|
|
201
|
-
...(retryAfter !== undefined ? { retryAfter } : {})
|
|
202
|
-
}
|
|
241
|
+
errorResult.error = {
|
|
242
|
+
type: 'RATE_LIMITED',
|
|
243
|
+
message: 'DNS query rate limit exceeded',
|
|
244
|
+
...(retryAfter !== undefined ? { retryAfter } : {})
|
|
203
245
|
};
|
|
246
|
+
return extended ? errorResult : errorResult;
|
|
204
247
|
}
|
|
205
248
|
if (error instanceof Error && error.message.includes('timeout')) {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
loginUrl: null,
|
|
210
|
-
error: {
|
|
211
|
-
type: 'DNS_TIMEOUT',
|
|
212
|
-
message: `DNS lookup timed out after ${timeout || 5000}ms`
|
|
213
|
-
}
|
|
249
|
+
errorResult.error = {
|
|
250
|
+
type: 'DNS_TIMEOUT',
|
|
251
|
+
message: `DNS lookup timed out after ${timeout || 5000}ms`
|
|
214
252
|
};
|
|
253
|
+
return extended ? errorResult : errorResult;
|
|
215
254
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
loginUrl: null,
|
|
220
|
-
error: {
|
|
221
|
-
type: 'NETWORK_ERROR',
|
|
222
|
-
message: error instanceof Error ? error.message : 'Unknown network error'
|
|
223
|
-
}
|
|
255
|
+
errorResult.error = {
|
|
256
|
+
type: 'NETWORK_ERROR',
|
|
257
|
+
message: error instanceof Error ? error.message : 'Unknown network error'
|
|
224
258
|
};
|
|
259
|
+
return extended ? errorResult : errorResult;
|
|
225
260
|
}
|
|
226
261
|
}
|
|
227
262
|
/**
|
|
@@ -230,14 +265,22 @@ async function getEmailProvider(email, timeout) {
|
|
|
230
265
|
* This function only checks predefined domains and returns immediately.
|
|
231
266
|
* Use this when you can't use async functions or don't want DNS lookups.
|
|
232
267
|
*
|
|
268
|
+
* By default, returns a simplified response with only essential fields.
|
|
269
|
+
* Use the `extended` option to get full provider details including domains and alias configuration.
|
|
270
|
+
*
|
|
233
271
|
* @param email - The email address to analyze
|
|
234
|
-
* @
|
|
272
|
+
* @param options - Optional configuration: extended response flag
|
|
273
|
+
* @returns SimplifiedEmailProviderResult (default) or EmailProviderResult (if extended) with provider info (limited to known domains)
|
|
235
274
|
*
|
|
236
275
|
* @example
|
|
237
276
|
* ```typescript
|
|
238
|
-
* //
|
|
277
|
+
* // Default: Simplified response (recommended for frontend)
|
|
239
278
|
* const gmail = getEmailProviderSync('user@gmail.com');
|
|
240
|
-
*
|
|
279
|
+
* // Returns: { provider: { companyProvider, loginUrl, type }, email, loginUrl }
|
|
280
|
+
*
|
|
281
|
+
* // Extended response (includes domains, alias config, etc.)
|
|
282
|
+
* const extended = getEmailProviderSync('user@gmail.com', { extended: true });
|
|
283
|
+
* // Returns: { provider: { companyProvider, loginUrl, domains, alias, type, ... }, ... }
|
|
241
284
|
*
|
|
242
285
|
* // Unknown domains return null
|
|
243
286
|
* const unknown = getEmailProviderSync('user@mycompany.com');
|
|
@@ -245,7 +288,8 @@ async function getEmailProvider(email, timeout) {
|
|
|
245
288
|
* console.log(unknown.error?.type); // "UNKNOWN_DOMAIN"
|
|
246
289
|
* ```
|
|
247
290
|
*/
|
|
248
|
-
function getEmailProviderSync(email) {
|
|
291
|
+
function getEmailProviderSync(email, options) {
|
|
292
|
+
const extended = options?.extended === true;
|
|
249
293
|
try {
|
|
250
294
|
const parsed = validateAndParseEmailForLookup(email);
|
|
251
295
|
if (!parsed.ok) {
|
|
@@ -257,12 +301,15 @@ function getEmailProviderSync(email) {
|
|
|
257
301
|
catch {
|
|
258
302
|
// If normalization fails, use original email
|
|
259
303
|
}
|
|
260
|
-
|
|
304
|
+
const errorResult = {
|
|
261
305
|
provider: null,
|
|
262
306
|
email: normalizedEmail,
|
|
263
|
-
loginUrl: null,
|
|
264
307
|
error: parsed.error
|
|
265
308
|
};
|
|
309
|
+
if (extended) {
|
|
310
|
+
errorResult.loginUrl = null;
|
|
311
|
+
}
|
|
312
|
+
return extended ? errorResult : errorResult;
|
|
266
313
|
}
|
|
267
314
|
const domain = parsed.domain;
|
|
268
315
|
// Load providers with verification
|
|
@@ -274,15 +321,18 @@ function getEmailProviderSync(email) {
|
|
|
274
321
|
if (process.env.NODE_ENV !== 'test' && !process.env.JEST_WORKER_ID) {
|
|
275
322
|
console.error('🚨 Provider lookup blocked due to validation failure');
|
|
276
323
|
}
|
|
277
|
-
|
|
324
|
+
const errorResult = {
|
|
278
325
|
provider: null,
|
|
279
326
|
email,
|
|
280
|
-
loginUrl: null,
|
|
281
327
|
error: {
|
|
282
328
|
type: 'NETWORK_ERROR',
|
|
283
329
|
message: 'Service temporarily unavailable'
|
|
284
330
|
}
|
|
285
331
|
};
|
|
332
|
+
if (extended) {
|
|
333
|
+
errorResult.loginUrl = null;
|
|
334
|
+
}
|
|
335
|
+
return extended ? errorResult : errorResult;
|
|
286
336
|
}
|
|
287
337
|
const domainMap = getDomainMapFromProviders(result.providers);
|
|
288
338
|
provider = domainMap.get(domain) || null;
|
|
@@ -291,15 +341,18 @@ function getEmailProviderSync(email) {
|
|
|
291
341
|
if (process.env.NODE_ENV !== 'test' && !process.env.JEST_WORKER_ID) {
|
|
292
342
|
console.error('🚨 Provider lookup failed:', error);
|
|
293
343
|
}
|
|
294
|
-
|
|
344
|
+
const errorResult = {
|
|
295
345
|
provider: null,
|
|
296
346
|
email,
|
|
297
|
-
loginUrl: null,
|
|
298
347
|
error: {
|
|
299
348
|
type: 'NETWORK_ERROR',
|
|
300
349
|
message: 'Service temporarily unavailable'
|
|
301
350
|
}
|
|
302
351
|
};
|
|
352
|
+
if (extended) {
|
|
353
|
+
errorResult.loginUrl = null;
|
|
354
|
+
}
|
|
355
|
+
return extended ? errorResult : errorResult;
|
|
303
356
|
}
|
|
304
357
|
// Normalize email using alias detection (even if no provider found)
|
|
305
358
|
// This ensures consistent email format regardless of provider detection result
|
|
@@ -310,10 +363,26 @@ function getEmailProviderSync(email) {
|
|
|
310
363
|
catch {
|
|
311
364
|
// If normalization fails, use original email
|
|
312
365
|
}
|
|
366
|
+
if (extended) {
|
|
367
|
+
const result = {
|
|
368
|
+
provider: provider || null,
|
|
369
|
+
email: normalizedEmail,
|
|
370
|
+
loginUrl: provider?.loginUrl || null,
|
|
371
|
+
detectionMethod: 'domain_match'
|
|
372
|
+
};
|
|
373
|
+
// Add error context for null results
|
|
374
|
+
if (!result.provider) {
|
|
375
|
+
result.error = {
|
|
376
|
+
type: 'UNKNOWN_DOMAIN',
|
|
377
|
+
message: `No email provider found for domain: ${domain} (sync mode - business domains not supported)`
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
return result;
|
|
381
|
+
}
|
|
382
|
+
// Default: simplified response
|
|
313
383
|
const result = {
|
|
314
|
-
provider: provider
|
|
384
|
+
provider: simplifyProvider(provider),
|
|
315
385
|
email: normalizedEmail,
|
|
316
|
-
loginUrl: provider?.loginUrl || null,
|
|
317
386
|
detectionMethod: 'domain_match'
|
|
318
387
|
};
|
|
319
388
|
// Add error context for null results
|
|
@@ -326,15 +395,18 @@ function getEmailProviderSync(email) {
|
|
|
326
395
|
return result;
|
|
327
396
|
}
|
|
328
397
|
catch (error) {
|
|
329
|
-
|
|
398
|
+
const errorResult = {
|
|
330
399
|
provider: null,
|
|
331
400
|
email,
|
|
332
|
-
loginUrl: null,
|
|
333
401
|
error: {
|
|
334
402
|
type: 'INVALID_EMAIL',
|
|
335
403
|
message: error instanceof Error ? error.message : 'Invalid email address'
|
|
336
404
|
}
|
|
337
405
|
};
|
|
406
|
+
if (extended) {
|
|
407
|
+
errorResult.loginUrl = null;
|
|
408
|
+
}
|
|
409
|
+
return extended ? errorResult : errorResult;
|
|
338
410
|
}
|
|
339
411
|
}
|
|
340
412
|
// Re-export alias detection functions from the dedicated module
|
|
@@ -345,25 +417,34 @@ Object.defineProperty(exports, "emailsMatch", { enumerable: true, get: function
|
|
|
345
417
|
* Enhanced email provider detection with concurrent DNS for maximum performance.
|
|
346
418
|
* This function uses parallel MX/TXT lookups for 2x faster business domain detection.
|
|
347
419
|
*
|
|
420
|
+
* By default, returns a simplified response with only essential fields.
|
|
421
|
+
* Use the `extended` option to get full provider details including domains and alias configuration.
|
|
422
|
+
*
|
|
348
423
|
* @param email - The email address to analyze
|
|
349
424
|
* @param options - Configuration options for DNS detection
|
|
350
|
-
* @returns Promise resolving to EmailProviderResult with enhanced performance data
|
|
425
|
+
* @returns Promise resolving to SimplifiedEmailProviderResult (default) or EmailProviderResult (if extended) with enhanced performance data
|
|
351
426
|
*
|
|
352
427
|
* @example
|
|
353
428
|
* ```typescript
|
|
354
|
-
* //
|
|
429
|
+
* // Default: Simplified response with performance data
|
|
355
430
|
* const result = await getEmailProviderFast('user@mycompany.com', {
|
|
356
431
|
* enableParallel: true,
|
|
357
432
|
* collectDebugInfo: true
|
|
358
433
|
* });
|
|
434
|
+
* // Returns: { provider: { companyProvider, loginUrl, type }, email, loginUrl, detectionMethod, timing, confidence }
|
|
359
435
|
*
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
436
|
+
* // Extended response (includes domains, alias config, etc.)
|
|
437
|
+
* const extended = await getEmailProviderFast('user@mycompany.com', {
|
|
438
|
+
* enableParallel: true,
|
|
439
|
+
* extended: true
|
|
440
|
+
* });
|
|
441
|
+
* console.log(extended.provider?.companyProvider); // "Google Workspace"
|
|
442
|
+
* console.log(extended.detectionMethod); // "mx_record"
|
|
443
|
+
* console.log(extended.timing); // { mx: 120, txt: 95, total: 125 }
|
|
363
444
|
* ```
|
|
364
445
|
*/
|
|
365
446
|
async function getEmailProviderFast(email, options = {}) {
|
|
366
|
-
const { timeout = 5000, enableParallel = true, collectDebugInfo = false } = options;
|
|
447
|
+
const { timeout = 5000, enableParallel = true, collectDebugInfo = false, extended = false } = options;
|
|
367
448
|
try {
|
|
368
449
|
const parsed = validateAndParseEmailForLookup(email);
|
|
369
450
|
if (!parsed.ok) {
|
|
@@ -377,7 +458,7 @@ async function getEmailProviderFast(email, options = {}) {
|
|
|
377
458
|
const domain = parsed.domain;
|
|
378
459
|
const trimmedEmail = parsed.trimmedEmail;
|
|
379
460
|
// First try standard domain matching (fast path)
|
|
380
|
-
const syncResult = getEmailProviderSync(trimmedEmail);
|
|
461
|
+
const syncResult = getEmailProviderSync(trimmedEmail, { extended });
|
|
381
462
|
if (syncResult.provider) {
|
|
382
463
|
// Email is already normalized in getEmailProviderSync
|
|
383
464
|
return {
|
|
@@ -415,34 +496,53 @@ async function getEmailProviderFast(email, options = {}) {
|
|
|
415
496
|
catch {
|
|
416
497
|
// If normalization fails, use original email
|
|
417
498
|
}
|
|
499
|
+
if (extended) {
|
|
500
|
+
const fastResult = {
|
|
501
|
+
provider: concurrentResult.provider,
|
|
502
|
+
email: normalizedEmail,
|
|
503
|
+
loginUrl: concurrentResult.provider?.loginUrl || null,
|
|
504
|
+
detectionMethod: concurrentResult.detectionMethod || 'mx_record',
|
|
505
|
+
timing: concurrentResult.timing,
|
|
506
|
+
confidence: concurrentResult.confidence,
|
|
507
|
+
debug: concurrentResult.debug,
|
|
508
|
+
error: !concurrentResult.provider && !concurrentResult.proxyService ? {
|
|
509
|
+
type: 'UNKNOWN_DOMAIN',
|
|
510
|
+
message: `No email provider found for domain: ${domain}`
|
|
511
|
+
} : undefined
|
|
512
|
+
};
|
|
513
|
+
if (concurrentResult.proxyService) {
|
|
514
|
+
fastResult.proxyService = concurrentResult.proxyService;
|
|
515
|
+
}
|
|
516
|
+
return fastResult;
|
|
517
|
+
}
|
|
518
|
+
// Default: simplified response
|
|
418
519
|
const fastResult = {
|
|
419
|
-
provider: concurrentResult.provider,
|
|
520
|
+
provider: simplifyProvider(concurrentResult.provider),
|
|
420
521
|
email: normalizedEmail,
|
|
421
|
-
loginUrl: concurrentResult.provider?.loginUrl || null,
|
|
422
522
|
detectionMethod: concurrentResult.detectionMethod || 'mx_record',
|
|
423
523
|
timing: concurrentResult.timing,
|
|
424
524
|
confidence: concurrentResult.confidence,
|
|
425
525
|
debug: concurrentResult.debug,
|
|
426
|
-
error: !concurrentResult.provider
|
|
526
|
+
error: !concurrentResult.provider ? {
|
|
427
527
|
type: 'UNKNOWN_DOMAIN',
|
|
428
528
|
message: `No email provider found for domain: ${domain}`
|
|
429
529
|
} : undefined
|
|
430
530
|
};
|
|
431
|
-
if (concurrentResult.proxyService) {
|
|
432
|
-
fastResult.proxyService = concurrentResult.proxyService;
|
|
433
|
-
}
|
|
434
531
|
return fastResult;
|
|
435
532
|
}
|
|
436
533
|
catch (error) {
|
|
437
|
-
|
|
534
|
+
const errorResult = {
|
|
438
535
|
provider: null,
|
|
439
536
|
email,
|
|
440
|
-
loginUrl: null,
|
|
441
537
|
error: {
|
|
442
538
|
type: 'NETWORK_ERROR',
|
|
443
539
|
message: error instanceof Error ? error.message : 'DNS detection failed'
|
|
444
540
|
}
|
|
445
541
|
};
|
|
542
|
+
if (extended) {
|
|
543
|
+
errorResult.loginUrl = null;
|
|
544
|
+
}
|
|
545
|
+
return errorResult;
|
|
446
546
|
}
|
|
447
547
|
}
|
|
448
548
|
/**
|
package/dist/hash-verifier.js
CHANGED
|
@@ -29,7 +29,7 @@ const KNOWN_GOOD_HASHES = {
|
|
|
29
29
|
// SHA-256 hash of the legitimate emailproviders.json
|
|
30
30
|
'emailproviders.json': 'a4fe056edad44ae5479cc100d5cc67cb5f6df86e19c4209db6c5f715f5bf070e',
|
|
31
31
|
// You can add hashes for other critical files
|
|
32
|
-
'package.json': '
|
|
32
|
+
'package.json': 'fc7bab75bddc7af13adce8cd3e51f67f597c999eea500bcdc983cd79b60b13c0',
|
|
33
33
|
};
|
|
34
34
|
/**
|
|
35
35
|
* Calculates SHA-256 hash of a file or string content
|
package/dist/index.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ import { getEmailProvider, getEmailProviderSync, getEmailProviderFast, normalize
|
|
|
20
20
|
import { detectProviderConcurrent } from './concurrent-dns';
|
|
21
21
|
import { validateInternationalEmail, emailToPunycode, domainToPunycode } from './idn';
|
|
22
22
|
export { getEmailProvider, getEmailProviderSync, getEmailProviderFast, normalizeEmail, emailsMatch, detectEmailAlias, Config };
|
|
23
|
-
export type { EmailProvider, EmailProviderResult } from './api';
|
|
23
|
+
export type { EmailProvider, EmailProviderResult, SimplifiedProvider, SimplifiedEmailProviderResult } from './api';
|
|
24
24
|
export type { AliasDetectionResult } from './alias-detection';
|
|
25
25
|
export { loadProviders, detectProviderConcurrent, validateInternationalEmail, emailToPunycode, domainToPunycode };
|
|
26
26
|
export type { ConcurrentDNSConfig, ConcurrentDNSResult } from './concurrent-dns';
|
package/dist/index.js
CHANGED
|
@@ -304,7 +304,7 @@ function batchProcessEmails(emails, options = {}) {
|
|
|
304
304
|
try {
|
|
305
305
|
const providerResult = (0, api_1.getEmailProviderSync)(validation.normalizedEmail);
|
|
306
306
|
result.provider = providerResult.provider?.companyProvider || null;
|
|
307
|
-
result.loginUrl = providerResult.loginUrl;
|
|
307
|
+
result.loginUrl = providerResult.provider?.loginUrl || null;
|
|
308
308
|
}
|
|
309
309
|
catch {
|
|
310
310
|
result.provider = null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikkelscheike/email-provider-links",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.1",
|
|
4
4
|
"description": "TypeScript library for email provider detection with 130 providers (218 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",
|