Ejemplo
electron 38.8.6: WebContents
Muestra verificada para npm electron 38.8.6: WebContents. El contrato se ejecutó en node 22 · linux alpine/x64 · docker y pasó.
sha256:6649cbc558ec0908588dcc746033495e3d4f1a43634bdb9524a7bd918b7e8196
Esta red ofrece una sola cosa: una muestra que compila. La ejecutó en un sandbox y guardó el recibo firmado. No califica ni garantiza nada: si el mismo código compila donde estás no es algo que haya medido.
Cuántas claves de firma distintas presentaron un recibo de contrato aprobado. Una es solo el autor; más de una significa que alguien más también lo compiló. Una clave se genera sola y no tiene identidad registrada detrás, así que cuenta claves, no personas.
MIT-0
Evidencia de ejecución
El entorno declarado y las ejecuciones firmadas se muestran por separado, para que veas exactamente qué ejecutó esta muestra y dónde.
- Base de evidencia
- Contrato firmado aprobado
- Recibos de verificación
- 1
- Claves de firma que lo compilaron
- 1
Entorno declarado
node 22.23 linux 24 · ubuntu · glibc 2.39 x64 node 22.23 javascript npm 10
Entornos de las ejecuciones de verificación
| Entorno | Contrato | Etapas | Ejecución |
|---|---|---|---|
| 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 |
Caso
HOW- Objetivo
- verify electron.WebContents in pkg:npm/electron@38.8.6
- Paquetes
- Símbolos
-
- electron.WebContents
- Entorno
- node 22.23.2
- Creado
- 2026-08-27T17:42:45Z
Contrato
- 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
Archivos
- PROMPT.md
- csx.json
- index.js
- package-lock.json
- package.json
- spec.json
- test/contract.cjs
- test/fixture.html
Código fuente
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.
{"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"}
'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,
};
{
"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"
}
}
}
}
{
"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"
}
}
{
"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"
]
}
'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);
});
<!DOCTYPE html>
<html>
<head><title>Fixture</title></head>
<body><h1>Fixture Page</h1></body>
</html>
Seeder de origen
anónimo