linkedin-secret-sauce 0.3.26 → 0.3.28

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.
@@ -289,9 +289,9 @@ async function searchSalesLeads(keywords, options) {
289
289
  // Extract metadata.totalDisplayCount (LinkedIn's display string like "500K+")
290
290
  const metadataVal = rrec && 'metadata' in rrec ? rrec.metadata : undefined;
291
291
  const metadata = (metadataVal && typeof metadataVal === 'object') ? metadataVal : undefined;
292
- // Calculate hasMore: if we got a full page of results, there may be more
293
- // This is more reliable than relying on total, which is often undefined
294
- const hasMore = items.length === count;
292
+ // Calculate hasMore using LinkedIn's total count (primary) or result length (fallback)
293
+ // LinkedIn API always returns paging.total, so we use it for accurate pagination
294
+ const hasMore = paging?.total ? (start + count) < paging.total : items.length === count;
295
295
  const result = options
296
296
  ? {
297
297
  items,
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseSalesSearchResults = parseSalesSearchResults;
4
+ const json_sanitizer_1 = require("../utils/json-sanitizer");
4
5
  function parseSalesSearchResults(rawResponse) {
5
6
  const rr = rawResponse;
6
7
  const elements = Array.isArray(rr?.elements) ? rr?.elements : [];
@@ -8,13 +9,13 @@ function parseSalesSearchResults(rawResponse) {
8
9
  for (const el of elements) {
9
10
  const name = [el?.firstName, el?.lastName].filter(Boolean).join(' ').trim() || undefined;
10
11
  const res = {
11
- name,
12
- headline: (el?.summary || '').split('\n')[0]?.slice(0, 180),
12
+ name: (0, json_sanitizer_1.sanitizeForJson)(name),
13
+ headline: (0, json_sanitizer_1.sanitizeForJson)((el?.summary || '').split('\n')[0]?.slice(0, 180)),
13
14
  salesProfileUrn: el?.entityUrn,
14
15
  objectUrn: el?.objectUrn,
15
- geoRegion: el?.geoRegion,
16
- locationText: el?.geoRegion,
17
- summary: el?.summary,
16
+ geoRegion: (0, json_sanitizer_1.sanitizeForJson)(el?.geoRegion),
17
+ locationText: (0, json_sanitizer_1.sanitizeForJson)(el?.geoRegion),
18
+ summary: (0, json_sanitizer_1.sanitizeForJson)(el?.summary),
18
19
  };
19
20
  // fsdKey from URN patterns
20
21
  const urn = String(el?.entityUrn || '');
@@ -39,8 +40,8 @@ function parseSalesSearchResults(rawResponse) {
39
40
  // Current position (backward compatible - extract from first position)
40
41
  const pos = Array.isArray(el?.currentPositions) && el.currentPositions.length > 0 ? el.currentPositions[0] : undefined;
41
42
  if (pos) {
42
- res.currentRole = pos?.title;
43
- res.currentCompany = pos?.companyName;
43
+ res.currentRole = (0, json_sanitizer_1.sanitizeForJson)(pos?.title);
44
+ res.currentCompany = (0, json_sanitizer_1.sanitizeForJson)(pos?.companyName);
44
45
  // Extract company logo from companyUrnResolutionResult if available
45
46
  const companyData = pos?.companyUrnResolutionResult;
46
47
  if (companyData?.companyPictureDisplayImage) {
@@ -56,7 +57,7 @@ function parseSalesSearchResults(rawResponse) {
56
57
  res.premium = el?.premium;
57
58
  res.openLink = el?.openLink;
58
59
  res.degree = el?.degree;
59
- res.industry = el?.industry;
60
+ res.industry = (0, json_sanitizer_1.sanitizeForJson)(el?.industry);
60
61
  res.isOpenProfile = el?.isOpenProfile;
61
62
  res.memorialized = el?.memorialized;
62
63
  res.saved = el?.saved;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Sanitizes string values to ensure they can be safely JSON serialized
3
+ *
4
+ * Removes control characters (0x00-0x1F, 0x7F-0x9F) that can break JSON parsing
5
+ * when consumers try to stringify the response data.
6
+ *
7
+ * This fixes the "Unterminated string in JSON" error that occurs when LinkedIn
8
+ * returns profile/company data containing unescaped control characters.
9
+ */
10
+ export declare function sanitizeForJson(value: unknown): string | undefined;
11
+ /**
12
+ * Sanitizes all string fields in an object recursively
13
+ */
14
+ export declare function sanitizeObject<T>(obj: T): T;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sanitizeForJson = sanitizeForJson;
4
+ exports.sanitizeObject = sanitizeObject;
5
+ /**
6
+ * Sanitizes string values to ensure they can be safely JSON serialized
7
+ *
8
+ * Removes control characters (0x00-0x1F, 0x7F-0x9F) that can break JSON parsing
9
+ * when consumers try to stringify the response data.
10
+ *
11
+ * This fixes the "Unterminated string in JSON" error that occurs when LinkedIn
12
+ * returns profile/company data containing unescaped control characters.
13
+ */
14
+ function sanitizeForJson(value) {
15
+ if (value === null || value === undefined)
16
+ return undefined;
17
+ if (typeof value !== 'string')
18
+ return String(value);
19
+ // Remove ASCII control characters (0x00-0x1F) and DEL (0x7F)
20
+ // Also remove C1 control codes (0x80-0x9F)
21
+ // These characters can break JSON serialization even though JSON.stringify
22
+ // should escape them - LinkedIn sometimes returns malformed strings
23
+ return String(value)
24
+ .replace(/[\u0000-\u001F\u007F-\u009F]/g, '')
25
+ .trim();
26
+ }
27
+ /**
28
+ * Sanitizes all string fields in an object recursively
29
+ */
30
+ function sanitizeObject(obj) {
31
+ if (obj === null || obj === undefined)
32
+ return obj;
33
+ if (typeof obj === 'string') {
34
+ return sanitizeForJson(obj);
35
+ }
36
+ if (Array.isArray(obj)) {
37
+ return obj.map(item => sanitizeObject(item));
38
+ }
39
+ if (typeof obj === 'object') {
40
+ const result = {};
41
+ for (const [key, value] of Object.entries(obj)) {
42
+ result[key] = sanitizeObject(value);
43
+ }
44
+ return result;
45
+ }
46
+ return obj;
47
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linkedin-secret-sauce",
3
- "version": "0.3.26",
3
+ "version": "0.3.28",
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",