erosolar-cli 1.5.14 → 1.6.0

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 (36) hide show
  1. package/dist/browser/BrowserSessionManager.d.ts +307 -0
  2. package/dist/browser/BrowserSessionManager.d.ts.map +1 -0
  3. package/dist/browser/BrowserSessionManager.js +713 -0
  4. package/dist/browser/BrowserSessionManager.js.map +1 -0
  5. package/dist/capabilities/browserAutomationCapability.d.ts +37 -0
  6. package/dist/capabilities/browserAutomationCapability.d.ts.map +1 -0
  7. package/dist/capabilities/browserAutomationCapability.js +49 -0
  8. package/dist/capabilities/browserAutomationCapability.js.map +1 -0
  9. package/dist/capabilities/frontendTestingCapability.d.ts +13 -0
  10. package/dist/capabilities/frontendTestingCapability.d.ts.map +1 -0
  11. package/dist/capabilities/frontendTestingCapability.js +28 -0
  12. package/dist/capabilities/frontendTestingCapability.js.map +1 -0
  13. package/dist/capabilities/index.d.ts +2 -0
  14. package/dist/capabilities/index.d.ts.map +1 -1
  15. package/dist/capabilities/index.js +2 -0
  16. package/dist/capabilities/index.js.map +1 -1
  17. package/dist/plugins/tools/browser/browserAutomationPlugin.d.ts +14 -0
  18. package/dist/plugins/tools/browser/browserAutomationPlugin.d.ts.map +1 -0
  19. package/dist/plugins/tools/browser/browserAutomationPlugin.js +26 -0
  20. package/dist/plugins/tools/browser/browserAutomationPlugin.js.map +1 -0
  21. package/dist/plugins/tools/frontendTesting/frontendTestingPlugin.d.ts +3 -0
  22. package/dist/plugins/tools/frontendTesting/frontendTestingPlugin.d.ts.map +1 -0
  23. package/dist/plugins/tools/frontendTesting/frontendTestingPlugin.js +14 -0
  24. package/dist/plugins/tools/frontendTesting/frontendTestingPlugin.js.map +1 -0
  25. package/dist/plugins/tools/nodeDefaults.d.ts.map +1 -1
  26. package/dist/plugins/tools/nodeDefaults.js +4 -0
  27. package/dist/plugins/tools/nodeDefaults.js.map +1 -1
  28. package/dist/tools/browserAutomationTools.d.ts +23 -0
  29. package/dist/tools/browserAutomationTools.d.ts.map +1 -0
  30. package/dist/tools/browserAutomationTools.js +908 -0
  31. package/dist/tools/browserAutomationTools.js.map +1 -0
  32. package/dist/tools/frontendTestingTools.d.ts +35 -0
  33. package/dist/tools/frontendTestingTools.d.ts.map +1 -0
  34. package/dist/tools/frontendTestingTools.js +1254 -0
  35. package/dist/tools/frontendTestingTools.js.map +1 -0
  36. package/package.json +4 -1
@@ -0,0 +1,713 @@
1
+ /**
2
+ * Browser Session Manager - Manages browser instances, sessions, cookies, and authentication
3
+ *
4
+ * Provides browser-use-like functionality for AI agents:
5
+ * - Persistent browser sessions with cookie management
6
+ * - Authentication state persistence
7
+ * - Multi-profile support
8
+ * - Session recovery and cleanup
9
+ *
10
+ * @license MIT
11
+ * @author Bo Shang
12
+ */
13
+ import { chromium, firefox, webkit } from 'playwright';
14
+ import * as fs from 'fs';
15
+ import * as path from 'path';
16
+ /**
17
+ * Browser Session Manager
18
+ * Manages browser instances, sessions, and authentication state
19
+ */
20
+ export class BrowserSessionManager {
21
+ sessions = new Map();
22
+ storageDir;
23
+ constructor(storageDir) {
24
+ this.storageDir = storageDir || path.join(process.env['HOME'] || '~', '.erosolar', 'browser-sessions');
25
+ this.ensureStorageDir();
26
+ }
27
+ ensureStorageDir() {
28
+ if (!fs.existsSync(this.storageDir)) {
29
+ fs.mkdirSync(this.storageDir, { recursive: true });
30
+ }
31
+ }
32
+ /**
33
+ * Create a new browser session
34
+ */
35
+ async createSession(config) {
36
+ const sessionId = config.sessionId || `session-${Date.now()}`;
37
+ // Check if session already exists
38
+ if (this.sessions.has(sessionId)) {
39
+ return sessionId;
40
+ }
41
+ // Select browser type
42
+ const browserType = config.browserType || 'chromium';
43
+ const browserLauncher = browserType === 'firefox' ? firefox : browserType === 'webkit' ? webkit : chromium;
44
+ // Build launch options
45
+ const launchOptions = {
46
+ headless: config.headless !== false,
47
+ };
48
+ if (config.proxy) {
49
+ launchOptions.proxy = config.proxy;
50
+ }
51
+ // Launch browser
52
+ const browser = await browserLauncher.launch(launchOptions);
53
+ // Build context options
54
+ const contextOptions = {
55
+ viewport: config.viewport || { width: 1920, height: 1080 },
56
+ };
57
+ if (config.userAgent) {
58
+ contextOptions.userAgent = config.userAgent;
59
+ }
60
+ // Apply stealth mode settings
61
+ if (config.stealthMode) {
62
+ contextOptions.userAgent = contextOptions.userAgent ||
63
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36';
64
+ contextOptions.locale = 'en-US';
65
+ contextOptions.timezoneId = 'America/New_York';
66
+ contextOptions.permissions = ['geolocation'];
67
+ contextOptions.extraHTTPHeaders = {
68
+ 'Accept-Language': 'en-US,en;q=0.9',
69
+ };
70
+ }
71
+ // Load existing session state if available
72
+ const savedState = await this.loadSessionState(sessionId);
73
+ if (savedState && savedState.cookies.length > 0) {
74
+ contextOptions.storageState = {
75
+ cookies: savedState.cookies.map(c => ({
76
+ name: c.name,
77
+ value: c.value,
78
+ domain: c.domain,
79
+ path: c.path,
80
+ expires: c.expires || -1,
81
+ httpOnly: c.httpOnly || false,
82
+ secure: c.secure || false,
83
+ sameSite: c.sameSite || 'Lax',
84
+ })),
85
+ origins: [],
86
+ };
87
+ }
88
+ // Create browser context
89
+ const context = await browser.newContext(contextOptions);
90
+ // Apply stealth scripts
91
+ if (config.stealthMode) {
92
+ await this.applyStealthScripts(context);
93
+ }
94
+ // Create initial page
95
+ const page = await context.newPage();
96
+ // Set default timeout
97
+ page.setDefaultTimeout(config.timeout || 30000);
98
+ // Create session state
99
+ const state = {
100
+ sessionId,
101
+ browserType,
102
+ isActive: true,
103
+ createdAt: Date.now(),
104
+ lastAccessedAt: Date.now(),
105
+ isAuthenticated: savedState?.isAuthenticated || false,
106
+ authDomain: savedState?.authDomain,
107
+ cookies: savedState?.cookies || [],
108
+ };
109
+ // Store active session
110
+ this.sessions.set(sessionId, {
111
+ config,
112
+ browser,
113
+ context,
114
+ page,
115
+ state,
116
+ });
117
+ return sessionId;
118
+ }
119
+ /**
120
+ * Apply stealth scripts to avoid bot detection
121
+ */
122
+ async applyStealthScripts(context) {
123
+ await context.addInitScript(() => {
124
+ // Override webdriver detection
125
+ Object.defineProperty(navigator, 'webdriver', {
126
+ get: () => undefined,
127
+ });
128
+ // Override plugins
129
+ Object.defineProperty(navigator, 'plugins', {
130
+ get: () => [1, 2, 3, 4, 5],
131
+ });
132
+ // Override languages
133
+ Object.defineProperty(navigator, 'languages', {
134
+ get: () => ['en-US', 'en'],
135
+ });
136
+ // Override permissions
137
+ const originalQuery = window.navigator.permissions.query;
138
+ window.navigator.permissions.query = (parameters) => parameters.name === 'notifications'
139
+ ? Promise.resolve({ state: Notification.permission })
140
+ : originalQuery(parameters);
141
+ // Override chrome runtime
142
+ window.chrome = {
143
+ runtime: {},
144
+ };
145
+ });
146
+ }
147
+ /**
148
+ * Get an active session
149
+ */
150
+ getSession(sessionId) {
151
+ const session = this.sessions.get(sessionId);
152
+ if (session) {
153
+ session.state.lastAccessedAt = Date.now();
154
+ }
155
+ return session;
156
+ }
157
+ /**
158
+ * Get the page for a session
159
+ */
160
+ getPage(sessionId) {
161
+ return this.getSession(sessionId)?.page;
162
+ }
163
+ /**
164
+ * Navigate to a URL
165
+ */
166
+ async navigateTo(sessionId, url, options) {
167
+ const session = this.getSession(sessionId);
168
+ if (!session) {
169
+ return { success: false, url: '', title: '', error: `Session ${sessionId} not found` };
170
+ }
171
+ try {
172
+ const response = await session.page.goto(url, {
173
+ waitUntil: options?.waitUntil || 'domcontentloaded',
174
+ });
175
+ session.state.currentUrl = session.page.url();
176
+ return {
177
+ success: response?.ok() ?? true,
178
+ url: session.page.url(),
179
+ title: await session.page.title(),
180
+ };
181
+ }
182
+ catch (error) {
183
+ return {
184
+ success: false,
185
+ url: url,
186
+ title: '',
187
+ error: error instanceof Error ? error.message : String(error),
188
+ };
189
+ }
190
+ }
191
+ /**
192
+ * Perform authentication
193
+ */
194
+ async authenticate(sessionId, authConfig) {
195
+ const session = this.getSession(sessionId);
196
+ if (!session) {
197
+ return { success: false, message: `Session ${sessionId} not found` };
198
+ }
199
+ try {
200
+ switch (authConfig.type) {
201
+ case 'form':
202
+ return await this.performFormAuth(session, authConfig);
203
+ case 'basic':
204
+ return await this.performBasicAuth(session, authConfig);
205
+ case 'cookie':
206
+ return await this.performCookieAuth(session, authConfig);
207
+ case 'token':
208
+ return await this.performTokenAuth(session, authConfig);
209
+ case 'oauth':
210
+ return { success: false, message: 'OAuth authentication requires manual interaction' };
211
+ default:
212
+ return { success: false, message: `Unknown auth type: ${authConfig.type}` };
213
+ }
214
+ }
215
+ catch (error) {
216
+ return {
217
+ success: false,
218
+ message: error instanceof Error ? error.message : String(error),
219
+ };
220
+ }
221
+ }
222
+ /**
223
+ * Perform form-based authentication
224
+ */
225
+ async performFormAuth(session, authConfig) {
226
+ const { page } = session;
227
+ const { credentials, formSelectors, loginUrl, successUrl, successSelector } = authConfig;
228
+ if (!credentials?.username || !credentials?.password) {
229
+ return { success: false, message: 'Username and password required for form auth' };
230
+ }
231
+ if (!formSelectors) {
232
+ return { success: false, message: 'Form selectors required for form auth' };
233
+ }
234
+ // Navigate to login page if specified
235
+ if (loginUrl) {
236
+ await page.goto(loginUrl, { waitUntil: 'domcontentloaded' });
237
+ }
238
+ // Fill in credentials
239
+ await page.fill(formSelectors.usernameField, credentials.username);
240
+ await page.fill(formSelectors.passwordField, credentials.password);
241
+ // Submit form
242
+ await page.click(formSelectors.submitButton);
243
+ // Wait for navigation or success indicator
244
+ if (successUrl) {
245
+ await page.waitForURL(successUrl, { timeout: 10000 }).catch(() => { });
246
+ }
247
+ else if (successSelector) {
248
+ await page.waitForSelector(successSelector, { timeout: 10000 }).catch(() => { });
249
+ }
250
+ else {
251
+ await page.waitForLoadState('networkidle');
252
+ }
253
+ // Check if authentication succeeded
254
+ const currentUrl = page.url();
255
+ const isSuccess = successUrl ? currentUrl.includes(successUrl) :
256
+ successSelector ? await page.$(successSelector) !== null : true;
257
+ if (isSuccess) {
258
+ session.state.isAuthenticated = true;
259
+ session.state.authDomain = new URL(currentUrl).hostname;
260
+ await this.saveCookies(session);
261
+ return { success: true, message: 'Authentication successful' };
262
+ }
263
+ return { success: false, message: 'Authentication failed - could not verify success' };
264
+ }
265
+ /**
266
+ * Perform basic HTTP authentication
267
+ */
268
+ async performBasicAuth(session, authConfig) {
269
+ const { context } = session;
270
+ const { credentials } = authConfig;
271
+ if (!credentials?.username || !credentials?.password) {
272
+ return { success: false, message: 'Username and password required for basic auth' };
273
+ }
274
+ await context.setHTTPCredentials({
275
+ username: credentials.username,
276
+ password: credentials.password,
277
+ });
278
+ session.state.isAuthenticated = true;
279
+ return { success: true, message: 'Basic auth credentials set' };
280
+ }
281
+ /**
282
+ * Perform cookie-based authentication
283
+ */
284
+ async performCookieAuth(session, _authConfig) {
285
+ const { context } = session;
286
+ // Load cookies from storage
287
+ const savedState = await this.loadSessionState(session.state.sessionId);
288
+ if (savedState && savedState.cookies.length > 0) {
289
+ await context.addCookies(savedState.cookies.map(c => ({
290
+ name: c.name,
291
+ value: c.value,
292
+ domain: c.domain,
293
+ path: c.path,
294
+ expires: c.expires || -1,
295
+ httpOnly: c.httpOnly || false,
296
+ secure: c.secure || false,
297
+ sameSite: c.sameSite || 'Lax',
298
+ })));
299
+ session.state.isAuthenticated = true;
300
+ return { success: true, message: 'Cookies loaded from storage' };
301
+ }
302
+ return { success: false, message: 'No stored cookies found' };
303
+ }
304
+ /**
305
+ * Perform token-based authentication
306
+ */
307
+ async performTokenAuth(session, authConfig) {
308
+ const { context } = session;
309
+ const { credentials } = authConfig;
310
+ if (!credentials?.token) {
311
+ return { success: false, message: 'Token required for token auth' };
312
+ }
313
+ // Set authorization header for all requests
314
+ await context.setExtraHTTPHeaders({
315
+ 'Authorization': `Bearer ${credentials.token}`,
316
+ });
317
+ session.state.isAuthenticated = true;
318
+ return { success: true, message: 'Token auth header set' };
319
+ }
320
+ /**
321
+ * Save cookies for a session
322
+ */
323
+ async saveCookies(session) {
324
+ const cookies = await session.context.cookies();
325
+ session.state.cookies = cookies.map(c => ({
326
+ name: c.name,
327
+ value: c.value,
328
+ domain: c.domain,
329
+ path: c.path,
330
+ expires: c.expires,
331
+ httpOnly: c.httpOnly,
332
+ secure: c.secure,
333
+ sameSite: c.sameSite,
334
+ }));
335
+ await this.saveSessionState(session.state);
336
+ }
337
+ /**
338
+ * Save session state to disk
339
+ */
340
+ async saveSessionState(state) {
341
+ const filePath = path.join(this.storageDir, `${state.sessionId}.json`);
342
+ fs.writeFileSync(filePath, JSON.stringify(state, null, 2), 'utf-8');
343
+ }
344
+ /**
345
+ * Load session state from disk
346
+ */
347
+ async loadSessionState(sessionId) {
348
+ const filePath = path.join(this.storageDir, `${sessionId}.json`);
349
+ if (fs.existsSync(filePath)) {
350
+ try {
351
+ const content = fs.readFileSync(filePath, 'utf-8');
352
+ return JSON.parse(content);
353
+ }
354
+ catch {
355
+ return null;
356
+ }
357
+ }
358
+ return null;
359
+ }
360
+ /**
361
+ * Take a screenshot
362
+ */
363
+ async takeScreenshot(sessionId, options) {
364
+ const session = this.getSession(sessionId);
365
+ if (!session) {
366
+ return { success: false, error: `Session ${sessionId} not found` };
367
+ }
368
+ try {
369
+ const screenshotOptions = {
370
+ fullPage: options?.fullPage || false,
371
+ type: 'png',
372
+ };
373
+ if (options?.path) {
374
+ screenshotOptions.path = options.path;
375
+ await session.page.screenshot(screenshotOptions);
376
+ return { success: true, path: options.path };
377
+ }
378
+ else {
379
+ const buffer = await session.page.screenshot(screenshotOptions);
380
+ return { success: true, data: buffer.toString('base64') };
381
+ }
382
+ }
383
+ catch (error) {
384
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
385
+ }
386
+ }
387
+ /**
388
+ * Click on an element
389
+ */
390
+ async click(sessionId, selector, options) {
391
+ const session = this.getSession(sessionId);
392
+ if (!session) {
393
+ return { success: false, error: `Session ${sessionId} not found` };
394
+ }
395
+ try {
396
+ await session.page.click(selector, {
397
+ timeout: options?.timeout || 10000,
398
+ force: options?.force || false,
399
+ });
400
+ return { success: true };
401
+ }
402
+ catch (error) {
403
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
404
+ }
405
+ }
406
+ /**
407
+ * Type text into an element
408
+ */
409
+ async type(sessionId, selector, text, options) {
410
+ const session = this.getSession(sessionId);
411
+ if (!session) {
412
+ return { success: false, error: `Session ${sessionId} not found` };
413
+ }
414
+ try {
415
+ if (options?.clear) {
416
+ await session.page.fill(selector, '');
417
+ }
418
+ await session.page.type(selector, text, { delay: options?.delay || 50 });
419
+ return { success: true };
420
+ }
421
+ catch (error) {
422
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
423
+ }
424
+ }
425
+ /**
426
+ * Fill an input field (faster than type)
427
+ */
428
+ async fill(sessionId, selector, value) {
429
+ const session = this.getSession(sessionId);
430
+ if (!session) {
431
+ return { success: false, error: `Session ${sessionId} not found` };
432
+ }
433
+ try {
434
+ await session.page.fill(selector, value);
435
+ return { success: true };
436
+ }
437
+ catch (error) {
438
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
439
+ }
440
+ }
441
+ /**
442
+ * Get text content of an element
443
+ */
444
+ async getText(sessionId, selector) {
445
+ const session = this.getSession(sessionId);
446
+ if (!session) {
447
+ return { success: false, error: `Session ${sessionId} not found` };
448
+ }
449
+ try {
450
+ const text = await session.page.textContent(selector);
451
+ return { success: true, text: text || '' };
452
+ }
453
+ catch (error) {
454
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
455
+ }
456
+ }
457
+ /**
458
+ * Get page HTML content
459
+ */
460
+ async getPageContent(sessionId) {
461
+ const session = this.getSession(sessionId);
462
+ if (!session) {
463
+ return { success: false, error: `Session ${sessionId} not found` };
464
+ }
465
+ try {
466
+ const html = await session.page.content();
467
+ return { success: true, html };
468
+ }
469
+ catch (error) {
470
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
471
+ }
472
+ }
473
+ /**
474
+ * Wait for a selector to appear
475
+ */
476
+ async waitForSelector(sessionId, selector, options) {
477
+ const session = this.getSession(sessionId);
478
+ if (!session) {
479
+ return { success: false, error: `Session ${sessionId} not found` };
480
+ }
481
+ try {
482
+ await session.page.waitForSelector(selector, {
483
+ timeout: options?.timeout || 30000,
484
+ state: options?.state || 'visible',
485
+ });
486
+ return { success: true };
487
+ }
488
+ catch (error) {
489
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
490
+ }
491
+ }
492
+ /**
493
+ * Execute JavaScript in the page context
494
+ */
495
+ async executeScript(sessionId, script, args) {
496
+ const session = this.getSession(sessionId);
497
+ if (!session) {
498
+ return { success: false, error: `Session ${sessionId} not found` };
499
+ }
500
+ try {
501
+ const result = await session.page.evaluate(script, args);
502
+ return { success: true, result: result };
503
+ }
504
+ catch (error) {
505
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
506
+ }
507
+ }
508
+ /**
509
+ * Select an option from a dropdown
510
+ */
511
+ async selectOption(sessionId, selector, value) {
512
+ const session = this.getSession(sessionId);
513
+ if (!session) {
514
+ return { success: false, error: `Session ${sessionId} not found` };
515
+ }
516
+ try {
517
+ await session.page.selectOption(selector, value);
518
+ return { success: true };
519
+ }
520
+ catch (error) {
521
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
522
+ }
523
+ }
524
+ /**
525
+ * Check/uncheck a checkbox
526
+ */
527
+ async setChecked(sessionId, selector, checked) {
528
+ const session = this.getSession(sessionId);
529
+ if (!session) {
530
+ return { success: false, error: `Session ${sessionId} not found` };
531
+ }
532
+ try {
533
+ await session.page.setChecked(selector, checked);
534
+ return { success: true };
535
+ }
536
+ catch (error) {
537
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
538
+ }
539
+ }
540
+ /**
541
+ * Upload a file
542
+ */
543
+ async uploadFile(sessionId, selector, filePath) {
544
+ const session = this.getSession(sessionId);
545
+ if (!session) {
546
+ return { success: false, error: `Session ${sessionId} not found` };
547
+ }
548
+ try {
549
+ await session.page.setInputFiles(selector, filePath);
550
+ return { success: true };
551
+ }
552
+ catch (error) {
553
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
554
+ }
555
+ }
556
+ /**
557
+ * Get all cookies for the session
558
+ */
559
+ async getCookies(sessionId, urls) {
560
+ const session = this.getSession(sessionId);
561
+ if (!session) {
562
+ return { success: false, error: `Session ${sessionId} not found` };
563
+ }
564
+ try {
565
+ const cookies = await session.context.cookies(urls);
566
+ return {
567
+ success: true,
568
+ cookies: cookies.map(c => ({
569
+ name: c.name,
570
+ value: c.value,
571
+ domain: c.domain,
572
+ path: c.path,
573
+ expires: c.expires,
574
+ httpOnly: c.httpOnly,
575
+ secure: c.secure,
576
+ sameSite: c.sameSite,
577
+ })),
578
+ };
579
+ }
580
+ catch (error) {
581
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
582
+ }
583
+ }
584
+ /**
585
+ * Add cookies to the session
586
+ */
587
+ async addCookies(sessionId, cookies) {
588
+ const session = this.getSession(sessionId);
589
+ if (!session) {
590
+ return { success: false, error: `Session ${sessionId} not found` };
591
+ }
592
+ try {
593
+ await session.context.addCookies(cookies.map(c => ({
594
+ name: c.name,
595
+ value: c.value,
596
+ domain: c.domain,
597
+ path: c.path,
598
+ expires: c.expires || -1,
599
+ httpOnly: c.httpOnly || false,
600
+ secure: c.secure || false,
601
+ sameSite: c.sameSite || 'Lax',
602
+ })));
603
+ return { success: true };
604
+ }
605
+ catch (error) {
606
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
607
+ }
608
+ }
609
+ /**
610
+ * Clear cookies for the session
611
+ */
612
+ async clearCookies(sessionId) {
613
+ const session = this.getSession(sessionId);
614
+ if (!session) {
615
+ return { success: false, error: `Session ${sessionId} not found` };
616
+ }
617
+ try {
618
+ await session.context.clearCookies();
619
+ session.state.cookies = [];
620
+ session.state.isAuthenticated = false;
621
+ return { success: true };
622
+ }
623
+ catch (error) {
624
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
625
+ }
626
+ }
627
+ /**
628
+ * Close a session
629
+ */
630
+ async closeSession(sessionId, saveCookies = true) {
631
+ const session = this.sessions.get(sessionId);
632
+ if (session) {
633
+ if (saveCookies) {
634
+ await this.saveCookies(session);
635
+ }
636
+ session.state.isActive = false;
637
+ await session.page.close().catch(() => { });
638
+ await session.context.close().catch(() => { });
639
+ await session.browser.close().catch(() => { });
640
+ this.sessions.delete(sessionId);
641
+ }
642
+ }
643
+ /**
644
+ * Close all sessions
645
+ */
646
+ async closeAllSessions() {
647
+ for (const sessionId of this.sessions.keys()) {
648
+ await this.closeSession(sessionId);
649
+ }
650
+ }
651
+ /**
652
+ * List all stored sessions
653
+ */
654
+ listStoredSessions() {
655
+ if (!fs.existsSync(this.storageDir)) {
656
+ return [];
657
+ }
658
+ return fs.readdirSync(this.storageDir)
659
+ .filter(f => f.endsWith('.json'))
660
+ .map(f => f.replace('.json', ''));
661
+ }
662
+ /**
663
+ * Delete stored session data
664
+ */
665
+ deleteStoredSession(sessionId) {
666
+ const filePath = path.join(this.storageDir, `${sessionId}.json`);
667
+ if (fs.existsSync(filePath)) {
668
+ fs.unlinkSync(filePath);
669
+ return true;
670
+ }
671
+ return false;
672
+ }
673
+ /**
674
+ * Get session info
675
+ */
676
+ getSessionInfo(sessionId) {
677
+ const session = this.sessions.get(sessionId);
678
+ if (session) {
679
+ return { ...session.state };
680
+ }
681
+ // For stored sessions, we need to load synchronously
682
+ const filePath = path.join(this.storageDir, `${sessionId}.json`);
683
+ if (fs.existsSync(filePath)) {
684
+ try {
685
+ const content = fs.readFileSync(filePath, 'utf-8');
686
+ return JSON.parse(content);
687
+ }
688
+ catch {
689
+ return null;
690
+ }
691
+ }
692
+ return null;
693
+ }
694
+ /**
695
+ * Check if session is authenticated
696
+ */
697
+ isAuthenticated(sessionId) {
698
+ const session = this.sessions.get(sessionId);
699
+ return session?.state.isAuthenticated || false;
700
+ }
701
+ }
702
+ // Export singleton instance
703
+ let defaultManager = null;
704
+ export function getDefaultBrowserSessionManager() {
705
+ if (!defaultManager) {
706
+ defaultManager = new BrowserSessionManager();
707
+ }
708
+ return defaultManager;
709
+ }
710
+ export function createBrowserSessionManager(storageDir) {
711
+ return new BrowserSessionManager(storageDir);
712
+ }
713
+ //# sourceMappingURL=BrowserSessionManager.js.map