22 * @file Module for intercepting console logs with stack trace capture
33 */
44import safeStringify from 'safe-stringify' ;
5- import { ConsoleLogEvent } from '@hawk.so/types' ;
5+ import type { ConsoleLogEvent } from '@hawk.so/types' ;
66
77/**
88 * Console interceptor that captures and formats console output
@@ -13,6 +13,72 @@ export class ConsoleCatcher {
1313 private isInitialized = false ;
1414 private isProcessing = false ;
1515
16+ /**
17+ * Initializes the console interceptor by overriding default console methods
18+ */
19+ public init ( ) : void {
20+ if ( this . isInitialized ) {
21+ return ;
22+ }
23+
24+ this . isInitialized = true ;
25+ const consoleMethods : string [ ] = [ 'log' , 'warn' , 'error' , 'info' , 'debug' ] ;
26+
27+ consoleMethods . forEach ( ( method ) => {
28+ if ( typeof window . console [ method ] !== 'function' ) {
29+ return ;
30+ }
31+
32+ const oldFunction = window . console [ method ] . bind ( window . console ) ;
33+
34+ window . console [ method ] = ( ...args : unknown [ ] ) : void => {
35+ // Prevent recursive calls
36+ if ( this . isProcessing ) {
37+ return oldFunction ( ...args ) ;
38+ }
39+
40+ /**
41+ * If the console call originates from Vue's internal runtime bundle, skip interception
42+ * to avoid capturing Vue-internal warnings and causing recursive loops.
43+ */
44+ const rawStack = new Error ( ) . stack || '' ;
45+ if ( rawStack . includes ( 'runtime-core.esm-bundler.js' ) ) {
46+ return oldFunction ( ...args ) ;
47+ }
48+
49+ // Additional protection against Hawk internal calls
50+ if ( rawStack . includes ( 'hawk.javascript' ) || rawStack . includes ( '@hawk.so' ) ) {
51+ return oldFunction ( ...args ) ;
52+ }
53+
54+ this . isProcessing = true ;
55+
56+ try {
57+ const stack = new Error ( ) . stack ?. split ( '\n' ) . slice ( 2 ) . join ( '\n' ) || '' ;
58+ const { message, styles } = this . formatConsoleArgs ( args ) ;
59+
60+ const logEvent : ConsoleLogEvent = {
61+ method,
62+ timestamp : new Date ( ) ,
63+ type : method ,
64+ message,
65+ stack,
66+ fileLine : stack . split ( '\n' ) [ 0 ] ?. trim ( ) ,
67+ styles,
68+ } ;
69+
70+ this . addToConsoleOutput ( logEvent ) ;
71+ } catch ( error ) {
72+ // Silently ignore errors in console processing to prevent infinite loops
73+ } finally {
74+ this . isProcessing = false ;
75+ }
76+
77+ oldFunction ( ...args ) ;
78+ } ;
79+ } ) ;
80+ }
81+
1682 /**
1783 * Converts any argument to its string representation
1884 */
@@ -113,72 +179,6 @@ export class ConsoleCatcher {
113179 } ;
114180 }
115181
116- /**
117- * Initializes the console interceptor by overriding default console methods
118- */
119- public init ( ) : void {
120- if ( this . isInitialized ) {
121- return ;
122- }
123-
124- this . isInitialized = true ;
125- const consoleMethods : string [ ] = [ 'log' , 'warn' , 'error' , 'info' , 'debug' ] ;
126-
127- consoleMethods . forEach ( ( method ) => {
128- if ( typeof window . console [ method ] !== 'function' ) {
129- return ;
130- }
131-
132- const oldFunction = window . console [ method ] . bind ( window . console ) ;
133-
134- window . console [ method ] = ( ...args : unknown [ ] ) : void => {
135- // Prevent recursive calls
136- if ( this . isProcessing ) {
137- return oldFunction ( ...args ) ;
138- }
139-
140- /**
141- * If the console call originates from Vue's internal runtime bundle, skip interception
142- * to avoid capturing Vue-internal warnings and causing recursive loops.
143- */
144- const rawStack = new Error ( ) . stack || '' ;
145- if ( rawStack . includes ( 'runtime-core.esm-bundler.js' ) ) {
146- return oldFunction ( ...args ) ;
147- }
148-
149- // Additional protection against Hawk internal calls
150- if ( rawStack . includes ( 'hawk.javascript' ) || rawStack . includes ( '@hawk.so' ) ) {
151- return oldFunction ( ...args ) ;
152- }
153-
154- this . isProcessing = true ;
155-
156- try {
157- const stack = new Error ( ) . stack ?. split ( '\n' ) . slice ( 2 ) . join ( '\n' ) || '' ;
158- const { message, styles } = this . formatConsoleArgs ( args ) ;
159-
160- const logEvent : ConsoleLogEvent = {
161- method,
162- timestamp : new Date ( ) ,
163- type : method ,
164- message,
165- stack,
166- fileLine : stack . split ( '\n' ) [ 0 ] ?. trim ( ) ,
167- styles,
168- } ;
169-
170- this . addToConsoleOutput ( logEvent ) ;
171- } catch ( error ) {
172- // Silently ignore errors in console processing to prevent infinite loops
173- } finally {
174- this . isProcessing = false ;
175- }
176-
177- oldFunction ( ...args ) ;
178- } ;
179- } ) ;
180- }
181-
182182 /**
183183 * Handles error events by converting them to console log events
184184 */
0 commit comments