linkedin-secret-sauce 0.3.29 → 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.
Files changed (55) hide show
  1. package/dist/cookie-pool.d.ts +1 -1
  2. package/dist/cookie-pool.js +67 -35
  3. package/dist/cosiall-client.d.ts +20 -1
  4. package/dist/cosiall-client.js +48 -25
  5. package/dist/enrichment/index.d.ts +43 -0
  6. package/dist/enrichment/index.js +231 -0
  7. package/dist/enrichment/orchestrator.d.ts +31 -0
  8. package/dist/enrichment/orchestrator.js +218 -0
  9. package/dist/enrichment/providers/apollo.d.ts +11 -0
  10. package/dist/enrichment/providers/apollo.js +136 -0
  11. package/dist/enrichment/providers/construct.d.ts +11 -0
  12. package/dist/enrichment/providers/construct.js +107 -0
  13. package/dist/enrichment/providers/dropcontact.d.ts +16 -0
  14. package/dist/enrichment/providers/dropcontact.js +37 -0
  15. package/dist/enrichment/providers/hunter.d.ts +11 -0
  16. package/dist/enrichment/providers/hunter.js +162 -0
  17. package/dist/enrichment/providers/index.d.ts +9 -0
  18. package/dist/enrichment/providers/index.js +18 -0
  19. package/dist/enrichment/providers/ldd.d.ts +11 -0
  20. package/dist/enrichment/providers/ldd.js +110 -0
  21. package/dist/enrichment/providers/smartprospect.d.ts +11 -0
  22. package/dist/enrichment/providers/smartprospect.js +249 -0
  23. package/dist/enrichment/types.d.ts +329 -0
  24. package/dist/enrichment/types.js +31 -0
  25. package/dist/enrichment/utils/disposable-domains.d.ts +24 -0
  26. package/dist/enrichment/utils/disposable-domains.js +1011 -0
  27. package/dist/enrichment/utils/index.d.ts +6 -0
  28. package/dist/enrichment/utils/index.js +22 -0
  29. package/dist/enrichment/utils/personal-domains.d.ts +31 -0
  30. package/dist/enrichment/utils/personal-domains.js +95 -0
  31. package/dist/enrichment/utils/validation.d.ts +42 -0
  32. package/dist/enrichment/utils/validation.js +130 -0
  33. package/dist/enrichment/verification/index.d.ts +4 -0
  34. package/dist/enrichment/verification/index.js +8 -0
  35. package/dist/enrichment/verification/mx.d.ts +16 -0
  36. package/dist/enrichment/verification/mx.js +168 -0
  37. package/dist/http-client.d.ts +1 -1
  38. package/dist/http-client.js +146 -63
  39. package/dist/index.d.ts +17 -14
  40. package/dist/index.js +20 -1
  41. package/dist/linkedin-api.d.ts +97 -4
  42. package/dist/linkedin-api.js +416 -134
  43. package/dist/parsers/company-parser.d.ts +15 -1
  44. package/dist/parsers/company-parser.js +45 -17
  45. package/dist/parsers/profile-parser.d.ts +19 -1
  46. package/dist/parsers/profile-parser.js +131 -81
  47. package/dist/parsers/search-parser.d.ts +1 -1
  48. package/dist/parsers/search-parser.js +24 -11
  49. package/dist/utils/logger.d.ts +1 -1
  50. package/dist/utils/logger.js +28 -18
  51. package/dist/utils/search-encoder.d.ts +32 -1
  52. package/dist/utils/search-encoder.js +102 -58
  53. package/dist/utils/sentry.d.ts +1 -1
  54. package/dist/utils/sentry.js +56 -8
  55. package/package.json +1 -1
@@ -0,0 +1,249 @@
1
+ "use strict";
2
+ /**
3
+ * SmartProspect/Smartlead Provider
4
+ *
5
+ * Smartlead's prospect database - a REVERSE-ENGINEERED private API.
6
+ * Two-phase process: search (free) then fetch (costs credits).
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.createSmartProspectProvider = createSmartProspectProvider;
10
+ const DEFAULT_API_URL = 'https://prospect-api.smartlead.ai/api/search-email-leads';
11
+ /**
12
+ * Delay helper for retry logic
13
+ */
14
+ async function delay(ms) {
15
+ return new Promise((r) => setTimeout(r, ms));
16
+ }
17
+ /**
18
+ * HTTP request with retry on 429 rate limit
19
+ */
20
+ async function requestWithRetry(url, options, retries = 2, backoffMs = 300) {
21
+ let lastErr;
22
+ for (let i = 0; i <= retries; i++) {
23
+ try {
24
+ const res = await fetch(url, options);
25
+ // Retry on rate limit
26
+ if (res.status === 429 && i < retries) {
27
+ await delay(backoffMs * Math.pow(2, i));
28
+ continue;
29
+ }
30
+ if (!res.ok) {
31
+ const errorText = await res.text().catch(() => '');
32
+ throw new Error(`SmartProspect API error: ${res.status} - ${errorText}`);
33
+ }
34
+ return (await res.json());
35
+ }
36
+ catch (err) {
37
+ lastErr = err;
38
+ if (i < retries) {
39
+ await delay(backoffMs * Math.pow(2, i));
40
+ continue;
41
+ }
42
+ }
43
+ }
44
+ throw lastErr ?? new Error('smartprospect_http_error');
45
+ }
46
+ /**
47
+ * Calculate match score between search input and contact result
48
+ */
49
+ function calculateMatchScore(contact, searchName, company, title) {
50
+ let score = 0;
51
+ // Name match scoring (0-50 points)
52
+ const contactName = contact.fullName?.toLowerCase() || '';
53
+ const searchNameLower = searchName.toLowerCase();
54
+ if (contactName === searchNameLower) {
55
+ score += 50; // Exact match
56
+ }
57
+ else if (contactName.includes(searchNameLower) || searchNameLower.includes(contactName)) {
58
+ score += 30; // Partial match
59
+ }
60
+ // Company match scoring (0-30 points)
61
+ if (company) {
62
+ const contactCompany = contact.company?.name?.toLowerCase() || '';
63
+ const searchCompany = company.toLowerCase();
64
+ if (contactCompany === searchCompany) {
65
+ score += 30; // Exact match
66
+ }
67
+ else if (contactCompany.includes(searchCompany) || searchCompany.includes(contactCompany)) {
68
+ score += 15; // Partial match
69
+ }
70
+ }
71
+ // Title match scoring (0-10 points)
72
+ if (title) {
73
+ const contactTitle = contact.title?.toLowerCase() || '';
74
+ const searchTitle = title.toLowerCase();
75
+ if (contactTitle.includes(searchTitle) || searchTitle.includes(contactTitle)) {
76
+ score += 10;
77
+ }
78
+ }
79
+ // Deliverability score bonus (0-10 points)
80
+ if (contact.emailDeliverability > 0) {
81
+ score += contact.emailDeliverability * 10;
82
+ }
83
+ return score;
84
+ }
85
+ /**
86
+ * Extract name components from candidate
87
+ */
88
+ function extractNames(candidate) {
89
+ const firstName = candidate.firstName ||
90
+ candidate.first_name ||
91
+ candidate.first ||
92
+ candidate.name?.split(' ')?.[0] ||
93
+ '';
94
+ const lastName = candidate.lastName ||
95
+ candidate.last_name ||
96
+ candidate.last ||
97
+ candidate.name?.split(' ')?.slice(1).join(' ') ||
98
+ '';
99
+ return { firstName, lastName };
100
+ }
101
+ /**
102
+ * Create the SmartProspect provider function
103
+ */
104
+ function createSmartProspectProvider(config) {
105
+ const { apiToken, apiUrl = DEFAULT_API_URL } = config;
106
+ if (!apiToken) {
107
+ // Return a no-op provider if not configured
108
+ const noopProvider = async () => null;
109
+ noopProvider.__name = 'smartprospect';
110
+ return noopProvider;
111
+ }
112
+ /**
113
+ * Search for contacts matching filters (FREE - no credits used)
114
+ */
115
+ async function searchContacts(filters) {
116
+ try {
117
+ const response = await requestWithRetry(`${apiUrl}/search-contacts`, {
118
+ method: 'POST',
119
+ headers: {
120
+ Authorization: `Bearer ${apiToken}`,
121
+ 'Content-Type': 'application/json',
122
+ Accept: 'application/json',
123
+ },
124
+ body: JSON.stringify({
125
+ ...filters,
126
+ dontDisplayOwnedContact: filters.dontDisplayOwnedContact ?? true,
127
+ limit: filters.limit ?? 10,
128
+ titleExactMatch: filters.titleExactMatch ?? false,
129
+ }),
130
+ });
131
+ return response;
132
+ }
133
+ catch {
134
+ return {
135
+ success: false,
136
+ message: 'Search failed',
137
+ data: { list: [], total_count: 0 },
138
+ };
139
+ }
140
+ }
141
+ /**
142
+ * Fetch/enrich emails for specific contact IDs (COSTS CREDITS)
143
+ */
144
+ async function fetchContacts(contactIds) {
145
+ try {
146
+ const response = await requestWithRetry(`${apiUrl}/fetch-contacts`, {
147
+ method: 'POST',
148
+ headers: {
149
+ Authorization: `Bearer ${apiToken}`,
150
+ 'Content-Type': 'application/json',
151
+ Accept: 'application/json',
152
+ },
153
+ body: JSON.stringify({ contactIds }),
154
+ });
155
+ return response;
156
+ }
157
+ catch {
158
+ return {
159
+ success: false,
160
+ message: 'Fetch failed',
161
+ data: {
162
+ list: [],
163
+ total_count: 0,
164
+ metrics: {
165
+ totalContacts: 0,
166
+ totalEmails: 0,
167
+ noEmailFound: 0,
168
+ invalidEmails: 0,
169
+ catchAllEmails: 0,
170
+ verifiedEmails: 0,
171
+ completed: 0,
172
+ },
173
+ leads_found: 0,
174
+ email_fetched: 0,
175
+ verification_status_list: [],
176
+ },
177
+ };
178
+ }
179
+ }
180
+ async function fetchEmail(candidate) {
181
+ const { firstName, lastName } = extractNames(candidate);
182
+ if (!firstName) {
183
+ return null; // Minimum requirement
184
+ }
185
+ const fullName = `${firstName} ${lastName}`.trim();
186
+ const company = candidate.company || candidate.currentCompany || candidate.organization || undefined;
187
+ const title = candidate.title || candidate.currentRole || candidate.current_role || undefined;
188
+ const domain = candidate.domain || candidate.companyDomain || candidate.company_domain || undefined;
189
+ // Build search filters
190
+ const filters = {
191
+ name: [fullName],
192
+ limit: 5, // Get top 5 to find best match
193
+ };
194
+ if (company) {
195
+ filters.company = [company];
196
+ }
197
+ if (domain) {
198
+ filters.domain = [domain];
199
+ }
200
+ // Step 1: Search for contacts (FREE)
201
+ const searchResult = await searchContacts(filters);
202
+ if (!searchResult.success || searchResult.data.list.length === 0) {
203
+ return null;
204
+ }
205
+ // Find best match by scoring
206
+ const matches = searchResult.data.list;
207
+ let bestMatch = null;
208
+ let bestScore = 0;
209
+ for (const contact of matches) {
210
+ const score = calculateMatchScore(contact, fullName, company, title);
211
+ if (score > bestScore) {
212
+ bestScore = score;
213
+ bestMatch = contact;
214
+ }
215
+ }
216
+ if (!bestMatch) {
217
+ return null;
218
+ }
219
+ // Step 2: Fetch email for best match (COSTS CREDITS)
220
+ const fetchResult = await fetchContacts([bestMatch.id]);
221
+ if (!fetchResult.success || fetchResult.data.list.length === 0) {
222
+ return null;
223
+ }
224
+ const enrichedContact = fetchResult.data.list[0];
225
+ const email = enrichedContact?.email;
226
+ if (!email) {
227
+ return null;
228
+ }
229
+ // Calculate verification confidence
230
+ const isVerified = enrichedContact.verificationStatus === 'valid';
231
+ const isCatchAll = enrichedContact.verificationStatus === 'catch_all';
232
+ const deliverability = enrichedContact.emailDeliverability || 0;
233
+ let confidence = deliverability * 100;
234
+ if (isVerified) {
235
+ confidence = Math.max(confidence, 90);
236
+ }
237
+ else if (isCatchAll) {
238
+ confidence = Math.min(confidence, 75);
239
+ }
240
+ return {
241
+ email,
242
+ verified: isVerified || isCatchAll, // Accept catch-all as semi-verified
243
+ score: confidence,
244
+ };
245
+ }
246
+ // Mark provider name for orchestrator
247
+ fetchEmail.__name = 'smartprospect';
248
+ return fetchEmail;
249
+ }
@@ -0,0 +1,329 @@
1
+ /**
2
+ * Email Enrichment Types
3
+ *
4
+ * Core types for the email enrichment module. These types are designed to be
5
+ * stateless - consumers pass their own API keys and configuration.
6
+ */
7
+ /**
8
+ * Canonical email result returned by enrichment operations
9
+ */
10
+ export interface CanonicalEmail {
11
+ /** The found business email, or null if not found */
12
+ business_email: string | null;
13
+ /** Which provider found the email */
14
+ business_email_source: string | null;
15
+ /** Whether the email was verified */
16
+ business_email_verified: boolean;
17
+ /** Confidence score (0-100) */
18
+ business_email_confidence?: number;
19
+ /** ISO timestamp of when the check was performed */
20
+ last_checked_at: string;
21
+ /** Status for debugging */
22
+ status?: string;
23
+ }
24
+ /**
25
+ * Raw result from a provider before normalization
26
+ */
27
+ export interface ProviderResult {
28
+ email?: string | null;
29
+ verified?: boolean;
30
+ score?: number;
31
+ confidence?: number;
32
+ }
33
+ /**
34
+ * Provider function signature
35
+ */
36
+ export type ProviderFunc = (candidate: EnrichmentCandidate) => Promise<ProviderResult | null>;
37
+ /**
38
+ * Input candidate for enrichment - flexible to accept various naming conventions
39
+ */
40
+ export interface EnrichmentCandidate {
41
+ firstName?: string;
42
+ first_name?: string;
43
+ first?: string;
44
+ lastName?: string;
45
+ last_name?: string;
46
+ last?: string;
47
+ name?: string;
48
+ fullName?: string;
49
+ full_name?: string;
50
+ company?: string;
51
+ currentCompany?: string;
52
+ organization?: string;
53
+ org?: string;
54
+ domain?: string;
55
+ companyDomain?: string;
56
+ company_domain?: string;
57
+ linkedinUsername?: string;
58
+ linkedin_username?: string;
59
+ linkedinUrl?: string;
60
+ linkedin_url?: string;
61
+ linkedinId?: string;
62
+ linkedin_id?: string;
63
+ title?: string;
64
+ currentRole?: string;
65
+ current_role?: string;
66
+ }
67
+ /**
68
+ * Hunter.io provider configuration
69
+ */
70
+ export interface HunterConfig {
71
+ apiKey: string;
72
+ }
73
+ /**
74
+ * Apollo.io provider configuration
75
+ */
76
+ export interface ApolloConfig {
77
+ apiKey: string;
78
+ }
79
+ /**
80
+ * SmartProspect/Smartlead provider configuration
81
+ */
82
+ export interface SmartProspectConfig {
83
+ apiToken: string;
84
+ apiUrl?: string;
85
+ }
86
+ /**
87
+ * LinkedIn Data Dump provider configuration
88
+ */
89
+ export interface LddConfig {
90
+ apiUrl: string;
91
+ apiToken: string;
92
+ }
93
+ /**
94
+ * Dropcontact provider configuration
95
+ */
96
+ export interface DropcontactConfig {
97
+ apiKey: string;
98
+ }
99
+ /**
100
+ * Email construction provider configuration (no API key needed)
101
+ */
102
+ export interface ConstructConfig {
103
+ /** Maximum email pattern attempts (default: 8) */
104
+ maxAttempts?: number;
105
+ /** Timeout for MX verification in ms (default: 5000) */
106
+ timeoutMs?: number;
107
+ }
108
+ /**
109
+ * All provider configurations
110
+ */
111
+ export interface ProvidersConfig {
112
+ construct?: ConstructConfig;
113
+ ldd?: LddConfig;
114
+ smartprospect?: SmartProspectConfig;
115
+ hunter?: HunterConfig;
116
+ apollo?: ApolloConfig;
117
+ dropcontact?: DropcontactConfig;
118
+ }
119
+ /**
120
+ * Options for enrichment operations
121
+ */
122
+ export interface EnrichmentOptions {
123
+ /** Maximum cost per email enrichment in USD (default: Infinity) */
124
+ maxCostPerEmail?: number;
125
+ /** Minimum confidence threshold 0-100 (default: 0) */
126
+ confidenceThreshold?: number;
127
+ /** Provider order (default: ['construct', 'ldd', 'smartprospect', 'hunter', 'apollo', 'dropcontact']) */
128
+ providerOrder?: ProviderName[];
129
+ /** Retry delay in ms on transient errors (default: 200) */
130
+ retryMs?: number;
131
+ }
132
+ /**
133
+ * Options for batch enrichment
134
+ */
135
+ export interface BatchEnrichmentOptions extends EnrichmentOptions {
136
+ /** Batch size for parallel processing (default: 50) */
137
+ batchSize?: number;
138
+ /** Delay between batches in ms (default: 200) */
139
+ delayMs?: number;
140
+ }
141
+ /**
142
+ * Cache adapter interface - consumers provide their own caching implementation
143
+ */
144
+ export interface CacheAdapter {
145
+ /** Get cached result for an email */
146
+ get: (email: string) => Promise<CanonicalEmail | null>;
147
+ /** Set cached result for an email */
148
+ set: (email: string, result: CanonicalEmail, ttlMs?: number) => Promise<void>;
149
+ }
150
+ /**
151
+ * Cost callback - called when a provider incurs a cost
152
+ */
153
+ export type CostCallback = (provider: string, costUsd: number) => void | Promise<void>;
154
+ /**
155
+ * Logger interface - consumers can provide their own logger
156
+ */
157
+ export interface EnrichmentLogger {
158
+ debug?: (message: string, context?: Record<string, unknown>) => void;
159
+ info?: (message: string, context?: Record<string, unknown>) => void;
160
+ warn?: (message: string, context?: Record<string, unknown>) => void;
161
+ error?: (message: string, context?: Record<string, unknown>) => void;
162
+ }
163
+ /**
164
+ * Configuration for createEnrichmentClient
165
+ */
166
+ export interface EnrichmentClientConfig {
167
+ /** Provider API keys and configuration */
168
+ providers: ProvidersConfig;
169
+ /** Enrichment options */
170
+ options?: EnrichmentOptions;
171
+ /** Optional cache adapter */
172
+ cache?: CacheAdapter;
173
+ /** Optional cost tracking callback */
174
+ onCost?: CostCallback;
175
+ /** Optional logger */
176
+ logger?: EnrichmentLogger;
177
+ }
178
+ /**
179
+ * Enrichment client interface
180
+ */
181
+ export interface EnrichmentClient {
182
+ /** Enrich a single candidate */
183
+ enrich: (candidate: EnrichmentCandidate) => Promise<CanonicalEmail>;
184
+ /** Enrich multiple candidates in batches */
185
+ enrichBatch: (candidates: EnrichmentCandidate[], options?: BatchEnrichmentOptions) => Promise<Array<{
186
+ candidate: EnrichmentCandidate;
187
+ } & CanonicalEmail>>;
188
+ }
189
+ /**
190
+ * Available provider names
191
+ */
192
+ export type ProviderName = 'construct' | 'ldd' | 'smartprospect' | 'hunter' | 'apollo' | 'dropcontact';
193
+ /**
194
+ * Default provider order
195
+ */
196
+ export declare const DEFAULT_PROVIDER_ORDER: ProviderName[];
197
+ /**
198
+ * Provider costs in USD per lookup
199
+ */
200
+ export declare const PROVIDER_COSTS: Record<ProviderName, number>;
201
+ /**
202
+ * Email verification result
203
+ */
204
+ export interface VerificationResult {
205
+ /** Whether the email is valid */
206
+ valid: boolean | null;
207
+ /** Confidence score 0-100 */
208
+ confidence: number;
209
+ /** Reason for the result */
210
+ reason?: 'valid' | 'invalid' | 'syntax' | 'mx_missing' | 'disposable' | 'role_account' | 'catch_all' | 'timeout' | 'error';
211
+ /** Whether this is a catch-all domain */
212
+ isCatchAll: boolean;
213
+ /** Whether this is a role account (info@, support@, etc.) */
214
+ isRoleAccount: boolean;
215
+ /** Whether this is a disposable email */
216
+ isDisposable: boolean;
217
+ /** MX records found */
218
+ mxRecords?: string[];
219
+ }
220
+ export interface SmartProspectCompany {
221
+ name: string;
222
+ website: string;
223
+ }
224
+ export interface SmartProspectContact {
225
+ id: string;
226
+ firstName: string;
227
+ lastName: string;
228
+ fullName: string;
229
+ title: string;
230
+ company: SmartProspectCompany;
231
+ department: string[];
232
+ level: string;
233
+ industry: string;
234
+ subIndustry: string;
235
+ companyHeadCount: string;
236
+ companyRevenue: string;
237
+ country: string;
238
+ state: string;
239
+ city: string;
240
+ email: string;
241
+ emailSource?: string;
242
+ linkedin: string;
243
+ emailDeliverability: number;
244
+ address: string;
245
+ status?: string;
246
+ verificationStatus?: string;
247
+ catchAllStatus?: string;
248
+ }
249
+ export interface SmartProspectSearchFilters {
250
+ name?: string[];
251
+ firstName?: string[];
252
+ lastName?: string[];
253
+ title?: string[];
254
+ company?: string[];
255
+ domain?: string[];
256
+ department?: string[];
257
+ level?: string[];
258
+ industry?: string[];
259
+ country?: string[];
260
+ state?: string[];
261
+ city?: string[];
262
+ companyHeadCount?: string[];
263
+ companyRevenue?: string[];
264
+ dontDisplayOwnedContact?: boolean;
265
+ limit?: number;
266
+ titleExactMatch?: boolean;
267
+ scroll_id?: string;
268
+ }
269
+ export interface SmartProspectSearchResponse {
270
+ success: boolean;
271
+ message: string;
272
+ data: {
273
+ list: SmartProspectContact[];
274
+ scroll_id?: string;
275
+ filter_id?: number;
276
+ total_count: number;
277
+ };
278
+ }
279
+ export interface SmartProspectFetchResponse {
280
+ success: boolean;
281
+ message: string;
282
+ data: {
283
+ list: SmartProspectContact[];
284
+ total_count: number;
285
+ metrics: {
286
+ totalContacts: number;
287
+ totalEmails: number;
288
+ noEmailFound: number;
289
+ invalidEmails: number;
290
+ catchAllEmails: number;
291
+ verifiedEmails: number;
292
+ completed: number;
293
+ };
294
+ leads_found: number;
295
+ email_fetched: number;
296
+ verification_status_list: string[];
297
+ };
298
+ }
299
+ export interface LddProfileEmail {
300
+ email_address: string;
301
+ email_type?: string | null;
302
+ }
303
+ export interface LddProfilePhone {
304
+ phone_number: string;
305
+ phone_type?: string | null;
306
+ }
307
+ export interface LddProfileData {
308
+ source_record_id: string;
309
+ linkedin_profile_url?: string | null;
310
+ linkedin_id?: string | null;
311
+ linkedin_username?: string | null;
312
+ first_name?: string | null;
313
+ last_name?: string | null;
314
+ full_name?: string | null;
315
+ profile_headline?: string | null;
316
+ profile_summary?: string | null;
317
+ profile_location?: string | null;
318
+ emails: LddProfileEmail[];
319
+ phones: LddProfilePhone[];
320
+ }
321
+ export type LddApiResponse = {
322
+ success: true;
323
+ data: LddProfileData;
324
+ } | {
325
+ success: false;
326
+ error: string;
327
+ message: string;
328
+ statusCode?: number;
329
+ };
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ /**
3
+ * Email Enrichment Types
4
+ *
5
+ * Core types for the email enrichment module. These types are designed to be
6
+ * stateless - consumers pass their own API keys and configuration.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.PROVIDER_COSTS = exports.DEFAULT_PROVIDER_ORDER = void 0;
10
+ /**
11
+ * Default provider order
12
+ */
13
+ exports.DEFAULT_PROVIDER_ORDER = [
14
+ 'construct',
15
+ 'ldd',
16
+ 'smartprospect',
17
+ 'hunter',
18
+ 'apollo',
19
+ 'dropcontact',
20
+ ];
21
+ /**
22
+ * Provider costs in USD per lookup
23
+ */
24
+ exports.PROVIDER_COSTS = {
25
+ construct: 0,
26
+ ldd: 0,
27
+ smartprospect: 0.01,
28
+ hunter: 0.005,
29
+ apollo: 0,
30
+ dropcontact: 0.01,
31
+ };
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Disposable Email Domain Detection
3
+ *
4
+ * Detects disposable/temporary email domains (Mailinator, Guerrillamail, etc.)
5
+ * that should be filtered out when enriching emails.
6
+ */
7
+ /**
8
+ * Set of known disposable email domains (600+)
9
+ */
10
+ export declare const DISPOSABLE_DOMAINS: Set<string>;
11
+ /**
12
+ * Check if an email is from a disposable domain
13
+ *
14
+ * @param email - Email address to check
15
+ * @returns true if the email is from a disposable domain
16
+ */
17
+ export declare function isDisposableEmail(email: string): boolean;
18
+ /**
19
+ * Check if a domain is a disposable email domain
20
+ *
21
+ * @param domain - Domain to check
22
+ * @returns true if the domain is a disposable email domain
23
+ */
24
+ export declare function isDisposableDomain(domain: string): boolean;