linkedin-secret-sauce 0.5.1 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -30,10 +30,62 @@ export interface ProviderResult {
30
30
  score?: number;
31
31
  confidence?: number;
32
32
  }
33
+ /**
34
+ * Extended provider result that can return multiple emails
35
+ */
36
+ export interface ProviderMultiResult {
37
+ emails: Array<{
38
+ email: string;
39
+ verified?: boolean;
40
+ confidence?: number;
41
+ isCatchAll?: boolean;
42
+ metadata?: Record<string, unknown>;
43
+ }>;
44
+ }
45
+ /**
46
+ * Email type classification
47
+ */
48
+ export type EmailType = 'business' | 'personal' | 'disposable' | 'role' | 'unknown';
49
+ /**
50
+ * Individual enriched email with full metadata
51
+ */
52
+ export interface EnrichedEmail {
53
+ /** The email address */
54
+ email: string;
55
+ /** Which provider found this email */
56
+ source: ProviderName;
57
+ /** Confidence score (0-100) */
58
+ confidence: number;
59
+ /** Whether the email was verified */
60
+ verified: boolean;
61
+ /** Email type classification */
62
+ type: EmailType;
63
+ /** Whether this is a catch-all domain */
64
+ isCatchAll?: boolean;
65
+ /** ISO timestamp of when this was found */
66
+ foundAt: string;
67
+ /** Additional provider-specific metadata */
68
+ metadata?: Record<string, unknown>;
69
+ }
70
+ /**
71
+ * Result containing all found emails from all providers
72
+ */
73
+ export interface MultiEmailResult {
74
+ /** All found emails, sorted by confidence (highest first) */
75
+ emails: EnrichedEmail[];
76
+ /** The original candidate */
77
+ candidate: EnrichmentCandidate;
78
+ /** Total cost incurred across all providers */
79
+ totalCost: number;
80
+ /** List of providers that were queried */
81
+ providersQueried: ProviderName[];
82
+ /** ISO timestamp of when enrichment completed */
83
+ completedAt: string;
84
+ }
33
85
  /**
34
86
  * Provider function signature
35
87
  */
36
- export type ProviderFunc = (candidate: EnrichmentCandidate) => Promise<ProviderResult | null>;
88
+ export type ProviderFunc = (candidate: EnrichmentCandidate) => Promise<ProviderResult | ProviderMultiResult | null>;
37
89
  /**
38
90
  * Input candidate for enrichment - flexible to accept various naming conventions
39
91
  */
@@ -60,6 +112,10 @@ export interface EnrichmentCandidate {
60
112
  linkedin_url?: string;
61
113
  linkedinId?: string;
62
114
  linkedin_id?: string;
115
+ numericLinkedInId?: string;
116
+ numeric_linkedin_id?: string;
117
+ objectUrn?: string;
118
+ object_urn?: string;
63
119
  title?: string;
64
120
  currentRole?: string;
65
121
  current_role?: string;
@@ -193,12 +249,16 @@ export interface EnrichmentClientConfig {
193
249
  * Enrichment client interface
194
250
  */
195
251
  export interface EnrichmentClient {
196
- /** Enrich a single candidate */
252
+ /** Enrich a single candidate - returns first valid business email (original behavior) */
197
253
  enrich: (candidate: EnrichmentCandidate) => Promise<CanonicalEmail>;
198
- /** Enrich multiple candidates in batches */
254
+ /** Enrich multiple candidates in batches - returns first valid business email per candidate */
199
255
  enrichBatch: (candidates: EnrichmentCandidate[], options?: BatchEnrichmentOptions) => Promise<Array<{
200
256
  candidate: EnrichmentCandidate;
201
257
  } & CanonicalEmail>>;
258
+ /** Enrich a single candidate - returns ALL found emails from ALL providers */
259
+ enrichAll: (candidate: EnrichmentCandidate) => Promise<MultiEmailResult>;
260
+ /** Enrich multiple candidates - returns ALL found emails for each candidate */
261
+ enrichAllBatch: (candidates: EnrichmentCandidate[], options?: BatchEnrichmentOptions) => Promise<MultiEmailResult[]>;
202
262
  }
203
263
  /**
204
264
  * Available provider names
@@ -260,26 +320,77 @@ export interface SmartProspectContact {
260
320
  verificationStatus?: string;
261
321
  catchAllStatus?: string;
262
322
  }
323
+ /**
324
+ * SmartProspect Search Filters
325
+ *
326
+ * Comprehensive filter interface matching SmartProspect/Smartlead's actual API.
327
+ * Field names and values match their exact API structure.
328
+ */
263
329
  export interface SmartProspectSearchFilters {
330
+ /** Full name (searches across first + last) */
264
331
  name?: string[];
332
+ /** First name only */
265
333
  firstName?: string[];
334
+ /** Last name only */
266
335
  lastName?: string[];
336
+ /** Job titles to search (free text, e.g., "CEO", "Software Engineer") */
267
337
  title?: string[];
268
- company?: string[];
269
- domain?: string[];
270
- department?: string[];
271
- level?: string[];
272
- industry?: string[];
338
+ /** Whether to match titles exactly (default: false) */
339
+ titleExactMatch?: boolean;
340
+ /** Departments - must use exact API values */
341
+ department?: SmartProspectDepartment[];
342
+ /** Seniority levels - must use exact API values */
343
+ level?: SmartProspectLevel[];
344
+ /** Company names (e.g., "Google", "Microsoft") */
345
+ companyName?: string[];
346
+ /** Company domains (e.g., "google.com", "microsoft.com") */
347
+ companyDomain?: string[];
348
+ /** Industries - must use exact API values */
349
+ companyIndustry?: SmartProspectIndustry[];
350
+ /** Sub-industries - must use exact API values */
351
+ companySubIndustry?: string[];
352
+ /** Headcount ranges - must use exact API values */
353
+ companyHeadCount?: SmartProspectHeadcount[];
354
+ /** Revenue ranges - must use exact API values */
355
+ companyRevenue?: SmartProspectRevenue[];
356
+ /** Countries (e.g., "United States", "United Kingdom", "Germany") */
273
357
  country?: string[];
358
+ /** States with country (e.g., "California, United States", "Bavaria, Germany") */
274
359
  state?: string[];
360
+ /** Cities with state and country (e.g., "San Francisco, California, United States") */
275
361
  city?: string[];
276
- companyHeadCount?: string[];
277
- companyRevenue?: string[];
362
+ /** Don't include contacts already owned/in campaigns (default: true) */
278
363
  dontDisplayOwnedContact?: boolean;
364
+ /** Number of results to return (default: 25, max: 100) */
279
365
  limit?: number;
280
- titleExactMatch?: boolean;
366
+ /** Scroll ID for cursor-based pagination (from previous response) */
281
367
  scroll_id?: string;
282
368
  }
369
+ /**
370
+ * SmartProspect Department values (exact API values)
371
+ */
372
+ export type SmartProspectDepartment = 'Engineering' | 'Finance & Administration' | 'Human Resources' | 'IT & IS' | 'Marketing' | 'Operations' | 'Other' | 'Support' | 'Sales';
373
+ /**
374
+ * SmartProspect Level/Seniority values (exact API values)
375
+ */
376
+ export type SmartProspectLevel = 'Staff' | 'Manager-Level' | 'Director-Level' | 'VP-Level' | 'C-Level';
377
+ /**
378
+ * SmartProspect Headcount ranges (exact API values)
379
+ */
380
+ export type SmartProspectHeadcount = '0 - 25' | '25 - 100' | '100 - 250' | '250 - 1000' | '1K - 10K' | '10K - 50K' | '50K - 100K' | '> 100K';
381
+ /**
382
+ * SmartProspect Revenue ranges (exact API values)
383
+ */
384
+ export type SmartProspectRevenue = '$0 - 1M' | '$1 - 10M' | '$10 - 50M' | '$50 - 100M' | '$100 - 250M' | '$250 - 500M' | '$500M - 1B' | '> $1B';
385
+ /**
386
+ * SmartProspect Industry values (exact API values)
387
+ */
388
+ export type SmartProspectIndustry = 'Software & Internet' | 'Business Services' | 'Real Estate & Construction' | 'Financial Services' | 'Healthcare, Pharmaceuticals, & Biotech' | 'Retail' | 'Consumer Services' | 'Education' | 'Media & Entertainment' | 'Travel, Recreation, and Leisure' | 'Transportation & Storage' | 'Manufacturing' | 'Wholesale & Distribution' | 'Non-Profit' | 'Energy & Utilities' | 'Government' | 'Agriculture & Mining' | 'Computers & Electronics' | 'Telecommunications' | 'Other';
389
+ /**
390
+ * SmartProspect Sub-Industry values (exact API values - partial list)
391
+ * Note: This is a subset of available sub-industries. The API accepts many more.
392
+ */
393
+ export declare const SMARTPROSPECT_SUB_INDUSTRIES: readonly ["Internet", "Information Technology and Services", "Information Services", "Computer Software", "Computer & Network Security", "Computer Games", "Glass, Ceramics & Concrete", "Construction", "Commercial Real Estate", "Civil Engineering", "Building Materials", "Architecture & Planning", "Writing and Editing", "Translation and Localization", "Think Tanks", "Staffing and Recruiting", "Security and Investigations", "Public Safety", "Public Relations and Communications", "Program Development", "Professional Training & Coaching", "Market Research", "Marketing and Advertising", "Management Consulting", "Legal Services", "Law Practice", "Law Enforcement", "International Trade and Development", "Import and Export", "Human Resources", "Graphic Design", "Facilities Services", "Executive Office", "Events Services", "Environmental Services", "Design", "Business Supplies and Equipment", "Animation", "Alternative Dispute Resolution", "Outsourcing/Offshoring"];
283
394
  export interface SmartProspectSearchResponse {
284
395
  success: boolean;
285
396
  message: string;
@@ -290,6 +401,27 @@ export interface SmartProspectSearchResponse {
290
401
  total_count: number;
291
402
  };
292
403
  }
404
+ /**
405
+ * SmartProspect Location lookup response (countries, states, cities)
406
+ */
407
+ export interface SmartProspectLocationItem {
408
+ id: number;
409
+ country_name?: string;
410
+ state_name?: string;
411
+ city_name?: string;
412
+ }
413
+ export interface SmartProspectLocationResponse {
414
+ success: boolean;
415
+ message: string;
416
+ data: SmartProspectLocationItem[];
417
+ pagination: {
418
+ limit: number;
419
+ offset: number;
420
+ page: number;
421
+ count: number;
422
+ };
423
+ search: string | null;
424
+ }
293
425
  export interface SmartProspectFetchResponse {
294
426
  success: boolean;
295
427
  message: string;
@@ -308,6 +440,30 @@ export interface SmartProspectFetchResponse {
308
440
  leads_found: number;
309
441
  email_fetched: number;
310
442
  verification_status_list: string[];
443
+ /** Filter ID returned by fetch-contacts for polling */
444
+ filter_id?: string;
445
+ /** Status of the fetch operation: "pending" means still processing */
446
+ status?: string;
447
+ };
448
+ }
449
+ /**
450
+ * Response from get-contacts polling endpoint
451
+ */
452
+ export interface SmartProspectGetContactsResponse {
453
+ success: boolean;
454
+ message: string;
455
+ data: {
456
+ list: SmartProspectContact[];
457
+ total_count: number;
458
+ metrics: {
459
+ totalContacts: number;
460
+ totalEmails: number;
461
+ noEmailFound: number;
462
+ invalidEmails: number;
463
+ catchAllEmails: number;
464
+ verifiedEmails: number;
465
+ completed: number;
466
+ };
311
467
  };
312
468
  }
313
469
  export interface LddProfileEmail {
@@ -6,7 +6,7 @@
6
6
  * stateless - consumers pass their own API keys and configuration.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.PROVIDER_COSTS = exports.DEFAULT_PROVIDER_ORDER = void 0;
9
+ exports.SMARTPROSPECT_SUB_INDUSTRIES = exports.PROVIDER_COSTS = exports.DEFAULT_PROVIDER_ORDER = void 0;
10
10
  /**
11
11
  * Default provider order
12
12
  */
@@ -29,3 +29,52 @@ exports.PROVIDER_COSTS = {
29
29
  apollo: 0,
30
30
  dropcontact: 0.01,
31
31
  };
32
+ /**
33
+ * SmartProspect Sub-Industry values (exact API values - partial list)
34
+ * Note: This is a subset of available sub-industries. The API accepts many more.
35
+ */
36
+ exports.SMARTPROSPECT_SUB_INDUSTRIES = [
37
+ // Software & Internet
38
+ 'Internet',
39
+ 'Information Technology and Services',
40
+ 'Information Services',
41
+ 'Computer Software',
42
+ 'Computer & Network Security',
43
+ 'Computer Games',
44
+ // Real Estate & Construction
45
+ 'Glass, Ceramics & Concrete',
46
+ 'Construction',
47
+ 'Commercial Real Estate',
48
+ 'Civil Engineering',
49
+ 'Building Materials',
50
+ 'Architecture & Planning',
51
+ // Business Services
52
+ 'Writing and Editing',
53
+ 'Translation and Localization',
54
+ 'Think Tanks',
55
+ 'Staffing and Recruiting',
56
+ 'Security and Investigations',
57
+ 'Public Safety',
58
+ 'Public Relations and Communications',
59
+ 'Program Development',
60
+ 'Professional Training & Coaching',
61
+ 'Market Research',
62
+ 'Marketing and Advertising',
63
+ 'Management Consulting',
64
+ 'Legal Services',
65
+ 'Law Practice',
66
+ 'Law Enforcement',
67
+ 'International Trade and Development',
68
+ 'Import and Export',
69
+ 'Human Resources',
70
+ 'Graphic Design',
71
+ 'Facilities Services',
72
+ 'Executive Office',
73
+ 'Events Services',
74
+ 'Environmental Services',
75
+ 'Design',
76
+ 'Business Supplies and Equipment',
77
+ 'Animation',
78
+ 'Alternative Dispute Resolution',
79
+ 'Outsourcing/Offshoring',
80
+ ];
@@ -44,7 +44,7 @@ const linkedin_config_1 = require("./utils/linkedin-config");
44
44
  function sleep(ms) {
45
45
  return new Promise((resolve) => setTimeout(resolve, ms));
46
46
  }
47
- function isRetryableStatus(status) {
47
+ function _isRetryableStatus(status) {
48
48
  return (status === 429 ||
49
49
  status === 500 ||
50
50
  status === 502 ||
@@ -1,5 +1,4 @@
1
- import type { SalesSearchFilters } from "./types";
2
- import type { LinkedInProfile, SearchSalesResult, TypeaheadResult, SalesNavigatorProfile, Company } from "./types";
1
+ import type { SalesSearchFilters, LinkedInProfile, SearchSalesResult, TypeaheadResult, SalesNavigatorProfile, Company } from "./types";
3
2
  /**
4
3
  * Fetches a LinkedIn profile by vanity URL (public identifier).
5
4
  * Results are cached for the configured TTL (default: 15 minutes).
@@ -102,15 +102,17 @@ function parseFullProfile(rawResponse, vanity) {
102
102
  function deepFindCompanyUrn(obj, depth = 0) {
103
103
  if (!obj || depth > 3)
104
104
  return undefined;
105
- if (typeof obj === "string" && /urn:li:(?:fsd_)?company:/i.test(obj))
105
+ if (typeof obj === "string" && /urn:li:(?:fsd_)?company:/i.test(obj)) {
106
106
  return obj;
107
+ }
107
108
  if (typeof obj !== "object")
108
109
  return undefined;
109
110
  const rec = obj;
110
111
  for (const k of Object.keys(rec)) {
111
112
  const v = rec[k];
112
- if (typeof v === "string" && /urn:li:(?:fsd_)?company:/i.test(v))
113
+ if (typeof v === "string" && /urn:li:(?:fsd_)?company:/i.test(v)) {
113
114
  return v;
115
+ }
114
116
  if (v && typeof v === "object") {
115
117
  const hit = deepFindCompanyUrn(v, depth + 1);
116
118
  if (hit)
@@ -52,7 +52,7 @@ function buildVoyagerHeaders(opts) {
52
52
  "x-li-track": JSON.stringify(trackPayload),
53
53
  "sec-fetch-site": "same-origin",
54
54
  "sec-fetch-mode": "cors",
55
- referer: referer ?? exports.defaultOrigin + "/",
55
+ referer: referer ?? `${exports.defaultOrigin}/`,
56
56
  origin: exports.defaultOrigin,
57
57
  };
58
58
  }
@@ -13,22 +13,21 @@ exports.buildLeadSearchQuery = buildLeadSearchQuery;
13
13
  function stableStringify(obj) {
14
14
  if (obj === null || typeof obj !== "object")
15
15
  return JSON.stringify(obj);
16
- if (Array.isArray(obj))
17
- return "[" + obj.map((v) => stableStringify(v)).join(",") + "]";
16
+ if (Array.isArray(obj)) {
17
+ return `[${obj.map((v) => stableStringify(v)).join(",")}]`;
18
+ }
18
19
  const rec = obj;
19
20
  const keys = Object.keys(rec).sort();
20
- return ("{" +
21
- keys
22
- .map((k) => JSON.stringify(k) + ":" + stableStringify(rec[k]))
23
- .join(",") +
24
- "}");
21
+ return (`{${keys
22
+ .map((k) => `${JSON.stringify(k)}:${stableStringify(rec[k])}`)
23
+ .join(",")}}`);
25
24
  }
26
25
  function buildFilterSignature(filters, rawQuery) {
27
26
  if (rawQuery)
28
- return "rq:" + String(rawQuery).trim();
27
+ return `rq:${String(rawQuery).trim()}`;
29
28
  if (!filters)
30
29
  return undefined;
31
- return "f:" + stableStringify(filters);
30
+ return `f:${stableStringify(filters)}`;
32
31
  }
33
32
  // Temporary minimal encoder: today we include only keywords in the query structure to
34
33
  // preserve existing behavior. Once facet ids are confirmed, extend this to encode filters
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linkedin-secret-sauce",
3
- "version": "0.5.1",
3
+ "version": "0.7.1",
4
4
  "description": "Private LinkedIn Sales Navigator client with automatic cookie management",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -10,6 +10,26 @@
10
10
  "publishConfig": {
11
11
  "registry": "https://registry.npmjs.org/"
12
12
  },
13
+ "scripts": {
14
+ "dev:playground": "pnpm -C apps/playground dev",
15
+ "search": "node scripts/rg-fast.mjs",
16
+ "rg:fast": "node scripts/rg-fast.mjs",
17
+ "build": "tsc -p tsconfig.json",
18
+ "typecheck": "tsc --noEmit",
19
+ "typecheck:playground": "pnpm -C apps/playground typecheck",
20
+ "typecheck:all": "pnpm typecheck && pnpm typecheck:playground",
21
+ "lint": "eslint \"src/**/*.ts\" --max-warnings=0",
22
+ "lint:playground": "eslint \"apps/playground/src/**/*.{ts,tsx}\" \"apps/playground/server/**/*.ts\" --max-warnings=0",
23
+ "lint:all": "eslint \"src/**/*.ts\" \"apps/playground/src/**/*.{ts,tsx}\" \"apps/playground/server/**/*.ts\" --max-warnings=0",
24
+ "lint:fix": "eslint \"src/**/*.ts\" \"apps/playground/src/**/*.{ts,tsx}\" \"apps/playground/server/**/*.ts\" --fix",
25
+ "check": "pnpm typecheck:all && pnpm lint:all",
26
+ "dev": "tsc -w -p tsconfig.json",
27
+ "test": "vitest run",
28
+ "prepublishOnly": "npm run build",
29
+ "release:patch": "npm version patch && git push --follow-tags",
30
+ "release:minor": "npm version minor && git push --follow-tags",
31
+ "release:major": "npm version major && git push --follow-tags"
32
+ },
13
33
  "keywords": [
14
34
  "linkedin",
15
35
  "sales-navigator",
@@ -39,18 +59,5 @@
39
59
  "husky": "^9.0.11",
40
60
  "typescript": "^5.9.3",
41
61
  "vitest": "^1.6.0"
42
- },
43
- "scripts": {
44
- "dev:playground": "pnpm -C apps/playground dev",
45
- "search": "node scripts/rg-fast.mjs",
46
- "rg:fast": "node scripts/rg-fast.mjs",
47
- "build": "tsc -p tsconfig.json",
48
- "lint": "eslint \"src/**/*.ts\" --max-warnings=0",
49
- "lint:fix": "eslint \"src/**/*.ts\" --fix",
50
- "dev": "tsc -w -p tsconfig.json",
51
- "test": "vitest run",
52
- "release:patch": "npm version patch && git push --follow-tags",
53
- "release:minor": "npm version minor && git push --follow-tags",
54
- "release:major": "npm version major && git push --follow-tags"
55
62
  }
56
- }
63
+ }