@myrialabs/clopen 0.1.9 → 0.2.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.
- package/README.md +23 -1
- package/backend/index.ts +25 -1
- package/backend/lib/auth/auth-service.ts +484 -0
- package/backend/lib/auth/index.ts +4 -0
- package/backend/lib/auth/permissions.ts +63 -0
- package/backend/lib/auth/rate-limiter.ts +145 -0
- package/backend/lib/auth/tokens.ts +53 -0
- package/backend/lib/chat/stream-manager.ts +4 -1
- package/backend/lib/database/migrations/024_create_users_table.ts +29 -0
- package/backend/lib/database/migrations/025_create_auth_sessions_table.ts +38 -0
- package/backend/lib/database/migrations/026_create_invite_tokens_table.ts +31 -0
- package/backend/lib/database/migrations/index.ts +21 -0
- package/backend/lib/database/queries/auth-queries.ts +201 -0
- package/backend/lib/database/queries/index.ts +2 -1
- package/backend/lib/database/queries/session-queries.ts +13 -0
- package/backend/lib/database/queries/snapshot-queries.ts +1 -1
- package/backend/lib/engine/adapters/opencode/server.ts +9 -1
- package/backend/lib/engine/adapters/opencode/stream.ts +175 -1
- package/backend/lib/mcp/config.ts +13 -18
- package/backend/lib/mcp/index.ts +9 -0
- package/backend/lib/mcp/remote-server.ts +132 -0
- package/backend/lib/mcp/servers/helper.ts +49 -3
- package/backend/lib/mcp/servers/index.ts +3 -2
- package/backend/lib/preview/browser/browser-audio-capture.ts +20 -3
- package/backend/lib/preview/browser/browser-navigation-tracker.ts +3 -0
- package/backend/lib/preview/browser/browser-pool.ts +73 -176
- package/backend/lib/preview/browser/browser-preview-service.ts +3 -2
- package/backend/lib/preview/browser/browser-tab-manager.ts +261 -23
- package/backend/lib/preview/browser/browser-video-capture.ts +36 -1
- package/backend/lib/snapshot/helpers.ts +22 -49
- package/backend/lib/snapshot/snapshot-service.ts +148 -83
- package/backend/lib/utils/ws.ts +65 -1
- package/backend/ws/auth/index.ts +17 -0
- package/backend/ws/auth/invites.ts +84 -0
- package/backend/ws/auth/login.ts +269 -0
- package/backend/ws/auth/status.ts +41 -0
- package/backend/ws/auth/users.ts +32 -0
- package/backend/ws/chat/stream.ts +13 -0
- package/backend/ws/engine/claude/accounts.ts +3 -1
- package/backend/ws/engine/utils.ts +38 -6
- package/backend/ws/index.ts +4 -4
- package/backend/ws/preview/browser/interact.ts +27 -5
- package/backend/ws/snapshot/restore.ts +111 -12
- package/backend/ws/snapshot/timeline.ts +56 -29
- package/bin/clopen.ts +56 -1
- package/bun.lock +113 -51
- package/frontend/App.svelte +47 -29
- package/frontend/lib/components/auth/InvitePage.svelte +215 -0
- package/frontend/lib/components/auth/LoginPage.svelte +129 -0
- package/frontend/lib/components/auth/SetupPage.svelte +1022 -0
- package/frontend/lib/components/chat/input/ChatInput.svelte +1 -2
- package/frontend/lib/components/chat/input/components/EngineModelPicker.svelte +2 -2
- package/frontend/lib/components/chat/input/composables/use-chat-actions.svelte.ts +4 -4
- package/frontend/lib/components/chat/input/composables/use-textarea-resize.svelte.ts +11 -19
- package/frontend/lib/components/checkpoint/TimelineModal.svelte +15 -3
- package/frontend/lib/components/checkpoint/timeline/TimelineNode.svelte +30 -19
- package/frontend/lib/components/checkpoint/timeline/types.ts +4 -0
- package/frontend/lib/components/common/FolderBrowser.svelte +9 -9
- package/frontend/lib/components/common/UpdateBanner.svelte +2 -2
- package/frontend/lib/components/git/CommitForm.svelte +6 -4
- package/frontend/lib/components/history/HistoryModal.svelte +1 -1
- package/frontend/lib/components/history/HistoryView.svelte +1 -1
- package/frontend/lib/components/preview/browser/BrowserPreview.svelte +1 -1
- package/frontend/lib/components/preview/browser/core/mcp-handlers.svelte.ts +12 -4
- package/frontend/lib/components/settings/SettingsModal.svelte +50 -15
- package/frontend/lib/components/settings/SettingsView.svelte +21 -7
- package/frontend/lib/components/settings/account/AccountSettings.svelte +5 -0
- package/frontend/lib/components/settings/admin/InviteManagement.svelte +239 -0
- package/frontend/lib/components/settings/admin/UserManagement.svelte +127 -0
- package/frontend/lib/components/settings/general/AdvancedSettings.svelte +10 -4
- package/frontend/lib/components/settings/general/AuthModeSettings.svelte +229 -0
- package/frontend/lib/components/settings/general/GeneralSettings.svelte +6 -1
- package/frontend/lib/components/settings/general/UpdateSettings.svelte +5 -5
- package/frontend/lib/components/settings/security/SecuritySettings.svelte +10 -0
- package/frontend/lib/components/settings/system/SystemSettings.svelte +10 -0
- package/frontend/lib/components/settings/user/UserSettings.svelte +147 -74
- package/frontend/lib/components/workspace/PanelHeader.svelte +1 -1
- package/frontend/lib/components/workspace/WorkspaceLayout.svelte +5 -10
- package/frontend/lib/components/workspace/panels/ChatPanel.svelte +3 -2
- package/frontend/lib/services/preview/browser/browser-webcodecs.service.ts +31 -8
- package/frontend/lib/stores/core/sessions.svelte.ts +15 -1
- package/frontend/lib/stores/features/auth.svelte.ts +296 -0
- package/frontend/lib/stores/features/settings.svelte.ts +53 -9
- package/frontend/lib/stores/features/user.svelte.ts +26 -68
- package/frontend/lib/stores/ui/settings-modal.svelte.ts +42 -21
- package/frontend/lib/stores/ui/update.svelte.ts +2 -14
- package/frontend/lib/stores/ui/workspace.svelte.ts +4 -4
- package/package.json +8 -6
- package/shared/types/stores/settings.ts +16 -2
- package/shared/utils/logger.ts +1 -0
- package/shared/utils/ws-client.ts +30 -13
- package/shared/utils/ws-server.ts +42 -4
- package/backend/lib/mcp/stdio-server.ts +0 -103
- package/backend/ws/mcp/index.ts +0 -61
|
@@ -1,35 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Browser Pool Module
|
|
2
|
+
* Browser Pool Module
|
|
3
3
|
*
|
|
4
|
-
* Uses puppeteer-
|
|
4
|
+
* Uses puppeteer-extra with StealthPlugin for Cloudflare bypass.
|
|
5
|
+
* Architecture mirrors the working test-cf.ts approach:
|
|
6
|
+
* - Single shared browser launched directly via puppeteer.launch()
|
|
7
|
+
* - Isolated BrowserContext per session (separate cookies, storage, cache)
|
|
8
|
+
* - StealthPlugin applied at launch time (via puppeteer-extra hooks)
|
|
5
9
|
*
|
|
6
|
-
*
|
|
7
|
-
* -
|
|
8
|
-
*
|
|
9
|
-
* -
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* - Separate cookies
|
|
13
|
-
* - Separate localStorage/sessionStorage
|
|
14
|
-
* - Separate cache
|
|
15
|
-
* - Separate service workers
|
|
16
|
-
* - No data leakage between users
|
|
17
|
-
*
|
|
18
|
-
* Memory Usage:
|
|
19
|
-
* - 1 user: ~300MB (browser) + ~20MB (context) = ~320MB
|
|
20
|
-
* - 10 users: ~300MB (browser) + ~200MB (contexts) = ~500MB
|
|
21
|
-
* - vs. old: 10 users = 10 browsers = 2-5GB
|
|
10
|
+
* Why not puppeteer-cluster?
|
|
11
|
+
* - Cluster's CONCURRENCY_CONTEXT mode accesses the browser via the raw
|
|
12
|
+
* underlying reference, bypassing puppeteer-extra's page creation hooks.
|
|
13
|
+
* - This causes a race condition where stealth evasions (evaluateOnNewDocument)
|
|
14
|
+
* may not be registered before the first navigation, breaking Cloudflare bypass.
|
|
15
|
+
* - Direct launch() ensures puppeteer-extra wraps ALL page creation correctly.
|
|
22
16
|
*/
|
|
23
17
|
|
|
24
|
-
import { Cluster } from 'puppeteer-cluster';
|
|
25
18
|
import type { Browser, BrowserContext, Page } from 'puppeteer';
|
|
26
19
|
import { debug } from '$shared/utils/logger';
|
|
20
|
+
import puppeteer from 'puppeteer-extra';
|
|
21
|
+
import StealthPlugin from 'puppeteer-extra-plugin-stealth';
|
|
22
|
+
|
|
23
|
+
puppeteer.use(StealthPlugin());
|
|
27
24
|
|
|
28
25
|
export interface PoolConfig {
|
|
29
|
-
maxConcurrency: number;
|
|
30
|
-
timeout: number;
|
|
31
|
-
retryLimit: number;
|
|
32
|
-
retryDelay: number;
|
|
26
|
+
maxConcurrency: number;
|
|
27
|
+
timeout: number;
|
|
28
|
+
retryLimit: number;
|
|
29
|
+
retryDelay: number;
|
|
33
30
|
}
|
|
34
31
|
|
|
35
32
|
export interface PooledSession {
|
|
@@ -40,150 +37,89 @@ export interface PooledSession {
|
|
|
40
37
|
}
|
|
41
38
|
|
|
42
39
|
const DEFAULT_CONFIG: PoolConfig = {
|
|
43
|
-
maxConcurrency: 50,
|
|
44
|
-
timeout: 60000,
|
|
45
|
-
retryLimit: 3,
|
|
46
|
-
retryDelay: 1000
|
|
40
|
+
maxConcurrency: 50,
|
|
41
|
+
timeout: 60000,
|
|
42
|
+
retryLimit: 3,
|
|
43
|
+
retryDelay: 1000
|
|
47
44
|
};
|
|
48
45
|
|
|
49
46
|
/**
|
|
50
|
-
*
|
|
47
|
+
* Chromium launch arguments for stealth (matches test-cf.ts exactly)
|
|
51
48
|
*/
|
|
52
49
|
const CHROMIUM_ARGS = [
|
|
53
|
-
// === CORE STABILITY (Windows compatible) ===
|
|
54
50
|
'--no-sandbox',
|
|
55
|
-
'--disable-
|
|
56
|
-
'--
|
|
57
|
-
|
|
58
|
-
// === PREVENT THROTTLING ===
|
|
59
|
-
'--disable-background-timer-throttling',
|
|
60
|
-
'--disable-backgrounding-occluded-windows',
|
|
61
|
-
'--disable-renderer-backgrounding',
|
|
62
|
-
|
|
63
|
-
// === DISABLE UNNECESSARY FEATURES ===
|
|
64
|
-
'--no-first-run',
|
|
65
|
-
'--no-default-browser-check',
|
|
66
|
-
'--disable-extensions',
|
|
67
|
-
'--disable-popup-blocking',
|
|
68
|
-
|
|
69
|
-
// === LOW-END DEVICE OPTIMIZATIONS ===
|
|
70
|
-
'--memory-pressure-off',
|
|
71
|
-
'--disable-features=TranslateUI',
|
|
72
|
-
'--disable-sync',
|
|
73
|
-
'--disable-domain-reliability',
|
|
74
|
-
'--disable-client-side-phishing-detection',
|
|
75
|
-
'--disable-software-rasterizer',
|
|
76
|
-
'--disable-smooth-scrolling',
|
|
77
|
-
'--disable-threaded-animation',
|
|
78
|
-
'--disable-threaded-scrolling',
|
|
79
|
-
'--disable-composited-antialiasing',
|
|
80
|
-
'--disable-webgl',
|
|
81
|
-
'--disable-webgl2',
|
|
82
|
-
'--disable-accelerated-2d-canvas',
|
|
83
|
-
'--disable-gpu-vsync',
|
|
84
|
-
'--disable-ipc-flooding-protection',
|
|
85
|
-
|
|
86
|
-
// === AUDIO SUPPORT ===
|
|
87
|
-
'--autoplay-policy=no-user-gesture-required',
|
|
88
|
-
'--use-fake-ui-for-media-stream'
|
|
51
|
+
'--disable-blink-features=AutomationControlled',
|
|
52
|
+
'--window-size=1366,768'
|
|
89
53
|
];
|
|
90
54
|
|
|
91
55
|
class BrowserPool {
|
|
92
|
-
private
|
|
56
|
+
private browser: Browser | null = null;
|
|
93
57
|
private sessions = new Map<string, PooledSession>();
|
|
94
58
|
private config: PoolConfig;
|
|
95
|
-
private
|
|
96
|
-
private
|
|
59
|
+
private isLaunching = false;
|
|
60
|
+
private launchPromise: Promise<Browser> | null = null;
|
|
97
61
|
|
|
98
62
|
constructor(config: Partial<PoolConfig> = {}) {
|
|
99
63
|
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
100
64
|
}
|
|
101
65
|
|
|
102
66
|
/**
|
|
103
|
-
* Get or create the
|
|
104
|
-
*
|
|
67
|
+
* Get or create the shared browser instance.
|
|
68
|
+
* Uses puppeteer-extra directly (same as test-cf.ts) to ensure
|
|
69
|
+
* StealthPlugin hooks fire for every page created.
|
|
105
70
|
*/
|
|
106
|
-
async
|
|
107
|
-
if (this.
|
|
108
|
-
return this.
|
|
71
|
+
async getBrowser(): Promise<Browser> {
|
|
72
|
+
if (this.browser?.connected) {
|
|
73
|
+
return this.browser;
|
|
109
74
|
}
|
|
110
75
|
|
|
111
|
-
if (this.
|
|
112
|
-
return this.
|
|
76
|
+
if (this.isLaunching && this.launchPromise) {
|
|
77
|
+
return this.launchPromise;
|
|
113
78
|
}
|
|
114
79
|
|
|
115
|
-
this.
|
|
116
|
-
this.
|
|
80
|
+
this.isLaunching = true;
|
|
81
|
+
this.launchPromise = this.launchBrowser();
|
|
117
82
|
|
|
118
83
|
try {
|
|
119
|
-
this.
|
|
120
|
-
return this.
|
|
84
|
+
this.browser = await this.launchPromise;
|
|
85
|
+
return this.browser;
|
|
121
86
|
} finally {
|
|
122
|
-
this.
|
|
123
|
-
this.
|
|
87
|
+
this.isLaunching = false;
|
|
88
|
+
this.launchPromise = null;
|
|
124
89
|
}
|
|
125
90
|
}
|
|
126
91
|
|
|
127
92
|
/**
|
|
128
|
-
* Launch puppeteer-
|
|
93
|
+
* Launch browser via puppeteer-extra (with StealthPlugin already registered).
|
|
94
|
+
* This matches test-cf.ts which successfully bypasses Cloudflare.
|
|
129
95
|
*/
|
|
130
|
-
private async
|
|
131
|
-
debug.log('preview', '🚀 Launching puppeteer-
|
|
132
|
-
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
// Monitor events
|
|
148
|
-
monitor: false // Disable built-in monitoring, we use our own logging
|
|
96
|
+
private async launchBrowser(): Promise<Browser> {
|
|
97
|
+
debug.log('preview', '🚀 Launching browser with puppeteer-extra + StealthPlugin...');
|
|
98
|
+
|
|
99
|
+
const browser = await puppeteer.launch({
|
|
100
|
+
headless: true,
|
|
101
|
+
channel: 'chrome',
|
|
102
|
+
args: CHROMIUM_ARGS
|
|
103
|
+
}) as unknown as Browser;
|
|
104
|
+
|
|
105
|
+
debug.log('preview', '✅ Browser launched successfully');
|
|
106
|
+
|
|
107
|
+
// Handle browser disconnection
|
|
108
|
+
browser.on('disconnected', () => {
|
|
109
|
+
debug.warn('preview', '⚠️ Browser disconnected');
|
|
110
|
+
this.browser = null;
|
|
111
|
+
// Close all sessions since browser is gone
|
|
112
|
+
this.sessions.clear();
|
|
149
113
|
});
|
|
150
114
|
|
|
151
|
-
|
|
152
|
-
cluster.on('taskerror', (err, data) => {
|
|
153
|
-
debug.error('preview', `Task error for session ${data?.sessionId}:`, err.message);
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
debug.log('preview', '✅ puppeteer-cluster launched successfully');
|
|
157
|
-
debug.log('preview', `📊 Max concurrency: ${this.config.maxConcurrency}`);
|
|
158
|
-
|
|
159
|
-
return cluster;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Get the shared browser instance from the cluster
|
|
164
|
-
* Note: This accesses the internal browser - use with caution
|
|
165
|
-
*/
|
|
166
|
-
async getBrowser(): Promise<Browser> {
|
|
167
|
-
const cluster = await this.getCluster();
|
|
168
|
-
|
|
169
|
-
// Access the browser through a dummy task
|
|
170
|
-
// This is a workaround since cluster doesn't expose browser directly
|
|
171
|
-
return new Promise((resolve, reject) => {
|
|
172
|
-
cluster
|
|
173
|
-
.execute(async ({ page }: { page: Page }) => {
|
|
174
|
-
const browser = page.browser();
|
|
175
|
-
resolve(browser);
|
|
176
|
-
})
|
|
177
|
-
.catch(reject);
|
|
178
|
-
});
|
|
115
|
+
return browser;
|
|
179
116
|
}
|
|
180
117
|
|
|
181
118
|
/**
|
|
182
|
-
* Create an isolated session with its own BrowserContext
|
|
183
|
-
*
|
|
119
|
+
* Create an isolated session with its own BrowserContext.
|
|
120
|
+
* Each context has separate cookies, localStorage, sessionStorage, and cache.
|
|
184
121
|
*/
|
|
185
122
|
async createSession(sessionId: string): Promise<PooledSession> {
|
|
186
|
-
// Check if session already exists
|
|
187
123
|
const existing = this.sessions.get(sessionId);
|
|
188
124
|
if (existing) {
|
|
189
125
|
debug.log('preview', `♻️ Reusing existing session: ${sessionId}`);
|
|
@@ -192,13 +128,10 @@ class BrowserPool {
|
|
|
192
128
|
|
|
193
129
|
debug.log('preview', `🔒 Creating isolated session: ${sessionId}`);
|
|
194
130
|
|
|
195
|
-
const cluster = await this.getCluster();
|
|
196
131
|
const browser = await this.getBrowser();
|
|
197
132
|
|
|
198
|
-
// Create isolated
|
|
199
|
-
//
|
|
200
|
-
// When sessionId is prefixed with projectId (e.g., "project123:tab-1"),
|
|
201
|
-
// this ensures complete isolation between projects
|
|
133
|
+
// Create isolated context — puppeteer-extra wraps this correctly
|
|
134
|
+
// so StealthPlugin's onPageCreated fires for every page in this context
|
|
202
135
|
const context = await browser.createBrowserContext();
|
|
203
136
|
const page = await context.newPage();
|
|
204
137
|
|
|
@@ -242,14 +175,12 @@ class BrowserPool {
|
|
|
242
175
|
debug.log('preview', `🗑️ Destroying session: ${sessionId}`);
|
|
243
176
|
|
|
244
177
|
try {
|
|
245
|
-
// Close the page first
|
|
246
178
|
if (session.page && !session.page.isClosed()) {
|
|
247
179
|
await session.page.close().catch((err: Error) => {
|
|
248
180
|
debug.warn('preview', `Error closing page: ${err.message}`);
|
|
249
181
|
});
|
|
250
182
|
}
|
|
251
183
|
|
|
252
|
-
// Close the context (this clears all cookies, storage, cache)
|
|
253
184
|
await session.context.close().catch((err: Error) => {
|
|
254
185
|
debug.warn('preview', `Error closing context: ${err.message}`);
|
|
255
186
|
});
|
|
@@ -261,35 +192,13 @@ class BrowserPool {
|
|
|
261
192
|
debug.log('preview', `✅ Session destroyed (remaining: ${this.sessions.size})`);
|
|
262
193
|
}
|
|
263
194
|
|
|
264
|
-
/**
|
|
265
|
-
* Execute a task in the cluster (for one-off operations)
|
|
266
|
-
*/
|
|
267
|
-
async execute<T>(
|
|
268
|
-
taskFunction: (opts: { page: Page; data: any }) => Promise<T>,
|
|
269
|
-
data?: any
|
|
270
|
-
): Promise<T> {
|
|
271
|
-
const cluster = await this.getCluster();
|
|
272
|
-
return cluster.execute(data, taskFunction);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* Queue a task in the cluster
|
|
277
|
-
*/
|
|
278
|
-
async queue(taskFunction: (opts: { page: Page; data: any }) => Promise<void>, data?: any): Promise<void> {
|
|
279
|
-
const cluster = await this.getCluster();
|
|
280
|
-
cluster.queue(data, taskFunction);
|
|
281
|
-
}
|
|
282
|
-
|
|
283
195
|
/**
|
|
284
196
|
* Check if a session is valid
|
|
285
197
|
*/
|
|
286
198
|
isSessionValid(sessionId: string): boolean {
|
|
287
199
|
const session = this.sessions.get(sessionId);
|
|
288
200
|
if (!session) return false;
|
|
289
|
-
|
|
290
|
-
// Check if page is still open
|
|
291
201
|
if (session.page.isClosed()) return false;
|
|
292
|
-
|
|
293
202
|
return true;
|
|
294
203
|
}
|
|
295
204
|
|
|
@@ -298,7 +207,7 @@ class BrowserPool {
|
|
|
298
207
|
*/
|
|
299
208
|
getStats() {
|
|
300
209
|
return {
|
|
301
|
-
|
|
210
|
+
browserConnected: this.browser?.connected ?? false,
|
|
302
211
|
activeSessions: this.sessions.size,
|
|
303
212
|
maxConcurrency: this.config.maxConcurrency,
|
|
304
213
|
sessions: Array.from(this.sessions.entries()).map(([id, session]) => ({
|
|
@@ -310,34 +219,22 @@ class BrowserPool {
|
|
|
310
219
|
};
|
|
311
220
|
}
|
|
312
221
|
|
|
313
|
-
/**
|
|
314
|
-
* Wait for all queued tasks to complete
|
|
315
|
-
*/
|
|
316
|
-
async idle(): Promise<void> {
|
|
317
|
-
if (this.cluster) {
|
|
318
|
-
await this.cluster.idle();
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
222
|
/**
|
|
323
223
|
* Clean up all resources
|
|
324
224
|
*/
|
|
325
225
|
async cleanup(): Promise<void> {
|
|
326
226
|
debug.log('preview', '🧹 Cleaning up browser pool...');
|
|
327
227
|
|
|
328
|
-
// Destroy all sessions
|
|
329
228
|
const sessionIds = Array.from(this.sessions.keys());
|
|
330
229
|
await Promise.all(sessionIds.map((id) => this.destroySession(id)));
|
|
331
230
|
|
|
332
|
-
|
|
333
|
-
if (this.cluster) {
|
|
231
|
+
if (this.browser) {
|
|
334
232
|
try {
|
|
335
|
-
await this.
|
|
336
|
-
await this.cluster.close();
|
|
233
|
+
await this.browser.close();
|
|
337
234
|
} catch (error) {
|
|
338
|
-
debug.warn('preview', `⚠️ Error closing
|
|
235
|
+
debug.warn('preview', `⚠️ Error closing browser: ${error}`);
|
|
339
236
|
}
|
|
340
|
-
this.
|
|
237
|
+
this.browser = null;
|
|
341
238
|
}
|
|
342
239
|
|
|
343
240
|
debug.log('preview', '✅ Browser pool cleaned up');
|
|
@@ -219,8 +219,9 @@ export class BrowserPreviewService extends EventEmitter {
|
|
|
219
219
|
await this.navigationTracker.setupNavigationTracking(tab.id, tab.page, tab);
|
|
220
220
|
|
|
221
221
|
// Setup dialog bindings and handling
|
|
222
|
-
|
|
223
|
-
await this.dialogHandler.
|
|
222
|
+
// Temporarily disable dialog injection to test CloudFlare evasion
|
|
223
|
+
// await this.dialogHandler.setupDialogBindings(tab.id, tab.page);
|
|
224
|
+
// await this.dialogHandler.setupDialogHandling(tab.id, tab.page, tab);
|
|
224
225
|
|
|
225
226
|
return tab;
|
|
226
227
|
}
|