Phase 1: Quick API Fixes — Missing Browser APIs (caches, dataLayer, Element.animate, relative fetch, HTML detection) #45

Closed
opened 2026-06-18 07:12:24 +00:00 by Artur · 0 comments
Owner

Phase 1: Quick API Fixes — Missing Browser APIs ergänzen

Problembeschreibung

Der 19-Site-Scan zeigt 6+ schnell fixbare Lücken in der Browser-API-Implementierung:

Gap Betroffene Sites Error
Element, Event, Node in buildVarDecls shadowed YouTube, Airbnb, web.dev ReferenceError: Element is not defined
caches API fehlt wasmbyexample.dev, PWA-Sites ReferenceError: caches is not defined
dataLayer nicht initialisiert wasmbyexample.dev, GTM-Sites ReferenceError: dataLayer is not defined
Element.animate fehlt YouTube, Polymer ShadyCSS Sites document.createElement('div').animate is not a function
Relative URL in instrumented fetch Qwik, dynamic relative fetch Invalid URL "/path"
HTML als JS geparsed ALLE Seiten (450+ Vorkommen) SyntaxError: Unexpected token '<'

Lösungsansätze

1.1 buildVarDecls bereinigen — KEINE globalen Constructors shadowen

// RAUS aus buildVarDecls:
var Element = this["Element"];        // → globaler Constructor
var Event = this["Event"];            // → globaler Constructor  
var CustomEvent = this["CustomEvent"];// → globaler Constructor
var EventTarget = this["EventTarget"];// → globaler Constructor
var Node = this["Node"];              // → globaler Constructor
var HTMLElement = this["HTMLElement"];// → globaler Constructor

// Diese sind im global Scope des new Function-Kontexts bereits vorhanden.
// Unser proxyWindow hat sie auf window, das reicht.
// Das Shadowing bricht Polymer/ShadyCSS weil diese Constructors dann undefined sind.

1.2 caches API — noop Implementierung

// In der Window-Initialisierung:
if (!('caches' in proxyWindow)) {
  Object.defineProperty(proxyWindow, 'caches', {
    value: {
      open: async () => undefined,
      match: async () => undefined,
      has: async () => false,
      keys: async () => [],
      delete: async () => false,
    },
    configurable: true,
  });
}

1.3 dataLayer — Default Array

// In der Window-Initialisierung:
if (!proxyWindow.dataLayer) {
  proxyWindow.dataLayer = [];
}

1.4 Element.animate — noop Web Animations

if (!Element.prototype.animate) {
  Element.prototype.animate = function() {
    return {
      finished: Promise.resolve(),
      cancel: () => {},
      play: () => {},
      pause: () => {},
      reverse: () => {},
      startTime: null,
      currentTime: null,
      playbackRate: 1,
      effect: null,
      oncancel: null,
      onfinish: null,
      onremove: null,
      pending: false,
      playState: 'finished',
      replaceState: 'active',
      addEventListener: () => {},
      removeEventListener: () => {},
      dispatchEvent: () => true,
      finish: () => {},
      persist: () => {},
      updatePlaybackRate: () => {},
    };
  };
}

1.5 Relative URL Resolution in fetch

// In src/network/fetch.ts — instrumentedFetch:
async function instrumentedFetch(input, init) {
  // Resolve relative URLs against window.location
  if (typeof input === 'string' && !input.startsWith('http')) {
    const base = window.location?.href ?? 'http://localhost/';
    input = new URL(input, base).href;
  }
  // ... rest
}

1.6 HTML-as-JS erkennen

// In executeRaw / fetchContent:
if (typeof content === 'string' && content.trimStart().startsWith('<')) {
  console.warn(`[ScriptLoader] URL returned HTML instead of JS: ${url}`);
  // Feuere onerror Event statt SyntaxError
  return;
}

Akzeptanzkriterien

  • buildVarDecls shadowt keine globalen Constructors mehr
  • window.caches existiert und ist ein Objekt
  • window.dataLayer existiert als Array
  • Element.animate existiert und returned ein Animation-ähnliches Objekt
  • Relative fetch-URLs werden gegen location.href resolved
  • HTML-Content in Scripts feuert onerror statt SyntaxError
  • Keine Regression: 1423+ bestehende Tests bleiben grün
  • 19-Site-Scan: Keine Element is not defined, caches, dataLayer Fehler mehr

Betroffene Dateien

  • src/js/execution-realm.ts — buildVarDecls bereinigen
  • src/pages/page.ts — Window-Initialisierung (caches, dataLayer, animate)
  • src/network/fetch.ts — Relative URL Resolution
  • src/js/script-loader.ts — HTML detection in executeRaw/fetchContent

Cross-Referenzen

  • ACTION-PLAN.md Phase 1
  • SPEC-GAP-REPORT.md Gaps 5, 9, 10, 11, 7
## Phase 1: Quick API Fixes — Missing Browser APIs ergänzen ### Problembeschreibung Der 19-Site-Scan zeigt 6+ schnell fixbare Lücken in der Browser-API-Implementierung: | Gap | Betroffene Sites | Error | |-----|-----------------|-------| | `Element`, `Event`, `Node` in buildVarDecls shadowed | YouTube, Airbnb, web.dev | `ReferenceError: Element is not defined` | | `caches` API fehlt | wasmbyexample.dev, PWA-Sites | `ReferenceError: caches is not defined` | | `dataLayer` nicht initialisiert | wasmbyexample.dev, GTM-Sites | `ReferenceError: dataLayer is not defined` | | `Element.animate` fehlt | YouTube, Polymer ShadyCSS Sites | `document.createElement('div').animate is not a function` | | Relative URL in instrumented fetch | Qwik, dynamic relative fetch | `Invalid URL "/path"` | | HTML als JS geparsed | ALLE Seiten (450+ Vorkommen) | `SyntaxError: Unexpected token '<'` | ### Lösungsansätze #### 1.1 buildVarDecls bereinigen — KEINE globalen Constructors shadowen ```typescript // RAUS aus buildVarDecls: var Element = this["Element"]; // → globaler Constructor var Event = this["Event"]; // → globaler Constructor var CustomEvent = this["CustomEvent"];// → globaler Constructor var EventTarget = this["EventTarget"];// → globaler Constructor var Node = this["Node"]; // → globaler Constructor var HTMLElement = this["HTMLElement"];// → globaler Constructor // Diese sind im global Scope des new Function-Kontexts bereits vorhanden. // Unser proxyWindow hat sie auf window, das reicht. // Das Shadowing bricht Polymer/ShadyCSS weil diese Constructors dann undefined sind. ``` #### 1.2 caches API — noop Implementierung ```typescript // In der Window-Initialisierung: if (!('caches' in proxyWindow)) { Object.defineProperty(proxyWindow, 'caches', { value: { open: async () => undefined, match: async () => undefined, has: async () => false, keys: async () => [], delete: async () => false, }, configurable: true, }); } ``` #### 1.3 dataLayer — Default Array ```typescript // In der Window-Initialisierung: if (!proxyWindow.dataLayer) { proxyWindow.dataLayer = []; } ``` #### 1.4 Element.animate — noop Web Animations ```typescript if (!Element.prototype.animate) { Element.prototype.animate = function() { return { finished: Promise.resolve(), cancel: () => {}, play: () => {}, pause: () => {}, reverse: () => {}, startTime: null, currentTime: null, playbackRate: 1, effect: null, oncancel: null, onfinish: null, onremove: null, pending: false, playState: 'finished', replaceState: 'active', addEventListener: () => {}, removeEventListener: () => {}, dispatchEvent: () => true, finish: () => {}, persist: () => {}, updatePlaybackRate: () => {}, }; }; } ``` #### 1.5 Relative URL Resolution in fetch ```typescript // In src/network/fetch.ts — instrumentedFetch: async function instrumentedFetch(input, init) { // Resolve relative URLs against window.location if (typeof input === 'string' && !input.startsWith('http')) { const base = window.location?.href ?? 'http://localhost/'; input = new URL(input, base).href; } // ... rest } ``` #### 1.6 HTML-as-JS erkennen ```typescript // In executeRaw / fetchContent: if (typeof content === 'string' && content.trimStart().startsWith('<')) { console.warn(`[ScriptLoader] URL returned HTML instead of JS: ${url}`); // Feuere onerror Event statt SyntaxError return; } ``` ### Akzeptanzkriterien - [ ] buildVarDecls shadowt keine globalen Constructors mehr - [ ] `window.caches` existiert und ist ein Objekt - [ ] `window.dataLayer` existiert als Array - [ ] `Element.animate` existiert und returned ein Animation-ähnliches Objekt - [ ] Relative fetch-URLs werden gegen location.href resolved - [ ] HTML-Content in Scripts feuert onerror statt SyntaxError - [ ] Keine Regression: 1423+ bestehende Tests bleiben grün - [ ] 19-Site-Scan: Keine `Element is not defined`, `caches`, `dataLayer` Fehler mehr ### Betroffene Dateien - `src/js/execution-realm.ts` — buildVarDecls bereinigen - `src/pages/page.ts` — Window-Initialisierung (caches, dataLayer, animate) - `src/network/fetch.ts` — Relative URL Resolution - `src/js/script-loader.ts` — HTML detection in executeRaw/fetchContent ### Cross-Referenzen - ACTION-PLAN.md Phase 1 - SPEC-GAP-REPORT.md Gaps 5, 9, 10, 11, 7
Artur 2026-06-18 07:12:24 +00:00
  • closed this issue
  • added the
    bug
    label
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
glow-all/true-headless-browser#45
No description provided.