@roomi-fields/notebooklm-mcp 1.1.2

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 (67) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +548 -0
  3. package/dist/auth/auth-manager.d.ts +139 -0
  4. package/dist/auth/auth-manager.d.ts.map +1 -0
  5. package/dist/auth/auth-manager.js +981 -0
  6. package/dist/auth/auth-manager.js.map +1 -0
  7. package/dist/config.d.ts +89 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +216 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/errors.d.ts +26 -0
  12. package/dist/errors.d.ts.map +1 -0
  13. package/dist/errors.js +41 -0
  14. package/dist/errors.js.map +1 -0
  15. package/dist/http-wrapper.d.ts +8 -0
  16. package/dist/http-wrapper.d.ts.map +1 -0
  17. package/dist/http-wrapper.js +221 -0
  18. package/dist/http-wrapper.js.map +1 -0
  19. package/dist/index.d.ts +32 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +499 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/library/notebook-library.d.ts +81 -0
  24. package/dist/library/notebook-library.d.ts.map +1 -0
  25. package/dist/library/notebook-library.js +362 -0
  26. package/dist/library/notebook-library.js.map +1 -0
  27. package/dist/library/types.d.ts +67 -0
  28. package/dist/library/types.d.ts.map +1 -0
  29. package/dist/library/types.js +8 -0
  30. package/dist/library/types.js.map +1 -0
  31. package/dist/session/browser-session.d.ts +108 -0
  32. package/dist/session/browser-session.d.ts.map +1 -0
  33. package/dist/session/browser-session.js +630 -0
  34. package/dist/session/browser-session.js.map +1 -0
  35. package/dist/session/session-manager.d.ts +76 -0
  36. package/dist/session/session-manager.d.ts.map +1 -0
  37. package/dist/session/session-manager.js +273 -0
  38. package/dist/session/session-manager.js.map +1 -0
  39. package/dist/session/shared-context-manager.d.ts +107 -0
  40. package/dist/session/shared-context-manager.d.ts.map +1 -0
  41. package/dist/session/shared-context-manager.js +447 -0
  42. package/dist/session/shared-context-manager.js.map +1 -0
  43. package/dist/tools/index.d.ts +225 -0
  44. package/dist/tools/index.d.ts.map +1 -0
  45. package/dist/tools/index.js +1396 -0
  46. package/dist/tools/index.js.map +1 -0
  47. package/dist/types.d.ts +82 -0
  48. package/dist/types.d.ts.map +1 -0
  49. package/dist/types.js +5 -0
  50. package/dist/types.js.map +1 -0
  51. package/dist/utils/cleanup-manager.d.ts +133 -0
  52. package/dist/utils/cleanup-manager.d.ts.map +1 -0
  53. package/dist/utils/cleanup-manager.js +673 -0
  54. package/dist/utils/cleanup-manager.js.map +1 -0
  55. package/dist/utils/logger.d.ts +61 -0
  56. package/dist/utils/logger.d.ts.map +1 -0
  57. package/dist/utils/logger.js +92 -0
  58. package/dist/utils/logger.js.map +1 -0
  59. package/dist/utils/page-utils.d.ts +54 -0
  60. package/dist/utils/page-utils.d.ts.map +1 -0
  61. package/dist/utils/page-utils.js +422 -0
  62. package/dist/utils/page-utils.js.map +1 -0
  63. package/dist/utils/stealth-utils.d.ts +135 -0
  64. package/dist/utils/stealth-utils.d.ts.map +1 -0
  65. package/dist/utils/stealth-utils.js +398 -0
  66. package/dist/utils/stealth-utils.js.map +1 -0
  67. package/package.json +71 -0
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Session Manager
3
+ *
4
+ * Manages multiple parallel browser sessions for NotebookLM API
5
+ *
6
+ * Features:
7
+ * - Session lifecycle management
8
+ * - Auto-cleanup of inactive sessions
9
+ * - Resource limits (max concurrent sessions)
10
+ * - Shared PERSISTENT browser fingerprint (ONE context for all sessions)
11
+ *
12
+ * Based on the Python implementation from session_manager.py
13
+ */
14
+ import { AuthManager } from "../auth/auth-manager.js";
15
+ import { BrowserSession } from "./browser-session.js";
16
+ import type { SessionInfo } from "../types.js";
17
+ export declare class SessionManager {
18
+ private authManager;
19
+ private sharedContextManager;
20
+ private sessions;
21
+ private maxSessions;
22
+ private sessionTimeout;
23
+ private cleanupInterval?;
24
+ constructor(authManager: AuthManager);
25
+ /**
26
+ * Generate a unique session ID
27
+ */
28
+ private generateSessionId;
29
+ /**
30
+ * Get existing session or create a new one
31
+ *
32
+ * @param sessionId Optional session ID to reuse existing session
33
+ * @param notebookUrl Notebook URL for the session
34
+ * @param overrideHeadless Optional override for headless mode (true = show browser)
35
+ */
36
+ getOrCreateSession(sessionId?: string, notebookUrl?: string, overrideHeadless?: boolean): Promise<BrowserSession>;
37
+ /**
38
+ * Get an existing session by ID
39
+ */
40
+ getSession(sessionId: string): BrowserSession | null;
41
+ /**
42
+ * Close and remove a specific session
43
+ */
44
+ closeSession(sessionId: string): Promise<boolean>;
45
+ /**
46
+ * Close all sessions that are using the provided notebook URL
47
+ */
48
+ closeSessionsForNotebook(url: string): Promise<number>;
49
+ /**
50
+ * Clean up all inactive sessions
51
+ */
52
+ cleanupInactiveSessions(): Promise<number>;
53
+ /**
54
+ * Clean up the oldest session to make space
55
+ */
56
+ private cleanupOldestSession;
57
+ /**
58
+ * Close all sessions (used during shutdown)
59
+ */
60
+ closeAllSessions(): Promise<void>;
61
+ /**
62
+ * Get all sessions info
63
+ */
64
+ getAllSessionsInfo(): SessionInfo[];
65
+ /**
66
+ * Get aggregate stats
67
+ */
68
+ getStats(): {
69
+ active_sessions: number;
70
+ max_sessions: number;
71
+ session_timeout: number;
72
+ oldest_session_seconds: number;
73
+ total_messages: number;
74
+ };
75
+ }
76
+ //# sourceMappingURL=session-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/session/session-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAItD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,qBAAa,cAAc;IACzB,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,oBAAoB,CAAuB;IACnD,OAAO,CAAC,QAAQ,CAA0C;IAC1D,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,eAAe,CAAC,CAAiB;gBAE7B,WAAW,EAAE,WAAW;IAwBpC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;;;;;OAMG;IACG,kBAAkB,CACtB,SAAS,CAAC,EAAE,MAAM,EAClB,WAAW,CAAC,EAAE,MAAM,EACpB,gBAAgB,CAAC,EAAE,OAAO,GACzB,OAAO,CAAC,cAAc,CAAC;IAmF1B;;OAEG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;IAIpD;;OAEG;IACG,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAgBvD;;OAEG;IACG,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAyB5D;;OAEG;IACG,uBAAuB,IAAI,OAAO,CAAC,MAAM,CAAC;IAsChD;;OAEG;YACW,oBAAoB;IA+BlC;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IA+BvC;;OAEG;IACH,kBAAkB,IAAI,WAAW,EAAE;IAInC;;OAEG;IACH,QAAQ,IAAI;QACV,eAAe,EAAE,MAAM,CAAC;QACxB,YAAY,EAAE,MAAM,CAAC;QACrB,eAAe,EAAE,MAAM,CAAC;QACxB,sBAAsB,EAAE,MAAM,CAAC;QAC/B,cAAc,EAAE,MAAM,CAAC;KACxB;CAoBF"}
@@ -0,0 +1,273 @@
1
+ /**
2
+ * Session Manager
3
+ *
4
+ * Manages multiple parallel browser sessions for NotebookLM API
5
+ *
6
+ * Features:
7
+ * - Session lifecycle management
8
+ * - Auto-cleanup of inactive sessions
9
+ * - Resource limits (max concurrent sessions)
10
+ * - Shared PERSISTENT browser fingerprint (ONE context for all sessions)
11
+ *
12
+ * Based on the Python implementation from session_manager.py
13
+ */
14
+ import { BrowserSession } from "./browser-session.js";
15
+ import { SharedContextManager } from "./shared-context-manager.js";
16
+ import { CONFIG } from "../config.js";
17
+ import { log } from "../utils/logger.js";
18
+ import { randomBytes } from "crypto";
19
+ export class SessionManager {
20
+ authManager;
21
+ sharedContextManager;
22
+ sessions = new Map();
23
+ maxSessions;
24
+ sessionTimeout;
25
+ cleanupInterval;
26
+ constructor(authManager) {
27
+ this.authManager = authManager;
28
+ this.sharedContextManager = new SharedContextManager(authManager);
29
+ this.maxSessions = CONFIG.maxSessions;
30
+ this.sessionTimeout = CONFIG.sessionTimeout;
31
+ log.info("🎯 SessionManager initialized");
32
+ log.info(` Max sessions: ${this.maxSessions}`);
33
+ log.info(` Timeout: ${this.sessionTimeout}s (${Math.floor(this.sessionTimeout / 60)} minutes)`);
34
+ const cleanupIntervalSeconds = Math.max(60, Math.min(Math.floor(this.sessionTimeout / 2), 300));
35
+ this.cleanupInterval = setInterval(() => {
36
+ this.cleanupInactiveSessions().catch((error) => {
37
+ log.warning(`⚠️ Error during automatic session cleanup: ${error}`);
38
+ });
39
+ }, cleanupIntervalSeconds * 1000);
40
+ this.cleanupInterval.unref();
41
+ }
42
+ /**
43
+ * Generate a unique session ID
44
+ */
45
+ generateSessionId() {
46
+ return randomBytes(4).toString("hex");
47
+ }
48
+ /**
49
+ * Get existing session or create a new one
50
+ *
51
+ * @param sessionId Optional session ID to reuse existing session
52
+ * @param notebookUrl Notebook URL for the session
53
+ * @param overrideHeadless Optional override for headless mode (true = show browser)
54
+ */
55
+ async getOrCreateSession(sessionId, notebookUrl, overrideHeadless) {
56
+ // Determine target notebook URL
57
+ const targetUrl = (notebookUrl || CONFIG.notebookUrl || "").trim();
58
+ if (!targetUrl) {
59
+ throw new Error("Notebook URL is required to create a session");
60
+ }
61
+ if (!targetUrl.startsWith("http")) {
62
+ throw new Error("Notebook URL must be an absolute URL");
63
+ }
64
+ // Generate ID if not provided
65
+ if (!sessionId) {
66
+ sessionId = this.generateSessionId();
67
+ log.info(`🆕 Auto-generated session ID: ${sessionId}`);
68
+ }
69
+ // Check if browser visibility mode needs to change
70
+ if (overrideHeadless !== undefined) {
71
+ if (this.sharedContextManager.needsHeadlessModeChange(overrideHeadless)) {
72
+ log.warning(`🔄 Browser visibility changed - closing all sessions to recreate browser context...`);
73
+ const currentMode = this.sharedContextManager.getCurrentHeadlessMode();
74
+ log.info(` Switching from ${currentMode ? 'HEADLESS' : 'VISIBLE'} to ${overrideHeadless ? 'VISIBLE' : 'HEADLESS'}`);
75
+ // Close all sessions (they all use the same context)
76
+ await this.closeAllSessions();
77
+ log.success(` ✅ All sessions closed, browser context will be recreated with new mode`);
78
+ }
79
+ }
80
+ // Return existing session if found
81
+ if (this.sessions.has(sessionId)) {
82
+ const session = this.sessions.get(sessionId);
83
+ if (session.notebookUrl !== targetUrl) {
84
+ log.warning(`♻️ Replacing session ${sessionId} with new notebook URL`);
85
+ await session.close();
86
+ this.sessions.delete(sessionId);
87
+ }
88
+ else {
89
+ session.updateActivity();
90
+ log.success(`♻️ Reusing existing session ${sessionId}`);
91
+ return session;
92
+ }
93
+ }
94
+ // Check if we need to free up space
95
+ if (this.sessions.size >= this.maxSessions) {
96
+ log.warning(`⚠️ Max sessions (${this.maxSessions}) reached, cleaning up...`);
97
+ const freed = await this.cleanupOldestSession();
98
+ if (!freed) {
99
+ throw new Error(`Max sessions (${this.maxSessions}) reached and no inactive sessions to clean up`);
100
+ }
101
+ }
102
+ // Create new session
103
+ log.info(`🆕 Creating new session ${sessionId}...`);
104
+ if (overrideHeadless !== undefined) {
105
+ log.info(` Show browser: ${overrideHeadless}`);
106
+ }
107
+ try {
108
+ // Ensure the shared context exists (ONE fingerprint for all sessions!)
109
+ await this.sharedContextManager.getOrCreateContext(overrideHeadless);
110
+ // Create and initialize session
111
+ const session = new BrowserSession(sessionId, this.sharedContextManager, this.authManager, targetUrl);
112
+ await session.init();
113
+ this.sessions.set(sessionId, session);
114
+ log.success(`✅ Session ${sessionId} created (${this.sessions.size}/${this.maxSessions} active)`);
115
+ return session;
116
+ }
117
+ catch (error) {
118
+ log.error(`❌ Failed to create session: ${error}`);
119
+ throw error;
120
+ }
121
+ }
122
+ /**
123
+ * Get an existing session by ID
124
+ */
125
+ getSession(sessionId) {
126
+ return this.sessions.get(sessionId) || null;
127
+ }
128
+ /**
129
+ * Close and remove a specific session
130
+ */
131
+ async closeSession(sessionId) {
132
+ if (!this.sessions.has(sessionId)) {
133
+ log.warning(`⚠️ Session ${sessionId} not found`);
134
+ return false;
135
+ }
136
+ const session = this.sessions.get(sessionId);
137
+ await session.close();
138
+ this.sessions.delete(sessionId);
139
+ log.success(`✅ Session ${sessionId} closed (${this.sessions.size}/${this.maxSessions} active)`);
140
+ return true;
141
+ }
142
+ /**
143
+ * Close all sessions that are using the provided notebook URL
144
+ */
145
+ async closeSessionsForNotebook(url) {
146
+ let closed = 0;
147
+ for (const [sessionId, session] of Array.from(this.sessions.entries())) {
148
+ if (session.notebookUrl === url) {
149
+ try {
150
+ await session.close();
151
+ }
152
+ catch (error) {
153
+ log.warning(` ⚠️ Error closing ${sessionId}: ${error}`);
154
+ }
155
+ finally {
156
+ this.sessions.delete(sessionId);
157
+ closed++;
158
+ }
159
+ }
160
+ }
161
+ if (closed > 0) {
162
+ log.warning(`🧹 Closed ${closed} session(s) using removed notebook (${this.sessions.size}/${this.maxSessions} active)`);
163
+ }
164
+ return closed;
165
+ }
166
+ /**
167
+ * Clean up all inactive sessions
168
+ */
169
+ async cleanupInactiveSessions() {
170
+ const inactiveSessions = [];
171
+ for (const [sessionId, session] of this.sessions.entries()) {
172
+ if (session.isExpired(this.sessionTimeout)) {
173
+ inactiveSessions.push(sessionId);
174
+ }
175
+ }
176
+ if (inactiveSessions.length === 0) {
177
+ return 0;
178
+ }
179
+ log.warning(`🧹 Cleaning up ${inactiveSessions.length} inactive sessions...`);
180
+ for (const sessionId of inactiveSessions) {
181
+ try {
182
+ const session = this.sessions.get(sessionId);
183
+ const age = (Date.now() - session.createdAt) / 1000;
184
+ const inactive = (Date.now() - session.lastActivity) / 1000;
185
+ log.warning(` 🗑️ ${sessionId}: age=${age.toFixed(0)}s, inactive=${inactive.toFixed(0)}s, messages=${session.messageCount}`);
186
+ await session.close();
187
+ this.sessions.delete(sessionId);
188
+ }
189
+ catch (error) {
190
+ log.warning(` ⚠️ Error cleaning up ${sessionId}: ${error}`);
191
+ }
192
+ }
193
+ log.success(`✅ Cleaned up ${inactiveSessions.length} sessions (${this.sessions.size}/${this.maxSessions} active)`);
194
+ return inactiveSessions.length;
195
+ }
196
+ /**
197
+ * Clean up the oldest session to make space
198
+ */
199
+ async cleanupOldestSession() {
200
+ if (this.sessions.size === 0) {
201
+ return false;
202
+ }
203
+ // Find oldest session
204
+ let oldestId = null;
205
+ let oldestTime = Infinity;
206
+ for (const [sessionId, session] of this.sessions.entries()) {
207
+ if (session.createdAt < oldestTime) {
208
+ oldestTime = session.createdAt;
209
+ oldestId = sessionId;
210
+ }
211
+ }
212
+ if (!oldestId) {
213
+ return false;
214
+ }
215
+ const oldestSession = this.sessions.get(oldestId);
216
+ const age = (Date.now() - oldestSession.createdAt) / 1000;
217
+ log.warning(`🗑️ Removing oldest session ${oldestId} (age: ${age.toFixed(0)}s)`);
218
+ await oldestSession.close();
219
+ this.sessions.delete(oldestId);
220
+ return true;
221
+ }
222
+ /**
223
+ * Close all sessions (used during shutdown)
224
+ */
225
+ async closeAllSessions() {
226
+ if (this.cleanupInterval) {
227
+ clearInterval(this.cleanupInterval);
228
+ this.cleanupInterval = undefined;
229
+ }
230
+ if (this.sessions.size === 0) {
231
+ log.warning("🛑 Closing shared context (no active sessions)...");
232
+ await this.sharedContextManager.closeContext();
233
+ log.success("✅ All sessions closed");
234
+ return;
235
+ }
236
+ log.warning(`🛑 Closing all ${this.sessions.size} sessions...`);
237
+ for (const sessionId of Array.from(this.sessions.keys())) {
238
+ try {
239
+ const session = this.sessions.get(sessionId);
240
+ await session.close();
241
+ this.sessions.delete(sessionId);
242
+ }
243
+ catch (error) {
244
+ log.warning(` ⚠️ Error closing ${sessionId}: ${error}`);
245
+ }
246
+ }
247
+ // Close the shared context
248
+ await this.sharedContextManager.closeContext();
249
+ log.success("✅ All sessions closed");
250
+ }
251
+ /**
252
+ * Get all sessions info
253
+ */
254
+ getAllSessionsInfo() {
255
+ return Array.from(this.sessions.values()).map((session) => session.getInfo());
256
+ }
257
+ /**
258
+ * Get aggregate stats
259
+ */
260
+ getStats() {
261
+ const sessionsInfo = this.getAllSessionsInfo();
262
+ const totalMessages = sessionsInfo.reduce((sum, info) => sum + info.message_count, 0);
263
+ const oldestSessionSeconds = Math.max(...sessionsInfo.map((info) => info.age_seconds), 0);
264
+ return {
265
+ active_sessions: sessionsInfo.length,
266
+ max_sessions: this.maxSessions,
267
+ session_timeout: this.sessionTimeout,
268
+ oldest_session_seconds: oldestSessionSeconds,
269
+ total_messages: totalMessages,
270
+ };
271
+ }
272
+ }
273
+ //# sourceMappingURL=session-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../src/session/session-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Shared Context Manager with Persistent Chrome Profile
3
+ *
4
+ * Manages ONE global persistent BrowserContext for ALL sessions.
5
+ * This is critical for avoiding bot detection:
6
+ *
7
+ * - Google tracks browser fingerprints (Canvas, WebGL, Audio, Fonts, etc.)
8
+ * - Multiple contexts = Multiple fingerprints = Suspicious!
9
+ * - ONE persistent context = ONE consistent fingerprint = Normal user
10
+ * - Persistent user_data_dir = SAME fingerprint across all app restarts!
11
+ *
12
+ * Based on the Python implementation from shared_context_manager.py
13
+ */
14
+ import type { BrowserContext } from "patchright";
15
+ import { AuthManager } from "../auth/auth-manager.js";
16
+ /**
17
+ * Shared Context Manager
18
+ *
19
+ * Benefits:
20
+ * 1. ONE consistent browser fingerprint for all sessions
21
+ * 2. Fingerprint persists across app restarts (user_data_dir)
22
+ * 3. Mimics real user behavior (one browser, multiple tabs)
23
+ * 4. Google sees: "Same browser since day 1"
24
+ */
25
+ export declare class SharedContextManager {
26
+ private authManager;
27
+ private globalContext;
28
+ private contextCreatedAt;
29
+ private currentProfileDir;
30
+ private isIsolatedProfile;
31
+ private currentHeadlessMode;
32
+ constructor(authManager: AuthManager);
33
+ /**
34
+ * Get the global shared persistent context, or create new if needed
35
+ *
36
+ * Context is recreated only when:
37
+ * - First time (no context exists in this app instance)
38
+ * - Context was closed/invalid
39
+ *
40
+ * Note: Auth expiry does NOT recreate context - we reuse the SAME
41
+ * fingerprint and just re-login!
42
+ *
43
+ * @param overrideHeadless Optional override for headless mode (true = show browser)
44
+ */
45
+ getOrCreateContext(overrideHeadless?: boolean): Promise<BrowserContext>;
46
+ /**
47
+ * Check if global context needs to be recreated
48
+ */
49
+ private needsRecreation;
50
+ /**
51
+ * Create/Load the global PERSISTENT context with Chrome user_data_dir
52
+ *
53
+ * This is THE KEY to fingerprint persistence!
54
+ *
55
+ * First time:
56
+ * - Chrome creates new profile in user_data_dir
57
+ * - Generates fingerprint (Canvas, WebGL, Audio, etc.)
58
+ * - Saves everything to disk
59
+ *
60
+ * Subsequent starts:
61
+ * - Chrome loads profile from user_data_dir
62
+ * - SAME fingerprint as before! ✅
63
+ * - Google sees: "Same browser since day 1"
64
+ *
65
+ * @param overrideHeadless Optional override for headless mode (true = show browser)
66
+ */
67
+ private recreateContext;
68
+ /**
69
+ * Manually close the global context (e.g., on shutdown)
70
+ *
71
+ * Note: This closes the context for ALL sessions!
72
+ * Chrome will save everything to user_data_dir automatically.
73
+ */
74
+ closeContext(): Promise<void>;
75
+ private prepareIsolatedProfileDir;
76
+ private pruneIsolatedProfiles;
77
+ private safeRemoveIsolatedProfile;
78
+ /**
79
+ * Get information about the global persistent context
80
+ */
81
+ getContextInfo(): {
82
+ exists: boolean;
83
+ age_seconds?: number;
84
+ age_hours?: number;
85
+ fingerprint_id?: string;
86
+ user_data_dir: string;
87
+ persistent: boolean;
88
+ };
89
+ /**
90
+ * Get the current headless mode of the browser context
91
+ *
92
+ * @returns boolean | null - true if headless, false if visible, null if no context exists
93
+ */
94
+ getCurrentHeadlessMode(): boolean | null;
95
+ /**
96
+ * Check if the browser context needs to be recreated due to headless mode change
97
+ *
98
+ * @param overrideHeadless - Optional override for headless mode (true = show browser)
99
+ * @returns boolean - true if context needs to be recreated with new mode
100
+ */
101
+ needsHeadlessModeChange(overrideHeadless?: boolean): boolean;
102
+ /**
103
+ * Get context ID for logging
104
+ */
105
+ private getContextId;
106
+ }
107
+ //# sourceMappingURL=shared-context-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared-context-manager.d.ts","sourceRoot":"","sources":["../../src/session/shared-context-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAIjD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAItD;;;;;;;;GAQG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,iBAAiB,CAAuB;IAChD,OAAO,CAAC,iBAAiB,CAAkB;IAC3C,OAAO,CAAC,mBAAmB,CAAwB;gBAEvC,WAAW,EAAE,WAAW;IAapC;;;;;;;;;;;OAWG;IACG,kBAAkB,CAAC,gBAAgB,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC;IAkB7E;;OAEG;YACW,eAAe;IAqB7B;;;;;;;;;;;;;;;;OAgBG;YACW,eAAe;IA+H7B;;;;;OAKG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;YAkCrB,yBAAyB;YA2BzB,qBAAqB;YAwDrB,yBAAyB;IAgBvC;;OAEG;IACH,cAAc,IAAI;QAChB,MAAM,EAAE,OAAO,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,aAAa,EAAE,MAAM,CAAC;QACtB,UAAU,EAAE,OAAO,CAAC;KACrB;IAwBD;;;;OAIG;IACH,sBAAsB,IAAI,OAAO,GAAG,IAAI;IAIxC;;;;;OAKG;IACH,uBAAuB,CAAC,gBAAgB,CAAC,EAAE,OAAO,GAAG,OAAO;IAuB5D;;OAEG;IACH,OAAO,CAAC,YAAY;CAOrB"}