@bubblelab/bubble-core 0.1.149 → 0.1.151

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.
Files changed (115) hide show
  1. package/dist/bubble-bundle.d.ts +77 -77
  2. package/dist/bubbles/service-bubble/agi-inc.d.ts +20 -20
  3. package/dist/bubbles/service-bubble/ai-agent.d.ts +74 -74
  4. package/dist/bubbles/service-bubble/airtable.d.ts +76 -76
  5. package/dist/bubbles/service-bubble/apify/actors/instagram-hashtag-scraper.d.ts +2 -2
  6. package/dist/bubbles/service-bubble/apify/actors/instagram-scraper.d.ts +8 -8
  7. package/dist/bubbles/service-bubble/apify/actors/linkedin-jobs-scraper.d.ts +2 -2
  8. package/dist/bubbles/service-bubble/apify/actors/linkedin-posts-search.d.ts +22 -22
  9. package/dist/bubbles/service-bubble/apify/actors/linkedin-profile-detail.d.ts +38 -38
  10. package/dist/bubbles/service-bubble/apify/actors/linkedin-profile-posts.d.ts +52 -52
  11. package/dist/bubbles/service-bubble/apify/actors/tiktok-scraper.d.ts +6 -6
  12. package/dist/bubbles/service-bubble/apify/actors/twitter-scraper.d.ts +12 -12
  13. package/dist/bubbles/service-bubble/apify/actors/youtube-scraper.d.ts +12 -12
  14. package/dist/bubbles/service-bubble/apify/apify-scraper.schema.d.ts +126 -126
  15. package/dist/bubbles/service-bubble/apify/apify.d.ts +18 -18
  16. package/dist/bubbles/service-bubble/ashby/ashby.d.ts +2 -2
  17. package/dist/bubbles/service-bubble/ashby/ashby.schema.d.ts +2 -2
  18. package/dist/bubbles/service-bubble/browserbase/browserbase.d.ts +38 -1
  19. package/dist/bubbles/service-bubble/browserbase/browserbase.d.ts.map +1 -1
  20. package/dist/bubbles/service-bubble/browserbase/browserbase.js +80 -0
  21. package/dist/bubbles/service-bubble/browserbase/browserbase.js.map +1 -1
  22. package/dist/bubbles/service-bubble/browserbase/browserbase.schema.d.ts +34 -1
  23. package/dist/bubbles/service-bubble/browserbase/browserbase.schema.d.ts.map +1 -1
  24. package/dist/bubbles/service-bubble/browserbase/browserbase.schema.js +30 -0
  25. package/dist/bubbles/service-bubble/browserbase/browserbase.schema.js.map +1 -1
  26. package/dist/bubbles/service-bubble/firecrawl.d.ts +334 -334
  27. package/dist/bubbles/service-bubble/followupboss.d.ts +4 -4
  28. package/dist/bubbles/service-bubble/github.d.ts +60 -60
  29. package/dist/bubbles/service-bubble/gmail.d.ts +164 -164
  30. package/dist/bubbles/service-bubble/google-calendar.d.ts +6 -6
  31. package/dist/bubbles/service-bubble/google-drive.d.ts +9 -9
  32. package/dist/bubbles/service-bubble/google-drive.d.ts.map +1 -1
  33. package/dist/bubbles/service-bubble/google-drive.js +37 -1
  34. package/dist/bubbles/service-bubble/google-drive.js.map +1 -1
  35. package/dist/bubbles/service-bubble/http.d.ts +2 -2
  36. package/dist/bubbles/service-bubble/insforge-db.d.ts +8 -8
  37. package/dist/bubbles/service-bubble/jira/jira.d.ts +30 -30
  38. package/dist/bubbles/service-bubble/jira/jira.schema.d.ts +36 -36
  39. package/dist/bubbles/service-bubble/notion/notion.d.ts +164 -164
  40. package/dist/bubbles/service-bubble/notion/property-schemas.d.ts +8 -8
  41. package/dist/bubbles/service-bubble/postgresql.d.ts +8 -8
  42. package/dist/bubbles/service-bubble/resend.d.ts +4 -4
  43. package/dist/bubbles/service-bubble/salesforce/index.d.ts +4 -0
  44. package/dist/bubbles/service-bubble/salesforce/index.d.ts.map +1 -0
  45. package/dist/bubbles/service-bubble/salesforce/index.js +4 -0
  46. package/dist/bubbles/service-bubble/salesforce/index.js.map +1 -0
  47. package/dist/bubbles/service-bubble/salesforce/salesforce.d.ts +1331 -0
  48. package/dist/bubbles/service-bubble/salesforce/salesforce.d.ts.map +1 -0
  49. package/dist/bubbles/service-bubble/salesforce/salesforce.js +618 -0
  50. package/dist/bubbles/service-bubble/salesforce/salesforce.js.map +1 -0
  51. package/dist/bubbles/service-bubble/salesforce/salesforce.schema.d.ts +1445 -0
  52. package/dist/bubbles/service-bubble/salesforce/salesforce.schema.d.ts.map +1 -0
  53. package/dist/bubbles/service-bubble/salesforce/salesforce.schema.js +609 -0
  54. package/dist/bubbles/service-bubble/salesforce/salesforce.schema.js.map +1 -0
  55. package/dist/bubbles/service-bubble/salesforce/salesforce.utils.d.ts +87 -0
  56. package/dist/bubbles/service-bubble/salesforce/salesforce.utils.d.ts.map +1 -0
  57. package/dist/bubbles/service-bubble/salesforce/salesforce.utils.js +181 -0
  58. package/dist/bubbles/service-bubble/salesforce/salesforce.utils.js.map +1 -0
  59. package/dist/bubbles/service-bubble/slack/slack.d.ts +328 -328
  60. package/dist/bubbles/service-bubble/slack/slack.utils.d.ts.map +1 -1
  61. package/dist/bubbles/service-bubble/slack/slack.utils.js +17 -2
  62. package/dist/bubbles/service-bubble/slack/slack.utils.js.map +1 -1
  63. package/dist/bubbles/service-bubble/stripe/stripe.d.ts +24 -24
  64. package/dist/bubbles/service-bubble/stripe/stripe.schema.d.ts +28 -28
  65. package/dist/bubbles/tool-bubble/amazon-shopping-tool/amazon-shopping-tool.d.ts +6 -6
  66. package/dist/bubbles/tool-bubble/amazon-shopping-tool/amazon-shopping-tool.schema.d.ts +8 -8
  67. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/ai-browser-agent.d.ts +66 -0
  68. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/ai-browser-agent.d.ts.map +1 -0
  69. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/ai-browser-agent.js +484 -0
  70. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/ai-browser-agent.js.map +1 -0
  71. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/ai-browser-agent.types.d.ts +85 -0
  72. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/ai-browser-agent.types.d.ts.map +1 -0
  73. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/ai-browser-agent.types.js +2 -0
  74. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/ai-browser-agent.types.js.map +1 -0
  75. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/ai-fallback-step.d.ts +27 -0
  76. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/ai-fallback-step.d.ts.map +1 -0
  77. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/ai-fallback-step.js +77 -0
  78. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/ai-fallback-step.js.map +1 -0
  79. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/index.d.ts +4 -0
  80. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/index.d.ts.map +1 -0
  81. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/index.js +3 -0
  82. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/index.js.map +1 -0
  83. package/dist/bubbles/tool-bubble/browser-tools/linkedin-accept-invitations/tool.d.ts.map +1 -1
  84. package/dist/bubbles/tool-bubble/browser-tools/linkedin-accept-invitations/tool.js +269 -167
  85. package/dist/bubbles/tool-bubble/browser-tools/linkedin-accept-invitations/tool.js.map +1 -1
  86. package/dist/bubbles/tool-bubble/browser-tools/linkedin-connection/tool.d.ts +2 -0
  87. package/dist/bubbles/tool-bubble/browser-tools/linkedin-connection/tool.d.ts.map +1 -1
  88. package/dist/bubbles/tool-bubble/browser-tools/linkedin-connection/tool.js +346 -229
  89. package/dist/bubbles/tool-bubble/browser-tools/linkedin-connection/tool.js.map +1 -1
  90. package/dist/bubbles/tool-bubble/browser-tools/linkedin-received-invitations/tool.d.ts +34 -33
  91. package/dist/bubbles/tool-bubble/browser-tools/linkedin-received-invitations/tool.d.ts.map +1 -1
  92. package/dist/bubbles/tool-bubble/browser-tools/linkedin-received-invitations/tool.js +212 -151
  93. package/dist/bubbles/tool-bubble/browser-tools/linkedin-received-invitations/tool.js.map +1 -1
  94. package/dist/bubbles/tool-bubble/browser-tools/linkedin-sent-invitations/tool.d.ts +33 -32
  95. package/dist/bubbles/tool-bubble/browser-tools/linkedin-sent-invitations/tool.d.ts.map +1 -1
  96. package/dist/bubbles/tool-bubble/browser-tools/linkedin-sent-invitations/tool.js +188 -127
  97. package/dist/bubbles/tool-bubble/browser-tools/linkedin-sent-invitations/tool.js.map +1 -1
  98. package/dist/bubbles/tool-bubble/bubbleflow-validation-tool.d.ts +4 -4
  99. package/dist/bubbles/tool-bubble/company-enrichment-tool.d.ts +20 -20
  100. package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.d.ts +8 -8
  101. package/dist/bubbles/tool-bubble/linkedin-tool.d.ts +380 -380
  102. package/dist/bubbles/tool-bubble/people-search-tool.d.ts +44 -44
  103. package/dist/bubbles/tool-bubble/reddit-scrape-tool.d.ts +10 -10
  104. package/dist/bubbles/tool-bubble/research-agent-tool.d.ts +4 -4
  105. package/dist/bubbles/tool-bubble/sql-query-tool.d.ts +4 -4
  106. package/dist/bubbles/tool-bubble/tiktok-tool.d.ts +60 -60
  107. package/dist/bubbles/tool-bubble/twitter-tool.d.ts +134 -134
  108. package/dist/bubbles/tool-bubble/yc-scraper-tool.d.ts +8 -8
  109. package/dist/bubbles/tool-bubble/youtube-tool.d.ts +20 -20
  110. package/dist/bubbles/workflow-bubble/generate-document.workflow.d.ts +12 -12
  111. package/dist/bubbles/workflow-bubble/pdf-form-operations.workflow.d.ts +8 -8
  112. package/dist/bubbles/workflow-bubble/slack-data-assistant.workflow.d.ts +2 -2
  113. package/dist/bubbles/workflow-bubble/slack-formatter-agent.d.ts +18 -18
  114. package/dist/bubbles.json +73 -2
  115. package/package.json +2 -2
@@ -1,8 +1,43 @@
1
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
2
+ var useValue = arguments.length > 2;
3
+ for (var i = 0; i < initializers.length; i++) {
4
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
5
+ }
6
+ return useValue ? value : void 0;
7
+ };
8
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
9
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
10
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
11
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
12
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
13
+ var _, done = false;
14
+ for (var i = decorators.length - 1; i >= 0; i--) {
15
+ var context = {};
16
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
17
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
18
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
19
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
20
+ if (kind === "accessor") {
21
+ if (result === void 0) continue;
22
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
23
+ if (_ = accept(result.get)) descriptor.get = _;
24
+ if (_ = accept(result.set)) descriptor.set = _;
25
+ if (_ = accept(result.init)) initializers.unshift(_);
26
+ }
27
+ else if (_ = accept(result)) {
28
+ if (kind === "field") initializers.unshift(_);
29
+ else descriptor[key] = _;
30
+ }
31
+ }
32
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
33
+ done = true;
34
+ };
1
35
  import { ToolBubble } from '../../../../types/tool-bubble-class.js';
36
+ import { AIFallbackStep } from '../_shared/ai/ai-fallback-step.js';
2
37
  import { BrowserBaseBubble, } from '../../../service-bubble/browserbase/index.js';
3
38
  import { CredentialType } from '@bubblelab/shared-schemas';
4
39
  import { parseBrowserSessionData, buildProxyConfig } from '../_shared/utils.js';
5
- import { LinkedInConnectionToolParamsSchema, LinkedInConnectionToolResultSchema, } from './schema.js';
40
+ import { LinkedInConnectionToolParamsSchema, LinkedInConnectionToolResultSchema, ProfileInfoSchema, } from './schema.js';
6
41
  /**
7
42
  * Recordable LinkedIn Connection Tool
8
43
  *
@@ -10,106 +45,167 @@ import { LinkedInConnectionToolParamsSchema, LinkedInConnectionToolResultSchema,
10
45
  * Each major action is decorated with @RecordableStep to capture before/after
11
46
  * screenshots, URLs, and timing information.
12
47
  */
13
- export class LinkedInConnectionTool extends ToolBubble {
14
- static bubbleName = 'linkedin-connection-tool';
15
- static schema = LinkedInConnectionToolParamsSchema;
16
- static resultSchema = LinkedInConnectionToolResultSchema;
17
- static shortDescription = 'LinkedIn connection automation with step recording';
18
- static longDescription = `
48
+ let LinkedInConnectionTool = (() => {
49
+ let _classSuper = ToolBubble;
50
+ let _instanceExtraInitializers = [];
51
+ let _stepNavigateToProfile_decorators;
52
+ let _stepWaitForProfilePage_decorators;
53
+ let _stepExtractProfileInfo_decorators;
54
+ let _stepClickConnect_decorators;
55
+ let _stepWaitForModal_decorators;
56
+ let _stepAddNote_decorators;
57
+ let _stepSendRequest_decorators;
58
+ return class LinkedInConnectionTool extends _classSuper {
59
+ static {
60
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
61
+ _stepNavigateToProfile_decorators = [AIFallbackStep('Navigate to profile', {
62
+ taskDescription: 'Navigate to the LinkedIn profile URL and wait for page to load',
63
+ })];
64
+ _stepWaitForProfilePage_decorators = [AIFallbackStep('Wait for profile page', {
65
+ taskDescription: 'Wait for LinkedIn profile page to fully load with action buttons (Connect, Message, Follow)',
66
+ })];
67
+ _stepExtractProfileInfo_decorators = [AIFallbackStep('Extract profile info', {
68
+ taskDescription: 'Extract the LinkedIn profile name, headline, and location from the profile page',
69
+ extractionSchema: ProfileInfoSchema,
70
+ })];
71
+ _stepClickConnect_decorators = [AIFallbackStep('Click Connect button', {
72
+ taskDescription: 'Find and click the Connect button to send a connection request. If there is no visible "Connect" button, first click the "More" button to open the dropdown menu, then click "Connect" inside the dropdown. The goal is to open the connection request modal.',
73
+ })];
74
+ _stepWaitForModal_decorators = [AIFallbackStep('Wait for connection modal', {
75
+ taskDescription: 'Wait for the connection modal to appear with "Add a note" or "Send without a note" buttons',
76
+ })];
77
+ _stepAddNote_decorators = [AIFallbackStep('Add note to connection', {
78
+ taskDescription: 'Click "Add a note" button and type the personalized message into the textarea',
79
+ })];
80
+ _stepSendRequest_decorators = [AIFallbackStep('Send connection request', {
81
+ taskDescription: 'Click the Send button to submit the connection request. Look for a blue "Send" button or "Send without a note" button in the connection modal.',
82
+ })];
83
+ __esDecorate(this, null, _stepNavigateToProfile_decorators, { kind: "method", name: "stepNavigateToProfile", static: false, private: false, access: { has: obj => "stepNavigateToProfile" in obj, get: obj => obj.stepNavigateToProfile }, metadata: _metadata }, null, _instanceExtraInitializers);
84
+ __esDecorate(this, null, _stepWaitForProfilePage_decorators, { kind: "method", name: "stepWaitForProfilePage", static: false, private: false, access: { has: obj => "stepWaitForProfilePage" in obj, get: obj => obj.stepWaitForProfilePage }, metadata: _metadata }, null, _instanceExtraInitializers);
85
+ __esDecorate(this, null, _stepExtractProfileInfo_decorators, { kind: "method", name: "stepExtractProfileInfo", static: false, private: false, access: { has: obj => "stepExtractProfileInfo" in obj, get: obj => obj.stepExtractProfileInfo }, metadata: _metadata }, null, _instanceExtraInitializers);
86
+ __esDecorate(this, null, _stepClickConnect_decorators, { kind: "method", name: "stepClickConnect", static: false, private: false, access: { has: obj => "stepClickConnect" in obj, get: obj => obj.stepClickConnect }, metadata: _metadata }, null, _instanceExtraInitializers);
87
+ __esDecorate(this, null, _stepWaitForModal_decorators, { kind: "method", name: "stepWaitForModal", static: false, private: false, access: { has: obj => "stepWaitForModal" in obj, get: obj => obj.stepWaitForModal }, metadata: _metadata }, null, _instanceExtraInitializers);
88
+ __esDecorate(this, null, _stepAddNote_decorators, { kind: "method", name: "stepAddNote", static: false, private: false, access: { has: obj => "stepAddNote" in obj, get: obj => obj.stepAddNote }, metadata: _metadata }, null, _instanceExtraInitializers);
89
+ __esDecorate(this, null, _stepSendRequest_decorators, { kind: "method", name: "stepSendRequest", static: false, private: false, access: { has: obj => "stepSendRequest" in obj, get: obj => obj.stepSendRequest }, metadata: _metadata }, null, _instanceExtraInitializers);
90
+ if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
91
+ }
92
+ static bubbleName = 'linkedin-connection-tool';
93
+ static schema = LinkedInConnectionToolParamsSchema;
94
+ static resultSchema = LinkedInConnectionToolResultSchema;
95
+ static shortDescription = 'LinkedIn connection automation with step recording';
96
+ static longDescription = `
19
97
  Recordable LinkedIn Connection Tool for automating connection requests.
20
98
  Records each step with screenshots and timing information for debugging.
21
99
  `;
22
- static alias = 'linkedin-recordable';
23
- static type = 'tool';
24
- sessionId = null;
25
- contextId = null;
26
- cookies = null;
27
- constructor(params = { operation: 'send_connection', profile_url: '' }, context) {
28
- super(params, context);
29
- }
30
- /** Required by RecordableToolBubble - returns the active browser session ID */
31
- chooseCredential() {
32
- const { credentials } = this.params;
33
- if (!credentials || typeof credentials !== 'object') {
34
- return undefined;
35
- }
36
- return credentials[CredentialType.LINKEDIN_CRED];
37
- }
38
- parseBrowserSessionData() {
39
- return parseBrowserSessionData(this.chooseCredential());
100
+ static alias = 'linkedin-recordable';
101
+ static type = 'tool';
102
+ /** JS helper to query elements across main document, iframes, and shadow DOM */
103
+ static CROSS_DOM_QUERY = `
104
+ function queryAllDOMs(selector) {
105
+ const results = [...document.querySelectorAll(selector)];
106
+ for (const iframe of document.querySelectorAll('iframe')) {
107
+ try {
108
+ if (iframe.contentDocument) {
109
+ results.push(...iframe.contentDocument.querySelectorAll(selector));
110
+ }
111
+ } catch(e) {}
112
+ }
113
+ const shadowHost = document.querySelector('[data-testid="interop-shadowdom"]');
114
+ if (shadowHost && shadowHost.shadowRoot) {
115
+ results.push(...shadowHost.shadowRoot.querySelectorAll(selector));
116
+ }
117
+ return results;
40
118
  }
41
- // ==================== RECORDABLE STEPS ====================
42
- async stepStartBrowserSession() {
43
- if (this.sessionId)
44
- return;
45
- const sessionData = this.parseBrowserSessionData();
46
- if (sessionData) {
47
- this.contextId = sessionData.contextId;
48
- this.cookies = sessionData.cookies;
119
+ `;
120
+ sessionId = (__runInitializers(this, _instanceExtraInitializers), null);
121
+ contextId = null;
122
+ cookies = null;
123
+ constructor(params = { operation: 'send_connection', profile_url: '' }, context) {
124
+ super(params, context);
49
125
  }
50
- const proxyConfig = buildProxyConfig(this.params.proxy);
51
- const browserbase = new BrowserBaseBubble({
52
- operation: 'start_session',
53
- context_id: this.contextId || undefined,
54
- cookies: this.cookies || undefined,
55
- credentials: this.params.credentials,
56
- stealth: { solveCaptchas: true },
57
- ...proxyConfig,
58
- }, this.context, 'startsession');
59
- const result = await browserbase.action();
60
- if (!result.data.success || !result.data.session_id) {
61
- throw new Error(result.data.error || 'Failed to start browser session');
126
+ /** Required by RecordableToolBubble - returns the active browser session ID */
127
+ chooseCredential() {
128
+ const { credentials } = this.params;
129
+ if (!credentials || typeof credentials !== 'object') {
130
+ return undefined;
131
+ }
132
+ return credentials[CredentialType.LINKEDIN_CRED];
62
133
  }
63
- this.sessionId = result.data.session_id;
64
- if (result.data.context_id) {
65
- this.contextId = result.data.context_id;
134
+ parseBrowserSessionData() {
135
+ return parseBrowserSessionData(this.chooseCredential());
66
136
  }
67
- console.log(`[RecordableLinkedIn] Session started: ${this.sessionId}`);
68
- const ipAddress = await this.detectIPAddress();
69
- if (ipAddress) {
70
- console.log(`[RecordableLinkedIn] Browser IP: ${ipAddress}`);
137
+ // ==================== RECORDABLE STEPS ====================
138
+ async stepStartBrowserSession() {
139
+ if (this.sessionId)
140
+ return;
141
+ const sessionData = this.parseBrowserSessionData();
142
+ if (sessionData) {
143
+ this.contextId = sessionData.contextId;
144
+ this.cookies = sessionData.cookies;
145
+ }
146
+ const proxyConfig = buildProxyConfig(this.params.proxy);
147
+ const browserbase = new BrowserBaseBubble({
148
+ operation: 'start_session',
149
+ context_id: this.contextId || undefined,
150
+ cookies: this.cookies || undefined,
151
+ credentials: this.params.credentials,
152
+ stealth: { solveCaptchas: true },
153
+ ...proxyConfig,
154
+ }, this.context, 'startsession');
155
+ const result = await browserbase.action();
156
+ if (!result.data.success || !result.data.session_id) {
157
+ throw new Error(result.data.error || 'Failed to start browser session');
158
+ }
159
+ this.sessionId = result.data.session_id;
160
+ if (result.data.context_id) {
161
+ this.contextId = result.data.context_id;
162
+ }
163
+ console.log(`[RecordableLinkedIn] Session started: ${this.sessionId}`);
164
+ const ipAddress = await this.detectIPAddress();
165
+ if (ipAddress) {
166
+ console.log(`[RecordableLinkedIn] Browser IP: ${ipAddress}`);
167
+ }
71
168
  }
72
- }
73
- async stepNavigateToProfile() {
74
- if (!this.sessionId)
75
- throw new Error('No active session');
76
- const browserbase = new BrowserBaseBubble({
77
- operation: 'navigate',
78
- session_id: this.sessionId,
79
- url: this.params.profile_url,
80
- wait_until: 'domcontentloaded',
81
- timeout: 30000,
82
- }, this.context, 'navigate');
83
- const result = await browserbase.action();
84
- if (!result.data.success) {
85
- throw new Error(result.data.error || 'Navigation failed');
169
+ async stepNavigateToProfile() {
170
+ if (!this.sessionId)
171
+ throw new Error('No active session');
172
+ const browserbase = new BrowserBaseBubble({
173
+ operation: 'navigate',
174
+ session_id: this.sessionId,
175
+ url: this.params.profile_url,
176
+ wait_until: 'domcontentloaded',
177
+ timeout: 30000,
178
+ }, this.context, 'navigate');
179
+ const result = await browserbase.action();
180
+ if (!result.data.success) {
181
+ throw new Error(result.data.error || 'Navigation failed');
182
+ }
86
183
  }
87
- }
88
- async stepWaitForProfilePage() {
89
- const checkScript = `
184
+ async stepWaitForProfilePage() {
185
+ const checkScript = `
90
186
  (() => {
91
- const buttons = document.querySelectorAll('button');
92
- for (const btn of buttons) {
93
- const ariaLabel = (btn.getAttribute('aria-label') || '').toLowerCase();
94
- const text = (btn.innerText || btn.textContent || '').trim().toLowerCase();
187
+ const elements = document.querySelectorAll('button, a, [role="button"]');
188
+ for (const el of elements) {
189
+ const ariaLabel = (el.getAttribute('aria-label') || '').toLowerCase();
190
+ const text = (el.innerText || el.textContent || '').trim().toLowerCase();
95
191
  if (ariaLabel.includes('connect') || text === 'connect') return true;
96
- if (ariaLabel === 'more actions') return true;
192
+ if (ariaLabel.includes('more actions')) return true;
97
193
  if (text === 'message' || ariaLabel.includes('message')) return true;
98
194
  if (text === 'follow' || ariaLabel.includes('follow')) return true;
99
195
  }
100
196
  return false;
101
197
  })()
102
198
  `;
103
- for (let attempt = 1; attempt <= 30; attempt++) {
104
- const found = await this.evaluate(checkScript);
105
- if (found)
106
- return true;
107
- await new Promise((r) => setTimeout(r, 1000));
199
+ for (let attempt = 1; attempt <= 30; attempt++) {
200
+ const found = await this.evaluate(checkScript);
201
+ if (found)
202
+ return true;
203
+ await new Promise((r) => setTimeout(r, 1000));
204
+ }
205
+ return false;
108
206
  }
109
- return false;
110
- }
111
- async stepExtractProfileInfo() {
112
- const info = (await this.evaluate(`
207
+ async stepExtractProfileInfo() {
208
+ const info = (await this.evaluate(`
113
209
  (() => {
114
210
  let name = '';
115
211
  const h1El = document.querySelector('h1');
@@ -134,54 +230,64 @@ export class LinkedInConnectionTool extends ToolBubble {
134
230
  return { name, headline, location, profile_url: window.location.href };
135
231
  })()
136
232
  `));
137
- return info.name ? info : null;
138
- }
139
- async stepClickConnect() {
140
- const directResult = (await this.evaluate(`
233
+ return info.name ? info : null;
234
+ }
235
+ async stepClickConnect() {
236
+ // Primary: find <a> with custom-invite href (new LinkedIn design)
237
+ const directResult = (await this.evaluate(`
141
238
  (() => {
142
- const buttons = document.querySelectorAll('button, [role="button"]');
143
- for (const btn of buttons) {
144
- const ariaLabel = btn.getAttribute('aria-label') || '';
145
- const text = (btn.innerText || btn.textContent || '').trim().toLowerCase();
146
- if (ariaLabel.toLowerCase().includes('connect') || text === 'connect') {
147
- if (btn.classList.contains('artdeco-button--primary') ||
148
- btn.closest('.pvs-profile-actions') ||
149
- btn.closest('.pv-top-card-v2-ctas') ||
150
- btn.closest('.artdeco-dropdown__content')) {
151
- btn.click();
152
- return { clicked: true, element: btn.tagName + ' - ' + (ariaLabel || text) };
239
+ // New LinkedIn design: Connect is an <a> with /custom-invite/ href
240
+ const connectLink = document.querySelector('a[href*="/custom-invite/"]');
241
+ if (connectLink) {
242
+ connectLink.click();
243
+ return { clicked: true, element: 'A - ' + (connectLink.getAttribute('aria-label') || 'custom-invite') };
244
+ }
245
+
246
+ // Fallback: search all clickable elements by aria-label or text
247
+ const elements = document.querySelectorAll('button, a, [role="button"]');
248
+ for (const el of elements) {
249
+ const ariaLabel = (el.getAttribute('aria-label') || '').toLowerCase();
250
+ const text = (el.innerText || el.textContent || '').trim().toLowerCase();
251
+ if ((ariaLabel.includes('invite') && ariaLabel.includes('connect')) ||
252
+ text === 'connect') {
253
+ const rect = el.getBoundingClientRect();
254
+ if (rect.width > 0 && rect.height > 0) {
255
+ el.click();
256
+ return { clicked: true, element: el.tagName + ' - ' + (ariaLabel || text) };
153
257
  }
154
258
  }
155
259
  }
156
260
  return { clicked: false };
157
261
  })()
158
262
  `));
159
- if (directResult.clicked)
160
- return true;
161
- const moreResult = (await this.evaluate(`
263
+ if (directResult.clicked)
264
+ return true;
265
+ // More dropdown fallback
266
+ const moreResult = (await this.evaluate(`
162
267
  (() => {
163
- const buttons = document.querySelectorAll('button');
164
- for (const btn of buttons) {
165
- const ariaLabel = (btn.getAttribute('aria-label') || '').toLowerCase();
166
- const text = (btn.innerText || btn.textContent || '').trim().toLowerCase();
167
- if ((ariaLabel === 'more actions' || ariaLabel === 'more' || text === 'more') &&
168
- (btn.classList.contains('artdeco-dropdown__trigger') || btn.closest('.pv-top-card-v2-ctas'))) {
169
- btn.click();
268
+ const elements = document.querySelectorAll('button, a, [role="button"]');
269
+ for (const el of elements) {
270
+ const ariaLabel = (el.getAttribute('aria-label') || '').toLowerCase();
271
+ const text = (el.innerText || el.textContent || '').trim().toLowerCase();
272
+ if (ariaLabel.includes('more actions') || text === 'more') {
273
+ el.click();
170
274
  return { clicked: true, element: ariaLabel || text };
171
275
  }
172
276
  }
173
277
  return { clicked: false };
174
278
  })()
175
279
  `));
176
- if (moreResult.clicked) {
177
- await new Promise((r) => setTimeout(r, 1000));
178
- const dropdownResult = (await this.evaluate(`
280
+ if (moreResult.clicked) {
281
+ await new Promise((r) => setTimeout(r, 1000));
282
+ const dropdownResult = (await this.evaluate(`
179
283
  (() => {
180
- const items = document.querySelectorAll('.artdeco-dropdown__item[role="button"], .artdeco-dropdown__content [role="button"]');
284
+ // Search dropdown items, menu items, and list items for Connect
285
+ const items = document.querySelectorAll('[role="button"], [role="menuitem"], [role="option"], li a, li button');
181
286
  for (const item of items) {
182
287
  const ariaLabel = (item.getAttribute('aria-label') || '').toLowerCase();
183
288
  const text = (item.innerText || item.textContent || '').trim().toLowerCase();
184
- if (ariaLabel.includes('connect') || text === 'connect') {
289
+ if ((ariaLabel.includes('invite') && ariaLabel.includes('connect')) ||
290
+ ariaLabel.includes('connect') || text === 'connect') {
185
291
  item.click();
186
292
  return { clicked: true, element: ariaLabel || text };
187
293
  }
@@ -189,49 +295,56 @@ export class LinkedInConnectionTool extends ToolBubble {
189
295
  return { clicked: false, itemCount: items.length };
190
296
  })()
191
297
  `));
192
- if (dropdownResult.clicked)
193
- return true;
194
- throw new Error(`Could not find Connect option in More dropdown (found ${dropdownResult.itemCount} items)`);
298
+ if (dropdownResult.clicked)
299
+ return true;
300
+ throw new Error(`Could not find Connect option in More dropdown (found ${dropdownResult.itemCount} items)`);
301
+ }
302
+ throw new Error('Could not find Connect button or More dropdown');
195
303
  }
196
- throw new Error('Could not find Connect button or More dropdown');
197
- }
198
- async stepWaitForModal() {
199
- const checkScript = `
304
+ async stepWaitForModal() {
305
+ const checkScript = `
200
306
  (() => {
201
- const buttons = document.querySelectorAll('button');
202
- for (const btn of buttons) {
203
- const text = (btn.innerText || btn.textContent || '').trim().toLowerCase();
307
+ ${LinkedInConnectionTool.CROSS_DOM_QUERY}
308
+ const elements = queryAllDOMs('button, a, [role="button"]');
309
+ for (const el of elements) {
310
+ const text = (el.innerText || el.textContent || '').trim().toLowerCase();
204
311
  if (text.includes('add a note') || text.includes('send without')) return true;
205
312
  }
206
313
  return false;
207
314
  })()
208
315
  `;
209
- for (let attempt = 1; attempt <= 8; attempt++) {
210
- const found = await this.evaluate(checkScript);
211
- if (found)
212
- return true;
213
- await new Promise((r) => setTimeout(r, 1000));
316
+ for (let attempt = 1; attempt <= 8; attempt++) {
317
+ const found = await this.evaluate(checkScript);
318
+ if (found)
319
+ return true;
320
+ await new Promise((r) => setTimeout(r, 1000));
321
+ }
322
+ throw new Error('Connection modal did not appear within 8 seconds');
214
323
  }
215
- throw new Error('Connection modal did not appear within 8 seconds');
216
- }
217
- async stepAddNote(message) {
218
- await this.evaluate(`
324
+ async stepAddNote(message) {
325
+ await this.evaluate(`
219
326
  (() => {
220
- const buttons = document.querySelectorAll('button');
221
- for (const btn of buttons) {
222
- const text = (btn.innerText || btn.textContent || '').trim().toLowerCase();
327
+ ${LinkedInConnectionTool.CROSS_DOM_QUERY}
328
+ const elements = queryAllDOMs('button, a, [role="button"]');
329
+ for (const el of elements) {
330
+ const text = (el.innerText || el.textContent || '').trim().toLowerCase();
223
331
  if (text.includes('add a note')) {
224
- btn.click();
332
+ el.click();
225
333
  return true;
226
334
  }
227
335
  }
228
336
  return false;
229
337
  })()
230
338
  `);
231
- await new Promise((r) => setTimeout(r, 500));
232
- await this.evaluate(`
339
+ await new Promise((r) => setTimeout(r, 500));
340
+ await this.evaluate(`
233
341
  (() => {
234
- const textarea = document.querySelector('#custom-message');
342
+ ${LinkedInConnectionTool.CROSS_DOM_QUERY}
343
+ const textareas = queryAllDOMs('textarea');
344
+ const textarea = textareas.find(t => {
345
+ const rect = t.getBoundingClientRect();
346
+ return rect.width > 0 && rect.height > 0;
347
+ }) || textareas[0];
235
348
  if (textarea) {
236
349
  textarea.value = ${JSON.stringify(message)};
237
350
  textarea.dispatchEvent(new Event('input', { bubbles: true }));
@@ -240,75 +353,77 @@ export class LinkedInConnectionTool extends ToolBubble {
240
353
  return false;
241
354
  })()
242
355
  `);
243
- }
244
- async stepSendRequest(withNote) {
245
- if (withNote) {
246
- const result = (await this.evaluate(`
356
+ }
357
+ async stepSendRequest(withNote) {
358
+ if (withNote) {
359
+ const result = (await this.evaluate(`
247
360
  (() => {
248
- const buttons = document.querySelectorAll('button');
249
- for (const btn of buttons) {
250
- const text = (btn.innerText || btn.textContent || '').trim().toLowerCase();
251
- if (text === 'send' && btn.classList.contains('artdeco-button--primary')) {
252
- btn.click();
361
+ ${LinkedInConnectionTool.CROSS_DOM_QUERY}
362
+ const elements = queryAllDOMs('button, a, [role="button"]');
363
+ for (const el of elements) {
364
+ const text = (el.innerText || el.textContent || '').trim().toLowerCase();
365
+ if (text === 'send') {
366
+ el.click();
253
367
  return { clicked: true };
254
368
  }
255
369
  }
256
370
  return { clicked: false };
257
371
  })()
258
372
  `));
259
- if (!result.clicked)
260
- throw new Error('Could not find Send button in modal');
261
- return true;
262
- }
263
- else {
264
- const result = (await this.evaluate(`
373
+ if (!result.clicked)
374
+ throw new Error('Could not find Send button in modal');
375
+ return true;
376
+ }
377
+ else {
378
+ const result = (await this.evaluate(`
265
379
  (() => {
266
- const buttons = document.querySelectorAll('button');
267
- for (const btn of buttons) {
268
- const text = (btn.innerText || btn.textContent || '').trim().toLowerCase();
380
+ ${LinkedInConnectionTool.CROSS_DOM_QUERY}
381
+ const elements = queryAllDOMs('button, a, [role="button"]');
382
+ for (const el of elements) {
383
+ const text = (el.innerText || el.textContent || '').trim().toLowerCase();
269
384
  if (text.includes('send without')) {
270
- btn.click();
385
+ el.click();
271
386
  return { clicked: true };
272
387
  }
273
388
  }
274
389
  return { clicked: false };
275
390
  })()
276
391
  `));
277
- if (!result.clicked)
278
- throw new Error('Could not find "Send without a note" button in modal');
279
- return true;
392
+ if (!result.clicked)
393
+ throw new Error('Could not find "Send without a note" button in modal');
394
+ return true;
395
+ }
280
396
  }
281
- }
282
- async stepEndBrowserSession() {
283
- if (!this.sessionId)
284
- return;
285
- const browserbase = new BrowserBaseBubble({
286
- operation: 'end_session',
287
- session_id: this.sessionId,
288
- }, this.context, 'endsession');
289
- await browserbase.action();
290
- console.log(`[RecordableLinkedIn] Session ended: ${this.sessionId}`);
291
- this.sessionId = null;
292
- }
293
- async evaluate(script) {
294
- if (!this.sessionId)
295
- throw new Error('No active session');
296
- const browserbase = new BrowserBaseBubble({
297
- operation: 'evaluate',
298
- session_id: this.sessionId,
299
- script,
300
- }, this.context, 'evaluate');
301
- const result = await browserbase.action();
302
- if (!result.data.success) {
303
- throw new Error(result.data.error || 'Evaluation failed');
397
+ async stepEndBrowserSession() {
398
+ if (!this.sessionId)
399
+ return;
400
+ const browserbase = new BrowserBaseBubble({
401
+ operation: 'end_session',
402
+ session_id: this.sessionId,
403
+ }, this.context, 'endsession');
404
+ await browserbase.action();
405
+ console.log(`[RecordableLinkedIn] Session ended: ${this.sessionId}`);
406
+ this.sessionId = null;
304
407
  }
305
- return result.data.result;
306
- }
307
- async detectIPAddress() {
308
- if (!this.sessionId)
309
- return null;
310
- try {
311
- const result = await this.evaluate(`
408
+ async evaluate(script) {
409
+ if (!this.sessionId)
410
+ throw new Error('No active session');
411
+ const browserbase = new BrowserBaseBubble({
412
+ operation: 'evaluate',
413
+ session_id: this.sessionId,
414
+ script,
415
+ }, this.context, 'evaluate');
416
+ const result = await browserbase.action();
417
+ if (!result.data.success) {
418
+ throw new Error(result.data.error || 'Evaluation failed');
419
+ }
420
+ return result.data.result;
421
+ }
422
+ async detectIPAddress() {
423
+ if (!this.sessionId)
424
+ return null;
425
+ try {
426
+ const result = await this.evaluate(`
312
427
  (async () => {
313
428
  try {
314
429
  const response = await fetch('https://api.ipify.org?format=json');
@@ -319,46 +434,48 @@ export class LinkedInConnectionTool extends ToolBubble {
319
434
  }
320
435
  })()
321
436
  `);
322
- return result;
323
- }
324
- catch {
325
- return null;
326
- }
327
- }
328
- async performAction() {
329
- try {
330
- await this.stepStartBrowserSession();
331
- await this.stepNavigateToProfile();
332
- const pageReady = await this.stepWaitForProfilePage();
333
- if (!pageReady) {
334
- console.log('[RecordableLinkedIn] Profile page slow to load, continuing anyway');
437
+ return result;
335
438
  }
336
- const profileInfo = await this.stepExtractProfileInfo();
337
- await this.stepClickConnect();
338
- await this.stepWaitForModal();
339
- const { message } = this.params;
340
- if (message) {
341
- await this.stepAddNote(message);
439
+ catch {
440
+ return null;
342
441
  }
343
- await this.stepSendRequest(!!message);
344
- return {
345
- operation: 'send_connection',
346
- success: true,
347
- message: `Connection request sent to ${profileInfo?.name || 'profile'}`,
348
- profile: profileInfo || undefined,
349
- error: '',
350
- };
351
442
  }
352
- catch (error) {
353
- return {
354
- operation: 'send_connection',
355
- success: false,
356
- error: error instanceof Error ? error.message : 'Unknown error',
357
- };
358
- }
359
- finally {
360
- await this.stepEndBrowserSession();
443
+ async performAction() {
444
+ try {
445
+ await this.stepStartBrowserSession();
446
+ await this.stepNavigateToProfile();
447
+ const pageReady = await this.stepWaitForProfilePage();
448
+ if (!pageReady) {
449
+ console.log('[RecordableLinkedIn] Profile page slow to load, continuing anyway');
450
+ }
451
+ const profileInfo = await this.stepExtractProfileInfo();
452
+ await this.stepClickConnect();
453
+ await this.stepWaitForModal();
454
+ const { message } = this.params;
455
+ if (message) {
456
+ await this.stepAddNote(message);
457
+ }
458
+ await this.stepSendRequest(!!message);
459
+ return {
460
+ operation: 'send_connection',
461
+ success: true,
462
+ message: `Connection request sent to ${profileInfo?.name || 'profile'}`,
463
+ profile: profileInfo || undefined,
464
+ error: '',
465
+ };
466
+ }
467
+ catch (error) {
468
+ return {
469
+ operation: 'send_connection',
470
+ success: false,
471
+ error: error instanceof Error ? error.message : 'Unknown error',
472
+ };
473
+ }
474
+ finally {
475
+ await this.stepEndBrowserSession();
476
+ }
361
477
  }
362
- }
363
- }
478
+ };
479
+ })();
480
+ export { LinkedInConnectionTool };
364
481
  //# sourceMappingURL=tool.js.map