linkedin-secret-sauce 0.3.27 → 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.
@@ -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.27",
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",
@@ -10,6 +10,20 @@
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
+ "lint": "eslint \"src/**/*.ts\" --max-warnings=0",
19
+ "lint:fix": "eslint \"src/**/*.ts\" --fix",
20
+ "dev": "tsc -w -p tsconfig.json",
21
+ "test": "vitest run",
22
+ "prepublishOnly": "npm run build",
23
+ "release:patch": "npm version patch && git push --follow-tags",
24
+ "release:minor": "npm version minor && git push --follow-tags",
25
+ "release:major": "npm version major && git push --follow-tags"
26
+ },
13
27
  "keywords": [
14
28
  "linkedin",
15
29
  "sales-navigator",
@@ -39,18 +53,5 @@
39
53
  "husky": "^9.0.11",
40
54
  "typescript": "^5.9.3",
41
55
  "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
56
  }
56
- }
57
+ }