11import '../styles/index.scss' ;
22import { FacebookPostObserver } from './observer' ;
33import { FloatingChatWindow } from './ui/components/ChatWindow' ;
4- import { metricsManager } from './metrics/MetricsManager' ;
54import { analytics } from '@/shared/analytics' ;
5+ import { SessionManager } from '@/shared/SessionManager' ;
6+ import { initializeGlobalGate , protectedExecute } from '@/shared/InitializationGate' ;
7+ import { createNavigationWatcher } from './utils/NavigationWatcher' ;
68import { isInAllowedGroupNow } from '@/content/utils/group' ;
9+ import { log , error } from '@/shared/logger' ;
710
811declare const __DEV__ : boolean ;
912if ( ! __DEV__ ) {
@@ -14,64 +17,134 @@ if (!__DEV__) {
1417 console . error = noop ;
1518}
1619
17- // Entry bootstrap: initialize metrics, observer and chat UI
18- ( async ( ) => {
20+ // Global instances
21+ let navigationWatcher : ReturnType < typeof createNavigationWatcher > | null = null ;
22+ let postObserver : FacebookPostObserver | null = null ;
23+ let chatWindow : FloatingChatWindow | null = null ;
24+
25+ /**
26+ * Initialize extension functionality - only called after session validation
27+ */
28+ async function initializeExtensionFeatures ( ) : Promise < void > {
1929 try {
20- // Check if we're in an allowed group
21- const allowed = isInAllowedGroupNow ( ) ;
22-
23- // CRITICAL: Only enable analytics and metrics AFTER user/session verification
24- if ( allowed ) {
25- // First initialize metrics manager which will verify/init user and session
26- await metricsManager . initialize ( ) ;
30+ await protectedExecute ( async ( ) => {
31+ log ( 'Initializing extension features' ) ;
32+
33+ // Initialize post observer with protection
34+ postObserver = new FacebookPostObserver ( ) ;
35+
36+ // Initialize chat window with protection
37+ chatWindow = new FloatingChatWindow ( ) ;
2738
28- // Only after successful verification, enable Mixpanel analytics
39+ // Enable and initialize analytics
2940 analytics . setEnabled ( true ) ;
3041 analytics . init ( ) ;
31- } else {
32- // Not in allowed group - disable analytics
33- analytics . setEnabled ( false ) ;
34- // Observe future SPA navigations to enter allowed context
35- const wrapHistory = ( method : 'pushState' | 'replaceState' ) => {
36- type PushReplace = ( data : unknown , unused : string , url ?: string | URL | null ) => unknown ;
37- const orig = history [ method ] . bind ( history ) as PushReplace ;
38- ( history as unknown as Record < string , unknown > ) [ method ] = ( (
39- data : unknown ,
40- unused : string ,
41- url ?: string | URL | null
42- ) => {
43- const ret = orig ( data , unused , url ) ;
44- window . dispatchEvent ( new Event ( 'locationchange' ) ) ;
45- return ret as unknown as void ;
46- } ) as History [ typeof method ] ;
47- } ;
48- wrapHistory ( 'pushState' ) ;
49- wrapHistory ( 'replaceState' ) ;
50- window . addEventListener ( 'popstate' , ( ) => window . dispatchEvent ( new Event ( 'locationchange' ) ) ) ;
51- let chatInitialized = false ;
52- window . addEventListener ( 'locationchange' , async ( ) => {
53- if ( isInAllowedGroupNow ( ) ) {
54- // Initialize metrics manager first (verifies user/session)
55- await metricsManager . initialize ( ) . catch ( ( ) => { } ) ;
56-
57- // Only after verification, enable analytics
58- analytics . setEnabled ( true ) ;
59- analytics . init ( ) ;
60-
61- if ( ! chatInitialized ) {
62- new FloatingChatWindow ( ) ;
63- chatInitialized = true ;
64- }
65- }
42+
43+ log ( 'Extension features initialized successfully' ) ;
44+ } , 'initializeExtensionFeatures' ) ;
45+ } catch ( err ) {
46+ error ( 'Failed to initialize extension features' , err ) ;
47+ throw err ;
48+ }
49+ }
50+
51+ /**
52+ * Set up navigation watcher for URL monitoring
53+ */
54+ function setupNavigationWatcher ( sessionManager : SessionManager ) : void {
55+ if ( navigationWatcher ) {
56+ navigationWatcher . destroy ( ) ;
57+ }
58+
59+ navigationWatcher = createNavigationWatcher ( sessionManager , {
60+ enableLogging : __DEV__ ,
61+ debounceMs : 100
62+ } ) ;
63+
64+ log ( 'Navigation watcher initialized' ) ;
65+ }
66+
67+ /**
68+ * Clean up extension resources
69+ */
70+ function cleanupExtension ( ) : void {
71+ if ( navigationWatcher ) {
72+ navigationWatcher . destroy ( ) ;
73+ navigationWatcher = null ;
74+ }
75+
76+ if ( postObserver ) {
77+ // FacebookPostObserver doesn't have destroy method yet - will add in next update
78+ postObserver = null ;
79+ }
80+
81+ if ( chatWindow ) {
82+ // FloatingChatWindow doesn't have destroy method yet - will add in next update
83+ chatWindow = null ;
84+ }
85+
86+ analytics . setEnabled ( false ) ;
87+ log ( 'Extension resources cleaned up' ) ;
88+ }
89+
90+ // Main entry point with new architecture
91+ ( async ( ) => {
92+ try {
93+ log ( 'Content script starting with new architecture' ) ;
94+
95+ // STEP 1: Check if we're in an allowed group
96+ const isInAllowedGroup = isInAllowedGroupNow ( ) ;
97+
98+ if ( ! isInAllowedGroup ) {
99+ log ( 'Not in allowed group, setting up navigation watcher only' ) ;
100+
101+ // Create session manager and navigation watcher for monitoring
102+ const sessionManager = SessionManager . getInstance ( {
103+ requireValidSession : true ,
104+ enableLogging : __DEV__
66105 } ) ;
106+
107+ setupNavigationWatcher ( sessionManager ) ;
108+
109+ // Exit early - no extension functionality until we enter allowed group
110+ return ;
67111 }
68-
69- // Then initialize the main functionality
70- new FacebookPostObserver ( ) ;
71- if ( allowed ) {
72- new FloatingChatWindow ( ) ;
112+
113+ log ( 'In allowed group, initializing session and extension' ) ;
114+
115+ // STEP 2: Initialize SessionManager
116+ const sessionManager = SessionManager . getInstance ( {
117+ requireValidSession : true ,
118+ enableLogging : __DEV__
119+ } ) ;
120+
121+ // STEP 3: Initialize InitializationGate with SessionManager
122+ // This will block until user/session are validated
123+ await initializeGlobalGate ( sessionManager ) ;
124+
125+ // STEP 4: Set up navigation watcher now that we have valid session
126+ setupNavigationWatcher ( sessionManager ) ;
127+
128+ // STEP 5: Only after valid session, initialize extension functionality
129+ await initializeExtensionFeatures ( ) ;
130+
131+ log ( 'Content script initialization complete' ) ;
132+
133+ } catch ( err ) {
134+ error ( 'Failed to initialize content script with new architecture' , err ) ;
135+
136+ // Fallback: clean up any partial initialization
137+ cleanupExtension ( ) ;
138+
139+ // Still set up navigation watcher in case user navigates to allowed group later
140+ try {
141+ const fallbackSessionManager = SessionManager . getInstance ( {
142+ requireValidSession : false ,
143+ enableLogging : __DEV__
144+ } ) ;
145+ setupNavigationWatcher ( fallbackSessionManager ) ;
146+ } catch ( fallbackErr ) {
147+ error ( 'Failed to set up fallback navigation watcher' , fallbackErr ) ;
73148 }
74- } catch ( error ) {
75- console . error ( 'Failed to initialize content script:' , error ) ;
76149 }
77150} ) ( ) ;
0 commit comments