content-security-toolkit 1.0.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/LICENSE +9 -0
- package/README.md +171 -0
- package/dist/config/default-extensions-config.json +103 -0
- package/dist/core/ContentProtector.d.ts +63 -0
- package/dist/core/ContentProtector.js +279 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +2 -0
- package/dist/core/mediator/ContentProtectionMediator.d.ts +86 -0
- package/dist/core/mediator/ContentProtectionMediator.js +238 -0
- package/dist/core/mediator/eventDataTypes.d.ts +205 -0
- package/dist/core/mediator/eventDataTypes.js +23 -0
- package/dist/core/mediator/handlers/abstractEventHandler.d.ts +67 -0
- package/dist/core/mediator/handlers/abstractEventHandler.js +106 -0
- package/dist/core/mediator/handlers/baseEventHandler.d.ts +65 -0
- package/dist/core/mediator/handlers/baseEventHandler.js +99 -0
- package/dist/core/mediator/handlers/devToolsEventHandler.d.ts +9 -0
- package/dist/core/mediator/handlers/devToolsEventHandler.js +95 -0
- package/dist/core/mediator/handlers/eventHandlerRegistry.d.ts +9 -0
- package/dist/core/mediator/handlers/eventHandlerRegistry.js +34 -0
- package/dist/core/mediator/handlers/extensionEventHandlers.d.ts +40 -0
- package/dist/core/mediator/handlers/extensionEventHandlers.js +140 -0
- package/dist/core/mediator/handlers/iFrameEventHandlers.d.ts +27 -0
- package/dist/core/mediator/handlers/iFrameEventHandlers.js +93 -0
- package/dist/core/mediator/handlers/index.d.ts +9 -0
- package/dist/core/mediator/handlers/index.js +34 -0
- package/dist/core/mediator/handlers/screenShotEventHandlers.d.ts +34 -0
- package/dist/core/mediator/handlers/screenShotEventHandlers.js +111 -0
- package/dist/core/mediator/protection-event.d.ts +94 -0
- package/dist/core/mediator/protection-event.js +43 -0
- package/dist/core/mediator/types.d.ts +105 -0
- package/dist/core/mediator/types.js +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +5 -0
- package/dist/strategies/AbstractStrategy.d.ts +152 -0
- package/dist/strategies/AbstractStrategy.js +296 -0
- package/dist/strategies/AbstractStrategy.mediator.d.ts +162 -0
- package/dist/strategies/AbstractStrategy.mediator.js +349 -0
- package/dist/strategies/ClipboardStrategy.d.ts +67 -0
- package/dist/strategies/ClipboardStrategy.js +291 -0
- package/dist/strategies/ContextMenuStrategy.d.ts +60 -0
- package/dist/strategies/ContextMenuStrategy.js +454 -0
- package/dist/strategies/DevToolsStrategy copy.d.ts +85 -0
- package/dist/strategies/DevToolsStrategy copy.js +362 -0
- package/dist/strategies/DevToolsStrategy-detectorManager.d.ts +70 -0
- package/dist/strategies/DevToolsStrategy-detectorManager.js +309 -0
- package/dist/strategies/DevToolsStrategy-simple.d.ts +75 -0
- package/dist/strategies/DevToolsStrategy-simple.js +366 -0
- package/dist/strategies/DevToolsStrategy.d.ts +55 -0
- package/dist/strategies/DevToolsStrategy.js +314 -0
- package/dist/strategies/ExtensionStrategy.d.ts +66 -0
- package/dist/strategies/ExtensionStrategy.js +486 -0
- package/dist/strategies/IFrameStrategy.d.ts +49 -0
- package/dist/strategies/IFrameStrategy.js +255 -0
- package/dist/strategies/KeyboardStrategy.d.ts +35 -0
- package/dist/strategies/KeyboardStrategy.js +130 -0
- package/dist/strategies/PrintStrategy.d.ts +47 -0
- package/dist/strategies/PrintStrategy.js +201 -0
- package/dist/strategies/ScreenshotStrategy.d.ts +90 -0
- package/dist/strategies/ScreenshotStrategy.js +488 -0
- package/dist/strategies/SelectionStrategy.d.ts +49 -0
- package/dist/strategies/SelectionStrategy.js +216 -0
- package/dist/strategies/StrategyRegistry.d.ts +133 -0
- package/dist/strategies/StrategyRegistry.js +379 -0
- package/dist/strategies/WatermarkStrategy.d.ts +47 -0
- package/dist/strategies/WatermarkStrategy.js +273 -0
- package/dist/strategies/index.d.ts +9 -0
- package/dist/strategies/index.js +10 -0
- package/dist/types/index.d.ts +271 -0
- package/dist/types/index.js +16 -0
- package/dist/utils/DOMObserver.d.ts +68 -0
- package/dist/utils/DOMObserver.js +134 -0
- package/dist/utils/base/LoggableComponent.d.ts +62 -0
- package/dist/utils/base/LoggableComponent.js +95 -0
- package/dist/utils/debuggerDetector/debuggerDetectionWorker.d.ts +6 -0
- package/dist/utils/debuggerDetector/debuggerDetectionWorker.js +24 -0
- package/dist/utils/debuggerDetector/debuggerDetector.d.ts +55 -0
- package/dist/utils/debuggerDetector/debuggerDetector.js +158 -0
- package/dist/utils/debuggerDetector/firefoxDetector.d.ts +8 -0
- package/dist/utils/debuggerDetector/firefoxDetector.js +64 -0
- package/dist/utils/detection.d.ts +29 -0
- package/dist/utils/detection.js +267 -0
- package/dist/utils/detectors/AbstractDevToolsDetector.d.ts +105 -0
- package/dist/utils/detectors/AbstractDevToolsDetector.js +136 -0
- package/dist/utils/detectors/dateToStringDetector.d.ts +43 -0
- package/dist/utils/detectors/dateToStringDetector.js +96 -0
- package/dist/utils/detectors/debugLibDetector.d.ts +64 -0
- package/dist/utils/detectors/debugLibDetector.js +195 -0
- package/dist/utils/detectors/debuggerDetectionWorker.d.ts +6 -0
- package/dist/utils/detectors/debuggerDetectionWorker.js +24 -0
- package/dist/utils/detectors/debuggerDetector.d.ts +51 -0
- package/dist/utils/detectors/debuggerDetector.js +211 -0
- package/dist/utils/detectors/defineGetterDetector.d.ts +48 -0
- package/dist/utils/detectors/defineGetterDetector.js +150 -0
- package/dist/utils/detectors/detectorInterface.d.ts +36 -0
- package/dist/utils/detectors/detectorInterface.js +1 -0
- package/dist/utils/detectors/devToolsDetectorManager.d.ts +88 -0
- package/dist/utils/detectors/devToolsDetectorManager.js +246 -0
- package/dist/utils/detectors/firefoxDetector.d.ts +8 -0
- package/dist/utils/detectors/firefoxDetector.js +64 -0
- package/dist/utils/detectors/funcToStringDetector.d.ts +43 -0
- package/dist/utils/detectors/funcToStringDetector.js +90 -0
- package/dist/utils/detectors/regToStringDetector.d.ts +43 -0
- package/dist/utils/detectors/regToStringDetector.js +129 -0
- package/dist/utils/detectors/sizeDetector.d.ts +54 -0
- package/dist/utils/detectors/sizeDetector.js +134 -0
- package/dist/utils/detectors/timingDetector.d.ts +55 -0
- package/dist/utils/detectors/timingDetector.js +143 -0
- package/dist/utils/dom.d.ts +20 -0
- package/dist/utils/dom.js +83 -0
- package/dist/utils/environment.d.ts +29 -0
- package/dist/utils/environment.js +267 -0
- package/dist/utils/eventManager.d.ts +167 -0
- package/dist/utils/eventManager.js +556 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/intervalManager.d.ts +96 -0
- package/dist/utils/intervalManager.js +229 -0
- package/dist/utils/keyboardShortcutManager/keyboardShortcutManager.d.ts +41 -0
- package/dist/utils/keyboardShortcutManager/keyboardShortcutManager.js +135 -0
- package/dist/utils/keyboardShortcutManager/keyboardShortcuts.d.ts +18 -0
- package/dist/utils/keyboardShortcutManager/keyboardShortcuts.js +195 -0
- package/dist/utils/logging/LogLevel.d.ts +21 -0
- package/dist/utils/logging/LogLevel.js +46 -0
- package/dist/utils/logging/LoggingConfig.d.ts +68 -0
- package/dist/utils/logging/LoggingConfig.js +64 -0
- package/dist/utils/logging/LoggingFactory.d.ts +22 -0
- package/dist/utils/logging/LoggingFactory.js +61 -0
- package/dist/utils/logging/LoggingService.d.ts +235 -0
- package/dist/utils/logging/LoggingService.js +385 -0
- package/dist/utils/logging/SimpleLoggingService.d.ts +39 -0
- package/dist/utils/logging/SimpleLoggingService.js +58 -0
- package/dist/utils/logging/advanced/LogLevel.d.ts +21 -0
- package/dist/utils/logging/advanced/LogLevel.js +46 -0
- package/dist/utils/logging/advanced/LoggingConfig.d.ts +68 -0
- package/dist/utils/logging/advanced/LoggingConfig.js +64 -0
- package/dist/utils/logging/advanced/LoggingFactory.d.ts +22 -0
- package/dist/utils/logging/advanced/LoggingFactory.js +61 -0
- package/dist/utils/logging/advanced/LoggingService.d.ts +235 -0
- package/dist/utils/logging/advanced/LoggingService.js +385 -0
- package/dist/utils/logging/simple/Loggable.d.ts +33 -0
- package/dist/utils/logging/simple/Loggable.js +1 -0
- package/dist/utils/logging/simple/LoggingDelegate.d.ts +42 -0
- package/dist/utils/logging/simple/LoggingDelegate.js +53 -0
- package/dist/utils/logging/simple/SimpleLoggingService.d.ts +39 -0
- package/dist/utils/logging/simple/SimpleLoggingService.js +58 -0
- package/dist/utils/orientation.d.ts +15 -0
- package/dist/utils/orientation.js +32 -0
- package/dist/utils/protectedContentManager-simple.d.ts +86 -0
- package/dist/utils/protectedContentManager-simple.js +180 -0
- package/dist/utils/protectedContentManager.d.ts +162 -0
- package/dist/utils/protectedContentManager.js +427 -0
- package/dist/utils/screenshotDetector.d.ts +72 -0
- package/dist/utils/screenshotDetector.js +179 -0
- package/dist/utils/securityOverlayManager-observer-pause.d.ts +283 -0
- package/dist/utils/securityOverlayManager-observer-pause.js +878 -0
- package/dist/utils/securityOverlayManager-simple.d.ts +197 -0
- package/dist/utils/securityOverlayManager-simple.js +552 -0
- package/dist/utils/securityOverlayManager.d.ts +260 -0
- package/dist/utils/securityOverlayManager.js +774 -0
- package/dist/utils/timeoutManager.d.ts +55 -0
- package/dist/utils/timeoutManager.js +121 -0
- package/package.json +54 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { isBrowser, getBrowser } from "../environment";
|
|
2
|
+
import { eventManager } from "../eventManager";
|
|
3
|
+
import { AbstractDevToolsDetector, DetectorErrorType } from "./AbstractDevToolsDetector";
|
|
4
|
+
/**
|
|
5
|
+
* Utility class for detecting DevTools using window size differences
|
|
6
|
+
* This approach works by detecting unusual differences between outer and inner window dimensions
|
|
7
|
+
* that typically occur when DevTools are open
|
|
8
|
+
*/
|
|
9
|
+
export class SizeDetector extends AbstractDevToolsDetector {
|
|
10
|
+
/**
|
|
11
|
+
* Create a new SizeDetector
|
|
12
|
+
* @param options Configuration options
|
|
13
|
+
*/
|
|
14
|
+
constructor(options = {}) {
|
|
15
|
+
super("SizeDetector", options);
|
|
16
|
+
this.resizeEventId = "";
|
|
17
|
+
this.widthThreshold = options.widthThreshold || 200;
|
|
18
|
+
this.heightThreshold = options.heightThreshold || 300;
|
|
19
|
+
// Initialize resize listener
|
|
20
|
+
this.initResizeListener();
|
|
21
|
+
this.logger.log(`Initialized with thresholds - width: ${this.widthThreshold}px, height: ${this.heightThreshold}px`);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Initialize resize event listener
|
|
25
|
+
*/
|
|
26
|
+
initResizeListener() {
|
|
27
|
+
this.safeExecute("initResizeListener", DetectorErrorType.INITIALIZATION_ERROR, () => {
|
|
28
|
+
if (!isBrowser())
|
|
29
|
+
return;
|
|
30
|
+
// Create resize handler
|
|
31
|
+
const resizeHandler = () => {
|
|
32
|
+
// Use setTimeout to avoid too many checks during resize
|
|
33
|
+
setTimeout(() => {
|
|
34
|
+
this.checkDevTools();
|
|
35
|
+
}, 100);
|
|
36
|
+
};
|
|
37
|
+
// Register resize event using eventManager
|
|
38
|
+
this.resizeEventId = eventManager.addEventListener(window, "resize", resizeHandler, "SizeDetector", {
|
|
39
|
+
passive: true,
|
|
40
|
+
priority: 5, // Medium-high priority
|
|
41
|
+
});
|
|
42
|
+
// Perform initial check
|
|
43
|
+
this.checkDevTools();
|
|
44
|
+
this.logger.log(`Resize listener initialized with event ID: ${this.resizeEventId}`);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Calculate screen zoom ratio
|
|
49
|
+
* @returns The screen zoom ratio or false if it can't be determined
|
|
50
|
+
*/
|
|
51
|
+
getScreenZoomRatio() {
|
|
52
|
+
return (this.safeExecute("getScreenZoomRatio", DetectorErrorType.DETECTION_ERROR, () => {
|
|
53
|
+
if (!isBrowser())
|
|
54
|
+
return false;
|
|
55
|
+
// Try to use devicePixelRatio first (most reliable)
|
|
56
|
+
if (typeof window.devicePixelRatio !== "undefined") {
|
|
57
|
+
return window.devicePixelRatio;
|
|
58
|
+
}
|
|
59
|
+
// Fallback to screen properties for older browsers
|
|
60
|
+
const screen = window.screen;
|
|
61
|
+
if (!screen)
|
|
62
|
+
return false;
|
|
63
|
+
if (screen.deviceXDPI && screen.logicalXDPI) {
|
|
64
|
+
return screen.deviceXDPI / screen.logicalXDPI;
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
}) || false);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Check if DevTools is open using window size differences
|
|
71
|
+
*/
|
|
72
|
+
checkDevTools() {
|
|
73
|
+
if (this.isChecking || !isBrowser())
|
|
74
|
+
return;
|
|
75
|
+
this.isChecking = true;
|
|
76
|
+
this.safeExecute("checkDevTools", DetectorErrorType.DETECTION_ERROR, () => {
|
|
77
|
+
// Get screen zoom ratio
|
|
78
|
+
const screenRatio = this.getScreenZoomRatio();
|
|
79
|
+
// If we can't get the screen ratio, we can't reliably detect
|
|
80
|
+
if (screenRatio === false) {
|
|
81
|
+
this.isChecking = false;
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
// Calculate size differences accounting for zoom
|
|
85
|
+
const widthDiff = window.outerWidth - window.innerWidth * screenRatio;
|
|
86
|
+
const heightDiff = window.outerHeight - window.innerHeight * screenRatio;
|
|
87
|
+
// Check if differences exceed thresholds
|
|
88
|
+
const widthUneven = widthDiff > this.widthThreshold;
|
|
89
|
+
const heightUneven = heightDiff > this.heightThreshold;
|
|
90
|
+
// DevTools is considered open if either dimension is uneven
|
|
91
|
+
const isOpen = widthUneven || heightUneven;
|
|
92
|
+
// Log detailed size information in debug mode
|
|
93
|
+
this.logger.log(`Window sizes - outer: ${window.outerWidth}x${window.outerHeight}, inner: ${window.innerWidth}x${window.innerHeight}, zoom: ${screenRatio}`);
|
|
94
|
+
this.logger.log(`Size differences - width: ${widthDiff.toFixed(2)}px, height: ${heightDiff.toFixed(2)}px`);
|
|
95
|
+
// Update DevTools state and notify listeners if changed
|
|
96
|
+
this.updateDevToolsState(isOpen);
|
|
97
|
+
this.isChecking = false;
|
|
98
|
+
});
|
|
99
|
+
// Ensure isChecking is reset even if an error occurs
|
|
100
|
+
if (this.isChecking) {
|
|
101
|
+
this.isChecking = false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Clean up resources
|
|
106
|
+
*/
|
|
107
|
+
dispose() {
|
|
108
|
+
this.safeExecute("dispose", DetectorErrorType.DISPOSAL_ERROR, () => {
|
|
109
|
+
if (isBrowser() && this.resizeEventId) {
|
|
110
|
+
// Remove the resize event listener using eventManager
|
|
111
|
+
eventManager.removeEventListener(window, this.resizeEventId);
|
|
112
|
+
this.resizeEventId = "";
|
|
113
|
+
this.logger.log("Removed resize event listener");
|
|
114
|
+
this.logger.log("Disposed");
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
super.dispose();
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Check if this detector is supported in the current browser
|
|
121
|
+
* @returns True if supported
|
|
122
|
+
*/
|
|
123
|
+
static isSupported() {
|
|
124
|
+
if (!isBrowser())
|
|
125
|
+
return false;
|
|
126
|
+
const browser = getBrowser();
|
|
127
|
+
const isIframe = window.self !== window.top;
|
|
128
|
+
// Not supported in iframes or Edge
|
|
129
|
+
if (isIframe || browser.name === "edge") {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { AbstractDevToolsDetector } from "./AbstractDevToolsDetector";
|
|
2
|
+
import { DevToolsDetectorOptions } from "./detectorInterface";
|
|
3
|
+
/**
|
|
4
|
+
* Options for the TimingDetector
|
|
5
|
+
*/
|
|
6
|
+
export interface TimingDetectorOptions extends DevToolsDetectorOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Threshold multiplier for detection
|
|
9
|
+
* Higher values make detection less sensitive
|
|
10
|
+
*/
|
|
11
|
+
thresholdMultiplier?: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Utility class for detecting DevTools using console timing differences
|
|
15
|
+
* This approach works especially well in Firefox
|
|
16
|
+
*/
|
|
17
|
+
export declare class TimingDetector extends AbstractDevToolsDetector {
|
|
18
|
+
private largeObjectArray;
|
|
19
|
+
private maxPrintTime;
|
|
20
|
+
private thresholdMultiplier;
|
|
21
|
+
/**
|
|
22
|
+
* Create a new TimingDetector
|
|
23
|
+
* @param options Configuration options
|
|
24
|
+
*/
|
|
25
|
+
constructor(options?: TimingDetectorOptions);
|
|
26
|
+
/**
|
|
27
|
+
* Initialize the large object array used for timing tests
|
|
28
|
+
*/
|
|
29
|
+
private initLargeObjectArray;
|
|
30
|
+
/**
|
|
31
|
+
* Create a large object for timing tests
|
|
32
|
+
*/
|
|
33
|
+
private createLargeObject;
|
|
34
|
+
/**
|
|
35
|
+
* Create an array of large objects for timing tests
|
|
36
|
+
*/
|
|
37
|
+
private createLargeObjectArray;
|
|
38
|
+
/**
|
|
39
|
+
* Calculate execution time of a function
|
|
40
|
+
*/
|
|
41
|
+
private calculateTime;
|
|
42
|
+
/**
|
|
43
|
+
* Check if DevTools is open using console timing
|
|
44
|
+
*/
|
|
45
|
+
checkDevTools(): void;
|
|
46
|
+
/**
|
|
47
|
+
* Clean up resources
|
|
48
|
+
*/
|
|
49
|
+
dispose(): void;
|
|
50
|
+
/**
|
|
51
|
+
* Check if this detector is supported in the current browser
|
|
52
|
+
* @returns True if supported
|
|
53
|
+
*/
|
|
54
|
+
static isSupported(): boolean;
|
|
55
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { getBrowser, isBrowser, isMobile } from "../environment";
|
|
2
|
+
import { AbstractDevToolsDetector, DetectorErrorType } from "./AbstractDevToolsDetector";
|
|
3
|
+
/**
|
|
4
|
+
* Utility class for detecting DevTools using console timing differences
|
|
5
|
+
* This approach works especially well in Firefox
|
|
6
|
+
*/
|
|
7
|
+
export class TimingDetector extends AbstractDevToolsDetector {
|
|
8
|
+
/**
|
|
9
|
+
* Create a new TimingDetector
|
|
10
|
+
* @param options Configuration options
|
|
11
|
+
*/
|
|
12
|
+
constructor(options = {}) {
|
|
13
|
+
super("TimingDetector", options);
|
|
14
|
+
this.largeObjectArray = [];
|
|
15
|
+
this.maxPrintTime = 0;
|
|
16
|
+
this.thresholdMultiplier = options.thresholdMultiplier || 10; //DIFFERENCE BETWEEN .log AND .table
|
|
17
|
+
// Initialize the large object array
|
|
18
|
+
this.initLargeObjectArray();
|
|
19
|
+
this.logger.log("Initialized with threshold multiplier:", this.thresholdMultiplier);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Initialize the large object array used for timing tests
|
|
23
|
+
*/
|
|
24
|
+
initLargeObjectArray() {
|
|
25
|
+
this.safeExecute("initLargeObjectArray", DetectorErrorType.INITIALIZATION_ERROR, () => {
|
|
26
|
+
if (!isBrowser())
|
|
27
|
+
return;
|
|
28
|
+
this.largeObjectArray = this.createLargeObjectArray();
|
|
29
|
+
this.maxPrintTime = 0;
|
|
30
|
+
this.logger.log("Large object array initialized with size:", this.largeObjectArray.length);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Create a large object for timing tests
|
|
35
|
+
*/
|
|
36
|
+
createLargeObject() {
|
|
37
|
+
return (this.safeExecute("createLargeObject", DetectorErrorType.INITIALIZATION_ERROR, () => {
|
|
38
|
+
const largeObject = {};
|
|
39
|
+
for (let i = 0; i < 500; i++) {
|
|
40
|
+
largeObject[`${i}`] = `${i}`;
|
|
41
|
+
}
|
|
42
|
+
return largeObject;
|
|
43
|
+
}) || {});
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Create an array of large objects for timing tests
|
|
47
|
+
*/
|
|
48
|
+
createLargeObjectArray() {
|
|
49
|
+
return (this.safeExecute("createLargeObjectArray", DetectorErrorType.INITIALIZATION_ERROR, () => {
|
|
50
|
+
const largeObject = this.createLargeObject();
|
|
51
|
+
const largeObjectArray = [];
|
|
52
|
+
for (let i = 0; i < 50; i++) {
|
|
53
|
+
largeObjectArray.push(largeObject);
|
|
54
|
+
}
|
|
55
|
+
return largeObjectArray;
|
|
56
|
+
}) || []);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Calculate execution time of a function
|
|
60
|
+
*/
|
|
61
|
+
calculateTime(func) {
|
|
62
|
+
return (this.safeExecute("calculateTime", DetectorErrorType.DETECTION_ERROR, () => {
|
|
63
|
+
const start = performance.now();
|
|
64
|
+
func();
|
|
65
|
+
return performance.now() - start;
|
|
66
|
+
}) || 0);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Check if DevTools is open using console timing
|
|
70
|
+
*/
|
|
71
|
+
checkDevTools() {
|
|
72
|
+
if (this.isChecking || !isBrowser())
|
|
73
|
+
return;
|
|
74
|
+
this.isChecking = true;
|
|
75
|
+
this.safeExecute("checkDevTools", DetectorErrorType.DETECTION_ERROR, () => {
|
|
76
|
+
// Measure time to print large object array using console.table
|
|
77
|
+
const tablePrintTime = this.calculateTime(() => {
|
|
78
|
+
console.table(this.largeObjectArray.slice(0, 8)); // Use a smaller slice to avoid freezing
|
|
79
|
+
});
|
|
80
|
+
// Measure time to print large object array using console.log
|
|
81
|
+
const logPrintTime = this.calculateTime(() => {
|
|
82
|
+
console.log(this.largeObjectArray.slice(0, 8)); // Use a smaller slice to avoid freezing
|
|
83
|
+
});
|
|
84
|
+
// Update max print time
|
|
85
|
+
this.maxPrintTime = Math.max(this.maxPrintTime, logPrintTime);
|
|
86
|
+
// Clear console
|
|
87
|
+
console.clear();
|
|
88
|
+
// Skip detection if we don't have valid measurements yet
|
|
89
|
+
if (tablePrintTime === 0 || this.maxPrintTime === 0) {
|
|
90
|
+
this.isChecking = false;
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
// If table print time is significantly higher than max log print time,
|
|
94
|
+
// DevTools is likely open
|
|
95
|
+
const isOpen = tablePrintTime > this.maxPrintTime * this.thresholdMultiplier;
|
|
96
|
+
// Update state and notify listeners if changed
|
|
97
|
+
this.updateDevToolsState(isOpen);
|
|
98
|
+
this.logger.log(`Timing check - table: ${tablePrintTime.toFixed(2)}ms, log: ${logPrintTime.toFixed(2)}ms, max: ${this.maxPrintTime.toFixed(2)}ms, ratio: ${(tablePrintTime / this.maxPrintTime).toFixed(2)}x`);
|
|
99
|
+
this.isChecking = false;
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Clean up resources
|
|
104
|
+
*/
|
|
105
|
+
dispose() {
|
|
106
|
+
this.safeExecute("dispose", DetectorErrorType.DISPOSAL_ERROR, () => {
|
|
107
|
+
this.largeObjectArray = [];
|
|
108
|
+
this.maxPrintTime = 0;
|
|
109
|
+
this.logger.log("Disposed");
|
|
110
|
+
});
|
|
111
|
+
super.dispose();
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Check if this detector is supported in the current browser
|
|
115
|
+
* @returns True if supported
|
|
116
|
+
*/
|
|
117
|
+
static isSupported() {
|
|
118
|
+
if (!isBrowser())
|
|
119
|
+
return false;
|
|
120
|
+
// Check if required console methods exist
|
|
121
|
+
if (typeof console === "undefined" || typeof console.table !== "function" || typeof console.log !== "function") {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
// Check if performance API is available
|
|
125
|
+
if (typeof performance === "undefined" || typeof performance.now !== "function") {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
// Get browser info
|
|
129
|
+
const browser = getBrowser();
|
|
130
|
+
const isMobileDevice = isMobile();
|
|
131
|
+
// This detector works best in Firefox and desktop browsers
|
|
132
|
+
// It's less reliable in mobile browsers and some WebKit browsers
|
|
133
|
+
// Not recommended for mobile Chrome or Edge
|
|
134
|
+
if (isMobileDevice && (browser.name === "chrome" || browser.name === "edge")) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
// Not recommended for Safari (desktop or mobile) as it has inconsistent timing behavior
|
|
138
|
+
if (browser.name === "safari") {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safely add event listener with error handling
|
|
3
|
+
*/
|
|
4
|
+
export declare const safeAddEventListener: (element: HTMLElement | Document | Window, event: string, handler: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions) => boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Safely remove event listener with error handling
|
|
7
|
+
*/
|
|
8
|
+
export declare const safeRemoveEventListener: (element: HTMLElement | Document | Window, event: string, handler: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions) => boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Create and inject a style element
|
|
11
|
+
*/
|
|
12
|
+
export declare const injectStyles: (css: string, id?: string) => HTMLStyleElement | null;
|
|
13
|
+
/**
|
|
14
|
+
* Remove a style element by ID
|
|
15
|
+
*/
|
|
16
|
+
export declare const removeStyles: (id: string) => boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Create an element with attributes and styles
|
|
19
|
+
*/
|
|
20
|
+
export declare const createElement: <T extends HTMLElement>(tag: string, attributes?: Record<string, string>, styles?: Partial<CSSStyleDeclaration>) => T;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// DOM UTILITIES
|
|
2
|
+
/**
|
|
3
|
+
* Safely add event listener with error handling
|
|
4
|
+
*/
|
|
5
|
+
export const safeAddEventListener = (element, event, handler, options) => {
|
|
6
|
+
try {
|
|
7
|
+
element.addEventListener(event, handler, options);
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
console.error(`Failed to add event listener for ${event}:`, error);
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Safely remove event listener with error handling
|
|
17
|
+
*/
|
|
18
|
+
export const safeRemoveEventListener = (element, event, handler, options) => {
|
|
19
|
+
try {
|
|
20
|
+
element.removeEventListener(event, handler, options);
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
console.error(`Failed to remove event listener for ${event}:`, error);
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Create and inject a style element
|
|
30
|
+
*/
|
|
31
|
+
export const injectStyles = (css, id) => {
|
|
32
|
+
if (typeof document === 'undefined')
|
|
33
|
+
return null;
|
|
34
|
+
try {
|
|
35
|
+
const style = document.createElement('style');
|
|
36
|
+
style.setAttribute('type', 'text/css');
|
|
37
|
+
if (id) {
|
|
38
|
+
style.id = id;
|
|
39
|
+
}
|
|
40
|
+
style.textContent = css;
|
|
41
|
+
document.head.appendChild(style);
|
|
42
|
+
return style;
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
console.error('Failed to inject styles:', error);
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Remove a style element by ID
|
|
51
|
+
*/
|
|
52
|
+
export const removeStyles = (id) => {
|
|
53
|
+
if (typeof document === 'undefined')
|
|
54
|
+
return false;
|
|
55
|
+
try {
|
|
56
|
+
const style = document.getElementById(id);
|
|
57
|
+
if (style && style.parentNode) {
|
|
58
|
+
style.parentNode.removeChild(style);
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
console.error(`Failed to remove styles with ID ${id}:`, error);
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Create an element with attributes and styles
|
|
70
|
+
*/
|
|
71
|
+
export const createElement = (tag, attributes = {}, styles = {}) => {
|
|
72
|
+
if (typeof document === 'undefined') {
|
|
73
|
+
throw new Error('Document is not available');
|
|
74
|
+
}
|
|
75
|
+
const element = document.createElement(tag);
|
|
76
|
+
// Set attributes
|
|
77
|
+
Object.entries(attributes).forEach(([key, value]) => {
|
|
78
|
+
element.setAttribute(key, value);
|
|
79
|
+
});
|
|
80
|
+
// Set styles
|
|
81
|
+
Object.assign(element.style, styles);
|
|
82
|
+
return element;
|
|
83
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect browser environment
|
|
3
|
+
*/
|
|
4
|
+
export declare const isBrowser: () => boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Detect mobile device
|
|
7
|
+
*/
|
|
8
|
+
export declare const isMobile: () => boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Detect specific browser
|
|
11
|
+
*/
|
|
12
|
+
export declare const getBrowser: () => {
|
|
13
|
+
name: string;
|
|
14
|
+
version: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Detect operating system
|
|
18
|
+
*/
|
|
19
|
+
export declare const getOS: () => {
|
|
20
|
+
name: "mac" | "linux" | "windows" | "unknown";
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Check if print is supported
|
|
24
|
+
*/
|
|
25
|
+
export declare const isPrintSupported: () => boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Check if beforeprint event is supported
|
|
28
|
+
*/
|
|
29
|
+
export declare const isBeforePrintSupported: () => boolean;
|