coffeeinabit 0.0.8 → 0.0.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coffeeinabit",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
4
4
  "description": "CoffeeInABit App",
5
5
  "main": "server.js",
6
6
  "type": "module",
@@ -12,7 +12,7 @@ export async function executeGetMessages(page, action) {
12
12
  });
13
13
 
14
14
  await page.waitForLoadState('domcontentloaded');
15
- await page.waitForLoadState('networkidle');
15
+ await new Promise(resolve => setTimeout(resolve, 1000));
16
16
  await new Promise(resolve => setTimeout(resolve, 2000));
17
17
 
18
18
  await page.evaluate(() => { window.scrollTo(0, 0); });
@@ -50,6 +50,12 @@ export async function executeGetMessages(page, action) {
50
50
  ];
51
51
 
52
52
  for (let attempt = 0; attempt < 10; attempt++) {
53
+ try {
54
+ const currentUrl = page.url();
55
+ if (currentUrl.includes('/messaging')) {
56
+ return true;
57
+ }
58
+ } catch (e) {}
53
59
  for (const selector of overlaySelectors) {
54
60
  try {
55
61
  const count = await page.locator(selector).count();
@@ -75,6 +81,49 @@ export async function executeGetMessages(page, action) {
75
81
  };
76
82
 
77
83
  const clickStrategies = [
84
+ async () => {
85
+ try {
86
+ const btn = page.locator('button:has-text("Message")').first();
87
+ if (await btn.isVisible().catch(() => false)) {
88
+ await btn.scrollIntoViewIfNeeded();
89
+ await new Promise(resolve => setTimeout(resolve, 300));
90
+ await btn.click({ timeout: 5000, force: false });
91
+ await new Promise(resolve => setTimeout(resolve, 1000));
92
+ return await checkOverlayAppeared(page);
93
+ }
94
+ } catch (error) {}
95
+ return false;
96
+ },
97
+ async () => {
98
+ try {
99
+ const btn = page.locator('button:has(svg[data-test-icon="send-privately-small"])').first();
100
+ if (await btn.isVisible().catch(() => false)) {
101
+ await btn.scrollIntoViewIfNeeded();
102
+ await new Promise(resolve => setTimeout(resolve, 300));
103
+ await btn.click({ timeout: 5000, force: false });
104
+ await new Promise(resolve => setTimeout(resolve, 1000));
105
+ return await checkOverlayAppeared(page);
106
+ }
107
+ } catch (error) {}
108
+ return false;
109
+ },
110
+ async () => {
111
+ try {
112
+ const classToken = 'DhBcSsKzUnyKdEOWwBJmWavDjlHFWuqygdMVO';
113
+ const candidates = await page.locator(`button.artdeco-button--primary.${classToken}`).all();
114
+ for (const btn of candidates.slice(0, 3)) {
115
+ const isVisible = await btn.isVisible().catch(() => false);
116
+ if (!isVisible) continue;
117
+ await btn.scrollIntoViewIfNeeded();
118
+ await new Promise(resolve => setTimeout(resolve, 200));
119
+ await btn.click({ timeout: 5000, force: false });
120
+ await new Promise(resolve => setTimeout(resolve, 800));
121
+ const ok = await checkOverlayAppeared(page);
122
+ if (ok) return true;
123
+ }
124
+ } catch (error) {}
125
+ return false;
126
+ },
78
127
  async () => {
79
128
  try {
80
129
  const buttons = await page.locator('button[aria-label^="Message"]').all();
@@ -246,14 +295,14 @@ export async function executeGetMessages(page, action) {
246
295
  }
247
296
 
248
297
  try {
249
- await page.waitForSelector('.msg-overlay-conversation-bubble__content-wrapper', { timeout: 15000 });
298
+ await page.waitForSelector('.msg-s-message-list-container', { timeout: 15000 });
250
299
  } catch (error) {
251
- await new Promise(resolve => setTimeout(resolve, 2000));
252
- const overlayExists = await page.locator('.msg-overlay-conversation-bubble__content-wrapper').count();
253
- if (overlayExists === 0) {
300
+ try {
301
+ await page.waitForSelector('.msg-overlay-conversation-bubble__content-wrapper', { timeout: 5000 });
302
+ } catch (e) {
254
303
  return {
255
304
  action: 'get_messages',
256
- result: { status: 'error', message: `Clicked Message button but overlay did not appear for ${username}` },
305
+ result: { status: 'error', message: `Clicked Message but no conversation view appeared for ${username}` },
257
306
  status: 'failed'
258
307
  };
259
308
  }
@@ -309,13 +358,20 @@ export async function executeGetMessages(page, action) {
309
358
 
310
359
  await new Promise(resolve => setTimeout(resolve, 1000));
311
360
 
312
- const content = await page.evaluate(() => {
361
+ const { content, items } = await page.evaluate(() => {
313
362
  const messageList = document.querySelector('.msg-s-message-list');
314
363
  if (messageList) {
315
- return messageList.innerText || '';
364
+ const ul = messageList.querySelector('ul.msg-s-message-list-content');
365
+ const lis = ul ? Array.from(ul.querySelectorAll('li')) : [];
366
+ const texts = lis.map(li => (li.innerText || '').trim()).filter(Boolean);
367
+ return { content: (messageList.innerText || ''), items: texts };
316
368
  }
317
369
  const wrapper = document.querySelector('.msg-overlay-conversation-bubble__content-wrapper');
318
- return wrapper ? wrapper.innerText : '';
370
+ const list = wrapper ? wrapper.querySelector('.msg-s-message-list') : null;
371
+ const ul = list ? list.querySelector('ul.msg-s-message-list-content') : null;
372
+ const lis = ul ? Array.from(ul.querySelectorAll('li')) : [];
373
+ const texts = lis.map(li => (li.innerText || '').trim()).filter(Boolean);
374
+ return { content: (wrapper ? wrapper.innerText : ''), items: texts };
319
375
  });
320
376
 
321
377
  return {
@@ -1,3 +1,5 @@
1
+ import { humanLikeType } from './human_typing.js';
2
+
1
3
  export async function executeSendMessages(page, action) {
2
4
  const username = action.parameters?.username || action.username;
3
5
  let messages = action.parameters?.messages || action.messages;
@@ -17,23 +19,93 @@ export async function executeSendMessages(page, action) {
17
19
  });
18
20
 
19
21
  await page.waitForLoadState('domcontentloaded');
22
+ await new Promise(resolve => setTimeout(resolve, 1000));
20
23
  await page.evaluate(() => { window.scrollTo(0, 300); });
21
24
  await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 2000) + 500));
22
25
 
23
26
  await closeAllConversationBubbles(page);
24
27
 
25
- const messageBtn = await getButtonByText(page, 'Message', true);
26
- if (!messageBtn) {
27
- return {
28
- action: 'send_messages',
29
- 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.` },
30
- status: 'failed'
31
- };
28
+ const checkConversationOpened = async () => {
29
+ for (let i = 0; i < 10; i++) {
30
+ try {
31
+ const url = page.url();
32
+ if (url.includes('/messaging')) return true;
33
+ } catch (e) {}
34
+ try {
35
+ 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) {}
38
+ await new Promise(r => setTimeout(r, 500));
39
+ }
40
+ return false;
41
+ };
42
+
43
+ const clickStrategies = [
44
+ async () => {
45
+ try {
46
+ const btn = page.locator('button:has-text("Message")').first();
47
+ if (await btn.isVisible().catch(() => false)) {
48
+ await btn.scrollIntoViewIfNeeded();
49
+ await new Promise(r => setTimeout(r, 300));
50
+ await btn.click({ timeout: 5000 });
51
+ await new Promise(r => setTimeout(r, 800));
52
+ return await checkConversationOpened();
53
+ }
54
+ } catch {}
55
+ return false;
56
+ },
57
+ async () => {
58
+ try {
59
+ const btn = page.locator('button:has(svg[data-test-icon="send-privately-small"])').first();
60
+ if (await btn.isVisible().catch(() => false)) {
61
+ await btn.scrollIntoViewIfNeeded();
62
+ await new Promise(r => setTimeout(r, 300));
63
+ await btn.click({ timeout: 5000 });
64
+ await new Promise(r => setTimeout(r, 800));
65
+ return await checkConversationOpened();
66
+ }
67
+ } catch {}
68
+ return false;
69
+ },
70
+ async () => {
71
+ try {
72
+ const classToken = 'DhBcSsKzUnyKdEOWwBJmWavDjlHFWuqygdMVO';
73
+ const candidates = await page.locator(`button.artdeco-button--primary.${classToken}`).all();
74
+ for (const btn of candidates.slice(0, 3)) {
75
+ const v = await btn.isVisible().catch(() => false);
76
+ if (!v) continue;
77
+ await btn.scrollIntoViewIfNeeded();
78
+ await new Promise(r => setTimeout(r, 200));
79
+ await btn.click({ timeout: 5000 });
80
+ await new Promise(r => setTimeout(r, 800));
81
+ if (await checkConversationOpened()) return true;
82
+ }
83
+ } catch {}
84
+ return false;
85
+ },
86
+ async () => {
87
+ try {
88
+ const buttons = await page.locator('button[aria-label^="Message"]').all();
89
+ for (const btn of buttons) {
90
+ const isVisible = await btn.isVisible().catch(() => false);
91
+ if (!isVisible) continue;
92
+ await btn.scrollIntoViewIfNeeded();
93
+ await new Promise(r => setTimeout(r, 300));
94
+ await btn.click({ timeout: 5000 });
95
+ await new Promise(r => setTimeout(r, 800));
96
+ if (await checkConversationOpened()) return true;
97
+ }
98
+ } catch {}
99
+ return false;
100
+ }
101
+ ];
102
+
103
+ let opened = false;
104
+ for (const s of clickStrategies) {
105
+ opened = await s();
106
+ if (opened) break;
32
107
  }
33
-
34
- try {
35
- await messageBtn.click();
36
- } catch (error) {
108
+ if (!opened) {
37
109
  return {
38
110
  action: 'send_messages',
39
111
  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.` },
@@ -46,8 +118,16 @@ export async function executeSendMessages(page, action) {
46
118
  for (const message of messages) {
47
119
  await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 100) + 500));
48
120
  await new Promise(resolve => setTimeout(resolve, 200));
49
-
50
- await typeLikeHuman(page, message);
121
+
122
+ const editor = page.locator('.msg-form__contenteditable[contenteditable="true"]').first();
123
+ if (await editor.isVisible().catch(() => false)) {
124
+ await editor.click();
125
+ await new Promise(r => setTimeout(r, 150));
126
+ await humanLikeType(editor, message);
127
+ } else {
128
+ await findAndClickMessageInput(page);
129
+ await humanLikeType(page.locator('.msg-form__contenteditable[contenteditable="true"]').first(), message);
130
+ }
51
131
  await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * 500) + 500));
52
132
 
53
133
  const clickedSend = await clickSendButton(page);