document.elementFromPoint(x, y) was undefined, which caused Google
Publisher Tag, viewability libs and any code doing hit-testing to
throw on bootstrap and trigger retry loops in the surrounding
framework. This is one of the throwing APIs feeding into the wedge
described in #62.
Without a layout engine we can't return the actual topmost element,
but a non-throwing stub is strictly better than "undefined" for the
headless-scraping use case:
- coords inside the viewport return document.body (or
document.documentElement as a fallback) so callers that just want
a hit target stop throwing
- coords outside the viewport (negative, > innerWidth/innerHeight,
NaN/Infinity) return null per spec
- elementsFromPoint mirrors the same shape but returns a one- or
zero-length array
- ShadowRoot.prototype gets the same treatment for completeness
Five new unit tests in obscura-js cover function presence, in-viewport
hit, out-of-viewport coords, non-numeric input, and the array shape.
Generated by Ora Studio
Vibe coded by ousamabenyounes
Co-authored-by: Ora Studio <[email protected]>
document.createEvent('CustomEvent') was returning a generic Event,
so the legacy DOM Level 2 pattern
var e = document.createEvent('CustomEvent');
e.initCustomEvent('foo', true, false, payload);
threw "TypeError: e.initCustomEvent is not a function" because the
returned object was an Event, not a CustomEvent — and CustomEvent
didn't define initCustomEvent anyway. The Starbucks China bundle
(and a long tail of other CDN bundles using the same shim) depended
on this and aborted bootstrap.
Two changes in crates/obscura-js/js/bootstrap.js:
1. Add CustomEvent.prototype.initCustomEvent(type, bubbles, cancelable,
detail) matching the spec.
2. Rewrite Document.prototype.createEvent so it dispatches to the
right class based on the type string ('CustomEvent', 'MouseEvent',
'MouseEvents', 'KeyboardEvent', 'FocusEvent', 'InputEvent',
'UIEvent', 'WheelEvent', 'PointerEvent', 'ErrorEvent',
'PopStateEvent', 'AnimationEvent', 'TransitionEvent', and
case-insensitive 'Events' aliases). The HTMLDocument variant on
the second Document class delegates to the canonical impl.
Spec note: createEvent returns the event with an empty type until
init*Event() is called — matched exactly.
Four new unit tests cover initCustomEvent presence and field setters,
class dispatch for CustomEvent / MouseEvent / MouseEvents / KeyboardEvent,
and the unknown-type fallback to Event.
Generated by Ora Studio
Vibe coded by ousamabenyounes
Co-authored-by: Ora Studio <[email protected]>
Playwright (and recent Puppeteer) call Target.attachToBrowserTarget on
connect to obtain a session for the implicit "browser" target. Without
the handler the dispatcher returns "Unknown Target method:
attachToBrowserTarget" and the connect handshake aborts before any
user code runs.
Add a handler that mirrors Target.attachToTarget but for the browser
target: register a "browser-session" → "browser" mapping in
ctx.sessions, emit Target.attachedToTarget with type=browser, and
return the new session id.
Note: this addresses item (1) from #64. The Rocket Loader / Cloudflare
JS execution gap and Page.getLayoutMetrics are tracked separately
(getLayoutMetrics is fixed in PR #79).
Generated by Ora Studio
Vibe coded by ousamabenyounes
Co-authored-by: Ora Studio <[email protected]>
Playwright calls Page.getLayoutMetrics before every page.screenshot() to
size the capture. Without it the call fails with "Unknown Page method:
getLayoutMetrics" and screenshot() throws.
Obscura has no visual layout engine, so we return a fixed 1280x720
viewport (Chrome's default) and try to derive the content height from
document.documentElement.scrollHeight via the JS runtime, falling back
to the viewport height when no live page is bound.
Generated by Ora Studio
Vibe coded by ousamabenyounes
Co-authored-by: Ora Studio <[email protected]>