-
Notifications
You must be signed in to change notification settings - Fork 297
feat(workflow): strengthen iframe-aware execution and extraction #103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 13 commits
ab941a2
c9d6dec
cd9ebc7
cb846ef
1856775
2ccea94
3ec843f
0e46a9f
015fb5c
5bfd65b
207b646
9f3109b
7c4a0cc
1c377b3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -122,6 +122,16 @@ function startRecorder() { | |||||||||||||||||
| emit(event) { | ||||||||||||||||||
| if (!isRecordingActive) return; | ||||||||||||||||||
|
|
||||||||||||||||||
| const frameUrl = window.location.href; | ||||||||||||||||||
| const isTopFrame = window.self === window.top; | ||||||||||||||||||
| const frameIdPath = (() => { | ||||||||||||||||||
| try { | ||||||||||||||||||
| let win: any = window; const parts: number[] = []; | ||||||||||||||||||
| while (win !== win.parent) { const parent = win.parent; let idx=0; for (let i=0;i<parent.frames.length;i++){ if(parent.frames[i]===win){idx=i;break;} } parts.unshift(idx); win=parent; if(parts.length>10) break; } | ||||||||||||||||||
| return parts.length ? parts.join('.') : '0'; | ||||||||||||||||||
| } catch { return '0'; } | ||||||||||||||||||
| })(); | ||||||||||||||||||
|
Comment on lines
+127
to
+133
|
||||||||||||||||||
| const frameIdPath = (() => { | |
| try { | |
| let win: any = window; const parts: number[] = []; | |
| while (win !== win.parent) { const parent = win.parent; let idx=0; for (let i=0;i<parent.frames.length;i++){ if(parent.frames[i]===win){idx=i;break;} } parts.unshift(idx); win=parent; if(parts.length>10) break; } | |
| return parts.length ? parts.join('.') : '0'; | |
| } catch { return '0'; } | |
| })(); | |
| const frameIdPath = getFrameIdPath(); |
Copilot
AI
Oct 26, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] While filtering non-trusted events is good for preventing duplication, a comment explaining why programmatic events cause 'massive duplication' would help future maintainers understand this filtering decision.
| // Ignore programmatic (non user-trusted) input events – these often cause massive duplication | |
| // Ignore programmatic (non user-trusted) input events. | |
| // Many frameworks, scripts, or browser extensions dispatch synthetic input events | |
| // (e.g., via element.value = "foo" or element.dispatchEvent(new Event("input"))). | |
| // These programmatic events can fire in rapid succession or in response to value changes | |
| // that are not user-driven, resulting in a flood of duplicate or irrelevant input events. | |
| // Filtering to only user-trusted events ensures we record only genuine user input, | |
| // preventing massive duplication and keeping the event log meaningful. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| <!doctype html> | ||
| <html> | ||
| <head> | ||
| <meta charset="UTF-8" /> | ||
| <title>Workflow Use - Options</title> | ||
| <style> | ||
| body { font-family: system-ui, sans-serif; margin: 16px; } | ||
| label { display: block; margin: 8px 0 4px; font-weight: 600; } | ||
| textarea { width: 100%; height: 100px; font-family: ui-monospace, monospace; } | ||
| input[type="number"] { width: 160px; } | ||
| .row { margin-bottom: 12px; } | ||
| .hint { color: #555; font-size: 12px; } | ||
| .section { border: 1px solid #ddd; padding: 12px; border-radius: 8px; margin-bottom: 16px; } | ||
| </style> | ||
| </head> | ||
| <body> | ||
| <h2>Recording Settings</h2> | ||
| <div class="section"> | ||
| <div class="row"> | ||
| <label> | ||
| <input type="checkbox" id="enableIframes" /> Enable recording from iframes | ||
| </label> | ||
| <div class="hint">When disabled, iframe-originated navigation/meta events are ignored.</div> | ||
| </div> | ||
| <div class="row"> | ||
| <label for="iframeWindow">Iframe allow window (ms)</label> | ||
| <input type="number" id="iframeWindow" min="0" step="100" /> | ||
| <div class="hint">Time after a user interaction in an iframe during which rrweb meta navigations are allowed.</div> | ||
| </div> | ||
| <div class="row"> | ||
| <label for="blocklist">Blocked domains (newline separated)</label> | ||
| <textarea id="blocklist" placeholder="example.com\nads.example.org"></textarea> | ||
| </div> | ||
| <div class="row"> | ||
| <label for="allowlist">Allowed domains (newline separated)</label> | ||
| <textarea id="allowlist" placeholder="Optional allowlist overrides blocklist"></textarea> | ||
| </div> | ||
| <button id="save">Save</button> | ||
| <span id="status" class="hint"></span> | ||
| </div> | ||
|
|
||
| <script> | ||
| const DEFAULTS = { | ||
| enableIframes: true, | ||
| iframeWindow: 3000, | ||
| blocklist: [ | ||
| 'doubleclick.net','googlesyndication.com','googleadservices.com', | ||
| 'amazon-adsystem.com','2mdn.net','recaptcha.google.com','recaptcha.net', | ||
| 'googletagmanager.com','indexww.com','adtrafficquality.google' | ||
| ], | ||
| allowlist: [], | ||
| }; | ||
|
|
||
| function toLines(str){ return (str||'').split(/\r?\n/).map(s=>s.trim()).filter(Boolean); } | ||
| function fromLines(arr){ return (arr||[]).join('\n'); } | ||
|
|
||
| async function load() { | ||
| const store = await chrome.storage.sync.get(DEFAULTS); | ||
| document.getElementById('enableIframes').checked = !!store.enableIframes; | ||
| document.getElementById('iframeWindow').value = store.iframeWindow; | ||
| document.getElementById('blocklist').value = fromLines(store.blocklist); | ||
| document.getElementById('allowlist').value = fromLines(store.allowlist); | ||
| } | ||
|
|
||
| async function save() { | ||
| const enableIframes = document.getElementById('enableIframes').checked; | ||
| const iframeWindow = parseInt(document.getElementById('iframeWindow').value || '0', 10); | ||
| const blocklist = toLines(document.getElementById('blocklist').value); | ||
| const allowlist = toLines(document.getElementById('allowlist').value); | ||
| await chrome.storage.sync.set({ enableIframes, iframeWindow, blocklist, allowlist }); | ||
| const el = document.getElementById('status'); | ||
| el.textContent = 'Saved'; | ||
| setTimeout(()=> el.textContent = '', 1500); | ||
| } | ||
|
|
||
| document.getElementById('save').addEventListener('click', save); | ||
| load(); | ||
| </script> | ||
| </body> | ||
| </html> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This frameIdPath calculation logic is duplicated in multiple locations (lines 127-132, 556-571, 700-705, 771, 873). Consider extracting this into a shared utility function to improve maintainability and reduce code duplication.