@bubblelab/bubble-core 0.1.150 → 0.1.152

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 (61) hide show
  1. package/dist/bubble-bundle.d.ts +6 -6
  2. package/dist/bubbles/service-bubble/browserbase/browserbase.d.ts +37 -0
  3. package/dist/bubbles/service-bubble/browserbase/browserbase.d.ts.map +1 -1
  4. package/dist/bubbles/service-bubble/browserbase/browserbase.js +80 -0
  5. package/dist/bubbles/service-bubble/browserbase/browserbase.js.map +1 -1
  6. package/dist/bubbles/service-bubble/browserbase/browserbase.schema.d.ts +33 -0
  7. package/dist/bubbles/service-bubble/browserbase/browserbase.schema.d.ts.map +1 -1
  8. package/dist/bubbles/service-bubble/browserbase/browserbase.schema.js +30 -0
  9. package/dist/bubbles/service-bubble/browserbase/browserbase.schema.js.map +1 -1
  10. package/dist/bubbles/service-bubble/google-drive.d.ts +1 -1
  11. package/dist/bubbles/service-bubble/google-drive.d.ts.map +1 -1
  12. package/dist/bubbles/service-bubble/google-drive.js +37 -1
  13. package/dist/bubbles/service-bubble/google-drive.js.map +1 -1
  14. package/dist/bubbles/service-bubble/slack/slack.utils.d.ts.map +1 -1
  15. package/dist/bubbles/service-bubble/slack/slack.utils.js +33 -4
  16. package/dist/bubbles/service-bubble/slack/slack.utils.js.map +1 -1
  17. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/ai-browser-agent.d.ts +66 -0
  18. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/ai-browser-agent.d.ts.map +1 -0
  19. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/ai-browser-agent.js +484 -0
  20. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/ai-browser-agent.js.map +1 -0
  21. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/ai-browser-agent.types.d.ts +85 -0
  22. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/ai-browser-agent.types.d.ts.map +1 -0
  23. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/ai-browser-agent.types.js +2 -0
  24. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/ai-browser-agent.types.js.map +1 -0
  25. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/ai-fallback-step.d.ts +27 -0
  26. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/ai-fallback-step.d.ts.map +1 -0
  27. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/ai-fallback-step.js +77 -0
  28. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/ai-fallback-step.js.map +1 -0
  29. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/index.d.ts +4 -0
  30. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/index.d.ts.map +1 -0
  31. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/index.js +3 -0
  32. package/dist/bubbles/tool-bubble/browser-tools/_shared/ai/index.js.map +1 -0
  33. package/dist/bubbles/tool-bubble/browser-tools/linkedin-accept-invitations/tool.d.ts.map +1 -1
  34. package/dist/bubbles/tool-bubble/browser-tools/linkedin-accept-invitations/tool.js +254 -195
  35. package/dist/bubbles/tool-bubble/browser-tools/linkedin-accept-invitations/tool.js.map +1 -1
  36. package/dist/bubbles/tool-bubble/browser-tools/linkedin-connection/tool.d.ts +2 -0
  37. package/dist/bubbles/tool-bubble/browser-tools/linkedin-connection/tool.d.ts.map +1 -1
  38. package/dist/bubbles/tool-bubble/browser-tools/linkedin-connection/tool.js +346 -229
  39. package/dist/bubbles/tool-bubble/browser-tools/linkedin-connection/tool.js.map +1 -1
  40. package/dist/bubbles/tool-bubble/browser-tools/linkedin-received-invitations/tool.d.ts +34 -33
  41. package/dist/bubbles/tool-bubble/browser-tools/linkedin-received-invitations/tool.d.ts.map +1 -1
  42. package/dist/bubbles/tool-bubble/browser-tools/linkedin-received-invitations/tool.js +212 -151
  43. package/dist/bubbles/tool-bubble/browser-tools/linkedin-received-invitations/tool.js.map +1 -1
  44. package/dist/bubbles/tool-bubble/browser-tools/linkedin-sent-invitations/tool.d.ts +33 -32
  45. package/dist/bubbles/tool-bubble/browser-tools/linkedin-sent-invitations/tool.d.ts.map +1 -1
  46. package/dist/bubbles/tool-bubble/browser-tools/linkedin-sent-invitations/tool.js +188 -127
  47. package/dist/bubbles/tool-bubble/browser-tools/linkedin-sent-invitations/tool.js.map +1 -1
  48. package/dist/bubbles.json +73 -2
  49. package/package.json +2 -2
  50. package/dist/bubbles/tool-bubble/linkedin-connection-tool/index.d.ts +0 -3
  51. package/dist/bubbles/tool-bubble/linkedin-connection-tool/index.d.ts.map +0 -1
  52. package/dist/bubbles/tool-bubble/linkedin-connection-tool/index.js +0 -3
  53. package/dist/bubbles/tool-bubble/linkedin-connection-tool/index.js.map +0 -1
  54. package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.d.ts +0 -160
  55. package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.d.ts.map +0 -1
  56. package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.js +0 -706
  57. package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.js.map +0 -1
  58. package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.schema.d.ts +0 -93
  59. package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.schema.d.ts.map +0 -1
  60. package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.schema.js +0 -50
  61. package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.schema.js.map +0 -1
@@ -0,0 +1,77 @@
1
+ import { AIBrowserAgent } from './ai-browser-agent.js';
2
+ /**
3
+ * Lightweight decorator that wraps a method with AI fallback error recovery.
4
+ * This is the OSS-compatible version of @RecordableStep — no recording,
5
+ * just AI-powered recovery when selectors/actions fail.
6
+ *
7
+ * When the decorated method throws, the decorator:
8
+ * 1. Creates an AIBrowserAgent with the active session
9
+ * 2. If extractionSchema is provided: uses AI vision to extract data
10
+ * 3. Otherwise: asks AI to suggest a recovery action (click, type, scroll, etc.)
11
+ * 4. Executes the suggested action
12
+ * 5. For wait/scroll: retries the original method
13
+ * 6. For click/type/click_coordinates: returns true (action completed)
14
+ *
15
+ * @param stepName - Human-readable name for logging
16
+ * @param options - Task description and optional extraction schema
17
+ */
18
+ export function AIFallbackStep(stepName, options = {}) {
19
+ return function (originalMethod, _context) {
20
+ return async function (...args) {
21
+ try {
22
+ return await originalMethod.apply(this, args);
23
+ }
24
+ catch (error) {
25
+ const self = this;
26
+ const errorMsg = error instanceof Error ? error.message : String(error);
27
+ const sessionId = self.sessionId;
28
+ if (!sessionId)
29
+ throw error;
30
+ const aiAgent = new AIBrowserAgent({
31
+ sessionId,
32
+ context: self.context,
33
+ credentials: self.params?.credentials,
34
+ });
35
+ const taskDesc = options.taskDescription || stepName;
36
+ if (options.extractionSchema) {
37
+ console.log(`[AIFallback] Extracting data for "${stepName}"`);
38
+ const extracted = await aiAgent.extractData(options.extractionSchema, taskDesc);
39
+ if (extracted !== null) {
40
+ console.log(`[AIFallback] Extraction succeeded for "${stepName}"`);
41
+ return extracted;
42
+ }
43
+ }
44
+ else {
45
+ console.log(`[AIFallback] Suggesting recovery for "${stepName}"`);
46
+ const action = await aiAgent.suggestRecoveryAction(taskDesc, errorMsg);
47
+ console.log(`[AIFallback] AI suggested:`, action);
48
+ if (action.action !== 'none') {
49
+ const success = await aiAgent.executeAction(action);
50
+ if (success) {
51
+ if (action.action === 'wait' || action.action === 'scroll') {
52
+ console.log(`[AIFallback] Retrying "${stepName}" after ${action.action}`);
53
+ try {
54
+ return await originalMethod.apply(this, args);
55
+ }
56
+ catch (retryError) {
57
+ console.log(`[AIFallback] Retry failed for "${stepName}":`, retryError);
58
+ }
59
+ }
60
+ else if (action.action === 'click' ||
61
+ action.action === 'type' ||
62
+ action.action === 'click_coordinates') {
63
+ console.log(`[AIFallback] Action completed for "${stepName}"`);
64
+ return true;
65
+ }
66
+ }
67
+ }
68
+ else {
69
+ console.log(`[AIFallback] AI could not help: ${action.reason}`);
70
+ }
71
+ }
72
+ throw error;
73
+ }
74
+ };
75
+ };
76
+ }
77
+ //# sourceMappingURL=ai-fallback-step.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-fallback-step.js","sourceRoot":"","sources":["../../../../../../src/bubbles/tool-bubble/browser-tools/_shared/ai/ai-fallback-step.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { AIBrowserAgent } from './ai-browser-agent.js';
2
+ export { AIFallbackStep } from './ai-fallback-step.js';
3
+ export type { AIBrowserAction, AIBrowserAgentConfig, } from './ai-browser-agent.types.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/bubbles/tool-bubble/browser-tools/_shared/ai/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,YAAY,EACV,eAAe,EACf,oBAAoB,GACrB,MAAM,6BAA6B,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { AIBrowserAgent } from './ai-browser-agent.js';
2
+ export { AIFallbackStep } from './ai-fallback-step.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../src/bubbles/tool-bubble/browser-tools/_shared/ai/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../../../../src/bubbles/tool-bubble/browser-tools/linkedin-accept-invitations/tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAKjE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,EAGL,KAAK,wCAAwC,EAC7C,KAAK,mCAAmC,EAEzC,MAAM,aAAa,CAAC;AAErB,qBAAa,6BAA6B,CACxC,CAAC,SACC,wCAAwC,GAAG,wCAAwC,CACrF,SAAQ,UAAU,CAAC,CAAC,EAAE,mCAAmC,CAAC;IAC1D,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAG,kCAAkC,CAAU;IACzE,MAAM,CAAC,QAAQ,CAAC,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAA6C;IACnE,MAAM,CAAC,QAAQ,CAAC,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAA6C;IACzE,MAAM,CAAC,QAAQ,CAAC,gBAAgB,kDACiB;IACjD,MAAM,CAAC,QAAQ,CAAC,eAAe,mIACmG;IAClI,MAAM,CAAC,QAAQ,CAAC,KAAK,iCAAiC;IACtD,MAAM,CAAC,QAAQ,CAAC,IAAI,UAAU;IAE9B,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,OAAO,CAA4B;gBAGzC,MAAM,GAAE,CAA4C,EACpD,OAAO,CAAC,EAAE,aAAa;IAKzB,SAAS,CAAC,gBAAgB,IAAI,MAAM,GAAG,SAAS;YAOlC,uBAAuB;YAgCvB,+BAA+B;YAkB/B,0BAA0B;YAqB1B,wBAAwB;YA2NxB,qBAAqB;YAYrB,QAAQ;YAaR,eAAe;IAiBvB,aAAa,IAAI,OAAO,CAAC,mCAAmC,CAAC;CAyCpE"}
1
+ {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../../../../src/bubbles/tool-bubble/browser-tools/linkedin-accept-invitations/tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAMjE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,EAGL,KAAK,wCAAwC,EAC7C,KAAK,mCAAmC,EAEzC,MAAM,aAAa,CAAC;AAErB,qBAAa,6BAA6B,CACxC,CAAC,SACC,wCAAwC,GAAG,wCAAwC,CACrF,SAAQ,UAAU,CAAC,CAAC,EAAE,mCAAmC,CAAC;IAC1D,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAG,kCAAkC,CAAU;IACzE,MAAM,CAAC,QAAQ,CAAC,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAA6C;IACnE,MAAM,CAAC,QAAQ,CAAC,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAA6C;IACzE,MAAM,CAAC,QAAQ,CAAC,gBAAgB,kDACiB;IACjD,MAAM,CAAC,QAAQ,CAAC,eAAe,mIACmG;IAClI,MAAM,CAAC,QAAQ,CAAC,KAAK,iCAAiC;IACtD,MAAM,CAAC,QAAQ,CAAC,IAAI,UAAU;IAE9B,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,OAAO,CAA4B;gBAGzC,MAAM,GAAE,CAA4C,EACpD,OAAO,CAAC,EAAE,aAAa;IAKzB,SAAS,CAAC,gBAAgB,IAAI,MAAM,GAAG,SAAS;YAOlC,uBAAuB;YAmCvB,+BAA+B;YAsB/B,0BAA0B;YAyB1B,wBAAwB;YA2NxB,qBAAqB;YAYrB,QAAQ;YAaR,eAAe;IAiBvB,aAAa,IAAI,OAAO,CAAC,mCAAmC,CAAC;CAyCpE"}
@@ -1,72 +1,129 @@
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
40
  import { LinkedInAcceptInvitationsToolParamsSchema, LinkedInAcceptInvitationsToolResultSchema, } from './schema.js';
6
- export class LinkedInAcceptInvitationsTool extends ToolBubble {
7
- static bubbleName = 'linkedin-accept-invitations-tool';
8
- static schema = LinkedInAcceptInvitationsToolParamsSchema;
9
- static resultSchema = LinkedInAcceptInvitationsToolResultSchema;
10
- static shortDescription = 'Accept top N LinkedIn connection invitations';
11
- static longDescription = 'Recordable tool that navigates to the LinkedIn invitation manager page and accepts the top N received connection invitations.';
12
- static alias = 'linkedin-accept-invitations';
13
- static type = 'tool';
14
- sessionId = null;
15
- contextId = null;
16
- cookies = null;
17
- constructor(params = { operation: 'accept_invitations' }, context) {
18
- super(params, context);
19
- }
20
- chooseCredential() {
21
- const { credentials } = this.params;
22
- return credentials?.[CredentialType.LINKEDIN_CRED];
23
- }
24
- async stepStartBrowserSession() {
25
- if (this.sessionId)
26
- return;
27
- const sessionData = parseBrowserSessionData(this.chooseCredential());
28
- if (sessionData) {
29
- this.contextId = sessionData.contextId;
30
- this.cookies = sessionData.cookies;
41
+ let LinkedInAcceptInvitationsTool = (() => {
42
+ let _classSuper = ToolBubble;
43
+ let _instanceExtraInitializers = [];
44
+ let _stepNavigateToInvitationManager_decorators;
45
+ let _stepWaitForInvitationsPage_decorators;
46
+ let _stepAcceptTopInvitations_decorators;
47
+ return class LinkedInAcceptInvitationsTool extends _classSuper {
48
+ static {
49
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
50
+ _stepNavigateToInvitationManager_decorators = [AIFallbackStep('Navigate to invitation manager', {
51
+ taskDescription: 'Navigate to the LinkedIn invitation manager page',
52
+ })];
53
+ _stepWaitForInvitationsPage_decorators = [AIFallbackStep('Wait for invitations to load', {
54
+ taskDescription: 'Wait for the received invitations list to fully load with Accept buttons',
55
+ })];
56
+ _stepAcceptTopInvitations_decorators = [AIFallbackStep('Accept top invitations', {
57
+ taskDescription: 'Click Accept on the top N connection invitations and extract their info',
58
+ })];
59
+ __esDecorate(this, null, _stepNavigateToInvitationManager_decorators, { kind: "method", name: "stepNavigateToInvitationManager", static: false, private: false, access: { has: obj => "stepNavigateToInvitationManager" in obj, get: obj => obj.stepNavigateToInvitationManager }, metadata: _metadata }, null, _instanceExtraInitializers);
60
+ __esDecorate(this, null, _stepWaitForInvitationsPage_decorators, { kind: "method", name: "stepWaitForInvitationsPage", static: false, private: false, access: { has: obj => "stepWaitForInvitationsPage" in obj, get: obj => obj.stepWaitForInvitationsPage }, metadata: _metadata }, null, _instanceExtraInitializers);
61
+ __esDecorate(this, null, _stepAcceptTopInvitations_decorators, { kind: "method", name: "stepAcceptTopInvitations", static: false, private: false, access: { has: obj => "stepAcceptTopInvitations" in obj, get: obj => obj.stepAcceptTopInvitations }, metadata: _metadata }, null, _instanceExtraInitializers);
62
+ if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
31
63
  }
32
- const proxyConfig = buildProxyConfig(this.params.proxy);
33
- const browserbase = new BrowserBaseBubble({
34
- operation: 'start_session',
35
- context_id: this.contextId || undefined,
36
- cookies: this.cookies || undefined,
37
- credentials: this.params.credentials,
38
- stealth: { solveCaptchas: true },
39
- timeout_seconds: 1200,
40
- ...proxyConfig,
41
- }, this.context, 'startsession');
42
- const result = await browserbase.action();
43
- if (!result.data.success || !result.data.session_id) {
44
- throw new Error(result.data.error || 'Failed to start browser session');
64
+ static bubbleName = 'linkedin-accept-invitations-tool';
65
+ static schema = LinkedInAcceptInvitationsToolParamsSchema;
66
+ static resultSchema = LinkedInAcceptInvitationsToolResultSchema;
67
+ static shortDescription = 'Accept top N LinkedIn connection invitations';
68
+ static longDescription = 'Recordable tool that navigates to the LinkedIn invitation manager page and accepts the top N received connection invitations.';
69
+ static alias = 'linkedin-accept-invitations';
70
+ static type = 'tool';
71
+ sessionId = (__runInitializers(this, _instanceExtraInitializers), null);
72
+ contextId = null;
73
+ cookies = null;
74
+ constructor(params = { operation: 'accept_invitations' }, context) {
75
+ super(params, context);
45
76
  }
46
- this.sessionId = result.data.session_id;
47
- if (result.data.context_id)
48
- this.contextId = result.data.context_id;
49
- console.log(`[AcceptInvitations] Session started: ${this.sessionId}`);
50
- const ip = await this.detectIPAddress();
51
- if (ip)
52
- console.log(`[AcceptInvitations] Browser IP: ${ip}`);
53
- }
54
- async stepNavigateToInvitationManager() {
55
- if (!this.sessionId)
56
- throw new Error('No active session');
57
- const browserbase = new BrowserBaseBubble({
58
- operation: 'navigate',
59
- session_id: this.sessionId,
60
- url: 'https://www.linkedin.com/mynetwork/invitation-manager/',
61
- wait_until: 'domcontentloaded',
62
- timeout: 30000,
63
- }, this.context, 'navigate');
64
- const result = await browserbase.action();
65
- if (!result.data.success)
66
- throw new Error(result.data.error || 'Navigation failed');
67
- }
68
- async stepWaitForInvitationsPage() {
69
- const checkScript = `(() => {
77
+ chooseCredential() {
78
+ const { credentials } = this.params;
79
+ return credentials?.[CredentialType.LINKEDIN_CRED];
80
+ }
81
+ async stepStartBrowserSession() {
82
+ if (this.sessionId)
83
+ return;
84
+ const sessionData = parseBrowserSessionData(this.chooseCredential());
85
+ if (sessionData) {
86
+ this.contextId = sessionData.contextId;
87
+ this.cookies = sessionData.cookies;
88
+ }
89
+ const proxyConfig = buildProxyConfig(this.params.proxy);
90
+ const browserbase = new BrowserBaseBubble({
91
+ operation: 'start_session',
92
+ context_id: this.contextId || undefined,
93
+ cookies: this.cookies || undefined,
94
+ credentials: this.params.credentials,
95
+ stealth: { solveCaptchas: true },
96
+ timeout_seconds: 1200,
97
+ ...proxyConfig,
98
+ }, this.context, 'startsession');
99
+ const result = await browserbase.action();
100
+ if (!result.data.success || !result.data.session_id) {
101
+ throw new Error(result.data.error || 'Failed to start browser session');
102
+ }
103
+ this.sessionId = result.data.session_id;
104
+ if (result.data.context_id)
105
+ this.contextId = result.data.context_id;
106
+ console.log(`[AcceptInvitations] Session started: ${this.sessionId}`);
107
+ const ip = await this.detectIPAddress();
108
+ if (ip)
109
+ console.log(`[AcceptInvitations] Browser IP: ${ip}`);
110
+ }
111
+ async stepNavigateToInvitationManager() {
112
+ if (!this.sessionId)
113
+ throw new Error('No active session');
114
+ const browserbase = new BrowserBaseBubble({
115
+ operation: 'navigate',
116
+ session_id: this.sessionId,
117
+ url: 'https://www.linkedin.com/mynetwork/invitation-manager/',
118
+ wait_until: 'domcontentloaded',
119
+ timeout: 30000,
120
+ }, this.context, 'navigate');
121
+ const result = await browserbase.action();
122
+ if (!result.data.success)
123
+ throw new Error(result.data.error || 'Navigation failed');
124
+ }
125
+ async stepWaitForInvitationsPage() {
126
+ const checkScript = `(() => {
70
127
  const buttons = document.querySelectorAll('button');
71
128
  let hasAcceptButton = false;
72
129
  for (const btn of buttons) {
@@ -78,25 +135,25 @@ export class LinkedInAcceptInvitationsTool extends ToolBubble {
78
135
  const peopleLabel = document.body.innerText.match(/People\\s*\\(\\d+\\)/i);
79
136
  return hasAcceptButton || !!peopleLabel;
80
137
  })()`;
81
- for (let attempt = 1; attempt <= 15; attempt++) {
82
- const found = await this.evaluate(checkScript);
83
- if (found)
84
- return true;
85
- await new Promise((r) => setTimeout(r, 1000));
138
+ for (let attempt = 1; attempt <= 15; attempt++) {
139
+ const found = await this.evaluate(checkScript);
140
+ if (found)
141
+ return true;
142
+ await new Promise((r) => setTimeout(r, 1000));
143
+ }
144
+ return false;
86
145
  }
87
- return false;
88
- }
89
- async stepAcceptTopInvitations() {
90
- const count = this.params.count ?? 5;
91
- const accepted = [];
92
- let skipped = 0;
93
- let availableCount = 0;
94
- const TEMP_ID = '__bubblelab_accept_target__';
95
- const MAX_CLICK_RETRIES = 2;
96
- const POST_ACCEPT_SETTLE_MS = 1500;
97
- for (let i = 0; i < count; i++) {
98
- // Step 1: Find first visible Accept button, extract card info, tag it with a temp ID
99
- const extractResult = (await this.evaluate(`
146
+ async stepAcceptTopInvitations() {
147
+ const count = this.params.count ?? 5;
148
+ const accepted = [];
149
+ let skipped = 0;
150
+ let availableCount = 0;
151
+ const TEMP_ID = '__bubblelab_accept_target__';
152
+ const MAX_CLICK_RETRIES = 2;
153
+ const POST_ACCEPT_SETTLE_MS = 1500;
154
+ for (let i = 0; i < count; i++) {
155
+ // Step 1: Find first visible Accept button, extract card info, tag it with a temp ID
156
+ const extractResult = (await this.evaluate(`
100
157
  (() => {
101
158
  // Clean up any previous temp ID
102
159
  const prev = document.getElementById('${TEMP_ID}');
@@ -203,24 +260,24 @@ export class LinkedInAcceptInvitationsTool extends ToolBubble {
203
260
  };
204
261
  })()
205
262
  `));
206
- if (extractResult.done) {
207
- console.log(`[AcceptInvitations] No more invitations to accept after ${accepted.length}`);
208
- break;
209
- }
210
- // Track available invitations on first iteration
211
- if (i === 0)
212
- availableCount = extractResult.buttonCount;
213
- const prevButtonCount = extractResult.buttonCount;
214
- // Step 2: Click the tagged button with retries (re-tag on failure)
215
- if (!this.sessionId)
216
- throw new Error('No active session');
217
- let clickSucceeded = false;
218
- for (let retry = 0; retry <= MAX_CLICK_RETRIES; retry++) {
219
- // On retry, wait for DOM to settle then re-tag the button
220
- if (retry > 0) {
221
- console.log(`[AcceptInvitations] Retrying click for invitation ${i + 1} (attempt ${retry + 1})`);
222
- await new Promise((r) => setTimeout(r, 1500));
223
- await this.evaluate(`
263
+ if (extractResult.done) {
264
+ console.log(`[AcceptInvitations] No more invitations to accept after ${accepted.length}`);
265
+ break;
266
+ }
267
+ // Track available invitations on first iteration
268
+ if (i === 0)
269
+ availableCount = extractResult.buttonCount;
270
+ const prevButtonCount = extractResult.buttonCount;
271
+ // Step 2: Click the tagged button with retries (re-tag on failure)
272
+ if (!this.sessionId)
273
+ throw new Error('No active session');
274
+ let clickSucceeded = false;
275
+ for (let retry = 0; retry <= MAX_CLICK_RETRIES; retry++) {
276
+ // On retry, wait for DOM to settle then re-tag the button
277
+ if (retry > 0) {
278
+ console.log(`[AcceptInvitations] Retrying click for invitation ${i + 1} (attempt ${retry + 1})`);
279
+ await new Promise((r) => setTimeout(r, 1500));
280
+ await this.evaluate(`
224
281
  (() => {
225
282
  const prev = document.getElementById('${TEMP_ID}');
226
283
  if (prev) prev.removeAttribute('id');
@@ -234,70 +291,70 @@ export class LinkedInAcceptInvitationsTool extends ToolBubble {
234
291
  return true;
235
292
  })()
236
293
  `);
294
+ }
295
+ const clickBubble = new BrowserBaseBubble({
296
+ operation: 'click',
297
+ session_id: this.sessionId,
298
+ selector: `#${TEMP_ID}`,
299
+ wait_for_navigation: false,
300
+ timeout: 5000,
301
+ }, this.context, 'clickaccept');
302
+ const clickResult = await clickBubble.action();
303
+ if (clickResult.data.success) {
304
+ clickSucceeded = true;
305
+ break;
306
+ }
237
307
  }
238
- const clickBubble = new BrowserBaseBubble({
239
- operation: 'click',
240
- session_id: this.sessionId,
241
- selector: `#${TEMP_ID}`,
242
- wait_for_navigation: false,
243
- timeout: 5000,
244
- }, this.context, 'clickaccept');
245
- const clickResult = await clickBubble.action();
246
- if (clickResult.data.success) {
247
- clickSucceeded = true;
248
- break;
308
+ if (!clickSucceeded) {
309
+ console.log(`[AcceptInvitations] Click failed for invitation ${i + 1} after ${MAX_CLICK_RETRIES + 1} attempts, skipping`);
310
+ skipped++;
311
+ await new Promise((r) => setTimeout(r, 1000));
312
+ continue;
249
313
  }
250
- }
251
- if (!clickSucceeded) {
252
- console.log(`[AcceptInvitations] Click failed for invitation ${i + 1} after ${MAX_CLICK_RETRIES + 1} attempts, skipping`);
253
- skipped++;
254
- await new Promise((r) => setTimeout(r, 1000));
255
- continue;
256
- }
257
- if (extractResult.info) {
258
- accepted.push(extractResult.info);
259
- console.log(`[AcceptInvitations] Accepted ${i + 1}/${count}: ${extractResult.info.name}`);
260
- }
261
- // Step 3: Wait for DOM to update — poll until Accept button count decreases
262
- const MAX_WAIT_POLLS = 15;
263
- for (let poll = 0; poll < MAX_WAIT_POLLS; poll++) {
264
- await new Promise((r) => setTimeout(r, 500));
265
- const currentCount = (await this.evaluate(`
314
+ if (extractResult.info) {
315
+ accepted.push(extractResult.info);
316
+ console.log(`[AcceptInvitations] Accepted ${i + 1}/${count}: ${extractResult.info.name}`);
317
+ }
318
+ // Step 3: Wait for DOM to update — poll until Accept button count decreases
319
+ const MAX_WAIT_POLLS = 15;
320
+ for (let poll = 0; poll < MAX_WAIT_POLLS; poll++) {
321
+ await new Promise((r) => setTimeout(r, 500));
322
+ const currentCount = (await this.evaluate(`
266
323
  Array.from(document.querySelectorAll('button')).filter(btn => {
267
324
  const text = (btn.innerText || btn.textContent || '').trim().toLowerCase();
268
325
  return text === 'accept' && btn.offsetParent !== null && !btn.disabled;
269
326
  }).length
270
327
  `));
271
- if (currentCount < prevButtonCount)
272
- break;
328
+ if (currentCount < prevButtonCount)
329
+ break;
330
+ }
331
+ // Extra settle time for LinkedIn UI animations before next iteration
332
+ await new Promise((r) => setTimeout(r, POST_ACCEPT_SETTLE_MS));
273
333
  }
274
- // Extra settle time for LinkedIn UI animations before next iteration
275
- await new Promise((r) => setTimeout(r, POST_ACCEPT_SETTLE_MS));
334
+ return { accepted, skipped, availableCount };
276
335
  }
277
- return { accepted, skipped, availableCount };
278
- }
279
- async stepEndBrowserSession() {
280
- if (!this.sessionId)
281
- return;
282
- const browserbase = new BrowserBaseBubble({ operation: 'end_session', session_id: this.sessionId }, this.context, 'endsession');
283
- await browserbase.action();
284
- console.log(`[AcceptInvitations] Session ended: ${this.sessionId}`);
285
- this.sessionId = null;
286
- }
287
- async evaluate(script) {
288
- if (!this.sessionId)
289
- throw new Error('No active session');
290
- const browserbase = new BrowserBaseBubble({ operation: 'evaluate', session_id: this.sessionId, script }, this.context, 'evaluate');
291
- const result = await browserbase.action();
292
- if (!result.data.success)
293
- throw new Error(result.data.error || 'Evaluation failed');
294
- return result.data.result;
295
- }
296
- async detectIPAddress() {
297
- if (!this.sessionId)
298
- return null;
299
- try {
300
- return (await this.evaluate(`
336
+ async stepEndBrowserSession() {
337
+ if (!this.sessionId)
338
+ return;
339
+ const browserbase = new BrowserBaseBubble({ operation: 'end_session', session_id: this.sessionId }, this.context, 'endsession');
340
+ await browserbase.action();
341
+ console.log(`[AcceptInvitations] Session ended: ${this.sessionId}`);
342
+ this.sessionId = null;
343
+ }
344
+ async evaluate(script) {
345
+ if (!this.sessionId)
346
+ throw new Error('No active session');
347
+ const browserbase = new BrowserBaseBubble({ operation: 'evaluate', session_id: this.sessionId, script }, this.context, 'evaluate');
348
+ const result = await browserbase.action();
349
+ if (!result.data.success)
350
+ throw new Error(result.data.error || 'Evaluation failed');
351
+ return result.data.result;
352
+ }
353
+ async detectIPAddress() {
354
+ if (!this.sessionId)
355
+ return null;
356
+ try {
357
+ return (await this.evaluate(`
301
358
  (async () => {
302
359
  try {
303
360
  const r = await fetch('https://api.ipify.org?format=json');
@@ -306,48 +363,50 @@ export class LinkedInAcceptInvitationsTool extends ToolBubble {
306
363
  } catch { return null; }
307
364
  })()
308
365
  `));
366
+ }
367
+ catch {
368
+ return null;
369
+ }
309
370
  }
310
- catch {
311
- return null;
312
- }
313
- }
314
- async performAction() {
315
- try {
316
- await this.stepStartBrowserSession();
317
- await this.stepNavigateToInvitationManager();
318
- const pageReady = await this.stepWaitForInvitationsPage();
319
- if (!pageReady)
320
- console.log('[AcceptInvitations] Page slow to load, continuing');
321
- const { accepted, skipped, availableCount } = await this.stepAcceptTopInvitations();
322
- const count = this.params.count ?? 5;
323
- // Success if we accepted all requested, OR if fewer were available than requested
324
- const allAvailableAccepted = availableCount < count
325
- ? accepted.length >= availableCount
326
- : accepted.length >= count;
327
- return {
328
- operation: 'accept_invitations',
329
- success: allAvailableAccepted,
330
- accepted,
331
- accepted_count: accepted.length,
332
- skipped_count: skipped,
333
- message: allAvailableAccepted
334
- ? `Accepted ${accepted.length} invitation(s)${availableCount < count ? ` (only ${availableCount} available)` : ''}`
335
- : `Accepted ${accepted.length}/${count} invitation(s), ${skipped} failed`,
336
- error: allAvailableAccepted
337
- ? ''
338
- : `Failed to accept ${skipped} invitation(s)`,
339
- };
340
- }
341
- catch (error) {
342
- return {
343
- operation: 'accept_invitations',
344
- success: false,
345
- error: error instanceof Error ? error.message : 'Unknown error',
346
- };
347
- }
348
- finally {
349
- await this.stepEndBrowserSession();
371
+ async performAction() {
372
+ try {
373
+ await this.stepStartBrowserSession();
374
+ await this.stepNavigateToInvitationManager();
375
+ const pageReady = await this.stepWaitForInvitationsPage();
376
+ if (!pageReady)
377
+ console.log('[AcceptInvitations] Page slow to load, continuing');
378
+ const { accepted, skipped, availableCount } = await this.stepAcceptTopInvitations();
379
+ const count = this.params.count ?? 5;
380
+ // Success if we accepted all requested, OR if fewer were available than requested
381
+ const allAvailableAccepted = availableCount < count
382
+ ? accepted.length >= availableCount
383
+ : accepted.length >= count;
384
+ return {
385
+ operation: 'accept_invitations',
386
+ success: allAvailableAccepted,
387
+ accepted,
388
+ accepted_count: accepted.length,
389
+ skipped_count: skipped,
390
+ message: allAvailableAccepted
391
+ ? `Accepted ${accepted.length} invitation(s)${availableCount < count ? ` (only ${availableCount} available)` : ''}`
392
+ : `Accepted ${accepted.length}/${count} invitation(s), ${skipped} failed`,
393
+ error: allAvailableAccepted
394
+ ? ''
395
+ : `Failed to accept ${skipped} invitation(s)`,
396
+ };
397
+ }
398
+ catch (error) {
399
+ return {
400
+ operation: 'accept_invitations',
401
+ success: false,
402
+ error: error instanceof Error ? error.message : 'Unknown error',
403
+ };
404
+ }
405
+ finally {
406
+ await this.stepEndBrowserSession();
407
+ }
350
408
  }
351
- }
352
- }
409
+ };
410
+ })();
411
+ export { LinkedInAcceptInvitationsTool };
353
412
  //# sourceMappingURL=tool.js.map