fix(mobile): patch pyodide.js at runtime to bypass Chrome 61 import() syntax

Chrome 61 (Karoo WebView) cannot parse dynamic import() — a SyntaxError at
parse time prevents loadPyodide from ever being defined.

Fix: fetch pyodide.js as text, replace every import( with a __loadScript(
shim that uses <script> tag injection, then inject via Blob URL. The Blob
script is never pre-scanned for module syntax so the patch is invisible to
the parser.

Also: expose waitForEngine() from extractActivity so callers can await
engine readiness before batching files — manual scan now shows "Preparing
extraction engine…" instead of flooding with N individual failures.
This commit is contained in:
Davide Scaini
2026-04-26 14:59:28 +02:00
parent a5c2810568
commit 1410be7427
3 changed files with 73 additions and 5 deletions
+26
View File
@@ -22,6 +22,24 @@ const pending = new Map<string, Pending>();
let reqCounter = 0;
let isExtracting = false;
// Engine readiness — tracked so callers can wait before batching files.
let _engineReady = false;
let _engineError: string | null = null;
const _engineResolvers: Array<() => void> = [];
const _engineRejecters: Array<(e: Error) => void> = [];
export function waitForEngine(timeoutMs = 300_000): Promise<void> {
if (_engineReady) return Promise.resolve();
if (_engineError) return Promise.reject(new Error(_engineError));
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
reject(new Error('Extraction engine timed out — check network and Bincio instance URL'));
}, timeoutMs);
_engineResolvers.push(() => { clearTimeout(timer); resolve(); });
_engineRejecters.push((e) => { clearTimeout(timer); reject(e); });
});
}
export function handleWebViewMessage(e: WebViewMessageEvent): void {
let msg: Record<string, unknown>;
try { msg = JSON.parse(e.nativeEvent.data); } catch { return; }
@@ -30,6 +48,14 @@ export function handleWebViewMessage(e: WebViewMessageEvent): void {
const p = reqId ? pending.get(reqId) : undefined;
switch (msg.type) {
case 'pyodide_ready':
_engineReady = true;
_engineResolvers.splice(0).forEach(fn => fn());
break;
case 'init_error':
_engineError = msg.message as string;
_engineRejecters.splice(0).forEach(fn => fn(new Error(_engineError!)));
break;
case 'result':
if (p) {
pending.delete(reqId!);