@bubblelab/bubble-core 0.1.39 → 0.1.41
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/dist/bubble-bundle.d.ts +134 -113
- package/dist/bubble-factory.d.ts.map +1 -1
- package/dist/bubble-factory.js +4 -0
- package/dist/bubble-factory.js.map +1 -1
- package/dist/bubbles/service-bubble/agi-inc.d.ts +22 -22
- package/dist/bubbles/service-bubble/ai-agent.d.ts +48 -48
- package/dist/bubbles/service-bubble/ai-agent.d.ts.map +1 -1
- package/dist/bubbles/service-bubble/ai-agent.js +5 -0
- package/dist/bubbles/service-bubble/ai-agent.js.map +1 -1
- package/dist/bubbles/service-bubble/airtable.d.ts +24 -24
- package/dist/bubbles/service-bubble/apify/apify.d.ts +18 -18
- package/dist/bubbles/service-bubble/ashby/ashby.d.ts +76 -76
- package/dist/bubbles/service-bubble/ashby/ashby.schema.d.ts +102 -102
- package/dist/bubbles/service-bubble/browserbase/browserbase.d.ts +18 -18
- package/dist/bubbles/service-bubble/browserbase/browserbase.schema.d.ts +23 -23
- package/dist/bubbles/service-bubble/crustdata/crustdata.d.ts +100 -100
- package/dist/bubbles/service-bubble/crustdata/crustdata.schema.d.ts +126 -126
- package/dist/bubbles/service-bubble/eleven-labs.d.ts +8 -8
- package/dist/bubbles/service-bubble/firecrawl.d.ts +450 -450
- package/dist/bubbles/service-bubble/followupboss.d.ts +218 -218
- package/dist/bubbles/service-bubble/fullenrich/fullenrich.d.ts +229 -229
- package/dist/bubbles/service-bubble/fullenrich/fullenrich.schema.d.ts +128 -128
- package/dist/bubbles/service-bubble/github.d.ts +84 -84
- package/dist/bubbles/service-bubble/gmail.d.ts +104 -104
- package/dist/bubbles/service-bubble/google-drive.d.ts +8 -8
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.d.ts +26 -26
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.schema.d.ts +18 -18
- package/dist/bubbles/service-bubble/http.d.ts +8 -8
- package/dist/bubbles/service-bubble/insforge-db.d.ts +8 -8
- package/dist/bubbles/service-bubble/jira/jira.d.ts +6 -6
- package/dist/bubbles/service-bubble/jira/jira.schema.d.ts +17 -17
- package/dist/bubbles/service-bubble/notion/notion.d.ts +24 -24
- package/dist/bubbles/service-bubble/postgresql.d.ts +8 -8
- package/dist/bubbles/service-bubble/resend.d.ts +8 -8
- package/dist/bubbles/service-bubble/slack/slack.d.ts +232 -232
- package/dist/bubbles/service-bubble/storage.d.ts +20 -20
- package/dist/bubbles/service-bubble/telegram.d.ts +298 -298
- package/dist/bubbles/tool-bubble/amazon-shopping-tool/amazon-shopping-tool.d.ts +5 -5
- package/dist/bubbles/tool-bubble/amazon-shopping-tool/amazon-shopping-tool.schema.d.ts +7 -7
- package/dist/bubbles/tool-bubble/company-enrichment-tool.d.ts +56 -56
- package/dist/bubbles/tool-bubble/google-maps-tool.d.ts +12 -12
- package/dist/bubbles/tool-bubble/instagram-tool.d.ts +8 -8
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/index.d.ts +3 -0
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/index.d.ts.map +1 -0
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/index.js +3 -0
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/index.js.map +1 -0
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.d.ts +143 -0
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.d.ts.map +1 -0
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.js +589 -0
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.js.map +1 -0
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.schema.d.ts +93 -0
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.schema.d.ts.map +1 -0
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.schema.js +44 -0
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.schema.js.map +1 -0
- package/dist/bubbles/tool-bubble/linkedin-tool.d.ts +609 -609
- package/dist/bubbles/tool-bubble/list-bubbles-tool.d.ts +4 -4
- package/dist/bubbles/tool-bubble/people-search-tool.d.ts +94 -94
- package/dist/bubbles/tool-bubble/reddit-scrape-tool.d.ts +12 -12
- package/dist/bubbles/tool-bubble/research-agent-tool.d.ts +6 -6
- package/dist/bubbles/tool-bubble/sql-query-tool.d.ts +8 -8
- package/dist/bubbles/tool-bubble/tiktok-tool.d.ts +68 -68
- package/dist/bubbles/tool-bubble/twitter-tool.d.ts +182 -182
- package/dist/bubbles/tool-bubble/web-search-tool.d.ts +8 -8
- package/dist/bubbles/workflow-bubble/generate-document.workflow.d.ts +10 -10
- package/dist/bubbles/workflow-bubble/parse-document.workflow.d.ts +10 -10
- package/dist/bubbles/workflow-bubble/pdf-form-operations.workflow.d.ts +8 -8
- package/dist/bubbles/workflow-bubble/pdf-ocr.workflow.d.ts +20 -20
- package/dist/bubbles/workflow-bubble/slack-data-assistant.workflow.d.ts +6 -6
- package/dist/bubbles/workflow-bubble/slack-formatter-agent.d.ts +74 -74
- package/dist/bubbles/workflow-bubble/slack-notifier.workflow.d.ts +14 -14
- package/dist/bubbles.json +125 -40
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,589 @@
|
|
|
1
|
+
import { ToolBubble } from '../../../types/tool-bubble-class.js';
|
|
2
|
+
import { CredentialType } from '@bubblelab/shared-schemas';
|
|
3
|
+
import { BrowserBaseBubble, BrowserSessionDataSchema, } from '../../service-bubble/browserbase/index.js';
|
|
4
|
+
import { LinkedInConnectionToolParamsSchema, LinkedInConnectionToolResultSchema, } from './linkedin-connection-tool.schema.js';
|
|
5
|
+
// Debug logging helper - only logs when DEBUG_BROWSER_BASE env var is set
|
|
6
|
+
const DEBUG = process.env.DEBUG_BROWSER_BASE;
|
|
7
|
+
function debugLog(...args) {
|
|
8
|
+
if (DEBUG) {
|
|
9
|
+
console.log(...args);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* LinkedIn Connection Tool
|
|
14
|
+
*
|
|
15
|
+
* A tool bubble for automating LinkedIn connection requests.
|
|
16
|
+
* Handles both profile types:
|
|
17
|
+
* - Profiles with direct "Connect" button
|
|
18
|
+
* - Profiles where "Connect" is under the "More" dropdown
|
|
19
|
+
*
|
|
20
|
+
* Features:
|
|
21
|
+
* - Send connection requests to LinkedIn profiles
|
|
22
|
+
* - Add optional personalized notes
|
|
23
|
+
* - Handle various profile layouts
|
|
24
|
+
*
|
|
25
|
+
* Required Credentials:
|
|
26
|
+
* - LINKEDIN_CRED: Browser session credential with LinkedIn cookies
|
|
27
|
+
*
|
|
28
|
+
* Security:
|
|
29
|
+
* - Uses BrowserBase cloud browsers (isolated)
|
|
30
|
+
* - Credentials are encrypted at rest
|
|
31
|
+
* - Session data is not persisted beyond operation
|
|
32
|
+
*/
|
|
33
|
+
export class LinkedInConnectionTool extends ToolBubble {
|
|
34
|
+
static bubbleName = 'linkedin-connection-tool';
|
|
35
|
+
static schema = LinkedInConnectionToolParamsSchema;
|
|
36
|
+
static resultSchema = LinkedInConnectionToolResultSchema;
|
|
37
|
+
static shortDescription = 'LinkedIn connection automation - send connection requests with optional notes';
|
|
38
|
+
static longDescription = `
|
|
39
|
+
LinkedIn Connection Tool for automating connection requests.
|
|
40
|
+
|
|
41
|
+
Features:
|
|
42
|
+
- Send connection requests to LinkedIn profiles
|
|
43
|
+
- Add optional personalized notes (up to 300 characters)
|
|
44
|
+
- Handles profiles with direct Connect button
|
|
45
|
+
- Handles profiles where Connect is under "More" dropdown
|
|
46
|
+
|
|
47
|
+
Required Credentials:
|
|
48
|
+
- LINKEDIN_CRED: Browser session credential (authenticate via browser session)
|
|
49
|
+
|
|
50
|
+
Note: The tool operates using authenticated browser sessions to ensure security.
|
|
51
|
+
`;
|
|
52
|
+
static alias = 'linkedin';
|
|
53
|
+
static type = 'tool';
|
|
54
|
+
sessionId = null;
|
|
55
|
+
contextId = null;
|
|
56
|
+
cookies = null;
|
|
57
|
+
constructor(params = { operation: 'send_connection', profile_url: '' }, context) {
|
|
58
|
+
super(params, context);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Choose the credential to use for LinkedIn operations
|
|
62
|
+
*/
|
|
63
|
+
chooseCredential() {
|
|
64
|
+
const { credentials } = this.params;
|
|
65
|
+
if (!credentials || typeof credentials !== 'object') {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
return credentials[CredentialType.LINKEDIN_CRED];
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Parse the LINKEDIN_CRED to extract contextId and cookies
|
|
72
|
+
*/
|
|
73
|
+
parseBrowserSessionData() {
|
|
74
|
+
const credential = this.chooseCredential();
|
|
75
|
+
if (!credential) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
const jsonString = Buffer.from(credential, 'base64').toString('utf-8');
|
|
80
|
+
const parsed = JSON.parse(jsonString);
|
|
81
|
+
const validated = BrowserSessionDataSchema.safeParse(parsed);
|
|
82
|
+
if (validated.success) {
|
|
83
|
+
return validated.data;
|
|
84
|
+
}
|
|
85
|
+
console.error('[LinkedInConnectionTool] Invalid credential format:', validated.error);
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
console.error('[LinkedInConnectionTool] Failed to parse credential:', error);
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Start a browser session using BrowserBase
|
|
95
|
+
*/
|
|
96
|
+
async startBrowserSession() {
|
|
97
|
+
debugLog('[LinkedInConnectionTool] Starting browser session');
|
|
98
|
+
if (this.sessionId) {
|
|
99
|
+
return this.sessionId;
|
|
100
|
+
}
|
|
101
|
+
const sessionData = this.parseBrowserSessionData();
|
|
102
|
+
if (sessionData) {
|
|
103
|
+
this.contextId = sessionData.contextId;
|
|
104
|
+
this.cookies = sessionData.cookies;
|
|
105
|
+
debugLog(`[LinkedInConnectionTool] Loaded session data: contextId=${this.contextId}, cookies=${this.cookies.length}`);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
debugLog('[LinkedInConnectionTool] No LINKEDIN_CRED found, creating new context');
|
|
109
|
+
}
|
|
110
|
+
const startsession_browserbase = new BrowserBaseBubble({
|
|
111
|
+
operation: 'start_session',
|
|
112
|
+
context_id: this.contextId || undefined,
|
|
113
|
+
cookies: this.cookies || undefined,
|
|
114
|
+
credentials: this.params.credentials,
|
|
115
|
+
}, this.context, 'startsession_browserbase');
|
|
116
|
+
const result = await startsession_browserbase.action();
|
|
117
|
+
if (!result.data.success || !result.data.session_id) {
|
|
118
|
+
throw new Error(result.data.error || 'Failed to start browser session');
|
|
119
|
+
}
|
|
120
|
+
this.sessionId = result.data.session_id;
|
|
121
|
+
if (result.data.context_id) {
|
|
122
|
+
this.contextId = result.data.context_id;
|
|
123
|
+
}
|
|
124
|
+
debugLog(`[LinkedInConnectionTool] Browser session started: ${this.sessionId}, context: ${this.contextId}`);
|
|
125
|
+
if (this.context?.logger && result.data.debug_url) {
|
|
126
|
+
this.context.logger.logBrowserSessionStart(this.sessionId, result.data.debug_url, this.context.variableId);
|
|
127
|
+
}
|
|
128
|
+
return this.sessionId;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* End the browser session
|
|
132
|
+
*/
|
|
133
|
+
async endBrowserSession() {
|
|
134
|
+
if (!this.sessionId)
|
|
135
|
+
return;
|
|
136
|
+
const sessionIdToEnd = this.sessionId;
|
|
137
|
+
try {
|
|
138
|
+
const endsession_browserbase = new BrowserBaseBubble({
|
|
139
|
+
operation: 'end_session',
|
|
140
|
+
session_id: sessionIdToEnd,
|
|
141
|
+
}, this.context, 'endsession_browserbase');
|
|
142
|
+
await endsession_browserbase.action();
|
|
143
|
+
debugLog(`[LinkedInConnectionTool] Browser session ended: ${sessionIdToEnd}`);
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
console.error('[LinkedInConnectionTool] Error ending session:', error);
|
|
147
|
+
}
|
|
148
|
+
finally {
|
|
149
|
+
if (this.context?.logger) {
|
|
150
|
+
this.context.logger.logBrowserSessionEnd(sessionIdToEnd, this.context.variableId);
|
|
151
|
+
}
|
|
152
|
+
this.sessionId = null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Navigate to a URL
|
|
157
|
+
*/
|
|
158
|
+
async navigateTo(url) {
|
|
159
|
+
if (!this.sessionId) {
|
|
160
|
+
throw new Error('No active browser session');
|
|
161
|
+
}
|
|
162
|
+
const navigate_browserbase = new BrowserBaseBubble({
|
|
163
|
+
operation: 'navigate',
|
|
164
|
+
session_id: this.sessionId,
|
|
165
|
+
url,
|
|
166
|
+
wait_until: 'domcontentloaded',
|
|
167
|
+
timeout: 30000,
|
|
168
|
+
}, this.context, 'navigate_browserbase');
|
|
169
|
+
const result = await navigate_browserbase.action();
|
|
170
|
+
if (!result.data.success) {
|
|
171
|
+
throw new Error(result.data.error || 'Navigation failed');
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Evaluate JavaScript in page
|
|
176
|
+
*/
|
|
177
|
+
async evaluate(script) {
|
|
178
|
+
if (!this.sessionId) {
|
|
179
|
+
throw new Error('No active browser session');
|
|
180
|
+
}
|
|
181
|
+
const evaluate_browserbase = new BrowserBaseBubble({
|
|
182
|
+
operation: 'evaluate',
|
|
183
|
+
session_id: this.sessionId,
|
|
184
|
+
script,
|
|
185
|
+
}, this.context, 'evaluate_browserbase');
|
|
186
|
+
const result = await evaluate_browserbase.action();
|
|
187
|
+
if (!result.data.success) {
|
|
188
|
+
throw new Error(result.data.error || 'Script evaluation failed');
|
|
189
|
+
}
|
|
190
|
+
return result.data.result;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Type text into an input field
|
|
194
|
+
*/
|
|
195
|
+
async typeText(selector, text) {
|
|
196
|
+
if (!this.sessionId) {
|
|
197
|
+
throw new Error('No active browser session');
|
|
198
|
+
}
|
|
199
|
+
const type_browserbase = new BrowserBaseBubble({
|
|
200
|
+
operation: 'type',
|
|
201
|
+
session_id: this.sessionId,
|
|
202
|
+
selector,
|
|
203
|
+
text,
|
|
204
|
+
delay: 50,
|
|
205
|
+
}, this.context, 'type_browserbase');
|
|
206
|
+
const result = await type_browserbase.action();
|
|
207
|
+
return result.data.success;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Get current page URL
|
|
211
|
+
*/
|
|
212
|
+
async getCurrentUrl() {
|
|
213
|
+
const result = (await this.evaluate(`window.location.href`));
|
|
214
|
+
return result;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Save current DOM state to file for debugging
|
|
218
|
+
* Only saves when DEBUG env var is set
|
|
219
|
+
*/
|
|
220
|
+
async saveDebugState(label) {
|
|
221
|
+
if (!DEBUG) {
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
try {
|
|
225
|
+
const fs = await import('fs/promises');
|
|
226
|
+
const htmlContent = (await this.evaluate(`document.documentElement.outerHTML`));
|
|
227
|
+
const currentUrl = await this.getCurrentUrl();
|
|
228
|
+
const timestamp = Date.now();
|
|
229
|
+
const debugPath = `/tmp/linkedin-debug-${label}-${timestamp}.html`;
|
|
230
|
+
// Add URL as comment at top of file
|
|
231
|
+
const contentWithUrl = `<!-- URL: ${currentUrl} -->\n${htmlContent}`;
|
|
232
|
+
await fs.writeFile(debugPath, contentWithUrl);
|
|
233
|
+
debugLog(`[LinkedInConnectionTool] Saved debug DOM to: ${debugPath}`);
|
|
234
|
+
return debugPath;
|
|
235
|
+
}
|
|
236
|
+
catch (e) {
|
|
237
|
+
console.error('[LinkedInConnectionTool] Failed to save debug state:', e);
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
async performAction() {
|
|
242
|
+
try {
|
|
243
|
+
await this.startBrowserSession();
|
|
244
|
+
return await this.sendConnection();
|
|
245
|
+
}
|
|
246
|
+
catch (error) {
|
|
247
|
+
console.error('[LinkedInConnectionTool] Error:', error);
|
|
248
|
+
return {
|
|
249
|
+
operation: 'send_connection',
|
|
250
|
+
success: false,
|
|
251
|
+
error: error instanceof Error ? error.message : 'Unknown error occurred',
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
finally {
|
|
255
|
+
await this.endBrowserSession();
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Send a connection request to a LinkedIn profile
|
|
260
|
+
*/
|
|
261
|
+
async sendConnection() {
|
|
262
|
+
const { profile_url, message } = this.params;
|
|
263
|
+
debugLog(`[LinkedInConnectionTool] Sending connection to: ${profile_url}`);
|
|
264
|
+
// Navigate to profile page
|
|
265
|
+
await this.navigateTo(profile_url);
|
|
266
|
+
// Wait for page to load
|
|
267
|
+
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
268
|
+
// Save debug state after page load
|
|
269
|
+
await this.saveDebugState('01-after-page-load');
|
|
270
|
+
// Extract profile info
|
|
271
|
+
const profileInfo = await this.extractProfileInfo();
|
|
272
|
+
debugLog('[LinkedInConnectionTool] Profile info:', profileInfo);
|
|
273
|
+
// Try to find and click the Connect button
|
|
274
|
+
// Strategy 1: Direct Connect button (visible on profile)
|
|
275
|
+
let connectClicked = false;
|
|
276
|
+
// Save debug state before attempting to click Connect
|
|
277
|
+
await this.saveDebugState('02-before-connect-click');
|
|
278
|
+
// Look for direct Connect button with various selectors
|
|
279
|
+
const directConnectResult = (await this.evaluate(`
|
|
280
|
+
(() => {
|
|
281
|
+
// Look for primary Connect button
|
|
282
|
+
const connectButtons = document.querySelectorAll('button');
|
|
283
|
+
for (const btn of connectButtons) {
|
|
284
|
+
const ariaLabel = btn.getAttribute('aria-label') || '';
|
|
285
|
+
const text = (btn.innerText || btn.textContent || '').trim().toLowerCase();
|
|
286
|
+
|
|
287
|
+
// Check for "Invite X to connect" aria-label or "Connect" text
|
|
288
|
+
if (ariaLabel.toLowerCase().includes('connect') || text === 'connect') {
|
|
289
|
+
// Make sure it's a primary action button, not in a dropdown
|
|
290
|
+
if (btn.classList.contains('artdeco-button--primary') ||
|
|
291
|
+
btn.closest('.pvs-profile-actions') ||
|
|
292
|
+
btn.closest('.pv-top-card-v2-ctas')) {
|
|
293
|
+
btn.click();
|
|
294
|
+
return { clicked: true, method: 'direct', ariaLabel, text };
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return { clicked: false };
|
|
299
|
+
})()
|
|
300
|
+
`));
|
|
301
|
+
if (directConnectResult.clicked) {
|
|
302
|
+
connectClicked = true;
|
|
303
|
+
debugLog(`[LinkedInConnectionTool] Clicked direct Connect button: ${directConnectResult.method}`);
|
|
304
|
+
}
|
|
305
|
+
// Strategy 2: Connect is under "More" dropdown
|
|
306
|
+
if (!connectClicked) {
|
|
307
|
+
debugLog('[LinkedInConnectionTool] Direct Connect not found, trying More dropdown...');
|
|
308
|
+
// Click the "More" button
|
|
309
|
+
const moreButtonResult = (await this.evaluate(`
|
|
310
|
+
(() => {
|
|
311
|
+
// Look for More button - specifically the profile overflow action button
|
|
312
|
+
// It has id like "ember67-profile-overflow-action" and aria-label="More actions"
|
|
313
|
+
const buttons = document.querySelectorAll('button');
|
|
314
|
+
for (const btn of buttons) {
|
|
315
|
+
const ariaLabel = (btn.getAttribute('aria-label') || '').toLowerCase();
|
|
316
|
+
const btnId = btn.id || '';
|
|
317
|
+
|
|
318
|
+
// Profile overflow button has specific ID pattern and aria-label
|
|
319
|
+
if (btnId.includes('profile-overflow-action') ||
|
|
320
|
+
(ariaLabel === 'more actions' && btn.classList.contains('artdeco-dropdown__trigger'))) {
|
|
321
|
+
btn.click();
|
|
322
|
+
return { clicked: true, id: btnId, ariaLabel };
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return { clicked: false };
|
|
326
|
+
})()
|
|
327
|
+
`));
|
|
328
|
+
if (moreButtonResult.clicked) {
|
|
329
|
+
debugLog(`[LinkedInConnectionTool] Clicked More button: id="${moreButtonResult.id}", aria-label="${moreButtonResult.ariaLabel}"`);
|
|
330
|
+
await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait longer for dropdown to open
|
|
331
|
+
// Save debug state after clicking More button
|
|
332
|
+
await this.saveDebugState('03-after-more-dropdown-open');
|
|
333
|
+
// Now look for Connect in the dropdown
|
|
334
|
+
const dropdownConnectResult = (await this.evaluate(`
|
|
335
|
+
(() => {
|
|
336
|
+
// LinkedIn uses div[role="button"] for dropdown items
|
|
337
|
+
// Look for Connect option with aria-label containing "connect"
|
|
338
|
+
const dropdownItems = document.querySelectorAll('.artdeco-dropdown__item[role="button"], .artdeco-dropdown__content-inner [role="button"]');
|
|
339
|
+
for (const item of dropdownItems) {
|
|
340
|
+
const ariaLabel = (item.getAttribute('aria-label') || '').toLowerCase();
|
|
341
|
+
const text = (item.innerText || item.textContent || '').trim().toLowerCase();
|
|
342
|
+
|
|
343
|
+
// Check aria-label like "Invite X to connect" or text "Connect"
|
|
344
|
+
if (ariaLabel.includes('connect') || text === 'connect') {
|
|
345
|
+
item.click();
|
|
346
|
+
return { clicked: true, ariaLabel, text };
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return { clicked: false };
|
|
351
|
+
})()
|
|
352
|
+
`));
|
|
353
|
+
if (dropdownConnectResult.clicked) {
|
|
354
|
+
connectClicked = true;
|
|
355
|
+
debugLog(`[LinkedInConnectionTool] Clicked Connect from dropdown: aria-label="${dropdownConnectResult.ariaLabel}", text="${dropdownConnectResult.text}"`);
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
debugLog('[LinkedInConnectionTool] Connect option not found in dropdown');
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
debugLog('[LinkedInConnectionTool] More button not found');
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
if (!connectClicked) {
|
|
366
|
+
// Save debug state before reporting failure
|
|
367
|
+
await this.saveDebugState('04-connect-not-found');
|
|
368
|
+
return {
|
|
369
|
+
operation: 'send_connection',
|
|
370
|
+
success: false,
|
|
371
|
+
profile: profileInfo || undefined,
|
|
372
|
+
error: 'Could not find Connect button. Profile may already be connected or connection requests may be restricted.',
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
// Wait for connection modal to appear
|
|
376
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
377
|
+
// Check if we need to add a note or send without note
|
|
378
|
+
if (message) {
|
|
379
|
+
debugLog('[LinkedInConnectionTool] Adding note to connection request');
|
|
380
|
+
// Click "Add a note" button
|
|
381
|
+
const addNoteResult = (await this.evaluate(`
|
|
382
|
+
(() => {
|
|
383
|
+
const buttons = document.querySelectorAll('button');
|
|
384
|
+
for (const btn of buttons) {
|
|
385
|
+
const ariaLabel = (btn.getAttribute('aria-label') || '').toLowerCase();
|
|
386
|
+
const text = (btn.innerText || btn.textContent || '').trim().toLowerCase();
|
|
387
|
+
|
|
388
|
+
if (ariaLabel.includes('add a note') || text.includes('add a note')) {
|
|
389
|
+
btn.click();
|
|
390
|
+
return { clicked: true };
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
return { clicked: false };
|
|
394
|
+
})()
|
|
395
|
+
`));
|
|
396
|
+
if (addNoteResult.clicked) {
|
|
397
|
+
debugLog('[LinkedInConnectionTool] Clicked Add a note button');
|
|
398
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
399
|
+
// Type the message into the textarea
|
|
400
|
+
const typed = await this.typeText('#custom-message', message);
|
|
401
|
+
if (!typed) {
|
|
402
|
+
// Fallback: try evaluate to set value
|
|
403
|
+
await this.evaluate(`
|
|
404
|
+
(() => {
|
|
405
|
+
const textarea = document.querySelector('#custom-message');
|
|
406
|
+
if (textarea) {
|
|
407
|
+
textarea.value = ${JSON.stringify(message)};
|
|
408
|
+
textarea.dispatchEvent(new Event('input', { bubbles: true }));
|
|
409
|
+
return true;
|
|
410
|
+
}
|
|
411
|
+
return false;
|
|
412
|
+
})()
|
|
413
|
+
`);
|
|
414
|
+
}
|
|
415
|
+
debugLog('[LinkedInConnectionTool] Typed note message');
|
|
416
|
+
}
|
|
417
|
+
// Wait a moment before sending
|
|
418
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
419
|
+
// Click Send button (after adding note)
|
|
420
|
+
const sendResult = (await this.evaluate(`
|
|
421
|
+
(() => {
|
|
422
|
+
const buttons = document.querySelectorAll('button');
|
|
423
|
+
for (const btn of buttons) {
|
|
424
|
+
const text = (btn.innerText || btn.textContent || '').trim().toLowerCase();
|
|
425
|
+
|
|
426
|
+
// Look for Send button (primary)
|
|
427
|
+
if (text === 'send' && btn.classList.contains('artdeco-button--primary')) {
|
|
428
|
+
btn.click();
|
|
429
|
+
return { clicked: true, text };
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
return { clicked: false };
|
|
433
|
+
})()
|
|
434
|
+
`));
|
|
435
|
+
if (!sendResult.clicked) {
|
|
436
|
+
return {
|
|
437
|
+
operation: 'send_connection',
|
|
438
|
+
success: false,
|
|
439
|
+
profile: profileInfo || undefined,
|
|
440
|
+
error: 'Could not find Send button to complete connection request.',
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
debugLog('[LinkedInConnectionTool] Clicked Send button');
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
// No message - click "Send without a note" button
|
|
447
|
+
debugLog('[LinkedInConnectionTool] No message provided, clicking Send without a note');
|
|
448
|
+
const sendWithoutNoteResult = (await this.evaluate(`
|
|
449
|
+
(() => {
|
|
450
|
+
const buttons = document.querySelectorAll('button');
|
|
451
|
+
for (const btn of buttons) {
|
|
452
|
+
const text = (btn.innerText || btn.textContent || '').trim().toLowerCase();
|
|
453
|
+
|
|
454
|
+
// Look for "Send without a note" button
|
|
455
|
+
if (text.includes('send without a note') || text.includes('send without note')) {
|
|
456
|
+
btn.click();
|
|
457
|
+
return { clicked: true, text };
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
return { clicked: false };
|
|
461
|
+
})()
|
|
462
|
+
`));
|
|
463
|
+
if (!sendWithoutNoteResult.clicked) {
|
|
464
|
+
return {
|
|
465
|
+
operation: 'send_connection',
|
|
466
|
+
success: false,
|
|
467
|
+
profile: profileInfo || undefined,
|
|
468
|
+
error: 'Could not find Send without a note button to complete connection request.',
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
debugLog('[LinkedInConnectionTool] Clicked Send without a note button');
|
|
472
|
+
}
|
|
473
|
+
// Wait for request to be processed
|
|
474
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
475
|
+
// Handle "Not now" prompt if it appears (for adding to address book)
|
|
476
|
+
await this.evaluate(`
|
|
477
|
+
(() => {
|
|
478
|
+
const buttons = document.querySelectorAll('button');
|
|
479
|
+
for (const btn of buttons) {
|
|
480
|
+
const text = (btn.innerText || btn.textContent || '').trim().toLowerCase();
|
|
481
|
+
if (text === 'not now') {
|
|
482
|
+
btn.click();
|
|
483
|
+
return true;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
return false;
|
|
487
|
+
})()
|
|
488
|
+
`);
|
|
489
|
+
return {
|
|
490
|
+
operation: 'send_connection',
|
|
491
|
+
success: true,
|
|
492
|
+
message: `Connection request sent to ${profileInfo?.name || 'profile'}`,
|
|
493
|
+
profile: profileInfo || undefined,
|
|
494
|
+
error: '',
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Extract profile information from the current page
|
|
499
|
+
*/
|
|
500
|
+
async extractProfileInfo() {
|
|
501
|
+
try {
|
|
502
|
+
const info = (await this.evaluate(`
|
|
503
|
+
(() => {
|
|
504
|
+
// Get profile name - try multiple strategies
|
|
505
|
+
let name = '';
|
|
506
|
+
|
|
507
|
+
// Strategy 1: h1 element (has obfuscated class but also standard classes)
|
|
508
|
+
const h1El = document.querySelector('h1');
|
|
509
|
+
if (h1El) {
|
|
510
|
+
name = h1El.textContent?.trim() || '';
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// Strategy 2: Profile picture alt/title attribute
|
|
514
|
+
if (!name) {
|
|
515
|
+
const imgEl = document.querySelector('img.pv-top-card-profile-picture__image--show') ||
|
|
516
|
+
document.querySelector('img[class*="pv-top-card-profile-picture"]');
|
|
517
|
+
if (imgEl) {
|
|
518
|
+
name = imgEl.getAttribute('alt') || imgEl.getAttribute('title') || '';
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// Strategy 3: Extract from Connect button aria-label "Invite X to connect"
|
|
523
|
+
if (!name) {
|
|
524
|
+
const connectBtn = document.querySelector('button[aria-label*="to connect"]');
|
|
525
|
+
if (connectBtn) {
|
|
526
|
+
const ariaLabel = connectBtn.getAttribute('aria-label') || '';
|
|
527
|
+
const match = ariaLabel.match(/Invite (.+) to connect/i);
|
|
528
|
+
if (match) {
|
|
529
|
+
name = match[1];
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// Get headline - div with text-body-medium break-words and data-generated-suggestion-target
|
|
535
|
+
let headline = '';
|
|
536
|
+
const headlineEl = document.querySelector('div.text-body-medium.break-words[data-generated-suggestion-target]') ||
|
|
537
|
+
document.querySelector('div.text-body-medium.break-words');
|
|
538
|
+
if (headlineEl) {
|
|
539
|
+
headline = headlineEl.textContent?.trim() || '';
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// Get location - span before Contact info link
|
|
543
|
+
let location = '';
|
|
544
|
+
const contactInfoLink = document.querySelector('a[href*="contact-info"]');
|
|
545
|
+
if (contactInfoLink) {
|
|
546
|
+
// Location is in a sibling or parent span
|
|
547
|
+
const parentSpan = contactInfoLink.closest('span');
|
|
548
|
+
if (parentSpan && parentSpan.previousElementSibling) {
|
|
549
|
+
location = parentSpan.previousElementSibling.textContent?.trim() || '';
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// Fallback: look for location pattern in spans
|
|
554
|
+
if (!location) {
|
|
555
|
+
const spans = document.querySelectorAll('span');
|
|
556
|
+
for (const span of spans) {
|
|
557
|
+
const text = span.textContent?.trim() || '';
|
|
558
|
+
// Location usually contains comma-separated place names
|
|
559
|
+
if (text.includes(',') && !text.includes('@') && !text.includes('|') &&
|
|
560
|
+
text.length < 100 && text.length > 5) {
|
|
561
|
+
// Check if it looks like a location (contains country/city patterns)
|
|
562
|
+
if (/(?:United|Kingdom|States|England|Germany|France|India|Canada|Australia|California|New York|London|Manchester)/i.test(text)) {
|
|
563
|
+
location = text;
|
|
564
|
+
break;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
return {
|
|
571
|
+
name,
|
|
572
|
+
headline,
|
|
573
|
+
location,
|
|
574
|
+
profile_url: window.location.href
|
|
575
|
+
};
|
|
576
|
+
})()
|
|
577
|
+
`));
|
|
578
|
+
if (!info.name) {
|
|
579
|
+
return null;
|
|
580
|
+
}
|
|
581
|
+
return info;
|
|
582
|
+
}
|
|
583
|
+
catch (error) {
|
|
584
|
+
console.error('[LinkedInConnectionTool] Error extracting profile info:', error);
|
|
585
|
+
return null;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
//# sourceMappingURL=linkedin-connection-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linkedin-connection-tool.js","sourceRoot":"","sources":["../../../../src/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.ts"],"names":[],"mappings":"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"}
|