linkedin-secret-sauce 0.12.1 → 0.12.3
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 +339 -31
- package/dist/cosiall-client.d.ts +1 -1
- package/dist/cosiall-client.js +1 -1
- package/dist/enrichment/index.d.ts +23 -2
- package/dist/enrichment/index.js +38 -22
- package/dist/enrichment/matching.d.ts +16 -2
- package/dist/enrichment/matching.js +387 -65
- package/dist/enrichment/providers/bounceban.d.ts +82 -0
- package/dist/enrichment/providers/bounceban.js +447 -0
- package/dist/enrichment/providers/bouncer.d.ts +1 -1
- package/dist/enrichment/providers/bouncer.js +19 -21
- package/dist/enrichment/providers/construct.d.ts +1 -1
- package/dist/enrichment/providers/construct.js +22 -38
- package/dist/enrichment/providers/cosiall.d.ts +1 -1
- package/dist/enrichment/providers/cosiall.js +3 -4
- package/dist/enrichment/providers/dropcontact.d.ts +15 -9
- package/dist/enrichment/providers/dropcontact.js +188 -19
- package/dist/enrichment/providers/hunter.d.ts +8 -1
- package/dist/enrichment/providers/hunter.js +52 -28
- package/dist/enrichment/providers/index.d.ts +2 -0
- package/dist/enrichment/providers/index.js +10 -1
- package/dist/enrichment/providers/ldd.d.ts +1 -10
- package/dist/enrichment/providers/ldd.js +20 -97
- package/dist/enrichment/providers/smartprospect.js +28 -48
- package/dist/enrichment/providers/snovio.d.ts +1 -1
- package/dist/enrichment/providers/snovio.js +29 -31
- package/dist/enrichment/providers/trykitt.d.ts +63 -0
- package/dist/enrichment/providers/trykitt.js +210 -0
- package/dist/enrichment/types.d.ts +220 -7
- package/dist/enrichment/types.js +16 -8
- package/dist/enrichment/utils/candidate-parser.d.ts +107 -0
- package/dist/enrichment/utils/candidate-parser.js +173 -0
- package/dist/enrichment/utils/noop-provider.d.ts +39 -0
- package/dist/enrichment/utils/noop-provider.js +37 -0
- package/dist/enrichment/utils/rate-limiter.d.ts +103 -0
- package/dist/enrichment/utils/rate-limiter.js +204 -0
- package/dist/enrichment/utils/validation.d.ts +75 -3
- package/dist/enrichment/utils/validation.js +164 -11
- package/dist/linkedin-api.d.ts +40 -1
- package/dist/linkedin-api.js +160 -27
- package/dist/types.d.ts +50 -1
- package/dist/utils/lru-cache.d.ts +105 -0
- package/dist/utils/lru-cache.js +175 -0
- package/docs/COSIALL_PROFILE_EMAILS.md +342 -0
- package/docs/ENRICHMENT.md +622 -0
- package/docs/INTEGRATION.md +405 -0
- package/docs/PLAYGROUND.md +558 -0
- package/docs/SALES_SEARCH.md +171 -0
- package/docs/api/.nojekyll +1 -0
- package/docs/api/assets/hierarchy.js +1 -0
- package/docs/api/assets/highlight.css +92 -0
- package/docs/api/assets/icons.js +18 -0
- package/docs/api/assets/icons.svg +1 -0
- package/docs/api/assets/main.js +60 -0
- package/docs/api/assets/navigation.js +1 -0
- package/docs/api/assets/search.js +1 -0
- package/docs/api/assets/style.css +1633 -0
- package/docs/api/classes/LinkedInClientError.html +37 -0
- package/docs/api/functions/_testGetAccountCookies.html +4 -0
- package/docs/api/functions/_testGetAccountEntry.html +4 -0
- package/docs/api/functions/_testGetAllAccountIds.html +3 -0
- package/docs/api/functions/_testGetPoolState.html +3 -0
- package/docs/api/functions/adminResetAccount.html +1 -0
- package/docs/api/functions/adminSetCooldown.html +1 -0
- package/docs/api/functions/buildCookieHeader.html +1 -0
- package/docs/api/functions/clearAllSmartLeadTokens.html +2 -0
- package/docs/api/functions/clearRequestHistory.html +1 -0
- package/docs/api/functions/clearSessionAccount.html +1 -0
- package/docs/api/functions/clearSmartLeadToken.html +2 -0
- package/docs/api/functions/createEnrichmentClient.html +8 -0
- package/docs/api/functions/extractCsrfToken.html +1 -0
- package/docs/api/functions/extractLinkedInHandle.html +7 -0
- package/docs/api/functions/fetchCookiesFromCosiall.html +14 -0
- package/docs/api/functions/fetchProfileEmailsFromCosiall.html +18 -0
- package/docs/api/functions/forceRefreshCookies.html +1 -0
- package/docs/api/functions/getAccountForSession.html +1 -0
- package/docs/api/functions/getAccountsSummary.html +1 -0
- package/docs/api/functions/getCompaniesBatch.html +5 -0
- package/docs/api/functions/getCompanyById.html +9 -0
- package/docs/api/functions/getCompanyByUrl.html +1 -0
- package/docs/api/functions/getConfig.html +1 -0
- package/docs/api/functions/getCookiePoolHealth.html +1 -0
- package/docs/api/functions/getProfileByUrn.html +17 -0
- package/docs/api/functions/getProfileByVanity.html +10 -0
- package/docs/api/functions/getProfilesBatch.html +1 -0
- package/docs/api/functions/getRequestHistory.html +1 -0
- package/docs/api/functions/getSalesNavigatorProfileDetails.html +1 -0
- package/docs/api/functions/getSalesNavigatorProfileFull.html +16 -0
- package/docs/api/functions/getSmartLeadToken.html +1 -0
- package/docs/api/functions/getSmartLeadTokenCacheStats.html +2 -0
- package/docs/api/functions/getSmartLeadUser.html +2 -0
- package/docs/api/functions/getSnapshot.html +1 -0
- package/docs/api/functions/getYearsAtCompanyOptions.html +2 -0
- package/docs/api/functions/getYearsInPositionOptions.html +2 -0
- package/docs/api/functions/getYearsOfExperienceOptions.html +2 -0
- package/docs/api/functions/incrementMetric.html +1 -0
- package/docs/api/functions/initializeCookiePool.html +1 -0
- package/docs/api/functions/initializeLinkedInClient.html +1 -0
- package/docs/api/functions/isBusinessEmail.html +4 -0
- package/docs/api/functions/isDisposableDomain.html +4 -0
- package/docs/api/functions/isDisposableEmail.html +4 -0
- package/docs/api/functions/isPersonalDomain.html +4 -0
- package/docs/api/functions/isPersonalEmail.html +4 -0
- package/docs/api/functions/isRoleAccount.html +4 -0
- package/docs/api/functions/isValidEmailSyntax.html +4 -0
- package/docs/api/functions/parseFullProfile.html +15 -0
- package/docs/api/functions/parseSalesSearchResults.html +1 -0
- package/docs/api/functions/reportAccountFailure.html +1 -0
- package/docs/api/functions/reportAccountSuccess.html +1 -0
- package/docs/api/functions/resolveCompanyUniversalName.html +1 -0
- package/docs/api/functions/searchSalesLeads.html +16 -0
- package/docs/api/functions/selectAccountForRequest.html +1 -0
- package/docs/api/functions/setAccountForSession.html +1 -0
- package/docs/api/functions/typeahead.html +1 -0
- package/docs/api/functions/verifyEmailMx.html +1 -0
- package/docs/api/hierarchy.html +1 -0
- package/docs/api/index.html +12 -0
- package/docs/api/interfaces/AccountCookies.html +4 -0
- package/docs/api/interfaces/BatchEnrichmentOptions.html +14 -0
- package/docs/api/interfaces/CacheAdapter.html +6 -0
- package/docs/api/interfaces/CanonicalEmail.html +14 -0
- package/docs/api/interfaces/Company.html +17 -0
- package/docs/api/interfaces/ConstructConfig.html +8 -0
- package/docs/api/interfaces/CosiallProfileEmailsResponse.html +11 -0
- package/docs/api/interfaces/DropcontactConfig.html +3 -0
- package/docs/api/interfaces/EnrichmentCandidate.html +34 -0
- package/docs/api/interfaces/EnrichmentClient.html +10 -0
- package/docs/api/interfaces/EnrichmentClientConfig.html +12 -0
- package/docs/api/interfaces/EnrichmentLogger.html +6 -0
- package/docs/api/interfaces/EnrichmentOptions.html +10 -0
- package/docs/api/interfaces/HunterConfig.html +3 -0
- package/docs/api/interfaces/LddConfig.html +4 -0
- package/docs/api/interfaces/LddProfileData.html +6 -0
- package/docs/api/interfaces/LinkedInClientConfig.html +20 -0
- package/docs/api/interfaces/LinkedInCookie.html +9 -0
- package/docs/api/interfaces/LinkedInPosition.html +14 -0
- package/docs/api/interfaces/LinkedInProfile.html +21 -0
- package/docs/api/interfaces/LinkedInSpotlightBadge.html +5 -0
- package/docs/api/interfaces/LinkedInTenure.html +3 -0
- package/docs/api/interfaces/Metrics.html +22 -0
- package/docs/api/interfaces/MetricsSnapshot.html +23 -0
- package/docs/api/interfaces/ProfileEducation.html +8 -0
- package/docs/api/interfaces/ProfileEmailsLookupOptions.html +9 -0
- package/docs/api/interfaces/ProfilePosition.html +12 -0
- package/docs/api/interfaces/ProfileSkill.html +3 -0
- package/docs/api/interfaces/ProviderResult.html +11 -0
- package/docs/api/interfaces/ProvidersConfig.html +17 -0
- package/docs/api/interfaces/RequestHistoryEntry.html +8 -0
- package/docs/api/interfaces/SalesLeadSearchResult.html +31 -0
- package/docs/api/interfaces/SalesNavigatorContactInfo.html +5 -0
- package/docs/api/interfaces/SalesNavigatorPosition.html +11 -0
- package/docs/api/interfaces/SalesNavigatorProfile.html +9 -0
- package/docs/api/interfaces/SalesNavigatorProfileFull.html +24 -0
- package/docs/api/interfaces/SearchSalesResult.html +5 -0
- package/docs/api/interfaces/SmartLeadAuthConfig.html +6 -0
- package/docs/api/interfaces/SmartLeadCredentials.html +3 -0
- package/docs/api/interfaces/SmartLeadLoginResponse.html +3 -0
- package/docs/api/interfaces/SmartLeadUser.html +8 -0
- package/docs/api/interfaces/SmartProspectConfig.html +19 -0
- package/docs/api/interfaces/SmartProspectContact.html +24 -0
- package/docs/api/interfaces/SmartProspectSearchFilters.html +42 -0
- package/docs/api/interfaces/TypeaheadItem.html +3 -0
- package/docs/api/interfaces/TypeaheadResult.html +3 -0
- package/docs/api/interfaces/VerificationResult.html +16 -0
- package/docs/api/types/CostCallback.html +2 -0
- package/docs/api/types/Geo.html +4 -0
- package/docs/api/types/LddApiResponse.html +1 -0
- package/docs/api/types/ProviderFunc.html +2 -0
- package/docs/api/types/ProviderName.html +2 -0
- package/docs/api/types/SalesSearchFilters.html +7 -0
- package/docs/api/types/TypeaheadType.html +1 -0
- package/docs/api/variables/COMPANY_SIZE_OPTIONS.html +1 -0
- package/docs/api/variables/DEFAULT_PROVIDER_ORDER.html +20 -0
- package/docs/api/variables/DISPOSABLE_DOMAINS.html +2 -0
- package/docs/api/variables/FUNCTION_OPTIONS.html +1 -0
- package/docs/api/variables/INDUSTRY_OPTIONS.html +1 -0
- package/docs/api/variables/LANGUAGE_OPTIONS.html +1 -0
- package/docs/api/variables/PERSONAL_DOMAINS.html +2 -0
- package/docs/api/variables/PROVIDER_COSTS.html +15 -0
- package/docs/api/variables/REGION_OPTIONS.html +1 -0
- package/docs/api/variables/SENIORITY_OPTIONS.html +3 -0
- package/docs/api/variables/YEARS_OPTIONS.html +1 -0
- package/docs/index.html +98 -0
- package/package.json +16 -5
|
@@ -10,6 +10,7 @@ exports.createConstructProvider = createConstructProvider;
|
|
|
10
10
|
const mx_1 = require("../verification/mx");
|
|
11
11
|
const personal_domains_1 = require("../utils/personal-domains");
|
|
12
12
|
const validation_1 = require("../utils/validation");
|
|
13
|
+
const candidate_parser_1 = require("../utils/candidate-parser");
|
|
13
14
|
/**
|
|
14
15
|
* Build all email pattern candidates for a person
|
|
15
16
|
*
|
|
@@ -19,11 +20,11 @@ const validation_1 = require("../utils/validation");
|
|
|
19
20
|
* 3. f.lastname, flastname, etc.
|
|
20
21
|
*/
|
|
21
22
|
function buildCandidates(input) {
|
|
22
|
-
const domain = String(input.domain ||
|
|
23
|
-
const first = (0, validation_1.cleanNamePart)(input.first ||
|
|
24
|
-
const last = (0, validation_1.cleanNamePart)(input.last ||
|
|
25
|
-
const fl = first ? first[0] :
|
|
26
|
-
const ll = last ? last[0] :
|
|
23
|
+
const domain = String(input.domain || "").toLowerCase();
|
|
24
|
+
const first = (0, validation_1.cleanNamePart)(input.first || "");
|
|
25
|
+
const last = (0, validation_1.cleanNamePart)(input.last || "");
|
|
26
|
+
const fl = first ? first[0] : "";
|
|
27
|
+
const ll = last ? last[0] : "";
|
|
27
28
|
const locals = [];
|
|
28
29
|
// Simple first name pattern (very common, especially for small companies/startups)
|
|
29
30
|
if (first)
|
|
@@ -59,28 +60,6 @@ function buildCandidates(input) {
|
|
|
59
60
|
}
|
|
60
61
|
return emails;
|
|
61
62
|
}
|
|
62
|
-
/**
|
|
63
|
-
* Extract name components from candidate
|
|
64
|
-
*/
|
|
65
|
-
function extractNames(candidate) {
|
|
66
|
-
const firstName = candidate.firstName ||
|
|
67
|
-
candidate.first_name ||
|
|
68
|
-
candidate.first ||
|
|
69
|
-
candidate.name?.split(' ')?.[0] ||
|
|
70
|
-
'';
|
|
71
|
-
const lastName = candidate.lastName ||
|
|
72
|
-
candidate.last_name ||
|
|
73
|
-
candidate.last ||
|
|
74
|
-
candidate.name?.split(' ')?.slice(1).join(' ') ||
|
|
75
|
-
'';
|
|
76
|
-
return { first: firstName, last: lastName };
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Extract domain from candidate
|
|
80
|
-
*/
|
|
81
|
-
function extractDomain(candidate) {
|
|
82
|
-
return candidate.domain || candidate.companyDomain || candidate.company_domain || '';
|
|
83
|
-
}
|
|
84
63
|
/**
|
|
85
64
|
* Create the construct provider function
|
|
86
65
|
*/
|
|
@@ -89,8 +68,8 @@ function createConstructProvider(config) {
|
|
|
89
68
|
const timeoutMs = config?.timeoutMs ?? 5000;
|
|
90
69
|
const smtpVerifyDelayMs = config?.smtpVerifyDelayMs ?? 2000; // Delay between SMTP checks
|
|
91
70
|
async function fetchEmail(candidate) {
|
|
92
|
-
const { first, last } =
|
|
93
|
-
const domain =
|
|
71
|
+
const { firstName: first, lastName: last } = (0, candidate_parser_1.extractName)(candidate);
|
|
72
|
+
const { domain } = (0, candidate_parser_1.extractCompany)(candidate);
|
|
94
73
|
// Skip if missing required fields
|
|
95
74
|
if (!first || !domain) {
|
|
96
75
|
return null;
|
|
@@ -102,7 +81,9 @@ function createConstructProvider(config) {
|
|
|
102
81
|
const candidates = buildCandidates({ first, last, domain });
|
|
103
82
|
const max = Math.min(candidates.length, maxAttempts);
|
|
104
83
|
// First, check if domain is catch-all
|
|
105
|
-
const catchAllResult = await (0, mx_1.checkDomainCatchAll)(domain, {
|
|
84
|
+
const catchAllResult = await (0, mx_1.checkDomainCatchAll)(domain, {
|
|
85
|
+
timeoutMs: 10000,
|
|
86
|
+
});
|
|
106
87
|
const isCatchAll = catchAllResult.isCatchAll;
|
|
107
88
|
// Collect ALL valid email patterns (not just first match)
|
|
108
89
|
const validEmails = [];
|
|
@@ -116,7 +97,7 @@ function createConstructProvider(config) {
|
|
|
116
97
|
const email = emailsToVerify[i];
|
|
117
98
|
// If we already found a valid email, skip the rest
|
|
118
99
|
if (validEmails.length > 0) {
|
|
119
|
-
attemptedPatterns.push({ email, status:
|
|
100
|
+
attemptedPatterns.push({ email, status: "skipped" });
|
|
120
101
|
continue;
|
|
121
102
|
}
|
|
122
103
|
// Add delay between checks (except first one)
|
|
@@ -124,18 +105,21 @@ function createConstructProvider(config) {
|
|
|
124
105
|
await new Promise((resolve) => setTimeout(resolve, smtpVerifyDelayMs));
|
|
125
106
|
}
|
|
126
107
|
// Verify single email
|
|
127
|
-
const results = await (0, mx_1.verifyEmailsExist)([email], {
|
|
108
|
+
const results = await (0, mx_1.verifyEmailsExist)([email], {
|
|
109
|
+
delayMs: 0,
|
|
110
|
+
timeoutMs,
|
|
111
|
+
});
|
|
128
112
|
const result = results[0];
|
|
129
113
|
if (result.exists === true) {
|
|
130
114
|
// Email confirmed to exist!
|
|
131
|
-
attemptedPatterns.push({ email, status:
|
|
115
|
+
attemptedPatterns.push({ email, status: "exists" });
|
|
132
116
|
validEmails.push({
|
|
133
117
|
email: result.email,
|
|
134
118
|
verified: true,
|
|
135
119
|
confidence: 95, // High confidence - SMTP verified
|
|
136
120
|
isCatchAll: false,
|
|
137
121
|
metadata: {
|
|
138
|
-
pattern: result.email.split(
|
|
122
|
+
pattern: result.email.split("@")[0],
|
|
139
123
|
mxRecords: catchAllResult.mxRecords,
|
|
140
124
|
smtpVerified: true,
|
|
141
125
|
attemptedPatterns, // Include what was tried
|
|
@@ -145,10 +129,10 @@ function createConstructProvider(config) {
|
|
|
145
129
|
break;
|
|
146
130
|
}
|
|
147
131
|
else if (result.exists === false) {
|
|
148
|
-
attemptedPatterns.push({ email, status:
|
|
132
|
+
attemptedPatterns.push({ email, status: "not_found" });
|
|
149
133
|
}
|
|
150
134
|
else {
|
|
151
|
-
attemptedPatterns.push({ email, status:
|
|
135
|
+
attemptedPatterns.push({ email, status: "unknown" });
|
|
152
136
|
}
|
|
153
137
|
}
|
|
154
138
|
// If no valid email found, include attempted patterns in metadata
|
|
@@ -168,7 +152,7 @@ function createConstructProvider(config) {
|
|
|
168
152
|
confidence: verification.confidence,
|
|
169
153
|
isCatchAll: isCatchAll ?? undefined,
|
|
170
154
|
metadata: {
|
|
171
|
-
pattern: email.split(
|
|
155
|
+
pattern: email.split("@")[0],
|
|
172
156
|
mxRecords: verification.mxRecords,
|
|
173
157
|
smtpVerified: false,
|
|
174
158
|
},
|
|
@@ -184,6 +168,6 @@ function createConstructProvider(config) {
|
|
|
184
168
|
return { emails: validEmails };
|
|
185
169
|
}
|
|
186
170
|
// Mark provider name for orchestrator
|
|
187
|
-
fetchEmail.__name =
|
|
171
|
+
fetchEmail.__name = "construct";
|
|
188
172
|
return fetchEmail;
|
|
189
173
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* This is FREE and returns all known emails for a LinkedIn profile.
|
|
6
6
|
*
|
|
7
7
|
* Lookup priority:
|
|
8
|
-
* 1. objectUrn (most precise - "urn:li:
|
|
8
|
+
* 1. objectUrn (most precise - "urn:li:member:129147375")
|
|
9
9
|
* 2. linkedInUrl (URL like "https://www.linkedin.com/in/john-doe/")
|
|
10
10
|
* 3. vanity (username extracted from URL or direct field)
|
|
11
11
|
*/
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* This is FREE and returns all known emails for a LinkedIn profile.
|
|
7
7
|
*
|
|
8
8
|
* Lookup priority:
|
|
9
|
-
* 1. objectUrn (most precise - "urn:li:
|
|
9
|
+
* 1. objectUrn (most precise - "urn:li:member:129147375")
|
|
10
10
|
* 2. linkedInUrl (URL like "https://www.linkedin.com/in/john-doe/")
|
|
11
11
|
* 3. vanity (username extracted from URL or direct field)
|
|
12
12
|
*/
|
|
@@ -14,6 +14,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
14
14
|
exports.createCosiallProvider = createCosiallProvider;
|
|
15
15
|
const cosiall_client_1 = require("../../cosiall-client");
|
|
16
16
|
const validation_1 = require("../utils/validation");
|
|
17
|
+
const noop_provider_1 = require("../utils/noop-provider");
|
|
17
18
|
/**
|
|
18
19
|
* Extract objectUrn from candidate
|
|
19
20
|
*/
|
|
@@ -62,9 +63,7 @@ function extractVanity(candidate) {
|
|
|
62
63
|
function createCosiallProvider(config) {
|
|
63
64
|
// Check if explicitly disabled
|
|
64
65
|
if (config?.enabled === false) {
|
|
65
|
-
|
|
66
|
-
noopProvider.__name = "cosiall";
|
|
67
|
-
return noopProvider;
|
|
66
|
+
return (0, noop_provider_1.createNoOpProvider)("cosiall");
|
|
68
67
|
}
|
|
69
68
|
async function fetchEmail(candidate) {
|
|
70
69
|
// Extract lookup parameters in priority order
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Dropcontact Provider
|
|
3
3
|
*
|
|
4
|
-
* Dropcontact API for email finding.
|
|
5
|
-
*
|
|
4
|
+
* Dropcontact API for email finding and enrichment.
|
|
5
|
+
* Uses the batch enrichment API with polling for results.
|
|
6
|
+
*
|
|
7
|
+
* API Flow:
|
|
8
|
+
* 1. POST /batch to submit contacts for enrichment
|
|
9
|
+
* 2. GET /batch/{request_id} to poll for results
|
|
10
|
+
*
|
|
11
|
+
* Features:
|
|
12
|
+
* - Email finding from name + company/website
|
|
13
|
+
* - Email verification (deliverable/undeliverable)
|
|
14
|
+
* - GDPR compliant (EU-based)
|
|
15
|
+
*
|
|
16
|
+
* @see https://developer.dropcontact.com/
|
|
6
17
|
*/
|
|
7
|
-
import type { EnrichmentCandidate, ProviderResult, DropcontactConfig } from
|
|
18
|
+
import type { EnrichmentCandidate, ProviderResult, DropcontactConfig } from "../types";
|
|
8
19
|
/**
|
|
9
20
|
* Create the Dropcontact provider function
|
|
10
|
-
*
|
|
11
|
-
* Note: This is a placeholder. Full implementation would:
|
|
12
|
-
* 1. POST to https://api.dropcontact.io/batch with contacts
|
|
13
|
-
* 2. Poll for results
|
|
14
|
-
* 3. Return enriched email with verification status
|
|
15
21
|
*/
|
|
16
|
-
export declare function createDropcontactProvider(config: DropcontactConfig): (
|
|
22
|
+
export declare function createDropcontactProvider(config: DropcontactConfig): (candidate: EnrichmentCandidate) => Promise<ProviderResult | null>;
|
|
@@ -2,36 +2,205 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Dropcontact Provider
|
|
4
4
|
*
|
|
5
|
-
* Dropcontact API for email finding.
|
|
6
|
-
*
|
|
5
|
+
* Dropcontact API for email finding and enrichment.
|
|
6
|
+
* Uses the batch enrichment API with polling for results.
|
|
7
|
+
*
|
|
8
|
+
* API Flow:
|
|
9
|
+
* 1. POST /batch to submit contacts for enrichment
|
|
10
|
+
* 2. GET /batch/{request_id} to poll for results
|
|
11
|
+
*
|
|
12
|
+
* Features:
|
|
13
|
+
* - Email finding from name + company/website
|
|
14
|
+
* - Email verification (deliverable/undeliverable)
|
|
15
|
+
* - GDPR compliant (EU-based)
|
|
16
|
+
*
|
|
17
|
+
* @see https://developer.dropcontact.com/
|
|
7
18
|
*/
|
|
8
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
20
|
exports.createDropcontactProvider = createDropcontactProvider;
|
|
21
|
+
const http_retry_1 = require("../utils/http-retry");
|
|
22
|
+
const noop_provider_1 = require("../utils/noop-provider");
|
|
23
|
+
const API_BASE = "https://api.dropcontact.io";
|
|
24
|
+
/**
|
|
25
|
+
* Extract inputs from candidate for Dropcontact API
|
|
26
|
+
*/
|
|
27
|
+
function extractInputs(candidate) {
|
|
28
|
+
const name = candidate.name || candidate.fullName || candidate.full_name;
|
|
29
|
+
const first = candidate.first ||
|
|
30
|
+
candidate.first_name ||
|
|
31
|
+
candidate.firstName ||
|
|
32
|
+
name?.split?.(" ")?.[0];
|
|
33
|
+
const last = candidate.last ||
|
|
34
|
+
candidate.last_name ||
|
|
35
|
+
candidate.lastName ||
|
|
36
|
+
name?.split?.(" ")?.slice(1).join(" ") ||
|
|
37
|
+
undefined;
|
|
38
|
+
const domain = candidate.domain ||
|
|
39
|
+
candidate.companyDomain ||
|
|
40
|
+
candidate.company_domain ||
|
|
41
|
+
undefined;
|
|
42
|
+
const company = candidate.company ||
|
|
43
|
+
candidate.currentCompany ||
|
|
44
|
+
candidate.organization ||
|
|
45
|
+
candidate.org ||
|
|
46
|
+
undefined;
|
|
47
|
+
const linkedin = candidate.linkedinUrl ||
|
|
48
|
+
candidate.linkedin_url ||
|
|
49
|
+
(candidate.linkedinHandle
|
|
50
|
+
? `https://www.linkedin.com/in/${candidate.linkedinHandle}`
|
|
51
|
+
: undefined) ||
|
|
52
|
+
(candidate.linkedin_handle
|
|
53
|
+
? `https://www.linkedin.com/in/${candidate.linkedin_handle}`
|
|
54
|
+
: undefined) ||
|
|
55
|
+
undefined;
|
|
56
|
+
return {
|
|
57
|
+
first_name: first,
|
|
58
|
+
last_name: last,
|
|
59
|
+
full_name: name,
|
|
60
|
+
company: company,
|
|
61
|
+
website: domain,
|
|
62
|
+
linkedin: linkedin,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
10
65
|
/**
|
|
11
66
|
* Create the Dropcontact provider function
|
|
12
|
-
*
|
|
13
|
-
* Note: This is a placeholder. Full implementation would:
|
|
14
|
-
* 1. POST to https://api.dropcontact.io/batch with contacts
|
|
15
|
-
* 2. Poll for results
|
|
16
|
-
* 3. Return enriched email with verification status
|
|
17
67
|
*/
|
|
18
68
|
function createDropcontactProvider(config) {
|
|
19
69
|
const { apiKey } = config;
|
|
20
70
|
if (!apiKey) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
71
|
+
return (0, noop_provider_1.createNoOpProvider)("dropcontact");
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Submit a batch request to Dropcontact
|
|
75
|
+
*/
|
|
76
|
+
async function submitBatch(contacts) {
|
|
77
|
+
const body = {
|
|
78
|
+
data: contacts,
|
|
79
|
+
siren: false, // We don't need French company registration numbers
|
|
80
|
+
language: "en",
|
|
81
|
+
};
|
|
82
|
+
try {
|
|
83
|
+
const response = await (0, http_retry_1.postWithRetry)(`${API_BASE}/batch`, body, { "X-Access-Token": apiKey }, { retries: 2, backoffMs: 500, timeoutMs: 30000 });
|
|
84
|
+
if (response.error) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
return response.request_id || null;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Poll for batch results with exponential backoff
|
|
95
|
+
*/
|
|
96
|
+
async function pollResults(requestId, maxAttempts = 10, initialDelayMs = 2000) {
|
|
97
|
+
let delayMs = initialDelayMs;
|
|
98
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
99
|
+
await (0, http_retry_1.delay)(delayMs);
|
|
100
|
+
try {
|
|
101
|
+
const response = await (0, http_retry_1.getWithRetry)(`${API_BASE}/batch/${requestId}`, { "X-Access-Token": apiKey }, { retries: 1, backoffMs: 500, timeoutMs: 30000 });
|
|
102
|
+
// Check if processing is complete
|
|
103
|
+
if (response.error) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
// If we have data and status is finished (or we got data back), return it
|
|
107
|
+
if (response.data && response.data.length > 0) {
|
|
108
|
+
// Check if still processing
|
|
109
|
+
if (response.status === "pending") {
|
|
110
|
+
// Increase delay for next poll (max 10 seconds)
|
|
111
|
+
delayMs = Math.min(delayMs * 1.5, 10000);
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
return response.data;
|
|
115
|
+
}
|
|
116
|
+
// If explicitly finished but no data
|
|
117
|
+
if (response.status === "finished") {
|
|
118
|
+
return response.data || null;
|
|
119
|
+
}
|
|
120
|
+
// Still processing, increase delay
|
|
121
|
+
delayMs = Math.min(delayMs * 1.5, 10000);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Network error, retry with backoff
|
|
125
|
+
delayMs = Math.min(delayMs * 2, 10000);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return null; // Timeout after max attempts
|
|
25
129
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
//
|
|
32
|
-
|
|
130
|
+
/**
|
|
131
|
+
* Fetch email for a candidate
|
|
132
|
+
*/
|
|
133
|
+
async function fetchEmail(candidate) {
|
|
134
|
+
const contact = extractInputs(candidate);
|
|
135
|
+
// Need at least a name and company/website to search
|
|
136
|
+
const hasName = (0, http_retry_1.truthy)(contact.first_name) || (0, http_retry_1.truthy)(contact.full_name);
|
|
137
|
+
const hasCompanyInfo = (0, http_retry_1.truthy)(contact.company) || (0, http_retry_1.truthy)(contact.website);
|
|
138
|
+
const hasLinkedIn = (0, http_retry_1.truthy)(contact.linkedin);
|
|
139
|
+
if (!hasName && !hasLinkedIn) {
|
|
140
|
+
return null; // Need at least name or LinkedIn URL
|
|
141
|
+
}
|
|
142
|
+
if (!hasCompanyInfo && !hasLinkedIn) {
|
|
143
|
+
return null; // Need company info or LinkedIn URL
|
|
144
|
+
}
|
|
145
|
+
// Submit single contact as batch
|
|
146
|
+
const requestId = await submitBatch([contact]);
|
|
147
|
+
if (!requestId) {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
// Poll for results
|
|
151
|
+
const results = await pollResults(requestId);
|
|
152
|
+
if (!results || results.length === 0) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
// Extract email from first result
|
|
156
|
+
const enriched = results[0];
|
|
157
|
+
if (!enriched.email || enriched.email.length === 0) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
// Find the best email (prefer valid ones)
|
|
161
|
+
let bestEmail = null;
|
|
162
|
+
for (const emailObj of enriched.email) {
|
|
163
|
+
if (!emailObj.email)
|
|
164
|
+
continue;
|
|
165
|
+
// Prefer valid emails
|
|
166
|
+
if (emailObj.qualification === "valid") {
|
|
167
|
+
bestEmail = emailObj;
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
// Take catch-all if no valid found yet
|
|
171
|
+
if (!bestEmail ||
|
|
172
|
+
(bestEmail.qualification !== "valid" &&
|
|
173
|
+
emailObj.qualification === "catch_all")) {
|
|
174
|
+
bestEmail = emailObj;
|
|
175
|
+
}
|
|
176
|
+
// Take any email if nothing else
|
|
177
|
+
if (!bestEmail) {
|
|
178
|
+
bestEmail = emailObj;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if (!bestEmail || !bestEmail.email) {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
// Map qualification to verified status
|
|
185
|
+
const verified = (0, http_retry_1.mapVerifiedStatus)(bestEmail.qualification);
|
|
186
|
+
// Confidence based on qualification
|
|
187
|
+
let score = 50;
|
|
188
|
+
if (bestEmail.qualification === "valid") {
|
|
189
|
+
score = 95;
|
|
190
|
+
}
|
|
191
|
+
else if (bestEmail.qualification === "catch_all") {
|
|
192
|
+
score = 60;
|
|
193
|
+
}
|
|
194
|
+
else if (bestEmail.qualification === "invalid") {
|
|
195
|
+
score = 10;
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
email: bestEmail.email,
|
|
199
|
+
verified,
|
|
200
|
+
score,
|
|
201
|
+
};
|
|
33
202
|
}
|
|
34
203
|
// Mark provider name for orchestrator
|
|
35
|
-
fetchEmail.__name =
|
|
204
|
+
fetchEmail.__name = "dropcontact";
|
|
36
205
|
return fetchEmail;
|
|
37
206
|
}
|
|
@@ -2,7 +2,14 @@
|
|
|
2
2
|
* Hunter.io Provider
|
|
3
3
|
*
|
|
4
4
|
* Hunter.io public API for email finding.
|
|
5
|
-
*
|
|
5
|
+
*
|
|
6
|
+
* Supports three modes (in order of preference):
|
|
7
|
+
* 1. linkedin_handle - Most accurate, uses LinkedIn vanity/handle
|
|
8
|
+
* 2. domain + first_name + last_name - Standard email finder
|
|
9
|
+
* 3. company + first_name + last_name - When domain is unknown
|
|
10
|
+
* 4. domain-search fallback - Returns multiple emails for a domain
|
|
11
|
+
*
|
|
12
|
+
* @see https://hunter.io/api-documentation/v2#email-finder
|
|
6
13
|
*/
|
|
7
14
|
import type { EnrichmentCandidate, ProviderResult, ProviderMultiResult, HunterConfig } from "../types";
|
|
8
15
|
/**
|
|
@@ -3,31 +3,35 @@
|
|
|
3
3
|
* Hunter.io Provider
|
|
4
4
|
*
|
|
5
5
|
* Hunter.io public API for email finding.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
|
+
* Supports three modes (in order of preference):
|
|
8
|
+
* 1. linkedin_handle - Most accurate, uses LinkedIn vanity/handle
|
|
9
|
+
* 2. domain + first_name + last_name - Standard email finder
|
|
10
|
+
* 3. company + first_name + last_name - When domain is unknown
|
|
11
|
+
* 4. domain-search fallback - Returns multiple emails for a domain
|
|
12
|
+
*
|
|
13
|
+
* @see https://hunter.io/api-documentation/v2#email-finder
|
|
7
14
|
*/
|
|
8
15
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
16
|
exports.createHunterProvider = createHunterProvider;
|
|
10
17
|
const http_retry_1 = require("../utils/http-retry");
|
|
18
|
+
const candidate_parser_1 = require("../utils/candidate-parser");
|
|
19
|
+
const noop_provider_1 = require("../utils/noop-provider");
|
|
11
20
|
const API_BASE = "https://api.hunter.io/v2";
|
|
12
21
|
/**
|
|
13
|
-
* Extract
|
|
22
|
+
* Extract Hunter-specific inputs from candidate using shared parser
|
|
14
23
|
*/
|
|
15
|
-
function
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const domain = candidate.domain ||
|
|
27
|
-
candidate.companyDomain ||
|
|
28
|
-
candidate.company_domain ||
|
|
29
|
-
undefined;
|
|
30
|
-
return { first, last, domain };
|
|
24
|
+
function extractHunterInputs(candidate) {
|
|
25
|
+
const { firstName, lastName } = (0, candidate_parser_1.extractName)(candidate);
|
|
26
|
+
const { company, domain } = (0, candidate_parser_1.extractCompany)(candidate);
|
|
27
|
+
const { username: linkedinHandle } = (0, candidate_parser_1.extractLinkedIn)(candidate);
|
|
28
|
+
return {
|
|
29
|
+
first: firstName || undefined,
|
|
30
|
+
last: lastName || undefined,
|
|
31
|
+
domain: domain ?? undefined,
|
|
32
|
+
company: company ?? undefined,
|
|
33
|
+
linkedinHandle: linkedinHandle ?? undefined,
|
|
34
|
+
};
|
|
31
35
|
}
|
|
32
36
|
/**
|
|
33
37
|
* Create the Hunter provider function
|
|
@@ -35,17 +39,23 @@ function extractInputs(candidate) {
|
|
|
35
39
|
function createHunterProvider(config) {
|
|
36
40
|
const { apiKey } = config;
|
|
37
41
|
if (!apiKey) {
|
|
38
|
-
|
|
39
|
-
const noopProvider = async () => null;
|
|
40
|
-
noopProvider.__name = "hunter";
|
|
41
|
-
return noopProvider;
|
|
42
|
+
return (0, noop_provider_1.createNoOpProvider)("hunter");
|
|
42
43
|
}
|
|
43
44
|
async function fetchEmail(candidate) {
|
|
44
|
-
const { first, last, domain } =
|
|
45
|
+
const { first, last, domain, company, linkedinHandle } = extractHunterInputs(candidate);
|
|
45
46
|
let url = null;
|
|
46
47
|
let isEmailFinder = false;
|
|
47
|
-
// Use
|
|
48
|
-
if ((0, http_retry_1.truthy)(
|
|
48
|
+
// Priority 1: Use linkedin_handle if available (most accurate)
|
|
49
|
+
if ((0, http_retry_1.truthy)(linkedinHandle)) {
|
|
50
|
+
const qs = new URLSearchParams({
|
|
51
|
+
api_key: String(apiKey),
|
|
52
|
+
linkedin_handle: String(linkedinHandle),
|
|
53
|
+
});
|
|
54
|
+
url = `${API_BASE}/email-finder?${qs.toString()}`;
|
|
55
|
+
isEmailFinder = true;
|
|
56
|
+
}
|
|
57
|
+
// Priority 2: Use domain + name (standard email finder)
|
|
58
|
+
else if ((0, http_retry_1.truthy)(first) && (0, http_retry_1.truthy)(last) && (0, http_retry_1.truthy)(domain)) {
|
|
49
59
|
const qs = new URLSearchParams({
|
|
50
60
|
api_key: String(apiKey),
|
|
51
61
|
domain: String(domain),
|
|
@@ -55,7 +65,18 @@ function createHunterProvider(config) {
|
|
|
55
65
|
url = `${API_BASE}/email-finder?${qs.toString()}`;
|
|
56
66
|
isEmailFinder = true;
|
|
57
67
|
}
|
|
58
|
-
//
|
|
68
|
+
// Priority 3: Use company + name (when domain unknown)
|
|
69
|
+
else if ((0, http_retry_1.truthy)(first) && (0, http_retry_1.truthy)(last) && (0, http_retry_1.truthy)(company)) {
|
|
70
|
+
const qs = new URLSearchParams({
|
|
71
|
+
api_key: String(apiKey),
|
|
72
|
+
company: String(company),
|
|
73
|
+
first_name: String(first),
|
|
74
|
+
last_name: String(last),
|
|
75
|
+
});
|
|
76
|
+
url = `${API_BASE}/email-finder?${qs.toString()}`;
|
|
77
|
+
isEmailFinder = true;
|
|
78
|
+
}
|
|
79
|
+
// Priority 4: Fall back to domain-search if only domain available (can return multiple)
|
|
59
80
|
else if ((0, http_retry_1.truthy)(domain)) {
|
|
60
81
|
const qs = new URLSearchParams({
|
|
61
82
|
api_key: String(apiKey),
|
|
@@ -65,10 +86,13 @@ function createHunterProvider(config) {
|
|
|
65
86
|
url = `${API_BASE}/domain-search?${qs.toString()}`;
|
|
66
87
|
}
|
|
67
88
|
else {
|
|
68
|
-
return null; // Can't search without domain
|
|
89
|
+
return null; // Can't search without domain, company, or linkedin_handle
|
|
69
90
|
}
|
|
70
91
|
try {
|
|
71
|
-
const json = await (0, http_retry_1.getWithRetry)(url, undefined, {
|
|
92
|
+
const json = await (0, http_retry_1.getWithRetry)(url, undefined, {
|
|
93
|
+
retries: 1,
|
|
94
|
+
backoffMs: 100,
|
|
95
|
+
});
|
|
72
96
|
// Parse email-finder response shape (single result)
|
|
73
97
|
if (isEmailFinder) {
|
|
74
98
|
const ef = (json && (json.data || json.result));
|
|
@@ -5,7 +5,9 @@ export { createConstructProvider } from "./construct";
|
|
|
5
5
|
export { createLddProvider } from "./ldd";
|
|
6
6
|
export { createSmartProspectProvider } from "./smartprospect";
|
|
7
7
|
export { createCosiallProvider } from "./cosiall";
|
|
8
|
+
export { createTryKittProvider, findEmailWithTryKitt, verifyEmailWithTryKitt, } from "./trykitt";
|
|
8
9
|
export { createHunterProvider } from "./hunter";
|
|
9
10
|
export { createDropcontactProvider } from "./dropcontact";
|
|
10
11
|
export { createBouncerProvider, verifyEmailWithBouncer, checkCatchAllDomain, verifyEmailsBatch, } from "./bouncer";
|
|
12
|
+
export { createBounceBanProvider, verifyEmailWithBounceBan, verifyEmailsBatchWithBounceBan, checkCatchAllWithBounceBan, } from "./bounceban";
|
|
11
13
|
export { createSnovioProvider, findEmailsWithSnovio, verifyEmailWithSnovio, clearSnovioTokenCache, } from "./snovio";
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Email Enrichment Providers
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.clearSnovioTokenCache = exports.verifyEmailWithSnovio = exports.findEmailsWithSnovio = exports.createSnovioProvider = exports.verifyEmailsBatch = exports.checkCatchAllDomain = exports.verifyEmailWithBouncer = exports.createBouncerProvider = exports.createDropcontactProvider = exports.createHunterProvider = exports.createCosiallProvider = exports.createSmartProspectProvider = exports.createLddProvider = exports.createConstructProvider = void 0;
|
|
6
|
+
exports.clearSnovioTokenCache = exports.verifyEmailWithSnovio = exports.findEmailsWithSnovio = exports.createSnovioProvider = exports.checkCatchAllWithBounceBan = exports.verifyEmailsBatchWithBounceBan = exports.verifyEmailWithBounceBan = exports.createBounceBanProvider = exports.verifyEmailsBatch = exports.checkCatchAllDomain = exports.verifyEmailWithBouncer = exports.createBouncerProvider = exports.createDropcontactProvider = exports.createHunterProvider = exports.verifyEmailWithTryKitt = exports.findEmailWithTryKitt = exports.createTryKittProvider = exports.createCosiallProvider = exports.createSmartProspectProvider = exports.createLddProvider = exports.createConstructProvider = void 0;
|
|
7
7
|
var construct_1 = require("./construct");
|
|
8
8
|
Object.defineProperty(exports, "createConstructProvider", { enumerable: true, get: function () { return construct_1.createConstructProvider; } });
|
|
9
9
|
var ldd_1 = require("./ldd");
|
|
@@ -12,6 +12,10 @@ var smartprospect_1 = require("./smartprospect");
|
|
|
12
12
|
Object.defineProperty(exports, "createSmartProspectProvider", { enumerable: true, get: function () { return smartprospect_1.createSmartProspectProvider; } });
|
|
13
13
|
var cosiall_1 = require("./cosiall");
|
|
14
14
|
Object.defineProperty(exports, "createCosiallProvider", { enumerable: true, get: function () { return cosiall_1.createCosiallProvider; } });
|
|
15
|
+
var trykitt_1 = require("./trykitt");
|
|
16
|
+
Object.defineProperty(exports, "createTryKittProvider", { enumerable: true, get: function () { return trykitt_1.createTryKittProvider; } });
|
|
17
|
+
Object.defineProperty(exports, "findEmailWithTryKitt", { enumerable: true, get: function () { return trykitt_1.findEmailWithTryKitt; } });
|
|
18
|
+
Object.defineProperty(exports, "verifyEmailWithTryKitt", { enumerable: true, get: function () { return trykitt_1.verifyEmailWithTryKitt; } });
|
|
15
19
|
var hunter_1 = require("./hunter");
|
|
16
20
|
Object.defineProperty(exports, "createHunterProvider", { enumerable: true, get: function () { return hunter_1.createHunterProvider; } });
|
|
17
21
|
var dropcontact_1 = require("./dropcontact");
|
|
@@ -21,6 +25,11 @@ Object.defineProperty(exports, "createBouncerProvider", { enumerable: true, get:
|
|
|
21
25
|
Object.defineProperty(exports, "verifyEmailWithBouncer", { enumerable: true, get: function () { return bouncer_1.verifyEmailWithBouncer; } });
|
|
22
26
|
Object.defineProperty(exports, "checkCatchAllDomain", { enumerable: true, get: function () { return bouncer_1.checkCatchAllDomain; } });
|
|
23
27
|
Object.defineProperty(exports, "verifyEmailsBatch", { enumerable: true, get: function () { return bouncer_1.verifyEmailsBatch; } });
|
|
28
|
+
var bounceban_1 = require("./bounceban");
|
|
29
|
+
Object.defineProperty(exports, "createBounceBanProvider", { enumerable: true, get: function () { return bounceban_1.createBounceBanProvider; } });
|
|
30
|
+
Object.defineProperty(exports, "verifyEmailWithBounceBan", { enumerable: true, get: function () { return bounceban_1.verifyEmailWithBounceBan; } });
|
|
31
|
+
Object.defineProperty(exports, "verifyEmailsBatchWithBounceBan", { enumerable: true, get: function () { return bounceban_1.verifyEmailsBatchWithBounceBan; } });
|
|
32
|
+
Object.defineProperty(exports, "checkCatchAllWithBounceBan", { enumerable: true, get: function () { return bounceban_1.checkCatchAllWithBounceBan; } });
|
|
24
33
|
var snovio_1 = require("./snovio");
|
|
25
34
|
Object.defineProperty(exports, "createSnovioProvider", { enumerable: true, get: function () { return snovio_1.createSnovioProvider; } });
|
|
26
35
|
Object.defineProperty(exports, "findEmailsWithSnovio", { enumerable: true, get: function () { return snovio_1.findEmailsWithSnovio; } });
|
|
@@ -9,16 +9,7 @@
|
|
|
9
9
|
* while usernames can be changed by users at any time.
|
|
10
10
|
*/
|
|
11
11
|
import type { EnrichmentCandidate, ProviderResult, ProviderMultiResult, LddConfig } from "../types";
|
|
12
|
-
|
|
13
|
-
* Extract numeric LinkedIn ID from various formats:
|
|
14
|
-
* - Direct number: "307567"
|
|
15
|
-
* - URN format: "urn:li:member:307567"
|
|
16
|
-
* - Full URN: "urn:li:fs_salesProfile:(ACwAAAAEsW8B...,NAME_SEARCH,PJOV)"
|
|
17
|
-
* - objectUrn: "urn:li:member:307567"
|
|
18
|
-
*
|
|
19
|
-
* Returns the numeric ID as a string, or null if not found.
|
|
20
|
-
*/
|
|
21
|
-
export declare function extractNumericLinkedInId(input: string | undefined | null): string | null;
|
|
12
|
+
export { extractNumericLinkedInId } from "../utils/candidate-parser";
|
|
22
13
|
/**
|
|
23
14
|
* Create the LDD provider function
|
|
24
15
|
*
|