샘플
electron 38.8.6: protocol
검증된 샘플 — npm electron 38.8.6: protocol. node 22 · linux alpine/x64 · docker에서 contract를 실행해 통과했습니다: electron type definitions declare Protocol interface…
sha256:58bdd1d293429f975bfdacd7c6e56aac56af4c455fb9b362a171347e33a59019
이 네트워크가 제공하는 것은 하나입니다. 빌드되는 샘플. 샌드박스에서 돌리고 서명된 영수증을 보관합니다. 등급을 매기지 않고 무엇도 보증하지 않습니다 — 같은 코드가 당신 환경에서 빌드되는지는 측정한 적이 없습니다.
통과한 계약 영수증을 낸 서로 다른 서명 키의 수입니다. 하나면 작성자 혼자이고, 둘 이상이면 다른 사람도 빌드했다는 뜻입니다. 키는 스스로 만드는 것이고 뒤에 등록된 신원이 없으므로, 세는 것은 사람이 아니라 키입니다.
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.protocol in pkg:npm/electron@38.8.6
- 패키지
- 심벌
-
- electron.protocol
- 환경
- node 22.23.2
- 생성일
- 2026-08-27T17:52:36Z
컨트랙트
- electron type definitions declare Protocol interface, CustomScheme, Privileges, ProtocolRequest, and ProtocolResponse interfaces across Main and CrossProcessExports namespaces
- protocol.handle and protocol.unhandle register and remove fetch-based request handlers with status query via isProtocolHandled
- protocol.registerSchemesAsPrivileged validates and registers custom schemes with standard, secure, CSP bypass, and fetch API privileges
- protocol legacy handlers registerBufferProtocol, registerStringProtocol, and registerFileProtocol respond to incoming requests with callbacks
- protocol request interceptors interceptBufferProtocol, interceptStringProtocol, and uninterceptProtocol override and restore protocol handling
- protocol normalizes request URLs, validates request metadata, and supports stream response handlers
파일
- PROMPT.md
- csx.json
- index.js
- package-lock.json
- package.json
- spec.json
- test/contract.cjs
소스
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.protocol 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.protocol
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:4282e167cc268b41d4359055f3a1bea150fa77d0c94396e08b53b2fa7649673a","contract":["electron type definitions declare Protocol interface, CustomScheme, Privileges, ProtocolRequest, and ProtocolResponse interfaces across Main and CrossProcessExports namespaces","protocol.handle and protocol.unhandle register and remove fetch-based request handlers with status query via isProtocolHandled","protocol.registerSchemesAsPrivileged validates and registers custom schemes with standard, secure, CSP bypass, and fetch API privileges","protocol legacy handlers registerBufferProtocol, registerStringProtocol, and registerFileProtocol respond to incoming requests with callbacks","protocol request interceptors interceptBufferProtocol, interceptStringProtocol, and uninterceptProtocol override and restore protocol handling","protocol normalizes request URLs, validates request metadata, and supports stream response handlers"],"goal":"verify electron.protocol in pkg:npm/electron@38.8.6","kind":"HOW","packages":["pkg:npm/electron@38.8.6"],"schemaVersion":1,"symbols":["electron.protocol"]},"contractCommand":["node","test/contract.cjs"],"environment":{"arch":"x64","distro":"ubuntu","ecosystem":"npm","executionContext":"node","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.protocol"],"verifierAdapter":"node-typescript@1"}
'use strict';
const fs = require('node:fs');
const path = require('node:path');
const { Readable } = require('node:stream');
/**
* Validates whether a scheme name follows standard RFC/URI scheme rules.
* @param {string} scheme
* @returns {boolean}
*/
function isValidSchemeName(scheme) {
if (typeof scheme !== 'string' || scheme.length === 0) {
return false;
}
return /^[a-zA-Z][a-zA-Z0-9+.-]*$/.test(scheme);
}
/**
* Valid privilege property keys allowed on CustomScheme.privileges.
*/
const ALLOWED_PRIVILEGE_KEYS = new Set([
'standard',
'secure',
'bypassCSP',
'allowServiceWorkers',
'supportFetchAPI',
'corsEnabled',
'stream',
'codeCache',
]);
/**
* Validates privileges object for custom schemes.
* @param {object} privileges
* @returns {boolean}
*/
function validatePrivileges(privileges) {
if (privileges === null || typeof privileges !== 'object' || Array.isArray(privileges)) {
return false;
}
for (const [key, val] of Object.entries(privileges)) {
if (!ALLOWED_PRIVILEGE_KEYS.has(key)) {
return false;
}
if (typeof val !== 'boolean') {
return false;
}
}
return true;
}
/**
* Reads and verifies electron.protocol TypeScript definitions from the electron package.
* @returns {{
* hasProtocolInterface: boolean,
* hasCustomSchemeInterface: boolean,
* hasPrivilegesInterface: boolean,
* hasProtocolRequestInterface: boolean,
* hasProtocolResponseInterface: boolean,
* protocolMethods: string[],
* customSchemeFields: string[],
* privilegeFields: string[],
* isMainExported: boolean,
* isCrossProcessExported: boolean,
* isTopLevelExported: boolean,
* isSessionDeclared: boolean,
* allDeclared: boolean
* }}
*/
function getProtocolDeclarations() {
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 expectedMethods = [
'handle',
'unhandle',
'isProtocolHandled',
'registerSchemesAsPrivileged',
'registerBufferProtocol',
'registerFileProtocol',
'registerHttpProtocol',
'registerStreamProtocol',
'registerStringProtocol',
'unregisterProtocol',
'isProtocolRegistered',
'interceptBufferProtocol',
'interceptFileProtocol',
'interceptHttpProtocol',
'interceptStreamProtocol',
'interceptStringProtocol',
'uninterceptProtocol',
'isProtocolIntercepted',
];
const protocolMethods = [];
const protoMatch = dtsContent.match(/interface\s+Protocol\s*\{([\s\S]*?)\n\s*\}/);
if (protoMatch) {
const body = protoMatch[1];
for (const m of expectedMethods) {
if (body.includes(`${m}(`)) {
protocolMethods.push(m);
}
}
}
const customSchemeFields = [];
const csMatch = dtsContent.match(/interface\s+CustomScheme\s*\{([\s\S]*?)\n\s*\}/);
if (csMatch) {
const csBody = csMatch[1];
if (/\bscheme:\s*string/m.test(csBody)) {
customSchemeFields.push('scheme');
}
if (/\bprivileges\?:/m.test(csBody)) {
customSchemeFields.push('privileges');
}
}
const expectedPrivileges = [
'standard',
'secure',
'bypassCSP',
'allowServiceWorkers',
'supportFetchAPI',
'corsEnabled',
'stream',
'codeCache',
];
const privilegeFields = [];
const privMatch = dtsContent.match(/interface\s+Privileges\s*\{([\s\S]*?)\n\s*\}/);
if (privMatch) {
const privBody = privMatch[1];
for (const p of expectedPrivileges) {
if (new RegExp(`\\b${p}\\?:`).test(privBody)) {
privilegeFields.push(p);
}
}
}
const hasProtocolRequestInterface = /interface\s+ProtocolRequest\s*\{/.test(dtsContent);
const hasProtocolResponseInterface = /interface\s+ProtocolResponse\s*\{/.test(dtsContent);
const isMainExported = /namespace\s+Main\s*\{[\s\S]*?const\s+protocol:\s*Protocol;/m.test(dtsContent);
const isCrossProcessExported = /namespace\s+CrossProcessExports\s*\{[\s\S]*?const\s+protocol:\s*Protocol;/m.test(dtsContent);
const isTopLevelExported = /const\s+protocol:\s*Protocol;/m.test(dtsContent);
const isSessionDeclared = /readonly\s+protocol:\s*Protocol;/m.test(dtsContent);
const hasProtocolInterface = protocolMethods.length === expectedMethods.length;
const hasCustomSchemeInterface = customSchemeFields.length === 2;
const hasPrivilegesInterface = privilegeFields.length === expectedPrivileges.length;
const allDeclared =
hasProtocolInterface &&
hasCustomSchemeInterface &&
hasPrivilegesInterface &&
hasProtocolRequestInterface &&
hasProtocolResponseInterface &&
isMainExported &&
isCrossProcessExported &&
isTopLevelExported &&
isSessionDeclared;
return {
hasProtocolInterface,
hasCustomSchemeInterface,
hasPrivilegesInterface,
hasProtocolRequestInterface,
hasProtocolResponseInterface,
protocolMethods,
customSchemeFields,
privilegeFields,
isMainExported,
isCrossProcessExported,
isTopLevelExported,
isSessionDeclared,
allDeclared,
};
}
/**
* Creates an in-memory Protocol manager implementing electron.protocol contract.
* @returns {object}
*/
function createProtocolManager() {
const handledSchemes = new Map();
const privilegedSchemes = new Map();
const legacyProtocols = new Map();
const interceptedProtocols = new Map();
let schemesPrivilegedLocked = false;
return {
/**
* Registers a modern fetch-based protocol handler.
* @param {string} scheme
* @param {(request: Request) => Response | Promise<Response>} handler
*/
handle(scheme, handler) {
if (!isValidSchemeName(scheme)) {
throw new TypeError(`Invalid scheme name: '${scheme}'`);
}
if (typeof handler !== 'function') {
throw new TypeError('Handler must be a function');
}
const lower = scheme.toLowerCase();
if (handledSchemes.has(lower)) {
throw new Error(`Scheme '${scheme}' already registered`);
}
handledSchemes.set(lower, handler);
},
/**
* Unregisters a protocol handler registered with handle.
* @param {string} scheme
*/
unhandle(scheme) {
if (!isValidSchemeName(scheme)) {
throw new TypeError(`Invalid scheme name: '${scheme}'`);
}
const lower = scheme.toLowerCase();
if (!handledSchemes.has(lower)) {
throw new Error(`Scheme '${scheme}' is not currently handled`);
}
handledSchemes.delete(lower);
},
/**
* Checks whether a scheme has an active modern handler.
* @param {string} scheme
* @returns {boolean}
*/
isProtocolHandled(scheme) {
if (!isValidSchemeName(scheme)) {
return false;
}
return handledSchemes.has(scheme.toLowerCase());
},
/**
* Registers custom schemes as privileged before app ready.
* @param {Array<{ scheme: string, privileges?: object }>} customSchemes
*/
registerSchemesAsPrivileged(customSchemes) {
if (schemesPrivilegedLocked) {
throw new Error('registerSchemesAsPrivileged can only be called before app is ready and only once');
}
if (!Array.isArray(customSchemes)) {
throw new TypeError('customSchemes must be an array');
}
for (const item of customSchemes) {
if (!item || typeof item !== 'object') {
throw new TypeError('Each custom scheme configuration must be an object');
}
if (!isValidSchemeName(item.scheme)) {
throw new TypeError(`Invalid scheme name: '${item.scheme}'`);
}
if (item.privileges !== undefined && !validatePrivileges(item.privileges)) {
throw new TypeError(`Invalid privileges provided for scheme '${item.scheme}'`);
}
const lower = item.scheme.toLowerCase();
const defaultPrivileges = {
standard: false,
secure: false,
bypassCSP: false,
allowServiceWorkers: false,
supportFetchAPI: false,
corsEnabled: false,
stream: false,
codeCache: false,
};
privilegedSchemes.set(lower, Object.assign(defaultPrivileges, item.privileges || {}));
}
schemesPrivilegedLocked = true;
},
/**
* Retrieves privileges for a registered scheme.
* @param {string} scheme
* @returns {object | null}
*/
getSchemePrivileges(scheme) {
if (!isValidSchemeName(scheme)) {
return null;
}
const priv = privilegedSchemes.get(scheme.toLowerCase());
return priv ? Object.assign({}, priv) : null;
},
/**
* Registers a Buffer-based protocol handler (legacy).
* @param {string} scheme
* @param {Function} handler
* @returns {boolean}
*/
registerBufferProtocol(scheme, handler) {
if (!isValidSchemeName(scheme) || typeof handler !== 'function') {
return false;
}
const lower = scheme.toLowerCase();
if (legacyProtocols.has(lower)) {
return false;
}
legacyProtocols.set(lower, { type: 'buffer', handler });
return true;
},
/**
* Registers a String-based protocol handler (legacy).
* @param {string} scheme
* @param {Function} handler
* @returns {boolean}
*/
registerStringProtocol(scheme, handler) {
if (!isValidSchemeName(scheme) || typeof handler !== 'function') {
return false;
}
const lower = scheme.toLowerCase();
if (legacyProtocols.has(lower)) {
return false;
}
legacyProtocols.set(lower, { type: 'string', handler });
return true;
},
/**
* Registers a File-based protocol handler (legacy).
* @param {string} scheme
* @param {Function} handler
* @returns {boolean}
*/
registerFileProtocol(scheme, handler) {
if (!isValidSchemeName(scheme) || typeof handler !== 'function') {
return false;
}
const lower = scheme.toLowerCase();
if (legacyProtocols.has(lower)) {
return false;
}
legacyProtocols.set(lower, { type: 'file', handler });
return true;
},
/**
* Registers a Stream-based protocol handler (legacy).
* @param {string} scheme
* @param {Function} handler
* @returns {boolean}
*/
registerStreamProtocol(scheme, handler) {
if (!isValidSchemeName(scheme) || typeof handler !== 'function') {
return false;
}
const lower = scheme.toLowerCase();
if (legacyProtocols.has(lower)) {
return false;
}
legacyProtocols.set(lower, { type: 'stream', handler });
return true;
},
/**
* Unregisters a legacy protocol handler.
* @param {string} scheme
* @returns {boolean}
*/
unregisterProtocol(scheme) {
if (!isValidSchemeName(scheme)) {
return false;
}
const lower = scheme.toLowerCase();
return legacyProtocols.delete(lower);
},
/**
* Checks whether a legacy protocol is registered.
* @param {string} scheme
* @returns {boolean}
*/
isProtocolRegistered(scheme) {
if (!isValidSchemeName(scheme)) {
return false;
}
return legacyProtocols.has(scheme.toLowerCase());
},
/**
* Intercepts a String protocol.
* @param {string} scheme
* @param {Function} handler
* @returns {boolean}
*/
interceptStringProtocol(scheme, handler) {
if (!isValidSchemeName(scheme) || typeof handler !== 'function') {
return false;
}
const lower = scheme.toLowerCase();
if (interceptedProtocols.has(lower)) {
return false;
}
interceptedProtocols.set(lower, { type: 'string', handler });
return true;
},
/**
* Intercepts a Buffer protocol.
* @param {string} scheme
* @param {Function} handler
* @returns {boolean}
*/
interceptBufferProtocol(scheme, handler) {
if (!isValidSchemeName(scheme) || typeof handler !== 'function') {
return false;
}
const lower = scheme.toLowerCase();
if (interceptedProtocols.has(lower)) {
return false;
}
interceptedProtocols.set(lower, { type: 'buffer', handler });
return true;
},
/**
* Intercepts a Stream protocol.
* @param {string} scheme
* @param {Function} handler
* @returns {boolean}
*/
interceptStreamProtocol(scheme, handler) {
if (!isValidSchemeName(scheme) || typeof handler !== 'function') {
return false;
}
const lower = scheme.toLowerCase();
if (interceptedProtocols.has(lower)) {
return false;
}
interceptedProtocols.set(lower, { type: 'stream', handler });
return true;
},
/**
* Removes protocol interception.
* @param {string} scheme
* @returns {boolean}
*/
uninterceptProtocol(scheme) {
if (!isValidSchemeName(scheme)) {
return false;
}
const lower = scheme.toLowerCase();
return interceptedProtocols.delete(lower);
},
/**
* Checks whether protocol is intercepted.
* @param {string} scheme
* @returns {boolean}
*/
isProtocolIntercepted(scheme) {
if (!isValidSchemeName(scheme)) {
return false;
}
return interceptedProtocols.has(scheme.toLowerCase());
},
/**
* Dispatches a request to active handler (interceptors first, then handle or legacy).
* @param {string | Request} requestInput
* @returns {Promise<any>}
*/
async dispatch(requestInput) {
const url = typeof requestInput === 'string' ? requestInput : requestInput.url;
const parsedUrl = new URL(url);
const scheme = parsedUrl.protocol.replace(/:$/, '').toLowerCase();
// Check interceptor first
if (interceptedProtocols.has(scheme)) {
const interceptor = interceptedProtocols.get(scheme);
return new Promise((resolve, reject) => {
try {
const req = {
url,
method: typeof requestInput === 'object' && requestInput.method ? requestInput.method : 'GET',
referrer: '',
headers: {},
};
interceptor.handler(req, (response) => {
resolve({ intercepted: true, type: interceptor.type, response });
});
} catch (err) {
reject(err);
}
});
}
// Check modern handle
if (handledSchemes.has(scheme)) {
const handler = handledSchemes.get(scheme);
const req = typeof requestInput === 'string' ? new Request(requestInput) : requestInput;
const res = await handler(req);
return res;
}
// Check legacy protocol
if (legacyProtocols.has(scheme)) {
const legacy = legacyProtocols.get(scheme);
return new Promise((resolve, reject) => {
try {
const req = {
url,
method: typeof requestInput === 'object' && requestInput.method ? requestInput.method : 'GET',
referrer: '',
headers: {},
};
legacy.handler(req, (response) => {
resolve({ legacy: true, type: legacy.type, response });
});
} catch (err) {
reject(err);
}
});
}
throw new Error(`No handler registered for scheme: ${scheme}`);
},
};
}
module.exports = {
isValidSchemeName,
validatePrivileges,
getProtocolDeclarations,
createProtocolManager,
};
{
"name": "sample-electron-protocol",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "sample-electron-protocol",
"version": "1.0.0",
"license": "MIT-0",
"dependencies": {
"electron": "38.8.6"
},
"description": "verify electron.protocol in pkg:npm/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-protocol",
"version": "1.0.0",
"description": "verify electron.protocol in pkg:npm/electron@38.8.6",
"main": "index.js",
"license": "MIT-0",
"dependencies": {
"electron": "38.8.6"
}
}
{
"schemaVersion": 1,
"goal": "verify electron.protocol in pkg:npm/electron@38.8.6",
"kind": "HOW",
"packages": [
"pkg:npm/electron@38.8.6"
],
"symbols": [
"electron.protocol"
]
}
'use strict';
const assert = require('node:assert');
const { Readable } = require('node:stream');
const {
isValidSchemeName,
validatePrivileges,
getProtocolDeclarations,
createProtocolManager,
} = require('../index.js');
async function runContracts() {
// Contract 1: electron type definitions declare Protocol interface, CustomScheme, Privileges, ProtocolRequest, and ProtocolResponse interfaces across Main and CrossProcessExports namespaces
{
const decl = getProtocolDeclarations();
assert.strictEqual(decl.allDeclared, true, 'All protocol declarations must be present');
assert.strictEqual(decl.hasProtocolInterface, true, 'Protocol interface must be declared');
assert.strictEqual(decl.hasCustomSchemeInterface, true, 'CustomScheme interface must be declared');
assert.strictEqual(decl.hasPrivilegesInterface, true, 'Privileges interface must be declared');
assert.strictEqual(decl.hasProtocolRequestInterface, true, 'ProtocolRequest interface must be declared');
assert.strictEqual(decl.hasProtocolResponseInterface, true, 'ProtocolResponse interface must be declared');
assert.strictEqual(decl.isMainExported, true, 'protocol must be exported in Main namespace');
assert.strictEqual(decl.isCrossProcessExported, true, 'protocol must be exported in CrossProcessExports namespace');
assert.strictEqual(decl.isTopLevelExported, true, 'protocol must be exported at top-level');
assert.strictEqual(decl.isSessionDeclared, true, 'protocol must be declared on Session interface');
assert.ok(decl.protocolMethods.includes('handle'), 'Protocol must have handle method');
assert.ok(decl.protocolMethods.includes('unhandle'), 'Protocol must have unhandle method');
assert.ok(decl.protocolMethods.includes('isProtocolHandled'), 'Protocol must have isProtocolHandled method');
assert.ok(decl.protocolMethods.includes('registerSchemesAsPrivileged'), 'Protocol must have registerSchemesAsPrivileged method');
assert.ok(decl.protocolMethods.includes('registerBufferProtocol'), 'Protocol must have registerBufferProtocol method');
assert.ok(decl.protocolMethods.includes('registerFileProtocol'), 'Protocol must have registerFileProtocol method');
assert.ok(decl.protocolMethods.includes('registerHttpProtocol'), 'Protocol must have registerHttpProtocol method');
assert.ok(decl.protocolMethods.includes('registerStreamProtocol'), 'Protocol must have registerStreamProtocol method');
assert.ok(decl.protocolMethods.includes('registerStringProtocol'), 'Protocol must have registerStringProtocol method');
assert.ok(decl.protocolMethods.includes('unregisterProtocol'), 'Protocol must have unregisterProtocol method');
assert.ok(decl.protocolMethods.includes('isProtocolRegistered'), 'Protocol must have isProtocolRegistered method');
assert.ok(decl.protocolMethods.includes('interceptBufferProtocol'), 'Protocol must have interceptBufferProtocol method');
assert.ok(decl.protocolMethods.includes('interceptFileProtocol'), 'Protocol must have interceptFileProtocol method');
assert.ok(decl.protocolMethods.includes('interceptHttpProtocol'), 'Protocol must have interceptHttpProtocol method');
assert.ok(decl.protocolMethods.includes('interceptStreamProtocol'), 'Protocol must have interceptStreamProtocol method');
assert.ok(decl.protocolMethods.includes('interceptStringProtocol'), 'Protocol must have interceptStringProtocol method');
assert.ok(decl.protocolMethods.includes('uninterceptProtocol'), 'Protocol must have uninterceptProtocol method');
assert.ok(decl.protocolMethods.includes('isProtocolIntercepted'), 'Protocol must have isProtocolIntercepted method');
assert.deepStrictEqual(decl.customSchemeFields, ['scheme', 'privileges']);
assert.ok(decl.privilegeFields.includes('standard'));
assert.ok(decl.privilegeFields.includes('secure'));
assert.ok(decl.privilegeFields.includes('bypassCSP'));
assert.ok(decl.privilegeFields.includes('allowServiceWorkers'));
assert.ok(decl.privilegeFields.includes('supportFetchAPI'));
assert.ok(decl.privilegeFields.includes('corsEnabled'));
assert.ok(decl.privilegeFields.includes('stream'));
assert.ok(decl.privilegeFields.includes('codeCache'));
}
// Contract 2: protocol.handle and protocol.unhandle register and remove fetch-based request handlers with status query via isProtocolHandled
{
const protocol = createProtocolManager();
assert.strictEqual(protocol.isProtocolHandled('app-assets'), false, 'Scheme should initially be unhandled');
protocol.handle('app-assets', async (req) => {
const url = new URL(req.url);
return new Response(`Loaded: ${url.pathname}`, {
status: 200,
headers: { 'content-type': 'text/plain' },
});
});
assert.strictEqual(protocol.isProtocolHandled('app-assets'), true, 'Scheme should be marked as handled');
assert.strictEqual(protocol.isProtocolHandled('APP-ASSETS'), true, 'Scheme check should be case-insensitive');
// Dispatching request
const response = await protocol.dispatch('app-assets://localhost/index.html');
assert.strictEqual(response.status, 200);
assert.strictEqual(response.headers.get('content-type'), 'text/plain');
const text = await response.text();
assert.strictEqual(text, 'Loaded: /index.html');
// Duplicate registration throws
assert.throws(() => {
protocol.handle('app-assets', () => new Response('dup'));
}, /already registered/);
// Unhandle scheme
protocol.unhandle('app-assets');
assert.strictEqual(protocol.isProtocolHandled('app-assets'), false);
// Unhandling unregistered scheme throws
assert.throws(() => {
protocol.unhandle('app-assets');
}, /not currently handled/);
// Invalid scheme arguments
assert.throws(() => protocol.handle('', () => {}), TypeError);
assert.throws(() => protocol.handle('123invalid', () => {}), TypeError);
assert.throws(() => protocol.handle('valid-scheme', 'not-a-fn'), TypeError);
}
// Contract 3: protocol.registerSchemesAsPrivileged validates and registers custom schemes with standard, secure, CSP bypass, and fetch API privileges
{
const protocol = createProtocolManager();
protocol.registerSchemesAsPrivileged([
{
scheme: 'secure-app',
privileges: {
standard: true,
secure: true,
supportFetchAPI: true,
corsEnabled: true,
bypassCSP: true,
stream: true,
},
},
{
scheme: 'worker-app',
privileges: {
allowServiceWorkers: true,
codeCache: true,
},
},
]);
const securePriv = protocol.getSchemePrivileges('secure-app');
assert.strictEqual(securePriv.standard, true);
assert.strictEqual(securePriv.secure, true);
assert.strictEqual(securePriv.supportFetchAPI, true);
assert.strictEqual(securePriv.corsEnabled, true);
assert.strictEqual(securePriv.bypassCSP, true);
assert.strictEqual(securePriv.stream, true);
assert.strictEqual(securePriv.allowServiceWorkers, false);
const workerPriv = protocol.getSchemePrivileges('worker-app');
assert.strictEqual(workerPriv.allowServiceWorkers, true);
assert.strictEqual(workerPriv.codeCache, true);
assert.strictEqual(workerPriv.standard, false);
assert.strictEqual(protocol.getSchemePrivileges('unknown-scheme'), null);
// Calling again throws because it may only be called once before ready
assert.throws(() => {
protocol.registerSchemesAsPrivileged([{ scheme: 'another-app' }]);
}, /can only be called before app is ready and only once/);
// Fresh instance validation tests
const freshProtocol = createProtocolManager();
assert.throws(() => freshProtocol.registerSchemesAsPrivileged('invalid-arg'), TypeError);
assert.throws(() => freshProtocol.registerSchemesAsPrivileged([null]), TypeError);
assert.throws(() => freshProtocol.registerSchemesAsPrivileged([{ scheme: 'bad scheme!' }]), TypeError);
assert.throws(() => freshProtocol.registerSchemesAsPrivileged([{ scheme: 'valid', privileges: { nonExistentKey: true } }]), TypeError);
}
// Contract 4: protocol legacy handlers registerBufferProtocol, registerStringProtocol, and registerFileProtocol respond to incoming requests with callbacks
{
const protocol = createProtocolManager();
const sampleBuffer = Buffer.from('hello-buffer-protocol');
const bufRegistered = protocol.registerBufferProtocol('app-buf', (request, callback) => {
assert.strictEqual(request.url, 'app-buf://localhost/data');
callback({
mimeType: 'application/octet-stream',
data: sampleBuffer,
});
});
assert.strictEqual(bufRegistered, true);
assert.strictEqual(protocol.isProtocolRegistered('app-buf'), true);
// Duplicate registration returns false
assert.strictEqual(protocol.registerBufferProtocol('app-buf', () => {}), false);
const bufResult = await protocol.dispatch('app-buf://localhost/data');
assert.strictEqual(bufResult.legacy, true);
assert.strictEqual(bufResult.type, 'buffer');
assert.deepStrictEqual(bufResult.response.data, sampleBuffer);
// String protocol
const strRegistered = protocol.registerStringProtocol('app-str', (request, callback) => {
callback({
mimeType: 'text/html',
data: '<h1>Hello String Protocol</h1>',
});
});
assert.strictEqual(strRegistered, true);
assert.strictEqual(protocol.isProtocolRegistered('app-str'), true);
const strResult = await protocol.dispatch('app-str://localhost/page');
assert.strictEqual(strResult.legacy, true);
assert.strictEqual(strResult.type, 'string');
assert.strictEqual(strResult.response.data, '<h1>Hello String Protocol</h1>');
// File protocol
const fileRegistered = protocol.registerFileProtocol('app-file', (request, callback) => {
callback({ path: '/mock/path/file.txt' });
});
assert.strictEqual(fileRegistered, true);
assert.strictEqual(protocol.isProtocolRegistered('app-file'), true);
const fileResult = await protocol.dispatch('app-file://localhost/file.txt');
assert.strictEqual(fileResult.legacy, true);
assert.strictEqual(fileResult.type, 'file');
assert.strictEqual(fileResult.response.path, '/mock/path/file.txt');
// Unregister protocols
assert.strictEqual(protocol.unregisterProtocol('app-buf'), true);
assert.strictEqual(protocol.isProtocolRegistered('app-buf'), false);
assert.strictEqual(protocol.unregisterProtocol('app-buf'), false);
}
// Contract 5: protocol request interceptors interceptBufferProtocol, interceptStringProtocol, and uninterceptProtocol override and restore protocol handling
{
const protocol = createProtocolManager();
assert.strictEqual(protocol.isProtocolIntercepted('http'), false);
const intercepted = protocol.interceptStringProtocol('http', (request, callback) => {
assert.strictEqual(request.url, 'http://example.com/api/test');
callback({
mimeType: 'application/json',
data: '{"intercepted":true}',
});
});
assert.strictEqual(intercepted, true);
assert.strictEqual(protocol.isProtocolIntercepted('http'), true);
// Duplicate interception returns false
assert.strictEqual(protocol.interceptStringProtocol('http', () => {}), false);
const dispatchResult = await protocol.dispatch('http://example.com/api/test');
assert.strictEqual(dispatchResult.intercepted, true);
assert.strictEqual(dispatchResult.type, 'string');
assert.strictEqual(dispatchResult.response.data, '{"intercepted":true}');
// Unintercept
assert.strictEqual(protocol.uninterceptProtocol('http'), true);
assert.strictEqual(protocol.isProtocolIntercepted('http'), false);
assert.strictEqual(protocol.uninterceptProtocol('http'), false);
// Buffer interceptor
const bufPayload = Buffer.from('intercepted-bytes');
protocol.interceptBufferProtocol('custom-proto', (req, cb) => {
cb({ data: bufPayload });
});
assert.strictEqual(protocol.isProtocolIntercepted('custom-proto'), true);
const bufInterceptResult = await protocol.dispatch('custom-proto://localhost/res');
assert.strictEqual(bufInterceptResult.intercepted, true);
assert.deepStrictEqual(bufInterceptResult.response.data, bufPayload);
protocol.uninterceptProtocol('custom-proto');
assert.strictEqual(protocol.isProtocolIntercepted('custom-proto'), false);
}
// Contract 6: protocol normalizes request URLs, validates request metadata, and supports stream response handlers
{
const protocol = createProtocolManager();
// Stream protocol
const streamRegistered = protocol.registerStreamProtocol('app-stream', (request, callback) => {
const readable = Readable.from([Buffer.from('chunk-1;'), Buffer.from('chunk-2')]);
callback({
statusCode: 200,
headers: { 'content-type': 'application/octet-stream' },
data: readable,
});
});
assert.strictEqual(streamRegistered, true);
assert.strictEqual(protocol.isProtocolRegistered('app-stream'), true);
const streamResult = await protocol.dispatch('app-stream://localhost/feed');
assert.strictEqual(streamResult.legacy, true);
assert.strictEqual(streamResult.type, 'stream');
assert.strictEqual(streamResult.response.statusCode, 200);
const chunks = [];
for await (const chunk of streamResult.response.data) {
chunks.push(chunk);
}
assert.strictEqual(Buffer.concat(chunks).toString('utf-8'), 'chunk-1;chunk-2');
// Scheme name validation tests
assert.strictEqual(isValidSchemeName('https'), true);
assert.strictEqual(isValidSchemeName('my-custom-scheme'), true);
assert.strictEqual(isValidSchemeName('scheme.v1+test'), true);
assert.strictEqual(isValidSchemeName('123scheme'), false);
assert.strictEqual(isValidSchemeName('scheme:'), false);
assert.strictEqual(isValidSchemeName('scheme/path'), false);
assert.strictEqual(isValidSchemeName(''), false);
assert.strictEqual(isValidSchemeName(null), false);
// Privilege validator tests
assert.strictEqual(validatePrivileges({ standard: true, secure: false }), true);
assert.strictEqual(validatePrivileges({ bypassCSP: true, supportFetchAPI: true }), true);
assert.strictEqual(validatePrivileges({ unknownField: true }), false);
assert.strictEqual(validatePrivileges({ standard: 'true' }), false);
assert.strictEqual(validatePrivileges(null), false);
assert.strictEqual(validatePrivileges([]), false);
}
console.log('All 6 electron.protocol contracts passed successfully.');
}
runContracts().catch((err) => {
console.error('Contract test failed:', err);
process.exit(1);
});
오리진 시더
익명