@florydev/linkedin-api-voyager 1.3.6 → 1.3.8

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.
package/README.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # LinkedIn API Voyager
2
2
 
3
+ > ⚠️ **MUDANÇA DE PACOTE:** Esta biblioteca foi renomeada e movida de `linkedin-api-voyager` para `@florydev/linkedin-api-voyager`.
4
+ > Por favor, atualize suas dependências. A versão antiga não receberá novas atualizações.
5
+
6
+ [![npm version](https://img.shields.io/npm/v/@florydev/linkedin-api-voyager.svg)](https://www.npmjs.com/package/@florydev/linkedin-api-voyager)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+
3
9
  Biblioteca TypeScript para interagir com endpoints internos do LinkedIn (Voyager). Esta não é uma API oficial.
4
10
 
5
11
  ## Instalação
@@ -81,6 +87,22 @@ const comments = await getCommentsByPostUrl(
81
87
 
82
88
  - `Client(config: { JSESSIONID: string; li_at: string })`: Configura a instância global do axios. Deve ser chamado antes de qualquer outra função.
83
89
  - `API_BASE_URL`: `https://www.linkedin.com/voyager/api`
90
+ - `linkedinSSE(topics?: LinkedInRealtimeTopicsParam)`: Abre uma conexão SSE com o realtime do LinkedIn e emite somente os eventos dos tópicos desejados.
91
+
92
+ Exemplo:
93
+
94
+ ```ts
95
+ import { Client, linkedinSSE } from "@florydev/linkedin-api-voyager";
96
+
97
+ Client({
98
+ JSESSIONID: process.env.LINKEDIN_JSESSIONID!,
99
+ li_at: process.env.LINKEDIN_LI_AT!,
100
+ });
101
+
102
+ await linkedinSSE(["Messages", "TypingIndicators"]);
103
+ ```
104
+
105
+ Tópicos disponíveis (param): keys do enum `LinkedInRealtimeTopic` (ex.: `"Messages"`, `"TypingIndicators"`, `"Conversations"`).
84
106
 
85
107
  ### Módulos Disponíveis
86
108
 
@@ -92,6 +114,14 @@ A biblioteca exporta funções dos seguintes módulos:
92
114
  - `search`: Busca de pessoas e empresas.
93
115
  - `utils`: Utilitários gerais.
94
116
 
117
+ ## Autor
118
+
119
+ **Flory Muenge Tshiteya**
120
+
121
+ - Github: [@Floryvibla](https://github.com/Floryvibla)
122
+ - LinkedIn: [Flory Muenge Tshiteya](https://www.linkedin.com/in/florymignon/)
123
+ - 🐦 X (Twitter): [@DevFlory](https://x.com/DevFlory)
124
+
95
125
  ````
96
126
 
97
127
  ### `src/user.ts`
package/lib/config.d.ts CHANGED
@@ -1,7 +1,10 @@
1
1
  import { AxiosInstance } from "axios";
2
2
  export declare const API_BASE_URL = "https://www.linkedin.com/voyager/api";
3
+ export declare let apiInstance: AxiosInstance | null;
3
4
  export declare const Client: (providedCookies: {
4
5
  JSESSIONID: string;
5
6
  li_at: string;
6
7
  }) => AxiosInstance;
7
- export declare const fetchData: (endpoint: string) => Promise<any>;
8
+ export declare const fetchData: (endpoint: string, options?: {
9
+ headers?: Record<string, string>;
10
+ }) => Promise<any>;
package/lib/config.js CHANGED
@@ -9,12 +9,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.fetchData = exports.Client = exports.API_BASE_URL = void 0;
12
+ exports.fetchData = exports.Client = exports.apiInstance = exports.API_BASE_URL = void 0;
13
13
  const axios_1 = require("axios");
14
14
  exports.API_BASE_URL = "https://www.linkedin.com/voyager/api";
15
- let apiInstance = null;
15
+ exports.apiInstance = null;
16
16
  const Client = (providedCookies) => {
17
- apiInstance = axios_1.default.create({
17
+ exports.apiInstance = axios_1.default.create({
18
18
  baseURL: exports.API_BASE_URL,
19
19
  headers: {
20
20
  "accept-language": "pt-BR,pt;q=0.9,fr-FR;q=0.8,fr;q=0.7,en-US;q=0.6,en;q=0.5",
@@ -23,14 +23,16 @@ const Client = (providedCookies) => {
23
23
  "csrf-token": `ajax:${providedCookies.JSESSIONID}`,
24
24
  },
25
25
  });
26
- return apiInstance;
26
+ return exports.apiInstance;
27
27
  };
28
28
  exports.Client = Client;
29
- const fetchData = (endpoint) => __awaiter(void 0, void 0, void 0, function* () {
30
- if (!apiInstance) {
29
+ const fetchData = (endpoint, options) => __awaiter(void 0, void 0, void 0, function* () {
30
+ if (!exports.apiInstance) {
31
31
  throw new Error("Client not initialized. Please call Client({ JSESSIONID, li_at }) first.");
32
32
  }
33
- const response = yield apiInstance.get(endpoint);
33
+ const response = yield exports.apiInstance.get(endpoint, {
34
+ headers: options === null || options === void 0 ? void 0 : options.headers,
35
+ });
34
36
  return response.data;
35
37
  });
36
38
  exports.fetchData = fetchData;
package/lib/index.d.ts CHANGED
@@ -4,3 +4,5 @@ export * from "./posts";
4
4
  export * from "./search";
5
5
  export * from "./utils";
6
6
  export * from "./config";
7
+ export * from "./message";
8
+ export * from "./types";
package/lib/index.js CHANGED
@@ -20,3 +20,5 @@ __exportStar(require("./posts"), exports);
20
20
  __exportStar(require("./search"), exports);
21
21
  __exportStar(require("./utils"), exports);
22
22
  __exportStar(require("./config"), exports);
23
+ __exportStar(require("./message"), exports);
24
+ __exportStar(require("./types"), exports);
@@ -0,0 +1 @@
1
+ export declare const getLinkedInRealtimeQueryMap: () => string;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getLinkedInRealtimeQueryMap = void 0;
4
+ const LINKEDIN_QUERY_MAP_BASE64 = `
5
+ eyAidG9waWNUb0dyYXBoUUxRdWVyeVBhcmFtcyI6IHsgImNvbnZlcnNhdGlvbnNUb3BpYyI6IHsg
6
+ InF1ZXJ5SWQiOiAidm95YWdlck1lc3NhZ2luZ0Rhc2hNZXNzZW5nZXJSZWFsdGltZURlY29yYXRp
7
+ b24uZjg1NTA0OGIzOTBiMjg2ZTUxM2Q3YjIzYzU5ZWZlZTMiLCAidmFyaWFibGVzIjoge30sICJl
8
+ eHRlbnNpb25zIjoge30gfSwgImNvbnZlcnNhdGlvbkRlbGV0ZXNUb3BpYyI6IHsgInF1ZXJ5SWQi
9
+ OiAidm95YWdlck1lc3NhZ2luZ0Rhc2hNZXNzZW5nZXJSZWFsdGltZURlY29yYXRpb24uMjgyYWJl
10
+ NWZhMWEyNDJjYjc2ODI1YzMyZGJiZmFlZGUiLCAidmFyaWFibGVzIjoge30sICJleHRlbnNpb25z
11
+ Ijoge30gfSwgIm1lc3NhZ2VSZWFjdGlvblN1bW1hcmllc1RvcGljIjogeyAicXVlcnlJZCI6ICJ2
12
+ b3lhZ2VyTWVzc2FnaW5nRGFzaE1lc3NlbmdlclJlYWx0aW1lRGVjb3JhdGlvbi44NWZmNWExYWFi
13
+ ZjdjNTJmNDBhYTg1Y2NjODRlM2JmNSIsICJ2YXJpYWJsZXMiOiB7fSwgImV4dGVuc2lvbnMiOiB7
14
+ fSB9LCAibWVzc2FnZVNlZW5SZWNlaXB0c1RvcGljIjogeyAicXVlcnlJZCI6ICJ2b3lhZ2VyTWVz
15
+ c2FnaW5nRGFzaE1lc3NlbmdlclJlYWx0aW1lRGVjb3JhdGlvbi5lMjNkMzk3MWRjODNhMTE1YjAz
16
+ NTg0Y2YyMzgxMjU2YyIsICJ2YXJpYWJsZXMiOiB7fSwgImV4dGVuc2lvbnMiOiB7fSB9LCAibWVz
17
+ c2FnZXNUb3BpYyI6IHsgInF1ZXJ5SWQiOiAidm95YWdlck1lc3NhZ2luZ0Rhc2hNZXNzZW5nZXJS
18
+ ZWFsdGltZURlY29yYXRpb24uZGIwZjFkM2Y1Mzc0N2Y0OWYzZmQ4N2IxMzlkZjllZGEiLCAidmFy
19
+ aWFibGVzIjoge30sICJleHRlbnNpb25zIjoge30gfSwgInJlcGx5U3VnZ2VzdGlvblRvcGljVjIi
20
+ OiB7ICJxdWVyeUlkIjogInZveWFnZXJNZXNzYWdpbmdEYXNoTWVzc2VuZ2VyUmVhbHRpbWVEZWNv
21
+ cmF0aW9uLjQxMjk2NGMzZjdmNWE2N2ZiMGU1NmI2YmIzYTAwMDI4IiwgInZhcmlhYmxlcyI6IHt9
22
+ LCAiZXh0ZW5zaW9ucyI6IHt9IH0sICJ0eXBpbmdJbmRpY2F0b3JzVG9waWMiOiB7ICJxdWVyeUlk
23
+ IjogInZveWFnZXJNZXNzYWdpbmdEYXNoTWVzc2VuZ2VyUmVhbHRpbWVEZWNvcmF0aW9uLjIzNGNl
24
+ MDNjZDA2MmIyNDM4ZGFlMDYwY2E4NTRhNmQyIiwgInZhcmlhYmxlcyI6IHt9LCAiZXh0ZW5zaW9u
25
+ cyI6IHt9IH0sICJyZWFjdGlvbnNUb3BpYyI6IHsgInF1ZXJ5SWQiOiAibGl2ZVZpZGVvVm95YWdl
26
+ clNvY2lhbERhc2hSZWFsdGltZURlY29yYXRpb24uYjhiMzNkZWRjYTdlZmJlMzRmMWQ3ZTg0YzNi
27
+ M2FhODEiLCAidmFyaWFibGVzIjoge30sICJleHRlbnNpb25zIjoge30gfSwgImNvbW1lbnRzVG9w
28
+ aWMiOiB7ICJxdWVyeUlkIjogImxpdmVWaWRlb1ZveWFnZXJTb2NpYWxEYXNoUmVhbHRpbWVEZWNv
29
+ cmF0aW9uLjBkMjMzMzUyZDZhYWYzNWZmMDBiOGU2N2U5Y2Q0ODU5IiwgInZhcmlhYmxlcyI6IHt9
30
+ LCAiZXh0ZW5zaW9ucyI6IHt9IH0sICJyZWFjdGlvbnNPbkNvbW1lbnRzVG9waWMiOiB7ICJxdWVy
31
+ eUlkIjogImxpdmVWaWRlb1ZveWFnZXJTb2NpYWxEYXNoUmVhbHRpbWVEZWNvcmF0aW9uLjBhMTgx
32
+ YjA1YjM3NTFmNzJhZTNlYjQ4OWI3N2UzMjQ1IiwgInZhcmlhYmxlcyI6IHt9LCAiZXh0ZW5zaW9u
33
+ cyI6IHt9IH0sICJzb2NpYWxQZXJtaXNzaW9uc1BlcnNvbmFsVG9waWMiOiB7ICJxdWVyeUlkIjog
34
+ ImxpdmVWaWRlb1ZveWFnZXJTb2NpYWxEYXNoUmVhbHRpbWVEZWNvcmF0aW9uLjE3MGJmM2JmYmNj
35
+ YTFkYTMyMmUzNGYzNGYzN2ZiOTU0IiwgInZhcmlhYmxlcyI6IHt9LCAiZXh0ZW5zaW9ucyI6IHt9
36
+ IH0sICJsaXZlVmlkZW9Qb3N0VG9waWMiOiB7ICJxdWVyeUlkIjogImxpdmVWaWRlb1ZveWFnZXJG
37
+ ZWVkRGFzaExpdmVVcGRhdGVzUmVhbHRpbWVEZWNvcmF0aW9uLjU0ZDYzNWRhMDAwOGVjZjY4NzFm
38
+ Y2Y4NDA4NWU1M2RlIiwgInZhcmlhYmxlcyI6IHt9LCAiZXh0ZW5zaW9ucyI6IHt9IH0sICJtZXNz
39
+ YWdlRHJhZnRzVG9waWMiOiB7ICJxdWVyeUlkIjogInZveWFnZXJNZXNzYWdpbmdEYXNoTWVzc2Vu
40
+ Z2VyUmVhbHRpbWVEZWNvcmF0aW9uLmZjZjdiNTRkMjU4YzI3Nzk5YTY5Mzc4NWJkNGZjYzExIiwg
41
+ InZhcmlhYmxlcyI6IHt9LCAiZXh0ZW5zaW9ucyI6IHt9IH0sICJjb252ZXJzYXRpb25EcmFmdHNU
42
+ b3BpYyI6IHsgInF1ZXJ5SWQiOiAidm95YWdlck1lc3NhZ2luZ0Rhc2hNZXNzZW5nZXJSZWFsdGlt
43
+ ZURlY29yYXRpb24uYTQzY2UxNTdkNzExNGIxYTBmOGRhNWUwMmE2MGNlMzgiLCAidmFyaWFibGVz
44
+ Ijoge30sICJleHRlbnNpb25zIjoge30gfSwgIm1lc3NhZ2VEcmFmdERlbGV0ZXNUb3BpYyI6IHsg
45
+ InF1ZXJ5SWQiOiAidm95YWdlck1lc3NhZ2luZ0Rhc2hNZXNzZW5nZXJSZWFsdGltZURlY29yYXRp
46
+ b24uZTNlNGM3MTIxODM4MzIxYTQyNzUyYjU1ZjQ4N2E3M2UiLCAidmFyaWFibGVzIjoge30sICJl
47
+ eHRlbnNpb25zIjoge30gfSwgImNvbnZlcnNhdGlvbkRyYWZ0RGVsZXRlc1RvcGljIjogeyAicXVl
48
+ cnlJZCI6ICJ2b3lhZ2VyTWVzc2FnaW5nRGFzaE1lc3NlbmdlclJlYWx0aW1lRGVjb3JhdGlvbi41
49
+ Mjg4MDM2YTJjMGU2M2Y0OWQzNGVlMzJiMTM5OTc2YyIsICJ2YXJpYWJsZXMiOiB7fSwgImV4dGVu
50
+ c2lvbnMiOiB7fSB9LCAicmVhbHRpbWVTZWFyY2hSZXN1bHRDbHVzdGVyc1RvcGljIjogeyAicXVl
51
+ cnlJZCI6ICJ2b3lhZ2VyU2VhcmNoRGFzaFJlYWx0aW1lRGVjb3JhdGlvbi4zYzhkMmNkNzMyOTg3
52
+ OTBmZWIzZDdmMzQyMWE4OGRmNCIsICJ2YXJpYWJsZXMiOiB7fSwgImV4dGVuc2lvbnMiOiB7fSB9
53
+ IH0gfQ==
54
+ `;
55
+ const getLinkedInRealtimeQueryMap = () => Buffer.from(LINKEDIN_QUERY_MAP_BASE64.replace(/\s+/g, ""), "base64").toString("utf8");
56
+ exports.getLinkedInRealtimeQueryMap = getLinkedInRealtimeQueryMap;
@@ -0,0 +1,30 @@
1
+ export declare enum LinkedInRealtimeTopic {
2
+ ConversationsBroadcast = "conversationsBroadcastTopic",
3
+ Conversations = "conversationsTopic",
4
+ ConversationDeletesBroadcast = "conversationDeletesBroadcastTopic",
5
+ ConversationDeletes = "conversationDeletesTopic",
6
+ MessageReactionSummariesBroadcast = "messageReactionSummariesBroadcastTopic",
7
+ MessageReactionSummaries = "messageReactionSummariesTopic",
8
+ MessageSeenReceiptsBroadcast = "messageSeenReceiptsBroadcastTopic",
9
+ MessageSeenReceipts = "messageSeenReceiptsTopic",
10
+ MessagesBroadcast = "messagesBroadcastTopic",
11
+ Messages = "messagesTopic",
12
+ ReplySuggestionBroadcast = "replySuggestionBroadcastTopic",
13
+ ReplySuggestionV2 = "replySuggestionTopicV2",
14
+ TypingIndicatorsBroadcast = "typingIndicatorsBroadcastTopic",
15
+ TypingIndicators = "typingIndicatorsTopic",
16
+ MessagingSecondaryPreviewBanner = "messagingSecondaryPreviewBannerTopic",
17
+ Reactions = "reactionsTopic",
18
+ Comments = "commentsTopic",
19
+ ReactionsOnComments = "reactionsOnCommentsTopic",
20
+ SocialPermissionsPersonal = "socialPermissionsPersonalTopic",
21
+ LiveVideoPost = "liveVideoPostTopic",
22
+ GeneratedJobDescriptions = "generatedJobDescriptionsTopic",
23
+ MessageDrafts = "messageDraftsTopic",
24
+ ConversationDrafts = "conversationDraftsTopic",
25
+ MessageDraftDeletes = "messageDraftDeletesTopic",
26
+ ConversationDraftDeletes = "conversationDraftDeletesTopic",
27
+ CoachStreamingResponses = "coachStreamingResponsesTopic",
28
+ RealtimeSearchResultClusters = "realtimeSearchResultClustersTopic",
29
+ MemberVerificationResultsPersonal = "memberVerificationResultsPersonalTopic"
30
+ }
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LinkedInRealtimeTopic = void 0;
4
+ var LinkedInRealtimeTopic;
5
+ (function (LinkedInRealtimeTopic) {
6
+ LinkedInRealtimeTopic["ConversationsBroadcast"] = "conversationsBroadcastTopic";
7
+ LinkedInRealtimeTopic["Conversations"] = "conversationsTopic";
8
+ LinkedInRealtimeTopic["ConversationDeletesBroadcast"] = "conversationDeletesBroadcastTopic";
9
+ LinkedInRealtimeTopic["ConversationDeletes"] = "conversationDeletesTopic";
10
+ LinkedInRealtimeTopic["MessageReactionSummariesBroadcast"] = "messageReactionSummariesBroadcastTopic";
11
+ LinkedInRealtimeTopic["MessageReactionSummaries"] = "messageReactionSummariesTopic";
12
+ LinkedInRealtimeTopic["MessageSeenReceiptsBroadcast"] = "messageSeenReceiptsBroadcastTopic";
13
+ LinkedInRealtimeTopic["MessageSeenReceipts"] = "messageSeenReceiptsTopic";
14
+ LinkedInRealtimeTopic["MessagesBroadcast"] = "messagesBroadcastTopic";
15
+ LinkedInRealtimeTopic["Messages"] = "messagesTopic";
16
+ LinkedInRealtimeTopic["ReplySuggestionBroadcast"] = "replySuggestionBroadcastTopic";
17
+ LinkedInRealtimeTopic["ReplySuggestionV2"] = "replySuggestionTopicV2";
18
+ LinkedInRealtimeTopic["TypingIndicatorsBroadcast"] = "typingIndicatorsBroadcastTopic";
19
+ LinkedInRealtimeTopic["TypingIndicators"] = "typingIndicatorsTopic";
20
+ LinkedInRealtimeTopic["MessagingSecondaryPreviewBanner"] = "messagingSecondaryPreviewBannerTopic";
21
+ LinkedInRealtimeTopic["Reactions"] = "reactionsTopic";
22
+ LinkedInRealtimeTopic["Comments"] = "commentsTopic";
23
+ LinkedInRealtimeTopic["ReactionsOnComments"] = "reactionsOnCommentsTopic";
24
+ LinkedInRealtimeTopic["SocialPermissionsPersonal"] = "socialPermissionsPersonalTopic";
25
+ LinkedInRealtimeTopic["LiveVideoPost"] = "liveVideoPostTopic";
26
+ LinkedInRealtimeTopic["GeneratedJobDescriptions"] = "generatedJobDescriptionsTopic";
27
+ LinkedInRealtimeTopic["MessageDrafts"] = "messageDraftsTopic";
28
+ LinkedInRealtimeTopic["ConversationDrafts"] = "conversationDraftsTopic";
29
+ LinkedInRealtimeTopic["MessageDraftDeletes"] = "messageDraftDeletesTopic";
30
+ LinkedInRealtimeTopic["ConversationDraftDeletes"] = "conversationDraftDeletesTopic";
31
+ LinkedInRealtimeTopic["CoachStreamingResponses"] = "coachStreamingResponsesTopic";
32
+ LinkedInRealtimeTopic["RealtimeSearchResultClusters"] = "realtimeSearchResultClustersTopic";
33
+ LinkedInRealtimeTopic["MemberVerificationResultsPersonal"] = "memberVerificationResultsPersonalTopic";
34
+ })(LinkedInRealtimeTopic || (exports.LinkedInRealtimeTopic = LinkedInRealtimeTopic = {}));
@@ -0,0 +1,8 @@
1
+ export type ParseLinkedInSSEChunkArgs = {
2
+ buffer: string;
3
+ chunk: Buffer;
4
+ topicsSet?: ReadonlySet<string>;
5
+ onEvent: (data: unknown) => void;
6
+ onError: (error: unknown) => void;
7
+ };
8
+ export declare const parseLinkedInSSEChunk: ({ buffer, chunk, topicsSet, onEvent, onError, }: ParseLinkedInSSEChunkArgs) => string;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseLinkedInSSEChunk = void 0;
4
+ const parseLinkedInSSEChunk = ({ buffer, chunk, topicsSet, onEvent, onError, }) => {
5
+ let nextBuffer = buffer + chunk.toString();
6
+ const parts = nextBuffer.split("\n\n");
7
+ nextBuffer = parts.pop() || "";
8
+ for (const part of parts) {
9
+ if (!part.trim().startsWith("data:"))
10
+ continue;
11
+ try {
12
+ const dataStr = part.replace("data:", "").trim();
13
+ const data = JSON.parse(dataStr);
14
+ if (!topicsSet) {
15
+ onEvent(data);
16
+ continue;
17
+ }
18
+ const topic = data === null || data === void 0 ? void 0 : data.topic;
19
+ if (typeof topic === "string" && topicsSet.has(topic)) {
20
+ onEvent(data);
21
+ continue;
22
+ }
23
+ const text = JSON.stringify(data);
24
+ for (const t of topicsSet) {
25
+ if (text.includes(t)) {
26
+ onEvent(data);
27
+ break;
28
+ }
29
+ }
30
+ }
31
+ catch (error) {
32
+ onError(error);
33
+ }
34
+ }
35
+ return nextBuffer;
36
+ };
37
+ exports.parseLinkedInSSEChunk = parseLinkedInSSEChunk;
@@ -0,0 +1,4 @@
1
+ import { LinkedInRealtimeTopic } from "./linkedin-realtime-topic";
2
+ export type LinkedInRealtimeTopicKey = keyof typeof LinkedInRealtimeTopic;
3
+ export type LinkedInRealtimeTopicsParam = LinkedInRealtimeTopicKey | LinkedInRealtimeTopicKey[];
4
+ export declare const createLinkedInRealtimeTopicsSet: (topics?: LinkedInRealtimeTopicsParam) => ReadonlySet<string> | undefined;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createLinkedInRealtimeTopicsSet = void 0;
4
+ const linkedin_realtime_topic_1 = require("./linkedin-realtime-topic");
5
+ const createLinkedInRealtimeTopicsSet = (topics) => {
6
+ if (!topics)
7
+ return undefined;
8
+ const list = Array.isArray(topics) ? topics : [topics];
9
+ const values = list.map((t) => linkedin_realtime_topic_1.LinkedInRealtimeTopic[t]);
10
+ return new Set(values);
11
+ };
12
+ exports.createLinkedInRealtimeTopicsSet = createLinkedInRealtimeTopicsSet;
@@ -0,0 +1,43 @@
1
+ export declare enum LinkedInRealtimeTopic {
2
+ ConversationsBroadcast = "conversationsBroadcastTopic",
3
+ Conversations = "conversationsTopic",
4
+ ConversationDeletesBroadcast = "conversationDeletesBroadcastTopic",
5
+ ConversationDeletes = "conversationDeletesTopic",
6
+ MessageReactionSummariesBroadcast = "messageReactionSummariesBroadcastTopic",
7
+ MessageReactionSummaries = "messageReactionSummariesTopic",
8
+ MessageSeenReceiptsBroadcast = "messageSeenReceiptsBroadcastTopic",
9
+ MessageSeenReceipts = "messageSeenReceiptsTopic",
10
+ MessagesBroadcast = "messagesBroadcastTopic",
11
+ Messages = "messagesTopic",
12
+ ReplySuggestionBroadcast = "replySuggestionBroadcastTopic",
13
+ ReplySuggestionV2 = "replySuggestionTopicV2",
14
+ TypingIndicatorsBroadcast = "typingIndicatorsBroadcastTopic",
15
+ TypingIndicators = "typingIndicatorsTopic",
16
+ MessagingSecondaryPreviewBanner = "messagingSecondaryPreviewBannerTopic",
17
+ Reactions = "reactionsTopic",
18
+ Comments = "commentsTopic",
19
+ ReactionsOnComments = "reactionsOnCommentsTopic",
20
+ SocialPermissionsPersonal = "socialPermissionsPersonalTopic",
21
+ LiveVideoPost = "liveVideoPostTopic",
22
+ GeneratedJobDescriptions = "generatedJobDescriptionsTopic",
23
+ MessageDrafts = "messageDraftsTopic",
24
+ ConversationDrafts = "conversationDraftsTopic",
25
+ MessageDraftDeletes = "messageDraftDeletesTopic",
26
+ ConversationDraftDeletes = "conversationDraftDeletesTopic",
27
+ CoachStreamingResponses = "coachStreamingResponsesTopic",
28
+ RealtimeSearchResultClusters = "realtimeSearchResultClustersTopic",
29
+ MemberVerificationResultsPersonal = "memberVerificationResultsPersonalTopic"
30
+ }
31
+ export type LinkedInRealtimeTopicKey = keyof typeof LinkedInRealtimeTopic;
32
+ export type LinkedInRealtimeTopicsParam = LinkedInRealtimeTopicKey | LinkedInRealtimeTopicKey[];
33
+ export declare const getLinkedInRealtimeQueryMap: () => string;
34
+ export declare const createLinkedInRealtimeTopicsSet: (topics?: LinkedInRealtimeTopicsParam) => ReadonlySet<string> | undefined;
35
+ export type ParseLinkedInSSEChunkArgs = {
36
+ buffer: string;
37
+ chunk: Buffer;
38
+ topicsSet?: ReadonlySet<string>;
39
+ onEvent: (data: unknown) => void;
40
+ onError: (error: unknown) => void;
41
+ };
42
+ export declare const parseLinkedInSSEChunk: ({ buffer, chunk, topicsSet, onEvent, onError, }: ParseLinkedInSSEChunkArgs) => string;
43
+ export declare function linkedinSSE(topics?: LinkedInRealtimeTopicsParam): Promise<void>;
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.parseLinkedInSSEChunk = exports.createLinkedInRealtimeTopicsSet = exports.getLinkedInRealtimeQueryMap = exports.LinkedInRealtimeTopic = void 0;
13
+ exports.linkedinSSE = linkedinSSE;
14
+ const config_1 = require("./config");
15
+ var LinkedInRealtimeTopic;
16
+ (function (LinkedInRealtimeTopic) {
17
+ LinkedInRealtimeTopic["ConversationsBroadcast"] = "conversationsBroadcastTopic";
18
+ LinkedInRealtimeTopic["Conversations"] = "conversationsTopic";
19
+ LinkedInRealtimeTopic["ConversationDeletesBroadcast"] = "conversationDeletesBroadcastTopic";
20
+ LinkedInRealtimeTopic["ConversationDeletes"] = "conversationDeletesTopic";
21
+ LinkedInRealtimeTopic["MessageReactionSummariesBroadcast"] = "messageReactionSummariesBroadcastTopic";
22
+ LinkedInRealtimeTopic["MessageReactionSummaries"] = "messageReactionSummariesTopic";
23
+ LinkedInRealtimeTopic["MessageSeenReceiptsBroadcast"] = "messageSeenReceiptsBroadcastTopic";
24
+ LinkedInRealtimeTopic["MessageSeenReceipts"] = "messageSeenReceiptsTopic";
25
+ LinkedInRealtimeTopic["MessagesBroadcast"] = "messagesBroadcastTopic";
26
+ LinkedInRealtimeTopic["Messages"] = "messagesTopic";
27
+ LinkedInRealtimeTopic["ReplySuggestionBroadcast"] = "replySuggestionBroadcastTopic";
28
+ LinkedInRealtimeTopic["ReplySuggestionV2"] = "replySuggestionTopicV2";
29
+ LinkedInRealtimeTopic["TypingIndicatorsBroadcast"] = "typingIndicatorsBroadcastTopic";
30
+ LinkedInRealtimeTopic["TypingIndicators"] = "typingIndicatorsTopic";
31
+ LinkedInRealtimeTopic["MessagingSecondaryPreviewBanner"] = "messagingSecondaryPreviewBannerTopic";
32
+ LinkedInRealtimeTopic["Reactions"] = "reactionsTopic";
33
+ LinkedInRealtimeTopic["Comments"] = "commentsTopic";
34
+ LinkedInRealtimeTopic["ReactionsOnComments"] = "reactionsOnCommentsTopic";
35
+ LinkedInRealtimeTopic["SocialPermissionsPersonal"] = "socialPermissionsPersonalTopic";
36
+ LinkedInRealtimeTopic["LiveVideoPost"] = "liveVideoPostTopic";
37
+ LinkedInRealtimeTopic["GeneratedJobDescriptions"] = "generatedJobDescriptionsTopic";
38
+ LinkedInRealtimeTopic["MessageDrafts"] = "messageDraftsTopic";
39
+ LinkedInRealtimeTopic["ConversationDrafts"] = "conversationDraftsTopic";
40
+ LinkedInRealtimeTopic["MessageDraftDeletes"] = "messageDraftDeletesTopic";
41
+ LinkedInRealtimeTopic["ConversationDraftDeletes"] = "conversationDraftDeletesTopic";
42
+ LinkedInRealtimeTopic["CoachStreamingResponses"] = "coachStreamingResponsesTopic";
43
+ LinkedInRealtimeTopic["RealtimeSearchResultClusters"] = "realtimeSearchResultClustersTopic";
44
+ LinkedInRealtimeTopic["MemberVerificationResultsPersonal"] = "memberVerificationResultsPersonalTopic";
45
+ })(LinkedInRealtimeTopic || (exports.LinkedInRealtimeTopic = LinkedInRealtimeTopic = {}));
46
+ const LINKEDIN_QUERY_MAP_BASE64 = "eyAidG9waWNUb0dyYXBoUUxRdWVyeVBhcmFtcyI6IHsgImNvbnZlcnNhdGlvbnNUb3BpYyI6IHsgInF1ZXJ5SWQiOiAidm95YWdlck1lc3NhZ2luZ0Rhc2hNZXNzZW5nZXJSZWFsdGltZURlY29yYXRpb24uZjg1NTA0OGIzOTBiMjg2ZTUxM2Q3YjIzYzU5ZWZlZTMiLCAidmFyaWFibGVzIjoge30sICJleHRlbnNpb25zIjoge30gfSwgImNvbnZlcnNhdGlvbkRlbGV0ZXNUb3BpYyI6IHsgInF1ZXJ5SWQiOiAidm95YWdlck1lc3NhZ2luZ0Rhc2hNZXNzZW5nZXJSZWFsdGltZURlY29yYXRpb24uMjgyYWJlNWZhMWEyNDJjYjc2ODI1YzMyZGJiZmFlZGUiLCAidmFyaWFibGVzIjoge30sICJleHRlbnNpb25zIjoge30gfSwgIm1lc3NhZ2VSZWFjdGlvblN1bW1hcmllc1RvcGljIjogeyAicXVlcnlJZCI6ICJ2b3lhZ2VyTWVzc2FnaW5nRGFzaE1lc3NlbmdlclJlYWx0aW1lRGVjb3JhdGlvbi44NWZmNWExYWFiZjdjNTJmNDBhYTg1Y2NjODRlM2JmNSIsICJ2YXJpYWJsZXMiOiB7fSwgImV4dGVuc2lvbnMiOiB7fSB9LCAibWVzc2FnZVNlZW5SZWNlaXB0c1RvcGljIjogeyAicXVlcnlJZCI6ICJ2b3lhZ2VyTWVzc2FnaW5nRGFzaE1lc3NlbmdlclJlYWx0aW1lRGVjb3JhdGlvbi5lMjNkMzk3MWRjODNhMTE1YjAzNTg0Y2YyMzgxMjU2YyIsICJ2YXJpYWJsZXMiOiB7fSwgImV4dGVuc2lvbnMiOiB7fSB9LCAibWVzc2FnZXNUb3BpYyI6IHsgInF1ZXJ5SWQiOiAidm95YWdlck1lc3NhZ2luZ0Rhc2hNZXNzZW5nZXJSZWFsdGltZURlY29yYXRpb24uZGIwZjFkM2Y1Mzc0N2Y0OWYzZmQ4N2IxMzlkZjllZGEiLCAidmFyaWFibGVzIjoge30sICJleHRlbnNpb25zIjoge30gfSwgInJlcGx5U3VnZ2VzdGlvblRvcGljVjIiOiB7ICJxdWVyeUlkIjogInZveWFnZXJNZXNzYWdpbmdEYXNoTWVzc2VuZ2VyUmVhbHRpbWVEZWNvcmF0aW9uLjQxMjk2NGMzZjdmNWE2N2ZiMGU1NmI2YmIzYTAwMDI4IiwgInZhcmlhYmxlcyI6IHt9LCAiZXh0ZW5zaW9ucyI6IHt9IH0sICJ0eXBpbmdJbmRpY2F0b3JzVG9waWMiOiB7ICJxdWVyeUlkIjogInZveWFnZXJNZXNzYWdpbmdEYXNoTWVzc2VuZ2VyUmVhbHRpbWVEZWNvcmF0aW9uLjIzNGNlMDNjZDA2MmIyNDM4ZGFlMDYwY2E4NTRhNmQyIiwgInZhcmlhYmxlcyI6IHt9LCAiZXh0ZW5zaW9ucyI6IHt9IH0sICJyZWFjdGlvbnNUb3BpYyI6IHsgInF1ZXJ5SWQiOiAibGl2ZVZpZGVvVm95YWdlclNvY2lhbERhc2hSZWFsdGltZURlY29yYXRpb24uYjhiMzNkZWRjYTdlZmJlMzRmMWQ3ZTg0YzNiM2FhODEiLCAidmFyaWFibGVzIjoge30sICJleHRlbnNpb25zIjoge30gfSwgImNvbW1lbnRzVG9waWMiOiB7ICJxdWVyeUlkIjogImxpdmVWaWRlb1ZveWFnZXJTb2NpYWxEYXNoUmVhbHRpbWVEZWNvcmF0aW9uLjBkMjMzMzUyZDZhYWYzNWZmMDBiOGU2N2U5Y2Q0ODU5IiwgInZhcmlhYmxlcyI6IHt9LCAiZXh0ZW5zaW9ucyI6IHt9IH0sICJyZWFjdGlvbnNPbkNvbW1lbnRzVG9waWMiOiB7ICJxdWVyeUlkIjogImxpdmVWaWRlb1ZveWFnZXJTb2NpYWxEYXNoUmVhbHRpbWVEZWNvcmF0aW9uLjBhMTgxYjA1YjM3NTFmNzJhZTNlYjQ4OWI3N2UzMjQ1IiwgInZhcmlhYmxlcyI6IHt9LCAiZXh0ZW5zaW9ucyI6IHt9IH0sICJzb2NpYWxQZXJtaXNzaW9uc1BlcnNvbmFsVG9waWMiOiB7ICJxdWVyeUlkIjogImxpdmVWaWRlb1ZveWFnZXJTb2NpYWxEYXNoUmVhbHRpbWVEZWNvcmF0aW9uLjE3MGJmM2JmYmNjYTFkYTMyMmUzNGYzNGYzN2ZiOTU0IiwgInZhcmlhYmxlcyI6IHt9LCAiZXh0ZW5zaW9ucyI6IHt9IH0sICJsaXZlVmlkZW9Qb3N0VG9waWMiOiB7ICJxdWVyeUlkIjogImxpdmVWaWRlb1ZveWFnZXJGZWVkRGFzaExpdmVVcGRhdGVzUmVhbHRpbWVEZWNvcmF0aW9uLjU0ZDYzNWRhMDAwOGVjZjY4NzFmY2Y4NDA4NWU1M2RlIiwgInZhcmlhYmxlcyI6IHt9LCAiZXh0ZW5zaW9ucyI6IHt9IH0sICJtZXNzYWdlRHJhZnRzVG9waWMiOiB7ICJxdWVyeUlkIjogInZveWFnZXJNZXNzYWdpbmdEYXNoTWVzc2VuZ2VyUmVhbHRpbWVEZWNvcmF0aW9uLmZjZjdiNTRkMjU4YzI3Nzk5YTY5Mzc4NWJkNGZjYzExIiwgInZhcmlhYmxlcyI6IHt9LCAiZXh0ZW5zaW9ucyI6IHt9IH0sICJjb252ZXJzYXRpb25EcmFmdHNUb3BpYyI6IHsgInF1ZXJ5SWQiOiAidm95YWdlck1lc3NhZ2luZ0Rhc2hNZXNzZW5nZXJSZWFsdGltZURlY29yYXRpb24uYTQzY2UxNTdkNzExNGIxYTBmOGRhNWUwMmE2MGNlMzgiLCAidmFyaWFibGVzIjoge30sICJleHRlbnNpb25zIjoge30gfSwgIm1lc3NhZ2VEcmFmdERlbGV0ZXNUb3BpYyI6IHsgInF1ZXJ5SWQiOiAidm95YWdlck1lc3NhZ2luZ0Rhc2hNZXNzZW5nZXJSZWFsdGltZURlY29yYXRpb24uZTNlNGM3MTIxODM4MzIxYTQyNzUyYjU1ZjQ4N2E3M2UiLCAidmFyaWFibGVzIjoge30sICJleHRlbnNpb25zIjoge30gfSwgImNvbnZlcnNhdGlvbkRyYWZ0RGVsZXRlc1RvcGljIjogeyAicXVlcnlJZCI6ICJ2b3lhZ2VyTWVzc2FnaW5nRGFzaE1lc3NlbmdlclJlYWx0aW1lRGVjb3JhdGlvbi41Mjg4MDM2YTJjMGU2M2Y0OWQzNGVlMzJiMTM5OTc2YyIsICJ2YXJpYWJsZXMiOiB7fSwgImV4dGVuc2lvbnMiOiB7fSB9LCAicmVhbHRpbWVTZWFyY2hSZXN1bHRDbHVzdGVyc1RvcGljIjogeyAicXVlcnlJZCI6ICJ2b3lhZ2VyU2VhcmNoRGFzaFJlYWx0aW1lRGVjb3JhdGlvbi4zYzhkMmNkNzMyOTg3OTBmZWIzZDdmMzQyMWE4OGRmNCIsICJ2YXJpYWJsZXMiOiB7fSwgImV4dGVuc2lvbnMiOiB7fSB9IH0gfQ==";
47
+ const getLinkedInRealtimeQueryMap = () => Buffer.from(LINKEDIN_QUERY_MAP_BASE64, "base64").toString("utf8");
48
+ exports.getLinkedInRealtimeQueryMap = getLinkedInRealtimeQueryMap;
49
+ const createLinkedInRealtimeTopicsSet = (topics) => {
50
+ if (!topics)
51
+ return undefined;
52
+ const list = Array.isArray(topics) ? topics : [topics];
53
+ return new Set(list.map((t) => LinkedInRealtimeTopic[t]));
54
+ };
55
+ exports.createLinkedInRealtimeTopicsSet = createLinkedInRealtimeTopicsSet;
56
+ const parseLinkedInSSEChunk = ({ buffer, chunk, topicsSet, onEvent, onError, }) => {
57
+ let nextBuffer = buffer + chunk.toString();
58
+ const parts = nextBuffer.split("\n\n");
59
+ nextBuffer = parts.pop() || "";
60
+ for (const part of parts) {
61
+ if (!part.trim().startsWith("data:"))
62
+ continue;
63
+ try {
64
+ const dataStr = part.replace("data:", "").trim();
65
+ const data = JSON.parse(dataStr);
66
+ if (!topicsSet) {
67
+ onEvent(data);
68
+ continue;
69
+ }
70
+ const topic = data === null || data === void 0 ? void 0 : data.topic;
71
+ if (typeof topic === "string" && topicsSet.has(topic)) {
72
+ onEvent(data);
73
+ continue;
74
+ }
75
+ const text = JSON.stringify(data);
76
+ for (const t of topicsSet)
77
+ if (text.includes(t))
78
+ onEvent(data);
79
+ }
80
+ catch (error) {
81
+ onError(error);
82
+ }
83
+ }
84
+ return nextBuffer;
85
+ };
86
+ exports.parseLinkedInSSEChunk = parseLinkedInSSEChunk;
87
+ function linkedinSSE(topics) {
88
+ return __awaiter(this, void 0, void 0, function* () {
89
+ if (!config_1.apiInstance) {
90
+ throw new Error("Client not initialized. Please call Client({ JSESSIONID, li_at }) first.");
91
+ }
92
+ const topicsSet = (0, exports.createLinkedInRealtimeTopicsSet)(topics);
93
+ const response = yield config_1.apiInstance.get("/connect?rc=1", {
94
+ baseURL: "https://www.linkedin.com/realtime",
95
+ responseType: "stream",
96
+ headers: {
97
+ Accept: "text/event-stream",
98
+ "x-li-accept": "application/vnd.linkedin.normalized+json+2.1",
99
+ "x-li-page-instance": "urn:li:page:feed_index_index;6b2b39e4-d1c7-4afd-83a6-29297d4f436b",
100
+ "x-li-query-accept": "application/graphql",
101
+ "x-li-query-map": (0, exports.getLinkedInRealtimeQueryMap)(),
102
+ "x-li-realtime-session": "401dc8e6-3c15-49e0-aa9d-7c6dec4a3318",
103
+ "x-li-recipe-accept": "application/vnd.linkedin.normalized+json+2.1",
104
+ "x-li-recipe-map": '{"inAppAlertsTopic":"com.linkedin.voyager.dash.deco.identity.notifications.InAppAlert-52","professionalEventsTopic":"com.linkedin.voyager.dash.deco.events.ProfessionalEventDetailPage-63","tabBadgeUpdateTopic":"com.linkedin.voyager.dash.deco.notifications.RealtimeBadgingItemCountsEvent-1","topCardLiveVideoTopic":"com.linkedin.voyager.dash.deco.video.TopCardLiveVideo-10"}',
105
+ "x-li-track": '{"clientVersion":"1.13.42636","mpVersion":"1.13.42636","osName":"web","timezoneOffset":-3,"timezone":"America/Sao_Paulo","deviceFormFactor":"DESKTOP","mpName":"voyager-web","displayDensity":2,"displayWidth":2880,"displayHeight":1800}',
106
+ "x-restli-protocol-version": "2.0.0",
107
+ },
108
+ });
109
+ let buffer = "";
110
+ const onEvent = (data) => console.log("data: ", JSON.stringify(data, null, 2));
111
+ const onError = (error) => console.log("error parsing part: ", error);
112
+ response.data.on("data", (chunk) => {
113
+ buffer = (0, exports.parseLinkedInSSEChunk)({
114
+ buffer,
115
+ chunk,
116
+ topicsSet,
117
+ onEvent,
118
+ onError,
119
+ });
120
+ });
121
+ });
122
+ }
@@ -0,0 +1,30 @@
1
+ import { LinkedInMessage } from "./types";
2
+ interface LinkedInConversation {
3
+ urn: string;
4
+ identifier: string;
5
+ fullName: string;
6
+ firstName: string;
7
+ lastName: string;
8
+ headline: string;
9
+ profilePicture: string | null;
10
+ lastMessage: {
11
+ text: string;
12
+ sentAt: Date;
13
+ isRead: boolean;
14
+ };
15
+ unreadCount: number;
16
+ isGroup: boolean;
17
+ participants: any[];
18
+ }
19
+ /**
20
+ * Organiza o payload bruto do messengerConversations do LinkedIn
21
+ * em uma lista de objetos limpos e tipados.
22
+ */
23
+ export declare const organizeInbox: (rawPayload: any) => LinkedInConversation[];
24
+ export declare const getMessagingInboxConversations: (input: {
25
+ mailboxUrn?: string;
26
+ identifier?: string;
27
+ queryId?: string;
28
+ }) => Promise<LinkedInConversation[]>;
29
+ export declare const getMessages: (conversationUrn: string) => Promise<LinkedInMessage[]>;
30
+ export {};
package/lib/message.js ADDED
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.getMessages = exports.getMessagingInboxConversations = exports.organizeInbox = void 0;
13
+ const config_1 = require("./config");
14
+ const user_1 = require("./user");
15
+ const utils_1 = require("./utils");
16
+ const DEFAULT_INBOX_QUERY_ID = "messengerConversations.0d5e6781bbee71c3e51c8843c6519f48";
17
+ /**
18
+ * Organiza o payload bruto do messengerConversations do LinkedIn
19
+ * em uma lista de objetos limpos e tipados.
20
+ */
21
+ const organizeInbox = (rawPayload) => {
22
+ var _a, _b;
23
+ const elements = ((_b = (_a = rawPayload === null || rawPayload === void 0 ? void 0 : rawPayload.data) === null || _a === void 0 ? void 0 : _a.messengerConversationsBySyncToken) === null || _b === void 0 ? void 0 : _b.elements) || [];
24
+ return elements.map((conv) => {
25
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
26
+ // 1. Identifica o outro participante (que não é o usuário logado)
27
+ // Geralmente o primeiro participante que não tem a URN do mailbox
28
+ const otherParticipant = ((_b = (_a = conv.conversationParticipants.find((p) => { var _a, _b; return ((_b = (_a = p.participantType) === null || _a === void 0 ? void 0 : _a.member) === null || _b === void 0 ? void 0 : _b.distance) !== "SELF"; })) === null || _a === void 0 ? void 0 : _a.participantType) === null || _b === void 0 ? void 0 : _b.member) ||
29
+ ((_d = (_c = conv.conversationParticipants[0]) === null || _c === void 0 ? void 0 : _c.participantType) === null || _d === void 0 ? void 0 : _d.member);
30
+ const memberInfo = otherParticipant;
31
+ // 2. Extrai a URN e o Identifier numérico
32
+ const conversationUrn = conv.entityUrn;
33
+ const identifier = ((_g = (_f = (_e = conversationUrn.split(":")) === null || _e === void 0 ? void 0 : _e[6]) === null || _f === void 0 ? void 0 : _f.split(",")) === null || _g === void 0 ? void 0 : _g[0]) || "";
34
+ // 3. Processa a Imagem (Pega o artifact com maior largura/qualidade)
35
+ let profilePic = null;
36
+ if ((_h = memberInfo === null || memberInfo === void 0 ? void 0 : memberInfo.profilePicture) === null || _h === void 0 ? void 0 : _h.artifacts) {
37
+ const bestArtifact = memberInfo.profilePicture.artifacts.reduce((prev, current) => {
38
+ return prev.width > current.width ? prev : current;
39
+ });
40
+ profilePic = `${memberInfo.profilePicture.rootUrl}${bestArtifact.fileIdentifyingUrlPathSegment}`;
41
+ }
42
+ // 4. Pega a última mensagem
43
+ const lastMsgElement = (_k = (_j = conv.messages) === null || _j === void 0 ? void 0 : _j.elements) === null || _k === void 0 ? void 0 : _k[0];
44
+ return {
45
+ urn: conversationUrn,
46
+ identifier: identifier,
47
+ fullName: `${((_l = memberInfo === null || memberInfo === void 0 ? void 0 : memberInfo.firstName) === null || _l === void 0 ? void 0 : _l.text) || ""} ${((_m = memberInfo === null || memberInfo === void 0 ? void 0 : memberInfo.lastName) === null || _m === void 0 ? void 0 : _m.text) || ""}`.trim(),
48
+ firstName: ((_o = memberInfo === null || memberInfo === void 0 ? void 0 : memberInfo.firstName) === null || _o === void 0 ? void 0 : _o.text) || "",
49
+ lastName: ((_p = memberInfo === null || memberInfo === void 0 ? void 0 : memberInfo.lastName) === null || _p === void 0 ? void 0 : _p.text) || "",
50
+ headline: ((_q = memberInfo === null || memberInfo === void 0 ? void 0 : memberInfo.headline) === null || _q === void 0 ? void 0 : _q.text) || "",
51
+ profilePicture: profilePic,
52
+ lastMessage: {
53
+ text: ((_r = lastMsgElement === null || lastMsgElement === void 0 ? void 0 : lastMsgElement.body) === null || _r === void 0 ? void 0 : _r.text) || "",
54
+ sentAt: new Date(conv.lastActivityAt),
55
+ isRead: conv.read,
56
+ },
57
+ unreadCount: conv.unreadCount || 0,
58
+ isGroup: conv.groupChat,
59
+ };
60
+ });
61
+ };
62
+ exports.organizeInbox = organizeInbox;
63
+ function resolveMailboxUrn(input) {
64
+ return __awaiter(this, void 0, void 0, function* () {
65
+ if (input.mailboxUrn)
66
+ return input.mailboxUrn;
67
+ if (!input.identifier)
68
+ throw new Error("mailboxUrn or identifier is required");
69
+ if (input.identifier.startsWith("urn:li:"))
70
+ return input.identifier;
71
+ const profileId = yield (0, user_1.extractProfileIdLinkedin)(input.identifier);
72
+ if (!profileId)
73
+ throw new Error("Profile not found");
74
+ return `urn:li:fsd_profile:${profileId}`;
75
+ });
76
+ }
77
+ const getMessagingInboxConversations = (input) => __awaiter(void 0, void 0, void 0, function* () {
78
+ var _a;
79
+ const mailboxUrn = yield resolveMailboxUrn(input);
80
+ const queryId = (_a = input.queryId) !== null && _a !== void 0 ? _a : DEFAULT_INBOX_QUERY_ID;
81
+ const response = yield (0, config_1.fetchData)(`/voyagerMessagingGraphQL/graphql?queryId=${queryId}&variables=(mailboxUrn:${encodeURIComponent(mailboxUrn)})`, { headers: { accept: "application/graphql" } });
82
+ const conversations = (0, exports.organizeInbox)(response);
83
+ return conversations;
84
+ });
85
+ exports.getMessagingInboxConversations = getMessagingInboxConversations;
86
+ const getMessages = (conversationUrn) => __awaiter(void 0, void 0, void 0, function* () {
87
+ var _a, _b, _c;
88
+ const response = yield (0, config_1.fetchData)(`/voyagerMessagingGraphQL/graphql?queryId=messengerMessages.5846eeb71c981f11e0134cb6626cc314&variables=(conversationUrn:${(0, utils_1.encodeLinkedinUrn)(conversationUrn)})`);
89
+ const included = (response === null || response === void 0 ? void 0 : response.included) || [];
90
+ const messageUrns = ((_c = (_b = (_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.messengerMessagesBySyncToken) === null || _c === void 0 ? void 0 : _c["*elements"]) || [];
91
+ // 1. Criamos mapas para busca rápida dentro do array 'included'
92
+ const messageMap = new Map();
93
+ const participantMap = new Map();
94
+ const mediaMap = new Map();
95
+ included.forEach((item) => {
96
+ if (item.$type === "com.linkedin.messenger.Message") {
97
+ messageMap.set(item.entityUrn, item);
98
+ }
99
+ else if (item.$type === "com.linkedin.messenger.MessagingParticipant") {
100
+ participantMap.set(item.entityUrn, item);
101
+ }
102
+ else if (item.$type === "com.linkedin.videocontent.VideoPlayMetadata") {
103
+ mediaMap.set(item.entityUrn, item);
104
+ }
105
+ // Adicione outros tipos de mídia aqui se necessário (File, Image, etc)
106
+ });
107
+ // 2. Montamos a lista final baseada na ordem do array principal (*elements)
108
+ return messageUrns
109
+ .map((urn) => {
110
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
111
+ const msg = messageMap.get(urn);
112
+ if (!msg)
113
+ return null;
114
+ const senderUrn = msg["*sender"];
115
+ const senderRaw = participantMap.get(senderUrn);
116
+ const memberInfo = (_a = senderRaw === null || senderRaw === void 0 ? void 0 : senderRaw.participantType) === null || _a === void 0 ? void 0 : _a.member;
117
+ // Processamento de Foto do Remetente
118
+ let profilePic = null;
119
+ if ((_b = memberInfo === null || memberInfo === void 0 ? void 0 : memberInfo.profilePicture) === null || _b === void 0 ? void 0 : _b.artifacts) {
120
+ const bestArtifact = memberInfo.profilePicture.artifacts.reduce((prev, curr) => (prev.width > curr.width ? prev : curr));
121
+ profilePic = `${memberInfo.profilePicture.rootUrl}${bestArtifact.fileIdentifyingUrlPathSegment}`;
122
+ }
123
+ // Processamento de Mídia (Video, Imagem, File)
124
+ let mediaContent = null;
125
+ const renderContent = (_c = msg.renderContent) === null || _c === void 0 ? void 0 : _c[0];
126
+ if (renderContent) {
127
+ // Caso seja Vídeo (URN referenciada)
128
+ if (renderContent["*video"]) {
129
+ const videoData = mediaMap.get(renderContent["*video"]);
130
+ const stream = (_f = (_e = (_d = videoData === null || videoData === void 0 ? void 0 : videoData.progressiveStreams) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.streamingLocations) === null || _f === void 0 ? void 0 : _f[0];
131
+ mediaContent = {
132
+ type: "VIDEO",
133
+ url: (stream === null || stream === void 0 ? void 0 : stream.url) || null,
134
+ thumbnail: ((_j = (_h = (_g = videoData === null || videoData === void 0 ? void 0 : videoData.thumbnail) === null || _g === void 0 ? void 0 : _g.artifacts) === null || _h === void 0 ? void 0 : _h[0]) === null || _j === void 0 ? void 0 : _j.fileIdentifyingUrlPathSegment) || null,
135
+ duration: videoData === null || videoData === void 0 ? void 0 : videoData.duration,
136
+ };
137
+ }
138
+ // Caso seja Imagem (Objeto direto)
139
+ else if (renderContent.vectorImage) {
140
+ mediaContent = {
141
+ type: "IMAGE",
142
+ url: renderContent.vectorImage.rootUrl +
143
+ (((_l = (_k = renderContent.vectorImage.artifacts) === null || _k === void 0 ? void 0 : _k[0]) === null || _l === void 0 ? void 0 : _l.fileIdentifyingUrlPathSegment) || ""),
144
+ };
145
+ }
146
+ // Caso seja Arquivo (Objeto direto)
147
+ else if (renderContent.file) {
148
+ mediaContent = {
149
+ type: "FILE",
150
+ url: renderContent.file.url,
151
+ fileName: renderContent.file.name,
152
+ };
153
+ }
154
+ else if (renderContent.audio) {
155
+ mediaContent = {
156
+ type: "AUDIO",
157
+ url: renderContent.audio.url,
158
+ duration: renderContent.audio.duration,
159
+ };
160
+ }
161
+ }
162
+ return {
163
+ id: msg.backendUrn,
164
+ text: ((_m = msg.body) === null || _m === void 0 ? void 0 : _m.text) || null,
165
+ sentAt: msg.deliveredAt,
166
+ media: mediaContent,
167
+ sender: {
168
+ urn: (senderRaw === null || senderRaw === void 0 ? void 0 : senderRaw.hostIdentityUrn) || null,
169
+ fullName: `${((_o = memberInfo === null || memberInfo === void 0 ? void 0 : memberInfo.firstName) === null || _o === void 0 ? void 0 : _o.text) || "LinkedIn User"} ${((_p = memberInfo === null || memberInfo === void 0 ? void 0 : memberInfo.lastName) === null || _p === void 0 ? void 0 : _p.text) || ""}`.trim(),
170
+ profilePicture: profilePic,
171
+ isSelf: (memberInfo === null || memberInfo === void 0 ? void 0 : memberInfo.distance) === "SELF",
172
+ },
173
+ };
174
+ })
175
+ .filter(Boolean)
176
+ .sort((a, b) => b.sentAt - a.sentAt);
177
+ });
178
+ exports.getMessages = getMessages;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const config_1 = require("./config");
4
+ const messaging_1 = require("./messaging");
5
+ const JSESSIONID = process.env.LINKEDIN_JSESSIONID;
6
+ const LI_AT = process.env.LINKEDIN_LI_AT;
7
+ const MAILBOX_URN = process.env.LINKEDIN_MAILBOX_URN;
8
+ if (!JSESSIONID || !LI_AT || !MAILBOX_URN) {
9
+ throw new Error("Missing env vars: LINKEDIN_JSESSIONID, LINKEDIN_LI_AT, LINKEDIN_MAILBOX_URN");
10
+ }
11
+ (0, config_1.Client)({ JSESSIONID, li_at: LI_AT });
12
+ (0, messaging_1.getMessagingInboxConversations)({ mailboxUrn: MAILBOX_URN })
13
+ .then((conversations) => {
14
+ console.log(JSON.stringify(conversations, null, 2));
15
+ })
16
+ .catch((error) => {
17
+ console.error(error);
18
+ });
@@ -0,0 +1,6 @@
1
+ import type { MessagingInboxConversation } from "./messaging-types";
2
+ export declare const getMessagingInboxConversations: (input: {
3
+ mailboxUrn?: string;
4
+ identifier?: string;
5
+ queryId?: string;
6
+ }) => Promise<MessagingInboxConversation[]>;
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.getMessagingInboxConversations = void 0;
13
+ const config_1 = require("./config");
14
+ const utils_1 = require("./utils");
15
+ const messaging_utils_1 = require("./messaging-utils");
16
+ const messaging_parsers_1 = require("./messaging-parsers");
17
+ const user_1 = require("./user");
18
+ const messaging_response_1 = require("./messaging-response");
19
+ const DEFAULT_INBOX_QUERY_ID = "messengerConversations.0d5e6781bbee71c3e51c8843c6519f48";
20
+ function resolveMailboxUrn(input) {
21
+ return __awaiter(this, void 0, void 0, function* () {
22
+ if (input.mailboxUrn)
23
+ return input.mailboxUrn;
24
+ if (!input.identifier)
25
+ throw new Error("mailboxUrn or identifier is required");
26
+ if (input.identifier.startsWith("urn:li:"))
27
+ return input.identifier;
28
+ const profileId = yield (0, user_1.extractProfileIdLinkedin)(input.identifier);
29
+ if (!profileId)
30
+ throw new Error("Profile not found");
31
+ return `urn:li:fsd_profile:${profileId}`;
32
+ });
33
+ }
34
+ const getMessagingInboxConversations = (input) => __awaiter(void 0, void 0, void 0, function* () {
35
+ var _a;
36
+ const mailboxUrn = yield resolveMailboxUrn(input);
37
+ const queryId = (_a = input.queryId) !== null && _a !== void 0 ? _a : DEFAULT_INBOX_QUERY_ID;
38
+ const response = yield (0, config_1.fetchData)(`/voyagerMessagingGraphQL/graphql?queryId=${queryId}&variables=(mailboxUrn:${encodeURIComponent(mailboxUrn)})`, { headers: { accept: "application/graphql" } });
39
+ const included = (0, messaging_response_1.extractIncluded)(response);
40
+ const byUrn = new Map();
41
+ for (const item of included) {
42
+ if (!(0, messaging_utils_1.isRecord)(item))
43
+ continue;
44
+ const urn = (0, messaging_utils_1.asString)(item.entityUrn);
45
+ if (urn)
46
+ byUrn.set(urn, item);
47
+ }
48
+ const elementUrns = (0, messaging_response_1.findBestElementUrns)(response, new Set(byUrn.keys()));
49
+ if (!(elementUrns === null || elementUrns === void 0 ? void 0 : elementUrns.length))
50
+ throw new Error("Inbox elements not found");
51
+ return elementUrns
52
+ .map((urn) => byUrn.get(urn))
53
+ .filter((v) => v !== undefined)
54
+ .map((thread) => (0, utils_1.resolveReferences)(thread, included))
55
+ .map((thread) => {
56
+ var _a, _b, _c;
57
+ const participantsRaw = (_a = (0, messaging_utils_1.pickFirstArray)(thread, ["participants", "conversationParticipants", "participants.elements"])) !== null && _a !== void 0 ? _a : [];
58
+ const participants = participantsRaw.map(messaging_parsers_1.parseInboxParticipant).filter((p) => Boolean(p.profileUrn || p.publicIdentifier || p.fullName));
59
+ const lastMessageAt = (0, messaging_utils_1.normalizeEpochMillis)((0, messaging_utils_1.pickFirstNumber)(thread, ["lastActivityAt", "lastActivityTime", "updatedAt", "lastMessageAt", "lastMessage.createdAt"]));
60
+ return {
61
+ threadUrn: (_b = (0, messaging_utils_1.pickFirstString)(thread, ["entityUrn", "backendUrn", "threadUrn"])) !== null && _b !== void 0 ? _b : "urn:li:unknown",
62
+ participants,
63
+ primaryParticipant: (_c = participants[0]) !== null && _c !== void 0 ? _c : null,
64
+ lastMessageText: (0, messaging_utils_1.pickFirstString)(thread, ["lastMessage.eventContent.attributedBody.text", "lastMessage.eventContent.text", "lastMessage.attributedBody.text", "lastMessage.body.text", "lastMessage.text", "snippet.text", "snippet"]),
65
+ lastMessageAt,
66
+ lastMessageAtISO: lastMessageAt ? new Date(lastMessageAt).toISOString() : null,
67
+ };
68
+ });
69
+ });
70
+ exports.getMessagingInboxConversations = getMessagingInboxConversations;
@@ -0,0 +1,2 @@
1
+ import type { MessagingInboxParticipant } from "./messaging-types";
2
+ export declare function parseInboxParticipant(participant: unknown): MessagingInboxParticipant;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseInboxParticipant = parseInboxParticipant;
4
+ const utils_1 = require("./utils");
5
+ const messaging_utils_1 = require("./messaging-utils");
6
+ function parseInboxParticipant(participant) {
7
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
8
+ const miniProfile = (_a = (0, utils_1.getNestedValue)(participant, "miniProfile")) !== null && _a !== void 0 ? _a : participant;
9
+ const firstName = (_b = (0, messaging_utils_1.pickFirstString)(miniProfile, ["firstName"])) !== null && _b !== void 0 ? _b : null;
10
+ const lastName = (_c = (0, messaging_utils_1.pickFirstString)(miniProfile, ["lastName"])) !== null && _c !== void 0 ? _c : null;
11
+ const fullName = (_e = (_d = (firstName || lastName ? `${firstName !== null && firstName !== void 0 ? firstName : ""} ${lastName !== null && lastName !== void 0 ? lastName : ""}`.trim() : null)) !== null && _d !== void 0 ? _d : (0, messaging_utils_1.pickFirstString)(miniProfile, ["fullName", "name", "title.text"])) !== null && _e !== void 0 ? _e : null;
12
+ const vectorImage = (_g = (_f = (0, utils_1.getNestedValue)(miniProfile, "picture.vectorImage")) !== null && _f !== void 0 ? _f : (0, utils_1.getNestedValue)(miniProfile, "picture.displayImageReferenceResolutionResult.vectorImage")) !== null && _g !== void 0 ? _g : (0, utils_1.getNestedValue)(participant, "image.attributes.0.detailData.nonEntityProfilePicture.vectorImage");
13
+ return {
14
+ profileUrn: (_j = (_h = (0, messaging_utils_1.pickFirstString)(miniProfile, ["entityUrn", "objectUrn"])) !== null && _h !== void 0 ? _h : (0, messaging_utils_1.pickFirstString)(participant, ["entityUrn"])) !== null && _j !== void 0 ? _j : null,
15
+ publicIdentifier: (_l = (_k = (0, messaging_utils_1.pickFirstString)(miniProfile, ["publicIdentifier"])) !== null && _k !== void 0 ? _k : (0, messaging_utils_1.pickFirstString)(participant, ["publicIdentifier"])) !== null && _l !== void 0 ? _l : null,
16
+ firstName,
17
+ lastName,
18
+ fullName,
19
+ headline: (_m = (0, messaging_utils_1.pickFirstString)(miniProfile, [
20
+ "headline",
21
+ "occupation",
22
+ "subtitle.text",
23
+ "headline.text",
24
+ ])) !== null && _m !== void 0 ? _m : null,
25
+ pictureUrl: (0, messaging_utils_1.buildVectorImageUrl)(vectorImage),
26
+ };
27
+ }
@@ -0,0 +1,2 @@
1
+ export declare function extractIncluded(response: unknown): unknown[];
2
+ export declare function findBestElementUrns(response: unknown, includedUrnSet: Set<string>): string[] | null;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractIncluded = extractIncluded;
4
+ exports.findBestElementUrns = findBestElementUrns;
5
+ const messaging_utils_1 = require("./messaging-utils");
6
+ function collectElementUrnCandidates(dataRoot) {
7
+ var _a;
8
+ const candidates = [];
9
+ const queue = [dataRoot];
10
+ while (queue.length) {
11
+ const node = queue.shift();
12
+ if (!(0, messaging_utils_1.isRecord)(node))
13
+ continue;
14
+ const rawElements = (_a = node["*elements"]) !== null && _a !== void 0 ? _a : node.elements;
15
+ if (Array.isArray(rawElements) &&
16
+ rawElements.length > 0 &&
17
+ rawElements.every((v) => typeof v === "string")) {
18
+ candidates.push(rawElements);
19
+ }
20
+ for (const value of Object.values(node))
21
+ queue.push(value);
22
+ }
23
+ return candidates;
24
+ }
25
+ function scoreCandidate(urns, includedUrnSet) {
26
+ let hits = 0;
27
+ for (const urn of urns)
28
+ if (includedUrnSet.has(urn))
29
+ hits += 1;
30
+ return hits;
31
+ }
32
+ function extractIncluded(response) {
33
+ if ((0, messaging_utils_1.isRecord)(response) && Array.isArray(response.included))
34
+ return response.included;
35
+ if ((0, messaging_utils_1.isRecord)(response) && (0, messaging_utils_1.isRecord)(response.data) && Array.isArray(response.data.included)) {
36
+ return response.data.included;
37
+ }
38
+ return [];
39
+ }
40
+ function findBestElementUrns(response, includedUrnSet) {
41
+ var _a;
42
+ const roots = [];
43
+ if ((0, messaging_utils_1.isRecord)(response) && (0, messaging_utils_1.isRecord)(response.data))
44
+ roots.push(response.data);
45
+ roots.push(response);
46
+ const allCandidates = roots.flatMap(collectElementUrnCandidates);
47
+ if (allCandidates.length === 0)
48
+ return null;
49
+ let best = null;
50
+ let bestScore = -1;
51
+ for (const candidate of allCandidates) {
52
+ const score = scoreCandidate(candidate, includedUrnSet);
53
+ if (score > bestScore) {
54
+ bestScore = score;
55
+ best = candidate;
56
+ }
57
+ }
58
+ if (best && bestScore === 0)
59
+ return (_a = allCandidates[0]) !== null && _a !== void 0 ? _a : null;
60
+ return best;
61
+ }
@@ -0,0 +1,17 @@
1
+ export interface MessagingInboxParticipant {
2
+ profileUrn: string | null;
3
+ publicIdentifier: string | null;
4
+ firstName: string | null;
5
+ lastName: string | null;
6
+ fullName: string | null;
7
+ headline: string | null;
8
+ pictureUrl: string | null;
9
+ }
10
+ export interface MessagingInboxConversation {
11
+ threadUrn: string;
12
+ participants: MessagingInboxParticipant[];
13
+ primaryParticipant: MessagingInboxParticipant | null;
14
+ lastMessageText: string | null;
15
+ lastMessageAt: number | null;
16
+ lastMessageAtISO: string | null;
17
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,11 @@
1
+ type JsonRecord = Record<string, unknown>;
2
+ export declare function isRecord(value: unknown): value is JsonRecord;
3
+ export declare function asString(value: unknown): string | null;
4
+ export declare function asNumber(value: unknown): number | null;
5
+ export declare function normalizeEpochMillis(value: unknown): number | null;
6
+ export declare function pickFirstString(obj: unknown, paths: string[]): string | null;
7
+ export declare function pickFirstNumber(obj: unknown, paths: string[]): number | null;
8
+ export declare function pickFirstArray(obj: unknown, paths: string[]): unknown[] | null;
9
+ export declare function buildVectorImageUrl(vectorImage: unknown): string | null;
10
+ export declare function findElementUrns(dataRoot: unknown): string[] | null;
11
+ export {};
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isRecord = isRecord;
4
+ exports.asString = asString;
5
+ exports.asNumber = asNumber;
6
+ exports.normalizeEpochMillis = normalizeEpochMillis;
7
+ exports.pickFirstString = pickFirstString;
8
+ exports.pickFirstNumber = pickFirstNumber;
9
+ exports.pickFirstArray = pickFirstArray;
10
+ exports.buildVectorImageUrl = buildVectorImageUrl;
11
+ exports.findElementUrns = findElementUrns;
12
+ const utils_1 = require("./utils");
13
+ function isRecord(value) {
14
+ return typeof value === "object" && value !== null && !Array.isArray(value);
15
+ }
16
+ function asString(value) {
17
+ return typeof value === "string" && value.trim().length > 0 ? value : null;
18
+ }
19
+ function asNumber(value) {
20
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
21
+ }
22
+ function normalizeEpochMillis(value) {
23
+ const num = asNumber(value);
24
+ if (num === null)
25
+ return null;
26
+ return num < 10000000000 ? num * 1000 : num;
27
+ }
28
+ function pickFirstString(obj, paths) {
29
+ for (const path of paths) {
30
+ const candidate = asString((0, utils_1.getNestedValue)(obj, path));
31
+ if (candidate)
32
+ return candidate;
33
+ }
34
+ return null;
35
+ }
36
+ function pickFirstNumber(obj, paths) {
37
+ for (const path of paths) {
38
+ const candidate = asNumber((0, utils_1.getNestedValue)(obj, path));
39
+ if (candidate !== null)
40
+ return candidate;
41
+ }
42
+ return null;
43
+ }
44
+ function pickFirstArray(obj, paths) {
45
+ for (const path of paths) {
46
+ const candidate = (0, utils_1.getNestedValue)(obj, path);
47
+ if (Array.isArray(candidate))
48
+ return candidate;
49
+ }
50
+ return null;
51
+ }
52
+ function buildVectorImageUrl(vectorImage) {
53
+ if (!isRecord(vectorImage))
54
+ return null;
55
+ const rootUrl = asString(vectorImage.rootUrl);
56
+ if (!rootUrl)
57
+ return null;
58
+ const artifacts = vectorImage.artifacts;
59
+ if (!Array.isArray(artifacts) || artifacts.length === 0)
60
+ return null;
61
+ const last = artifacts.at(-1);
62
+ if (!isRecord(last))
63
+ return null;
64
+ const seg = asString(last.fileIdentifyingUrlPathSegment);
65
+ return seg ? `${rootUrl}${seg}` : null;
66
+ }
67
+ function findElementUrns(dataRoot) {
68
+ const queue = [dataRoot];
69
+ while (queue.length) {
70
+ const node = queue.shift();
71
+ if (!isRecord(node))
72
+ continue;
73
+ const elements = node["*elements"];
74
+ if (Array.isArray(elements) && elements.every((v) => typeof v === "string")) {
75
+ return elements;
76
+ }
77
+ for (const value of Object.values(node))
78
+ queue.push(value);
79
+ }
80
+ return null;
81
+ }
@@ -0,0 +1 @@
1
+ export * from "./messaging-inbox";
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./messaging-inbox"), exports);
package/lib/teste.js CHANGED
@@ -1,15 +1,23 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  Object.defineProperty(exports, "__esModule", { value: true });
3
12
  const config_1 = require("./config");
4
- const user_1 = require("./user");
13
+ const linkedin_sse_1 = require("./linkedin-sse");
5
14
  (0, config_1.Client)({
6
- JSESSIONID: "2687703175806319775",
7
- li_at: "AQEDARgQ7uMA1d5dAAABmm_VFQcAAAGcT-gumU0Agr-WPhYEN-QPXcfx84Ct0mtL2WQqj9YrWiAR2onQlCPyIa9RWXygwj3JKVSY1elRE6DjH4y6nEE5I3NhxBpswfzbRBCIgKUYmKWeEblF1t9VeGDl",
8
- });
9
- (0, user_1.getUserMiniProfile)("wesbush")
10
- .then((profile) => {
11
- console.log("profile: ", profile);
12
- })
13
- .catch((error) => {
14
- console.log("error: ", error);
15
+ JSESSIONID: "0466411065031579456",
16
+ li_at: "AQEDAU9C-sMEobZ6AAABmgzAd04AAAGc5X6rR04Ab8DYREgT31dxDOoVSZ86b0QnMvC5LTO2hSQcC5_A8qISIL9l-DdYFs9yPYZS4osBMOkDS6Q3wpkQ5Y_Wd8piLcBsF8dNJ22XBoVYRG6w2ZjpHgxb",
15
17
  });
18
+ function start() {
19
+ return __awaiter(this, void 0, void 0, function* () {
20
+ yield (0, linkedin_sse_1.linkedinSSE)(["Messages", "TypingIndicators"]);
21
+ });
22
+ }
23
+ start();
package/lib/types.d.ts CHANGED
@@ -792,3 +792,40 @@ export type EntitySearchResult = {
792
792
  $type: string;
793
793
  };
794
794
  };
795
+ export interface LinkedInConversation {
796
+ urn: string;
797
+ identifier: string;
798
+ fullName: string;
799
+ firstName: string;
800
+ lastName: string;
801
+ headline: string;
802
+ profilePicture: string | null;
803
+ lastMessage: {
804
+ text: string;
805
+ sentAt: Date;
806
+ isRead: boolean;
807
+ };
808
+ unreadCount: number;
809
+ isGroup: boolean;
810
+ participants: any[];
811
+ }
812
+ export interface LinkedInMessage {
813
+ id: string;
814
+ text: string;
815
+ sentAt: number;
816
+ media?: {
817
+ type: "VIDEO" | "IMAGE" | "FILE" | "AUDIO";
818
+ url: string | null;
819
+ thumbnail?: string | null;
820
+ duration?: number;
821
+ fileName?: string;
822
+ } | null;
823
+ sender: {
824
+ urn: string;
825
+ fullName: string;
826
+ firstName: string;
827
+ lastName: string;
828
+ profilePicture: string | null;
829
+ isSelf: boolean;
830
+ };
831
+ }
package/lib/utils.d.ts CHANGED
@@ -20,6 +20,7 @@ interface Experience {
20
20
  time_period?: string | null;
21
21
  duration?: string | null;
22
22
  }
23
+ export declare function encodeLinkedinUrn(raw: string): string;
23
24
  export declare const getDataIncludedForEntity: (jsonData: AnyObject, entityUrn: string) => any;
24
25
  export declare function extractExperiences(jsonData: AnyObject): Experience[];
25
26
  export declare function assert(value: unknown, message?: string | Error): asserts value;
package/lib/utils.js CHANGED
@@ -24,6 +24,7 @@ exports.extractDataWithReferences = extractDataWithReferences;
24
24
  exports.debugResolvedStructure = debugResolvedStructure;
25
25
  exports.extractFieldsFromIncluded = extractFieldsFromIncluded;
26
26
  exports.mergeExtraFields = mergeExtraFields;
27
+ exports.encodeLinkedinUrn = encodeLinkedinUrn;
27
28
  exports.extractExperiences = extractExperiences;
28
29
  exports.assert = assert;
29
30
  exports.getIdFromUrn = getIdFromUrn;
@@ -212,6 +213,9 @@ function mergeExtraFields(mainData, extraData, matchKey = "companyUrn") {
212
213
  return item;
213
214
  });
214
215
  }
216
+ function encodeLinkedinUrn(raw) {
217
+ return encodeURIComponent(raw).replace(/\(/g, "%28").replace(/\)/g, "%29");
218
+ }
215
219
  const getDataIncludedForEntity = (jsonData, entityUrn) => {
216
220
  const data = jsonData === null || jsonData === void 0 ? void 0 : jsonData.included;
217
221
  if (data.length) {
package/package.json CHANGED
@@ -1,10 +1,34 @@
1
1
  {
2
2
  "name": "@florydev/linkedin-api-voyager",
3
- "version": "1.3.6",
3
+ "version": "1.3.8",
4
4
  "description": "Uma biblioteca TypeScript para interagir com a API interna do LinkedIn (Voyager)",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
7
7
  "license": "MIT",
8
+ "author": {
9
+ "name": "Flory Muenge Tshiteya",
10
+ "url": "https://github.com/Floryvibla"
11
+ },
12
+ "homepage": "https://github.com/Floryvibla/linkedin-api-voyager#readme",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/Floryvibla/linkedin-api-voyager.git"
16
+ },
17
+ "bugs": {
18
+ "url": "https://github.com/Floryvibla/linkedin-api-voyager/issues"
19
+ },
20
+ "keywords": [
21
+ "linkedin",
22
+ "api",
23
+ "voyager",
24
+ "typescript",
25
+ "scraper",
26
+ "crawler",
27
+ "nodejs",
28
+ "profile",
29
+ "company",
30
+ "search"
31
+ ],
8
32
  "files": [
9
33
  "lib/**/*"
10
34
  ],
@@ -12,6 +36,7 @@
12
36
  "build": "tsc",
13
37
  "prepare": "npm run build",
14
38
  "dev": "nodemon src/teste.ts",
39
+ "release": "npm run build && npm version patch --no-git-tag-version && npm publish --access public",
15
40
  "prepublishOnly": "npm run build"
16
41
  },
17
42
  "devDependencies": {