@dynamicu/chromedebug-mcp 2.6.7 → 2.7.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/CLAUDE.md +1 -1
- package/README.md +1 -1
- package/chrome-extension/background.js +611 -505
- package/chrome-extension/browser-recording-manager.js +1 -1
- package/chrome-extension/chrome-debug-logger.js +168 -0
- package/chrome-extension/console-interception-library.js +430 -0
- package/chrome-extension/content.css +16 -16
- package/chrome-extension/content.js +458 -126
- package/chrome-extension/extension-config.js +1 -1
- package/chrome-extension/license-helper.js +26 -0
- package/chrome-extension/manifest.free.json +0 -3
- package/chrome-extension/options.js +1 -1
- package/chrome-extension/popup.html +221 -191
- package/chrome-extension/popup.js +88 -379
- package/chrome-extension/pro/enhanced-capture.js +406 -0
- package/chrome-extension/pro/frame-editor.html +410 -0
- package/chrome-extension/pro/frame-editor.js +1496 -0
- package/chrome-extension/pro/function-tracker.js +843 -0
- package/chrome-extension/pro/jszip.min.js +13 -0
- 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 +2 -2
- 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
|
@@ -2,29 +2,9 @@
|
|
|
2
2
|
const EXTENSION_VERSION = '2.0.4-BUILD-20250119';
|
|
3
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
|
+
// Chrome Web Store URLs for upgrade flow
|
|
6
|
+
const CHROME_STORE_PRO_URL = 'https://chrome.google.com/webstore/detail/chromedebug-mcp-pro/[PRO_EXTENSION_ID]';
|
|
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;
|
|
@@ -445,14 +425,7 @@ async function checkServerStatus() {
|
|
|
445
425
|
|
|
446
426
|
if (connected) {
|
|
447
427
|
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
|
-
`;
|
|
428
|
+
statusTextEl.textContent = `Server connected (port ${connectedPort})`;
|
|
456
429
|
} else {
|
|
457
430
|
statusEl.className = 'server-status disconnected';
|
|
458
431
|
|
|
@@ -472,9 +445,6 @@ async function checkServerStatus() {
|
|
|
472
445
|
<button id="copyInstallCmd" style="padding: 4px 8px; font-size: 11px; background: #2196F3; color: white; border: none; border-radius: 3px; cursor: pointer;">
|
|
473
446
|
📋 Copy Commands
|
|
474
447
|
</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
448
|
</div>
|
|
479
449
|
`;
|
|
480
450
|
|
|
@@ -929,7 +899,7 @@ function updateRecordingsDisplay(recordings) {
|
|
|
929
899
|
if (type === 'snapshot') {
|
|
930
900
|
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
901
|
} else {
|
|
932
|
-
prompt = `Please use the
|
|
902
|
+
prompt = `Please use the chrome_debug_show_frames function in Chrome Debug to load the recording "${recordingId}"${portText}.`;
|
|
933
903
|
}
|
|
934
904
|
|
|
935
905
|
navigator.clipboard.writeText(prompt).then(() => {
|
|
@@ -1002,352 +972,71 @@ function updateRecordingsDisplay(recordings) {
|
|
|
1002
972
|
|
|
1003
973
|
|
|
1004
974
|
|
|
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
|
-
}
|
|
975
|
+
// Initialize tier status display for FREE version
|
|
976
|
+
function initializeTierStatus() {
|
|
977
|
+
if (IS_PRO_VERSION) {
|
|
978
|
+
// Hide license section for PRO version
|
|
979
|
+
const licenseSection = document.getElementById('license-section');
|
|
980
|
+
if (licenseSection) {
|
|
981
|
+
licenseSection.style.display = 'none';
|
|
982
|
+
console.log('[Tier] PRO version detected - hiding license section');
|
|
1031
983
|
}
|
|
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
984
|
} 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';
|
|
1081
|
-
|
|
1082
|
-
// Trigger animation
|
|
1083
|
-
setTimeout(() => {
|
|
1084
|
-
inlineManager.style.maxHeight = '400px';
|
|
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;
|
|
985
|
+
// Show FREE tier status (no license validation)
|
|
986
|
+
const freeTierStatus = document.getElementById('free-tier-status');
|
|
987
|
+
const proTierStatus = document.getElementById('pro-tier-status');
|
|
988
|
+
const licenseActivation = document.getElementById('license-activation');
|
|
1095
989
|
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
990
|
+
if (freeTierStatus) freeTierStatus.style.display = 'block';
|
|
991
|
+
if (proTierStatus) proTierStatus.style.display = 'none';
|
|
992
|
+
if (licenseActivation) licenseActivation.style.display = 'none';
|
|
1099
993
|
|
|
1100
|
-
//
|
|
1101
|
-
|
|
994
|
+
// Fetch and display current usage count
|
|
995
|
+
updateUsageDisplay();
|
|
1102
996
|
|
|
1103
|
-
|
|
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>`;
|
|
997
|
+
console.log('[Tier] FREE version - showing usage counter');
|
|
1106
998
|
}
|
|
1107
999
|
}
|
|
1108
1000
|
|
|
1109
1001
|
/**
|
|
1110
|
-
*
|
|
1002
|
+
* Fetch usage from background and update the display
|
|
1111
1003
|
*/
|
|
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
|
-
|
|
1004
|
+
async function updateUsageDisplay() {
|
|
1217
1005
|
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';
|
|
1006
|
+
const response = await chrome.runtime.sendMessage({ action: 'getUsage' });
|
|
1224
1007
|
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
if (result.deactivated) {
|
|
1230
|
-
messageDiv.textContent = 'Deactivated! Activating on this device...';
|
|
1231
|
-
messageDiv.style.color = '#4caf50';
|
|
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;
|
|
1008
|
+
if (response && response.success) {
|
|
1009
|
+
const usageCountEl = document.getElementById('usage-count');
|
|
1010
|
+
const usageLimitEl = document.getElementById('usage-limit');
|
|
1240
1011
|
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
}
|
|
1012
|
+
if (usageCountEl) {
|
|
1013
|
+
usageCountEl.textContent = response.count || 0;
|
|
1014
|
+
}
|
|
1015
|
+
if (usageLimitEl) {
|
|
1016
|
+
usageLimitEl.textContent = response.limit || 5;
|
|
1017
|
+
}
|
|
1244
1018
|
|
|
1245
|
-
|
|
1246
|
-
throw new Error(result.error || 'Deactivation failed');
|
|
1019
|
+
console.log(`[Usage] Display updated: ${response.count}/${response.limit}`);
|
|
1247
1020
|
}
|
|
1248
|
-
|
|
1249
1021
|
} 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
|
-
}
|
|
1022
|
+
console.error('[Usage] Failed to fetch usage:', error);
|
|
1308
1023
|
}
|
|
1309
1024
|
}
|
|
1310
1025
|
|
|
1311
|
-
// Upgrade button handler
|
|
1026
|
+
// Upgrade button handler - redirect to Chrome Web Store PRO version
|
|
1312
1027
|
function handleUpgradeClick() {
|
|
1313
|
-
console.log('[
|
|
1314
|
-
chrome.tabs.create({url:
|
|
1028
|
+
console.log('[Upgrade] Opening Chrome Web Store PRO version');
|
|
1029
|
+
chrome.tabs.create({url: CHROME_STORE_PRO_URL});
|
|
1315
1030
|
}
|
|
1316
1031
|
|
|
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
1032
|
document.addEventListener('DOMContentLoaded', () => {
|
|
1336
1033
|
console.log('DOM loaded, initializing popup');
|
|
1337
1034
|
|
|
1338
|
-
// Initialize
|
|
1339
|
-
|
|
1340
|
-
console.error('[License] Failed to initialize license UI:', error);
|
|
1341
|
-
});
|
|
1035
|
+
// Initialize tier status display
|
|
1036
|
+
initializeTierStatus();
|
|
1342
1037
|
|
|
1343
|
-
//
|
|
1344
|
-
const activateLicenseBtn = document.getElementById('activate-license-btn');
|
|
1038
|
+
// Upgrade button handler
|
|
1345
1039
|
const upgradeBtn = document.getElementById('upgrade-btn');
|
|
1346
|
-
|
|
1347
|
-
if (activateLicenseBtn) {
|
|
1348
|
-
activateLicenseBtn.addEventListener('click', handleLicenseActivation);
|
|
1349
|
-
}
|
|
1350
|
-
|
|
1351
1040
|
if (upgradeBtn) {
|
|
1352
1041
|
upgradeBtn.addEventListener('click', handleUpgradeClick);
|
|
1353
1042
|
}
|
|
@@ -1711,6 +1400,17 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
1711
1400
|
console.log('Starting recording with server');
|
|
1712
1401
|
}
|
|
1713
1402
|
|
|
1403
|
+
// Check FREE tier usage limit before starting
|
|
1404
|
+
const usageCheck = await chrome.runtime.sendMessage({ action: 'checkUsageLimit' });
|
|
1405
|
+
if (usageCheck && !usageCheck.allowed) {
|
|
1406
|
+
console.log('[Usage] Daily limit reached:', usageCheck);
|
|
1407
|
+
if (recordingStatus) {
|
|
1408
|
+
recordingStatus.innerHTML = '<strong style="color: #f44336;">Daily limit reached</strong><br>' +
|
|
1409
|
+
`<small>${usageCheck.count}/${usageCheck.limit} recordings used today.<br>Upgrade to Pro for unlimited.</small>`;
|
|
1410
|
+
}
|
|
1411
|
+
return;
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1714
1414
|
// Get the current active tab
|
|
1715
1415
|
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
|
|
1716
1416
|
console.log('Current tab:', tab);
|
|
@@ -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 });
|
|
@@ -2070,9 +1760,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
2070
1760
|
// Single source of truth - load from server
|
|
2071
1761
|
await loadWorkflowRecordings(true);
|
|
2072
1762
|
|
|
2073
|
-
// Show success toast
|
|
1763
|
+
// Show success toast - response.workflow.actions is the array
|
|
2074
1764
|
const workflowData = response.workflow;
|
|
2075
|
-
const actionCount = workflowData?.
|
|
1765
|
+
const actionCount = workflowData?.actions?.length || 0;
|
|
2076
1766
|
showToast(`Workflow recording saved! ${actionCount} actions recorded`, 3000, 'success');
|
|
2077
1767
|
} catch (error) {
|
|
2078
1768
|
console.error('Error loading workflow recordings:', error);
|
|
@@ -2972,9 +2662,9 @@ async function loadScreenRecordings(autoShow = false) {
|
|
|
2972
2662
|
let prompt;
|
|
2973
2663
|
|
|
2974
2664
|
if (name) {
|
|
2975
|
-
prompt = `Please use the
|
|
2665
|
+
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
2666
|
} else {
|
|
2977
|
-
prompt = `Please use the
|
|
2667
|
+
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
2668
|
}
|
|
2979
2669
|
|
|
2980
2670
|
navigator.clipboard.writeText(prompt).then(() => {
|
|
@@ -3228,6 +2918,17 @@ chrome.storage.onChanged.addListener((changes, namespace) => {
|
|
|
3228
2918
|
isWorkflowRecording = changes.workflowRecording.newValue === true;
|
|
3229
2919
|
updateWorkflowRecordingUI();
|
|
3230
2920
|
}
|
|
2921
|
+
// Update usage display when usage count changes
|
|
2922
|
+
if (changes.chromedebug_daily_usage) {
|
|
2923
|
+
const usage = changes.chromedebug_daily_usage.newValue;
|
|
2924
|
+
if (usage) {
|
|
2925
|
+
const usageCountEl = document.getElementById('usage-count');
|
|
2926
|
+
const usageLimitEl = document.getElementById('usage-limit');
|
|
2927
|
+
if (usageCountEl) usageCountEl.textContent = usage.count || 0;
|
|
2928
|
+
if (usageLimitEl) usageLimitEl.textContent = '5'; // FREE tier limit
|
|
2929
|
+
console.log(`[Usage] Storage updated: ${usage.count}/5`);
|
|
2930
|
+
}
|
|
2931
|
+
}
|
|
3231
2932
|
}
|
|
3232
2933
|
});
|
|
3233
2934
|
|
|
@@ -3266,12 +2967,20 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|
|
3266
2967
|
recordingStatus.innerHTML = `<strong style="color: #4CAF50;">Recording saved!</strong><br>` +
|
|
3267
2968
|
`<small>${request.totalFrames} frames (${Math.round(request.duration / 1000)}s)</small>`;
|
|
3268
2969
|
}
|
|
3269
|
-
//
|
|
3270
|
-
|
|
2970
|
+
// Reload screen recordings list to show the new recording
|
|
2971
|
+
loadScreenRecordings(true);
|
|
3271
2972
|
// Clear status after 5 seconds
|
|
3272
2973
|
setTimeout(() => {
|
|
3273
2974
|
if (recordingStatus) recordingStatus.textContent = '';
|
|
3274
2975
|
}, 5000);
|
|
2976
|
+
} else if (request.action === 'workflowRecordingSaved') {
|
|
2977
|
+
console.log('Workflow recording saved:', request.workflowId);
|
|
2978
|
+
// Reload workflow recordings list to show the new recording
|
|
2979
|
+
loadWorkflowRecordings(true);
|
|
2980
|
+
} else if (request.action === 'recordingStopped') {
|
|
2981
|
+
console.log('Recording stopped:', request.sessionId);
|
|
2982
|
+
// Reload screen recordings list immediately
|
|
2983
|
+
loadScreenRecordings(true);
|
|
3275
2984
|
} else if (request.action === 'uploadError') {
|
|
3276
2985
|
const recordingStatus = document.getElementById('recordingStatus');
|
|
3277
2986
|
if (recordingStatus) {
|