parse-dashboard 8.2.0-alpha.8 → 8.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/Parse-Dashboard/browser-control/BrowserControlAPI.js +468 -0
- package/Parse-Dashboard/browser-control/BrowserEventStream.js +294 -0
- package/Parse-Dashboard/browser-control/BrowserSessionManager.js +304 -0
- package/Parse-Dashboard/browser-control/README.md +852 -0
- package/Parse-Dashboard/browser-control/ServerOrchestrator.js +334 -0
- package/Parse-Dashboard/browser-control/index.js +27 -0
- package/Parse-Dashboard/browser-control/setup.js +405 -0
- package/Parse-Dashboard/public/bundles/120.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/183.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/19.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/221.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/372.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/448.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/573.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/578.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/584.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/629.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/643.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/647.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/701.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/729.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/75.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/753.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/817.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/844.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/862.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/866.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/874.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/881.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/929.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/950.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/97.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/976.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/dashboard.bundle.js +1 -1
- package/Parse-Dashboard/public/bundles/dashboard.bundle.js.LICENSE.txt +23 -0
- package/Parse-Dashboard/public/bundles/login.bundle.js +1 -1
- package/Parse-Dashboard/server.js +33 -2
- package/README.md +43 -0
- package/package.json +18 -9
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser Control Setup - Development Mode Only
|
|
3
|
+
*
|
|
4
|
+
* This module handles initialization of the browser-control feature for AI agents.
|
|
5
|
+
* It is designed to be completely isolated from production code.
|
|
6
|
+
*
|
|
7
|
+
* SECURITY: This module will NOT load in production environments (NODE_ENV=production)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const { spawn, execSync } = require('child_process');
|
|
11
|
+
const net = require('net');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Webpack compilation state - shared across the module
|
|
16
|
+
* Tracks whether webpack is currently compiling or idle
|
|
17
|
+
*/
|
|
18
|
+
const webpackState = {
|
|
19
|
+
isCompiling: true, // Start as true since initial compilation hasn't happened
|
|
20
|
+
lastCompilationTime: null,
|
|
21
|
+
lastCompilationDuration: null,
|
|
22
|
+
errors: [],
|
|
23
|
+
warnings: [],
|
|
24
|
+
compileCount: 0,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get the current webpack compilation state
|
|
29
|
+
* @returns {Object} Current webpack state
|
|
30
|
+
*/
|
|
31
|
+
function getWebpackState() {
|
|
32
|
+
return { ...webpackState };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Start webpack in watch mode with compilation state tracking
|
|
37
|
+
* @returns {Object} Webpack compiler instance
|
|
38
|
+
*/
|
|
39
|
+
function startWebpackWatchMode() {
|
|
40
|
+
const webpack = require('webpack');
|
|
41
|
+
const webpackConfig = require(path.resolve(__dirname, '../../webpack/build.config.js'));
|
|
42
|
+
|
|
43
|
+
const compiler = webpack(webpackConfig);
|
|
44
|
+
|
|
45
|
+
// Track compilation start
|
|
46
|
+
compiler.hooks.watchRun.tap('BrowserControlPlugin', () => {
|
|
47
|
+
webpackState.isCompiling = true;
|
|
48
|
+
webpackState.compileCount++;
|
|
49
|
+
webpackState.compilationStartTime = Date.now();
|
|
50
|
+
console.log(`[Webpack] Compilation #${webpackState.compileCount} started...`);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Track compilation end
|
|
54
|
+
compiler.hooks.done.tap('BrowserControlPlugin', (stats) => {
|
|
55
|
+
const duration = Date.now() - webpackState.compilationStartTime;
|
|
56
|
+
webpackState.isCompiling = false;
|
|
57
|
+
webpackState.lastCompilationTime = Date.now();
|
|
58
|
+
webpackState.lastCompilationDuration = duration;
|
|
59
|
+
webpackState.errors = stats.hasErrors() ? stats.toJson().errors.map(e => e.message || e) : [];
|
|
60
|
+
webpackState.warnings = stats.hasWarnings() ? stats.toJson().warnings.length : 0;
|
|
61
|
+
|
|
62
|
+
if (stats.hasErrors()) {
|
|
63
|
+
console.log(`[Webpack] Compilation #${webpackState.compileCount} failed with errors (${duration}ms)`);
|
|
64
|
+
} else {
|
|
65
|
+
console.log(`[Webpack] Compilation #${webpackState.compileCount} completed in ${duration}ms`);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Start watching
|
|
70
|
+
const watcher = compiler.watch({
|
|
71
|
+
aggregateTimeout: 300,
|
|
72
|
+
poll: undefined,
|
|
73
|
+
}, (err) => {
|
|
74
|
+
if (err) {
|
|
75
|
+
console.error('[Webpack] Fatal error:', err);
|
|
76
|
+
webpackState.isCompiling = false;
|
|
77
|
+
webpackState.errors = [err.message];
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return { compiler, watcher };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Check if a port is in use by attempting to connect to it
|
|
86
|
+
* @param {number} port - Port number to check
|
|
87
|
+
* @returns {Promise<boolean>} - True if port is in use, false otherwise
|
|
88
|
+
*/
|
|
89
|
+
async function isPortInUse(port) {
|
|
90
|
+
return new Promise((resolve) => {
|
|
91
|
+
const socket = new net.Socket();
|
|
92
|
+
socket.setTimeout(1000);
|
|
93
|
+
|
|
94
|
+
socket.on('connect', () => {
|
|
95
|
+
socket.destroy();
|
|
96
|
+
resolve(true);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
socket.on('timeout', () => {
|
|
100
|
+
socket.destroy();
|
|
101
|
+
resolve(false);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
socket.on('error', () => {
|
|
105
|
+
socket.destroy();
|
|
106
|
+
resolve(false);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
socket.connect(port, '127.0.0.1');
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Get process info using the port (for error messages)
|
|
115
|
+
* @param {number} port - Port number
|
|
116
|
+
* @returns {string|null} - Process info or null if not found
|
|
117
|
+
*/
|
|
118
|
+
function getProcessOnPort(port) {
|
|
119
|
+
try {
|
|
120
|
+
const result = execSync(`lsof -i :${port} -t 2>/dev/null || true`, { encoding: 'utf8' }).trim();
|
|
121
|
+
if (result) {
|
|
122
|
+
const pid = result.split('\n')[0];
|
|
123
|
+
const processInfo = execSync(`ps -p ${pid} -o comm= 2>/dev/null || true`, { encoding: 'utf8' }).trim();
|
|
124
|
+
return processInfo ? `${processInfo} (PID: ${pid})` : `PID: ${pid}`;
|
|
125
|
+
}
|
|
126
|
+
} catch {
|
|
127
|
+
// Silently fail - process info is optional
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Initialize browser control for the dashboard
|
|
134
|
+
* @param {Express.Application} app - Express app instance
|
|
135
|
+
* @param {Object} config - Dashboard configuration
|
|
136
|
+
* @returns {Object|null} - Setup result with initialization hook, or null if disabled
|
|
137
|
+
*/
|
|
138
|
+
function setupBrowserControl(app, config) {
|
|
139
|
+
const isProduction = process.env.NODE_ENV === 'production';
|
|
140
|
+
const configAllowsBrowserControl = config.data.browserControl === true;
|
|
141
|
+
const envAllowsBrowserControl = process.env.PARSE_DASHBOARD_BROWSER_CONTROL === 'true';
|
|
142
|
+
const explicitlyEnabled = configAllowsBrowserControl || envAllowsBrowserControl;
|
|
143
|
+
|
|
144
|
+
const shouldEnable = explicitlyEnabled && !isProduction;
|
|
145
|
+
|
|
146
|
+
if (explicitlyEnabled && isProduction) {
|
|
147
|
+
console.error('⚠️ SECURITY WARNING: Browser Control API cannot be enabled in production (NODE_ENV=production)');
|
|
148
|
+
console.error('⚠️ This is a development-only feature.');
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (!shouldEnable) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
let parseServerProcess = null;
|
|
157
|
+
let mongoDBInstance = null;
|
|
158
|
+
let browserControlAPI = null;
|
|
159
|
+
let browserEventStream = null;
|
|
160
|
+
let webpackWatcher = null;
|
|
161
|
+
|
|
162
|
+
// Auto-start MongoDB and Parse Server
|
|
163
|
+
const { MongoCluster } = require('mongodb-runner');
|
|
164
|
+
const mongoPort = parseInt(process.env.MONGO_PORT, 10) || 27017;
|
|
165
|
+
const parseServerPort = parseInt(process.env.PARSE_SERVER_PORT, 10) || 1337;
|
|
166
|
+
const parseServerURL = `http://localhost:${parseServerPort}/parse`;
|
|
167
|
+
|
|
168
|
+
// Use credentials from config file if available, otherwise fall back to env vars or defaults
|
|
169
|
+
const firstApp = config.data.apps && config.data.apps.length > 0 ? config.data.apps[0] : null;
|
|
170
|
+
const parseServerAppId = process.env.PARSE_SERVER_APP_ID || (firstApp ? firstApp.appId : 'testAppId');
|
|
171
|
+
const parseServerMasterKey = process.env.PARSE_SERVER_MASTER_KEY || (firstApp ? firstApp.masterKey : 'testMasterKey');
|
|
172
|
+
const mongoVersion = process.env.MONGO_VERSION || '8.0.4';
|
|
173
|
+
|
|
174
|
+
// Configure dashboard synchronously before parseDashboard middleware is mounted
|
|
175
|
+
// to ensure the dashboard knows about the auto-started Parse Server
|
|
176
|
+
if (!config.data.apps || config.data.apps.length === 0) {
|
|
177
|
+
config.data.apps = [{
|
|
178
|
+
serverURL: parseServerURL,
|
|
179
|
+
appId: parseServerAppId,
|
|
180
|
+
masterKey: parseServerMasterKey,
|
|
181
|
+
appName: 'Browser Control Test App'
|
|
182
|
+
}];
|
|
183
|
+
console.log('Dashboard auto-configured with test app');
|
|
184
|
+
} else {
|
|
185
|
+
// Update existing first app's serverURL to point to the auto-started Parse Server
|
|
186
|
+
config.data.apps[0].serverURL = parseServerURL;
|
|
187
|
+
console.log(`Dashboard configured to use Parse Server at ${parseServerURL}`);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Wait for MongoDB to be ready by polling for successful connections
|
|
191
|
+
// Throws an error if MongoDB is not ready after maxRetries attempts
|
|
192
|
+
const waitForMongo = async (mongoUri, maxRetries = 20, delayMs = 500) => {
|
|
193
|
+
const { MongoClient } = require('mongodb');
|
|
194
|
+
|
|
195
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
196
|
+
try {
|
|
197
|
+
const client = new MongoClient(mongoUri, {
|
|
198
|
+
serverSelectionTimeoutMS: 1000,
|
|
199
|
+
connectTimeoutMS: 1000
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
await client.connect();
|
|
203
|
+
await client.close();
|
|
204
|
+
|
|
205
|
+
console.log(`MongoDB ready after ${attempt} attempt(s)`);
|
|
206
|
+
return;
|
|
207
|
+
} catch (error) {
|
|
208
|
+
if (attempt === maxRetries) {
|
|
209
|
+
throw new Error(
|
|
210
|
+
`MongoDB not ready after ${maxRetries} attempts (${maxRetries * delayMs}ms): ${error.message}`
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
// Wait before next attempt
|
|
214
|
+
await new Promise(resolve => setTimeout(resolve, delayMs));
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
// Start MongoDB first
|
|
220
|
+
const startMongoDB = async () => {
|
|
221
|
+
// Security check: Abort if MongoDB port is already in use
|
|
222
|
+
if (await isPortInUse(mongoPort)) {
|
|
223
|
+
const processInfo = getProcessOnPort(mongoPort);
|
|
224
|
+
console.error(`\n⛔ SECURITY: MongoDB port ${mongoPort} is already in use${processInfo ? ` by ${processInfo}` : ''}`);
|
|
225
|
+
console.error('⛔ Browser Control will not start to prevent potential conflicts or security issues.');
|
|
226
|
+
console.error('⛔ Please stop the existing process or use a different port via MONGO_PORT environment variable.\n');
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
try {
|
|
231
|
+
console.log(`Starting MongoDB ${mongoVersion} instance on port ${mongoPort}...`);
|
|
232
|
+
const os = require('os');
|
|
233
|
+
mongoDBInstance = await MongoCluster.start({
|
|
234
|
+
topology: 'standalone',
|
|
235
|
+
version: mongoVersion,
|
|
236
|
+
tmpDir: os.tmpdir(),
|
|
237
|
+
args: ['--port', mongoPort.toString()],
|
|
238
|
+
});
|
|
239
|
+
const mongoUri = mongoDBInstance.connectionString;
|
|
240
|
+
console.log(`MongoDB ${mongoVersion} started at ${mongoUri}`);
|
|
241
|
+
return mongoUri;
|
|
242
|
+
} catch (error) {
|
|
243
|
+
console.warn('Failed to start MongoDB:', error.message);
|
|
244
|
+
console.warn('Attempting to use existing MongoDB connection...');
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
// Start Parse Server after MongoDB is ready
|
|
250
|
+
const startParseServer = async (mongoUri) => {
|
|
251
|
+
// Security check: Abort if Parse Server port is already in use
|
|
252
|
+
if (await isPortInUse(parseServerPort)) {
|
|
253
|
+
const processInfo = getProcessOnPort(parseServerPort);
|
|
254
|
+
console.error(`\n⛔ SECURITY: Parse Server port ${parseServerPort} is already in use${processInfo ? ` by ${processInfo}` : ''}`);
|
|
255
|
+
console.error('⛔ Browser Control will not start Parse Server to prevent potential conflicts or security issues.');
|
|
256
|
+
console.error('⛔ Please stop the existing process or use a different port via PARSE_SERVER_PORT environment variable.\n');
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
try {
|
|
261
|
+
console.log(`Starting Parse Server for browser control on port ${parseServerPort}...`);
|
|
262
|
+
parseServerProcess = spawn('npx', [
|
|
263
|
+
'parse-server',
|
|
264
|
+
'--appId', parseServerAppId,
|
|
265
|
+
'--masterKey', parseServerMasterKey,
|
|
266
|
+
'--databaseURI', mongoUri,
|
|
267
|
+
'--port', parseServerPort.toString(),
|
|
268
|
+
'--serverURL', parseServerURL,
|
|
269
|
+
'--mountPath', '/parse'
|
|
270
|
+
], {
|
|
271
|
+
stdio: ['ignore', 'pipe', 'pipe']
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
// Listen for Parse Server output
|
|
275
|
+
parseServerProcess.stdout.on('data', (data) => {
|
|
276
|
+
const output = data.toString();
|
|
277
|
+
if (output.includes('parse-server running') || output.includes('listening on port')) {
|
|
278
|
+
console.log(`Parse Server started at ${parseServerURL}`);
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
parseServerProcess.stderr.on('data', (data) => {
|
|
283
|
+
const error = data.toString();
|
|
284
|
+
// Only log actual errors, not warnings
|
|
285
|
+
if (error.includes('error') || error.includes('Error')) {
|
|
286
|
+
console.error('[Parse Server]:', error);
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
parseServerProcess.on('exit', (code) => {
|
|
291
|
+
if (code !== 0 && code !== null) {
|
|
292
|
+
console.error(`Parse Server exited with code ${code}`);
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
parseServerProcess.on('error', (err) => {
|
|
297
|
+
console.error(`Failed to spawn Parse Server: ${err.message}`);
|
|
298
|
+
console.error('This may happen if npx is not available or parse-server is not installed.');
|
|
299
|
+
console.error('Browser control will work but you need to configure apps manually.');
|
|
300
|
+
parseServerProcess = null;
|
|
301
|
+
});
|
|
302
|
+
} catch (error) {
|
|
303
|
+
console.warn('Failed to start Parse Server:', error.message);
|
|
304
|
+
console.warn('Browser control will work but you need to configure apps manually');
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
// Start MongoDB, wait for it to be ready, then start Parse Server
|
|
309
|
+
startMongoDB()
|
|
310
|
+
.then(async (mongoUri) => {
|
|
311
|
+
if (!mongoUri) {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
try {
|
|
316
|
+
// Wait for MongoDB to accept connections before starting Parse Server
|
|
317
|
+
await waitForMongo(mongoUri);
|
|
318
|
+
await startParseServer(mongoUri);
|
|
319
|
+
} catch (error) {
|
|
320
|
+
console.error('Failed to connect to MongoDB:', error.message);
|
|
321
|
+
console.error('Parse Server will not be started');
|
|
322
|
+
}
|
|
323
|
+
})
|
|
324
|
+
.catch(error => {
|
|
325
|
+
console.error('Error in MongoDB startup sequence:', error.message);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// Start webpack in watch mode with state tracking
|
|
329
|
+
try {
|
|
330
|
+
const webpackResult = startWebpackWatchMode();
|
|
331
|
+
webpackWatcher = webpackResult.watcher;
|
|
332
|
+
console.log('Webpack watch mode started with state tracking');
|
|
333
|
+
} catch (error) {
|
|
334
|
+
console.warn('Failed to start webpack watch mode:', error.message);
|
|
335
|
+
// Mark webpack as not compiling if we couldn't start it
|
|
336
|
+
webpackState.isCompiling = false;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Load browser control API BEFORE parseDashboard middleware to bypass authentication
|
|
340
|
+
try {
|
|
341
|
+
const createBrowserControlAPI = require('./BrowserControlAPI');
|
|
342
|
+
browserControlAPI = createBrowserControlAPI(getWebpackState);
|
|
343
|
+
app.use('/browser-control', browserControlAPI);
|
|
344
|
+
console.log('Browser Control API enabled at /browser-control');
|
|
345
|
+
} catch (error) {
|
|
346
|
+
console.warn('Failed to load Browser Control API:', error.message);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Cleanup function for servers
|
|
350
|
+
const cleanup = () => {
|
|
351
|
+
// Shutdown WebSocket server
|
|
352
|
+
if (browserEventStream) {
|
|
353
|
+
browserEventStream.shutdown().catch(err => {
|
|
354
|
+
console.warn('Error shutting down Browser Event Stream:', err.message);
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Stop webpack watcher
|
|
359
|
+
if (webpackWatcher) {
|
|
360
|
+
console.log('Stopping webpack watcher...');
|
|
361
|
+
webpackWatcher.close(() => {
|
|
362
|
+
console.log('Webpack watcher stopped');
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if (parseServerProcess) {
|
|
367
|
+
console.log('Stopping Parse Server...');
|
|
368
|
+
parseServerProcess.kill('SIGTERM');
|
|
369
|
+
// Force kill after 5 seconds if still running
|
|
370
|
+
setTimeout(() => {
|
|
371
|
+
if (parseServerProcess && !parseServerProcess.killed) {
|
|
372
|
+
parseServerProcess.kill('SIGKILL');
|
|
373
|
+
}
|
|
374
|
+
}, 5000);
|
|
375
|
+
}
|
|
376
|
+
if (mongoDBInstance) {
|
|
377
|
+
console.log('Stopping MongoDB...');
|
|
378
|
+
mongoDBInstance.close().catch(err => {
|
|
379
|
+
console.warn('Error stopping MongoDB:', err.message);
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
// Hook to initialize WebSocket when HTTP server is ready
|
|
385
|
+
const initializeWebSocket = (server) => {
|
|
386
|
+
if (!browserControlAPI) {
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
try {
|
|
391
|
+
const BrowserEventStream = require('./BrowserEventStream');
|
|
392
|
+
browserEventStream = new BrowserEventStream(server, browserControlAPI.sessionManager);
|
|
393
|
+
} catch (error) {
|
|
394
|
+
console.warn('Failed to initialize Browser Event Stream:', error.message);
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
// Return setup result with hooks
|
|
399
|
+
return {
|
|
400
|
+
cleanup,
|
|
401
|
+
initializeWebSocket
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
module.exports = setupBrowserControl;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[120],{71120
|
|
1
|
+
"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[120],{71120(e,o,n){n.d(o,{a:()=>u,d:()=>l});var t=n(38950),i=Object.defineProperty,r=(e,o)=>i(e,"name",{value:o,configurable:!0});function a(e,o){return o.forEach(function(o){o&&"string"!=typeof o&&!Array.isArray(o)&&Object.keys(o).forEach(function(n){if("default"!==n&&!(n in e)){var t=Object.getOwnPropertyDescriptor(o,n);Object.defineProperty(e,n,t.get?t:{enumerable:!0,get:function(){return o[n]}})}})}),Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}r(a,"_mergeNamespaces");var u={exports:{}};!function(e){function o(o,n,t){var i,r=o.getWrapperElement();return(i=r.appendChild(document.createElement("div"))).className=t?"CodeMirror-dialog CodeMirror-dialog-bottom":"CodeMirror-dialog CodeMirror-dialog-top","string"==typeof n?i.innerHTML=n:i.appendChild(n),e.addClass(r,"dialog-opened"),i}function n(e,o){e.state.currentNotificationClose&&e.state.currentNotificationClose(),e.state.currentNotificationClose=o}r(o,"dialogDiv"),r(n,"closeNotification"),e.defineExtension("openDialog",function(t,i,a){a||(a={}),n(this,null);var u=o(this,t,a.bottom),l=!1,c=this;function s(o){if("string"==typeof o)d.value=o;else{if(l)return;l=!0,e.rmClass(u.parentNode,"dialog-opened"),u.parentNode.removeChild(u),c.focus(),a.onClose&&a.onClose(u)}}r(s,"close");var f,d=u.getElementsByTagName("input")[0];return d?(d.focus(),a.value&&(d.value=a.value,!1!==a.selectValueOnOpen&&d.select()),a.onInput&&e.on(d,"input",function(e){a.onInput(e,d.value,s)}),a.onKeyUp&&e.on(d,"keyup",function(e){a.onKeyUp(e,d.value,s)}),e.on(d,"keydown",function(o){a&&a.onKeyDown&&a.onKeyDown(o,d.value,s)||((27==o.keyCode||!1!==a.closeOnEnter&&13==o.keyCode)&&(d.blur(),e.e_stop(o),s()),13==o.keyCode&&i(d.value,o))}),!1!==a.closeOnBlur&&e.on(u,"focusout",function(e){null!==e.relatedTarget&&s()})):(f=u.getElementsByTagName("button")[0])&&(e.on(f,"click",function(){s(),c.focus()}),!1!==a.closeOnBlur&&e.on(f,"blur",s),f.focus()),s}),e.defineExtension("openConfirm",function(t,i,a){n(this,null);var u=o(this,t,a&&a.bottom),l=u.getElementsByTagName("button"),c=!1,s=this,f=1;function d(){c||(c=!0,e.rmClass(u.parentNode,"dialog-opened"),u.parentNode.removeChild(u),s.focus())}r(d,"close"),l[0].focus();for(var p=0;p<l.length;++p){var g=l[p];(function(o){e.on(g,"click",function(n){e.e_preventDefault(n),d(),o&&o(s)})})(i[p]),e.on(g,"blur",function(){--f,setTimeout(function(){f<=0&&d()},200)}),e.on(g,"focus",function(){++f})}}),e.defineExtension("openNotification",function(t,i){n(this,s);var a,u=o(this,t,i&&i.bottom),l=!1,c=i&&void 0!==i.duration?i.duration:5e3;function s(){l||(l=!0,clearTimeout(a),e.rmClass(u.parentNode,"dialog-opened"),u.parentNode.removeChild(u))}return r(s,"close"),e.on(u,"click",function(o){e.e_preventDefault(o),s()}),c&&(a=setTimeout(s,c)),s})}(t.a.exports);var l=a({__proto__:null,default:u.exports},[u.exports])}}]);
|