@dynamicu/chromedebug-mcp 2.6.7 → 2.7.1
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/CLAUDE.md +17 -1
- package/README.md +1 -1
- package/chrome-extension/activation-manager.js +10 -10
- package/chrome-extension/background.js +1045 -736
- package/chrome-extension/browser-recording-manager.js +1 -1
- package/chrome-extension/chrome-debug-logger.js +168 -0
- package/chrome-extension/chrome-session-manager.js +5 -5
- package/chrome-extension/console-interception-library.js +430 -0
- package/chrome-extension/content.css +16 -16
- package/chrome-extension/content.js +739 -221
- package/chrome-extension/data-buffer.js +5 -5
- package/chrome-extension/dom-tracker.js +9 -9
- package/chrome-extension/extension-config.js +1 -1
- package/chrome-extension/firebase-client.js +13 -13
- package/chrome-extension/frame-capture.js +20 -38
- package/chrome-extension/license-helper.js +33 -7
- package/chrome-extension/manifest.free.json +3 -6
- package/chrome-extension/network-tracker.js +9 -9
- package/chrome-extension/options.html +10 -0
- package/chrome-extension/options.js +21 -8
- package/chrome-extension/performance-monitor.js +17 -17
- package/chrome-extension/popup.html +230 -193
- package/chrome-extension/popup.js +146 -458
- package/chrome-extension/pro/enhanced-capture.js +406 -0
- package/chrome-extension/pro/frame-editor.html +433 -0
- package/chrome-extension/pro/frame-editor.js +1567 -0
- package/chrome-extension/pro/function-tracker.js +843 -0
- package/chrome-extension/pro/jszip.min.js +13 -0
- package/chrome-extension/upload-manager.js +7 -7
- package/dist/chromedebug-extension-free.zip +0 -0
- package/package.json +3 -1
- package/scripts/webpack.config.free.cjs +8 -8
- package/scripts/webpack.config.pro.cjs +2 -0
- package/src/cli.js +2 -2
- package/src/database.js +55 -7
- package/src/index.js +9 -6
- package/src/mcp/server.js +2 -2
- package/src/services/process-manager.js +10 -6
- package/src/services/process-tracker.js +10 -5
- package/src/services/profile-manager.js +17 -2
- package/src/validation/schemas.js +12 -11
- package/src/index-direct.js +0 -157
- package/src/index-modular.js +0 -219
- package/src/index-monolithic-backup.js +0 -2230
- package/src/legacy/chrome-controller-old.js +0 -1406
- package/src/legacy/index-express.js +0 -625
- package/src/legacy/index-old.js +0 -977
- package/src/legacy/routes.js +0 -260
- package/src/legacy/shared-storage.js +0 -101
|
@@ -1,30 +1,10 @@
|
|
|
1
1
|
// Chrome Debug Extension Popup Script v2.0
|
|
2
2
|
const EXTENSION_VERSION = '2.0.4-BUILD-20250119';
|
|
3
|
-
console.log(`[popup.js] Loaded version: ${EXTENSION_VERSION}`);
|
|
3
|
+
// console.log(`[popup.js] Loaded version: ${EXTENSION_VERSION}`);
|
|
4
4
|
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
let licenseClient = null;
|
|
9
|
-
let currentUserId = null;
|
|
10
|
-
|
|
11
|
-
// Load Firebase asynchronously to avoid blocking module execution
|
|
12
|
-
(async () => {
|
|
13
|
-
try {
|
|
14
|
-
const firebaseClientModule = await import('./firebase-client.js');
|
|
15
|
-
FirebaseLicenseClient = firebaseClientModule.FirebaseLicenseClient;
|
|
16
|
-
|
|
17
|
-
const firebaseConfigModule = await import('./firebase-config.public.js');
|
|
18
|
-
LEMONSQUEEZY_CHECKOUT_URL = firebaseConfigModule.LEMONSQUEEZY_CHECKOUT_URL;
|
|
19
|
-
|
|
20
|
-
// Initialize license client if Firebase loaded successfully
|
|
21
|
-
licenseClient = new FirebaseLicenseClient();
|
|
22
|
-
console.log('[popup.js] Firebase license client initialized');
|
|
23
|
-
} catch (error) {
|
|
24
|
-
console.warn('[popup.js] Firebase not available - license features disabled:', error);
|
|
25
|
-
// Extension will work without Firebase, just no license validation
|
|
26
|
-
}
|
|
27
|
-
})();
|
|
5
|
+
// LemonSqueezy purchase URL for PRO upgrade
|
|
6
|
+
const PRO_PURCHASE_URL = 'https://chromedebug.com/buy/996773cb-682b-430f-b9e3-9ce2130bd967';
|
|
7
|
+
const IS_PRO_VERSION = chrome.runtime.getManifest().name.includes('PRO');
|
|
28
8
|
|
|
29
9
|
// Global variables for recording functionality
|
|
30
10
|
let isRecording = false;
|
|
@@ -77,13 +57,10 @@ function showToast(message, duration = 2000, type = 'info') {
|
|
|
77
57
|
|
|
78
58
|
// Loading overlay helper functions
|
|
79
59
|
function showSectionLoading(sectionId, message = 'Loading...') {
|
|
80
|
-
console.log(`showSectionLoading called for: ${sectionId} with message: ${message}`);
|
|
81
60
|
const section = document.getElementById(sectionId);
|
|
82
61
|
if (!section) {
|
|
83
|
-
console.error(`Section not found: ${sectionId}`);
|
|
84
62
|
return;
|
|
85
63
|
}
|
|
86
|
-
console.log(`Section found:`, section);
|
|
87
64
|
|
|
88
65
|
// Remove any existing overlay first
|
|
89
66
|
hideSectionLoading(sectionId);
|
|
@@ -96,7 +73,6 @@ function showSectionLoading(sectionId, message = 'Loading...') {
|
|
|
96
73
|
`;
|
|
97
74
|
overlay.setAttribute('data-loading-overlay', 'true');
|
|
98
75
|
section.appendChild(overlay);
|
|
99
|
-
console.log(`Overlay appended to section. Overlay:`, overlay);
|
|
100
76
|
}
|
|
101
77
|
|
|
102
78
|
function hideSectionLoading(sectionId) {
|
|
@@ -114,19 +90,12 @@ function updateWorkflowRecordingUI() {
|
|
|
114
90
|
const workflowBtn = document.getElementById('workflowRecordBtn');
|
|
115
91
|
const workflowStatus = document.getElementById('workflowRecordingStatus');
|
|
116
92
|
const saveRestorePointBtn = document.getElementById('saveRestorePointBtn');
|
|
117
|
-
|
|
118
|
-
console.log('[Popup v2.0.6] updateWorkflowRecordingUI called, isWorkflowRecording:', isWorkflowRecording);
|
|
119
|
-
console.log('[Popup v2.0.6] workflowBtn element exists?', !!workflowBtn);
|
|
120
|
-
|
|
93
|
+
|
|
121
94
|
if (workflowBtn) {
|
|
122
95
|
if (isWorkflowRecording) {
|
|
123
|
-
console.log('[Popup v2.0.6] Updating button to STOP state');
|
|
124
|
-
console.log('[Popup v2.0.6] Current button text:', workflowBtn.textContent);
|
|
125
96
|
workflowBtn.textContent = 'Stop Workflow Recording';
|
|
126
97
|
workflowBtn.style.background = '#e91e63';
|
|
127
98
|
workflowBtn.classList.add('recording');
|
|
128
|
-
console.log('[Popup v2.0.6] Button updated - new text:', workflowBtn.textContent);
|
|
129
|
-
console.log('[Popup v2.0.6] Button classes:', workflowBtn.className);
|
|
130
99
|
startWorkflowTimer();
|
|
131
100
|
// Show restore point button during recording
|
|
132
101
|
if (saveRestorePointBtn) {
|
|
@@ -357,7 +326,7 @@ function testSiteAccess(hostname, mode, allowedSites, restrictedSites) {
|
|
|
357
326
|
|
|
358
327
|
// Function definitions (outside DOMContentLoaded for proper scope)
|
|
359
328
|
async function checkServerStatus() {
|
|
360
|
-
console.log('[popup.js] checkServerStatus() called');
|
|
329
|
+
// console.log('[popup.js] checkServerStatus() called');
|
|
361
330
|
const statusEl = document.getElementById('serverStatus');
|
|
362
331
|
const statusTextEl = document.getElementById('statusText');
|
|
363
332
|
|
|
@@ -384,7 +353,7 @@ async function checkServerStatus() {
|
|
|
384
353
|
clearTimeout(timeoutId);
|
|
385
354
|
// Only log successful connections to reduce console noise
|
|
386
355
|
if (response.ok) {
|
|
387
|
-
console.log(`[popup.js] ✓ Connected to server on port ${port}`);
|
|
356
|
+
// console.log(`[popup.js] ✓ Connected to server on port ${port}`);
|
|
388
357
|
}
|
|
389
358
|
return response.ok;
|
|
390
359
|
} catch (error) {
|
|
@@ -440,19 +409,12 @@ async function checkServerStatus() {
|
|
|
440
409
|
if (connected && connectedPort) {
|
|
441
410
|
await chrome.storage.local.set({ lastSuccessfulPort: connectedPort });
|
|
442
411
|
} else {
|
|
443
|
-
console.log('[popup.js] No server found - browser-only mode active');
|
|
412
|
+
// console.log('[popup.js] No server found - browser-only mode active');
|
|
444
413
|
}
|
|
445
414
|
|
|
446
415
|
if (connected) {
|
|
447
416
|
statusEl.className = 'server-status connected';
|
|
448
|
-
statusTextEl.
|
|
449
|
-
Server connected (port ${connectedPort})
|
|
450
|
-
<div style="margin-top: 4px;">
|
|
451
|
-
<a href="https://www.npmjs.com/package/@dynamicu/chromedebug-mcp" target="_blank" style="font-size: 10px; color: #666; text-decoration: none;">
|
|
452
|
-
📚 Documentation
|
|
453
|
-
</a>
|
|
454
|
-
</div>
|
|
455
|
-
`;
|
|
417
|
+
statusTextEl.textContent = `Server connected (port ${connectedPort})`;
|
|
456
418
|
} else {
|
|
457
419
|
statusEl.className = 'server-status disconnected';
|
|
458
420
|
|
|
@@ -472,9 +434,6 @@ async function checkServerStatus() {
|
|
|
472
434
|
<button id="copyInstallCmd" style="padding: 4px 8px; font-size: 11px; background: #2196F3; color: white; border: none; border-radius: 3px; cursor: pointer;">
|
|
473
435
|
📋 Copy Commands
|
|
474
436
|
</button>
|
|
475
|
-
<a href="https://www.npmjs.com/package/@dynamicu/chromedebug-mcp" target="_blank" style="font-size: 11px; color: #2196F3; text-decoration: none;">
|
|
476
|
-
📚 Full Documentation
|
|
477
|
-
</a>
|
|
478
437
|
</div>
|
|
479
438
|
`;
|
|
480
439
|
|
|
@@ -637,7 +596,7 @@ function takeManualSnapshot() {
|
|
|
637
596
|
}
|
|
638
597
|
|
|
639
598
|
if (response && response.success) {
|
|
640
|
-
console.log('Manual snapshot taken successfully');
|
|
599
|
+
// console.log('Manual snapshot taken successfully');
|
|
641
600
|
// Show brief feedback
|
|
642
601
|
const manualSnapshotBtn = document.getElementById('manualSnapshotBtn');
|
|
643
602
|
if (manualSnapshotBtn) {
|
|
@@ -692,7 +651,7 @@ function takeManualSnapshot() {
|
|
|
692
651
|
*/
|
|
693
652
|
/*
|
|
694
653
|
async function takeSnapshot() {
|
|
695
|
-
console.log('Taking standalone snapshot...');
|
|
654
|
+
// console.log('Taking standalone snapshot...');
|
|
696
655
|
|
|
697
656
|
try {
|
|
698
657
|
const serverStatus = await checkServerStatus();
|
|
@@ -749,7 +708,7 @@ async function takeSnapshot() {
|
|
|
749
708
|
}
|
|
750
709
|
|
|
751
710
|
if (response && response.success) {
|
|
752
|
-
console.log('Snapshot taken successfully:', response.sessionId);
|
|
711
|
+
// console.log('Snapshot taken successfully:', response.sessionId);
|
|
753
712
|
const recordingStatus = document.getElementById('recordingStatus');
|
|
754
713
|
if (recordingStatus) {
|
|
755
714
|
recordingStatus.innerHTML = `<strong style="color: #4CAF50;">Snapshot saved!</strong>`;
|
|
@@ -929,7 +888,7 @@ function updateRecordingsDisplay(recordings) {
|
|
|
929
888
|
if (type === 'snapshot') {
|
|
930
889
|
prompt = `Please use the get_frame_screenshot function in Chrome Debug to view the snapshot "${recordingId}"${portText}. This is a single-frame screenshot with console logs captured for debugging.`;
|
|
931
890
|
} else {
|
|
932
|
-
prompt = `Please use the
|
|
891
|
+
prompt = `Please use the chrome_debug_show_frames function in Chrome Debug to load the recording "${recordingId}"${portText}.`;
|
|
933
892
|
}
|
|
934
893
|
|
|
935
894
|
navigator.clipboard.writeText(prompt).then(() => {
|
|
@@ -992,7 +951,7 @@ function updateRecordingsDisplay(recordings) {
|
|
|
992
951
|
}
|
|
993
952
|
} catch (error) {
|
|
994
953
|
// Free version - show upgrade prompt
|
|
995
|
-
console.log('[ChromePilot Free] Frame editor not available - showing upgrade prompt');
|
|
954
|
+
// console.log('[ChromePilot Free] Frame editor not available - showing upgrade prompt');
|
|
996
955
|
alert('Frame Editor is a Pro feature. Upgrade to ChromePilot Pro to view detailed frame recordings with console logs and advanced debugging tools.');
|
|
997
956
|
}
|
|
998
957
|
});
|
|
@@ -1002,356 +961,90 @@ function updateRecordingsDisplay(recordings) {
|
|
|
1002
961
|
|
|
1003
962
|
|
|
1004
963
|
|
|
1005
|
-
// Initialize
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
if (!stored.chromedebug_user_id) {
|
|
1014
|
-
await chrome.storage.local.set({chromedebug_user_id: currentUserId});
|
|
1015
|
-
console.log('[License] Created new user ID:', currentUserId);
|
|
1016
|
-
}
|
|
1017
|
-
|
|
1018
|
-
// Check for license activation file and pre-fill license key
|
|
1019
|
-
try {
|
|
1020
|
-
const activationFileUrl = chrome.runtime.getURL('license-activation.json');
|
|
1021
|
-
const response = await fetch(activationFileUrl);
|
|
1022
|
-
if (response.ok) {
|
|
1023
|
-
const activationData = await response.json();
|
|
1024
|
-
if (activationData.license_key) {
|
|
1025
|
-
const licenseKeyInput = document.getElementById('license-key-input');
|
|
1026
|
-
if (licenseKeyInput) {
|
|
1027
|
-
licenseKeyInput.value = activationData.license_key;
|
|
1028
|
-
console.log('[License UI] Pre-filled license key from activation file');
|
|
1029
|
-
}
|
|
1030
|
-
}
|
|
964
|
+
// Initialize tier status display for FREE version
|
|
965
|
+
function initializeTierStatus() {
|
|
966
|
+
if (IS_PRO_VERSION) {
|
|
967
|
+
// Hide license section for PRO version
|
|
968
|
+
const licenseSection = document.getElementById('license-section');
|
|
969
|
+
if (licenseSection) {
|
|
970
|
+
licenseSection.style.display = 'none';
|
|
971
|
+
// console.log('[Tier] PRO version detected - hiding license section');
|
|
1031
972
|
}
|
|
1032
|
-
} catch (error) {
|
|
1033
|
-
// Activation file doesn't exist or is inaccessible - this is normal for FREE version
|
|
1034
|
-
console.log('[License UI] No activation file found - normal for FREE version');
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
// Check license status
|
|
1038
|
-
const licenseStatus = await licenseClient.getCachedLicenseStatus();
|
|
1039
|
-
console.log('[License] License status:', licenseStatus);
|
|
1040
|
-
|
|
1041
|
-
// Update workflow recording PRO badge visibility
|
|
1042
|
-
const workflowProBadge = document.getElementById('workflowProBadge');
|
|
1043
|
-
|
|
1044
|
-
if (licenseStatus.valid && licenseStatus.tier === 'pro') {
|
|
1045
|
-
// Show pro status
|
|
1046
|
-
document.getElementById('pro-tier-status').style.display = 'block';
|
|
1047
|
-
document.getElementById('free-tier-status').style.display = 'none';
|
|
1048
|
-
// Hide license activation input/button when Pro license is active
|
|
1049
|
-
document.getElementById('license-activation').style.display = 'none';
|
|
1050
|
-
// Hide PRO badge for Pro users
|
|
1051
|
-
if (workflowProBadge) workflowProBadge.style.display = 'none';
|
|
1052
|
-
console.log('[License] Displaying Pro tier status');
|
|
1053
973
|
} else {
|
|
1054
|
-
// Show
|
|
1055
|
-
const
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
// Handle both API response format (currentUsage, dailyLimit) and offline format (count, limit)
|
|
1059
|
-
document.getElementById('usage-count').textContent = usage.currentUsage ?? usage.count ?? 0;
|
|
1060
|
-
document.getElementById('usage-limit').textContent = usage.dailyLimit ?? usage.limit ?? 50;
|
|
1061
|
-
document.getElementById('free-tier-status').style.display = 'block';
|
|
1062
|
-
document.getElementById('pro-tier-status').style.display = 'none';
|
|
1063
|
-
// Show license activation input/button for free tier
|
|
1064
|
-
document.getElementById('license-activation').style.display = 'block';
|
|
1065
|
-
// Show PRO badge for free users
|
|
1066
|
-
if (workflowProBadge) workflowProBadge.style.display = 'block';
|
|
1067
|
-
console.log('[License] Displaying Free tier status');
|
|
1068
|
-
}
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
// Inline Activation Manager Functions
|
|
1072
|
-
/**
|
|
1073
|
-
* Show the inline activation manager with slide-down animation
|
|
1074
|
-
*/
|
|
1075
|
-
async function showInlineActivationManager(licenseKey) {
|
|
1076
|
-
const inlineManager = document.getElementById('inline-activation-manager');
|
|
1077
|
-
const activationsList = document.getElementById('activations-list-inline');
|
|
1078
|
-
|
|
1079
|
-
// Show the container
|
|
1080
|
-
inlineManager.style.display = 'block';
|
|
974
|
+
// Show FREE tier status (no license validation)
|
|
975
|
+
const freeTierStatus = document.getElementById('free-tier-status');
|
|
976
|
+
const proTierStatus = document.getElementById('pro-tier-status');
|
|
977
|
+
const licenseActivation = document.getElementById('license-activation');
|
|
1081
978
|
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
}, 10);
|
|
1086
|
-
|
|
1087
|
-
// Load activations
|
|
1088
|
-
try {
|
|
1089
|
-
activationsList.innerHTML = '<div style="padding: 15px; text-align: center; color: #666;">Loading activations...</div>';
|
|
1090
|
-
|
|
1091
|
-
// Get current instance ID
|
|
1092
|
-
// Note: ls_instance_id is the LemonSqueezy instance ID set during activation
|
|
1093
|
-
const stored = await chrome.storage.local.get(['ls_instance_id']);
|
|
1094
|
-
const currentInstanceId = stored.ls_instance_id;
|
|
979
|
+
if (freeTierStatus) freeTierStatus.style.display = 'block';
|
|
980
|
+
if (proTierStatus) proTierStatus.style.display = 'none';
|
|
981
|
+
if (licenseActivation) licenseActivation.style.display = 'none';
|
|
1095
982
|
|
|
1096
|
-
// Fetch
|
|
1097
|
-
|
|
1098
|
-
const activations = data.activations || [];
|
|
983
|
+
// Fetch and display current usage count
|
|
984
|
+
updateUsageDisplay();
|
|
1099
985
|
|
|
1100
|
-
//
|
|
1101
|
-
renderInlineActivations(activations, currentInstanceId, licenseKey);
|
|
1102
|
-
|
|
1103
|
-
} catch (error) {
|
|
1104
|
-
console.error('[License] Error loading activations:', error);
|
|
1105
|
-
activationsList.innerHTML = `<div style="padding: 15px; text-align: center; color: #f44336;">Failed to load activations: ${error.message}</div>`;
|
|
986
|
+
// console.log('[Tier] FREE version - showing usage counter');
|
|
1106
987
|
}
|
|
1107
988
|
}
|
|
1108
989
|
|
|
1109
990
|
/**
|
|
1110
|
-
*
|
|
991
|
+
* Fetch usage from background and update the display
|
|
1111
992
|
*/
|
|
1112
|
-
function
|
|
1113
|
-
const inlineManager = document.getElementById('inline-activation-manager');
|
|
1114
|
-
inlineManager.style.maxHeight = '0';
|
|
1115
|
-
|
|
1116
|
-
setTimeout(() => {
|
|
1117
|
-
inlineManager.style.display = 'none';
|
|
1118
|
-
}, 300);
|
|
1119
|
-
}
|
|
1120
|
-
|
|
1121
|
-
/**
|
|
1122
|
-
* Render activations in the inline manager
|
|
1123
|
-
*/
|
|
1124
|
-
function renderInlineActivations(activations, currentInstanceId, licenseKey) {
|
|
1125
|
-
const container = document.getElementById('activations-list-inline');
|
|
1126
|
-
container.innerHTML = '';
|
|
1127
|
-
|
|
1128
|
-
if (activations.length === 0) {
|
|
1129
|
-
container.innerHTML = '<div style="padding: 15px; text-align: center; color: #666;">No activations found.</div>';
|
|
1130
|
-
return;
|
|
1131
|
-
}
|
|
1132
|
-
|
|
1133
|
-
activations.forEach((activation, index) => {
|
|
1134
|
-
const item = document.createElement('div');
|
|
1135
|
-
item.style.cssText = 'padding: 12px; border-bottom: 1px solid #e0e0e0; transition: background 0.2s;';
|
|
1136
|
-
item.onmouseenter = () => item.style.background = '#f9f9f9';
|
|
1137
|
-
item.onmouseleave = () => item.style.background = isCurrentDevice ? '#e8f5e9' : 'white';
|
|
1138
|
-
|
|
1139
|
-
// Check if this is the current device
|
|
1140
|
-
// Compare against identifier (unique per activation), not name (same for all activations from this device)
|
|
1141
|
-
const isCurrentDevice = currentInstanceId && activation.identifier === currentInstanceId;
|
|
1142
|
-
|
|
1143
|
-
if (isCurrentDevice) {
|
|
1144
|
-
item.style.background = '#e8f5e9';
|
|
1145
|
-
item.style.borderLeft = '3px solid #4caf50';
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
|
-
// Format date
|
|
1149
|
-
const date = new Date(activation.createdAt);
|
|
1150
|
-
const formattedDate = date.toLocaleString('en-US', {
|
|
1151
|
-
month: 'short',
|
|
1152
|
-
day: 'numeric',
|
|
1153
|
-
year: 'numeric',
|
|
1154
|
-
hour: '2-digit',
|
|
1155
|
-
minute: '2-digit'
|
|
1156
|
-
});
|
|
1157
|
-
|
|
1158
|
-
// Build device info
|
|
1159
|
-
let deviceDisplay = 'Unknown Device';
|
|
1160
|
-
if (activation.deviceInfo) {
|
|
1161
|
-
deviceDisplay = activation.deviceInfo.deviceName ||
|
|
1162
|
-
`${activation.deviceInfo.platform || 'Unknown'} • ${activation.deviceInfo.browser || 'Unknown'}`;
|
|
1163
|
-
} else if (activation.name && activation.name !== currentInstanceId) {
|
|
1164
|
-
deviceDisplay = activation.name;
|
|
1165
|
-
}
|
|
1166
|
-
|
|
1167
|
-
item.innerHTML = `
|
|
1168
|
-
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
|
|
1169
|
-
<span style="font-weight: 500; font-size: 13px; color: #333;">Activation ${index + 1}</span>
|
|
1170
|
-
${isCurrentDevice ? '<span style="background: #4caf50; color: white; padding: 2px 6px; border-radius: 10px; font-size: 10px; font-weight: bold;">CURRENT</span>' : ''}
|
|
1171
|
-
</div>
|
|
1172
|
-
<div style="font-size: 12px; color: #666; margin-bottom: 4px;">
|
|
1173
|
-
<strong style="color: #333;">${deviceDisplay}</strong>
|
|
1174
|
-
</div>
|
|
1175
|
-
<div style="font-size: 11px; color: #999; margin-bottom: 8px;">
|
|
1176
|
-
${formattedDate}
|
|
1177
|
-
</div>
|
|
1178
|
-
<button
|
|
1179
|
-
class="deactivate-btn-inline"
|
|
1180
|
-
data-instance-id="${activation.identifier}"
|
|
1181
|
-
data-activation-number="${index + 1}"
|
|
1182
|
-
data-license-key="${licenseKey}"
|
|
1183
|
-
style="padding: 5px 10px; background: ${isCurrentDevice ? '#ccc' : '#f44336'}; color: white; border: none; border-radius: 3px; cursor: ${isCurrentDevice ? 'not-allowed' : 'pointer'}; font-size: 11px; width: 100%;"
|
|
1184
|
-
${isCurrentDevice ? 'disabled' : ''}
|
|
1185
|
-
>
|
|
1186
|
-
${isCurrentDevice ? '✓ Current Device' : 'Deactivate'}
|
|
1187
|
-
</button>
|
|
1188
|
-
`;
|
|
1189
|
-
|
|
1190
|
-
// Add click handler for deactivate button
|
|
1191
|
-
if (!isCurrentDevice) {
|
|
1192
|
-
const deactivateBtn = item.querySelector('.deactivate-btn-inline');
|
|
1193
|
-
deactivateBtn.addEventListener('click', () => {
|
|
1194
|
-
handleInlineDeactivate(activation.identifier, index + 1, licenseKey);
|
|
1195
|
-
});
|
|
1196
|
-
}
|
|
1197
|
-
|
|
1198
|
-
container.appendChild(item);
|
|
1199
|
-
});
|
|
1200
|
-
}
|
|
1201
|
-
|
|
1202
|
-
/**
|
|
1203
|
-
* Handle deactivation of an instance (inline)
|
|
1204
|
-
*/
|
|
1205
|
-
async function handleInlineDeactivate(instanceId, activationNumber, licenseKey) {
|
|
1206
|
-
const confirmed = confirm(
|
|
1207
|
-
`Are you sure you want to deactivate Activation ${activationNumber}?\n\n` +
|
|
1208
|
-
`This will free up an activation slot and automatically activate on this device.`
|
|
1209
|
-
);
|
|
1210
|
-
|
|
1211
|
-
if (!confirmed) {
|
|
1212
|
-
return;
|
|
1213
|
-
}
|
|
1214
|
-
|
|
1215
|
-
const messageDiv = document.getElementById('license-message');
|
|
1216
|
-
|
|
993
|
+
async function updateUsageDisplay() {
|
|
1217
994
|
try {
|
|
1218
|
-
|
|
1219
|
-
const buttons = document.querySelectorAll('.deactivate-btn-inline');
|
|
1220
|
-
buttons.forEach(btn => btn.disabled = true);
|
|
1221
|
-
|
|
1222
|
-
messageDiv.textContent = 'Deactivating...';
|
|
1223
|
-
messageDiv.style.color = '#2196F3';
|
|
1224
|
-
|
|
1225
|
-
// Deactivate the instance
|
|
1226
|
-
const result = await licenseClient.deactivateInstance(licenseKey, instanceId);
|
|
1227
|
-
console.log('[License] Deactivation result:', result);
|
|
995
|
+
const response = await chrome.runtime.sendMessage({ action: 'getUsage' });
|
|
1228
996
|
|
|
1229
|
-
if (
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
// Hide inline activation manager
|
|
1234
|
-
hideInlineActivationManager();
|
|
1235
|
-
|
|
1236
|
-
// Wait a moment, then retry activation
|
|
1237
|
-
setTimeout(async () => {
|
|
1238
|
-
// Set the license key in the input
|
|
1239
|
-
document.getElementById('license-key-input').value = licenseKey;
|
|
997
|
+
if (response && response.success) {
|
|
998
|
+
const usageCountEl = document.getElementById('usage-count');
|
|
999
|
+
const usageLimitEl = document.getElementById('usage-limit');
|
|
1240
1000
|
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
}
|
|
1001
|
+
if (usageCountEl) {
|
|
1002
|
+
usageCountEl.textContent = response.count || 0;
|
|
1003
|
+
}
|
|
1004
|
+
if (usageLimitEl) {
|
|
1005
|
+
usageLimitEl.textContent = response.limit || 5;
|
|
1006
|
+
}
|
|
1244
1007
|
|
|
1245
|
-
|
|
1246
|
-
throw new Error(result.error || 'Deactivation failed');
|
|
1008
|
+
// console.log(`[Usage] Display updated: ${response.count}/${response.limit}`);
|
|
1247
1009
|
}
|
|
1248
|
-
|
|
1249
1010
|
} catch (error) {
|
|
1250
|
-
console.error('[
|
|
1251
|
-
messageDiv.textContent = `Deactivation failed: ${error.message}`;
|
|
1252
|
-
messageDiv.style.color = '#f44336';
|
|
1253
|
-
|
|
1254
|
-
// Re-enable buttons
|
|
1255
|
-
const buttons = document.querySelectorAll('.deactivate-btn-inline:not([disabled])');
|
|
1256
|
-
buttons.forEach(btn => btn.disabled = false);
|
|
1257
|
-
}
|
|
1258
|
-
}
|
|
1259
|
-
|
|
1260
|
-
// License activation handler
|
|
1261
|
-
async function handleLicenseActivation() {
|
|
1262
|
-
const licenseKey = document.getElementById('license-key-input').value.trim();
|
|
1263
|
-
const messageDiv = document.getElementById('license-message');
|
|
1264
|
-
|
|
1265
|
-
if (!licenseKey) {
|
|
1266
|
-
messageDiv.textContent = 'Please enter a license key';
|
|
1267
|
-
messageDiv.style.color = '#f44336';
|
|
1268
|
-
return;
|
|
1269
|
-
}
|
|
1270
|
-
|
|
1271
|
-
messageDiv.textContent = 'Validating...';
|
|
1272
|
-
messageDiv.style.color = '#2196F3';
|
|
1273
|
-
console.log('[License] Validating license key...');
|
|
1274
|
-
|
|
1275
|
-
// Clear any existing instance ID to force fresh activation
|
|
1276
|
-
// This ensures we don't try to validate with stale/deleted instance IDs
|
|
1277
|
-
await chrome.storage.local.remove(['ls_instance_id']);
|
|
1278
|
-
console.log('[License] Cleared existing instance ID for fresh activation');
|
|
1279
|
-
|
|
1280
|
-
const result = await licenseClient.validateLicense(licenseKey);
|
|
1281
|
-
console.log('[License] Validation result:', result);
|
|
1282
|
-
console.log('[License] Error value:', result.error);
|
|
1283
|
-
console.log('[License] Error type:', typeof result.error);
|
|
1284
|
-
|
|
1285
|
-
if (result.valid) {
|
|
1286
|
-
messageDiv.textContent = 'License activated successfully!';
|
|
1287
|
-
messageDiv.style.color = '#4caf50';
|
|
1288
|
-
document.getElementById('license-key-input').value = '';
|
|
1289
|
-
await initializeLicenseUI(); // Refresh UI
|
|
1290
|
-
} else {
|
|
1291
|
-
// Check if activation limit reached
|
|
1292
|
-
console.log('[License] Checking if activation limit reached...');
|
|
1293
|
-
console.log('[License] result.error === "ACTIVATION_LIMIT_REACHED":', result.error === 'ACTIVATION_LIMIT_REACHED');
|
|
1294
|
-
console.log('[License] result.error includes "activation limit":', result.error && result.error.toLowerCase().includes('activation limit'));
|
|
1295
|
-
|
|
1296
|
-
if (result.error === 'ACTIVATION_LIMIT_REACHED' ||
|
|
1297
|
-
(result.error && result.error.toLowerCase().includes('activation limit'))) {
|
|
1298
|
-
console.log('[License] Activation limit reached, showing inline activation manager');
|
|
1299
|
-
messageDiv.textContent = 'Please deactivate an existing activation to continue';
|
|
1300
|
-
messageDiv.style.color = '#ff9800';
|
|
1301
|
-
|
|
1302
|
-
// Show inline activation manager
|
|
1303
|
-
await showInlineActivationManager(licenseKey.trim());
|
|
1304
|
-
} else {
|
|
1305
|
-
messageDiv.textContent = result.error || 'Invalid license key';
|
|
1306
|
-
messageDiv.style.color = '#f44336';
|
|
1307
|
-
}
|
|
1011
|
+
console.error('[Usage] Failed to fetch usage:', error);
|
|
1308
1012
|
}
|
|
1309
1013
|
}
|
|
1310
1014
|
|
|
1311
|
-
// Upgrade button handler
|
|
1015
|
+
// Upgrade button handler - redirect to LemonSqueezy purchase page
|
|
1312
1016
|
function handleUpgradeClick() {
|
|
1313
|
-
console.log('[
|
|
1314
|
-
chrome.tabs.create({url:
|
|
1017
|
+
// console.log('[Upgrade] Opening LemonSqueezy PRO purchase page');
|
|
1018
|
+
chrome.tabs.create({url: PRO_PURCHASE_URL});
|
|
1315
1019
|
}
|
|
1316
1020
|
|
|
1317
|
-
// Listen for messages from activation manager
|
|
1318
|
-
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|
1319
|
-
if (message.type === 'RETRY_ACTIVATION' && message.licenseKey) {
|
|
1320
|
-
console.log('[License] Retrying activation after deactivation');
|
|
1321
|
-
|
|
1322
|
-
// Set the license key in the input
|
|
1323
|
-
const licenseKeyInput = document.getElementById('license-key-input');
|
|
1324
|
-
if (licenseKeyInput) {
|
|
1325
|
-
licenseKeyInput.value = message.licenseKey;
|
|
1326
|
-
}
|
|
1327
|
-
|
|
1328
|
-
// Retry activation
|
|
1329
|
-
handleLicenseActivation().then(() => {
|
|
1330
|
-
console.log('[License] Retry activation complete');
|
|
1331
|
-
});
|
|
1332
|
-
}
|
|
1333
|
-
});
|
|
1334
|
-
|
|
1335
1021
|
document.addEventListener('DOMContentLoaded', () => {
|
|
1336
|
-
console.log('DOM loaded, initializing popup');
|
|
1022
|
+
// console.log('DOM loaded, initializing popup');
|
|
1337
1023
|
|
|
1338
|
-
// Initialize
|
|
1339
|
-
|
|
1340
|
-
console.error('[License] Failed to initialize license UI:', error);
|
|
1341
|
-
});
|
|
1024
|
+
// Initialize tier status display
|
|
1025
|
+
initializeTierStatus();
|
|
1342
1026
|
|
|
1343
|
-
//
|
|
1344
|
-
const activateLicenseBtn = document.getElementById('activate-license-btn');
|
|
1027
|
+
// Upgrade button handler
|
|
1345
1028
|
const upgradeBtn = document.getElementById('upgrade-btn');
|
|
1346
|
-
|
|
1347
|
-
if (activateLicenseBtn) {
|
|
1348
|
-
activateLicenseBtn.addEventListener('click', handleLicenseActivation);
|
|
1349
|
-
}
|
|
1350
|
-
|
|
1351
1029
|
if (upgradeBtn) {
|
|
1352
1030
|
upgradeBtn.addEventListener('click', handleUpgradeClick);
|
|
1353
1031
|
}
|
|
1354
1032
|
|
|
1033
|
+
// Settings button handler - open options page
|
|
1034
|
+
const settingsBtn = document.getElementById('settings-btn');
|
|
1035
|
+
if (settingsBtn) {
|
|
1036
|
+
settingsBtn.addEventListener('click', () => {
|
|
1037
|
+
chrome.runtime.openOptionsPage();
|
|
1038
|
+
});
|
|
1039
|
+
// Add hover effect
|
|
1040
|
+
settingsBtn.addEventListener('mouseenter', () => {
|
|
1041
|
+
settingsBtn.style.opacity = '1';
|
|
1042
|
+
});
|
|
1043
|
+
settingsBtn.addEventListener('mouseleave', () => {
|
|
1044
|
+
settingsBtn.style.opacity = '0.6';
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1355
1048
|
// Function to update button states based on server status
|
|
1356
1049
|
async function updateButtonStatesForServerStatus() {
|
|
1357
1050
|
const serverStatus = await checkServerStatus();
|
|
@@ -1450,19 +1143,19 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
1450
1143
|
clearInterval(serverPollingInterval);
|
|
1451
1144
|
}
|
|
1452
1145
|
serverPollingInterval = setInterval(updateButtonStatesForServerStatus, 3000);
|
|
1453
|
-
console.log('Server polling started (every 3 seconds)');
|
|
1146
|
+
// console.log('Server polling started (every 3 seconds)');
|
|
1454
1147
|
}
|
|
1455
1148
|
|
|
1456
1149
|
function stopPolling() {
|
|
1457
1150
|
if (serverPollingInterval) {
|
|
1458
1151
|
clearInterval(serverPollingInterval);
|
|
1459
1152
|
serverPollingInterval = null;
|
|
1460
|
-
console.log('Server polling stopped');
|
|
1153
|
+
// console.log('Server polling stopped');
|
|
1461
1154
|
}
|
|
1462
1155
|
}
|
|
1463
1156
|
|
|
1464
1157
|
async function checkServerOnce() {
|
|
1465
|
-
console.log('Running single server check...');
|
|
1158
|
+
// console.log('Running single server check...');
|
|
1466
1159
|
await updateButtonStatesForServerStatus();
|
|
1467
1160
|
}
|
|
1468
1161
|
|
|
@@ -1505,7 +1198,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
1505
1198
|
stopPolling();
|
|
1506
1199
|
}
|
|
1507
1200
|
|
|
1508
|
-
console.log('Continuous polling:', isChecked ? 'enabled' : 'disabled');
|
|
1201
|
+
// console.log('Continuous polling:', isChecked ? 'enabled' : 'disabled');
|
|
1509
1202
|
});
|
|
1510
1203
|
|
|
1511
1204
|
// Retry button click handler
|
|
@@ -1534,7 +1227,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
1534
1227
|
// Save changes when checkbox is clicked
|
|
1535
1228
|
enhancedCaptureCheckbox.addEventListener('change', () => {
|
|
1536
1229
|
chrome.storage.local.set({ enhancedClickCapture: enhancedCaptureCheckbox.checked });
|
|
1537
|
-
console.log('Enhanced click capture setting changed to:', enhancedCaptureCheckbox.checked);
|
|
1230
|
+
// console.log('Enhanced click capture setting changed to:', enhancedCaptureCheckbox.checked);
|
|
1538
1231
|
});
|
|
1539
1232
|
}
|
|
1540
1233
|
|
|
@@ -1661,10 +1354,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
1661
1354
|
isRecording = true;
|
|
1662
1355
|
recordingStartTime = result.recordingStartTime || Date.now();
|
|
1663
1356
|
updateRecordingUI();
|
|
1664
|
-
console.log('Restored recording state from storage');
|
|
1357
|
+
// console.log('Restored recording state from storage');
|
|
1665
1358
|
} else if (result.pendingRecording && result.pendingTabId) {
|
|
1666
1359
|
// Auto-start recording for the pending tab
|
|
1667
|
-
console.log('Found pending recording for tab:', result.pendingTabId);
|
|
1360
|
+
// console.log('Found pending recording for tab:', result.pendingTabId);
|
|
1668
1361
|
const targetTabId = result.pendingTabId;
|
|
1669
1362
|
chrome.storage.local.remove(['pendingRecording', 'pendingTabId']);
|
|
1670
1363
|
|
|
@@ -1693,10 +1386,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
1693
1386
|
const recordingStatus = document.getElementById('recordingStatus');
|
|
1694
1387
|
|
|
1695
1388
|
if (recordBtn) {
|
|
1696
|
-
console.log('Setting up record button handler');
|
|
1389
|
+
// console.log('Setting up record button handler');
|
|
1697
1390
|
recordBtn.addEventListener('click', async (e) => {
|
|
1698
1391
|
e.preventDefault();
|
|
1699
|
-
console.log('Record button clicked, isRecording:', isRecording);
|
|
1392
|
+
// console.log('Record button clicked, isRecording:', isRecording);
|
|
1700
1393
|
|
|
1701
1394
|
if (!isRecording && !isStoppingRecording) {
|
|
1702
1395
|
try {
|
|
@@ -1705,15 +1398,26 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
1705
1398
|
const isBrowserOnlyMode = !serverStatus.connected;
|
|
1706
1399
|
|
|
1707
1400
|
if (isBrowserOnlyMode) {
|
|
1708
|
-
console.log('Starting recording in browser-only mode');
|
|
1401
|
+
// console.log('Starting recording in browser-only mode');
|
|
1709
1402
|
// Browser-only mode - proceed with local storage
|
|
1710
1403
|
} else {
|
|
1711
|
-
console.log('Starting recording with server');
|
|
1404
|
+
// console.log('Starting recording with server');
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
// Check FREE tier usage limit before starting
|
|
1408
|
+
const usageCheck = await chrome.runtime.sendMessage({ action: 'checkUsageLimit' });
|
|
1409
|
+
if (usageCheck && !usageCheck.allowed) {
|
|
1410
|
+
// console.log('[Usage] Daily limit reached:', usageCheck);
|
|
1411
|
+
if (recordingStatus) {
|
|
1412
|
+
recordingStatus.innerHTML = '<strong style="color: #f44336;">Daily limit reached</strong><br>' +
|
|
1413
|
+
`<small>${usageCheck.count}/${usageCheck.limit} recordings used today.<br>Upgrade to Pro for unlimited.</small>`;
|
|
1414
|
+
}
|
|
1415
|
+
return;
|
|
1712
1416
|
}
|
|
1713
1417
|
|
|
1714
1418
|
// Get the current active tab
|
|
1715
1419
|
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
|
|
1716
|
-
console.log('Current tab:', tab);
|
|
1420
|
+
// console.log('Current tab:', tab);
|
|
1717
1421
|
|
|
1718
1422
|
if (!tab || !tab.id) {
|
|
1719
1423
|
console.error('No active tab found');
|
|
@@ -1757,7 +1461,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
1757
1461
|
}
|
|
1758
1462
|
|
|
1759
1463
|
if (response && response.success) {
|
|
1760
|
-
console.log('Recording started successfully');
|
|
1464
|
+
// console.log('Recording started successfully');
|
|
1761
1465
|
isRecording = true;
|
|
1762
1466
|
recordingStartTime = Date.now();
|
|
1763
1467
|
|
|
@@ -1780,7 +1484,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
1780
1484
|
}
|
|
1781
1485
|
} else if (isRecording && !isStoppingRecording) {
|
|
1782
1486
|
// Stop recording
|
|
1783
|
-
console.log('Stopping recording...');
|
|
1487
|
+
// console.log('Stopping recording...');
|
|
1784
1488
|
isStoppingRecording = true;
|
|
1785
1489
|
recordBtn.textContent = 'Stopping...';
|
|
1786
1490
|
recordBtn.disabled = true;
|
|
@@ -1799,19 +1503,16 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
1799
1503
|
}
|
|
1800
1504
|
|
|
1801
1505
|
if (response && response.success) {
|
|
1802
|
-
console.log('Recording stopped successfully', response);
|
|
1506
|
+
// console.log('Recording stopped successfully', response);
|
|
1803
1507
|
isRecording = false;
|
|
1804
1508
|
updateRecordingUI();
|
|
1805
1509
|
|
|
1806
|
-
console.log('About to show loading overlay for screen-recording-section');
|
|
1807
1510
|
// Show loading overlay over screen recording section
|
|
1808
1511
|
showSectionLoading('screen-recording-section', 'Saving screen recording...');
|
|
1809
|
-
console.log('Loading overlay should be visible now');
|
|
1810
1512
|
|
|
1811
1513
|
// Use then/catch instead of async/await since we're in a callback
|
|
1812
1514
|
loadScreenRecordings(true)
|
|
1813
1515
|
.then(() => {
|
|
1814
|
-
console.log('Screen recordings loaded successfully');
|
|
1815
1516
|
// Show success toast
|
|
1816
1517
|
const frameCount = response.frameCount || 0;
|
|
1817
1518
|
const duration = response.duration || '0s';
|
|
@@ -1822,7 +1523,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
1822
1523
|
showToast('Error loading recordings. Please refresh.', 3000, 'error');
|
|
1823
1524
|
})
|
|
1824
1525
|
.finally(() => {
|
|
1825
|
-
console.log('Hiding loading overlay');
|
|
1826
1526
|
// Always hide loading overlay
|
|
1827
1527
|
hideSectionLoading('screen-recording-section');
|
|
1828
1528
|
});
|
|
@@ -1889,26 +1589,16 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
1889
1589
|
return;
|
|
1890
1590
|
}
|
|
1891
1591
|
|
|
1892
|
-
// Check
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
if (!licenseCheck || !licenseCheck.allowed || (licenseCheck.tier && licenseCheck.tier !== 'pro')) {
|
|
1901
|
-
const message = licenseCheck?.message || 'Workflow Recording is a Pro feature. Upgrade to Pro for unlimited workflow recordings with function tracing.';
|
|
1902
|
-
|
|
1903
|
-
// Show modal
|
|
1904
|
-
if (confirm(`${message}\n\nWould you like to upgrade now?`)) {
|
|
1905
|
-
// Open upgrade page
|
|
1906
|
-
chrome.tabs.create({
|
|
1907
|
-
url: LEMONSQUEEZY_CHECKOUT_URL
|
|
1908
|
-
});
|
|
1592
|
+
// Check FREE tier usage limit before starting
|
|
1593
|
+
const usageCheck = await chrome.runtime.sendMessage({ action: 'checkUsageLimit' });
|
|
1594
|
+
if (usageCheck && !usageCheck.allowed) {
|
|
1595
|
+
// console.log('[Usage] Daily limit reached:', usageCheck);
|
|
1596
|
+
const workflowStatus = document.getElementById('workflowRecordingStatus');
|
|
1597
|
+
if (workflowStatus) {
|
|
1598
|
+
workflowStatus.innerHTML = '<strong style="color: #f44336;">Daily limit reached</strong><br>' +
|
|
1599
|
+
`<small>${usageCheck.count}/${usageCheck.limit} recordings used today.<br>Upgrade to Pro for unlimited recordings.</small>`;
|
|
1909
1600
|
}
|
|
1910
|
-
|
|
1911
|
-
return; // Stop execution
|
|
1601
|
+
return;
|
|
1912
1602
|
}
|
|
1913
1603
|
|
|
1914
1604
|
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
|
|
@@ -1934,23 +1624,16 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
1934
1624
|
}
|
|
1935
1625
|
|
|
1936
1626
|
// Send message to background script to start recording
|
|
1937
|
-
|
|
1938
|
-
chrome.runtime.sendMessage({
|
|
1627
|
+
chrome.runtime.sendMessage({
|
|
1939
1628
|
action: 'startWorkflowRecording',
|
|
1940
1629
|
tabId: tab.id,
|
|
1941
1630
|
includeLogsInExport: includeLogsInExport,
|
|
1942
1631
|
sessionName: sessionName,
|
|
1943
1632
|
screenshotSettings: screenshotSettings
|
|
1944
1633
|
}, (response) => {
|
|
1945
|
-
console.log('[Popup v2.0.6] Received response from background:', response);
|
|
1946
|
-
console.log('[Popup v2.0.6] chrome.runtime.lastError:', chrome.runtime.lastError);
|
|
1947
|
-
console.log('[Popup v2.0.6] Checking which branch will execute...');
|
|
1948
|
-
|
|
1949
1634
|
if (chrome.runtime.lastError) {
|
|
1950
|
-
console.error('[Popup v2.0.6] RUNTIME ERROR BRANCH:', chrome.runtime.lastError);
|
|
1951
1635
|
// Check if this tab allows content script injection
|
|
1952
1636
|
if (!tab.url || tab.url.startsWith('chrome://') || tab.url.startsWith('chrome-extension://') || tab.url.startsWith('moz-extension://')) {
|
|
1953
|
-
console.log('Cannot inject content script into restricted URL:', tab.url);
|
|
1954
1637
|
return;
|
|
1955
1638
|
}
|
|
1956
1639
|
// Inject content script if needed
|
|
@@ -1996,31 +1679,17 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
1996
1679
|
});
|
|
1997
1680
|
});
|
|
1998
1681
|
} else if (response && response.success) {
|
|
1999
|
-
console.log('[Popup v2.0.6] *** SUCCESS BRANCH REACHED! ***');
|
|
2000
|
-
console.log('[Popup v2.0.6] Workflow recording started successfully, updating UI now');
|
|
2001
|
-
console.log('[Popup v2.0.6] Setting isWorkflowRecording = true');
|
|
2002
1682
|
isWorkflowRecording = true;
|
|
2003
1683
|
// Save state and start time to storage
|
|
2004
1684
|
const startTime = Date.now();
|
|
2005
|
-
chrome.storage.local.set({
|
|
1685
|
+
chrome.storage.local.set({
|
|
2006
1686
|
workflowRecording: true,
|
|
2007
1687
|
workflowStartTime: startTime
|
|
2008
1688
|
});
|
|
2009
1689
|
workflowStartTime = startTime;
|
|
2010
|
-
console.log('[Popup v2.0.6] About to call updateWorkflowRecordingUI()');
|
|
2011
1690
|
updateWorkflowRecordingUI();
|
|
2012
|
-
console.log('[Popup v2.0.6] updateWorkflowRecordingUI() call completed');
|
|
2013
1691
|
// Hide any previous results
|
|
2014
1692
|
if (workflowRecordingsList) workflowRecordingsList.style.display = 'none';
|
|
2015
|
-
} else {
|
|
2016
|
-
console.error('[Popup v2.0.6] *** ELSE BRANCH - Unexpected response ***');
|
|
2017
|
-
console.error('[Popup v2.0.6] Response details:', {
|
|
2018
|
-
exists: !!response,
|
|
2019
|
-
success: response?.success,
|
|
2020
|
-
type: typeof response,
|
|
2021
|
-
keys: response ? Object.keys(response) : 'no response',
|
|
2022
|
-
fullResponse: response
|
|
2023
|
-
});
|
|
2024
1693
|
}
|
|
2025
1694
|
});
|
|
2026
1695
|
} catch (error) {
|
|
@@ -2070,9 +1739,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
2070
1739
|
// Single source of truth - load from server
|
|
2071
1740
|
await loadWorkflowRecordings(true);
|
|
2072
1741
|
|
|
2073
|
-
// Show success toast
|
|
1742
|
+
// Show success toast - response.workflow.actions is the array
|
|
2074
1743
|
const workflowData = response.workflow;
|
|
2075
|
-
const actionCount = workflowData?.
|
|
1744
|
+
const actionCount = workflowData?.actions?.length || 0;
|
|
2076
1745
|
showToast(`Workflow recording saved! ${actionCount} actions recorded`, 3000, 'success');
|
|
2077
1746
|
} catch (error) {
|
|
2078
1747
|
console.error('Error loading workflow recordings:', error);
|
|
@@ -2122,7 +1791,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
2122
1791
|
}
|
|
2123
1792
|
|
|
2124
1793
|
if (response && response.success) {
|
|
2125
|
-
console.log('Restore point created:', response.restorePointId);
|
|
1794
|
+
// console.log('Restore point created:', response.restorePointId);
|
|
2126
1795
|
// Refresh restore points list
|
|
2127
1796
|
loadRestorePoints();
|
|
2128
1797
|
} else {
|
|
@@ -2256,7 +1925,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
2256
1925
|
}
|
|
2257
1926
|
|
|
2258
1927
|
if (response && response.success) {
|
|
2259
|
-
console.log('Successfully restored from point');
|
|
1928
|
+
// console.log('Successfully restored from point');
|
|
2260
1929
|
} else {
|
|
2261
1930
|
console.error('Failed to restore from point:', response);
|
|
2262
1931
|
}
|
|
@@ -2278,7 +1947,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
2278
1947
|
});
|
|
2279
1948
|
|
|
2280
1949
|
if (response.ok) {
|
|
2281
|
-
console.log('Restore point deleted');
|
|
1950
|
+
// console.log('Restore point deleted');
|
|
2282
1951
|
break;
|
|
2283
1952
|
}
|
|
2284
1953
|
} catch (error) {
|
|
@@ -2472,7 +2141,7 @@ async function loadWorkflowRecordings(autoShow = false) {
|
|
|
2472
2141
|
const response = await fetch(`http://localhost:${port}/chromedebug/workflow-recordings`);
|
|
2473
2142
|
if (response.ok) {
|
|
2474
2143
|
const data = await response.json();
|
|
2475
|
-
console.log('Loaded workflow recordings from port', port, ':', data);
|
|
2144
|
+
// console.log('Loaded workflow recordings from port', port, ':', data);
|
|
2476
2145
|
|
|
2477
2146
|
// Handle both data.recordings and direct array response
|
|
2478
2147
|
const recordings = data.recordings || data;
|
|
@@ -2567,7 +2236,7 @@ async function loadWorkflowRecordings(autoShow = false) {
|
|
|
2567
2236
|
playBtn.addEventListener('click', () => playWorkflow(recording.session_id));
|
|
2568
2237
|
|
|
2569
2238
|
deleteBtn.addEventListener('click', () => {
|
|
2570
|
-
console.log('Delete clicked for recording:', recording);
|
|
2239
|
+
// console.log('Delete clicked for recording:', recording);
|
|
2571
2240
|
const recordingId = recording.id || recording.session_id;
|
|
2572
2241
|
if (!recordingId) {
|
|
2573
2242
|
console.error('No ID found for recording:', recording);
|
|
@@ -2625,7 +2294,7 @@ async function loadWorkflowRecordings(autoShow = false) {
|
|
|
2625
2294
|
|
|
2626
2295
|
// Function to play a workflow
|
|
2627
2296
|
async function playWorkflow(sessionId) {
|
|
2628
|
-
console.log('Playing workflow:', sessionId);
|
|
2297
|
+
// console.log('Playing workflow:', sessionId);
|
|
2629
2298
|
|
|
2630
2299
|
try {
|
|
2631
2300
|
// Get the current active tab
|
|
@@ -2705,7 +2374,7 @@ async function playWorkflow(sessionId) {
|
|
|
2705
2374
|
}, 100);
|
|
2706
2375
|
});
|
|
2707
2376
|
} else if (response && response.success) {
|
|
2708
|
-
console.log('Workflow playback started');
|
|
2377
|
+
// console.log('Workflow playback started');
|
|
2709
2378
|
}
|
|
2710
2379
|
});
|
|
2711
2380
|
} catch (error) {
|
|
@@ -2785,11 +2454,11 @@ async function loadScreenRecordings(autoShow = false) {
|
|
|
2785
2454
|
|
|
2786
2455
|
// First, load browser-only recordings from IndexedDB
|
|
2787
2456
|
try {
|
|
2788
|
-
console.log('[Popup] Requesting browser-only recordings...');
|
|
2457
|
+
// console.log('[Popup] Requesting browser-only recordings...');
|
|
2789
2458
|
const browserRecordings = await chrome.runtime.sendMessage({
|
|
2790
2459
|
action: 'getBrowserRecordings'
|
|
2791
2460
|
});
|
|
2792
|
-
console.log('[Popup] Browser recordings received:', browserRecordings);
|
|
2461
|
+
// console.log('[Popup] Browser recordings received:', browserRecordings);
|
|
2793
2462
|
|
|
2794
2463
|
if (browserRecordings && browserRecordings.length > 0) {
|
|
2795
2464
|
hasRecordings = true;
|
|
@@ -2929,10 +2598,10 @@ async function loadScreenRecordings(autoShow = false) {
|
|
|
2929
2598
|
const formattedDate = date.toLocaleString();
|
|
2930
2599
|
|
|
2931
2600
|
// Use session name if available, otherwise use session ID
|
|
2932
|
-
console.log('Recording data:', recording);
|
|
2933
|
-
console.log('Recording name:', recording.name);
|
|
2601
|
+
// console.log('Recording data:', recording);
|
|
2602
|
+
// console.log('Recording name:', recording.name);
|
|
2934
2603
|
const displayName = recording.name || `Recording ${recording.sessionId}`;
|
|
2935
|
-
console.log('Display name:', displayName);
|
|
2604
|
+
// console.log('Display name:', displayName);
|
|
2936
2605
|
|
|
2937
2606
|
recordingItem.innerHTML = `
|
|
2938
2607
|
<div class="recording-info">
|
|
@@ -2972,9 +2641,9 @@ async function loadScreenRecordings(autoShow = false) {
|
|
|
2972
2641
|
let prompt;
|
|
2973
2642
|
|
|
2974
2643
|
if (name) {
|
|
2975
|
-
prompt = `Please use the
|
|
2644
|
+
prompt = `Please use the chrome_debug_show_frames function in Chrome Debug to display the screen recording "${name}" (session: ${sessionId}) that was recorded on port ${port}.`;
|
|
2976
2645
|
} else {
|
|
2977
|
-
prompt = `Please use the
|
|
2646
|
+
prompt = `Please use the chrome_debug_show_frames function in Chrome Debug to display the screen recording "${sessionId}" that was recorded on port ${port}.`;
|
|
2978
2647
|
}
|
|
2979
2648
|
|
|
2980
2649
|
navigator.clipboard.writeText(prompt).then(() => {
|
|
@@ -3228,14 +2897,25 @@ chrome.storage.onChanged.addListener((changes, namespace) => {
|
|
|
3228
2897
|
isWorkflowRecording = changes.workflowRecording.newValue === true;
|
|
3229
2898
|
updateWorkflowRecordingUI();
|
|
3230
2899
|
}
|
|
2900
|
+
// Update usage display when usage count changes
|
|
2901
|
+
if (changes.chromedebug_daily_usage) {
|
|
2902
|
+
const usage = changes.chromedebug_daily_usage.newValue;
|
|
2903
|
+
if (usage) {
|
|
2904
|
+
const usageCountEl = document.getElementById('usage-count');
|
|
2905
|
+
const usageLimitEl = document.getElementById('usage-limit');
|
|
2906
|
+
if (usageCountEl) usageCountEl.textContent = usage.count || 0;
|
|
2907
|
+
if (usageLimitEl) usageLimitEl.textContent = '5'; // FREE tier limit
|
|
2908
|
+
// console.log(`[Usage] Storage updated: ${usage.count}/5`);
|
|
2909
|
+
}
|
|
2910
|
+
}
|
|
3231
2911
|
}
|
|
3232
2912
|
});
|
|
3233
2913
|
|
|
3234
2914
|
// Listen for messages from background script
|
|
3235
2915
|
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|
3236
|
-
console.log('Popup received message:', request);
|
|
2916
|
+
// console.log('Popup received message:', request);
|
|
3237
2917
|
if (request.action === 'uploadComplete') {
|
|
3238
|
-
console.log('Upload complete with ID:', request.recordingId);
|
|
2918
|
+
// console.log('Upload complete with ID:', request.recordingId);
|
|
3239
2919
|
const recordingStatus = document.getElementById('recordingStatus');
|
|
3240
2920
|
if (recordingStatus) {
|
|
3241
2921
|
recordingStatus.innerHTML = `<strong style="color: #4CAF50;">Recording saved!</strong>`;
|
|
@@ -3247,7 +2927,7 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|
|
3247
2927
|
if (recordingStatus) recordingStatus.textContent = '';
|
|
3248
2928
|
}, 3000);
|
|
3249
2929
|
} else if (request.action === 'sessionComplete') {
|
|
3250
|
-
console.log('Session complete:', request.sessionId, 'with', request.totalChunks, 'chunks');
|
|
2930
|
+
// console.log('Session complete:', request.sessionId, 'with', request.totalChunks, 'chunks');
|
|
3251
2931
|
const recordingStatus = document.getElementById('recordingStatus');
|
|
3252
2932
|
if (recordingStatus) {
|
|
3253
2933
|
recordingStatus.innerHTML = `<strong style="color: #4CAF50;">Recording session saved!</strong><br>` +
|
|
@@ -3260,18 +2940,26 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|
|
3260
2940
|
if (recordingStatus) recordingStatus.textContent = '';
|
|
3261
2941
|
}, 5000);
|
|
3262
2942
|
} else if (request.action === 'frameSessionComplete') {
|
|
3263
|
-
console.log('Frame session complete:', request.sessionId, 'with', request.totalFrames, 'frames');
|
|
2943
|
+
// console.log('Frame session complete:', request.sessionId, 'with', request.totalFrames, 'frames');
|
|
3264
2944
|
const recordingStatus = document.getElementById('recordingStatus');
|
|
3265
2945
|
if (recordingStatus) {
|
|
3266
2946
|
recordingStatus.innerHTML = `<strong style="color: #4CAF50;">Recording saved!</strong><br>` +
|
|
3267
2947
|
`<small>${request.totalFrames} frames (${Math.round(request.duration / 1000)}s)</small>`;
|
|
3268
2948
|
}
|
|
3269
|
-
//
|
|
3270
|
-
|
|
2949
|
+
// Reload screen recordings list to show the new recording
|
|
2950
|
+
loadScreenRecordings(true);
|
|
3271
2951
|
// Clear status after 5 seconds
|
|
3272
2952
|
setTimeout(() => {
|
|
3273
2953
|
if (recordingStatus) recordingStatus.textContent = '';
|
|
3274
2954
|
}, 5000);
|
|
2955
|
+
} else if (request.action === 'workflowRecordingSaved') {
|
|
2956
|
+
// console.log('Workflow recording saved:', request.workflowId);
|
|
2957
|
+
// Reload workflow recordings list to show the new recording
|
|
2958
|
+
loadWorkflowRecordings(true);
|
|
2959
|
+
} else if (request.action === 'recordingStopped') {
|
|
2960
|
+
// console.log('Recording stopped:', request.sessionId);
|
|
2961
|
+
// Reload screen recordings list immediately
|
|
2962
|
+
loadScreenRecordings(true);
|
|
3275
2963
|
} else if (request.action === 'uploadError') {
|
|
3276
2964
|
const recordingStatus = document.getElementById('recordingStatus');
|
|
3277
2965
|
if (recordingStatus) {
|