@gxp-dev/tools 2.0.6 โ†’ 2.0.8

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 (100) hide show
  1. package/bin/lib/commands/build.js +18 -12
  2. package/browser-extensions/README.md +1 -0
  3. package/browser-extensions/chrome/background.js +857 -0
  4. package/browser-extensions/chrome/content.js +51 -0
  5. package/browser-extensions/chrome/devtools.html +9 -0
  6. package/browser-extensions/chrome/devtools.js +23 -0
  7. package/browser-extensions/chrome/icons/gx_off_128.png +0 -0
  8. package/browser-extensions/chrome/icons/gx_off_16.png +0 -0
  9. package/browser-extensions/chrome/icons/gx_off_32.png +0 -0
  10. package/browser-extensions/chrome/icons/gx_off_64.png +0 -0
  11. package/browser-extensions/chrome/icons/gx_on_128.png +0 -0
  12. package/browser-extensions/chrome/icons/gx_on_16.png +0 -0
  13. package/browser-extensions/chrome/icons/gx_on_32.png +0 -0
  14. package/browser-extensions/chrome/icons/gx_on_64.png +0 -0
  15. package/browser-extensions/chrome/inspector.js +1087 -0
  16. package/browser-extensions/chrome/manifest.json +70 -0
  17. package/browser-extensions/chrome/panel.html +638 -0
  18. package/browser-extensions/chrome/panel.js +862 -0
  19. package/browser-extensions/chrome/popup.html +399 -0
  20. package/browser-extensions/chrome/popup.js +515 -0
  21. package/browser-extensions/chrome/rules.json +1 -0
  22. package/browser-extensions/chrome/test-chrome.html +145 -0
  23. package/browser-extensions/chrome/test-mixed-content.html +190 -0
  24. package/browser-extensions/chrome/test-uri-pattern.html +199 -0
  25. package/browser-extensions/firefox/README.md +134 -0
  26. package/browser-extensions/firefox/background.js +804 -0
  27. package/browser-extensions/firefox/content.js +120 -0
  28. package/browser-extensions/firefox/debug-errors.html +229 -0
  29. package/browser-extensions/firefox/debug-https.html +113 -0
  30. package/browser-extensions/firefox/devtools.html +9 -0
  31. package/browser-extensions/firefox/devtools.js +24 -0
  32. package/browser-extensions/firefox/icons/gx_off_128.png +0 -0
  33. package/browser-extensions/firefox/icons/gx_off_16.png +0 -0
  34. package/browser-extensions/firefox/icons/gx_off_32.png +0 -0
  35. package/browser-extensions/firefox/icons/gx_off_64.png +0 -0
  36. package/browser-extensions/firefox/icons/gx_on_128.png +0 -0
  37. package/browser-extensions/firefox/icons/gx_on_16.png +0 -0
  38. package/browser-extensions/firefox/icons/gx_on_32.png +0 -0
  39. package/browser-extensions/firefox/icons/gx_on_64.png +0 -0
  40. package/browser-extensions/firefox/inspector.js +1087 -0
  41. package/browser-extensions/firefox/manifest.json +67 -0
  42. package/browser-extensions/firefox/panel.html +638 -0
  43. package/browser-extensions/firefox/panel.js +862 -0
  44. package/browser-extensions/firefox/popup.html +525 -0
  45. package/browser-extensions/firefox/popup.js +536 -0
  46. package/browser-extensions/firefox/test-gramercy.html +126 -0
  47. package/browser-extensions/firefox/test-imports.html +58 -0
  48. package/browser-extensions/firefox/test-masking.html +147 -0
  49. package/browser-extensions/firefox/test-uri-pattern.html +199 -0
  50. package/package.json +7 -2
  51. package/runtime/PortalContainer.vue +326 -0
  52. package/runtime/dev-tools/DevToolsModal.vue +217 -0
  53. package/runtime/dev-tools/LayoutSwitcher.vue +221 -0
  54. package/runtime/dev-tools/MockDataEditor.vue +621 -0
  55. package/runtime/dev-tools/SocketSimulator.vue +562 -0
  56. package/runtime/dev-tools/StoreInspector.vue +644 -0
  57. package/runtime/dev-tools/index.js +6 -0
  58. package/runtime/gxpStringsPlugin.js +428 -0
  59. package/runtime/index.html +22 -0
  60. package/runtime/main.js +32 -0
  61. package/runtime/mock-api/auth-middleware.js +97 -0
  62. package/runtime/mock-api/image-generator.js +221 -0
  63. package/runtime/mock-api/index.js +197 -0
  64. package/runtime/mock-api/response-generator.js +394 -0
  65. package/runtime/mock-api/route-generator.js +323 -0
  66. package/runtime/mock-api/socket-triggers.js +371 -0
  67. package/runtime/mock-api/spec-loader.js +300 -0
  68. package/runtime/server.js +180 -0
  69. package/runtime/stores/gxpPortalConfigStore.js +554 -0
  70. package/runtime/stores/index.js +6 -0
  71. package/runtime/vite-inspector-plugin.js +749 -0
  72. package/runtime/vite-source-tracker-plugin.js +232 -0
  73. package/runtime/vite.config.js +402 -0
  74. package/scripts/launch-chrome.js +90 -0
  75. package/scripts/pack-chrome.js +91 -0
  76. package/socket-events/AiSessionMessageCreated.json +18 -0
  77. package/socket-events/SocialStreamPostCreated.json +24 -0
  78. package/socket-events/SocialStreamPostVariantCompleted.json +23 -0
  79. package/template/README.md +332 -0
  80. package/template/app-manifest.json +32 -0
  81. package/template/dev-assets/images/avatar-placeholder.png +0 -0
  82. package/template/dev-assets/images/background-placeholder.jpg +0 -0
  83. package/template/dev-assets/images/banner-placeholder.jpg +0 -0
  84. package/template/dev-assets/images/icon-placeholder.png +0 -0
  85. package/template/dev-assets/images/logo-placeholder.png +0 -0
  86. package/template/dev-assets/images/product-placeholder.jpg +0 -0
  87. package/template/dev-assets/images/thumbnail-placeholder.jpg +0 -0
  88. package/template/env.example +51 -0
  89. package/template/gitignore +53 -0
  90. package/template/index.html +22 -0
  91. package/template/main.js +28 -0
  92. package/template/src/DemoPage.vue +459 -0
  93. package/template/src/Plugin.vue +38 -0
  94. package/template/src/stores/index.js +9 -0
  95. package/template/src/stores/test-data.json +173 -0
  96. package/template/theme-layouts/AdditionalStyling.css +0 -0
  97. package/template/theme-layouts/PrivateLayout.vue +39 -0
  98. package/template/theme-layouts/PublicLayout.vue +39 -0
  99. package/template/theme-layouts/SystemLayout.vue +39 -0
  100. package/template/vite.config.js +333 -0
@@ -0,0 +1,536 @@
1
+ // Configuration defaults
2
+ const DEFAULT_CONFIG = {
3
+ enabled: false,
4
+ // Legacy fields for backward compatibility
5
+ redirectUrl: "https://localhost:3060/src/Plugin.vue",
6
+ urlPattern: "uploads\\/plugin-version\\/\\d+\\/file_name\\/.*\\.js(\\?.*)?",
7
+ useCustomPattern: false,
8
+ // New rules-based configuration
9
+ rules: {
10
+ js: {
11
+ enabled: true,
12
+ pattern: "uploads\\/plugin-version\\/\\d+\\/file_name\\/.*\\.js(\\?.*)?",
13
+ redirectUrl: "https://localhost:3060/src/Plugin.vue",
14
+ useCustomPattern: false,
15
+ },
16
+ css: {
17
+ enabled: true,
18
+ pattern:
19
+ "uploads\\/plugin-version\\/\\d+\\/style_file_name\\/.*\\.css(\\?.*)?",
20
+ redirectUrl: "",
21
+ returnBlank: true,
22
+ useCustomPattern: false,
23
+ },
24
+ },
25
+ maskingMode: false,
26
+ clearCacheOnEnable: true,
27
+ disableCacheForRedirects: true,
28
+ };
29
+
30
+ // Global state
31
+ let config = { ...DEFAULT_CONFIG };
32
+ let pendingChanges = false;
33
+
34
+ // DOM elements
35
+ const elements = {
36
+ // Status and main toggle
37
+ statusMessage: null,
38
+ masterToggle: null,
39
+ statusInfo: null,
40
+
41
+ // JavaScript rule elements
42
+ jsRuleContainer: null,
43
+ jsRuleToggle: null,
44
+ jsRedirectUrl: null,
45
+ jsUseCustomPattern: null,
46
+ jsPattern: null,
47
+ jsPatternGroup: null,
48
+
49
+ // CSS rule elements
50
+ cssRuleContainer: null,
51
+ cssRuleToggle: null,
52
+ cssRedirectUrl: null,
53
+ cssReturnBlank: null,
54
+ cssUseCustomPattern: null,
55
+ cssPattern: null,
56
+ cssPatternGroup: null,
57
+ cssRedirectGroup: null,
58
+
59
+ // Advanced settings
60
+ advancedHeader: null,
61
+ advancedContent: null,
62
+ advancedToggle: null,
63
+ maskingMode: null,
64
+ clearCacheOnEnable: null,
65
+ disableCacheForRedirects: null,
66
+
67
+ // Action buttons
68
+ saveBtn: null,
69
+ clearCacheBtn: null,
70
+ };
71
+
72
+ // Initialize popup
73
+ document.addEventListener("DOMContentLoaded", async () => {
74
+ try {
75
+ initializeElements();
76
+ setupEventListeners();
77
+ await loadConfiguration();
78
+ updateUI();
79
+ console.log("[JavaScript Proxy] Popup initialized successfully");
80
+ } catch (error) {
81
+ console.error("[JavaScript Proxy] Error initializing popup:", error);
82
+ showStatus("Error initializing popup: " + error.message, "error");
83
+ }
84
+ });
85
+
86
+ // Initialize DOM elements
87
+ function initializeElements() {
88
+ // Get all elements and store in global object
89
+ for (const key in elements) {
90
+ const element = document.getElementById(key);
91
+ if (!element) {
92
+ throw new Error(`Required element not found: ${key}`);
93
+ }
94
+ elements[key] = element;
95
+ }
96
+ }
97
+
98
+ // Setup event listeners
99
+ function setupEventListeners() {
100
+ // Master toggle
101
+ elements.masterToggle.addEventListener("change", handleMasterToggle);
102
+
103
+ // Rule toggles
104
+ elements.jsRuleToggle.addEventListener("change", () =>
105
+ handleRuleToggle("js")
106
+ );
107
+ elements.cssRuleToggle.addEventListener("change", () =>
108
+ handleRuleToggle("css")
109
+ );
110
+
111
+ // JavaScript rule events
112
+ elements.jsRedirectUrl.addEventListener("input", () =>
113
+ handleFieldChange("js", "redirectUrl")
114
+ );
115
+ elements.jsUseCustomPattern.addEventListener("change", () =>
116
+ handleCustomPatternToggle("js")
117
+ );
118
+ elements.jsPattern.addEventListener("input", () =>
119
+ handleFieldChange("js", "pattern")
120
+ );
121
+
122
+ // CSS rule events
123
+ elements.cssRedirectUrl.addEventListener("input", () =>
124
+ handleFieldChange("css", "redirectUrl")
125
+ );
126
+ elements.cssReturnBlank.addEventListener("change", handleCssBlankToggle);
127
+ elements.cssUseCustomPattern.addEventListener("change", () =>
128
+ handleCustomPatternToggle("css")
129
+ );
130
+ elements.cssPattern.addEventListener("input", () =>
131
+ handleFieldChange("css", "pattern")
132
+ );
133
+
134
+ // Advanced settings toggle
135
+ elements.advancedHeader.addEventListener("click", toggleAdvancedSettings);
136
+
137
+ // Advanced settings checkboxes
138
+ elements.maskingMode.addEventListener("change", () =>
139
+ handleAdvancedSettingChange("maskingMode")
140
+ );
141
+ elements.clearCacheOnEnable.addEventListener("change", () =>
142
+ handleAdvancedSettingChange("clearCacheOnEnable")
143
+ );
144
+ elements.disableCacheForRedirects.addEventListener("change", () =>
145
+ handleAdvancedSettingChange("disableCacheForRedirects")
146
+ );
147
+
148
+ // Action buttons
149
+ elements.saveBtn.addEventListener("click", saveConfiguration);
150
+ elements.clearCacheBtn.addEventListener("click", clearCache);
151
+ }
152
+
153
+ // Load configuration from storage
154
+ async function loadConfiguration() {
155
+ try {
156
+ const result = await browser.runtime.sendMessage({ action: "getConfig" });
157
+ if (result) {
158
+ config = { ...DEFAULT_CONFIG, ...result };
159
+ // Ensure rules exist and have proper structure
160
+ config = migrateConfig(config);
161
+ }
162
+ console.log("[JavaScript Proxy] Loaded configuration:", config);
163
+ } catch (error) {
164
+ console.error("[JavaScript Proxy] Error loading configuration:", error);
165
+ showStatus("Error loading configuration: " + error.message, "error");
166
+ }
167
+ }
168
+
169
+ // Migrate legacy configuration to new rules format
170
+ function migrateConfig(config) {
171
+ // If rules don't exist, create them from legacy config
172
+ if (!config.rules) {
173
+ config.rules = {
174
+ js: {
175
+ enabled: true,
176
+ pattern: config.urlPattern || DEFAULT_CONFIG.rules.js.pattern,
177
+ redirectUrl: config.redirectUrl || DEFAULT_CONFIG.rules.js.redirectUrl,
178
+ useCustomPattern: config.useCustomPattern || false,
179
+ },
180
+ css: {
181
+ enabled: true,
182
+ pattern: DEFAULT_CONFIG.rules.css.pattern,
183
+ redirectUrl: "",
184
+ returnBlank: true,
185
+ useCustomPattern: false,
186
+ },
187
+ };
188
+ } else {
189
+ // Ensure all required fields exist
190
+ if (!config.rules.js) {
191
+ config.rules.js = {
192
+ enabled: true,
193
+ pattern: config.urlPattern || DEFAULT_CONFIG.rules.js.pattern,
194
+ redirectUrl: config.redirectUrl || DEFAULT_CONFIG.rules.js.redirectUrl,
195
+ useCustomPattern: config.useCustomPattern || false,
196
+ };
197
+ }
198
+ if (!config.rules.css) {
199
+ config.rules.css = {
200
+ enabled: true,
201
+ pattern: DEFAULT_CONFIG.rules.css.pattern,
202
+ redirectUrl: "",
203
+ returnBlank: true,
204
+ useCustomPattern: false,
205
+ };
206
+ }
207
+ }
208
+
209
+ return config;
210
+ }
211
+
212
+ // Update UI based on current configuration
213
+ function updateUI() {
214
+ // Update master toggle
215
+ elements.masterToggle.checked = config.enabled;
216
+ updateStatusInfo();
217
+
218
+ // Update rule toggles
219
+ elements.jsRuleToggle.checked = config.rules.js.enabled;
220
+ elements.cssRuleToggle.checked = config.rules.css.enabled;
221
+
222
+ // Update JavaScript rule fields
223
+ elements.jsRedirectUrl.value = config.rules.js.redirectUrl || "";
224
+ elements.jsUseCustomPattern.checked = config.rules.js.useCustomPattern;
225
+ elements.jsPattern.value = config.rules.js.pattern || "";
226
+
227
+ // Update CSS rule fields
228
+ elements.cssRedirectUrl.value = config.rules.css.redirectUrl || "";
229
+ elements.cssReturnBlank.checked = config.rules.css.returnBlank;
230
+ elements.cssUseCustomPattern.checked = config.rules.css.useCustomPattern;
231
+ elements.cssPattern.value = config.rules.css.pattern || "";
232
+
233
+ // Update advanced settings
234
+ elements.maskingMode.checked = config.maskingMode;
235
+ elements.clearCacheOnEnable.checked = config.clearCacheOnEnable;
236
+ elements.disableCacheForRedirects.checked = config.disableCacheForRedirects;
237
+
238
+ // Update UI visibility and states
239
+ updateRuleContainerStates();
240
+ updatePatternVisibility("js");
241
+ updatePatternVisibility("css");
242
+ updateCssRedirectVisibility();
243
+ updateSaveButtonState();
244
+ }
245
+
246
+ // Update status info text
247
+ function updateStatusInfo() {
248
+ const activeRules = [];
249
+ if (config.enabled) {
250
+ if (config.rules.js.enabled) activeRules.push("JS redirects");
251
+ if (config.rules.css.enabled) {
252
+ if (config.rules.css.returnBlank) {
253
+ activeRules.push("CSS blank returns");
254
+ } else {
255
+ activeRules.push("CSS redirects");
256
+ }
257
+ }
258
+ }
259
+
260
+ if (config.enabled && activeRules.length > 0) {
261
+ elements.statusInfo.textContent = `Extension is active: ${activeRules.join(
262
+ ", "
263
+ )}`;
264
+ } else if (config.enabled) {
265
+ elements.statusInfo.textContent =
266
+ "Extension is enabled but no rules are active";
267
+ } else {
268
+ elements.statusInfo.textContent = "Extension is currently disabled";
269
+ }
270
+ }
271
+
272
+ // Update rule container visual states
273
+ function updateRuleContainerStates() {
274
+ // Disable rule containers when master toggle is off
275
+ elements.jsRuleContainer.classList.toggle("disabled", !config.enabled);
276
+ elements.cssRuleContainer.classList.toggle("disabled", !config.enabled);
277
+ }
278
+
279
+ // Update pattern field visibility for a rule
280
+ function updatePatternVisibility(ruleType) {
281
+ const rule = config.rules[ruleType];
282
+ const patternGroup = elements[`${ruleType}PatternGroup`];
283
+
284
+ if (rule.useCustomPattern) {
285
+ patternGroup.classList.remove("hidden");
286
+ } else {
287
+ patternGroup.classList.add("hidden");
288
+ }
289
+ }
290
+
291
+ // Update CSS redirect URL visibility based on blank return setting
292
+ function updateCssRedirectVisibility() {
293
+ if (config.rules.css.returnBlank) {
294
+ elements.cssRedirectGroup.classList.add("hidden");
295
+ } else {
296
+ elements.cssRedirectGroup.classList.remove("hidden");
297
+ }
298
+ }
299
+
300
+ // Update save button state
301
+ function updateSaveButtonState() {
302
+ elements.saveBtn.disabled = !pendingChanges;
303
+ elements.saveBtn.textContent = pendingChanges ? "Save Changes" : "No Changes";
304
+ }
305
+
306
+ // Handle master toggle change
307
+ async function handleMasterToggle() {
308
+ const enabled = elements.masterToggle.checked;
309
+
310
+ try {
311
+ // Send toggle message to background script
312
+ const response = await browser.runtime.sendMessage({
313
+ action: "toggleProxy",
314
+ enabled: enabled,
315
+ });
316
+
317
+ if (response && response.success) {
318
+ config.enabled = enabled;
319
+ updateUI();
320
+ showStatus(
321
+ enabled
322
+ ? "Extension enabled successfully"
323
+ : "Extension disabled successfully",
324
+ "success"
325
+ );
326
+ } else {
327
+ throw new Error(response ? response.error : "Unknown error");
328
+ }
329
+ } catch (error) {
330
+ console.error("[JavaScript Proxy] Error toggling proxy:", error);
331
+ showStatus("Error toggling extension: " + error.message, "error");
332
+ // Revert the toggle
333
+ elements.masterToggle.checked = config.enabled;
334
+ }
335
+ }
336
+
337
+ // Handle rule toggle change
338
+ function handleRuleToggle(ruleType) {
339
+ const toggle = elements[`${ruleType}RuleToggle`];
340
+ config.rules[ruleType].enabled = toggle.checked;
341
+ setPendingChanges(true);
342
+ updateUI();
343
+ }
344
+
345
+ // Handle field changes
346
+ function handleFieldChange(ruleType, fieldName) {
347
+ const element =
348
+ elements[
349
+ `${ruleType}${fieldName.charAt(0).toUpperCase() + fieldName.slice(1)}`
350
+ ];
351
+ config.rules[ruleType][fieldName] = element.value;
352
+ setPendingChanges(true);
353
+ updateUI();
354
+ }
355
+
356
+ // Handle custom pattern toggle
357
+ function handleCustomPatternToggle(ruleType) {
358
+ const toggle = elements[`${ruleType}UseCustomPattern`];
359
+ config.rules[ruleType].useCustomPattern = toggle.checked;
360
+ setPendingChanges(true);
361
+ updatePatternVisibility(ruleType);
362
+ updateSaveButtonState();
363
+ }
364
+
365
+ // Handle CSS blank return toggle
366
+ function handleCssBlankToggle() {
367
+ config.rules.css.returnBlank = elements.cssReturnBlank.checked;
368
+ setPendingChanges(true);
369
+ updateCssRedirectVisibility();
370
+ updateUI();
371
+ }
372
+
373
+ // Handle advanced setting changes
374
+ function handleAdvancedSettingChange(settingName) {
375
+ config[settingName] = elements[settingName].checked;
376
+ setPendingChanges(true);
377
+ updateSaveButtonState();
378
+ }
379
+
380
+ // Toggle advanced settings panel
381
+ function toggleAdvancedSettings() {
382
+ const isHidden = elements.advancedContent.classList.contains("hidden");
383
+
384
+ if (isHidden) {
385
+ elements.advancedContent.classList.remove("hidden");
386
+ elements.advancedToggle.textContent = "Hide โ–ฒ";
387
+ } else {
388
+ elements.advancedContent.classList.add("hidden");
389
+ elements.advancedToggle.textContent = "Show โ–ผ";
390
+ }
391
+ }
392
+
393
+ // Set pending changes state
394
+ function setPendingChanges(hasPendingChanges) {
395
+ pendingChanges = hasPendingChanges;
396
+ updateSaveButtonState();
397
+ }
398
+
399
+ // Validate configuration
400
+ function validateConfig() {
401
+ const errors = [];
402
+
403
+ // Check JavaScript rule
404
+ if (config.rules.js.enabled) {
405
+ if (!config.rules.js.redirectUrl) {
406
+ errors.push(
407
+ "JavaScript redirect URL is required when JS rule is enabled"
408
+ );
409
+ } else {
410
+ try {
411
+ new URL(config.rules.js.redirectUrl);
412
+ } catch (e) {
413
+ errors.push("JavaScript redirect URL is not valid");
414
+ }
415
+ }
416
+
417
+ if (config.rules.js.useCustomPattern && !config.rules.js.pattern) {
418
+ errors.push(
419
+ "JavaScript custom pattern is required when custom pattern is enabled"
420
+ );
421
+ }
422
+
423
+ if (config.rules.js.pattern) {
424
+ try {
425
+ new RegExp(config.rules.js.pattern);
426
+ } catch (e) {
427
+ errors.push("JavaScript URL pattern is not a valid regular expression");
428
+ }
429
+ }
430
+ }
431
+
432
+ // Check CSS rule
433
+ if (config.rules.css.enabled) {
434
+ if (!config.rules.css.returnBlank && !config.rules.css.redirectUrl) {
435
+ errors.push(
436
+ "CSS redirect URL is required when CSS rule is enabled and not returning blank"
437
+ );
438
+ }
439
+
440
+ if (config.rules.css.redirectUrl) {
441
+ try {
442
+ new URL(config.rules.css.redirectUrl);
443
+ } catch (e) {
444
+ errors.push("CSS redirect URL is not valid");
445
+ }
446
+ }
447
+
448
+ if (config.rules.css.useCustomPattern && !config.rules.css.pattern) {
449
+ errors.push(
450
+ "CSS custom pattern is required when custom pattern is enabled"
451
+ );
452
+ }
453
+
454
+ if (config.rules.css.pattern) {
455
+ try {
456
+ new RegExp(config.rules.css.pattern);
457
+ } catch (e) {
458
+ errors.push("CSS URL pattern is not a valid regular expression");
459
+ }
460
+ }
461
+ }
462
+
463
+ return errors;
464
+ }
465
+
466
+ // Save configuration
467
+ async function saveConfiguration() {
468
+ if (!pendingChanges) return;
469
+
470
+ try {
471
+ // Validate configuration
472
+ const errors = validateConfig();
473
+ if (errors.length > 0) {
474
+ showStatus("Validation errors: " + errors.join(", "), "error");
475
+ return;
476
+ }
477
+
478
+ // Disable save button during save
479
+ elements.saveBtn.disabled = true;
480
+ elements.saveBtn.textContent = "Saving...";
481
+
482
+ // Send configuration to background script
483
+ const response = await browser.runtime.sendMessage({
484
+ action: "updateConfig",
485
+ config: config,
486
+ });
487
+
488
+ if (response && response.success) {
489
+ setPendingChanges(false);
490
+ showStatus("Configuration saved successfully", "success");
491
+ } else {
492
+ throw new Error(response ? response.error : "Unknown error");
493
+ }
494
+ } catch (error) {
495
+ console.error("[JavaScript Proxy] Error saving configuration:", error);
496
+ showStatus("Error saving configuration: " + error.message, "error");
497
+ } finally {
498
+ updateSaveButtonState();
499
+ }
500
+ }
501
+
502
+ // Clear cache
503
+ async function clearCache() {
504
+ try {
505
+ elements.clearCacheBtn.disabled = true;
506
+ elements.clearCacheBtn.textContent = "Clearing...";
507
+
508
+ const response = await browser.runtime.sendMessage({
509
+ action: "clearCache",
510
+ });
511
+
512
+ if (response && response.success) {
513
+ showStatus("Cache cleared successfully", "success");
514
+ } else {
515
+ throw new Error(response ? response.error : "Unknown error");
516
+ }
517
+ } catch (error) {
518
+ console.error("[JavaScript Proxy] Error clearing cache:", error);
519
+ showStatus("Error clearing cache: " + error.message, "error");
520
+ } finally {
521
+ elements.clearCacheBtn.disabled = false;
522
+ elements.clearCacheBtn.textContent = "Clear Cache";
523
+ }
524
+ }
525
+
526
+ // Show status message
527
+ function showStatus(message, type = "success") {
528
+ elements.statusMessage.textContent = message;
529
+ elements.statusMessage.className = `status-message status-${type}`;
530
+ elements.statusMessage.classList.remove("hidden");
531
+
532
+ // Auto-hide after 5 seconds
533
+ setTimeout(() => {
534
+ elements.statusMessage.classList.add("hidden");
535
+ }, 5000);
536
+ }
@@ -0,0 +1,126 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Test Gramercy.cloud Regex Pattern</title>
5
+ <style>
6
+ body { font-family: Arial, sans-serif; padding: 20px; max-width: 800px; }
7
+ .test-section { margin: 20px 0; padding: 20px; border: 2px solid #ddd; border-radius: 8px; }
8
+ .success { border-color: #28a745; background: #f8fff8; }
9
+ .warning { border-color: #ffc107; background: #fffbf0; }
10
+ .code { background: #e9ecef; padding: 8px; font-family: monospace; margin: 8px 0; word-break: break-all; }
11
+ .results { background: #f5f5f5; padding: 10px; margin: 10px 0; border-radius: 4px; }
12
+ button { padding: 10px 15px; margin: 5px; cursor: pointer; background: #007bff; color: white; border: none; border-radius: 4px; }
13
+ </style>
14
+ </head>
15
+ <body>
16
+ <h1>Gramercy.cloud Regex Test</h1>
17
+
18
+ <div class="test-section success">
19
+ <h2>โœ… Your Regex Pattern</h2>
20
+ <div class="code">([a-zA-Z0-9-]+\.)gramercy\.cloud\/uploads</div>
21
+ <p><strong>Target URL:</strong></p>
22
+ <div class="code">https://hilton-pop-art-cytz-dani-martin-hueg.gramercy.cloud/uploads/assets/5233/file_name/nU01Ln1738011172.png?URLPrefix=...</div>
23
+ </div>
24
+
25
+ <div class="test-section">
26
+ <h2>๐Ÿงช Regex Testing</h2>
27
+ <button onclick="testRegex()">Test Regex Match</button>
28
+ <button onclick="testActualRequest()">Test Actual XHR Request</button>
29
+ <div id="testResults" class="results"></div>
30
+ </div>
31
+
32
+ <div class="test-section warning">
33
+ <h2>โš™๏ธ Extension Setup Required</h2>
34
+ <ol>
35
+ <li>Open the Traffic Proxy extension popup</li>
36
+ <li>Add a new rule:</li>
37
+ <ul>
38
+ <li><strong>Pattern:</strong> <code>([a-zA-Z0-9-]+\.)gramercy\.cloud\/uploads</code></li>
39
+ <li><strong>Redirect To:</strong> <code>your-proxy-server.com</code></li>
40
+ </ul>
41
+ <li>Enable the proxy (green button)</li>
42
+ <li>Click "Test Actual XHR Request" below</li>
43
+ </ol>
44
+ </div>
45
+
46
+ <script>
47
+ function log(message) {
48
+ const results = document.getElementById('testResults');
49
+ const timestamp = new Date().toLocaleTimeString();
50
+ results.innerHTML += `<div>${timestamp}: ${message}</div>`;
51
+ }
52
+
53
+ function testRegex() {
54
+ const results = document.getElementById('testResults');
55
+ results.innerHTML = '';
56
+
57
+ const pattern = /([a-zA-Z0-9-]+\.)gramercy\.cloud\/uploads/i;
58
+ const testUrls = [
59
+ 'https://hilton-pop-art-cytz-dani-martin-hueg.gramercy.cloud/uploads/assets/5233/file_name/nU01Ln1738011172.png',
60
+ 'hilton-pop-art-cytz-dani-martin-hueg.gramercy.cloud', // hostname only
61
+ 'hilton-pop-art-cytz-dani-martin-hueg.gramercy.cloud/uploads', // hostname + path
62
+ 'other-subdomain.gramercy.cloud/uploads/test.jpg',
63
+ 'gramercy.cloud/uploads', // should NOT match (no subdomain)
64
+ 'hilton-pop-art-cytz-dani-martin-hueg.gramercy.cloud/downloads' // should NOT match (wrong path)
65
+ ];
66
+
67
+ log('๐Ÿงช Testing regex pattern against various URLs:');
68
+
69
+ testUrls.forEach(url => {
70
+ const matches = pattern.test(url);
71
+ const icon = matches ? 'โœ…' : 'โŒ';
72
+ log(`${icon} ${url} - ${matches ? 'MATCHES' : 'NO MATCH'}`);
73
+ });
74
+
75
+ log('');
76
+ log('๐Ÿ“ Summary: Your regex will match URLs with:');
77
+ log(' โ€ข Any subdomain of gramercy.cloud');
78
+ log(' โ€ข Path starting with /uploads');
79
+ log(' โ€ข Case insensitive matching');
80
+ }
81
+
82
+ async function testActualRequest() {
83
+ const results = document.getElementById('testResults');
84
+ results.innerHTML = '';
85
+
86
+ log('๐ŸŒ Testing actual XHR request to gramercy.cloud...');
87
+
88
+ // The exact URL from your example
89
+ const testUrl = 'https://hilton-pop-art-cytz-dani-martin-hueg.gramercy.cloud/uploads/assets/5233/file_name/nU01Ln1738011172.png?URLPrefix=aHR0cHM6Ly9oaWx0b24tcG9wLWFydC1jeXR6LWRhbmktbWFydGluLWh1ZWcuZ3JhbWVyY3kuY2xvdWQvdXBsb2Fkcy9hc3NldHMvNTIzMy9maWxlX25hbWU=&Expires=1749745178&KeyName=uploads-backend-key&Signature=s1rfbFVLZWNdagigcQxbRacOa4k=';
90
+
91
+ try {
92
+ log('๐Ÿ“ก Making XHR request...');
93
+
94
+ const xhr = new XMLHttpRequest();
95
+ xhr.onload = function() {
96
+ log(`โœ… XHR Success: ${xhr.status} ${xhr.statusText}`);
97
+ log(`๐Ÿ“ Response size: ${xhr.responseText.length} bytes`);
98
+ log('๐Ÿ” Check browser Network tab to see if request was intercepted');
99
+ log('๐Ÿ”” You should see a proxy notification if extension is working');
100
+ };
101
+
102
+ xhr.onerror = function() {
103
+ log('โŒ XHR failed - this might be expected if proxy redirected');
104
+ log('๐Ÿ” Check browser Network tab to see actual destination');
105
+ };
106
+
107
+ xhr.ontimeout = function() {
108
+ log('โฐ XHR timed out');
109
+ };
110
+
111
+ xhr.open('GET', testUrl);
112
+ xhr.timeout = 10000; // 10 second timeout
113
+ xhr.send();
114
+
115
+ } catch (error) {
116
+ log(`โŒ Error making request: ${error.message}`);
117
+ }
118
+ }
119
+
120
+ // Auto-run regex test on page load
121
+ window.addEventListener('load', function() {
122
+ testRegex();
123
+ });
124
+ </script>
125
+ </body>
126
+ </html>