linkedin-secret-sauce 0.4.0 → 0.5.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/dist/enrichment/index.d.ts +43 -0
- package/dist/enrichment/index.js +231 -0
- package/dist/enrichment/orchestrator.d.ts +31 -0
- package/dist/enrichment/orchestrator.js +218 -0
- package/dist/enrichment/providers/apollo.d.ts +11 -0
- package/dist/enrichment/providers/apollo.js +136 -0
- package/dist/enrichment/providers/construct.d.ts +11 -0
- package/dist/enrichment/providers/construct.js +107 -0
- package/dist/enrichment/providers/dropcontact.d.ts +16 -0
- package/dist/enrichment/providers/dropcontact.js +37 -0
- package/dist/enrichment/providers/hunter.d.ts +11 -0
- package/dist/enrichment/providers/hunter.js +162 -0
- package/dist/enrichment/providers/index.d.ts +9 -0
- package/dist/enrichment/providers/index.js +18 -0
- package/dist/enrichment/providers/ldd.d.ts +11 -0
- package/dist/enrichment/providers/ldd.js +110 -0
- package/dist/enrichment/providers/smartprospect.d.ts +11 -0
- package/dist/enrichment/providers/smartprospect.js +249 -0
- package/dist/enrichment/types.d.ts +329 -0
- package/dist/enrichment/types.js +31 -0
- package/dist/enrichment/utils/disposable-domains.d.ts +24 -0
- package/dist/enrichment/utils/disposable-domains.js +1011 -0
- package/dist/enrichment/utils/index.d.ts +6 -0
- package/dist/enrichment/utils/index.js +22 -0
- package/dist/enrichment/utils/personal-domains.d.ts +31 -0
- package/dist/enrichment/utils/personal-domains.js +95 -0
- package/dist/enrichment/utils/validation.d.ts +42 -0
- package/dist/enrichment/utils/validation.js +130 -0
- package/dist/enrichment/verification/index.d.ts +4 -0
- package/dist/enrichment/verification/index.js +8 -0
- package/dist/enrichment/verification/mx.d.ts +16 -0
- package/dist/enrichment/verification/mx.js +168 -0
- package/dist/index.d.ts +17 -14
- package/dist/index.js +20 -1
- package/package.json +1 -1
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enrichment Utilities
|
|
3
|
+
*/
|
|
4
|
+
export { isPersonalEmail, isBusinessEmail, isPersonalDomain, PERSONAL_DOMAINS } from './personal-domains';
|
|
5
|
+
export { isDisposableEmail, isDisposableDomain, DISPOSABLE_DOMAINS } from './disposable-domains';
|
|
6
|
+
export { isValidEmailSyntax, isRoleAccount, asciiFold, cleanNamePart, hostnameFromUrl, extractLinkedInUsername, } from './validation';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Enrichment Utilities
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.extractLinkedInUsername = exports.hostnameFromUrl = exports.cleanNamePart = exports.asciiFold = exports.isRoleAccount = exports.isValidEmailSyntax = exports.DISPOSABLE_DOMAINS = exports.isDisposableDomain = exports.isDisposableEmail = exports.PERSONAL_DOMAINS = exports.isPersonalDomain = exports.isBusinessEmail = exports.isPersonalEmail = void 0;
|
|
7
|
+
var personal_domains_1 = require("./personal-domains");
|
|
8
|
+
Object.defineProperty(exports, "isPersonalEmail", { enumerable: true, get: function () { return personal_domains_1.isPersonalEmail; } });
|
|
9
|
+
Object.defineProperty(exports, "isBusinessEmail", { enumerable: true, get: function () { return personal_domains_1.isBusinessEmail; } });
|
|
10
|
+
Object.defineProperty(exports, "isPersonalDomain", { enumerable: true, get: function () { return personal_domains_1.isPersonalDomain; } });
|
|
11
|
+
Object.defineProperty(exports, "PERSONAL_DOMAINS", { enumerable: true, get: function () { return personal_domains_1.PERSONAL_DOMAINS; } });
|
|
12
|
+
var disposable_domains_1 = require("./disposable-domains");
|
|
13
|
+
Object.defineProperty(exports, "isDisposableEmail", { enumerable: true, get: function () { return disposable_domains_1.isDisposableEmail; } });
|
|
14
|
+
Object.defineProperty(exports, "isDisposableDomain", { enumerable: true, get: function () { return disposable_domains_1.isDisposableDomain; } });
|
|
15
|
+
Object.defineProperty(exports, "DISPOSABLE_DOMAINS", { enumerable: true, get: function () { return disposable_domains_1.DISPOSABLE_DOMAINS; } });
|
|
16
|
+
var validation_1 = require("./validation");
|
|
17
|
+
Object.defineProperty(exports, "isValidEmailSyntax", { enumerable: true, get: function () { return validation_1.isValidEmailSyntax; } });
|
|
18
|
+
Object.defineProperty(exports, "isRoleAccount", { enumerable: true, get: function () { return validation_1.isRoleAccount; } });
|
|
19
|
+
Object.defineProperty(exports, "asciiFold", { enumerable: true, get: function () { return validation_1.asciiFold; } });
|
|
20
|
+
Object.defineProperty(exports, "cleanNamePart", { enumerable: true, get: function () { return validation_1.cleanNamePart; } });
|
|
21
|
+
Object.defineProperty(exports, "hostnameFromUrl", { enumerable: true, get: function () { return validation_1.hostnameFromUrl; } });
|
|
22
|
+
Object.defineProperty(exports, "extractLinkedInUsername", { enumerable: true, get: function () { return validation_1.extractLinkedInUsername; } });
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Personal Email Domain Detection
|
|
3
|
+
*
|
|
4
|
+
* Detects personal email domains (Gmail, Yahoo, Outlook, etc.) that should
|
|
5
|
+
* be filtered out when looking for business emails.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Set of known personal email domains
|
|
9
|
+
*/
|
|
10
|
+
export declare const PERSONAL_DOMAINS: Set<string>;
|
|
11
|
+
/**
|
|
12
|
+
* Check if an email is from a personal domain
|
|
13
|
+
*
|
|
14
|
+
* @param email - Email address to check
|
|
15
|
+
* @returns true if the email is from a personal domain
|
|
16
|
+
*/
|
|
17
|
+
export declare function isPersonalEmail(email: string): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Check if an email is from a business domain
|
|
20
|
+
*
|
|
21
|
+
* @param email - Email address to check
|
|
22
|
+
* @returns true if the email is NOT from a personal domain
|
|
23
|
+
*/
|
|
24
|
+
export declare function isBusinessEmail(email: string): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Check if a domain is a personal email domain
|
|
27
|
+
*
|
|
28
|
+
* @param domain - Domain to check
|
|
29
|
+
* @returns true if the domain is a personal email domain
|
|
30
|
+
*/
|
|
31
|
+
export declare function isPersonalDomain(domain: string): boolean;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Personal Email Domain Detection
|
|
4
|
+
*
|
|
5
|
+
* Detects personal email domains (Gmail, Yahoo, Outlook, etc.) that should
|
|
6
|
+
* be filtered out when looking for business emails.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.PERSONAL_DOMAINS = void 0;
|
|
10
|
+
exports.isPersonalEmail = isPersonalEmail;
|
|
11
|
+
exports.isBusinessEmail = isBusinessEmail;
|
|
12
|
+
exports.isPersonalDomain = isPersonalDomain;
|
|
13
|
+
/**
|
|
14
|
+
* Set of known personal email domains
|
|
15
|
+
*/
|
|
16
|
+
exports.PERSONAL_DOMAINS = new Set([
|
|
17
|
+
// Gmail ecosystem
|
|
18
|
+
'gmail.com',
|
|
19
|
+
'googlemail.com',
|
|
20
|
+
// Microsoft ecosystem
|
|
21
|
+
'outlook.com',
|
|
22
|
+
'hotmail.com',
|
|
23
|
+
'live.com',
|
|
24
|
+
'msn.com',
|
|
25
|
+
// Yahoo
|
|
26
|
+
'yahoo.com',
|
|
27
|
+
'ymail.com',
|
|
28
|
+
'yahoo.co.uk',
|
|
29
|
+
'yahoo.fr',
|
|
30
|
+
'yahoo.de',
|
|
31
|
+
'yahoo.es',
|
|
32
|
+
'yahoo.it',
|
|
33
|
+
'yahoo.ca',
|
|
34
|
+
'yahoo.com.au',
|
|
35
|
+
'yahoo.co.jp',
|
|
36
|
+
'yahoo.co.in',
|
|
37
|
+
// Apple
|
|
38
|
+
'icloud.com',
|
|
39
|
+
'me.com',
|
|
40
|
+
'mac.com',
|
|
41
|
+
// Other major providers
|
|
42
|
+
'aol.com',
|
|
43
|
+
'proton.me',
|
|
44
|
+
'protonmail.com',
|
|
45
|
+
'pm.me',
|
|
46
|
+
'gmx.com',
|
|
47
|
+
'gmx.de',
|
|
48
|
+
'gmx.net',
|
|
49
|
+
'mail.com',
|
|
50
|
+
'zoho.com',
|
|
51
|
+
// International
|
|
52
|
+
'yandex.ru',
|
|
53
|
+
'yandex.com',
|
|
54
|
+
'mail.ru',
|
|
55
|
+
'qq.com',
|
|
56
|
+
'163.com',
|
|
57
|
+
'126.com',
|
|
58
|
+
'naver.com',
|
|
59
|
+
'daum.net',
|
|
60
|
+
]);
|
|
61
|
+
/**
|
|
62
|
+
* Check if an email is from a personal domain
|
|
63
|
+
*
|
|
64
|
+
* @param email - Email address to check
|
|
65
|
+
* @returns true if the email is from a personal domain
|
|
66
|
+
*/
|
|
67
|
+
function isPersonalEmail(email) {
|
|
68
|
+
if (!email || typeof email !== 'string')
|
|
69
|
+
return true;
|
|
70
|
+
const at = email.indexOf('@');
|
|
71
|
+
if (at < 0)
|
|
72
|
+
return true;
|
|
73
|
+
const domain = email.slice(at + 1).toLowerCase();
|
|
74
|
+
return exports.PERSONAL_DOMAINS.has(domain);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Check if an email is from a business domain
|
|
78
|
+
*
|
|
79
|
+
* @param email - Email address to check
|
|
80
|
+
* @returns true if the email is NOT from a personal domain
|
|
81
|
+
*/
|
|
82
|
+
function isBusinessEmail(email) {
|
|
83
|
+
return !isPersonalEmail(email);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Check if a domain is a personal email domain
|
|
87
|
+
*
|
|
88
|
+
* @param domain - Domain to check
|
|
89
|
+
* @returns true if the domain is a personal email domain
|
|
90
|
+
*/
|
|
91
|
+
function isPersonalDomain(domain) {
|
|
92
|
+
if (!domain || typeof domain !== 'string')
|
|
93
|
+
return false;
|
|
94
|
+
return exports.PERSONAL_DOMAINS.has(domain.toLowerCase());
|
|
95
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Email Validation Utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides email syntax validation and name parsing utilities.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Validate email syntax
|
|
8
|
+
*
|
|
9
|
+
* @param email - Email address to validate
|
|
10
|
+
* @returns true if the email has valid syntax
|
|
11
|
+
*/
|
|
12
|
+
export declare function isValidEmailSyntax(email: string): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Check if an email is a role account
|
|
15
|
+
*
|
|
16
|
+
* @param email - Email address to check
|
|
17
|
+
* @returns true if the email is a role account
|
|
18
|
+
*/
|
|
19
|
+
export declare function isRoleAccount(email: string): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* ASCII fold diacritics for name normalization
|
|
22
|
+
* e.g., "Jos" -> "Jose", "Mller" -> "Muller"
|
|
23
|
+
*/
|
|
24
|
+
export declare function asciiFold(s: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Clean name part: lowercase, remove diacritics, keep only a-z0-9
|
|
27
|
+
*/
|
|
28
|
+
export declare function cleanNamePart(s: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* Extract hostname from URL
|
|
31
|
+
*
|
|
32
|
+
* @param url - URL to extract hostname from
|
|
33
|
+
* @returns hostname without www prefix, or null if invalid
|
|
34
|
+
*/
|
|
35
|
+
export declare function hostnameFromUrl(url?: string | null): string | null;
|
|
36
|
+
/**
|
|
37
|
+
* Extract LinkedIn username from URL
|
|
38
|
+
*
|
|
39
|
+
* @param url - LinkedIn URL
|
|
40
|
+
* @returns username or null if not found
|
|
41
|
+
*/
|
|
42
|
+
export declare function extractLinkedInUsername(url: string): string | null;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Email Validation Utilities
|
|
4
|
+
*
|
|
5
|
+
* Provides email syntax validation and name parsing utilities.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.isValidEmailSyntax = isValidEmailSyntax;
|
|
9
|
+
exports.isRoleAccount = isRoleAccount;
|
|
10
|
+
exports.asciiFold = asciiFold;
|
|
11
|
+
exports.cleanNamePart = cleanNamePart;
|
|
12
|
+
exports.hostnameFromUrl = hostnameFromUrl;
|
|
13
|
+
exports.extractLinkedInUsername = extractLinkedInUsername;
|
|
14
|
+
/**
|
|
15
|
+
* Validate email syntax
|
|
16
|
+
*
|
|
17
|
+
* @param email - Email address to validate
|
|
18
|
+
* @returns true if the email has valid syntax
|
|
19
|
+
*/
|
|
20
|
+
function isValidEmailSyntax(email) {
|
|
21
|
+
if (!email || typeof email !== 'string')
|
|
22
|
+
return false;
|
|
23
|
+
if (email.includes(' '))
|
|
24
|
+
return false;
|
|
25
|
+
const parts = email.split('@');
|
|
26
|
+
if (parts.length !== 2)
|
|
27
|
+
return false;
|
|
28
|
+
const [local, domain] = parts;
|
|
29
|
+
if (!local || !domain)
|
|
30
|
+
return false;
|
|
31
|
+
if (!domain.includes('.'))
|
|
32
|
+
return false;
|
|
33
|
+
if (local.length > 64)
|
|
34
|
+
return false;
|
|
35
|
+
if (domain.length > 255)
|
|
36
|
+
return false;
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Role account patterns (info@, support@, etc.)
|
|
41
|
+
*/
|
|
42
|
+
const ROLE_PATTERNS = [
|
|
43
|
+
/^info@/i,
|
|
44
|
+
/^support@/i,
|
|
45
|
+
/^admin@/i,
|
|
46
|
+
/^noreply@/i,
|
|
47
|
+
/^no-reply@/i,
|
|
48
|
+
/^contact@/i,
|
|
49
|
+
/^sales@/i,
|
|
50
|
+
/^help@/i,
|
|
51
|
+
/^team@/i,
|
|
52
|
+
/^hello@/i,
|
|
53
|
+
/^feedback@/i,
|
|
54
|
+
/^service@/i,
|
|
55
|
+
/^webmaster@/i,
|
|
56
|
+
/^postmaster@/i,
|
|
57
|
+
/^abuse@/i,
|
|
58
|
+
/^security@/i,
|
|
59
|
+
/^hostmaster@/i,
|
|
60
|
+
/^marketing@/i,
|
|
61
|
+
/^press@/i,
|
|
62
|
+
/^media@/i,
|
|
63
|
+
/^jobs@/i,
|
|
64
|
+
/^careers@/i,
|
|
65
|
+
/^hr@/i,
|
|
66
|
+
/^legal@/i,
|
|
67
|
+
/^billing@/i,
|
|
68
|
+
/^privacy@/i,
|
|
69
|
+
];
|
|
70
|
+
/**
|
|
71
|
+
* Check if an email is a role account
|
|
72
|
+
*
|
|
73
|
+
* @param email - Email address to check
|
|
74
|
+
* @returns true if the email is a role account
|
|
75
|
+
*/
|
|
76
|
+
function isRoleAccount(email) {
|
|
77
|
+
if (!email)
|
|
78
|
+
return false;
|
|
79
|
+
const emailLower = email.toLowerCase();
|
|
80
|
+
return ROLE_PATTERNS.some((pattern) => pattern.test(emailLower));
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* ASCII fold diacritics for name normalization
|
|
84
|
+
* e.g., "Jos" -> "Jose", "Mller" -> "Muller"
|
|
85
|
+
*/
|
|
86
|
+
function asciiFold(s) {
|
|
87
|
+
try {
|
|
88
|
+
return s.normalize('NFD').replace(/\p{Diacritic}+/gu, '');
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return s;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Clean name part: lowercase, remove diacritics, keep only a-z0-9
|
|
96
|
+
*/
|
|
97
|
+
function cleanNamePart(s) {
|
|
98
|
+
const lower = asciiFold(String(s || '').toLowerCase());
|
|
99
|
+
return lower.replace(/[^a-z0-9]/g, '');
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Extract hostname from URL
|
|
103
|
+
*
|
|
104
|
+
* @param url - URL to extract hostname from
|
|
105
|
+
* @returns hostname without www prefix, or null if invalid
|
|
106
|
+
*/
|
|
107
|
+
function hostnameFromUrl(url) {
|
|
108
|
+
if (!url)
|
|
109
|
+
return null;
|
|
110
|
+
try {
|
|
111
|
+
const u = new URL(url);
|
|
112
|
+
const h = u.hostname.toLowerCase();
|
|
113
|
+
return h.startsWith('www.') ? h.slice(4) : h;
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Extract LinkedIn username from URL
|
|
121
|
+
*
|
|
122
|
+
* @param url - LinkedIn URL
|
|
123
|
+
* @returns username or null if not found
|
|
124
|
+
*/
|
|
125
|
+
function extractLinkedInUsername(url) {
|
|
126
|
+
if (!url)
|
|
127
|
+
return null;
|
|
128
|
+
const match = url.match(/linkedin\.com\/in\/([^/?]+)/);
|
|
129
|
+
return match ? match[1] : null;
|
|
130
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Email Verification Module
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.verifyEmailMx = void 0;
|
|
7
|
+
var mx_1 = require("./mx");
|
|
8
|
+
Object.defineProperty(exports, "verifyEmailMx", { enumerable: true, get: function () { return mx_1.verifyEmailMx; } });
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MX Record Resolution and Email Verification
|
|
3
|
+
*
|
|
4
|
+
* Provides MX record resolution with timeout support and confidence scoring.
|
|
5
|
+
*/
|
|
6
|
+
import type { VerificationResult } from '../types';
|
|
7
|
+
/**
|
|
8
|
+
* Verify an email address via MX record lookup
|
|
9
|
+
*
|
|
10
|
+
* @param email - Email address to verify
|
|
11
|
+
* @param options - Verification options
|
|
12
|
+
* @returns Verification result with confidence score
|
|
13
|
+
*/
|
|
14
|
+
export declare function verifyEmailMx(email: string, options?: {
|
|
15
|
+
timeoutMs?: number;
|
|
16
|
+
}): Promise<VerificationResult>;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MX Record Resolution and Email Verification
|
|
4
|
+
*
|
|
5
|
+
* Provides MX record resolution with timeout support and confidence scoring.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.verifyEmailMx = verifyEmailMx;
|
|
9
|
+
const promises_1 = require("node:dns/promises");
|
|
10
|
+
const disposable_domains_1 = require("../utils/disposable-domains");
|
|
11
|
+
const validation_1 = require("../utils/validation");
|
|
12
|
+
/**
|
|
13
|
+
* Resolve MX records with timeout
|
|
14
|
+
*
|
|
15
|
+
* @param domain - Domain to resolve
|
|
16
|
+
* @param timeoutMs - Timeout in milliseconds
|
|
17
|
+
* @returns Array of MX records or empty array on failure
|
|
18
|
+
*/
|
|
19
|
+
async function resolveMxWithTimeout(domain, timeoutMs) {
|
|
20
|
+
const controller = new AbortController();
|
|
21
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
22
|
+
try {
|
|
23
|
+
const result = await (0, promises_1.resolveMx)(domain);
|
|
24
|
+
return Array.isArray(result) ? result : [];
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
clearTimeout(timeoutId);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Calculate confidence score based on verification factors
|
|
35
|
+
*/
|
|
36
|
+
function calculateConfidence(params) {
|
|
37
|
+
const { mxValid, isCatchAll, isRoleAccount, isDisposable, mxCount } = params;
|
|
38
|
+
if (!mxValid)
|
|
39
|
+
return 0;
|
|
40
|
+
let score = 20; // Base score for valid MX
|
|
41
|
+
// MX record count bonus
|
|
42
|
+
if (mxCount >= 2)
|
|
43
|
+
score += 20;
|
|
44
|
+
else if (mxCount === 1)
|
|
45
|
+
score += 10;
|
|
46
|
+
// Non-catch-all bonus (we assume catch-all if MX exists but can't verify)
|
|
47
|
+
if (!isCatchAll)
|
|
48
|
+
score += 30;
|
|
49
|
+
// Non-role account bonus
|
|
50
|
+
if (!isRoleAccount)
|
|
51
|
+
score += 20;
|
|
52
|
+
// Non-disposable bonus
|
|
53
|
+
if (!isDisposable)
|
|
54
|
+
score += 20;
|
|
55
|
+
return Math.min(100, Math.max(0, score));
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Verify an email address via MX record lookup
|
|
59
|
+
*
|
|
60
|
+
* @param email - Email address to verify
|
|
61
|
+
* @param options - Verification options
|
|
62
|
+
* @returns Verification result with confidence score
|
|
63
|
+
*/
|
|
64
|
+
async function verifyEmailMx(email, options) {
|
|
65
|
+
const timeoutMs = options?.timeoutMs ?? 5000;
|
|
66
|
+
// Step 1: Syntax validation
|
|
67
|
+
if (!(0, validation_1.isValidEmailSyntax)(email)) {
|
|
68
|
+
return {
|
|
69
|
+
valid: false,
|
|
70
|
+
confidence: 0,
|
|
71
|
+
reason: 'syntax',
|
|
72
|
+
isCatchAll: false,
|
|
73
|
+
isRoleAccount: false,
|
|
74
|
+
isDisposable: false,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
// Step 2: Disposable email detection
|
|
78
|
+
const disposable = (0, disposable_domains_1.isDisposableEmail)(email);
|
|
79
|
+
if (disposable) {
|
|
80
|
+
return {
|
|
81
|
+
valid: false,
|
|
82
|
+
confidence: 0,
|
|
83
|
+
reason: 'disposable',
|
|
84
|
+
isCatchAll: false,
|
|
85
|
+
isRoleAccount: false,
|
|
86
|
+
isDisposable: true,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
// Step 3: Role account detection
|
|
90
|
+
const roleAccount = (0, validation_1.isRoleAccount)(email);
|
|
91
|
+
// Step 4: MX record validation
|
|
92
|
+
const domain = email.split('@')[1];
|
|
93
|
+
if (!domain) {
|
|
94
|
+
return {
|
|
95
|
+
valid: false,
|
|
96
|
+
confidence: 0,
|
|
97
|
+
reason: 'syntax',
|
|
98
|
+
isCatchAll: false,
|
|
99
|
+
isRoleAccount: roleAccount,
|
|
100
|
+
isDisposable: false,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
const mx = await resolveMxWithTimeout(domain, timeoutMs);
|
|
105
|
+
if (!mx || mx.length === 0) {
|
|
106
|
+
return {
|
|
107
|
+
valid: false,
|
|
108
|
+
confidence: 0,
|
|
109
|
+
reason: 'mx_missing',
|
|
110
|
+
isCatchAll: false,
|
|
111
|
+
isRoleAccount: roleAccount,
|
|
112
|
+
isDisposable: false,
|
|
113
|
+
mxRecords: [],
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
// Conservative: assume catch-all if MX exists (full detection requires SMTP handshake)
|
|
117
|
+
const catchAll = true;
|
|
118
|
+
// Calculate confidence
|
|
119
|
+
const confidence = calculateConfidence({
|
|
120
|
+
mxValid: true,
|
|
121
|
+
isCatchAll: catchAll,
|
|
122
|
+
isRoleAccount: roleAccount,
|
|
123
|
+
isDisposable: false,
|
|
124
|
+
mxCount: mx.length,
|
|
125
|
+
});
|
|
126
|
+
const valid = confidence >= 50;
|
|
127
|
+
// Determine reason
|
|
128
|
+
let reason = 'valid';
|
|
129
|
+
if (!valid) {
|
|
130
|
+
if (catchAll)
|
|
131
|
+
reason = 'catch_all';
|
|
132
|
+
else if (roleAccount)
|
|
133
|
+
reason = 'role_account';
|
|
134
|
+
}
|
|
135
|
+
const mxRecords = mx.map((m) => m.exchange);
|
|
136
|
+
return {
|
|
137
|
+
valid,
|
|
138
|
+
confidence,
|
|
139
|
+
reason,
|
|
140
|
+
isCatchAll: catchAll,
|
|
141
|
+
isRoleAccount: roleAccount,
|
|
142
|
+
isDisposable: false,
|
|
143
|
+
mxRecords,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
const error = err;
|
|
148
|
+
if (error &&
|
|
149
|
+
(error.code === 'ETIMEOUT' || error.name === 'AbortError' || error.message === 'timeout')) {
|
|
150
|
+
return {
|
|
151
|
+
valid: null,
|
|
152
|
+
confidence: 0,
|
|
153
|
+
reason: 'timeout',
|
|
154
|
+
isCatchAll: false,
|
|
155
|
+
isRoleAccount: roleAccount,
|
|
156
|
+
isDisposable: false,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
valid: null,
|
|
161
|
+
confidence: 0,
|
|
162
|
+
reason: 'error',
|
|
163
|
+
isCatchAll: false,
|
|
164
|
+
isRoleAccount: roleAccount,
|
|
165
|
+
isDisposable: false,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
export { initializeLinkedInClient, getConfig } from
|
|
2
|
-
export type { LinkedInClientConfig } from
|
|
3
|
-
export { LinkedInClientError } from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export { parseFullProfile } from
|
|
7
|
-
export { parseSalesSearchResults } from
|
|
8
|
-
export * from
|
|
9
|
-
export * from
|
|
10
|
-
export type { LinkedInTenure, LinkedInPosition, LinkedInSpotlightBadge, SalesLeadSearchResult, } from
|
|
11
|
-
export * from
|
|
12
|
-
export { getRequestHistory, clearRequestHistory } from
|
|
13
|
-
export type { RequestHistoryEntry } from
|
|
14
|
-
export * from
|
|
1
|
+
export { initializeLinkedInClient, getConfig } from "./config";
|
|
2
|
+
export type { LinkedInClientConfig } from "./config";
|
|
3
|
+
export { LinkedInClientError } from "./utils/errors";
|
|
4
|
+
export * from "./cosiall-client";
|
|
5
|
+
export * from "./cookie-pool";
|
|
6
|
+
export { parseFullProfile } from "./parsers/profile-parser";
|
|
7
|
+
export { parseSalesSearchResults } from "./parsers/search-parser";
|
|
8
|
+
export * from "./linkedin-api";
|
|
9
|
+
export * from "./types";
|
|
10
|
+
export type { LinkedInTenure, LinkedInPosition, LinkedInSpotlightBadge, SalesLeadSearchResult, } from "./types";
|
|
11
|
+
export * from "./utils/metrics";
|
|
12
|
+
export { getRequestHistory, clearRequestHistory, } from "./utils/request-history";
|
|
13
|
+
export type { RequestHistoryEntry } from "./utils/request-history";
|
|
14
|
+
export * from "./constants";
|
|
15
|
+
export { createEnrichmentClient } from "./enrichment";
|
|
16
|
+
export type { CanonicalEmail, EnrichmentCandidate, ProviderResult, ProviderFunc, ProviderName, EnrichmentClientConfig, EnrichmentClient, ProvidersConfig, EnrichmentOptions, BatchEnrichmentOptions, HunterConfig, ApolloConfig, SmartProspectConfig, LddConfig, DropcontactConfig, ConstructConfig, CacheAdapter, CostCallback, EnrichmentLogger, VerificationResult, SmartProspectContact, SmartProspectSearchFilters, LddProfileData, LddApiResponse, } from "./enrichment";
|
|
17
|
+
export { isPersonalEmail, isBusinessEmail, isPersonalDomain, isDisposableEmail, isDisposableDomain, isValidEmailSyntax, isRoleAccount, verifyEmailMx, PERSONAL_DOMAINS, DISPOSABLE_DOMAINS, DEFAULT_PROVIDER_ORDER, PROVIDER_COSTS, } from "./enrichment";
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.clearRequestHistory = exports.getRequestHistory = exports.parseSalesSearchResults = exports.parseFullProfile = exports.LinkedInClientError = exports.getConfig = exports.initializeLinkedInClient = void 0;
|
|
17
|
+
exports.PROVIDER_COSTS = exports.DEFAULT_PROVIDER_ORDER = exports.DISPOSABLE_DOMAINS = exports.PERSONAL_DOMAINS = exports.verifyEmailMx = exports.isRoleAccount = exports.isValidEmailSyntax = exports.isDisposableDomain = exports.isDisposableEmail = exports.isPersonalDomain = exports.isBusinessEmail = exports.isPersonalEmail = exports.createEnrichmentClient = exports.clearRequestHistory = exports.getRequestHistory = exports.parseSalesSearchResults = exports.parseFullProfile = exports.LinkedInClientError = exports.getConfig = exports.initializeLinkedInClient = void 0;
|
|
18
18
|
var config_1 = require("./config");
|
|
19
19
|
Object.defineProperty(exports, "initializeLinkedInClient", { enumerable: true, get: function () { return config_1.initializeLinkedInClient; } });
|
|
20
20
|
Object.defineProperty(exports, "getConfig", { enumerable: true, get: function () { return config_1.getConfig; } });
|
|
@@ -33,3 +33,22 @@ var request_history_1 = require("./utils/request-history");
|
|
|
33
33
|
Object.defineProperty(exports, "getRequestHistory", { enumerable: true, get: function () { return request_history_1.getRequestHistory; } });
|
|
34
34
|
Object.defineProperty(exports, "clearRequestHistory", { enumerable: true, get: function () { return request_history_1.clearRequestHistory; } });
|
|
35
35
|
__exportStar(require("./constants"), exports);
|
|
36
|
+
// Email Enrichment Module
|
|
37
|
+
var enrichment_1 = require("./enrichment");
|
|
38
|
+
Object.defineProperty(exports, "createEnrichmentClient", { enumerable: true, get: function () { return enrichment_1.createEnrichmentClient; } });
|
|
39
|
+
var enrichment_2 = require("./enrichment");
|
|
40
|
+
// Utilities
|
|
41
|
+
Object.defineProperty(exports, "isPersonalEmail", { enumerable: true, get: function () { return enrichment_2.isPersonalEmail; } });
|
|
42
|
+
Object.defineProperty(exports, "isBusinessEmail", { enumerable: true, get: function () { return enrichment_2.isBusinessEmail; } });
|
|
43
|
+
Object.defineProperty(exports, "isPersonalDomain", { enumerable: true, get: function () { return enrichment_2.isPersonalDomain; } });
|
|
44
|
+
Object.defineProperty(exports, "isDisposableEmail", { enumerable: true, get: function () { return enrichment_2.isDisposableEmail; } });
|
|
45
|
+
Object.defineProperty(exports, "isDisposableDomain", { enumerable: true, get: function () { return enrichment_2.isDisposableDomain; } });
|
|
46
|
+
Object.defineProperty(exports, "isValidEmailSyntax", { enumerable: true, get: function () { return enrichment_2.isValidEmailSyntax; } });
|
|
47
|
+
Object.defineProperty(exports, "isRoleAccount", { enumerable: true, get: function () { return enrichment_2.isRoleAccount; } });
|
|
48
|
+
// Verification
|
|
49
|
+
Object.defineProperty(exports, "verifyEmailMx", { enumerable: true, get: function () { return enrichment_2.verifyEmailMx; } });
|
|
50
|
+
// Constants
|
|
51
|
+
Object.defineProperty(exports, "PERSONAL_DOMAINS", { enumerable: true, get: function () { return enrichment_2.PERSONAL_DOMAINS; } });
|
|
52
|
+
Object.defineProperty(exports, "DISPOSABLE_DOMAINS", { enumerable: true, get: function () { return enrichment_2.DISPOSABLE_DOMAINS; } });
|
|
53
|
+
Object.defineProperty(exports, "DEFAULT_PROVIDER_ORDER", { enumerable: true, get: function () { return enrichment_2.DEFAULT_PROVIDER_ORDER; } });
|
|
54
|
+
Object.defineProperty(exports, "PROVIDER_COSTS", { enumerable: true, get: function () { return enrichment_2.PROVIDER_COSTS; } });
|