parse-dashboard-analytics 7.4.2 → 7.4.5

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 (43) hide show
  1. package/Parse-Dashboard/Authentication.js +9 -4
  2. package/Parse-Dashboard/CLI/mfa.js +11 -5
  3. package/Parse-Dashboard/app.js +93 -26
  4. package/Parse-Dashboard/browser-control/BrowserControlAPI.js +468 -0
  5. package/Parse-Dashboard/browser-control/BrowserEventStream.js +294 -0
  6. package/Parse-Dashboard/browser-control/BrowserSessionManager.js +304 -0
  7. package/Parse-Dashboard/browser-control/README.md +852 -0
  8. package/Parse-Dashboard/browser-control/ServerOrchestrator.js +334 -0
  9. package/Parse-Dashboard/browser-control/index.js +27 -0
  10. package/Parse-Dashboard/browser-control/setup.js +405 -0
  11. package/Parse-Dashboard/public/bundles/120.bundle.js +1 -1
  12. package/Parse-Dashboard/public/bundles/183.bundle.js +1 -1
  13. package/Parse-Dashboard/public/bundles/19.bundle.js +1 -1
  14. package/Parse-Dashboard/public/bundles/221.bundle.js +1 -1
  15. package/Parse-Dashboard/public/bundles/372.bundle.js +1 -1
  16. package/Parse-Dashboard/public/bundles/448.bundle.js +1 -1
  17. package/Parse-Dashboard/public/bundles/573.bundle.js +1 -1
  18. package/Parse-Dashboard/public/bundles/578.bundle.js +1 -1
  19. package/Parse-Dashboard/public/bundles/584.bundle.js +1 -1
  20. package/Parse-Dashboard/public/bundles/629.bundle.js +1 -1
  21. package/Parse-Dashboard/public/bundles/643.bundle.js +1 -1
  22. package/Parse-Dashboard/public/bundles/647.bundle.js +1 -1
  23. package/Parse-Dashboard/public/bundles/701.bundle.js +1 -1
  24. package/Parse-Dashboard/public/bundles/729.bundle.js +1 -1
  25. package/Parse-Dashboard/public/bundles/75.bundle.js +1 -1
  26. package/Parse-Dashboard/public/bundles/753.bundle.js +1 -1
  27. package/Parse-Dashboard/public/bundles/817.bundle.js +1 -1
  28. package/Parse-Dashboard/public/bundles/844.bundle.js +1 -1
  29. package/Parse-Dashboard/public/bundles/862.bundle.js +1 -1
  30. package/Parse-Dashboard/public/bundles/866.bundle.js +1 -1
  31. package/Parse-Dashboard/public/bundles/874.bundle.js +1 -1
  32. package/Parse-Dashboard/public/bundles/881.bundle.js +1 -1
  33. package/Parse-Dashboard/public/bundles/929.bundle.js +1 -1
  34. package/Parse-Dashboard/public/bundles/950.bundle.js +1 -1
  35. package/Parse-Dashboard/public/bundles/97.bundle.js +1 -1
  36. package/Parse-Dashboard/public/bundles/976.bundle.js +1 -1
  37. package/Parse-Dashboard/public/bundles/dashboard.bundle.js +1 -1
  38. package/Parse-Dashboard/public/bundles/dashboard.bundle.js.LICENSE.txt +27 -33
  39. package/Parse-Dashboard/public/bundles/login.bundle.js +1 -1
  40. package/Parse-Dashboard/public/bundles/sprites.svg +294 -154
  41. package/Parse-Dashboard/server.js +33 -2
  42. package/README.md +475 -117
  43. package/package.json +68 -53
@@ -0,0 +1,852 @@
1
+ # Browser Control API for Parse Dashboard
2
+
3
+ ## Overview
4
+
5
+ The Browser Control API is a development-time tool that allows AI agents to interact with Parse Dashboard through an automated browser during feature implementation and debugging. This enables real-time verification without writing test files.
6
+
7
+ **This is NOT a replacement for unit tests or E2E tests** - it's specifically designed for AI agents to validate implementations while actively developing features.
8
+
9
+ ## Quick Start
10
+
11
+ ### Prerequisites
12
+
13
+ **Requirements:**
14
+ - Node.js 20.19.0 or higher
15
+
16
+ **Note:** MongoDB is automatically started when you run `npm run browser-control` - no manual setup needed!
17
+
18
+ ### 1. Start Dashboard with Browser Control
19
+
20
+ When you run the browser-control command, **MongoDB and Parse Server automatically start** alongside the dashboard - zero setup required!
21
+
22
+ ```bash
23
+ npm run browser-control
24
+ ```
25
+
26
+ This will:
27
+ 1. Download and start MongoDB 8.0.4 (if not already downloaded)
28
+ 2. Start Parse Server on port 1337 (connects to the auto-started MongoDB)
29
+ 3. Start Dashboard on port 4040
30
+ 4. Auto-configure dashboard with a test app pointing to Parse Server
31
+ 5. Enable Browser Control API at `/browser-control`
32
+
33
+ Or for visible browser (helpful for debugging):
34
+
35
+ ```bash
36
+ npm run browser-control:visible
37
+ ```
38
+
39
+ Both scripts include webpack watch mode, so code changes are automatically rebuilt. Just reload the page to see updates.
40
+
41
+ **What happens automatically:**
42
+ - MongoDB 8.0.4 is downloaded (on first run) and started automatically
43
+ - Parse Server spawns and connects to the MongoDB instance
44
+ - Dashboard creates a test app called "Browser Control Test App"
45
+ - You can immediately start creating browser sessions and testing
46
+ - Everything stops cleanly when you exit (Ctrl+C)
47
+
48
+ ### 2. Wait for Dashboard to be Ready
49
+
50
+ Before creating a browser session, wait for webpack to finish compiling the assets:
51
+
52
+ ```bash
53
+ curl http://localhost:4040/browser-control/ready/wait
54
+ ```
55
+
56
+ Response:
57
+ ```json
58
+ {
59
+ "ready": true,
60
+ "waited": 6273,
61
+ "webpack": {
62
+ "compiling": false,
63
+ "lastCompilationTime": 1234567890000,
64
+ "lastCompilationDuration": 6152,
65
+ "compileCount": 1
66
+ }
67
+ }
68
+ ```
69
+
70
+ This is important because webpack runs in watch mode and compiles assets on startup and after file changes. Navigating before compilation completes will result in timeouts.
71
+
72
+ ### 3. Create a Browser Session
73
+
74
+ ```bash
75
+ curl -X POST http://localhost:4040/browser-control/session/start \
76
+ -H "Content-Type: application/json" \
77
+ -d '{"headless": true, "startServers": false}'
78
+ ```
79
+
80
+ Response:
81
+ ```json
82
+ {
83
+ "sessionId": "sess_1234567890_abc123",
84
+ "dashboardUrl": null,
85
+ "parseServerUrl": null
86
+ }
87
+ ```
88
+
89
+ ### 4. Navigate to Dashboard
90
+
91
+ ```bash
92
+ curl -X POST http://localhost:4040/browser-control/session/sess_1234567890_abc123/navigate \
93
+ -H "Content-Type: application/json" \
94
+ -d '{"url": "http://localhost:4040/"}'
95
+ ```
96
+
97
+ ### 5. Take Screenshot
98
+
99
+ ```bash
100
+ curl http://localhost:4040/browser-control/session/sess_1234567890_abc123/screenshot
101
+ ```
102
+
103
+ ### 6. Cleanup
104
+
105
+ ```bash
106
+ curl -X DELETE http://localhost:4040/browser-control/session/sess_1234567890_abc123
107
+ ```
108
+
109
+ ## API Reference
110
+
111
+ ### Session Management
112
+
113
+ #### Create Session
114
+ **POST** `/browser-control/session/start`
115
+
116
+ Create a new browser session, optionally starting Parse Server and Dashboard.
117
+
118
+ **Request Body:**
119
+ ```json
120
+ {
121
+ "headless": true, // Optional: Run headless (default: true)
122
+ "width": 1280, // Optional: Browser width (default: 1280)
123
+ "height": 720, // Optional: Browser height (default: 720)
124
+ "slowMo": 0, // Optional: Slow down by N ms (default: 0)
125
+ "startServers": false, // Optional: Start Parse Server + Dashboard (default: false)
126
+ "parseServerOptions": { // Optional: Parse Server config
127
+ "port": 1337,
128
+ "appId": "testAppId",
129
+ "masterKey": "testMasterKey",
130
+ "databaseURI": "mongodb://localhost:27017/test"
131
+ },
132
+ "dashboardOptions": { // Optional: Dashboard config
133
+ "port": 4040,
134
+ "appName": "TestApp"
135
+ }
136
+ }
137
+ ```
138
+
139
+ **Response:**
140
+ ```json
141
+ {
142
+ "sessionId": "sess_1234567890_abc123",
143
+ "dashboardUrl": "http://localhost:4040",
144
+ "parseServerUrl": "http://localhost:1337/parse",
145
+ "servers": {
146
+ "parseServer": { "port": 1337, "appId": "testAppId" },
147
+ "dashboard": { "port": 4040 }
148
+ }
149
+ }
150
+ ```
151
+
152
+ #### Get Session Status
153
+ **GET** `/browser-control/session/:sessionId/status`
154
+
155
+ **Response:**
156
+ ```json
157
+ {
158
+ "sessionId": "sess_1234567890_abc123",
159
+ "active": true,
160
+ "pageUrl": "http://localhost:4040/apps",
161
+ "createdAt": 1234567890000,
162
+ "lastActivity": 1234567895000,
163
+ "uptime": 5000
164
+ }
165
+ ```
166
+
167
+ #### Delete Session
168
+ **DELETE** `/browser-control/session/:sessionId`
169
+
170
+ Cleanup and destroy browser session.
171
+
172
+ **Response:**
173
+ ```json
174
+ {
175
+ "success": true,
176
+ "sessionId": "sess_1234567890_abc123"
177
+ }
178
+ ```
179
+
180
+ #### List All Sessions
181
+ **GET** `/browser-control/sessions`
182
+
183
+ **Response:**
184
+ ```json
185
+ {
186
+ "sessions": [
187
+ {
188
+ "sessionId": "sess_1234567890_abc123",
189
+ "createdAt": 1234567890000,
190
+ "lastActivity": 1234567895000,
191
+ "uptime": 5000,
192
+ "crashed": false,
193
+ "pageUrl": "http://localhost:4040/apps"
194
+ }
195
+ ],
196
+ "count": 1
197
+ }
198
+ ```
199
+
200
+ ### Navigation & Interaction
201
+
202
+ #### Navigate
203
+ **POST** `/browser-control/session/:sessionId/navigate`
204
+
205
+ Navigate to a URL.
206
+
207
+ **Request Body:**
208
+ ```json
209
+ {
210
+ "url": "http://localhost:4040/apps",
211
+ "waitUntil": "networkidle2", // Optional: load, domcontentloaded, networkidle0, networkidle2
212
+ "timeout": 30000 // Optional: timeout in ms (default: 30000)
213
+ }
214
+ ```
215
+
216
+ **Response:**
217
+ ```json
218
+ {
219
+ "success": true,
220
+ "currentUrl": "http://localhost:4040/apps"
221
+ }
222
+ ```
223
+
224
+ #### Click Element
225
+ **POST** `/browser-control/session/:sessionId/click`
226
+
227
+ Click an element by CSS selector.
228
+
229
+ **Request Body:**
230
+ ```json
231
+ {
232
+ "selector": "#login-button",
233
+ "timeout": 5000 // Optional: timeout in ms (default: 5000)
234
+ }
235
+ ```
236
+
237
+ **Response:**
238
+ ```json
239
+ {
240
+ "success": true,
241
+ "selector": "#login-button"
242
+ }
243
+ ```
244
+
245
+ #### Type Text
246
+ **POST** `/browser-control/session/:sessionId/type`
247
+
248
+ Type text into an input field.
249
+
250
+ **Request Body:**
251
+ ```json
252
+ {
253
+ "selector": "input[name='username']",
254
+ "text": "admin",
255
+ "timeout": 5000, // Optional: timeout in ms (default: 5000)
256
+ "delay": 0 // Optional: delay between keystrokes in ms (default: 0)
257
+ }
258
+ ```
259
+
260
+ **Response:**
261
+ ```json
262
+ {
263
+ "success": true,
264
+ "selector": "input[name='username']",
265
+ "text": "admin"
266
+ }
267
+ ```
268
+
269
+ #### Wait for Element
270
+ **POST** `/browser-control/session/:sessionId/wait`
271
+
272
+ Wait for an element to appear.
273
+
274
+ **Request Body:**
275
+ ```json
276
+ {
277
+ "selector": ".data-browser",
278
+ "timeout": 10000, // Optional: timeout in ms (default: 10000)
279
+ "visible": true // Optional: wait for visibility (default: true)
280
+ }
281
+ ```
282
+
283
+ **Response:**
284
+ ```json
285
+ {
286
+ "success": true,
287
+ "selector": ".data-browser",
288
+ "found": true,
289
+ "duration": 342
290
+ }
291
+ ```
292
+
293
+ #### Reload Page
294
+ **POST** `/browser-control/session/:sessionId/reload`
295
+
296
+ Reload the current page.
297
+
298
+ **Request Body:**
299
+ ```json
300
+ {
301
+ "waitUntil": "networkidle2" // Optional: wait condition
302
+ }
303
+ ```
304
+
305
+ **Response:**
306
+ ```json
307
+ {
308
+ "success": true,
309
+ "currentUrl": "http://localhost:4040/apps"
310
+ }
311
+ ```
312
+
313
+ ### Inspection & Debugging
314
+
315
+ #### Take Screenshot
316
+ **GET** `/browser-control/session/:sessionId/screenshot?fullPage=true&encoding=base64`
317
+
318
+ Capture a screenshot of the current page.
319
+
320
+ **Query Parameters:**
321
+ - `fullPage`: Capture full scrollable page (default: `true`)
322
+ - `encoding`: `base64` or `binary` (default: `base64`)
323
+
324
+ **Response:**
325
+ ```json
326
+ {
327
+ "base64": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
328
+ }
329
+ ```
330
+
331
+ #### Execute JavaScript
332
+ **POST** `/browser-control/session/:sessionId/evaluate`
333
+
334
+ Execute JavaScript in the page context.
335
+
336
+ > [!WARNING]
337
+ > This endpoint executes arbitrary JavaScript in the browser page context. While the code runs in a sandboxed browser environment (not on the server), it can access anything visible to the page including cookies, localStorage, and DOM content. This is intentional for AI agent debugging but is a powerful capability. The endpoint is protected by the production block - it cannot be enabled when `NODE_ENV=production`.
338
+
339
+ **Request Body:**
340
+ ```json
341
+ {
342
+ "script": "document.querySelector('.graph-panel-header')?.offsetHeight"
343
+ }
344
+ ```
345
+
346
+ **Response:**
347
+ ```json
348
+ {
349
+ "result": 50
350
+ }
351
+ ```
352
+
353
+ #### Query Elements
354
+ **POST** `/browser-control/session/:sessionId/query`
355
+
356
+ Query elements on the page.
357
+
358
+ **Request Body:**
359
+ ```json
360
+ {
361
+ "selector": ".data-row",
362
+ "multiple": true // Optional: query multiple elements (default: false)
363
+ }
364
+ ```
365
+
366
+ **Response (single):**
367
+ ```json
368
+ {
369
+ "element": {
370
+ "text": "Test Object",
371
+ "visible": true,
372
+ "tagName": "DIV",
373
+ "className": "data-row"
374
+ }
375
+ }
376
+ ```
377
+
378
+ **Response (multiple):**
379
+ ```json
380
+ {
381
+ "elements": [
382
+ {
383
+ "text": "Object 1",
384
+ "visible": true,
385
+ "tagName": "DIV",
386
+ "className": "data-row"
387
+ },
388
+ {
389
+ "text": "Object 2",
390
+ "visible": true,
391
+ "tagName": "DIV",
392
+ "className": "data-row"
393
+ }
394
+ ],
395
+ "count": 2
396
+ }
397
+ ```
398
+
399
+ ### Server Management
400
+
401
+ #### Get Server Status
402
+ **GET** `/browser-control/servers/status`
403
+
404
+ **Response:**
405
+ ```json
406
+ {
407
+ "parseServer": {
408
+ "running": true,
409
+ "port": 1337,
410
+ "serverURL": "http://localhost:1337/parse",
411
+ "appId": "testAppId"
412
+ },
413
+ "dashboard": {
414
+ "running": true,
415
+ "port": 4040,
416
+ "url": "http://localhost:4040"
417
+ }
418
+ }
419
+ ```
420
+
421
+ #### Stop Servers
422
+ **POST** `/browser-control/servers/stop`
423
+
424
+ Stop Parse Server and Dashboard instances.
425
+
426
+ **Response:**
427
+ ```json
428
+ {
429
+ "success": true
430
+ }
431
+ ```
432
+
433
+ ### Webpack Readiness
434
+
435
+ #### Check Ready Status
436
+ **GET** `/browser-control/ready`
437
+
438
+ Check if the dashboard is ready (webpack has finished compiling assets).
439
+
440
+ **Response:**
441
+ ```json
442
+ {
443
+ "ready": true,
444
+ "webpack": {
445
+ "compiling": false,
446
+ "lastCompilationTime": 1234567890000,
447
+ "lastCompilationDuration": 6152,
448
+ "compileCount": 1,
449
+ "hasErrors": false
450
+ }
451
+ }
452
+ ```
453
+
454
+ #### Wait for Ready
455
+ **GET** `/browser-control/ready/wait?timeout=30000`
456
+
457
+ Wait for webpack to finish compiling. This is a blocking endpoint that polls until webpack is idle or timeout is reached.
458
+
459
+ **Query Parameters:**
460
+ - `timeout`: Maximum time to wait in milliseconds (default: 30000)
461
+
462
+ **Response (success):**
463
+ ```json
464
+ {
465
+ "ready": true,
466
+ "waited": 6273,
467
+ "webpack": {
468
+ "compiling": false,
469
+ "lastCompilationTime": 1234567890000,
470
+ "lastCompilationDuration": 6152,
471
+ "compileCount": 1
472
+ }
473
+ }
474
+ ```
475
+
476
+ **Response (timeout - HTTP 408):**
477
+ ```json
478
+ {
479
+ "ready": false,
480
+ "error": "Timeout waiting for webpack to finish compiling",
481
+ "waited": 30000,
482
+ "webpack": {
483
+ "compiling": true,
484
+ "compileCount": 1
485
+ }
486
+ }
487
+ ```
488
+
489
+ > [!IMPORTANT]
490
+ > Always call `/ready/wait` before creating browser sessions, especially after:
491
+ > - Starting the dashboard
492
+ > - Editing source files (triggers webpack recompilation)
493
+ >
494
+ > Navigation attempts while webpack is compiling will timeout because the JavaScript bundles are not yet available.
495
+
496
+ ### Cleanup
497
+
498
+ #### Cleanup All
499
+ **POST** `/browser-control/cleanup`
500
+
501
+ Cleanup all sessions and stop all servers.
502
+
503
+ **Response:**
504
+ ```json
505
+ {
506
+ "success": true
507
+ }
508
+ ```
509
+
510
+ ## WebSocket Event Stream
511
+
512
+ Connect to the WebSocket stream to receive real-time events from the browser.
513
+
514
+ ### Connection
515
+
516
+ ```
517
+ ws://localhost:4040/browser-control/stream/:sessionId
518
+ ```
519
+
520
+ ### Event Types
521
+
522
+ #### Console Messages
523
+ ```json
524
+ {
525
+ "type": "console",
526
+ "level": "log",
527
+ "text": "Application loaded",
528
+ "timestamp": 1234567890000
529
+ }
530
+ ```
531
+
532
+ #### Errors
533
+ ```json
534
+ {
535
+ "type": "error",
536
+ "message": "Uncaught TypeError: Cannot read property 'x' of undefined",
537
+ "stack": "TypeError: Cannot read property 'x' of undefined\n at...",
538
+ "timestamp": 1234567890000
539
+ }
540
+ ```
541
+
542
+ #### Network Requests
543
+ ```json
544
+ {
545
+ "type": "network",
546
+ "method": "POST",
547
+ "url": "http://localhost:1337/parse/classes/TestClass",
548
+ "status": 200,
549
+ "timestamp": 1234567890000
550
+ }
551
+ ```
552
+
553
+ #### Navigation
554
+ ```json
555
+ {
556
+ "type": "navigation",
557
+ "url": "http://localhost:4040/apps/testApp/browser",
558
+ "timestamp": 1234567890000
559
+ }
560
+ ```
561
+
562
+ #### Session Events
563
+ ```json
564
+ {
565
+ "type": "session-event",
566
+ "event": "created",
567
+ "sessionId": "sess_1234567890_abc123",
568
+ "timestamp": 1234567890000
569
+ }
570
+ ```
571
+
572
+ ## AI Agent Workflow Examples
573
+
574
+ ### Example 1: Verify Feature Implementation
575
+
576
+ ```javascript
577
+ // AI agent just implemented a delete button feature
578
+
579
+ // 1. Wait for webpack to be ready (important after editing files!)
580
+ await fetch('http://localhost:4040/browser-control/ready/wait');
581
+
582
+ // 2. Create session
583
+ const createRes = await fetch('http://localhost:4040/browser-control/session/start', {
584
+ method: 'POST',
585
+ headers: { 'Content-Type': 'application/json' },
586
+ body: JSON.stringify({ headless: false, startServers: false })
587
+ });
588
+ const { sessionId } = await createRes.json();
589
+
590
+ // 3. Navigate to class browser
591
+ await fetch(`http://localhost:4040/browser-control/session/${sessionId}/navigate`, {
592
+ method: 'POST',
593
+ headers: { 'Content-Type': 'application/json' },
594
+ body: JSON.stringify({ url: 'http://localhost:4040/apps/testApp/browser/TestClass' })
595
+ });
596
+
597
+ // 4. Check if delete button exists
598
+ const queryRes = await fetch(`http://localhost:4040/browser-control/session/${sessionId}/query`, {
599
+ method: 'POST',
600
+ headers: { 'Content-Type': 'application/json' },
601
+ body: JSON.stringify({ selector: '.delete-button' })
602
+ });
603
+ const { element } = await queryRes.json();
604
+
605
+ if (element) {
606
+ console.log('✓ Delete button found!');
607
+
608
+ // 5. Take screenshot for verification
609
+ const screenshotRes = await fetch(
610
+ `http://localhost:4040/browser-control/session/${sessionId}/screenshot`
611
+ );
612
+ const { base64 } = await screenshotRes.json();
613
+ // AI can analyze screenshot
614
+ } else {
615
+ console.log('❌ Delete button not found - need to fix');
616
+ }
617
+
618
+ // 6. Cleanup
619
+ await fetch(`http://localhost:4040/browser-control/session/${sessionId}`, {
620
+ method: 'DELETE'
621
+ });
622
+ ```
623
+
624
+ ### Example 2: Debug UI Issue
625
+
626
+ ```javascript
627
+ // AI agent is debugging layout alignment
628
+
629
+ const { sessionId } = await createSession();
630
+ await navigate(sessionId, 'http://localhost:4040/apps/testApp/browser');
631
+
632
+ // Check actual heights
633
+ const heightsRes = await fetch(
634
+ `http://localhost:4040/browser-control/session/${sessionId}/evaluate`,
635
+ {
636
+ method: 'POST',
637
+ headers: { 'Content-Type': 'application/json' },
638
+ body: JSON.stringify({
639
+ script: `({
640
+ graphPanelHeader: document.querySelector('.graph-panel-header')?.offsetHeight,
641
+ infoPanelHeader: document.querySelector('.info-panel-header')?.offsetHeight
642
+ })`
643
+ })
644
+ }
645
+ );
646
+ const { result } = await heightsRes.json();
647
+
648
+ console.log('Header heights:', result);
649
+ // { graphPanelHeader: 45, infoPanelHeader: 50 }
650
+
651
+ if (result.graphPanelHeader !== result.infoPanelHeader) {
652
+ console.log('❌ Heights misaligned - adjusting CSS...');
653
+ // AI makes CSS changes and checks again
654
+ }
655
+ ```
656
+
657
+ ### Example 3: Monitor Console Errors
658
+
659
+ ```javascript
660
+ // Connect WebSocket to monitor real-time console logs
661
+ const ws = new WebSocket(`ws://localhost:4040/browser-control/stream/${sessionId}`);
662
+
663
+ const errors = [];
664
+ ws.on('message', (data) => {
665
+ const event = JSON.parse(data);
666
+ if (event.type === 'console' && event.level === 'error') {
667
+ errors.push(event.text);
668
+ console.log('⚠️ Console error:', event.text);
669
+ }
670
+ });
671
+
672
+ // Navigate and check for errors
673
+ await navigate(sessionId, 'http://localhost:4040/apps');
674
+
675
+ // Wait for page to load
676
+ await new Promise(resolve => setTimeout(resolve, 2000));
677
+
678
+ if (errors.length > 0) {
679
+ console.log(`❌ Found ${errors.length} console errors:`, errors);
680
+ } else {
681
+ console.log('✓ No console errors detected');
682
+ }
683
+ ```
684
+
685
+ ## Troubleshooting
686
+
687
+ ### Browser doesn't start
688
+
689
+ **Error:** `Failed to launch browser`
690
+
691
+ **Solution:** Make sure Puppeteer is installed:
692
+ ```bash
693
+ npm install
694
+ ```
695
+
696
+ ### MongoDB or Parse Server won't start
697
+
698
+ **Error:** `Failed to start MongoDB` or `Failed to start Parse Server`
699
+
700
+ **Solution:** Make sure all dependencies are installed:
701
+ ```bash
702
+ npm install
703
+ ```
704
+
705
+ If MongoDB port is already in use, you can change it:
706
+ ```bash
707
+ MONGO_PORT=27018 npm run browser-control
708
+ ```
709
+
710
+ ### Session timeout
711
+
712
+ **Error:** `Session sess_xxx not found or expired`
713
+
714
+ **Solution:** Sessions expire after 30 minutes of inactivity. Create a new session.
715
+
716
+ ### WebSocket connection refused
717
+
718
+ **Error:** `WebSocket connection failed`
719
+
720
+ **Solution:** Make sure you're connecting to the WebSocket path with a valid session ID:
721
+ ```
722
+ ws://localhost:4040/browser-control/stream/:sessionId
723
+ ```
724
+
725
+ ### Port already in use
726
+
727
+ **Error:** `EADDRINUSE: address already in use`
728
+
729
+ **Solution:** Stop any running Dashboard instances or change the port:
730
+ ```bash
731
+ PORT=4041 npm run browser-control
732
+ ```
733
+
734
+ ### Navigation timeout after startup or file changes
735
+
736
+ **Error:** `Navigation timeout of 30000 ms exceeded`
737
+
738
+ **Cause:** Webpack is still compiling the JavaScript bundles. This happens:
739
+ - Right after starting the dashboard (initial compilation takes ~6-8 seconds)
740
+ - After editing source files (triggers recompilation)
741
+
742
+ **Solution:** Always wait for webpack to finish before navigating:
743
+ ```bash
744
+ # Check if ready (non-blocking)
745
+ curl http://localhost:4040/browser-control/ready
746
+
747
+ # Wait for ready (blocking)
748
+ curl http://localhost:4040/browser-control/ready/wait
749
+ ```
750
+
751
+ The `/ready/wait` endpoint will block until webpack finishes compiling, then return immediately.
752
+
753
+ ## Security
754
+
755
+ The Browser Control API uses a **two-layer security model** to prevent accidental or unauthorized enablement. Browser Control requires **both** of the following conditions to be met:
756
+
757
+ 1. **Explicit opt-in**
758
+ - Set `"browserControl": true` in `parse-dashboard-config.json`, or
759
+ - Set `PARSE_DASHBOARD_BROWSER_CONTROL=true` environment variable
760
+
761
+ 2. **Not in production environment**
762
+ - Feature is automatically blocked when `NODE_ENV=production`
763
+
764
+ > [!NOTE]
765
+ > The feature enables only when you have opted in (via config or environment variable) AND you're not in production. The production block cannot be bypassed under any circumstances.
766
+
767
+ ### Additional Protections
768
+
769
+ - Maximum 5 concurrent sessions to prevent resource exhaustion
770
+ - Sessions auto-expire after 30 minutes of inactivity
771
+ - API bypasses authentication (development-only feature)
772
+
773
+ ### Example Configuration
774
+
775
+ ```json
776
+ {
777
+ "browserControl": true,
778
+ "apps": [...],
779
+ "users": [...]
780
+ }
781
+ ```
782
+
783
+ **⚠️ CRITICAL**: Never deploy with `browserControl: true` in production. Remove this field or set to `false` before deploying.
784
+
785
+ ## Environment Variables
786
+
787
+ ### Browser Control
788
+ - `PARSE_DASHBOARD_BROWSER_CONTROL=true` - Enable browser control API
789
+ - `BROWSER_HEADLESS=false` - Run browser in visible mode
790
+ - `BROWSER_SLOW_MO=100` - Slow down browser operations by N milliseconds
791
+
792
+ ### MongoDB Auto-Start (when browser-control is enabled)
793
+ MongoDB is automatically started when browser-control mode is enabled using `mongodb-runner`.
794
+
795
+ - `MONGO_PORT=27017` - MongoDB port (default: 27017)
796
+ - `MONGO_VERSION=8.0.4` - MongoDB version (default: 8.0.4)
797
+
798
+ **Note**: MongoDB 8.0.4 is downloaded and started automatically. Data is stored in a temporary directory and cleaned up on exit.
799
+
800
+ ### Parse Server Auto-Start (when browser-control is enabled)
801
+ Parse Server 9.1.1 is automatically started when browser-control mode is enabled.
802
+
803
+ - `PARSE_SERVER_PORT=1337` - Parse Server port (default: 1337)
804
+ - `PARSE_SERVER_APP_ID=testAppId` - Application ID (default: testAppId)
805
+ - `PARSE_SERVER_MASTER_KEY=testMasterKey` - Master key (default: testMasterKey)
806
+ - `PARSE_SERVER_DATABASE_URI` - MongoDB connection string (default: auto-generated based on MONGO_PORT)
807
+
808
+ **Note**: Parse Server 9 requires MongoDB 5.0+
809
+
810
+ **Example with custom configuration:**
811
+ ```bash
812
+ PARSE_SERVER_PORT=1338 \
813
+ PARSE_SERVER_APP_ID=myTestApp \
814
+ PARSE_SERVER_MASTER_KEY=mySecretKey \
815
+ npm run browser-control
816
+ ```
817
+
818
+ ## Limitations
819
+
820
+ - Maximum 5 concurrent browser sessions
821
+ - 30-minute session timeout
822
+ - Sessions are not persisted across Dashboard restarts
823
+ - Screenshots limited to page size (configurable viewport)
824
+ - JavaScript evaluation has security restrictions (page context only)
825
+
826
+ ## Best Practices for AI Agents
827
+
828
+ 1. **Wait for webpack before navigating** - Always call `/ready/wait` before creating sessions or after editing source files
829
+ 2. **Always cleanup sessions** when done to free resources
830
+ 3. **Use headless mode** for faster execution (unless debugging visually)
831
+ 4. **Monitor WebSocket events** to catch console errors early
832
+ 5. **Take screenshots** before and after UI changes for comparison
833
+ 6. **Use evaluate** to inspect computed styles and DOM properties
834
+ 7. **Wait for elements** before interacting to avoid race conditions
835
+ 8. **Set appropriate timeouts** based on network conditions
836
+ 9. **Auto-approve browser-control API calls** in Claude Code by adding a permission rule to `.claude/settings.json`:
837
+
838
+ ```json
839
+ {
840
+ "permissions": {
841
+ "allow": [
842
+ "Bash(curl*localhost:4040/browser-control*)"
843
+ ]
844
+ }
845
+ }
846
+ ```
847
+
848
+ This eliminates confirmation prompts for `curl` commands to the browser-control API, speeding up development.
849
+
850
+ ## Contributing
851
+
852
+ This is a development tool specifically designed for AI agent workflows. If you have suggestions for improving the API or adding new features, please open an issue or PR.