From 2edb804660fd2df68f6b8e195fb2e2262936951c Mon Sep 17 00:00:00 2001 From: Ruslan Date: Tue, 5 May 2026 11:05:09 +0000 Subject: [PATCH] fix: autofill login first then password, continuous re-fill for SPA re-renders --- universal-runtime/manager.py | 43 +++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/universal-runtime/manager.py b/universal-runtime/manager.py index 844af19..d7081c3 100644 --- a/universal-runtime/manager.py +++ b/universal-runtime/manager.py @@ -30,8 +30,6 @@ _lock = threading.Lock() _AUTOFILL_CONTENT_JS = r""" (function() { const CREDS = __CREDS__; - let userFilled = false; - let passFilled = false; console.log('[PortalAutofill] loaded for', location.href); function isVisible(el) { @@ -112,23 +110,27 @@ _AUTOFILL_CONTENT_JS = r""" } function tryFill() { - if (userFilled && passFilled) return; const p = findPassField(); const u = findUserField(p); - if (CREDS.password && p && !passFilled) { - if (setNativeValue(p, CREDS.password)) { - passFilled = true; - console.log('[PortalAutofill] password filled'); - } - } - if (CREDS.login && u && !userFilled) { + // Fill login FIRST so password-triggered re-render doesn't clear it + if (CREDS.login && u) { if (setNativeValue(u, CREDS.login)) { - userFilled = true; console.log('[PortalAutofill] user filled'); } } - if (!CREDS.login) userFilled = true; - if (!CREDS.password) passFilled = true; + if (CREDS.password && p) { + if (setNativeValue(p, CREDS.password)) { + console.log('[PortalAutofill] password filled'); + } + } + } + + // Watch for SPA re-renders clearing the fields and re-fill continuously + let _filling = false; + function scheduleFill() { + if (_filling) return; + _filling = true; + requestAnimationFrame(() => { tryFill(); _filling = false; }); } if (document.readyState === 'loading') { @@ -137,17 +139,22 @@ _AUTOFILL_CONTENT_JS = r""" tryFill(); } - const obs = new MutationObserver(() => { - if (!(userFilled && passFilled)) tryFill(); - }); + // Periodic check for first 30s in case of async SPA resets + let _checks = 0; + const _interval = setInterval(() => { + tryFill(); + if (++_checks >= 30) clearInterval(_interval); + }, 1000); + + const obs = new MutationObserver(scheduleFill); if (document.documentElement) { obs.observe(document.documentElement, { childList: true, subtree: true }); } const resetAndRefill = () => { - userFilled = !CREDS.login; - passFilled = !CREDS.password; + _checks = 0; setTimeout(tryFill, 150); + setTimeout(tryFill, 600); }; ['pushState', 'replaceState'].forEach(fn => { const orig = history[fn];