coffeeinabit 0.0.11 → 0.0.13

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,10 +1,14 @@
1
1
  import { humanLikeType } from './human_typing.js';
2
2
 
3
3
  export async function executeSendMessages(page, action) {
4
+ console.log('[send_messages] Starting executeSendMessages');
4
5
  const username = action.parameters?.username || action.username;
5
6
  let messages = action.parameters?.messages || action.messages;
6
7
 
8
+ console.log('[send_messages] Username:', username, 'Messages:', messages);
9
+
7
10
  if (!username || !messages) {
11
+ console.error('[send_messages] Missing username or messages');
8
12
  throw new Error('Missing username or messages for send_messages');
9
13
  }
10
14
 
@@ -13,99 +17,142 @@ export async function executeSendMessages(page, action) {
13
17
  }
14
18
 
15
19
  const profileUrl = `https://www.linkedin.com/in/${username}`;
20
+ console.log('[send_messages] Navigating to profile:', profileUrl);
16
21
  await page.goto(profileUrl, {
17
22
  waitUntil: 'load',
18
23
  timeout: Math.floor(Math.random() * 20000) + 40000
19
24
  });
25
+ console.log('[send_messages] Page loaded, URL:', page.url());
20
26
 
21
27
  await page.waitForLoadState('domcontentloaded');
22
28
  await new Promise(resolve => setTimeout(resolve, 1000));
23
29
  await page.evaluate(() => { window.scrollTo(0, 300); });
24
30
  await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 2000) + 500));
25
31
 
32
+ console.log('[send_messages] Closing all conversation bubbles');
26
33
  await closeAllConversationBubbles(page);
27
34
 
28
35
  const checkConversationOpened = async () => {
36
+ console.log('[send_messages] Checking if conversation opened');
29
37
  for (let i = 0; i < 10; i++) {
30
38
  try {
31
39
  const url = page.url();
32
- if (url.includes('/messaging')) return true;
33
- } catch (e) {}
40
+ if (url.includes('/messaging')) {
41
+ console.log('[send_messages] Conversation opened (URL check)');
42
+ return true;
43
+ }
44
+ } catch (e) {
45
+ console.log('[send_messages] Error checking URL:', e.message);
46
+ }
34
47
  try {
35
48
  const cnt = await page.locator('.msg-s-message-list-container, .msg-overlay-conversation-bubble__content-wrapper').count();
36
- if (cnt > 0) return true;
37
- } catch (e) {}
49
+ if (cnt > 0) {
50
+ console.log('[send_messages] Conversation opened (element count:', cnt, ')');
51
+ return true;
52
+ }
53
+ } catch (e) {
54
+ console.log('[send_messages] Error checking elements:', e.message);
55
+ }
38
56
  await new Promise(r => setTimeout(r, 500));
39
57
  }
58
+ console.log('[send_messages] Conversation not opened after 10 attempts');
40
59
  return false;
41
60
  };
42
61
 
43
62
  const clickStrategies = [
44
63
  async () => {
64
+ console.log('[send_messages] Strategy 1: Looking for button with text "Message"');
45
65
  try {
46
66
  const btn = page.locator('button:has-text("Message")').first();
47
67
  if (await btn.isVisible().catch(() => false)) {
68
+ console.log('[send_messages] Found Message button, clicking...');
48
69
  await btn.scrollIntoViewIfNeeded();
49
70
  await new Promise(r => setTimeout(r, 300));
50
71
  await btn.click({ timeout: 5000 });
51
72
  await new Promise(r => setTimeout(r, 800));
52
73
  return await checkConversationOpened();
74
+ } else {
75
+ console.log('[send_messages] Message button not visible');
53
76
  }
54
- } catch {}
77
+ } catch (e) {
78
+ console.log('[send_messages] Strategy 1 error:', e.message);
79
+ }
55
80
  return false;
56
81
  },
57
82
  async () => {
83
+ console.log('[send_messages] Strategy 2: Looking for button with send-privately-small icon');
58
84
  try {
59
85
  const btn = page.locator('button:has(svg[data-test-icon="send-privately-small"])').first();
60
86
  if (await btn.isVisible().catch(() => false)) {
87
+ console.log('[send_messages] Found send-privately button, clicking...');
61
88
  await btn.scrollIntoViewIfNeeded();
62
89
  await new Promise(r => setTimeout(r, 300));
63
90
  await btn.click({ timeout: 5000 });
64
91
  await new Promise(r => setTimeout(r, 800));
65
92
  return await checkConversationOpened();
93
+ } else {
94
+ console.log('[send_messages] send-privately button not visible');
66
95
  }
67
- } catch {}
96
+ } catch (e) {
97
+ console.log('[send_messages] Strategy 2 error:', e.message);
98
+ }
68
99
  return false;
69
100
  },
70
101
  async () => {
102
+ console.log('[send_messages] Strategy 3: Looking for primary button with class token');
71
103
  try {
72
104
  const classToken = 'DhBcSsKzUnyKdEOWwBJmWavDjlHFWuqygdMVO';
73
105
  const candidates = await page.locator(`button.artdeco-button--primary.${classToken}`).all();
106
+ console.log('[send_messages] Found', candidates.length, 'candidate buttons');
74
107
  for (const btn of candidates.slice(0, 3)) {
75
108
  const v = await btn.isVisible().catch(() => false);
76
109
  if (!v) continue;
110
+ console.log('[send_messages] Clicking candidate button');
77
111
  await btn.scrollIntoViewIfNeeded();
78
112
  await new Promise(r => setTimeout(r, 200));
79
113
  await btn.click({ timeout: 5000 });
80
114
  await new Promise(r => setTimeout(r, 800));
81
115
  if (await checkConversationOpened()) return true;
82
116
  }
83
- } catch {}
117
+ } catch (e) {
118
+ console.log('[send_messages] Strategy 3 error:', e.message);
119
+ }
84
120
  return false;
85
121
  },
86
122
  async () => {
123
+ console.log('[send_messages] Strategy 4: Looking for button with aria-label containing "Message"');
87
124
  try {
88
125
  const buttons = await page.locator('button[aria-label^="Message"]').all();
126
+ console.log('[send_messages] Found', buttons.length, 'buttons with Message aria-label');
89
127
  for (const btn of buttons) {
90
128
  const isVisible = await btn.isVisible().catch(() => false);
91
129
  if (!isVisible) continue;
130
+ console.log('[send_messages] Clicking Message button');
92
131
  await btn.scrollIntoViewIfNeeded();
93
132
  await new Promise(r => setTimeout(r, 300));
94
133
  await btn.click({ timeout: 5000 });
95
134
  await new Promise(r => setTimeout(r, 800));
96
135
  if (await checkConversationOpened()) return true;
97
136
  }
98
- } catch {}
137
+ } catch (e) {
138
+ console.log('[send_messages] Strategy 4 error:', e.message);
139
+ }
99
140
  return false;
100
141
  }
101
142
  ];
102
143
 
144
+ console.log('[send_messages] Trying to find and click Message button');
103
145
  let opened = false;
104
- for (const s of clickStrategies) {
105
- opened = await s();
106
- if (opened) break;
146
+ for (let i = 0; i < clickStrategies.length; i++) {
147
+ console.log('[send_messages] Trying strategy', i + 1);
148
+ opened = await clickStrategies[i]();
149
+ if (opened) {
150
+ console.log('[send_messages] Strategy', i + 1, 'succeeded, conversation opened');
151
+ break;
152
+ }
107
153
  }
108
154
  if (!opened) {
155
+ console.error('[send_messages] Failed to open conversation - could not find Message button');
109
156
  return {
110
157
  action: 'send_messages',
111
158
  result: { status: 'not_connected', message: `Could not find Message button on ${username}'s profile. This usually means you are not connected with this user on LinkedIn.` },
@@ -113,37 +160,117 @@ export async function executeSendMessages(page, action) {
113
160
  };
114
161
  }
115
162
 
163
+ console.log('[send_messages] Finding and clicking message input');
116
164
  await findAndClickMessageInput(page);
117
165
 
118
- for (const message of messages) {
166
+ console.log('[send_messages] Processing', messages.length, 'message(s)');
167
+ for (let msgIndex = 0; msgIndex < messages.length; msgIndex++) {
168
+ const message = messages[msgIndex];
169
+ console.log('[send_messages] Processing message', msgIndex + 1, 'of', messages.length, ':', message);
170
+
119
171
  await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 100) + 500));
120
172
  await new Promise(resolve => setTimeout(resolve, 200));
121
173
 
122
- const editor = page.locator('.msg-form__contenteditable[contenteditable="true"]').first();
123
- if (await editor.isVisible().catch(() => false)) {
174
+ const editor = page.locator('[aria-label="Write a message…"]').first();
175
+ console.log('[send_messages] Looking for message editor by aria-label');
176
+
177
+ let editorReady = false;
178
+ for (let attempt = 0; attempt < 5; attempt++) {
179
+ console.log('[send_messages] Editor preparation attempt', attempt + 1, 'of 5');
180
+ try {
181
+ const isVisible = await editor.isVisible({ timeout: 2000 }).catch(() => false);
182
+ console.log('[send_messages] Editor visible:', isVisible);
183
+ if (isVisible) {
184
+ console.log('[send_messages] Clicking editor');
185
+ await editor.click({ timeout: 3000, force: true });
186
+ await new Promise(r => setTimeout(r, 200));
187
+
188
+ console.log('[send_messages] Clearing and focusing editor');
189
+ await editor.evaluate((el) => {
190
+ el.focus();
191
+ el.innerHTML = '';
192
+ el.dispatchEvent(new Event('input', { bubbles: true }));
193
+ });
194
+
195
+ await new Promise(r => setTimeout(r, 150));
196
+
197
+ const isFocused = await editor.evaluate((el) => {
198
+ return document.activeElement === el;
199
+ });
200
+ console.log('[send_messages] Editor focused:', isFocused);
201
+
202
+ if (isFocused) {
203
+ editorReady = true;
204
+ console.log('[send_messages] Editor ready!');
205
+ break;
206
+ }
207
+ }
208
+ } catch (e) {
209
+ console.log('[send_messages] Error preparing editor:', e.message);
210
+ }
211
+
212
+ await new Promise(r => setTimeout(r, 300));
213
+ console.log('[send_messages] Retrying to find message input');
214
+ await findAndClickMessageInput(page);
215
+ }
216
+
217
+ if (!editorReady) {
218
+ console.warn('[send_messages] Editor not ready after 5 attempts, trying one more time');
219
+ await findAndClickMessageInput(page);
220
+ await new Promise(r => setTimeout(r, 500));
221
+ }
222
+
223
+ console.log('[send_messages] Typing message:', message);
224
+ await humanLikeType(editor, message);
225
+ await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 300) + 300));
226
+
227
+ const textTyped = await editor.evaluate((el) => {
228
+ const text = el.innerText || el.textContent || '';
229
+ return text.trim().length > 0;
230
+ });
231
+ console.log('[send_messages] Text typed successfully:', textTyped);
232
+
233
+ if (!textTyped) {
234
+ console.warn('[send_messages] Text not typed, retrying...');
235
+ await new Promise(resolve => setTimeout(resolve, 500));
124
236
  await editor.click();
125
- await new Promise(r => setTimeout(r, 150));
237
+ await editor.evaluate((el) => {
238
+ el.focus();
239
+ el.dispatchEvent(new Event('focus', { bubbles: true }));
240
+ });
241
+ await new Promise(resolve => setTimeout(resolve, 200));
242
+ console.log('[send_messages] Retrying to type message');
126
243
  await humanLikeType(editor, message);
127
- } else {
128
- await findAndClickMessageInput(page);
129
- await humanLikeType(page.locator('.msg-form__contenteditable[contenteditable="true"]').first(), message);
244
+ await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 300) + 300));
245
+
246
+ const textTypedRetry = await editor.evaluate((el) => {
247
+ const text = el.innerText || el.textContent || '';
248
+ return text.trim().length > 0;
249
+ });
250
+ console.log('[send_messages] Text typed after retry:', textTypedRetry);
130
251
  }
131
- await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 500) + 500));
132
252
 
253
+ await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 200) + 200));
254
+
255
+ console.log('[send_messages] Clicking send button');
133
256
  const clickedSend = await clickSendButton(page);
134
257
  if (!clickedSend) {
258
+ console.error('[send_messages] Failed to click send button');
135
259
  return {
136
260
  action: 'send_messages',
137
261
  result: { status: 'send_button_not_found', message: 'Could not find send button.' },
138
262
  status: 'failed'
139
263
  };
140
264
  }
265
+ console.log('[send_messages] Send button clicked successfully');
141
266
 
142
267
  await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 1000) + 500));
143
268
  }
144
269
 
270
+ console.log('[send_messages] Closing all conversation bubbles');
145
271
  await closeAllConversationBubbles(page);
146
272
 
273
+ console.log('[send_messages] Successfully completed!');
147
274
  return {
148
275
  action: 'send_messages',
149
276
  result: { status: 'success', message: `Message successfully sent to ${username}` },
@@ -159,43 +286,68 @@ async function typeLikeHuman(page, text) {
159
286
  }
160
287
 
161
288
  async function findAndClickMessageInput(page) {
289
+ console.log('[send_messages] findAndClickMessageInput: Waiting 1 second');
162
290
  await new Promise(resolve => setTimeout(resolve, 1000));
163
291
 
292
+ console.log('[send_messages] findAndClickMessageInput: Looking for editor by aria-label');
164
293
  const editorClicked = await page.evaluate(() => {
165
- const editor = document.querySelector('.msg-form__contenteditable[contenteditable="true"]');
294
+ const editor = document.querySelector('[aria-label="Write a message…"]');
166
295
  if (editor) {
296
+ console.log('[send_messages] Found editor, focusing and clicking');
167
297
  editor.focus();
298
+ editor.click();
299
+ editor.dispatchEvent(new Event('focus', { bubbles: true }));
168
300
  return true;
169
301
  }
302
+ console.log('[send_messages] Editor not found');
170
303
  return false;
171
304
  });
172
305
 
173
306
  if (editorClicked) {
307
+ console.log('[send_messages] Editor clicked successfully');
174
308
  await new Promise(resolve => setTimeout(resolve, 500));
175
309
  return;
176
310
  }
177
311
 
312
+ console.log('[send_messages] Editor not found, trying placeholder');
178
313
  const placeholderClicked = await page.evaluate(() => {
179
314
  const placeholder = document.querySelector('.msg-form__placeholder');
180
315
  if (placeholder) {
316
+ console.log('[send_messages] Found placeholder, clicking');
181
317
  placeholder.click();
318
+ const editor = document.querySelector('[aria-label="Write a message…"]');
319
+ if (editor) {
320
+ editor.focus();
321
+ editor.dispatchEvent(new Event('focus', { bubbles: true }));
322
+ }
182
323
  return true;
183
324
  }
325
+ console.log('[send_messages] Placeholder not found');
184
326
  return false;
185
327
  });
186
328
 
187
329
  if (placeholderClicked) {
330
+ console.log('[send_messages] Placeholder clicked successfully');
188
331
  await new Promise(resolve => setTimeout(resolve, 500));
332
+ } else {
333
+ console.warn('[send_messages] Neither editor nor placeholder found');
189
334
  }
190
335
  }
191
336
 
192
337
  async function closeAllConversationBubbles(page) {
338
+ console.log('[send_messages] Closing all conversation bubbles');
193
339
  await page.evaluate(() => {
194
- const closeButtons = document.querySelectorAll('.msg-overlay-bubble-header__control--new-convo-btn');
340
+ const allButtons = document.querySelectorAll('button');
341
+ const closeButtons = Array.from(allButtons).filter(btn => {
342
+ const useElement = btn.querySelector('svg use[href="#close-small"]');
343
+ return useElement !== null;
344
+ });
345
+ console.log('[send_messages] Found', closeButtons.length, 'close buttons');
195
346
  closeButtons.forEach(btn => {
196
347
  try {
197
348
  btn.click();
198
349
  } catch (e) {
350
+ console.log('[send_messages] Error clicking close button:', e.message);
199
351
  }
200
352
  });
201
353
  });
@@ -203,18 +355,32 @@ async function closeAllConversationBubbles(page) {
203
355
  }
204
356
 
205
357
  async function clickSendButton(page) {
358
+ console.log('[send_messages] clickSendButton: Waiting 500ms');
206
359
  await new Promise(resolve => setTimeout(resolve, 500));
207
360
 
208
- const clicked = await page.evaluate(() => {
209
- const sendButton = document.querySelector('.msg-form__send-button:not([disabled])');
210
- if (sendButton) {
211
- sendButton.click();
361
+ for (let attempt = 0; attempt < 10; attempt++) {
362
+ console.log('[send_messages] clickSendButton: Attempt', attempt + 1, 'of 10');
363
+ const clicked = await page.evaluate(() => {
364
+ const sendButton = document.querySelector('.msg-form__send-button:not([disabled])');
365
+ if (sendButton && !sendButton.disabled) {
366
+ console.log('[send_messages] Found enabled send button, clicking');
367
+ sendButton.click();
368
+ return true;
369
+ }
370
+ console.log('[send_messages] Send button not found or disabled');
371
+ return false;
372
+ });
373
+
374
+ if (clicked) {
375
+ console.log('[send_messages] Send button clicked successfully');
212
376
  return true;
213
377
  }
214
- return false;
215
- });
378
+
379
+ await new Promise(resolve => setTimeout(resolve, 300));
380
+ }
216
381
 
217
- return clicked;
382
+ console.error('[send_messages] Failed to click send button after 10 attempts');
383
+ return false;
218
384
  }
219
385
 
220
386
  async function getButtonByText(page, text, inMain = false) {