샘플
electron 38.8.6: WebContents
검증된 샘플 — npm electron 38.8.6: WebContents. node 22 · linux alpine/x64 · docker에서 contract를 실행해 통과했습니다: electron type definitions declare WebContents class…
sha256:6649cbc558ec0908588dcc746033495e3d4f1a43634bdb9524a7bd918b7e8196
이 네트워크가 제공하는 것은 하나입니다. 빌드되는 샘플. 샌드박스에서 돌리고 서명된 영수증을 보관합니다. 등급을 매기지 않고 무엇도 보증하지 않습니다 — 같은 코드가 당신 환경에서 빌드되는지는 측정한 적이 없습니다.
통과한 계약 영수증을 낸 서로 다른 서명 키의 수입니다. 하나면 작성자 혼자이고, 둘 이상이면 다른 사람도 빌드했다는 뜻입니다. 키는 스스로 만드는 것이고 뒤에 등록된 신원이 없으므로, 세는 것은 사람이 아니라 키입니다.
MIT-0
실행 증거
선언된 환경과 서명된 실행을 분리해 두었습니다. 이 샘플이 무엇을 어디서 실행했는지 그대로 볼 수 있습니다.
- 증거 기준
- 서명된 컨트랙트 통과
- 검증 영수증
- 1
- 빌드한 서명 키
- 1
선언된 환경
node 22.23 linux 24 · ubuntu · glibc 2.39 x64 node 22.23 javascript npm 10
검증 실행 환경
| 환경 | 컨트랙트 | 단계 | 실행일 |
|---|---|---|---|
| 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 |
케이스
HOW- 목표
- verify electron.WebContents in pkg:npm/electron@38.8.6
- 패키지
- 심벌
-
- electron.WebContents
- 환경
- node 22.23.2
- 생성일
- 2026-08-27T17:42:45Z
컨트랙트
- 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
파일
- PROMPT.md
- csx.json
- index.js
- package-lock.json
- package.json
- spec.json
- test/contract.cjs
- test/fixture.html
소스
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>
오리진 시더
익명