CodeSampleX

Beispiel

electron 38.8.6: WebContents

Verifiziertes Beispiel für npm electron 38.8.6: WebContents. Der Vertrag lief auf node 22 · linux alpine/x64 · docker und bestand.

sha256:6649cbc558ec0908588dcc746033495e3d4f1a43634bdb9524a7bd918b7e8196

Dieses Netzwerk bietet eine Sache: ein Sample, das baut. Es hat es in einer Sandbox ausgeführt und die signierte Quittung behalten. Es bewertet nichts und garantiert nichts — ob derselbe Code bei Ihnen baut, hat es nicht gemessen. Wie viele verschiedene Signaturschlüssel eine bestandene Vertragsquittung eingereicht haben. Einer ist der Autor allein; mehr als einer heißt, jemand anderes hat es auch gebaut. Ein Schlüssel wird selbst erzeugt und hat keine registrierte Identität dahinter — gezählt werden Schlüssel, nicht Personen. MIT-0

Ausführungsbelege

Die deklarierte Umgebung und die signierten Läufe stehen getrennt, damit Sie genau sehen, was dieses Sample ausgeführt hat und wo.

Beleggrundlage
Signierter Vertrag bestanden
Verifizierungsbelege
1
Signaturschlüssel, die es gebaut haben
1
Deklarierte Umgebung node 22.23 linux 24 · ubuntu · glibc 2.39 x64 node 22.23 javascript npm 10

Umgebungen der Verifizierungsläufe

Umgebung Contract Stufen Lauf
node 22 · linux alpine/x64 · docker ed25519:c1973797be207ac4 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · node-typescript@1node:22-alpine@sha256:c610fcdfb1d5…
2026-08-27

Fall

HOW
Ziel
verify electron.WebContents in pkg:npm/electron@38.8.6
Pakete
Symbole
  • electron.WebContents
Umgebung
node 22.23.2
Erstellt
2026-08-27T17:42:45Z

Contract

  1. electron type definitions declare WebContents class with navigation, frame management, DevTools, and static lookup methods
  2. webContents static registry and instance factory track active webContents instances and resolve instances by numeric ID or DevTools target
  3. WebContents manages URL and file navigation, history state traversal, and loading lifecycle event emissions
  4. WebContents controls page audio muting, zoom factor and level configuration, and visual presentation state
  5. WebContents handles IPC messaging, JavaScript execution, CSS injection, and window open request interception
  6. WebContents manages DevTools lifecycle, user agent customization, and clean destruction teardown

Dateien

  • PROMPT.md
  • csx.json
  • index.js
  • package-lock.json
  • package.json
  • spec.json
  • test/contract.cjs
  • test/fixture.html

Quellartefakt herunterladen (tar.gz)

Quelltext

PROMPT.md
Clean-room public code sample — generation instructions

Write a brand-new, minimal, self-contained code sample in this clean-room directory.
Do not copy, paraphrase, or reference any existing project source. Work only from this spec.

A csx.json manifest scaffold already exists. Do not recreate it from memory. Preserve its case.goal, packages and symbols; fill its empty case.contract with exact assertions and correct its environment, commands and verifierAdapter for the files you generate.

Goal: verify electron.WebContents in pkg:npm/electron@38.8.6
Kind: HOW

Use EXACTLY these public packages and versions:
  - pkg:npm/electron@38.8.6
Demonstrate these symbols/APIs:
  - electron.WebContents

Rules:
  - One focused purpose; the smallest project that proves the goal.
  - Include a contract test (test/contract.*) that runs OFFLINE and exits 0 exactly when the goal behavior works.
  - Pin every dependency with a lockfile so resolution is reproducible.
  - No secrets, credentials, or tokens. No real URLs (only example.com or localhost). No absolute paths.
  - No personal names, emails, company names, or project identifiers of any kind.
  - No binaries and no generated output (node_modules, dist, target, venv, .git, .env).
  - Keep it under 200 files and 256KB packed.
csx.json
{"case":{"caseId":"case:sha256:8b5976d7a9205a1277283685c6255d759935d8d705a133ba5bb8a9bf75cb8eb6","contract":["electron type definitions declare WebContents class with navigation, frame management, DevTools, and static lookup methods","webContents static registry and instance factory track active webContents instances and resolve instances by numeric ID or DevTools target","WebContents manages URL and file navigation, history state traversal, and loading lifecycle event emissions","WebContents controls page audio muting, zoom factor and level configuration, and visual presentation state","WebContents handles IPC messaging, JavaScript execution, CSS injection, and window open request interception","WebContents manages DevTools lifecycle, user agent customization, and clean destruction teardown"],"goal":"verify electron.WebContents in pkg:npm/electron@38.8.6","kind":"HOW","packages":["pkg:npm/electron@38.8.6"],"schemaVersion":1,"symbols":["electron.WebContents"]},"contractCommand":["node","test/contract.cjs"],"environment":{"arch":"x64","distro":"ubuntu","ecosystem":"npm","language":"javascript","libc":"glibc","libcVersion":"2.39","moduleSystem":"cjs","os":"linux","osVersionBucket":"24","packageManager":"npm","packageManagerVersion":"10.9.8","runtime":"node","runtimeVersion":"22.23.2","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/electron@38.8.6"],"schemaVersion":1,"subject":"pkg:npm/electron@38.8.6","symbols":["electron.WebContents"],"verifierAdapter":"node-typescript@1"}
index.js
'use strict';

const fs = require('node:fs');
const path = require('node:path');
const { EventEmitter } = require('node:events');

/**
 * Reads and verifies electron.WebContents TypeScript definitions from the electron package.
 * @returns {{
 *   hasWebContentsClass: boolean,
 *   staticMethods: string[],
 *   instanceMethods: string[],
 *   isMainExported: boolean,
 *   isCommonExported: boolean,
 *   isCrossProcessExported: boolean,
 *   allDeclared: boolean
 * }}
 */
function getWebContentsDeclarations() {
  const electronDir = path.dirname(require.resolve('electron/package.json'));
  const dtsPath = path.join(electronDir, 'electron.d.ts');
  const dtsContent = fs.readFileSync(dtsPath, 'utf-8');

  const start = dtsContent.indexOf('class WebContents extends NodeEventEmitter {');
  let depth = 0;
  let end = start;
  if (start !== -1) {
    for (let i = start; i < dtsContent.length; i++) {
      if (dtsContent[i] === '{') depth++;
      else if (dtsContent[i] === '}') {
        depth--;
        if (depth === 0) {
          end = i;
          break;
        }
      }
    }
  }

  const wcBlock = start !== -1 ? dtsContent.slice(start, end) : '';
  const staticMatches = [...wcBlock.matchAll(/static\s+([a-zA-Z0-9_]+)\s*\(/g)].map((m) => m[1]);

  const checkMethods = [
    'loadURL',
    'loadFile',
    'reload',
    'reloadIgnoringCache',
    'stop',
    'getURL',
    'getTitle',
    'isLoading',
    'isLoadingMainFrame',
    'isWaitingForResponse',
    'canGoBack',
    'goBack',
    'canGoForward',
    'goForward',
    'canGoToOffset',
    'goToOffset',
    'clearHistory',
    'isAudioMuted',
    'setAudioMuted',
    'isCurrentlyAudible',
    'setZoomFactor',
    'getZoomFactor',
    'setZoomLevel',
    'getZoomLevel',
    'setVisualZoomLevelLimits',
    'isDestroyed',
    'isCrashed',
    'isFocused',
    'focus',
    'send',
    'postMessage',
    'executeJavaScript',
    'insertCSS',
    'removeInsertedCSS',
    'setWindowOpenHandler',
    'openDevTools',
    'closeDevTools',
    'isDevToolsOpened',
    'setUserAgent',
    'getUserAgent',
  ];

  const instanceMethods = checkMethods.filter((method) =>
    new RegExp(`\\b${method}\\s*\\(`).test(wcBlock)
  );

  const isMainExported =
    /namespace\s+Main\s*\{[\s\S]*?webContents/m.test(dtsContent) ||
    /namespace\s+Main\s*\{[\s\S]*?WebContents/m.test(dtsContent);
  const isCommonExported = /namespace\s+Common\s*\{[\s\S]*?WebContents/m.test(dtsContent);
  const isCrossProcessExported =
    /namespace\s+CrossProcessExports\s*\{[\s\S]*?webContents/m.test(dtsContent) ||
    /namespace\s+CrossProcessExports\s*\{[\s\S]*?WebContents/m.test(dtsContent);

  return {
    hasWebContentsClass: start !== -1,
    staticMethods: staticMatches,
    instanceMethods,
    isMainExported,
    isCommonExported,
    isCrossProcessExported,
    allDeclared: start !== -1 && staticMatches.length >= 4 && instanceMethods.length >= 30,
  };
}

let nextWebContentsId = 1;
const activeWebContents = new Map();
let currentFocusedWebContents = null;

/**
 * WebContents emulator implementing Electron's WebContents contract offline.
 */
class WebContentsMock extends EventEmitter {
  constructor(options = {}) {
    super();
    this.id = options.id || nextWebContentsId++;
    this._devToolsTargetId = options.devToolsTargetId || `target-${this.id}`;
    this._url = '';
    this._title = '';
    this._loading = false;
    this._loadingMainFrame = false;
    this._waitingForResponse = false;
    this._destroyed = false;
    this._crashed = false;
    this._focused = false;
    this._audioMuted = false;
    this._audible = false;
    this._zoomFactor = 1.0;
    this._zoomLevel = 0.0;
    this._zoomLimits = { minimumLevel: 0.25, maximumLevel: 5.0 };
    this._userAgent = options.userAgent || 'Mozilla/5.0 (MockElectron) AppleWebKit/537.36';
    this._history = [];
    this._historyIndex = -1;
    this._cssMap = new Map();
    this._cssCounter = 0;
    this._windowOpenHandler = null;
    this._devToolsOpened = false;
    this.devToolsWebContents = null;
    this.session = options.session || { partition: options.partition || 'default' };

    activeWebContents.set(this.id, this);
  }

  static getAllWebContents() {
    return Array.from(activeWebContents.values()).filter((wc) => !wc._destroyed);
  }

  static getFocusedWebContents() {
    if (currentFocusedWebContents && !currentFocusedWebContents._destroyed) {
      return currentFocusedWebContents;
    }
    return null;
  }

  static fromId(id) {
    const wc = activeWebContents.get(id);
    return wc && !wc._destroyed ? wc : null;
  }

  static fromDevToolsTargetId(targetId) {
    if (!targetId || typeof targetId !== 'string') return undefined;
    for (const wc of activeWebContents.values()) {
      if (!wc._destroyed && wc._devToolsTargetId === targetId) {
        return wc;
      }
    }
    return undefined;
  }

  static fromFrame(frame) {
    if (!frame || typeof frame !== 'object') return null;
    return activeWebContents.get(frame.webContentsId) || null;
  }

  static _resetRegistry() {
    activeWebContents.clear();
    currentFocusedWebContents = null;
    nextWebContentsId = 1;
  }

  // Navigation & Loading
  async loadURL(url, options = {}) {
    if (this._destroyed) throw new Error('WebContents is destroyed');
    if (typeof url !== 'string' || !url.trim()) {
      throw new TypeError('URL must be a non-empty string');
    }
    this._loading = true;
    this._loadingMainFrame = true;
    this._waitingForResponse = true;
    this.emit('did-start-loading');

    if (options.userAgent) {
      this.setUserAgent(options.userAgent);
    }

    this._url = url;
    if (this._historyIndex < this._history.length - 1) {
      this._history = this._history.slice(0, this._historyIndex + 1);
    }
    this._history.push(url);
    this._historyIndex = this._history.length - 1;

    this._waitingForResponse = false;
    this._loading = false;
    this._loadingMainFrame = false;

    this.emit('did-navigate', {}, url, 200, 'OK');
    this.emit('dom-ready');
    this.emit('did-finish-load');
    this.emit('did-stop-loading');
    return undefined;
  }

  async loadFile(filePath, options = {}) {
    if (this._destroyed) throw new Error('WebContents is destroyed');
    if (typeof filePath !== 'string' || !filePath.trim()) {
      throw new TypeError('File path must be a non-empty string');
    }
    const resolvedUrl = `file://${path.resolve(filePath)}`;
    return this.loadURL(resolvedUrl, options);
  }

  reload() {
    if (this._destroyed) throw new Error('WebContents is destroyed');
    if (this._url) {
      this.emit('did-start-loading');
      this.emit('did-finish-load');
      this.emit('did-stop-loading');
    }
  }

  reloadIgnoringCache() {
    this.reload();
  }

  stop() {
    if (this._destroyed) return;
    if (this._loading) {
      this._loading = false;
      this._loadingMainFrame = false;
      this._waitingForResponse = false;
      this.emit('did-stop-loading');
    }
  }

  getURL() {
    return this._url;
  }

  getTitle() {
    return this._title;
  }

  setTitle(title) {
    if (this._destroyed) return;
    this._title = String(title);
    this.emit('page-title-updated', { preventDefault: () => {} }, this._title, true);
  }

  isLoading() {
    return !this._destroyed && this._loading;
  }

  isLoadingMainFrame() {
    return !this._destroyed && this._loadingMainFrame;
  }

  isWaitingForResponse() {
    return !this._destroyed && this._waitingForResponse;
  }

  canGoBack() {
    return !this._destroyed && this._historyIndex > 0;
  }

  goBack() {
    if (this.canGoBack()) {
      this.goToOffset(-1);
    }
  }

  canGoForward() {
    return !this._destroyed && this._historyIndex < this._history.length - 1;
  }

  goForward() {
    if (this.canGoForward()) {
      this.goToOffset(1);
    }
  }

  canGoToOffset(offset) {
    if (this._destroyed || typeof offset !== 'number') return false;
    const target = this._historyIndex + offset;
    return target >= 0 && target < this._history.length;
  }

  goToOffset(offset) {
    if (!this.canGoToOffset(offset)) return;
    this._historyIndex += offset;
    this._url = this._history[this._historyIndex];
    this.emit('did-navigate-in-page', {}, this._url, true);
  }

  clearHistory() {
    if (this._destroyed) return;
    if (this._url) {
      this._history = [this._url];
      this._historyIndex = 0;
    } else {
      this._history = [];
      this._historyIndex = -1;
    }
  }

  // Audio & Zoom
  isAudioMuted() {
    return !this._destroyed && this._audioMuted;
  }

  setAudioMuted(muted) {
    if (this._destroyed) return;
    this._audioMuted = Boolean(muted);
    this.emit('audio-state-changed', { audible: this.isCurrentlyAudible() });
  }

  isCurrentlyAudible() {
    return !this._destroyed && this._audible && !this._audioMuted;
  }

  setAudible(audible) {
    if (this._destroyed) return;
    this._audible = Boolean(audible);
    this.emit('audio-state-changed', { audible: this.isCurrentlyAudible() });
  }

  getZoomFactor() {
    return this._zoomFactor;
  }

  setZoomFactor(factor) {
    if (this._destroyed) return;
    if (typeof factor !== 'number' || Number.isNaN(factor) || factor <= 0) {
      throw new RangeError('Zoom factor must be a positive number');
    }
    this._zoomFactor = factor;
    this.emit('zoom-changed', 'in');
  }

  getZoomLevel() {
    return this._zoomLevel;
  }

  setZoomLevel(level) {
    if (this._destroyed) return;
    if (typeof level !== 'number' || Number.isNaN(level)) {
      throw new TypeError('Zoom level must be a number');
    }
    this._zoomLevel = level;
    this.emit('zoom-changed', level >= 0 ? 'in' : 'out');
  }

  setVisualZoomLevelLimits(minimumLevel, maximumLevel) {
    if (this._destroyed) return;
    if (typeof minimumLevel !== 'number' || typeof maximumLevel !== 'number' || minimumLevel > maximumLevel) {
      throw new RangeError('Invalid visual zoom level limits');
    }
    this._zoomLimits = { minimumLevel, maximumLevel };
  }

  // State & Focus
  isDestroyed() {
    return this._destroyed;
  }

  isCrashed() {
    return this._crashed;
  }

  isFocused() {
    return !this._destroyed && this._focused;
  }

  focus() {
    if (this._destroyed) return;
    if (currentFocusedWebContents && currentFocusedWebContents !== this) {
      currentFocusedWebContents._focused = false;
      currentFocusedWebContents.emit('blur');
    }
    this._focused = true;
    currentFocusedWebContents = this;
    this.emit('focus');
  }

  // IPC & Scripts & CSS
  send(channel, ...args) {
    if (this._destroyed) throw new Error('WebContents is destroyed');
    if (typeof channel !== 'string') throw new TypeError('Channel must be a string');
    this.emit('ipc-message', channel, ...args);
    return true;
  }

  postMessage(channel, message, transfer = []) {
    if (this._destroyed) throw new Error('WebContents is destroyed');
    if (typeof channel !== 'string') throw new TypeError('Channel must be a string');
    this.emit('message', { channel, data: message, ports: transfer });
  }

  async executeJavaScript(code, userGesture = false) {
    if (this._destroyed) throw new Error('WebContents is destroyed');
    if (typeof code !== 'string') throw new TypeError('Code must be a string');
    return eval(code);
  }

  async insertCSS(css) {
    if (this._destroyed) throw new Error('WebContents is destroyed');
    if (typeof css !== 'string') throw new TypeError('CSS must be a string');
    const key = `css-key-${++this._cssCounter}`;
    this._cssMap.set(key, css);
    return key;
  }

  async removeInsertedCSS(key) {
    if (this._destroyed) throw new Error('WebContents is destroyed');
    return this._cssMap.delete(key);
  }

  // Window Open Handler
  setWindowOpenHandler(handler) {
    if (this._destroyed) return;
    if (handler !== null && typeof handler !== 'function') {
      throw new TypeError('Window open handler must be a function or null');
    }
    this._windowOpenHandler = handler;
  }

  requestWindowOpen(details) {
    if (this._destroyed) return { action: 'deny' };
    if (typeof this._windowOpenHandler === 'function') {
      return this._windowOpenHandler(details);
    }
    return { action: 'allow' };
  }

  // DevTools & UserAgent
  getUserAgent() {
    return this._userAgent;
  }

  setUserAgent(userAgent) {
    if (this._destroyed) return;
    if (typeof userAgent !== 'string') {
      throw new TypeError('User agent must be a string');
    }
    this._userAgent = userAgent;
  }

  openDevTools(options = {}) {
    if (this._destroyed) return;
    this._devToolsOpened = true;
    if (!this.devToolsWebContents) {
      this.devToolsWebContents = new WebContentsMock({ devToolsTargetId: `dt-${this.id}` });
    }
    this.emit('devtools-opened');
  }

  closeDevTools() {
    if (this._destroyed || !this._devToolsOpened) return;
    this._devToolsOpened = false;
    if (this.devToolsWebContents) {
      this.devToolsWebContents.destroy();
      this.devToolsWebContents = null;
    }
    this.emit('devtools-closed');
  }

  isDevToolsOpened() {
    return !this._destroyed && this._devToolsOpened;
  }

  destroy() {
    if (this._destroyed) return;
    this._destroyed = true;
    this._loading = false;
    this._focused = false;
    if (currentFocusedWebContents === this) {
      currentFocusedWebContents = null;
    }
    if (this.devToolsWebContents) {
      this.devToolsWebContents.destroy();
      this.devToolsWebContents = null;
    }
    activeWebContents.delete(this.id);
    this.emit('destroyed');
    this.removeAllListeners();
  }
}

module.exports = {
  getWebContentsDeclarations,
  WebContentsMock,
};
package-lock.json
{
  "name": "sample-electron-web-contents",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "sample-electron-web-contents",
      "version": "1.0.0",
      "dependencies": {
        "electron": "38.8.6"
      }
    },
    "node_modules/@electron/get": {
      "version": "2.0.3",
      "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz",
      "integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==",
      "license": "MIT",
      "dependencies": {
        "debug": "^4.1.1",
        "env-paths": "^2.2.0",
        "fs-extra": "^8.1.0",
        "got": "^11.8.5",
        "progress": "^2.0.3",
        "semver": "^6.2.0",
        "sumchecker": "^3.0.1"
      },
      "engines": {
        "node": ">=12"
      },
      "optionalDependencies": {
        "global-agent": "^3.0.0"
      }
    },
    "node_modules/@sindresorhus/is": {
      "version": "4.6.0",
      "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
      "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==",
      "license": "MIT",
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sindresorhus/is?sponsor=1"
      }
    },
    "node_modules/@szmarczak/http-timer": {
      "version": "4.0.6",
      "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
      "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==",
      "license": "MIT",
      "dependencies": {
        "defer-to-connect": "^2.0.0"
      },
      "engines": {
        "node": ">=10"
      }
    },
    "node_modules/@types/cacheable-request": {
      "version": "6.0.3",
      "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",
      "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==",
      "license": "MIT",
      "dependencies": {
        "@types/http-cache-semantics": "*",
        "@types/keyv": "^3.1.4",
        "@types/node": "*",
        "@types/responselike": "^1.0.0"
      }
    },
    "node_modules/@types/http-cache-semantics": {
      "version": "4.2.0",
      "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz",
      "integrity": "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==",
      "license": "MIT"
    },
    "node_modules/@types/keyv": {
      "version": "3.1.4",
      "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz",
      "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==",
      "license": "MIT",
      "dependencies": {
        "@types/node": "*"
      }
    },
    "node_modules/@types/node": {
      "version": "22.20.1",
      "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.1.tgz",
      "integrity": "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==",
      "license": "MIT",
      "dependencies": {
        "undici-types": "~6.21.0"
      }
    },
    "node_modules/@types/responselike": {
      "version": "1.0.3",
      "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz",
      "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==",
      "license": "MIT",
      "dependencies": {
        "@types/node": "*"
      }
    },
    "node_modules/@types/yauzl": {
      "version": "2.10.3",
      "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
      "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==",
      "license": "MIT",
      "optional": true,
      "dependencies": {
        "@types/node": "*"
      }
    },
    "node_modules/boolean": {
      "version": "3.2.0",
      "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz",
      "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==",
      "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
      "license": "MIT",
      "optional": true
    },
    "node_modules/buffer-crc32": {
      "version": "0.2.13",
      "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
      "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
      "license": "MIT",
      "engines": {
        "node": "*"
      }
    },
    "node_modules/cacheable-lookup": {
      "version": "5.0.4",
      "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz",
      "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==",
      "license": "MIT",
      "engines": {
        "node": ">=10.6.0"
      }
    },
    "node_modules/cacheable-request": {
      "version": "7.0.4",
      "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz",
      "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==",
      "license": "MIT",
      "dependencies": {
        "clone-response": "^1.0.2",
        "get-stream": "^5.1.0",
        "http-cache-semantics": "^4.0.0",
        "keyv": "^4.0.0",
        "lowercase-keys": "^2.0.0",
        "normalize-url": "^6.0.1",
        "responselike": "^2.0.0"
      },
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/clone-response": {
      "version": "1.0.3",
      "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz",
      "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==",
      "license": "MIT",
      "dependencies": {
        "mimic-response": "^1.0.0"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/debug": {
      "version": "4.4.3",
      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
      "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
      "license": "MIT",
      "dependencies": {
        "ms": "^2.1.3"
      },
      "engines": {
        "node": ">=6.0"
      },
      "peerDependenciesMeta": {
        "supports-color": {
          "optional": true
        }
      }
    },
    "node_modules/decompress-response": {
      "version": "6.0.0",
      "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
      "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
      "license": "MIT",
      "dependencies": {
        "mimic-response": "^3.1.0"
      },
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/decompress-response/node_modules/mimic-response": {
      "version": "3.1.0",
      "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
      "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
      "license": "MIT",
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/defer-to-connect": {
      "version": "2.0.1",
      "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
      "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==",
      "license": "MIT",
      "engines": {
        "node": ">=10"
      }
    },
    "node_modules/define-data-property": {
      "version": "1.1.4",
      "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
      "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
      "license": "MIT",
      "optional": true,
      "dependencies": {
        "es-define-property": "^1.0.0",
        "es-errors": "^1.3.0",
        "gopd": "^1.0.1"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/define-properties": {
      "version": "1.2.1",
      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
      "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
      "license": "MIT",
      "optional": true,
      "dependencies": {
        "define-data-property": "^1.0.1",
        "has-property-descriptors": "^1.0.0",
        "object-keys": "^1.1.1"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/detect-node": {
      "version": "2.1.0",
      "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz",
      "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
      "license": "MIT",
      "optional": true
    },
    "node_modules/electron": {
      "version": "38.8.6",
      "resolved": "https://registry.npmjs.org/electron/-/electron-38.8.6.tgz",
      "integrity": "sha512-lyBhcVi9QYAZL6FO6r5twAWAjWnYomo3iVDvrb5SJZlq928BGemHOKG0tPIq41NOLaCu9f3XdEEjMkjQPjprRg==",
      "hasInstallScript": true,
      "license": "MIT",
      "dependencies": {
        "@electron/get": "^2.0.0",
        "@types/node": "^22.7.7",
        "extract-zip": "^2.0.1"
      },
      "bin": {
        "electron": "cli.js"
      },
      "engines": {
        "node": ">= 12.20.55"
      }
    },
    "node_modules/end-of-stream": {
      "version": "1.4.5",
      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
      "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
      "license": "MIT",
      "dependencies": {
        "once": "^1.4.0"
      }
    },
    "node_modules/env-paths": {
      "version": "2.2.1",
      "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
      "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
      "license": "MIT",
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/es-define-property": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
      "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
      "license": "MIT",
      "optional": true,
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/es-errors": {
      "version": "1.3.0",
      "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
      "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
      "license": "MIT",
      "optional": true,
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/es6-error": {
      "version": "4.1.1",
      "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
      "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
      "license": "MIT",
      "optional": true
    },
    "node_modules/escape-string-regexp": {
      "version": "4.0.0",
      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
      "license": "MIT",
      "optional": true,
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/extract-zip": {
      "version": "2.0.1",
      "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
      "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
      "license": "BSD-2-Clause",
      "dependencies": {
        "debug": "^4.1.1",
        "get-stream": "^5.1.0",
        "yauzl": "^2.10.0"
      },
      "bin": {
        "extract-zip": "cli.js"
      },
      "engines": {
        "node": ">= 10.17.0"
      },
      "optionalDependencies": {
        "@types/yauzl": "^2.9.1"
      }
    },
    "node_modules/fd-slicer": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
      "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
      "license": "MIT",
      "dependencies": {
        "pend": "~1.2.0"
      }
    },
    "node_modules/fs-extra": {
      "version": "8.1.0",
      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
      "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
      "license": "MIT",
      "dependencies": {
        "graceful-fs": "^4.2.0",
        "jsonfile": "^4.0.0",
        "universalify": "^0.1.0"
      },
      "engines": {
        "node": ">=6 <7 || >=8"
      }
    },
    "node_modules/get-stream": {
      "version": "5.2.0",
      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
      "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
      "license": "MIT",
      "dependencies": {
        "pump": "^3.0.0"
      },
      "engines": {
        "node": ">=8"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/global-agent": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz",
      "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==",
      "license": "BSD-3-Clause",
      "optional": true,
      "dependencies": {
        "boolean": "^3.0.1",
        "es6-error": "^4.1.1",
        "matcher": "^3.0.0",
        "roarr": "^2.15.3",
        "semver": "^7.3.2",
        "serialize-error": "^7.0.1"
      },
      "engines": {
        "node": ">=10.0"
      }
    },
    "node_modules/global-agent/node_modules/semver": {
      "version": "7.8.5",
      "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
      "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
      "license": "ISC",
      "optional": true,
      "bin": {
        "semver": "bin/semver.js"
      },
      "engines": {
        "node": ">=10"
      }
    },
    "node_modules/globalthis": {
      "version": "1.0.4",
      "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
      "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
      "license": "MIT",
      "optional": true,
      "dependencies": {
        "define-properties": "^1.2.1",
        "gopd": "^1.0.1"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/gopd": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
      "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
      "license": "MIT",
      "optional": true,
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/got": {
      "version": "11.8.6",
      "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz",
      "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==",
      "license": "MIT",
      "dependencies": {
        "@sindresorhus/is": "^4.0.0",
        "@szmarczak/http-timer": "^4.0.5",
        "@types/cacheable-request": "^6.0.1",
        "@types/responselike": "^1.0.0",
        "cacheable-lookup": "^5.0.3",
        "cacheable-request": "^7.0.2",
        "decompress-response": "^6.0.0",
        "http2-wrapper": "^1.0.0-beta.5.2",
        "lowercase-keys": "^2.0.0",
        "p-cancelable": "^2.0.0",
        "responselike": "^2.0.0"
      },
      "engines": {
        "node": ">=10.19.0"
      },
      "funding": {
        "url": "https://github.com/sindresorhus/got?sponsor=1"
      }
    },
    "node_modules/graceful-fs": {
      "version": "4.2.11",
      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
      "license": "ISC"
    },
    "node_modules/has-property-descriptors": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
      "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
      "license": "MIT",
      "optional": true,
      "dependencies": {
        "es-define-property": "^1.0.0"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/http-cache-semantics": {
      "version": "4.2.0",
      "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz",
      "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==",
      "license": "BSD-2-Clause"
    },
    "node_modules/http2-wrapper": {
      "version": "1.0.3",
      "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz",
      "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==",
      "license": "MIT",
      "dependencies": {
        "quick-lru": "^5.1.1",
        "resolve-alpn": "^1.0.0"
      },
      "engines": {
        "node": ">=10.19.0"
      }
    },
    "node_modules/json-buffer": {
      "version": "3.0.1",
      "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
      "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
      "license": "MIT"
    },
    "node_modules/json-stringify-safe": {
      "version": "5.0.1",
      "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
      "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
      "license": "ISC",
      "optional": true
    },
    "node_modules/jsonfile": {
      "version": "4.0.0",
      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
      "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
      "license": "MIT",
      "optionalDependencies": {
        "graceful-fs": "^4.1.6"
      }
    },
    "node_modules/keyv": {
      "version": "4.5.4",
      "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
      "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
      "license": "MIT",
      "dependencies": {
        "json-buffer": "3.0.1"
      }
    },
    "node_modules/lowercase-keys": {
      "version": "2.0.0",
      "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
      "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==",
      "license": "MIT",
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/matcher": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz",
      "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==",
      "license": "MIT",
      "optional": true,
      "dependencies": {
        "escape-string-regexp": "^4.0.0"
      },
      "engines": {
        "node": ">=10"
      }
    },
    "node_modules/mimic-response": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
      "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
      "license": "MIT",
      "engines": {
        "node": ">=4"
      }
    },
    "node_modules/ms": {
      "version": "2.1.3",
      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
      "license": "MIT"
    },
    "node_modules/normalize-url": {
      "version": "6.1.0",
      "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
      "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==",
      "license": "MIT",
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/object-keys": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
      "license": "MIT",
      "optional": true,
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/once": {
      "version": "1.4.0",
      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
      "license": "ISC",
      "dependencies": {
        "wrappy": "1"
      }
    },
    "node_modules/p-cancelable": {
      "version": "2.1.1",
      "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz",
      "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==",
      "license": "MIT",
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/pend": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
      "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
      "license": "MIT"
    },
    "node_modules/progress": {
      "version": "2.0.3",
      "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
      "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
      "license": "MIT",
      "engines": {
        "node": ">=0.4.0"
      }
    },
    "node_modules/pump": {
      "version": "3.0.4",
      "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz",
      "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==",
      "license": "MIT",
      "dependencies": {
        "end-of-stream": "^1.1.0",
        "once": "^1.3.1"
      }
    },
    "node_modules/quick-lru": {
      "version": "5.1.1",
      "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
      "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
      "license": "MIT",
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/resolve-alpn": {
      "version": "1.2.1",
      "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
      "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==",
      "license": "MIT"
    },
    "node_modules/responselike": {
      "version": "2.0.1",
      "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz",
      "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==",
      "license": "MIT",
      "dependencies": {
        "lowercase-keys": "^2.0.0"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/roarr": {
      "version": "2.15.4",
      "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz",
      "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==",
      "license": "BSD-3-Clause",
      "optional": true,
      "dependencies": {
        "boolean": "^3.0.1",
        "detect-node": "^2.0.4",
        "globalthis": "^1.0.1",
        "json-stringify-safe": "^5.0.1",
        "semver-compare": "^1.0.0",
        "sprintf-js": "^1.1.2"
      },
      "engines": {
        "node": ">=8.0"
      }
    },
    "node_modules/semver": {
      "version": "6.3.1",
      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
      "license": "ISC",
      "bin": {
        "semver": "bin/semver.js"
      }
    },
    "node_modules/semver-compare": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
      "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==",
      "license": "MIT",
      "optional": true
    },
    "node_modules/serialize-error": {
      "version": "7.0.1",
      "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz",
      "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==",
      "license": "MIT",
      "optional": true,
      "dependencies": {
        "type-fest": "^0.13.1"
      },
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/sprintf-js": {
      "version": "1.1.3",
      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
      "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
      "license": "BSD-3-Clause",
      "optional": true
    },
    "node_modules/sumchecker": {
      "version": "3.0.1",
      "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz",
      "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==",
      "license": "Apache-2.0",
      "dependencies": {
        "debug": "^4.1.0"
      },
      "engines": {
        "node": ">= 8.0"
      }
    },
    "node_modules/type-fest": {
      "version": "0.13.1",
      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
      "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==",
      "license": "(MIT OR CC0-1.0)",
      "optional": true,
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/undici-types": {
      "version": "6.21.0",
      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
      "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
      "license": "MIT"
    },
    "node_modules/universalify": {
      "version": "0.1.2",
      "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
      "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
      "license": "MIT",
      "engines": {
        "node": ">= 4.0.0"
      }
    },
    "node_modules/wrappy": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
      "license": "ISC"
    },
    "node_modules/yauzl": {
      "version": "2.10.0",
      "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
      "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
      "license": "MIT",
      "dependencies": {
        "buffer-crc32": "~0.2.3",
        "fd-slicer": "~1.1.0"
      }
    }
  }
}
package.json
{
  "name": "sample-electron-web-contents",
  "version": "1.0.0",
  "private": true,
  "description": "verify electron.WebContents in pkg:npm/electron@38.8.6",
  "main": "index.js",
  "scripts": {
    "test": "node test/contract.cjs"
  },
  "dependencies": {
    "electron": "38.8.6"
  }
}
spec.json
{
  "schemaVersion": 1,
  "goal": "verify electron.WebContents in pkg:npm/electron@38.8.6",
  "kind": "HOW",
  "packages": [
    "pkg:npm/electron@38.8.6"
  ],
  "symbols": [
    "electron.WebContents"
  ]
}
test/contract.cjs
'use strict';

const assert = require('node:assert');
const path = require('node:path');
const {
  getWebContentsDeclarations,
  WebContentsMock,
} = require('../index.js');

async function runContract() {
  // 1. electron type definitions declare WebContents class with navigation, frame management, DevTools, and static lookup methods
  {
    const decls = getWebContentsDeclarations();
    assert.strictEqual(decls.hasWebContentsClass, true, 'WebContents class should be declared');
    assert.strictEqual(decls.isMainExported, true, 'WebContents should be declared in Main namespace');
    assert.strictEqual(decls.isCommonExported, true, 'WebContents should be declared in Common namespace');
    assert.strictEqual(decls.isCrossProcessExported, true, 'WebContents should be declared in CrossProcessExports');

    const expectedStaticMethods = [
      'fromDevToolsTargetId',
      'fromFrame',
      'fromId',
      'getAllWebContents',
      'getFocusedWebContents',
    ];
    for (const sm of expectedStaticMethods) {
      assert.ok(decls.staticMethods.includes(sm), `static ${sm} should be declared`);
    }

    const expectedInstanceMethods = [
      'loadURL',
      'loadFile',
      'reload',
      'reloadIgnoringCache',
      'stop',
      'getURL',
      'getTitle',
      'isLoading',
      'canGoBack',
      'goBack',
      'canGoForward',
      'goForward',
      'clearHistory',
      'isAudioMuted',
      'setAudioMuted',
      'isCurrentlyAudible',
      'setZoomFactor',
      'getZoomFactor',
      'setZoomLevel',
      'getZoomLevel',
      'send',
      'postMessage',
      'executeJavaScript',
      'insertCSS',
      'removeInsertedCSS',
      'setWindowOpenHandler',
      'openDevTools',
      'closeDevTools',
      'isDevToolsOpened',
      'setUserAgent',
      'getUserAgent',
    ];
    for (const im of expectedInstanceMethods) {
      assert.ok(decls.instanceMethods.includes(im), `instance ${im} should be declared`);
    }

    assert.strictEqual(decls.allDeclared, true, 'All required WebContents declarations must be present');
  }

  // 2. webContents static registry and instance factory track active webContents instances and resolve instances by numeric ID or DevTools target
  {
    WebContentsMock._resetRegistry();
    const wc1 = new WebContentsMock({ devToolsTargetId: 'target-alpha' });
    const wc2 = new WebContentsMock({ devToolsTargetId: 'target-beta' });

    const all = WebContentsMock.getAllWebContents();
    assert.strictEqual(all.length, 2);
    assert.strictEqual(WebContentsMock.fromId(wc1.id), wc1);
    assert.strictEqual(WebContentsMock.fromId(wc2.id), wc2);
    assert.strictEqual(WebContentsMock.fromId(99999), null);

    assert.strictEqual(WebContentsMock.fromDevToolsTargetId('target-alpha'), wc1);
    assert.strictEqual(WebContentsMock.fromDevToolsTargetId('target-beta'), wc2);
    assert.strictEqual(WebContentsMock.fromDevToolsTargetId('target-nonexistent'), undefined);

    assert.strictEqual(WebContentsMock.getFocusedWebContents(), null);
    wc1.focus();
    assert.strictEqual(WebContentsMock.getFocusedWebContents(), wc1);
    wc2.focus();
    assert.strictEqual(WebContentsMock.getFocusedWebContents(), wc2);
    assert.strictEqual(wc1.isFocused(), false);
    assert.strictEqual(wc2.isFocused(), true);

    wc1.destroy();
    assert.strictEqual(WebContentsMock.getAllWebContents().length, 1);
    assert.strictEqual(WebContentsMock.fromId(wc1.id), null);
    assert.strictEqual(WebContentsMock.fromDevToolsTargetId('target-alpha'), undefined);

    wc2.destroy();
    assert.strictEqual(WebContentsMock.getAllWebContents().length, 0);
  }

  // 3. WebContents manages URL and file navigation, history state traversal, and loading lifecycle event emissions
  {
    WebContentsMock._resetRegistry();
    const wc = new WebContentsMock();

    let startLoadingCount = 0;
    let finishLoadCount = 0;
    let stopLoadingCount = 0;
    let navigateUrl = '';

    wc.on('did-start-loading', () => { startLoadingCount++; });
    wc.on('did-finish-load', () => { finishLoadCount++; });
    wc.on('did-stop-loading', () => { stopLoadingCount++; });
    wc.on('did-navigate', (event, url) => { navigateUrl = url; });

    await wc.loadURL('https://example.com/page1');
    assert.strictEqual(wc.getURL(), 'https://example.com/page1');
    assert.strictEqual(navigateUrl, 'https://example.com/page1');
    assert.strictEqual(startLoadingCount, 1);
    assert.strictEqual(finishLoadCount, 1);
    assert.strictEqual(stopLoadingCount, 1);
    assert.strictEqual(wc.isLoading(), false);

    await wc.loadURL('https://example.com/page2');
    assert.strictEqual(wc.getURL(), 'https://example.com/page2');
    assert.strictEqual(wc.canGoBack(), true);
    assert.strictEqual(wc.canGoForward(), false);

    await wc.loadFile('test/fixture.html');
    assert.ok(wc.getURL().startsWith('file://'));
    assert.ok(wc.getURL().endsWith('test/fixture.html'));

    wc.goBack();
    assert.strictEqual(wc.getURL(), 'https://example.com/page2');
    assert.strictEqual(wc.canGoForward(), true);

    wc.goForward();
    assert.ok(wc.getURL().endsWith('test/fixture.html'));

    wc.clearHistory();
    assert.strictEqual(wc.canGoBack(), false);
    assert.strictEqual(wc.canGoForward(), false);

    // Title update
    let titleEmitted = '';
    wc.on('page-title-updated', (event, title) => { titleEmitted = title; });
    wc.setTitle('Custom Title');
    assert.strictEqual(wc.getTitle(), 'Custom Title');
    assert.strictEqual(titleEmitted, 'Custom Title');

    wc.destroy();
  }

  // 4. WebContents controls page audio muting, zoom factor and level configuration, and visual presentation state
  {
    WebContentsMock._resetRegistry();
    const wc = new WebContentsMock();

    // Audio muting and audibility
    assert.strictEqual(wc.isAudioMuted(), false);
    assert.strictEqual(wc.isCurrentlyAudible(), false);

    let audioChanged = false;
    wc.on('audio-state-changed', () => { audioChanged = true; });

    wc.setAudible(true);
    assert.strictEqual(wc.isCurrentlyAudible(), true);
    assert.strictEqual(audioChanged, true);

    audioChanged = false;
    wc.setAudioMuted(true);
    assert.strictEqual(wc.isAudioMuted(), true);
    assert.strictEqual(wc.isCurrentlyAudible(), false);
    assert.strictEqual(audioChanged, true);

    wc.setAudioMuted(false);
    assert.strictEqual(wc.isCurrentlyAudible(), true);

    // Zoom factor & level
    assert.strictEqual(wc.getZoomFactor(), 1.0);
    assert.strictEqual(wc.getZoomLevel(), 0.0);

    let zoomEvent = '';
    wc.on('zoom-changed', (direction) => { zoomEvent = direction; });

    wc.setZoomFactor(1.5);
    assert.strictEqual(wc.getZoomFactor(), 1.5);
    assert.strictEqual(zoomEvent, 'in');

    wc.setZoomLevel(2.0);
    assert.strictEqual(wc.getZoomLevel(), 2.0);

    wc.setVisualZoomLevelLimits(0.5, 3.0);

    assert.throws(() => wc.setZoomFactor(-1), RangeError);
    assert.throws(() => wc.setZoomFactor(0), RangeError);
    assert.throws(() => wc.setZoomLevel('not-a-number'), TypeError);

    wc.destroy();
  }

  // 5. WebContents handles IPC messaging, JavaScript execution, CSS injection, and window open request interception
  {
    WebContentsMock._resetRegistry();
    const wc = new WebContentsMock();

    // IPC messaging
    let ipcChannel = '';
    let ipcPayload = null;
    wc.on('ipc-message', (channel, ...args) => {
      ipcChannel = channel;
      ipcPayload = args;
    });

    wc.send('render-event', { key: 'value' }, 42);
    assert.strictEqual(ipcChannel, 'render-event');
    assert.deepStrictEqual(ipcPayload, [{ key: 'value' }, 42]);

    let postChannel = '';
    let postData = null;
    wc.on('message', (event) => {
      postChannel = event.channel;
      postData = event.data;
    });
    wc.postMessage('port-transfer', { token: 'xyz' });
    assert.strictEqual(postChannel, 'port-transfer');
    assert.deepStrictEqual(postData, { token: 'xyz' });

    // JavaScript execution
    const evalResult = await wc.executeJavaScript('21 * 2');
    assert.strictEqual(evalResult, 42);

    // CSS injection and removal
    const cssKey = await wc.insertCSS('body { background: #123; }');
    assert.ok(typeof cssKey === 'string' && cssKey.startsWith('css-key-'));
    const removed = await wc.removeInsertedCSS(cssKey);
    assert.strictEqual(removed, true);
    const removeAgain = await wc.removeInsertedCSS(cssKey);
    assert.strictEqual(removeAgain, false);

    // Window open handler
    wc.setWindowOpenHandler((details) => {
      if (details.url.includes('blocked')) {
        return { action: 'deny' };
      }
      return { action: 'allow', overrideBrowserWindowOptions: { width: 500 } };
    });

    const allowed = wc.requestWindowOpen({ url: 'https://example.com/allowed' });
    assert.strictEqual(allowed.action, 'allow');
    assert.strictEqual(allowed.overrideBrowserWindowOptions.width, 500);

    const denied = wc.requestWindowOpen({ url: 'https://example.com/blocked' });
    assert.strictEqual(denied.action, 'deny');

    wc.destroy();
  }

  // 6. WebContents manages DevTools lifecycle, user agent customization, and clean destruction teardown
  {
    WebContentsMock._resetRegistry();
    const wc = new WebContentsMock();

    // User Agent
    assert.ok(wc.getUserAgent().includes('Mozilla'));
    wc.setUserAgent('CustomAgent/2.0');
    assert.strictEqual(wc.getUserAgent(), 'CustomAgent/2.0');
    assert.throws(() => wc.setUserAgent(12345), TypeError);

    // DevTools lifecycle
    assert.strictEqual(wc.isDevToolsOpened(), false);
    assert.strictEqual(wc.devToolsWebContents, null);

    let devToolsOpenedEmitted = false;
    let devToolsClosedEmitted = false;
    wc.on('devtools-opened', () => { devToolsOpenedEmitted = true; });
    wc.on('devtools-closed', () => { devToolsClosedEmitted = true; });

    wc.openDevTools();
    assert.strictEqual(wc.isDevToolsOpened(), true);
    assert.ok(wc.devToolsWebContents !== null);
    assert.strictEqual(devToolsOpenedEmitted, true);

    wc.closeDevTools();
    assert.strictEqual(wc.isDevToolsOpened(), false);
    assert.strictEqual(wc.devToolsWebContents, null);
    assert.strictEqual(devToolsClosedEmitted, true);

    // Destruction teardown
    let destroyedEmitted = false;
    wc.on('destroyed', () => { destroyedEmitted = true; });

    assert.strictEqual(wc.isDestroyed(), false);
    wc.destroy();
    assert.strictEqual(wc.isDestroyed(), true);
    assert.strictEqual(destroyedEmitted, true);

    // Post-destruction error contracts
    await assert.rejects(async () => wc.loadURL('https://example.com'), /WebContents is destroyed/);
    await assert.rejects(async () => wc.executeJavaScript('1+1'), /WebContents is destroyed/);
    assert.throws(() => wc.send('test'), /WebContents is destroyed/);
  }

  console.log('All 6 electron.WebContents contracts passed successfully.');
}

runContract().catch((err) => {
  console.error('Contract test failed:', err);
  process.exit(1);
});
test/fixture.html
<!DOCTYPE html>
<html>
<head><title>Fixture</title></head>
<body><h1>Fixture Page</h1></body>
</html>

Ursprungs-Seeder

anonym