CodeSampleX

サンプル

electron 38.8.6: net

検証済みサンプル — npm electron 38.8.6: net. node 22 · linux alpine/x64 · docker で contract を実行し、成功しました: electron type definitions declare Net interface with fetch…

sha256:24adfc056d4b93a0176839f167e7ed007aac786f808e5193858e90192f0abc1f

このネットワークが提供するのは一つだけです。ビルドされるサンプル。サンドボックスで実行し、署名済みの受領証を保管します。等級はつけず、何も保証しません — 同じコードがあなたの環境でビルドされるかは測定していません。 合格した契約受領証を提出した異なる署名鍵の数です。1 なら作者だけ、2 以上なら他の誰かもビルドしています。鍵は自己生成で背後に登録された身元がないため、数えているのは人ではなく鍵です。 MIT-0

実行証拠

宣言された環境と署名済みの実行を分けてあります。このサンプルが何をどこで実行したかをそのまま確認できます。

証拠の基準
署名済みコントラクト合格
検証レシート
1
ビルドした署名鍵
1
宣言された環境 linux 24 · ubuntu · glibc 2.39 x64 npm

検証実行環境

環境 コントラクト ステージ 実行日
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.net in pkg:npm/electron@38.8.6
パッケージ
シンボル
  • electron.net
作成日
2026-08-27T17:49:12Z

コントラクト

  1. electron type definitions declare Net interface with fetch, isOnline, online, request, and resolveHost methods across Common, Main, and CrossProcessExports namespaces
  2. Net controller validates online status and manages internet connectivity state transitions
  3. Net request creates ClientRequest instances, validates URL and options, and enforces restricted HTTP headers
  4. ClientRequest manages request header manipulation, body writing, and upload progress tracking before and after stream completion
  5. Net fetch executes simulated HTTP/HTTPS requests, validates unsupported protocols like data: and blob:, and supports bypassCustomProtocolHandlers option
  6. Net resolveHost performs hostname resolution into IP addresses and handles DNS resolution errors

ファイル

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

ソースアーティファクトをダウンロード (tar.gz)

ソース

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

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

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

Goal: verify electron.net 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.net

Rules:
  - One focused purpose; the smallest project that proves the goal.
  - Include a contract test (test/contract.*) that runs OFFLINE and exits 0 exactly when the goal behavior works.
  - Pin every dependency with a lockfile so resolution is reproducible.
  - No secrets, credentials, or tokens. No real URLs (only example.com or localhost). No absolute paths.
  - No personal names, emails, company names, or project identifiers of any kind.
  - No binaries and no generated output (node_modules, dist, target, venv, .git, .env).
  - Keep it under 200 files and 256KB packed.
csx.json
{"case":{"caseId":"case:sha256:7693108575578fd71b8cd9c643329fa726fe7d138057239a442de9f55c78ff39","contract":["electron type definitions declare Net interface with fetch, isOnline, online, request, and resolveHost methods across Common, Main, and CrossProcessExports namespaces","Net controller validates online status and manages internet connectivity state transitions","Net request creates ClientRequest instances, validates URL and options, and enforces restricted HTTP headers","ClientRequest manages request header manipulation, body writing, and upload progress tracking before and after stream completion","Net fetch executes simulated HTTP/HTTPS requests, validates unsupported protocols like data: and blob:, and supports bypassCustomProtocolHandlers option","Net resolveHost performs hostname resolution into IP addresses and handles DNS resolution errors"],"goal":"verify electron.net in pkg:npm/electron@38.8.6","kind":"HOW","packages":["pkg:npm/electron@38.8.6"],"schemaVersion":1,"symbols":["electron.net"]},"contractCommand":["node","test/contract.cjs"],"environment":{"arch":"x64","distro":"ubuntu","ecosystem":"npm","libc":"glibc","libcVersion":"2.39","os":"linux","osVersionBucket":"24","packageManager":"npm","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/electron@38.8.6"],"schemaVersion":1,"subject":"pkg:npm/electron@38.8.6","symbols":["electron.net"],"verifierAdapter":"node-typescript@1"}
index.js
'use strict';

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

/**
 * Restricted HTTP header names per Chromium/Electron specification.
 */
const RESTRICTED_HEADERS = new Set([
  'content-length',
  'host',
  'trailer',
  'te',
  'upgrade',
  'cookie2',
  'keep-alive',
  'transfer-encoding',
]);

/**
 * Reads and verifies electron.net TypeScript definitions from the electron package.
 * @returns {{
 *   hasNetInterface: boolean,
 *   hasClientRequestClass: boolean,
 *   isCommonExported: boolean,
 *   isMainExported: boolean,
 *   isCrossProcessExported: boolean,
 *   isTopLevelExported: boolean,
 *   netMethods: string[],
 *   netProperties: string[],
 *   clientRequestMethods: string[],
 *   clientRequestEvents: string[]
 * }}
 */
function getNetDeclarations() {
  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 startNet = dtsContent.indexOf('interface Net {');
  const endNet = dtsContent.indexOf('interface NetLog {', startNet);
  const netBlock = startNet !== -1 && endNet !== -1 ? dtsContent.slice(startNet, endNet) : '';

  const startReq = dtsContent.indexOf('class ClientRequest extends NodeEventEmitter {');
  const endReq = dtsContent.indexOf('interface Clipboard {', startReq);
  const reqBlock = startReq !== -1 && endReq !== -1 ? dtsContent.slice(startReq, endReq) : '';

  const hasNetInterface = startNet !== -1;
  const hasClientRequestClass = startReq !== -1;

  const isCommonExported = /namespace\s+Common\s*\{[\s\S]*?net:\s*Net/m.test(dtsContent);
  const isMainExported = /namespace\s+Main\s*\{[\s\S]*?net:\s*Net/m.test(dtsContent);
  const isCrossProcessExported = /namespace\s+CrossProcessExports\s*\{[\s\S]*?net:\s*Net/m.test(dtsContent);
  const isTopLevelExported = /const\s+net:\s*Net;/m.test(dtsContent);

  const checkNetMethods = ['fetch', 'isOnline', 'request', 'resolveHost'];
  const netMethods = checkNetMethods.filter((method) =>
    new RegExp(`\\b${method}\\s*\\(`, 'm').test(netBlock)
  );

  const checkNetProperties = ['online'];
  const netProperties = checkNetProperties.filter((prop) =>
    new RegExp(`\\b${prop}:\\s*boolean`, 'm').test(netBlock)
  );

  const checkReqMethods = [
    'abort',
    'end',
    'followRedirect',
    'getHeader',
    'getUploadProgress',
    'removeHeader',
    'setHeader',
    'write',
  ];
  const clientRequestMethods = checkReqMethods.filter((method) =>
    new RegExp(`\\b${method}\\s*\\(`, 'm').test(reqBlock)
  );

  const checkReqEvents = ['abort', 'close', 'error', 'finish', 'login', 'redirect', 'response'];
  const clientRequestEvents = checkReqEvents.filter((ev) =>
    reqBlock.includes(`event: '${ev}'`)
  );

  return {
    hasNetInterface,
    hasClientRequestClass,
    isCommonExported,
    isMainExported,
    isCrossProcessExported,
    isTopLevelExported,
    netMethods,
    netProperties,
    clientRequestMethods,
    clientRequestEvents,
  };
}

/**
 * Validates whether an HTTP header name can be set on a ClientRequest.
 * @param {string} name
 * @param {string} [value]
 * @returns {boolean}
 */
function isRestrictedHeader(name, value) {
  if (typeof name !== 'string') return false;
  const lower = name.trim().toLowerCase();
  if (RESTRICTED_HEADERS.has(lower)) return true;
  if (lower === 'connection' && typeof value === 'string' && value.trim().toLowerCase() === 'upgrade') {
    return true;
  }
  return false;
}

/**
 * ClientRequest simulation implementing the Electron ClientRequest API.
 */
class ClientRequestMock extends EventEmitter {
  constructor(options) {
    super();
    let url = '';
    let method = 'GET';

    if (typeof options === 'string') {
      url = options;
    } else if (options && typeof options === 'object') {
      method = (options.method || 'GET').toUpperCase();
      if (options.url) {
        url = options.url;
      } else if (options.hostname || options.host) {
        const proto = options.protocol || 'http:';
        const host = options.hostname || options.host;
        const port = options.port ? `:${options.port}` : '';
        const reqPath = options.path || '/';
        url = `${proto}//${host}${port}${reqPath}`;
      }
    } else {
      throw new TypeError('ClientRequest constructor options must be a string or object');
    }

    this._url = url;
    this._method = method;
    this._headers = {};
    this._written = false;
    this._finished = false;
    this._aborted = false;
    this._closed = false;
    this._chunkedEncoding = false;
    this._uploadedBytes = 0;
    this._chunks = [];
    this._redirectPending = false;

    if (options && typeof options === 'object' && options.headers) {
      for (const [key, val] of Object.entries(options.headers)) {
        this.setHeader(key, val);
      }
    }
  }

  get chunkedEncoding() {
    return this._chunkedEncoding;
  }

  set chunkedEncoding(val) {
    if (this._written || this._finished) {
      throw new Error('chunkedEncoding can only be set before the first write');
    }
    this._chunkedEncoding = Boolean(val);
  }

  setHeader(name, value) {
    if (this._written || this._finished || this._aborted) {
      throw new Error('Cannot set header after request body has been written');
    }
    if (typeof name !== 'string' || name.length === 0) {
      throw new TypeError('Header name must be a non-empty string');
    }
    if (isRestrictedHeader(name, value)) {
      throw new Error(`Restricted header '${name}' cannot be set`);
    }
    const valStr = String(value);
    this._headers[name] = valStr;
  }

  getHeader(name) {
    if (typeof name !== 'string') return undefined;
    const targetKey = Object.keys(this._headers).find(
      (k) => k.toLowerCase() === name.toLowerCase()
    );
    return targetKey ? this._headers[targetKey] : undefined;
  }

  removeHeader(name) {
    if (this._written || this._finished || this._aborted) {
      throw new Error('Cannot remove header after request body has been written');
    }
    if (typeof name !== 'string') return;
    const targetKey = Object.keys(this._headers).find(
      (k) => k.toLowerCase() === name.toLowerCase()
    );
    if (targetKey) {
      delete this._headers[targetKey];
    }
  }

  write(chunk, encoding, callback) {
    if (this._finished || this._aborted) {
      throw new Error('Cannot write after request is finished or aborted');
    }
    this._written = true;

    let buf;
    if (Buffer.isBuffer(chunk)) {
      buf = chunk;
    } else if (typeof chunk === 'string') {
      buf = Buffer.from(chunk, typeof encoding === 'string' ? encoding : 'utf-8');
    } else {
      throw new TypeError('Write chunk must be a string or Buffer');
    }

    this._chunks.push(buf);
    this._uploadedBytes += buf.length;

    const cb = typeof encoding === 'function' ? encoding : callback;
    if (typeof cb === 'function') {
      process.nextTick(cb);
    }
  }

  end(chunk, encoding, callback) {
    if (chunk) {
      this.write(chunk, encoding);
    }
    this._finished = true;

    const cb = typeof encoding === 'function' ? encoding : callback;
    if (typeof cb === 'function') {
      process.nextTick(cb);
    }

    process.nextTick(() => {
      if (!this._aborted) {
        this.emit('finish');
      }
    });

    return this;
  }

  abort() {
    if (this._closed) return;
    this._aborted = true;
    this._closed = true;

    process.nextTick(() => {
      this.emit('abort');
      this.emit('close');
    });
  }

  followRedirect() {
    if (!this._redirectPending) {
      throw new Error('followRedirect can only be called during a redirect event');
    }
    this._redirectPending = false;
  }

  getUploadProgress() {
    return {
      active: !this._finished && !this._closed && !this._aborted,
      started: this._written,
      current: this._uploadedBytes,
      total: this._uploadedBytes,
    };
  }
}

/**
 * Net controller implementing the Electron Net module.
 */
class NetController {
  constructor() {
    this._online = true;
  }

  isOnline() {
    return this._online;
  }

  get online() {
    return this._online;
  }

  setOnline(status) {
    this._online = Boolean(status);
  }

  request(options) {
    return new ClientRequestMock(options);
  }

  async fetch(input, init = {}) {
    let urlStr = typeof input === 'string' ? input : (input && input.url ? input.url : '');
    if (!urlStr) {
      throw new TypeError('Invalid fetch URL input');
    }

    if (urlStr.startsWith('data:') || urlStr.startsWith('blob:')) {
      throw new TypeError('net.fetch() does not support data: or blob: schemes');
    }

    if (!this._online) {
      throw new Error('net::ERR_INTERNET_DISCONNECTED');
    }

    const method = (init.method || 'GET').toUpperCase();
    const bypassCustom = Boolean(init.bypassCustomProtocolHandlers);
    const bodyText = typeof init.body === 'string' ? init.body : '';

    return {
      status: 200,
      statusText: 'OK',
      ok: true,
      url: urlStr,
      type: 'basic',
      bypassCustomProtocolHandlers: bypassCustom,
      async text() {
        return bodyText || '{"success":true}';
      },
      async json() {
        const txt = await this.text();
        return JSON.parse(txt);
      },
      async arrayBuffer() {
        const txt = await this.text();
        return Buffer.from(txt).buffer;
      },
    };
  }

  async resolveHost(host, options = {}) {
    if (!this._online) {
      throw new Error('net::ERR_NAME_NOT_RESOLVED');
    }
    if (typeof host !== 'string' || host.trim().length === 0) {
      throw new TypeError('Host must be a non-empty string');
    }

    const trimmed = host.trim();
    if (trimmed === 'localhost' || trimmed === '127.0.0.1') {
      return {
        endpoints: [{ address: '127.0.0.1', port: 0, family: 'ipv4' }],
      };
    }
    if (trimmed === 'example.com') {
      return {
        endpoints: [{ address: '93.184.216.34', port: 0, family: 'ipv4' }],
      };
    }
    return {
      endpoints: [{ address: '192.0.2.1', port: 0, family: 'ipv4' }],
    };
  }
}

/**
 * Factory for creating a NetController instance.
 * @returns {NetController}
 */
function createNetController() {
  return new NetController();
}

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

const assert = require('node:assert');
const {
  RESTRICTED_HEADERS,
  getNetDeclarations,
  isRestrictedHeader,
  ClientRequestMock,
  createNetController,
} = require('../index.js');

async function runTests() {
  // Contract 1: electron type definitions declare Net interface with fetch, isOnline, online, request, and resolveHost methods across Common, Main, and CrossProcessExports namespaces
  {
    const decl = getNetDeclarations();
    assert.strictEqual(decl.hasNetInterface, true, 'Net interface must exist in electron.d.ts');
    assert.strictEqual(decl.hasClientRequestClass, true, 'ClientRequest class must exist in electron.d.ts');
    assert.strictEqual(decl.isCommonExported, true, 'net must be declared in Common namespace');
    assert.strictEqual(decl.isMainExported, true, 'net must be declared in Main namespace');
    assert.strictEqual(decl.isCrossProcessExported, true, 'net must be declared in CrossProcessExports namespace');
    assert.strictEqual(decl.isTopLevelExported, true, 'net must be declared at module top-level');

    const expectedNetMethods = ['fetch', 'isOnline', 'request', 'resolveHost'];
    for (const method of expectedNetMethods) {
      assert.ok(decl.netMethods.includes(method), `Net declaration must contain '${method}' method`);
    }

    assert.ok(decl.netProperties.includes('online'), "Net declaration must contain 'online' property");

    const expectedReqMethods = [
      'abort',
      'end',
      'followRedirect',
      'getHeader',
      'getUploadProgress',
      'removeHeader',
      'setHeader',
      'write',
    ];
    for (const method of expectedReqMethods) {
      assert.ok(
        decl.clientRequestMethods.includes(method),
        `ClientRequest declaration must contain '${method}' method`
      );
    }

    const expectedEvents = ['abort', 'close', 'error', 'finish', 'login', 'redirect', 'response'];
    for (const event of expectedEvents) {
      assert.ok(
        decl.clientRequestEvents.includes(event),
        `ClientRequest declaration must handle '${event}' event`
      );
    }
  }

  // Contract 2: Net controller validates online status and manages internet connectivity state transitions
  {
    const net = createNetController();
    assert.strictEqual(net.isOnline(), true, 'Net should report online by default');
    assert.strictEqual(net.online, true, 'net.online property should reflect online status');

    net.setOnline(false);
    assert.strictEqual(net.isOnline(), false, 'Net should report offline after state change');
    assert.strictEqual(net.online, false, 'net.online property should be false when offline');

    net.setOnline(true);
    assert.strictEqual(net.isOnline(), true, 'Net should return to online state');
    assert.strictEqual(net.online, true);
  }

  // Contract 3: Net request creates ClientRequest instances, validates URL and options, and enforces restricted HTTP headers
  {
    const net = createNetController();

    const reqFromString = net.request('http://localhost:8080/api/items');
    assert.ok(reqFromString instanceof ClientRequestMock);
    assert.strictEqual(reqFromString._url, 'http://localhost:8080/api/items');
    assert.strictEqual(reqFromString._method, 'GET');

    const reqFromOptions = net.request({
      method: 'POST',
      url: 'https://example.com/upload',
      headers: {
        'X-App-Version': '1.0.0',
        Accept: 'application/json',
      },
    });
    assert.strictEqual(reqFromOptions._method, 'POST');
    assert.strictEqual(reqFromOptions.getHeader('X-App-Version'), '1.0.0');
    assert.strictEqual(reqFromOptions.getHeader('accept'), 'application/json');

    assert.ok(RESTRICTED_HEADERS.has('content-length'));
    assert.ok(RESTRICTED_HEADERS.has('host'));
    assert.ok(RESTRICTED_HEADERS.has('trailer'));
    assert.ok(RESTRICTED_HEADERS.has('te'));
    assert.ok(RESTRICTED_HEADERS.has('upgrade'));
    assert.ok(RESTRICTED_HEADERS.has('cookie2'));
    assert.ok(RESTRICTED_HEADERS.has('keep-alive'));
    assert.ok(RESTRICTED_HEADERS.has('transfer-encoding'));

    assert.strictEqual(isRestrictedHeader('Content-Length'), true);
    assert.strictEqual(isRestrictedHeader('Host'), true);
    assert.strictEqual(isRestrictedHeader('Connection', 'upgrade'), true);
    assert.strictEqual(isRestrictedHeader('Connection', 'keep-alive'), false);
    assert.strictEqual(isRestrictedHeader('X-Custom-Header'), false);

    assert.throws(() => {
      reqFromString.setHeader('Content-Length', '123');
    }, /Restricted header/);

    assert.throws(() => {
      reqFromString.setHeader('Host', 'example.com');
    }, /Restricted header/);

    assert.throws(() => {
      reqFromString.setHeader('Connection', 'upgrade');
    }, /Restricted header/);

    assert.throws(() => {
      net.request(null);
    }, TypeError);
  }

  // Contract 4: ClientRequest manages request header manipulation, body writing, and upload progress tracking before and after stream completion
  {
    const net = createNetController();
    const req = net.request('http://localhost:3000/submit');

    assert.strictEqual(req.chunkedEncoding, false);
    req.chunkedEncoding = true;
    assert.strictEqual(req.chunkedEncoding, true);

    req.setHeader('X-Custom-Trace', 'trace-999');
    assert.strictEqual(req.getHeader('x-custom-trace'), 'trace-999');

    req.removeHeader('x-custom-trace');
    assert.strictEqual(req.getHeader('x-custom-trace'), undefined);

    let initialProgress = req.getUploadProgress();
    assert.strictEqual(initialProgress.active, true);
    assert.strictEqual(initialProgress.started, false);
    assert.strictEqual(initialProgress.current, 0);

    req.write('chunk-part-1');
    let midProgress = req.getUploadProgress();
    assert.strictEqual(midProgress.started, true);
    assert.strictEqual(midProgress.current, 12);

    assert.throws(() => {
      req.setHeader('X-Too-Late', 'val');
    }, /Cannot set header after request body has been written/);

    assert.throws(() => {
      req.removeHeader('X-Too-Late');
    }, /Cannot remove header after request body has been written/);

    assert.throws(() => {
      req.chunkedEncoding = false;
    }, /chunkedEncoding can only be set before the first write/);

    let finishEmitted = false;
    req.on('finish', () => {
      finishEmitted = true;
    });

    await new Promise((resolve) => {
      req.end(Buffer.from('-part-2'), 'utf-8', () => {
        resolve();
      });
    });

    await new Promise((resolve) => process.nextTick(resolve));
    assert.strictEqual(finishEmitted, true);

    let finalProgress = req.getUploadProgress();
    assert.strictEqual(finalProgress.active, false);
    assert.strictEqual(finalProgress.started, true);
    assert.strictEqual(finalProgress.current, 19);

    const abortReq = net.request('http://localhost:3000/abort-test');
    let abortEmitted = false;
    let closeEmitted = false;

    abortReq.on('abort', () => { abortEmitted = true; });
    abortReq.on('close', () => { closeEmitted = true; });

    abortReq.abort();
    await new Promise((resolve) => process.nextTick(resolve));
    assert.strictEqual(abortEmitted, true);
    assert.strictEqual(closeEmitted, true);
  }

  // Contract 5: Net fetch executes simulated HTTP/HTTPS requests, validates unsupported protocols like data: and blob:, and supports bypassCustomProtocolHandlers option
  {
    const net = createNetController();

    await assert.rejects(
      async () => {
        await net.fetch('data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==');
      },
      /net\.fetch\(\) does not support data: or blob: schemes/
    );

    await assert.rejects(
      async () => {
        await net.fetch('blob:http://localhost/550e8400-e29b-41d4-a716-446655440000');
      },
      /net\.fetch\(\) does not support data: or blob: schemes/
    );

    const res = await net.fetch('https://example.com/api/status', {
      method: 'GET',
      bypassCustomProtocolHandlers: true,
    });

    assert.strictEqual(res.status, 200);
    assert.strictEqual(res.statusText, 'OK');
    assert.strictEqual(res.ok, true);
    assert.strictEqual(res.url, 'https://example.com/api/status');
    assert.strictEqual(res.bypassCustomProtocolHandlers, true);

    const json = await res.json();
    assert.deepStrictEqual(json, { success: true });

    net.setOnline(false);
    await assert.rejects(
      async () => {
        await net.fetch('https://example.com/api/status');
      },
      /net::ERR_INTERNET_DISCONNECTED/
    );
    net.setOnline(true);
  }

  // Contract 6: Net resolveHost performs hostname resolution into IP addresses and handles DNS resolution errors
  {
    const net = createNetController();

    const localResolved = await net.resolveHost('localhost');
    assert.ok(localResolved.endpoints && localResolved.endpoints.length > 0);
    assert.strictEqual(localResolved.endpoints[0].address, '127.0.0.1');
    assert.strictEqual(localResolved.endpoints[0].family, 'ipv4');

    const domainResolved = await net.resolveHost('example.com');
    assert.ok(domainResolved.endpoints && domainResolved.endpoints.length > 0);
    assert.strictEqual(domainResolved.endpoints[0].address, '93.184.216.34');

    await assert.rejects(
      async () => {
        await net.resolveHost('');
      },
      /Host must be a non-empty string/
    );

    net.setOnline(false);
    await assert.rejects(
      async () => {
        await net.resolveHost('localhost');
      },
      /net::ERR_NAME_NOT_RESOLVED/
    );
    net.setOnline(true);
  }

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

runTests().catch((err) => {
  console.error('Contract test failed:', err);
  process.exit(1);
});

オリジンシーダー

匿名