Upload via GUI (7543 Dateien)

This commit is contained in:
2026-10-22 06:56:19 +00:00
parent e4585e50ee
commit d6518698b1
50 changed files with 1914 additions and 0 deletions
+9
View File
@@ -0,0 +1,9 @@
export declare class Cache {
private cacheRoot;
constructor(cacheRoot?: string);
static getCacheDirectory(downloadUrl: string): string;
getCachePath(downloadUrl: string, fileName: string): string;
getPathForFileInCache(url: string, fileName: string): string | null;
private hashFile;
putFileInCache(url: string, currentPath: string, fileName: string): Promise<string>;
}
+99
View File
@@ -0,0 +1,99 @@
import debug from 'debug';
import envPaths from 'env-paths';
import fs from 'graceful-fs';
import crypto from 'node:crypto';
import path from 'node:path';
import { pipeline } from 'node:stream/promises';
const d = debug('@electron/get:cache');
const defaultCacheRoot = envPaths('electron', {
suffix: '',
}).cache;
export class Cache {
cacheRoot;
constructor(cacheRoot = defaultCacheRoot) {
this.cacheRoot = cacheRoot;
}
static getCacheDirectory(downloadUrl) {
const parsed = new URL(downloadUrl);
parsed.hash = '';
parsed.search = '';
parsed.pathname = path.posix.dirname(parsed.pathname);
return crypto.createHash('sha256').update(parsed.toString()).digest('hex');
}
getCachePath(downloadUrl, fileName) {
return path.resolve(this.cacheRoot, Cache.getCacheDirectory(downloadUrl), fileName);
}
getPathForFileInCache(url, fileName) {
const cachePath = this.getCachePath(url, fileName);
if (fs.existsSync(cachePath)) {
return cachePath;
}
return null;
}
async hashFile(path) {
const hasher = crypto.createHash('sha256');
await pipeline(fs.createReadStream(path), hasher);
return hasher.digest('hex');
}
async putFileInCache(url, currentPath, fileName) {
const attempt = async (attemptsLeft = 3) => {
try {
const cachePath = this.getCachePath(url, fileName);
d(`Moving ${currentPath} to ${cachePath}`);
if (!fs.existsSync(path.dirname(cachePath))) {
await fs.promises.mkdir(path.dirname(cachePath), { recursive: true });
}
if (fs.existsSync(cachePath)) {
const [existingHash, currentHash] = await Promise.all([
this.hashFile(cachePath),
this.hashFile(currentPath),
]);
if (existingHash !== currentHash) {
d('* Replacing existing file as it does not match our inbound file');
await fs.promises.rm(cachePath, { recursive: true, force: true });
}
else {
d('* Using existing file as the hash matches our inbound file, no need to replace');
return cachePath;
}
}
try {
await fs.promises.rename(currentPath, cachePath);
}
catch (err) {
if (err.code === 'EXDEV') {
// Cross-device link, fallback to copy and delete
await fs.promises.cp(currentPath, cachePath, {
force: true,
recursive: true,
verbatimSymlinks: true,
});
await fs.promises.rm(currentPath, { force: true, recursive: true });
}
else {
throw err;
}
}
return cachePath;
}
catch (err) {
if (process.platform === 'win32' && err.code === 'EPERM') {
// On windows this normally means we're fighting another instance of @electron/get
// also trying to write this file to the cache
d('Experienced error putting thing in cache', err);
if (attemptsLeft > 0) {
d('Trying again in a few seconds');
await new Promise((resolve) => {
setTimeout(resolve, 2000);
});
return await attempt(attemptsLeft - 1);
}
d('We have already tried too many times, giving up...');
}
throw err;
}
};
return await attempt();
}
}
//# sourceMappingURL=Cache.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"Cache.js","sourceRoot":"","sources":["../src/Cache.ts"],"names":[],"mappings":"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"}
+18
View File
@@ -0,0 +1,18 @@
/**
* Generic interface for the artifact downloader library.
* The default implementation is {@link FetchDownloader},
* but any custom downloader can be passed to `@electron/get` via
* the {@link ElectronDownloadRequestOptions.downloader} option.
*
* @typeParam T - Options to pass to the downloader
* @category Downloader
*/
export interface Downloader<T> {
/**
* Download an artifact from an arbitrary URL to a file path on system
* @param url URL of the file to download
* @param targetFilePath Filesystem path to download the artifact to (including the file name)
* @param options Options to pass to the downloader
*/
download(url: string, targetFilePath: string, options: T): Promise<void>;
}
+2
View File
@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=Downloader.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"Downloader.js","sourceRoot":"","sources":["../src/Downloader.ts"],"names":[],"mappings":""}
+43
View File
@@ -0,0 +1,43 @@
import { Downloader } from './Downloader.js';
/**
* @category Downloader
*/
export interface Progress {
/** Bytes downloaded so far. */
transferred: number;
/** Total bytes to download, or `null` if the response had no `Content-Length` header. */
total: number | null;
/**
* Ratio of `transferred` to `total` between 0 and 1.
* If `total` is unknown, this is 0 until the download completes, then 1.
*/
percent: number;
}
/**
* @category Downloader
*/
export declare class HTTPError extends Error {
readonly response: Response;
constructor(response: Response);
}
/**
* @category Downloader
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/RequestInit | `RequestInit`} for possible keys/values.
*/
export type FetchDownloaderOptions = RequestInit & {
/** Called on each chunk with the current download {@link Progress}. */
getProgressCallback?: (progress: Progress) => Promise<void>;
/**
* Disables the console progress bar. Setting the `ELECTRON_GET_NO_PROGRESS`
* environment variable to a non-empty value also does this.
*/
quiet?: boolean;
};
/**
* Default {@link Downloader} implemented with the built-in
* {@link https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API | Fetch API}.
* @category Downloader
*/
export declare class FetchDownloader implements Downloader<FetchDownloaderOptions> {
download(url: string, targetFilePath: string, options?: FetchDownloaderOptions): Promise<void>;
}
+82
View File
@@ -0,0 +1,82 @@
import fs from 'graceful-fs';
import path from 'node:path';
import ProgressBar from 'progress';
import { pipeline } from 'node:stream/promises';
import { Readable } from 'node:stream';
const PROGRESS_BAR_DELAY_IN_SECONDS = 30;
/**
* @category Downloader
*/
export class HTTPError extends Error {
response;
constructor(response) {
super(`Response code ${response.status} (${response.statusText}) for ${response.url}`);
this.response = response;
this.name = 'HTTPError';
}
}
/**
* Default {@link Downloader} implemented with the built-in
* {@link https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API | Fetch API}.
* @category Downloader
*/
export class FetchDownloader {
async download(url, targetFilePath, options = {}) {
const { quiet, getProgressCallback, ...fetchOptions } = options;
let downloadCompleted = false;
let bar;
let progressPercent;
let timeout = undefined;
await fs.promises.mkdir(path.dirname(targetFilePath), { recursive: true });
if (!quiet && !process.env.ELECTRON_GET_NO_PROGRESS) {
const start = new Date();
timeout = setTimeout(() => {
if (!downloadCompleted) {
bar = new ProgressBar(`Downloading ${path.basename(url)}: [:bar] :percent ETA: :eta seconds `, {
curr: progressPercent,
total: 100,
});
// https://github.com/visionmedia/node-progress/issues/159
// eslint-disable-next-line @typescript-eslint/no-explicit-any
bar.start = start;
}
}, PROGRESS_BAR_DELAY_IN_SECONDS * 1000);
}
try {
const response = await fetch(url, fetchOptions);
if (!response.ok) {
throw new HTTPError(response);
}
if (!response.body) {
throw new Error('Response body is empty');
}
const contentLength = response.headers.get('content-length');
const total = contentLength ? parseInt(contentLength, 10) : null;
let transferred = 0;
const onProgress = (percent) => {
progressPercent = percent;
if (bar) {
bar.update(percent);
}
if (getProgressCallback) {
void getProgressCallback({ transferred, total, percent });
}
};
await pipeline(Readable.fromWeb(response.body), async function* (source) {
for await (const chunk of source) {
transferred += chunk.length;
onProgress(total ? transferred / total : 0);
yield chunk;
}
}, fs.createWriteStream(targetFilePath));
onProgress(1);
}
finally {
downloadCompleted = true;
if (timeout) {
clearTimeout(timeout);
}
}
}
}
//# sourceMappingURL=FetchDownloader.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"FetchDownloader.js","sourceRoot":"","sources":["../src/FetchDownloader.ts"],"names":[],"mappings":"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"}
+4
View File
@@ -0,0 +1,4 @@
import { ElectronArtifactDetails } from './types.js';
export declare function getArtifactFileName(details: ElectronArtifactDetails): string;
export declare function getArtifactRemoteURL(details: ElectronArtifactDetails): Promise<string>;
export declare function getArtifactVersion(details: ElectronArtifactDetails): string;
+54
View File
@@ -0,0 +1,54 @@
import { ensureIsTruthyString, normalizeVersion } from './utils.js';
const BASE_URL = 'https://github.com/electron/electron/releases/download/';
const NIGHTLY_BASE_URL = 'https://github.com/electron/nightlies/releases/download/';
export function getArtifactFileName(details) {
ensureIsTruthyString(details, 'artifactName');
if (details.isGeneric) {
return details.artifactName;
}
ensureIsTruthyString(details, 'arch');
ensureIsTruthyString(details, 'platform');
ensureIsTruthyString(details, 'version');
return `${[
details.artifactName,
details.version,
details.platform,
details.arch,
...(details.artifactSuffix ? [details.artifactSuffix] : []),
].join('-')}.zip`;
}
function mirrorVar(name, options, defaultValue) {
// Convert camelCase to camel_case for env var reading
const snakeName = name.replace(/([a-z])([A-Z])/g, (_, a, b) => `${a}_${b}`).toLowerCase();
return (
// .npmrc
process.env[`npm_config_electron_${name.toLowerCase()}`] ||
process.env[`NPM_CONFIG_ELECTRON_${snakeName.toUpperCase()}`] ||
process.env[`npm_config_electron_${snakeName}`] ||
// package.json
process.env[`npm_package_config_electron_${name}`] ||
process.env[`npm_package_config_electron_${snakeName.toLowerCase()}`] ||
// env
process.env[`ELECTRON_${snakeName.toUpperCase()}`] ||
options[name] ||
defaultValue);
}
export async function getArtifactRemoteURL(details) {
const opts = details.mirrorOptions || {};
let base = mirrorVar('mirror', opts, BASE_URL);
if (details.version.includes('nightly')) {
base = mirrorVar('nightlyMirror', opts, NIGHTLY_BASE_URL);
}
const path = mirrorVar('customDir', opts, details.version).replace('{{ version }}', details.version.replace(/^v/, ''));
const file = mirrorVar('customFilename', opts, getArtifactFileName(details));
// Allow customized download URL resolution.
if (opts.resolveAssetURL) {
const url = await opts.resolveAssetURL(details);
return url;
}
return `${base}${path}/${file}`;
}
export function getArtifactVersion(details) {
return normalizeVersion(mirrorVar('customVersion', details.mirrorOptions || {}, details.version));
}
//# sourceMappingURL=artifact-utils.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"artifact-utils.js","sourceRoot":"","sources":["../src/artifact-utils.ts"],"names":[],"mappings":"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"}
+3
View File
@@ -0,0 +1,3 @@
import { DownloadOptions } from './types.js';
import { Downloader } from './Downloader.js';
export declare function getDownloaderForSystem(): Promise<Downloader<DownloadOptions>>;
+5
View File
@@ -0,0 +1,5 @@
import { FetchDownloader } from './FetchDownloader.js';
export async function getDownloaderForSystem() {
return new FetchDownloader();
}
//# sourceMappingURL=downloader-resolver.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"downloader-resolver.js","sourceRoot":"","sources":["../src/downloader-resolver.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,MAAM,CAAC,KAAK,UAAU,sBAAsB;IAC1C,OAAO,IAAI,eAAe,EAAE,CAAC;AAC/B,CAAC"}
+27
View File
@@ -0,0 +1,27 @@
import { ElectronDownloadRequestOptions, ElectronGenericArtifactDetails, ElectronPlatformArtifactDetailsWithDefaults } from './types.js';
export { getHostArch } from './utils.js';
export { initializeProxy } from './proxy.js';
export * from './types.js';
/**
* Downloads an artifact from an Electron release and returns an absolute path
* to the downloaded file.
*
* Each release of Electron comes with artifacts, many of which are
* platform/arch-specific (e.g. `ffmpeg-v31.0.0-darwin-arm64.zip`) and others that
* are generic (e.g. `SHASUMS256.txt`).
*
*
* @param artifactDetails - The information required to download the artifact
* @category Download Artifact
*/
export declare function downloadArtifact(artifactDetails: ElectronPlatformArtifactDetailsWithDefaults | ElectronGenericArtifactDetails): Promise<string>;
/**
* Downloads the Electron binary for a specific version and returns an absolute path to a
* ZIP file.
*
* @param version - The version of Electron you want to download (e.g. `31.0.0`)
* @param options - Options to customize the download behavior
* @returns An absolute path to the downloaded ZIP file
* @category Download Electron
*/
export declare function download(version: string, options?: ElectronDownloadRequestOptions): Promise<string>;
+188
View File
@@ -0,0 +1,188 @@
import debug from 'debug';
import fs from 'graceful-fs';
import path from 'node:path';
import util from 'node:util';
import semver from 'semver';
import sumchecker from 'sumchecker';
import { getArtifactFileName, getArtifactRemoteURL, getArtifactVersion } from './artifact-utils.js';
import { ElectronDownloadCacheMode, } from './types.js';
import { Cache } from './Cache.js';
import { getDownloaderForSystem } from './downloader-resolver.js';
import { initializeProxy } from './proxy.js';
import { withTempDirectoryIn, getHostArch, getNodeArch, ensureIsTruthyString, isOfficialDropped32BitDownload, isOfficialLinuxIA32Download, mkdtemp, doesCallerOwnTemporaryOutput, effectiveCacheMode, shouldTryReadCache, TempDirCleanUpMode, } from './utils.js';
export { getHostArch } from './utils.js';
export { initializeProxy } from './proxy.js';
export * from './types.js';
const d = debug('@electron/get:index');
if (process.env.ELECTRON_GET_USE_PROXY) {
initializeProxy();
}
async function validateArtifact(artifactDetails, downloadedAssetPath, _downloadArtifact) {
return await withTempDirectoryIn(artifactDetails.tempDirectory, async (tempFolder) => {
// Don't try to verify the hash of the hash file itself
// and for older versions that don't have a SHASUMS256.txt
if (!artifactDetails.artifactName.startsWith('SHASUMS256') &&
!artifactDetails.unsafelyDisableChecksums &&
semver.gte(artifactDetails.version, '1.3.2')) {
let shasumPath;
const checksums = artifactDetails.checksums;
if (checksums) {
shasumPath = path.resolve(tempFolder, 'SHASUMS256.txt');
const fileNames = Object.keys(checksums);
if (fileNames.length === 0) {
throw new Error('Provided "checksums" object is empty, cannot generate a valid SHASUMS256.txt');
}
const generatedChecksums = fileNames
.map((fileName) => `${checksums[fileName]} *${fileName}`)
.join('\n');
await util.promisify(fs.writeFile)(shasumPath, generatedChecksums);
}
else {
shasumPath = await _downloadArtifact({
isGeneric: true,
version: artifactDetails.version,
artifactName: 'SHASUMS256.txt',
downloadOptions: artifactDetails.downloadOptions,
cacheRoot: artifactDetails.cacheRoot,
downloader: artifactDetails.downloader,
mirrorOptions: artifactDetails.mirrorOptions,
tempDirectory: artifactDetails.tempDirectory,
// Never use the cache for loading checksums, load
// them fresh every time
cacheMode: ElectronDownloadCacheMode.Bypass,
});
}
try {
// For versions 1.3.2 - 1.3.4, need to overwrite the `defaultTextEncoding` option:
// https://github.com/electron/electron/pull/6676#discussion_r75332120
if (semver.satisfies(artifactDetails.version, '1.3.2 - 1.3.4')) {
const validatorOptions = {};
validatorOptions.defaultTextEncoding = 'binary';
const checker = new sumchecker.ChecksumValidator('sha256', shasumPath, validatorOptions);
await checker.validate(path.dirname(downloadedAssetPath), path.basename(downloadedAssetPath));
}
else {
await sumchecker('sha256', shasumPath, path.dirname(downloadedAssetPath), [
path.basename(downloadedAssetPath),
]);
}
}
finally {
// Once we're done make sure we clean up the shasum temp dir
await fs.promises.rm(path.dirname(shasumPath), { recursive: true, force: true });
}
}
}, TempDirCleanUpMode.CLEAN);
}
/**
* Downloads an artifact from an Electron release and returns an absolute path
* to the downloaded file.
*
* Each release of Electron comes with artifacts, many of which are
* platform/arch-specific (e.g. `ffmpeg-v31.0.0-darwin-arm64.zip`) and others that
* are generic (e.g. `SHASUMS256.txt`).
*
*
* @param artifactDetails - The information required to download the artifact
* @category Download Artifact
*/
export async function downloadArtifact(artifactDetails) {
const details = {
...artifactDetails,
};
if (!artifactDetails.isGeneric) {
const platformArtifactDetails = details;
if (!platformArtifactDetails.platform) {
d('No platform found, defaulting to the host platform');
platformArtifactDetails.platform = process.platform;
}
if (platformArtifactDetails.arch) {
platformArtifactDetails.arch = getNodeArch(platformArtifactDetails.arch);
}
else {
d('No arch found, defaulting to the host arch');
platformArtifactDetails.arch = getHostArch();
}
}
ensureIsTruthyString(details, 'version');
details.version = getArtifactVersion(details);
const fileName = getArtifactFileName(details);
const url = await getArtifactRemoteURL(details);
const cache = new Cache(details.cacheRoot);
const cacheMode = effectiveCacheMode(details);
// Do not check if the file exists in the cache when force === true
if (shouldTryReadCache(cacheMode)) {
d(`Checking the cache (${details.cacheRoot}) for ${fileName} (${url})`);
const cachedPath = cache.getPathForFileInCache(url, fileName);
if (cachedPath === null) {
d('Cache miss');
}
else {
d('Cache hit');
let artifactPath = cachedPath;
if (doesCallerOwnTemporaryOutput(cacheMode)) {
// Copy out of cache into temporary directory if readOnly cache so
// that the caller can take ownership of the returned file
const tempDir = await mkdtemp(artifactDetails.tempDirectory);
artifactPath = path.resolve(tempDir, fileName);
await util.promisify(fs.copyFile)(cachedPath, artifactPath);
}
try {
await validateArtifact(details, artifactPath, downloadArtifact);
return artifactPath;
}
catch (err) {
if (doesCallerOwnTemporaryOutput(cacheMode)) {
await fs.promises.rm(path.dirname(artifactPath), { recursive: true, force: true });
}
d("Artifact in cache didn't match checksums", err);
d('falling back to re-download');
}
}
}
if (!details.isGeneric &&
isOfficialLinuxIA32Download(details.platform, details.arch, details.version, details.mirrorOptions)) {
console.warn('Official Linux/ia32 support is deprecated.');
console.warn('For more info: https://electronjs.org/blog/linux-32bit-support');
}
if (!details.isGeneric &&
isOfficialDropped32BitDownload(details.platform, details.arch, details.version, details.mirrorOptions)) {
throw new Error(`Electron ${details.version} does not have a published ${details.platform}/${details.arch} artifact. ` +
'Electron 44 and newer no longer publish win32/ia32 or linux/armv7l builds; ' +
'the last release line with 32-bit support is Electron 43, which is supported until January 2027.');
}
return await withTempDirectoryIn(details.tempDirectory, async (tempFolder) => {
const tempDownloadPath = path.resolve(tempFolder, getArtifactFileName(details));
const downloader = details.downloader || (await getDownloaderForSystem());
d(`Downloading ${url} to ${tempDownloadPath} with options: ${JSON.stringify(details.downloadOptions)}`);
await downloader.download(url, tempDownloadPath, details.downloadOptions);
d('attempting to validate artifact...', { details });
await validateArtifact(details, tempDownloadPath, downloadArtifact);
d('artifact validated');
if (doesCallerOwnTemporaryOutput(cacheMode)) {
return tempDownloadPath;
}
else {
return await cache.putFileInCache(url, tempDownloadPath, fileName);
}
}, doesCallerOwnTemporaryOutput(cacheMode) ? TempDirCleanUpMode.ORPHAN : TempDirCleanUpMode.CLEAN);
}
/**
* Downloads the Electron binary for a specific version and returns an absolute path to a
* ZIP file.
*
* @param version - The version of Electron you want to download (e.g. `31.0.0`)
* @param options - Options to customize the download behavior
* @returns An absolute path to the downloaded ZIP file
* @category Download Electron
*/
export function download(version, options) {
return downloadArtifact({
...options,
version,
platform: process.platform,
arch: process.arch,
artifactName: 'electron',
});
}
//# sourceMappingURL=index.js.map
+1
View File
File diff suppressed because one or more lines are too long
+14
View File
@@ -0,0 +1,14 @@
/**
* Initializes a third-party proxy module for HTTP(S) requests. Call this function before
* using the {@link download} and {@link downloadArtifact} APIs if you need proxy support.
*
* If the `ELECTRON_GET_USE_PROXY` environment variable is set to `true`, this function will be
* called automatically for `@electron/get` requests.
*
* Supported environment variables are `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY`.
*
* @category Utility
* @see {@link https://undici.nodejs.org/#/docs/api/EnvHttpProxyAgent | `EnvHttpProxyAgent`}
* documentation for available environment variables.
*/
export declare function initializeProxy(): void;
+28
View File
@@ -0,0 +1,28 @@
import { createRequire } from 'node:module';
import debug from 'debug';
const d = debug('@electron/get:proxy');
const require = createRequire(import.meta.url);
/**
* Initializes a third-party proxy module for HTTP(S) requests. Call this function before
* using the {@link download} and {@link downloadArtifact} APIs if you need proxy support.
*
* If the `ELECTRON_GET_USE_PROXY` environment variable is set to `true`, this function will be
* called automatically for `@electron/get` requests.
*
* Supported environment variables are `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY`.
*
* @category Utility
* @see {@link https://undici.nodejs.org/#/docs/api/EnvHttpProxyAgent | `EnvHttpProxyAgent`}
* documentation for available environment variables.
*/
export function initializeProxy() {
try {
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { EnvHttpProxyAgent, setGlobalDispatcher } = require('undici');
setGlobalDispatcher(new EnvHttpProxyAgent());
}
catch (e) {
d('Could not load undici, built-in proxy support not available:', e);
}
}
//# sourceMappingURL=proxy.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,CAAC,GAAG,KAAK,CAAC,qBAAqB,CAAC,CAAC;AACvC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE/C;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC;QACH,iEAAiE;QACjE,MAAM,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;QACrE,mBAAmB,CAAC,IAAI,iBAAiB,EAAE,CAAC,CAAC;IAC/C,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,CAAC,CAAC,8DAA8D,EAAE,CAAC,CAAC,CAAC;IACvE,CAAC;AACH,CAAC"}
+244
View File
@@ -0,0 +1,244 @@
import { Downloader } from './Downloader.js';
import { FetchDownloader, FetchDownloaderOptions, HTTPError, Progress } from './FetchDownloader.js';
export { Downloader, FetchDownloader, FetchDownloaderOptions, HTTPError, Progress };
/**
* Custom downloaders can implement any set of options.
* @category Downloader
*/
export type DownloadOptions = any;
/**
* Options for specifying an alternative download mirror for Electron.
*
* @category Utility
* @example
*
* To download the Electron v4.0.4 release for x64 Linux from
* https://github.com/electron/electron/releases/download/v4.0.4/electron-v4.0.4-linux-x64.zip
*
* ```js
* const opts = {
* mirror: 'https://github.com/electron/electron/releases/download',
* customDir: 'v4.0.4',
* customFilename: 'electron-v4.0.4-linux-x64.zip',
* }
* ```
*/
export interface MirrorOptions {
/**
* The mirror URL for [`electron-nightly`](https://npmjs.com/package/electron-nightly),
* which lives in a separate npm package.
*/
nightlyMirror?: string;
/**
* The base URL of the mirror to download from.
* e.g https://github.com/electron/electron/releases/download
*/
mirror?: string;
/**
* The name of the directory to download from,
* often scoped by version number e.g 'v4.0.4'
*/
customDir?: string;
/**
* The name of the asset to download,
* e.g 'electron-v4.0.4-linux-x64.zip'
*/
customFilename?: string;
/**
* The version of the asset to download,
* e.g '4.0.4'
*/
customVersion?: string;
/**
* A function allowing customization of the url returned
* from getArtifactRemoteURL().
*/
resolveAssetURL?: (opts: DownloadOptions) => Promise<string>;
}
/**
* @category Download Artifact
* @internal
*/
export interface ElectronDownloadRequest {
/**
* The version of Electron associated with the artifact.
*/
version: string;
/**
* The type of artifact. For example:
* * `electron`
* * `ffmpeg`
*/
artifactName: string;
}
export declare enum ElectronDownloadCacheMode {
/**
* Reads from the cache if present
* Writes to the cache after fetch if not present
*/
ReadWrite = 0,
/**
* Reads from the cache if present
* Will **not** write back to the cache after fetching missing artifact
*/
ReadOnly = 1,
/**
* Skips reading from the cache
* Will write back into the cache, overwriting anything currently in the cache after fetch
*/
WriteOnly = 2,
/**
* Bypasses the cache completely, neither reads from nor writes to the cache
*/
Bypass = 3
}
/**
* @category Download Electron
*/
export interface ElectronDownloadRequestOptions {
/**
* When set to `true`, disables checking that the artifact download completed successfully
* with the correct payload.
*
* @defaultValue `false`
*/
unsafelyDisableChecksums?: boolean;
/**
* Provides checksums for the artifact as strings.
* Can be used if you already know the checksums of the Electron artifact
* you are downloading and want to skip the checksum file download
* without skipping the checksum validation.
*
* This should be an object whose keys are the file names of the artifacts and
* the values are their respective SHA256 checksums.
*
* @example
* ```json
* {
* "electron-v4.0.4-linux-x64.zip": "877617029f4c0f2b24f3805a1c3554ba166fda65c4e88df9480ae7b6ffa26a22"
* }
* ```
*/
checksums?: Record<string, string>;
/**
* The directory that caches Electron artifact downloads.
*
* @defaultValue The default value is dependent upon the host platform:
*
* * Linux: `$XDG_CACHE_HOME` or `~/.cache/electron/`
* * MacOS: `~/Library/Caches/electron/`
* * Windows: `%LOCALAPPDATA%/electron/Cache` or `~/AppData/Local/electron/Cache/`
*/
cacheRoot?: string;
/**
* Options passed to the downloader module.
*
* @see {@link FetchDownloaderOptions} for options for the default {@link FetchDownloader}.
*/
downloadOptions?: DownloadOptions;
/**
* Options related to specifying an artifact mirror.
*/
mirrorOptions?: MirrorOptions;
/**
* A custom {@link Downloader} class used to download artifacts. Defaults to the
* built-in {@link FetchDownloader}.
*/
downloader?: Downloader<DownloadOptions>;
/**
* A temporary directory for downloads.
* It is used before artifacts are put into cache.
*
* @defaultValue the OS default temporary directory via [`os.tmpdir()`](https://nodejs.org/api/os.html#ostmpdir)
*/
tempDirectory?: string;
/**
* Controls the cache read and write behavior.
*
* When set to either {@link ElectronDownloadCacheMode.ReadOnly | ReadOnly} or
* {@link ElectronDownloadCacheMode.Bypass | Bypass}, the caller is responsible
* for cleaning up the returned file path once they are done using it
* (e.g. via `fs.remove(path.dirname(pathFromElectronGet))`).
*
* When set to either {@link ElectronDownloadCacheMode.WriteOnly | WriteOnly} or
* {@link ElectronDownloadCacheMode.ReadWrite | ReadWrite} (the default), the caller
* should not move or delete the file path that is returned as the path
* points directly to the disk cache.
*
* @defaultValue {@link ElectronDownloadCacheMode.ReadWrite}
*/
cacheMode?: ElectronDownloadCacheMode;
}
/**
* @category Download Artifact
* @internal
*/
export type ElectronPlatformArtifactDetails = {
/**
* The target artifact platform. These are Node-style platform names, for example:
* * `win32`
* * `darwin`
* * `linux`
*
* @see Node.js {@link https://nodejs.org/api/process.html#processplatform | process.platform} docs
*/
platform: string;
/**
* The target artifact architecture. These are Node-style architecture names, for example:
* * `ia32` (Electron 43 and earlier)
* * `x64`
* * `armv7l` (Electron 43 and earlier)
*
* @see Node.js {@link https://nodejs.org/api/process.html#processarch | process.arch} docs
*/
arch: string;
artifactSuffix?: string;
isGeneric?: false;
} & ElectronDownloadRequest & ElectronDownloadRequestOptions;
/**
* Options to download a generic (i.e. platform and architecture-agnostic)
* Electron artifact. Contains all options from {@link ElectronDownloadRequestOptions},
* but specifies a `version` and `artifactName` for the artifact to download.
*
* @category Download Artifact
* @interface
*/
export type ElectronGenericArtifactDetails = {
isGeneric: true;
} & ElectronDownloadRequest & ElectronDownloadRequestOptions;
/**
* @category Download Artifact
* @internal
*/
export type ElectronArtifactDetails = ElectronPlatformArtifactDetails | ElectronGenericArtifactDetails;
/**
* Options to download a platform and architecture-specific Electron artifact.
* Contains all options from {@link ElectronDownloadRequestOptions}, but
* specifies a `version` and `artifactName` for the artifact to download.
*
* If `platform` and `arch` are omitted, they will be inferred using the host
* system platform and architecture.
*
* @category Download Artifact
* @interface
*/
export type ElectronPlatformArtifactDetailsWithDefaults = Omit<ElectronPlatformArtifactDetails, 'platform' | 'arch'> & {
/**
* The target artifact platform. These are Node-style platform names, for example:
* * `win32`
* * `darwin`
* * `linux`
*
* @see Node.js {@link https://nodejs.org/api/process.html#processplatform | process.platform} docs
*/
platform?: string;
/**
* The target artifact architecture. These are Node-style architecture names, for example:
* * `ia32` (Electron 43 and earlier)
* * `x64`
* * `armv7l` (Electron 43 and earlier)
*
* @see Node.js {@link https://nodejs.org/api/process.html#processarch | process.arch} docs
*/
arch?: string;
};
+25
View File
@@ -0,0 +1,25 @@
import { FetchDownloader, HTTPError } from './FetchDownloader.js';
export { FetchDownloader, HTTPError };
export var ElectronDownloadCacheMode;
(function (ElectronDownloadCacheMode) {
/**
* Reads from the cache if present
* Writes to the cache after fetch if not present
*/
ElectronDownloadCacheMode[ElectronDownloadCacheMode["ReadWrite"] = 0] = "ReadWrite";
/**
* Reads from the cache if present
* Will **not** write back to the cache after fetching missing artifact
*/
ElectronDownloadCacheMode[ElectronDownloadCacheMode["ReadOnly"] = 1] = "ReadOnly";
/**
* Skips reading from the cache
* Will write back into the cache, overwriting anything currently in the cache after fetch
*/
ElectronDownloadCacheMode[ElectronDownloadCacheMode["WriteOnly"] = 2] = "WriteOnly";
/**
* Bypasses the cache completely, neither reads from nor writes to the cache
*/
ElectronDownloadCacheMode[ElectronDownloadCacheMode["Bypass"] = 3] = "Bypass";
})(ElectronDownloadCacheMode || (ElectronDownloadCacheMode = {}));
//# sourceMappingURL=types.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAA0B,SAAS,EAAY,MAAM,sBAAsB,CAAC;AAEpG,OAAO,EAAc,eAAe,EAA0B,SAAS,EAAY,CAAC;AA4EpF,MAAM,CAAN,IAAY,yBAoBX;AApBD,WAAY,yBAAyB;IACnC;;;OAGG;IACH,mFAAS,CAAA;IACT;;;OAGG;IACH,iFAAQ,CAAA;IACR;;;OAGG;IACH,mFAAS,CAAA;IACT;;OAEG;IACH,6EAAM,CAAA;AACR,CAAC,EApBW,yBAAyB,KAAzB,yBAAyB,QAoBpC"}
+38
View File
@@ -0,0 +1,38 @@
import { ElectronDownloadCacheMode, ElectronGenericArtifactDetails, ElectronPlatformArtifactDetailsWithDefaults } from './types.js';
export declare function mkdtemp(parentDirectory?: string): Promise<string>;
export declare enum TempDirCleanUpMode {
CLEAN = 0,
ORPHAN = 1
}
export declare function withTempDirectoryIn<T>(parentDirectory: string | undefined, fn: (directory: string) => Promise<T>, cleanUp: TempDirCleanUpMode): Promise<T>;
export declare function withTempDirectory<T>(fn: (directory: string) => Promise<T>, cleanUp: TempDirCleanUpMode): Promise<T>;
export declare function normalizeVersion(version: string): string;
/**
* Runs the `uname` command and returns the trimmed output.
*/
export declare function uname(): string;
/**
* Generates an architecture name that would be used in an Electron or Node.js
* download file name.
*/
export declare function getNodeArch(arch: string): string;
/**
* Generates an architecture name that would be used in an Electron or Node.js
* download file name from the `process` module information.
*
* @category Utility
*/
export declare function getHostArch(): string;
export declare function ensureIsTruthyString<T, K extends keyof T>(obj: T, key: K): void;
export declare function isOfficialLinuxIA32Download(platform: string, arch: string, version: string, mirrorOptions?: object): boolean;
export declare function isOfficialDropped32BitDownload(platform: string, arch: string, version: string, mirrorOptions?: object): boolean;
/**
* Find the value of a environment variable which may or may not have the
* prefix, in a case-insensitive manner.
*/
export declare function getEnv(prefix?: string): (name: string) => string | undefined;
export declare function setEnv(key: string, value: string | undefined): void;
export declare function effectiveCacheMode(artifactDetails: ElectronPlatformArtifactDetailsWithDefaults | ElectronGenericArtifactDetails): ElectronDownloadCacheMode;
export declare function shouldTryReadCache(cacheMode: ElectronDownloadCacheMode): boolean;
export declare function shouldWriteCache(cacheMode: ElectronDownloadCacheMode): boolean;
export declare function doesCallerOwnTemporaryOutput(cacheMode: ElectronDownloadCacheMode): boolean;
+147
View File
@@ -0,0 +1,147 @@
import childProcess from 'node:child_process';
import fs from 'graceful-fs';
import os from 'node:os';
import path from 'node:path';
import semver from 'semver';
import { ElectronDownloadCacheMode, } from './types.js';
async function useAndRemoveDirectory(directory, fn) {
let result;
try {
result = await fn(directory);
}
finally {
await fs.promises.rm(directory, { recursive: true, force: true });
}
return result;
}
export async function mkdtemp(parentDirectory = os.tmpdir()) {
const tempDirectoryPrefix = 'electron-download-';
return await fs.promises.mkdtemp(path.resolve(parentDirectory, tempDirectoryPrefix));
}
export var TempDirCleanUpMode;
(function (TempDirCleanUpMode) {
TempDirCleanUpMode[TempDirCleanUpMode["CLEAN"] = 0] = "CLEAN";
TempDirCleanUpMode[TempDirCleanUpMode["ORPHAN"] = 1] = "ORPHAN";
})(TempDirCleanUpMode || (TempDirCleanUpMode = {}));
export async function withTempDirectoryIn(parentDirectory = os.tmpdir(), fn, cleanUp) {
const tempDirectory = await mkdtemp(parentDirectory);
if (cleanUp === TempDirCleanUpMode.CLEAN) {
return useAndRemoveDirectory(tempDirectory, fn);
}
else {
return fn(tempDirectory);
}
}
export async function withTempDirectory(fn, cleanUp) {
return withTempDirectoryIn(undefined, fn, cleanUp);
}
export function normalizeVersion(version) {
if (!version.startsWith('v')) {
return `v${version}`;
}
return version;
}
/**
* Runs the `uname` command and returns the trimmed output.
*/
export function uname() {
return childProcess.execSync('uname -m').toString().trim();
}
/**
* Generates an architecture name that would be used in an Electron or Node.js
* download file name.
*/
export function getNodeArch(arch) {
if (arch === 'arm') {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
switch (process.config.variables.arm_version) {
case '6':
return uname();
case '7':
default:
return 'armv7l';
}
}
return arch;
}
/**
* Generates an architecture name that would be used in an Electron or Node.js
* download file name from the `process` module information.
*
* @category Utility
*/
export function getHostArch() {
return getNodeArch(process.arch);
}
export function ensureIsTruthyString(obj, key) {
if (!obj[key] || typeof obj[key] !== 'string') {
throw new Error(`Expected property "${String(key)}" to be provided as a string but it was not`);
}
}
export function isOfficialLinuxIA32Download(platform, arch, version, mirrorOptions) {
return (platform === 'linux' &&
arch === 'ia32' &&
Number(version.slice(1).split('.')[0]) >= 4 &&
typeof mirrorOptions === 'undefined');
}
// Electron 44 dropped support for 32-bit Windows (win32/ia32) and for
// armv7l Linux. The last official releases to ship these artifacts are
// v44.0.0-alpha.3 on the release channel and v45.0.0-nightly.20260713 on
// the nightly channel.
const FIRST_RELEASE_WITHOUT_32_BIT_SUPPORT = '44.0.0-alpha.4';
const FIRST_NIGHTLY_WITHOUT_32_BIT_SUPPORT = '45.0.0-nightly.20260714';
export function isOfficialDropped32BitDownload(platform, arch, version, mirrorOptions) {
// Custom mirrors may legitimately host their own builds for these platforms
if (typeof mirrorOptions !== 'undefined') {
return false;
}
if (!((platform === 'win32' && arch === 'ia32') || (platform === 'linux' && arch === 'armv7l'))) {
return false;
}
const parsedVersion = semver.parse(version);
if (parsedVersion === null) {
return false;
}
const firstVersionWithoutArtifacts = parsedVersion.prerelease.includes('nightly')
? FIRST_NIGHTLY_WITHOUT_32_BIT_SUPPORT
: FIRST_RELEASE_WITHOUT_32_BIT_SUPPORT;
return semver.gte(parsedVersion, firstVersionWithoutArtifacts);
}
/**
* Find the value of a environment variable which may or may not have the
* prefix, in a case-insensitive manner.
*/
export function getEnv(prefix = '') {
const envsLowerCase = {};
for (const envKey in process.env) {
envsLowerCase[envKey.toLowerCase()] = process.env[envKey];
}
return (name) => {
return (envsLowerCase[`${prefix}${name}`.toLowerCase()] ||
envsLowerCase[name.toLowerCase()] ||
undefined);
};
}
export function setEnv(key, value) {
// The `void` operator always returns `undefined`.
// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void
if (value !== void 0) {
process.env[key] = value;
}
}
export function effectiveCacheMode(artifactDetails) {
return artifactDetails.cacheMode || ElectronDownloadCacheMode.ReadWrite;
}
export function shouldTryReadCache(cacheMode) {
return (cacheMode === ElectronDownloadCacheMode.ReadOnly ||
cacheMode === ElectronDownloadCacheMode.ReadWrite);
}
export function shouldWriteCache(cacheMode) {
return (cacheMode === ElectronDownloadCacheMode.WriteOnly ||
cacheMode === ElectronDownloadCacheMode.ReadWrite);
}
export function doesCallerOwnTemporaryOutput(cacheMode) {
return (cacheMode === ElectronDownloadCacheMode.Bypass ||
cacheMode === ElectronDownloadCacheMode.ReadOnly);
}
//# sourceMappingURL=utils.js.map