linkedin-secret-sauce 0.5.0 → 0.6.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.
@@ -0,0 +1,239 @@
1
+ /**
2
+ * Contact Matching Utilities
3
+ *
4
+ * Matches contacts between LinkedIn Sales Navigator and SmartProspect
5
+ * to find the same person across both platforms.
6
+ */
7
+ import type { SmartProspectContact, SmartProspectConfig, SmartProspectFetchResponse } from './types';
8
+ import { type SmartProspectClient } from './providers/smartprospect';
9
+ /**
10
+ * LinkedIn Sales Navigator contact (simplified from API response)
11
+ */
12
+ export interface LinkedInContact {
13
+ /** LinkedIn member URN (e.g., "urn:li:member:1044675597") */
14
+ objectUrn?: string;
15
+ /** Sales Nav entity URN */
16
+ entityUrn?: string;
17
+ firstName: string;
18
+ lastName: string;
19
+ fullName?: string;
20
+ /** Geographic region (e.g., "Sofia, Sofia City, Bulgaria") */
21
+ geoRegion?: string;
22
+ /** Current positions array */
23
+ currentPositions?: Array<{
24
+ companyName?: string;
25
+ title?: string;
26
+ companyUrn?: string;
27
+ companyUrnResolutionResult?: {
28
+ name?: string;
29
+ website?: string;
30
+ industry?: string;
31
+ location?: string;
32
+ };
33
+ }>;
34
+ /** Profile picture */
35
+ profilePictureDisplayImage?: {
36
+ rootUrl?: string;
37
+ artifacts?: Array<{
38
+ fileIdentifyingUrlPathSegment?: string;
39
+ }>;
40
+ };
41
+ }
42
+ /**
43
+ * Match result with confidence score
44
+ */
45
+ export interface MatchResult {
46
+ /** The matched SmartProspect contact */
47
+ smartProspectContact: SmartProspectContact;
48
+ /** The LinkedIn contact that was matched */
49
+ linkedInContact: LinkedInContact;
50
+ /** Match confidence score (0-100) */
51
+ confidence: number;
52
+ /** Which fields matched */
53
+ matchedFields: string[];
54
+ /** Match quality classification */
55
+ quality: 'exact' | 'high' | 'medium' | 'low' | 'none';
56
+ }
57
+ /**
58
+ * Options for matching
59
+ */
60
+ export interface MatchOptions {
61
+ /** Minimum confidence threshold (default: 50) */
62
+ minConfidence?: number;
63
+ /** Whether to use fuzzy matching for names (default: true) */
64
+ fuzzyNames?: boolean;
65
+ /** Whether to use fuzzy matching for company names (default: true) */
66
+ fuzzyCompany?: boolean;
67
+ }
68
+ /**
69
+ * Calculate match confidence between a LinkedIn contact and SmartProspect contact
70
+ */
71
+ export declare function calculateMatchConfidence(linkedin: LinkedInContact, smartprospect: SmartProspectContact, options?: MatchOptions): {
72
+ confidence: number;
73
+ matchedFields: string[];
74
+ };
75
+ /**
76
+ * Classify match quality based on confidence and matched fields
77
+ */
78
+ export declare function classifyMatchQuality(confidence: number, matchedFields: string[]): 'exact' | 'high' | 'medium' | 'low' | 'none';
79
+ /**
80
+ * Find the best matching SmartProspect contact for a LinkedIn contact
81
+ */
82
+ export declare function findBestMatch(linkedInContact: LinkedInContact, smartProspectContacts: SmartProspectContact[], options?: MatchOptions): MatchResult | null;
83
+ /**
84
+ * Match multiple LinkedIn contacts to SmartProspect contacts
85
+ */
86
+ export declare function matchContacts(linkedInContacts: LinkedInContact[], smartProspectContacts: SmartProspectContact[], options?: MatchOptions): MatchResult[];
87
+ /**
88
+ * Build SmartProspect search filters from a LinkedIn contact
89
+ * This helps you search SmartProspect for a specific LinkedIn contact
90
+ */
91
+ export declare function buildSmartProspectFiltersFromLinkedIn(linkedInContact: LinkedInContact): {
92
+ firstName: string[];
93
+ lastName: string[];
94
+ companyName?: string[];
95
+ title?: string[];
96
+ country?: string[];
97
+ };
98
+ /**
99
+ * Parse LinkedIn Sales Navigator API response elements into LinkedInContact array
100
+ */
101
+ export declare function parseLinkedInSearchResponse(elements: Array<Record<string, unknown>>): LinkedInContact[];
102
+ /**
103
+ * Result of enriching a LinkedIn contact via SmartProspect
104
+ */
105
+ export interface LinkedInEnrichmentResult {
106
+ /** Whether enrichment was successful */
107
+ success: boolean;
108
+ /** The original LinkedIn contact */
109
+ linkedInContact: LinkedInContact;
110
+ /** The matched SmartProspect contact (if found) */
111
+ matchedContact: SmartProspectContact | null;
112
+ /** Match confidence score (0-100) */
113
+ matchConfidence: number;
114
+ /** Match quality classification */
115
+ matchQuality: 'exact' | 'high' | 'medium' | 'low' | 'none';
116
+ /** Which fields matched */
117
+ matchedFields: string[];
118
+ /** Enriched email (if fetched) */
119
+ email: string | null;
120
+ /** Email deliverability score (0-1) */
121
+ emailDeliverability: number;
122
+ /** Email verification status */
123
+ verificationStatus: string | null;
124
+ /** All candidate contacts found in SmartProspect */
125
+ allCandidates: SmartProspectContact[];
126
+ /** Total candidates found in search */
127
+ totalCandidatesFound: number;
128
+ /** Error message if failed */
129
+ error?: string;
130
+ }
131
+ /**
132
+ * Options for LinkedIn contact enrichment
133
+ */
134
+ export interface LinkedInEnrichmentOptions {
135
+ /** Minimum match confidence to consider (default: 60) */
136
+ minConfidence?: number;
137
+ /** Whether to auto-fetch email if good match found (default: true) - COSTS CREDITS */
138
+ autoFetch?: boolean;
139
+ /** Whether to use fuzzy name matching (default: true) */
140
+ fuzzyNames?: boolean;
141
+ /** Whether to use fuzzy company matching (default: true) */
142
+ fuzzyCompany?: boolean;
143
+ /** Search limit - how many candidates to retrieve (default: 25) */
144
+ searchLimit?: number;
145
+ /** Whether to include company name in search (default: true) */
146
+ includeCompany?: boolean;
147
+ /** Whether to include location in search (default: false) */
148
+ includeLocation?: boolean;
149
+ }
150
+ /**
151
+ * Enrich a LinkedIn Sales Navigator contact using SmartProspect
152
+ *
153
+ * This is the main function consumers should use. It:
154
+ * 1. Takes a LinkedIn contact from Sales Navigator search results
155
+ * 2. Searches SmartProspect for matching candidates
156
+ * 3. Uses intelligent matching to find the exact same person
157
+ * 4. Optionally fetches their verified email (costs credits)
158
+ *
159
+ * @example
160
+ * ```ts
161
+ * import { enrichLinkedInContact } from 'linkedin-secret-sauce';
162
+ *
163
+ * // From your LinkedIn Sales Nav search result
164
+ * const linkedInContact = {
165
+ * firstName: 'Valentin',
166
+ * lastName: 'Rangelov',
167
+ * geoRegion: 'Sofia, Sofia City, Bulgaria',
168
+ * currentPositions: [{
169
+ * companyName: 'Recruitica',
170
+ * title: 'Chief Technology Officer'
171
+ * }]
172
+ * };
173
+ *
174
+ * const result = await enrichLinkedInContact(linkedInContact, {
175
+ * email: process.env.SMARTLEAD_EMAIL,
176
+ * password: process.env.SMARTLEAD_PASSWORD
177
+ * });
178
+ *
179
+ * if (result.success && result.email) {
180
+ * console.log(`Found email: ${result.email}`);
181
+ * console.log(`Match confidence: ${result.matchConfidence}%`);
182
+ * console.log(`Deliverability: ${result.emailDeliverability * 100}%`);
183
+ * }
184
+ * ```
185
+ */
186
+ export declare function enrichLinkedInContact(linkedInContact: LinkedInContact, smartProspectConfig: SmartProspectConfig, options?: LinkedInEnrichmentOptions): Promise<LinkedInEnrichmentResult>;
187
+ /**
188
+ * Enrich multiple LinkedIn contacts in batch
189
+ *
190
+ * Processes contacts sequentially to avoid rate limits.
191
+ * For parallel processing, use Promise.all with rate limiting.
192
+ */
193
+ export declare function enrichLinkedInContactsBatch(linkedInContacts: LinkedInContact[], smartProspectConfig: SmartProspectConfig, options?: LinkedInEnrichmentOptions & {
194
+ /** Delay between requests in ms (default: 200) */
195
+ delayMs?: number;
196
+ /** Callback for progress updates */
197
+ onProgress?: (completed: number, total: number, result: LinkedInEnrichmentResult) => void;
198
+ }): Promise<LinkedInEnrichmentResult[]>;
199
+ /**
200
+ * Create a reusable enricher function with pre-configured SmartProspect client
201
+ *
202
+ * More efficient for multiple enrichments as it reuses the same client/token.
203
+ *
204
+ * @example
205
+ * ```ts
206
+ * const enricher = createLinkedInEnricher({
207
+ * email: process.env.SMARTLEAD_EMAIL,
208
+ * password: process.env.SMARTLEAD_PASSWORD
209
+ * });
210
+ *
211
+ * // Now use for multiple contacts
212
+ * const result1 = await enricher.enrich(contact1);
213
+ * const result2 = await enricher.enrich(contact2);
214
+ *
215
+ * // Or batch
216
+ * const results = await enricher.enrichBatch([contact1, contact2, contact3]);
217
+ * ```
218
+ */
219
+ export declare function createLinkedInEnricher(smartProspectConfig: SmartProspectConfig, defaultOptions?: LinkedInEnrichmentOptions): {
220
+ /** The underlying SmartProspect client */
221
+ client: SmartProspectClient;
222
+ /** Enrich a single LinkedIn contact */
223
+ enrich: (contact: LinkedInContact, options?: LinkedInEnrichmentOptions) => Promise<LinkedInEnrichmentResult>;
224
+ /** Enrich multiple LinkedIn contacts */
225
+ enrichBatch: (contacts: LinkedInContact[], options?: LinkedInEnrichmentOptions & {
226
+ delayMs?: number;
227
+ onProgress?: (completed: number, total: number, result: LinkedInEnrichmentResult) => void;
228
+ }) => Promise<LinkedInEnrichmentResult[]>;
229
+ /** Search SmartProspect for a LinkedIn contact without fetching (FREE) */
230
+ searchOnly: (contact: LinkedInContact, options?: {
231
+ searchLimit?: number;
232
+ includeCompany?: boolean;
233
+ }) => Promise<{
234
+ candidates: SmartProspectContact[];
235
+ bestMatch: MatchResult | null;
236
+ }>;
237
+ /** Fetch email for a specific SmartProspect contact ID (COSTS CREDITS) */
238
+ fetchEmail: (contactId: string) => Promise<SmartProspectFetchResponse>;
239
+ } | null;