← Commit history

Dashboard finally renders: fix the inline onerror that killed the script. Every img used onerror=this.style.visibility=SINGLEQUOTE hidden SINGLEQUOTE inside a single-quoted JS string, so the inner quotes closed the string early and produced Uncaught SyntaxError missing paren after argument list at the served line 30 col 130 (found by appending the served script to the live DOM and reading window.onerror, after browser_errors showed zero because the script never RAN to throw a catchable error). This is why the page rendered its static shell through seven ships while the SSE backend was healthy all along. Replaced all three inline handlers with a data-fallback=hide attribute plus ONE delegated error listener, same pattern as the click delegation, so no inline handler can ever put quotes-in-quotes again. Note for future: node --check and even new Function on the extracted template CANNOT catch this because template-literal unescaping differs from what the HTTP server emits byte-for-byte; the only reliable check is loading the served page in a real browser.

John Lauer ·97ecaffeb9 ·2mo ago ·parent 70ce588
4 files changed +9−9
adom-bridge-puppeteer-manifest.json+4−4
@@ -1,10 +1,10 @@ {   "manifest_version": 1,   "name": "puppeteer",-  "version": "1.9.231",-  "url": "https://wiki.adom.inc/download/adom/adom-desktop-puppeteer-bridge/1.9.231/adom-bridge-puppeteer-v1.9.231.zip",-  "sha256": "517511bbfd1cb0e0734e1aeba8dc5ec8dae06a1d5de00f32bdb3f53d51fcc549",-  "size": 456153,+  "version": "1.9.232",+  "url": "https://wiki.adom.inc/download/adom/adom-desktop-puppeteer-bridge/1.9.232/adom-bridge-puppeteer-v1.9.232.zip",+  "sha256": "5abb78344c2a1a236faf276dffa7317e43246219d15599e6abdda5ee30940395",+  "size": 456136,   "verbPrefixes": [     "browser_",     "desktop_recorder_",
src/BRIDGE_VERSION+1−1
@@ -1 +1 @@-1.9.231+1.9.232
src/bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "puppeteer",   "displayName": "Puppeteer (Chrome for Testing + Native)",-  "version": "1.9.231",+  "version": "1.9.232",   "description": "Drives a browser ALREADY on the machine \u2014 installed Chrome, else Microsoft Edge (every Windows PC ships with Edge) \u2014 launched with a FRESH isolated profile, so the common case has NO ~150 MB Chrome-for-Testing download and it never touches the user's real tabs/logins. Binds its local server to LOOPBACK (127.0.0.1) only, so no Windows Firewall 'allow Node through the firewall' prompt ever pops. Chrome for Testing is fetched only as a LAST RESORT if the machine has no Chromium browser at all. SPAWN-VERIFIED fallback: pup tries each detected browser (Chrome \u2192 Edge \u2192 CfT) and actually launches it, falling through to the next if one won't start (and handling browsers like Edge that relaunch onto another PID), so a corrupt/partial install never hard-fails an open. The browser that launches is cached as the default (persisted across restarts) so it isn't re-probed each time. On spawn the bridge SELF-WARMS: detects browsers + disk, and only if the box has no Chrome/Edge and no cached CfT does it background-fetch CfT so the first open is instant. browser_use pins a specific browser (chrome | edge | cft | auto); {browser:'chrome',install:true} downloads & installs REAL Google Chrome (user-scoped, no admin) on an Edge-only box. browser_readiness (READ-ONLY) reports which browser will be used + the full candidate list + the default + free disk. Every failure returns a specific errorCode + _hint (chrome_install_no_disk, chrome_download_network, chrome_install_permission, chrome_stable_not_detected, \u2026). Launches with FULL browser permissions by default for full debug (strictPermissions:true opts out). Headful automation: open/close windows+tabs, navigate, screenshot, eval JS, record. pup is a GENERIC, non-profile browser only \u2014 every session is a fresh isolated Chrome/Edge process, never the user's real signed-in browser; profile defaults to sessionId. To drive the user's REAL Chrome/Edge (their profile, cookies, SSO), use the Adom browser EXTENSION's nbrowser_* verbs \u2014 a separate bridge, not pup's job. macOS (v1.9.74+): full parity with mac-native mechanics \u2014 background-by-default is the app-level hide (windows stay drivable/screenshottable while hidden), raise/lower map to unhide+activate/hide, browser_alert_window posts a native toast whose click focuses the window, browser_use {browser:'chrome',install:true} installs Chrome from the official dmg, and taskbar identity/badging remains Windows-only.",   "homepage": "https://wiki.adom.inc/adom/adom-desktop",   "author": "Adom Inc.",
src/server.js+3−3
@@ -7946,7 +7946,7 @@ function render(){   const groups=(d.taskbarButtons||[]).map(b=>({...b,wins:b.windows.map(s=>byId[s]).filter(Boolean)})).filter(g=>g.wins.length);   _q('#m').innerHTML = groups.length? groups.map(g=>     '<div class="tbgroup">'-    +'<div class="tbhead"><img class="tbicon" src="/dashboard/badge?session='+encodeURIComponent(g.wins[0].sessionId)+'&t='+d.ts+'" onerror="this.style.visibility=\'hidden\'">'+    +'<div class="tbhead"><img class="tbicon" src="/dashboard/badge?session='+encodeURIComponent(g.wins[0].sessionId)+'&t='+d.ts+'" data-fallback="hide">'       +'<span class="tblabel">'+esc(g.label)+'</span>'       +'<span class="tbmeta">taskbar button · '+g.wins.length+' window'+(g.wins.length>1?'s':'')+' · '+esc(g.grouping)+'</span>'       +'<button class="btn sm" data-act="flash-group" data-ids="'+esc(g.windows.join(','))+'">flash</button>'@@ -7955,7 +7955,7 @@ function render(){     const crashed=w.tabs.some(t=>t.crashed)||w.lostBrowser;     return '<div class="card '+(w.foreground?'fg':'')+(crashed?' crash':'')+'">'     +'<div class="chead">'-      +'<img class="badge" src="/dashboard/badge?session='+encodeURIComponent(w.sessionId)+'&t='+d.ts+'" onerror="this.style.visibility=\'hidden\'">'+      +'<img class="badge" src="/dashboard/badge?session='+encodeURIComponent(w.sessionId)+'&t='+d.ts+'" data-fallback="hide">'       +'<span class="sid">'+esc(w.sessionId)+'</span>'       +'<span class="sub">'+esc(w.profile)+' · '+ago(w.uptimeMs)+'</span>'       +'<button class="btn sm" data-act="flash" data-sid="'+esc(w.sessionId)+'">flash</button>'@@ -7986,7 +7986,7 @@ function render(){       +(w.lastAgentUpdate?'<tr><td class="k">last action</td><td>'+esc(w.lastAgentUpdate.verb||'')+' '+esc(w.lastAgentUpdate.note||'')+'</td></tr>':'')     +'</table>'     +'<div class="tabs">'+w.tabs.map(t=>'<div class="tab '+(t.active?'act':'')+'">'-        +'<img class="fav" src="/dashboard/favicon?session='+encodeURIComponent(w.sessionId)+'&tab='+encodeURIComponent(t.tabId)+'" onerror="this.style.visibility=\'hidden\'">'+        +'<img class="fav" src="/dashboard/favicon?session='+encodeURIComponent(w.sessionId)+'&tab='+encodeURIComponent(t.tabId)+'" data-fallback="hide">'         +'<span class="id">'+esc(t.tabId)+'</span><span class="u">'+esc(t.title||t.url||'—')+'</span>'         +(t.crashed?'<span class="x">crashed</span>':'')         +'<button class="btn xs" data-act="close-tab" data-sid="'+esc(w.sessionId)+'" data-tid="'+esc(t.tabId)+'">×</button>'