mcpbrowser 0.2.34 → 0.2.36

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.
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Page management for MCPBrowser
3
+ */
4
+
5
+ import { domainPages } from './browser.js';
6
+ import { cleanHtml, enrichHtml } from './html.js';
7
+
8
+ /**
9
+ * Get or create a page for the given domain, reusing existing tabs when possible.
10
+ * @param {Browser} browser - The Puppeteer browser instance
11
+ * @param {string} hostname - The hostname to get/create a page for
12
+ * @param {boolean} reuseLastKeptPage - Whether to reuse existing tabs
13
+ * @returns {Promise<Page>} The page for this domain
14
+ */
15
+ export async function getOrCreatePage(browser, hostname, reuseLastKeptPage = true) {
16
+ let page = null;
17
+
18
+ // Check if we have an existing page for this domain
19
+ if (reuseLastKeptPage && domainPages.has(hostname)) {
20
+ const existingPage = domainPages.get(hostname);
21
+ if (!existingPage.isClosed()) {
22
+ page = existingPage;
23
+ await page.bringToFront().catch(() => {});
24
+ console.error(`[MCPBrowser] Reusing existing tab for domain: ${hostname}`);
25
+ } else {
26
+ // Page was closed externally, remove from map
27
+ domainPages.delete(hostname);
28
+ }
29
+ }
30
+
31
+ // Create new tab if no existing page for this domain
32
+ if (!page) {
33
+ try {
34
+ page = await browser.newPage();
35
+ } catch (error) {
36
+ // If newPage() fails (can happen with some profiles), try to reuse existing page
37
+ const pages = await browser.pages();
38
+ for (const p of pages) {
39
+ try {
40
+ const pageUrl = p.url();
41
+ // Skip chrome:// pages and other internal pages
42
+ if (!pageUrl.startsWith('chrome://') && !pageUrl.startsWith('chrome-extension://')) {
43
+ page = p;
44
+ break;
45
+ }
46
+ } catch {
47
+ // Skip pages we can't access
48
+ }
49
+ }
50
+ if (!page) {
51
+ throw new Error('Unable to create or find a controllable page');
52
+ }
53
+ }
54
+ // Add new page to domain map
55
+ domainPages.set(hostname, page);
56
+ console.error(`[MCPBrowser] Created new tab for domain: ${hostname}`);
57
+ }
58
+
59
+ return page;
60
+ }
61
+
62
+ /**
63
+ * Navigate to URL with fallback strategy for slow pages.
64
+ * @param {Page} page - The Puppeteer page instance
65
+ * @param {string} url - The URL to navigate to
66
+ * @param {string} waitUntil - Wait condition (networkidle0, load, etc.)
67
+ * @param {number} timeout - Navigation timeout in ms
68
+ * @returns {Promise<void>}
69
+ */
70
+ export async function navigateToUrl(page, url, waitUntil, timeout) {
71
+ console.error(`[MCPBrowser] Navigating to: ${url}`);
72
+
73
+ const startTime = Date.now();
74
+
75
+ try {
76
+ // Simple, fast navigation - no complex fallback logic
77
+ await page.goto(url, { waitUntil, timeout });
78
+
79
+ const loadTime = Date.now() - startTime;
80
+ console.error(`[MCPBrowser] Navigation completed in ${loadTime}ms: ${page.url()}`);
81
+ } catch (error) {
82
+ const elapsed = Date.now() - startTime;
83
+ console.error(`[MCPBrowser] Navigation error after ${elapsed}ms: ${error.message}`);
84
+ throw error;
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Wait for page to stabilize after authentication.
90
+ * @param {Page} page - The Puppeteer page instance
91
+ * @returns {Promise<void>}
92
+ */
93
+ export async function waitForPageStability(page) {
94
+ console.error(`[MCPBrowser] Waiting for page to stabilize...`);
95
+ await new Promise(resolve => setTimeout(resolve, 3000));
96
+
97
+ try {
98
+ await page.waitForNetworkIdle({ timeout: 5000 });
99
+ } catch {
100
+ // Ignore timeout - page may have long-polling or websockets
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Extract and process HTML from the page.
106
+ * @param {Page} page - The Puppeteer page instance
107
+ * @param {boolean} removeUnnecessaryHTML - Whether to clean the HTML
108
+ * @returns {Promise<string>} The processed HTML
109
+ */
110
+ export async function extractAndProcessHtml(page, removeUnnecessaryHTML) {
111
+ const html = await page.evaluate(() => document.documentElement?.outerHTML || "");
112
+
113
+ let processedHtml;
114
+ if (removeUnnecessaryHTML) {
115
+ const cleaned = cleanHtml(html);
116
+ processedHtml = enrichHtml(cleaned, page.url());
117
+ } else {
118
+ processedHtml = enrichHtml(html, page.url());
119
+ }
120
+
121
+ return processedHtml;
122
+ }