sentienceapi 0.92.1 → 0.92.2
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/package.json +1 -1
- package/src/extension/background.js +56 -185
- package/src/extension/content.js +117 -289
- package/src/extension/injected_api.js +799 -1374
- package/src/extension/manifest.json +1 -1
- package/src/extension/pkg/README.md +136 -19
- package/src/extension/pkg/sentience_core.js +190 -396
- package/src/extension/pkg/sentience_core_bg.wasm +0 -0
- package/src/extension/release.json +47 -47
- package/src/extension/test-content.js +0 -4
package/package.json
CHANGED
|
@@ -1,233 +1,104 @@
|
|
|
1
|
-
|
|
2
|
-
// This runs in an isolated environment, completely immune to page CSP policies
|
|
1
|
+
import init, { analyze_page_with_options, analyze_page, prune_for_api } from "../pkg/sentience_core.js";
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
// Dynamic import() is FORBIDDEN in ServiceWorkerGlobalScope
|
|
6
|
-
import init, { analyze_page, analyze_page_with_options, prune_for_api } from './pkg/sentience_core.js';
|
|
3
|
+
let wasmReady = !1, wasmInitPromise = null;
|
|
7
4
|
|
|
8
|
-
console.log('[Sentience Background] Initializing...');
|
|
9
|
-
|
|
10
|
-
// Global WASM initialization state
|
|
11
|
-
let wasmReady = false;
|
|
12
|
-
let wasmInitPromise = null;
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Initialize WASM module - called once on service worker startup
|
|
16
|
-
* Uses static imports (not dynamic import()) which is required for Service Workers
|
|
17
|
-
*/
|
|
18
5
|
async function initWASM() {
|
|
19
|
-
if (wasmReady) return
|
|
20
|
-
if (wasmInitPromise) return wasmInitPromise;
|
|
21
|
-
|
|
22
|
-
wasmInitPromise = (async () => {
|
|
6
|
+
if (!wasmReady) return wasmInitPromise || (wasmInitPromise = (async () => {
|
|
23
7
|
try {
|
|
24
|
-
|
|
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');
|
|
8
|
+
globalThis.js_click_element = () => {}, await init(), wasmReady = !0;
|
|
40
9
|
} catch (error) {
|
|
41
|
-
console.error('[Sentience Background] WASM initialization failed:', error);
|
|
42
10
|
throw error;
|
|
43
11
|
}
|
|
44
|
-
})();
|
|
45
|
-
|
|
46
|
-
return wasmInitPromise;
|
|
12
|
+
})(), wasmInitPromise);
|
|
47
13
|
}
|
|
48
14
|
|
|
49
|
-
// Initialize WASM on service worker startup
|
|
50
|
-
initWASM().catch(err => {
|
|
51
|
-
console.error('[Sentience Background] Failed to initialize WASM:', err);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Message handler for all extension communication
|
|
56
|
-
* Includes global error handling to prevent extension crashes
|
|
57
|
-
*/
|
|
58
|
-
chrome.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
|
-
}
|
|
76
|
-
|
|
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
|
-
}
|
|
92
|
-
|
|
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;
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Handle screenshot capture (existing functionality)
|
|
114
|
-
*/
|
|
115
15
|
async function handleScreenshotCapture(_tabId, options = {}) {
|
|
116
16
|
try {
|
|
117
|
-
const {
|
|
118
|
-
|
|
119
|
-
quality = 90
|
|
120
|
-
} = options;
|
|
121
|
-
|
|
122
|
-
const dataUrl = await chrome.tabs.captureVisibleTab(null, {
|
|
17
|
+
const {format: format = "png", quality: quality = 90} = options;
|
|
18
|
+
return await chrome.tabs.captureVisibleTab(null, {
|
|
123
19
|
format: format,
|
|
124
20
|
quality: quality
|
|
125
21
|
});
|
|
126
|
-
|
|
127
|
-
console.log(`[Sentience Background] Screenshot captured: ${format}, size: ${dataUrl.length} bytes`);
|
|
128
|
-
return dataUrl;
|
|
129
22
|
} catch (error) {
|
|
130
|
-
console.error('[Sentience Background] Screenshot error:', error);
|
|
131
23
|
throw new Error(`Failed to capture screenshot: ${error.message}`);
|
|
132
24
|
}
|
|
133
25
|
}
|
|
134
26
|
|
|
135
|
-
/**
|
|
136
|
-
* Handle snapshot processing with WASM (NEW!)
|
|
137
|
-
* This is where the magic happens - completely CSP-immune!
|
|
138
|
-
* Includes safeguards to prevent crashes and hangs.
|
|
139
|
-
*
|
|
140
|
-
* @param {Array} rawData - Raw element data from injected_api.js
|
|
141
|
-
* @param {Object} options - Snapshot options (limit, filter, etc.)
|
|
142
|
-
* @returns {Promise<Object>} Processed snapshot result
|
|
143
|
-
*/
|
|
144
27
|
async function handleSnapshotProcessing(rawData, options = {}) {
|
|
145
|
-
const MAX_ELEMENTS = 10000; // Safety limit to prevent hangs
|
|
146
28
|
const startTime = performance.now();
|
|
147
|
-
|
|
148
29
|
try {
|
|
149
|
-
|
|
150
|
-
if (
|
|
151
|
-
|
|
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
|
-
}
|
|
158
|
-
|
|
159
|
-
// Ensure WASM is initialized
|
|
160
|
-
await initWASM();
|
|
161
|
-
if (!wasmReady) {
|
|
162
|
-
throw new Error('WASM module not initialized');
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
console.log(`[Sentience Background] Processing ${rawData.length} elements with options:`, options);
|
|
166
|
-
|
|
167
|
-
// Run WASM processing using the imported functions directly
|
|
168
|
-
// Wrap in try-catch with timeout protection
|
|
169
|
-
let analyzedElements;
|
|
30
|
+
if (!Array.isArray(rawData)) throw new Error("rawData must be an array");
|
|
31
|
+
if (rawData.length > 1e4 && (rawData = rawData.slice(0, 1e4)), await initWASM(),
|
|
32
|
+
!wasmReady) throw new Error("WASM module not initialized");
|
|
33
|
+
let analyzedElements, prunedRawData;
|
|
170
34
|
try {
|
|
171
|
-
// Use a timeout wrapper to prevent infinite hangs
|
|
172
35
|
const wasmPromise = new Promise((resolve, reject) => {
|
|
173
36
|
try {
|
|
174
37
|
let result;
|
|
175
|
-
|
|
176
|
-
result = analyze_page_with_options(rawData, options);
|
|
177
|
-
} else {
|
|
178
|
-
result = analyze_page(rawData);
|
|
179
|
-
}
|
|
38
|
+
result = options.limit || options.filter ? analyze_page_with_options(rawData, options) : analyze_page(rawData),
|
|
180
39
|
resolve(result);
|
|
181
40
|
} catch (e) {
|
|
182
41
|
reject(e);
|
|
183
42
|
}
|
|
184
43
|
});
|
|
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
|
-
]);
|
|
44
|
+
analyzedElements = await Promise.race([ wasmPromise, new Promise((_, reject) => setTimeout(() => reject(new Error("WASM processing timeout (>18s)")), 18e3)) ]);
|
|
193
45
|
} catch (e) {
|
|
194
|
-
const errorMsg = e.message ||
|
|
195
|
-
console.error(`[Sentience Background] WASM analyze_page failed: ${errorMsg}`, e);
|
|
46
|
+
const errorMsg = e.message || "Unknown WASM error";
|
|
196
47
|
throw new Error(`WASM analyze_page failed: ${errorMsg}`);
|
|
197
48
|
}
|
|
198
|
-
|
|
199
|
-
// Prune elements for API (prevents 413 errors on large sites)
|
|
200
|
-
let prunedRawData;
|
|
201
49
|
try {
|
|
202
50
|
prunedRawData = prune_for_api(rawData);
|
|
203
51
|
} catch (e) {
|
|
204
|
-
console.warn('[Sentience Background] prune_for_api failed, using original data:', e);
|
|
205
52
|
prunedRawData = rawData;
|
|
206
53
|
}
|
|
207
|
-
|
|
208
|
-
const duration = performance.now() - startTime;
|
|
209
|
-
console.log(`[Sentience Background] ✓ Processed: ${analyzedElements.length} analyzed, ${prunedRawData.length} pruned (${duration.toFixed(1)}ms)`);
|
|
210
|
-
|
|
54
|
+
performance.now();
|
|
211
55
|
return {
|
|
212
56
|
elements: analyzedElements,
|
|
213
57
|
raw_elements: prunedRawData
|
|
214
58
|
};
|
|
215
59
|
} catch (error) {
|
|
216
|
-
|
|
217
|
-
console.error(`[Sentience Background] Processing error after ${duration.toFixed(1)}ms:`, error);
|
|
60
|
+
performance.now();
|
|
218
61
|
throw error;
|
|
219
62
|
}
|
|
220
63
|
}
|
|
221
64
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
});
|
|
65
|
+
initWASM().catch(err => {}), chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|
66
|
+
try {
|
|
67
|
+
return "captureScreenshot" === request.action ? (handleScreenshotCapture(sender.tab.id, request.options).then(screenshot => {
|
|
68
|
+
sendResponse({
|
|
69
|
+
success: !0,
|
|
70
|
+
screenshot: screenshot
|
|
71
|
+
});
|
|
72
|
+
}).catch(error => {
|
|
73
|
+
sendResponse({
|
|
74
|
+
success: !1,
|
|
75
|
+
error: error.message || "Screenshot capture failed"
|
|
76
|
+
});
|
|
77
|
+
}), !0) : "processSnapshot" === request.action ? (handleSnapshotProcessing(request.rawData, request.options).then(result => {
|
|
78
|
+
sendResponse({
|
|
79
|
+
success: !0,
|
|
80
|
+
result: result
|
|
81
|
+
});
|
|
82
|
+
}).catch(error => {
|
|
83
|
+
sendResponse({
|
|
84
|
+
success: !1,
|
|
85
|
+
error: error.message || "Snapshot processing failed"
|
|
86
|
+
});
|
|
87
|
+
}), !0) : (sendResponse({
|
|
88
|
+
success: !1,
|
|
89
|
+
error: "Unknown action"
|
|
90
|
+
}), !1);
|
|
91
|
+
} catch (error) {
|
|
92
|
+
try {
|
|
93
|
+
sendResponse({
|
|
94
|
+
success: !1,
|
|
95
|
+
error: `Fatal error: ${error.message || "Unknown error"}`
|
|
96
|
+
});
|
|
97
|
+
} catch (e) {}
|
|
98
|
+
return !1;
|
|
99
|
+
}
|
|
100
|
+
}), self.addEventListener("error", event => {
|
|
101
|
+
event.preventDefault();
|
|
102
|
+
}), self.addEventListener("unhandledrejection", event => {
|
|
103
|
+
event.preventDefault();
|
|
104
|
+
});
|