1+ // Sentience Chrome Extension - Background Service Worker
2+ // Auto-generated from modular source
3+ import init , { analyze_page_with_options , analyze_page , prune_for_api } from '../pkg/sentience_core.js' ;
4+
15// background.js - Service Worker with WASM (CSP-Immune!)
26// This runs in an isolated environment, completely immune to page CSP policies
37
4- // ✅ STATIC IMPORTS at top level - Required for Service Workers!
5- // Dynamic import() is FORBIDDEN in ServiceWorkerGlobalScope
6- import init , { analyze_page , analyze_page_with_options , prune_for_api } from './pkg/sentience_core.js' ;
78
89console . log ( '[Sentience Background] Initializing...' ) ;
910
@@ -16,120 +17,121 @@ let wasmInitPromise = null;
1617 * Uses static imports (not dynamic import()) which is required for Service Workers
1718 */
1819async function initWASM ( ) {
19- if ( wasmReady ) return ;
20- if ( wasmInitPromise ) return wasmInitPromise ;
20+ if ( wasmReady ) return ;
21+ if ( wasmInitPromise ) return wasmInitPromise ;
2122
22- wasmInitPromise = ( async ( ) => {
23- try {
24- console . log ( '[Sentience Background] Loading WASM module...' ) ;
25-
26- // Define the js_click_element function that WASM expects
27- // In Service Workers, use 'globalThis' instead of 'window'
28- // In background context, we can't actually click, so we log a warning
29- globalThis . js_click_element = ( _id ) => {
30- console . warn ( '[Sentience Background] js_click_element called in background (ignored)' ) ;
31- } ;
32-
33- // Initialize WASM - this calls the init() function from the static import
34- // The init() function handles fetching and instantiating the .wasm file
35- await init ( ) ;
36-
37- wasmReady = true ;
38- console . log ( '[Sentience Background] ✓ WASM ready!' ) ;
39- console . log ( '[Sentience Background] Available functions: analyze_page, analyze_page_with_options, prune_for_api' ) ;
40- } catch ( error ) {
41- console . error ( '[Sentience Background] WASM initialization failed:' , error ) ;
42- throw error ;
43- }
44- } ) ( ) ;
23+ wasmInitPromise = ( async ( ) => {
24+ try {
25+ console . log ( '[Sentience Background] Loading WASM module...' ) ;
26+
27+ // Define the js_click_element function that WASM expects
28+ // In Service Workers, use 'globalThis' instead of 'window'
29+ // In background context, we can't actually click, so we log a warning
30+ globalThis . js_click_element = ( ) => {
31+ console . warn ( '[Sentience Background] js_click_element called in background (ignored)' ) ;
32+ } ;
33+
34+ // Initialize WASM - this calls the init() function from the static import
35+ // The init() function handles fetching and instantiating the .wasm file
36+ await init ( ) ;
37+
38+ wasmReady = true ;
39+ console . log ( '[Sentience Background] ✓ WASM ready!' ) ;
40+ console . log (
41+ '[Sentience Background] Available functions: analyze_page, analyze_page_with_options, prune_for_api'
42+ ) ;
43+ } catch ( error ) {
44+ console . error ( '[Sentience Background] WASM initialization failed:' , error ) ;
45+ throw error ;
46+ }
47+ } ) ( ) ;
4548
46- return wasmInitPromise ;
49+ return wasmInitPromise ;
4750}
4851
4952// Initialize WASM on service worker startup
50- initWASM ( ) . catch ( err => {
51- console . error ( '[Sentience Background] Failed to initialize WASM:' , err ) ;
53+ initWASM ( ) . catch ( ( err ) => {
54+ console . error ( '[Sentience Background] Failed to initialize WASM:' , err ) ;
5255} ) ;
5356
5457/**
5558 * Message handler for all extension communication
5659 * Includes global error handling to prevent extension crashes
5760 */
5861chrome . runtime . onMessage . addListener ( ( request , sender , sendResponse ) => {
59- // Global error handler to prevent extension crashes
60- try {
61- // Handle screenshot requests (existing functionality)
62- if ( request . action === 'captureScreenshot' ) {
63- handleScreenshotCapture ( sender . tab . id , request . options )
64- . then ( screenshot => {
65- sendResponse ( { success : true , screenshot } ) ;
66- } )
67- . catch ( error => {
68- console . error ( '[Sentience Background] Screenshot capture failed:' , error ) ;
69- sendResponse ( {
70- success : false ,
71- error : error . message || 'Screenshot capture failed'
72- } ) ;
73- } ) ;
74- return true ; // Async response
75- }
62+ // Global error handler to prevent extension crashes
63+ try {
64+ // Handle screenshot requests (existing functionality)
65+ if ( request . action === 'captureScreenshot' ) {
66+ handleScreenshotCapture ( sender . tab . id , request . options )
67+ . then ( ( screenshot ) => {
68+ sendResponse ( { success : true , screenshot } ) ;
69+ } )
70+ . catch ( ( error ) => {
71+ console . error ( '[Sentience Background] Screenshot capture failed:' , error ) ;
72+ sendResponse ( {
73+ success : false ,
74+ error : error . message || 'Screenshot capture failed' ,
75+ } ) ;
76+ } ) ;
77+ return true ; // Async response
78+ }
7679
77- // Handle WASM processing requests (NEW!)
78- if ( request . action === 'processSnapshot' ) {
79- handleSnapshotProcessing ( request . rawData , request . options )
80- . then ( result => {
81- sendResponse ( { success : true , result } ) ;
82- } )
83- . catch ( error => {
84- console . error ( '[Sentience Background] Snapshot processing failed:' , error ) ;
85- sendResponse ( {
86- success : false ,
87- error : error . message || 'Snapshot processing failed'
88- } ) ;
89- } ) ;
90- return true ; // Async response
91- }
80+ // Handle WASM processing requests (NEW!)
81+ if ( request . action === 'processSnapshot' ) {
82+ handleSnapshotProcessing ( request . rawData , request . options )
83+ . then ( ( result ) => {
84+ sendResponse ( { success : true , result } ) ;
85+ } )
86+ . catch ( ( error ) => {
87+ console . error ( '[Sentience Background] Snapshot processing failed:' , error ) ;
88+ sendResponse ( {
89+ success : false ,
90+ error : error . message || 'Snapshot processing failed' ,
91+ } ) ;
92+ } ) ;
93+ return true ; // Async response
94+ }
9295
93- // Unknown action
94- console . warn ( '[Sentience Background] Unknown action:' , request . action ) ;
95- sendResponse ( { success : false , error : 'Unknown action' } ) ;
96- return false ;
97- } catch ( error ) {
98- // Catch any synchronous errors that might crash the extension
99- console . error ( '[Sentience Background] Fatal error in message handler:' , error ) ;
100- try {
101- sendResponse ( {
102- success : false ,
103- error : `Fatal error: ${ error . message || 'Unknown error' } `
104- } ) ;
105- } catch ( e ) {
106- // If sendResponse already called, ignore
107- }
108- return false ;
96+ // Unknown action
97+ console . warn ( '[Sentience Background] Unknown action:' , request . action ) ;
98+ sendResponse ( { success : false , error : 'Unknown action' } ) ;
99+ return false ;
100+ } catch ( error ) {
101+ // Catch any synchronous errors that might crash the extension
102+ console . error ( '[Sentience Background] Fatal error in message handler:' , error ) ;
103+ try {
104+ sendResponse ( {
105+ success : false ,
106+ error : `Fatal error: ${ error . message || 'Unknown error' } ` ,
107+ } ) ;
108+ } catch ( e ) {
109+ // If sendResponse already called, ignore
109110 }
111+ return false ;
112+ }
110113} ) ;
111114
112115/**
113116 * Handle screenshot capture (existing functionality)
114117 */
115118async function handleScreenshotCapture ( _tabId , options = { } ) {
116- try {
117- const {
118- format = 'png' ,
119- quality = 90
120- } = options ;
121-
122- const dataUrl = await chrome . tabs . captureVisibleTab ( null , {
123- format : format ,
124- quality : quality
125- } ) ;
126-
127- console . log ( `[Sentience Background] Screenshot captured: ${ format } , size: ${ dataUrl . length } bytes` ) ;
128- return dataUrl ;
129- } catch ( error ) {
130- console . error ( '[Sentience Background] Screenshot error:' , error ) ;
131- throw new Error ( `Failed to capture screenshot: ${ error . message } ` ) ;
132- }
119+ try {
120+ const { format = 'png' , quality = 90 } = options ;
121+
122+ const dataUrl = await chrome . tabs . captureVisibleTab ( null , {
123+ format,
124+ quality,
125+ } ) ;
126+
127+ console . log (
128+ `[Sentience Background] Screenshot captured: ${ format } , size: ${ dataUrl . length } bytes`
129+ ) ;
130+ return dataUrl ;
131+ } catch ( error ) {
132+ console . error ( '[Sentience Background] Screenshot error:' , error ) ;
133+ throw new Error ( `Failed to capture screenshot: ${ error . message } ` ) ;
134+ }
133135}
134136
135137/**
@@ -142,92 +144,99 @@ async function handleScreenshotCapture(_tabId, options = {}) {
142144 * @returns {Promise<Object> } Processed snapshot result
143145 */
144146async function handleSnapshotProcessing ( rawData , options = { } ) {
145- const MAX_ELEMENTS = 10000 ; // Safety limit to prevent hangs
146- const startTime = performance . now ( ) ;
147-
148- try {
149- // Safety check: limit element count to prevent hangs
150- if ( ! Array . isArray ( rawData ) ) {
151- throw new Error ( 'rawData must be an array' ) ;
152- }
153-
154- if ( rawData . length > MAX_ELEMENTS ) {
155- console . warn ( `[Sentience Background] ⚠️ Large dataset: ${ rawData . length } elements. Limiting to ${ MAX_ELEMENTS } to prevent hangs.` ) ;
156- rawData = rawData . slice ( 0 , MAX_ELEMENTS ) ;
157- }
147+ const MAX_ELEMENTS = 10000 ; // Safety limit to prevent hangs
148+ const startTime = performance . now ( ) ;
158149
159- // Ensure WASM is initialized
160- await initWASM ( ) ;
161- if ( ! wasmReady ) {
162- throw new Error ( 'WASM module not initialized ' ) ;
163- }
150+ try {
151+ // Safety check: limit element count to prevent hangs
152+ if ( ! Array . isArray ( rawData ) ) {
153+ throw new Error ( 'rawData must be an array ' ) ;
154+ }
164155
165- console . log ( `[Sentience Background] Processing ${ rawData . length } elements with options:` , options ) ;
156+ if ( rawData . length > MAX_ELEMENTS ) {
157+ console . warn (
158+ `[Sentience Background] ⚠️ Large dataset: ${ rawData . length } elements. Limiting to ${ MAX_ELEMENTS } to prevent hangs.`
159+ ) ;
160+ rawData = rawData . slice ( 0 , MAX_ELEMENTS ) ;
161+ }
166162
167- // Run WASM processing using the imported functions directly
168- // Wrap in try-catch with timeout protection
169- let analyzedElements ;
170- try {
171- // Use a timeout wrapper to prevent infinite hangs
172- const wasmPromise = new Promise ( ( resolve , reject ) => {
173- try {
174- let result ;
175- if ( options . limit || options . filter ) {
176- result = analyze_page_with_options ( rawData , options ) ;
177- } else {
178- result = analyze_page ( rawData ) ;
179- }
180- resolve ( result ) ;
181- } catch ( e ) {
182- reject ( e ) ;
183- }
184- } ) ;
185-
186- // Add timeout protection (18 seconds - less than content.js timeout)
187- analyzedElements = await Promise . race ( [
188- wasmPromise ,
189- new Promise ( ( _ , reject ) =>
190- setTimeout ( ( ) => reject ( new Error ( 'WASM processing timeout (>18s)' ) ) , 18000 )
191- )
192- ] ) ;
193- } catch ( e ) {
194- const errorMsg = e . message || 'Unknown WASM error' ;
195- console . error ( `[Sentience Background] WASM analyze_page failed: ${ errorMsg } ` , e ) ;
196- throw new Error ( `WASM analyze_page failed: ${ errorMsg } ` ) ;
197- }
163+ // Ensure WASM is initialized
164+ await initWASM ( ) ;
165+ if ( ! wasmReady ) {
166+ throw new Error ( 'WASM module not initialized' ) ;
167+ }
198168
199- // Prune elements for API (prevents 413 errors on large sites)
200- let prunedRawData ;
169+ console . log (
170+ `[Sentience Background] Processing ${ rawData . length } elements with options:` ,
171+ options
172+ ) ;
173+
174+ // Run WASM processing using the imported functions directly
175+ // Wrap in try-catch with timeout protection
176+ let analyzedElements ;
177+ try {
178+ // Use a timeout wrapper to prevent infinite hangs
179+ const wasmPromise = new Promise ( ( resolve , reject ) => {
201180 try {
202- prunedRawData = prune_for_api ( rawData ) ;
181+ let result ;
182+ if ( options . limit || options . filter ) {
183+ result = analyze_page_with_options ( rawData , options ) ;
184+ } else {
185+ result = analyze_page ( rawData ) ;
186+ }
187+ resolve ( result ) ;
203188 } catch ( e ) {
204- console . warn ( '[Sentience Background] prune_for_api failed, using original data:' , e ) ;
205- prunedRawData = rawData ;
189+ reject ( e ) ;
206190 }
191+ } ) ;
192+
193+ // Add timeout protection (18 seconds - less than content.js timeout)
194+ analyzedElements = await Promise . race ( [
195+ wasmPromise ,
196+ new Promise ( ( _ , reject ) =>
197+ setTimeout ( ( ) => reject ( new Error ( 'WASM processing timeout (>18s)' ) ) , 18000 )
198+ ) ,
199+ ] ) ;
200+ } catch ( e ) {
201+ const errorMsg = e . message || 'Unknown WASM error' ;
202+ console . error ( `[Sentience Background] WASM analyze_page failed: ${ errorMsg } ` , e ) ;
203+ throw new Error ( `WASM analyze_page failed: ${ errorMsg } ` ) ;
204+ }
207205
208- const duration = performance . now ( ) - startTime ;
209- console . log ( `[Sentience Background] ✓ Processed: ${ analyzedElements . length } analyzed, ${ prunedRawData . length } pruned (${ duration . toFixed ( 1 ) } ms)` ) ;
210-
211- return {
212- elements : analyzedElements ,
213- raw_elements : prunedRawData
214- } ;
215- } catch ( error ) {
216- const duration = performance . now ( ) - startTime ;
217- console . error ( `[Sentience Background] Processing error after ${ duration . toFixed ( 1 ) } ms:` , error ) ;
218- throw error ;
206+ // Prune elements for API (prevents 413 errors on large sites)
207+ let prunedRawData ;
208+ try {
209+ prunedRawData = prune_for_api ( rawData ) ;
210+ } catch ( e ) {
211+ console . warn ( '[Sentience Background] prune_for_api failed, using original data:' , e ) ;
212+ prunedRawData = rawData ;
219213 }
214+
215+ const duration = performance . now ( ) - startTime ;
216+ console . log (
217+ `[Sentience Background] ✓ Processed: ${ analyzedElements . length } analyzed, ${ prunedRawData . length } pruned (${ duration . toFixed ( 1 ) } ms)`
218+ ) ;
219+
220+ return {
221+ elements : analyzedElements ,
222+ raw_elements : prunedRawData ,
223+ } ;
224+ } catch ( error ) {
225+ const duration = performance . now ( ) - startTime ;
226+ console . error ( `[Sentience Background] Processing error after ${ duration . toFixed ( 1 ) } ms:` , error ) ;
227+ throw error ;
228+ }
220229}
221230
222231console . log ( '[Sentience Background] Service worker ready' ) ;
223232
224233// Global error handlers to prevent extension crashes
225234self . addEventListener ( 'error' , ( event ) => {
226- console . error ( '[Sentience Background] Global error caught:' , event . error ) ;
227- event . preventDefault ( ) ; // Prevent extension crash
235+ console . error ( '[Sentience Background] Global error caught:' , event . error ) ;
236+ event . preventDefault ( ) ; // Prevent extension crash
228237} ) ;
229238
230239self . addEventListener ( 'unhandledrejection' , ( event ) => {
231- console . error ( '[Sentience Background] Unhandled promise rejection:' , event . reason ) ;
232- event . preventDefault ( ) ; // Prevent extension crash
240+ console . error ( '[Sentience Background] Unhandled promise rejection:' , event . reason ) ;
241+ event . preventDefault ( ) ; // Prevent extension crash
233242} ) ;
0 commit comments