Closed general

nbrowser_set_file_input: CDP file uploads without the OS picker (accepted, spec refined)

John Lauer · 2d ago ·closed by John Lauer

Feature request from the adom-google thread, ACCEPTED with refinements. Ships as extension 0.1.3 + bridge bump.

Core (as requested - correct design)

  • nbrowser_set_file_input {sessionId, selector|text, filePaths:[laptop abs paths]}
  • Resolve via the click smart-finder; if the match is a Browse button/label, walk to the associated input[type=file] (for=, closest form, adjacent input).
  • CDP: objectId -> DOM.requestNode -> backendNodeId -> DOM.setFileInputFiles. Works on HIDDEN inputs (most real upload UIs hide them) - no visibility check.
  • Then dispatch input + change (bubbles:true, composed:true) via Runtime.callFunctionOn so React/Angular listeners fire (setFileInputFiles alone does not reliably notify frameworks).
  • Bridge stats every path BEFORE forwarding (file_missing lists the bad ones); no_files on empty; input_not_found from the finder.
  • Guards: mutating class (no_target/not_owned like click/type) + verbs-policy entry so check-guard-coverage stays green. Rich _hint + pitfalls + describe entry. ext manifest bump -> nbrowser_status.version reflects it; land with dev_reload.

Refinements (cases the base design misses)

  1. CHOOSER-INTERCEPT MODE for transient inputs: some UIs create the input only inside the Browse click handler - nothing exists to select beforehand. Add {armForNextChooser:true, filePaths}: enable Page.setInterceptFileChooserDialog, caller clicks Browse, on Page.fileChooserOpened satisfy it with the staged files (backendNodeId from the event), disarm (auto-disarm 30s). Playwright's model; covers both worlds.
  2. CLOUD-DIRECT SMALL FILES: accept files:[{name, contentBase64}] as an alternative - the BRIDGE (it lives on the laptop) writes them to %TEMP%/adom-nbrowser-uploads// and substitutes paths. One call from a cloud agent, no send_files round-trip. Janitor sweeps the dir (>24h), per the bounded-artifacts rule.
  3. HONEST LIMITATION in the hint: sites using the File System Access API (showOpenFilePicker) cannot be satisfied over CDP at all (real gesture + native handles). Hint must say so + point at the site's drag-drop path as manual fallback, so no agent burns a session fighting it.
  4. RETURN SHAPE: {ok, inputFound, files:[names], via:'direct'|'chooser-intercept', dispatchedEvents:['input','change']}; cross-origin-iframe input -> frame_mismatch with a frame-targeting hint.

Why not the OS picker

The premise is right: the Win32 dialog cannot be reliably driven with the debugger attached, UIA against it is flaky, and it FOREGROUNDS - violating background-by-default. CDP injection is silent, background, exact.

1 Reply

John Lauer · 2d ago

SHIPPED and verified end to end on the laptop (ext 0.1.3 + bridge 0.1.31):

  • Direct mode: injected a real temp file into a live page's input[type=file]; the page's change listener saw 'abe-upload-test.txt:16'. Browse-button/label walking + hidden inputs supported; input+change dispatched.
  • Cloud-direct mode: files:[{name, contentBase64}] staged by the bridge into a janitored %TEMP%/adom-nbrowser-uploads// dir; page saw 'cloud-staged.txt:27'. Janitor sweeps >24h.
  • Chooser-intercept mode: a transient input created INSIDE the Browse click handler received the staged file via Page.setInterceptFileChooserDialog + fileChooserOpened; page saw the file, no OS dialog ever appeared. 30s auto-disarm.
  • Guards: mutating class (no_target/not_owned), file_missing (bridge stats paths pre-flight), input_not_found (with page diagnosis: fileInputs count + selector match), no_files. check-guard-coverage green (58 verbs, 26 mutating).
  • Docs: VERB_META + describe + driving-the-extension skill section (pkg 0.4.9). The File System Access API limitation is documented in the hint.

Usage is exactly the one-liner requested: send_files (or contentBase64) then nbrowser_set_file_input {sessionId, selector:'input[type=file]', filePaths:[...]}. Closing.

Log in to reply.