Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
getHostArch,
getNodeArch,
ensureIsTruthyString,
isOfficialDropped32BitDownload,
isOfficialLinuxIA32Download,
mkdtemp,
doesCallerOwnTemporaryOutput,
Expand Down Expand Up @@ -202,6 +203,22 @@ export async function downloadArtifact(
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) => {
Expand Down
8 changes: 4 additions & 4 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,9 @@ export type ElectronPlatformArtifactDetails = {
platform: string;
/**
* The target artifact architecture. These are Node-style architecture names, for example:
* * `ia32`
* * `ia32` (Electron 43 and earlier)
* * `x64`
* * `armv7l`
* * `armv7l` (Electron 43 and earlier)
*
* @see Node.js {@link https://nodejs.org/api/process.html#processarch | process.arch} docs
*/
Expand Down Expand Up @@ -252,9 +252,9 @@ export type ElectronPlatformArtifactDetailsWithDefaults = Omit<
platform?: string;
/**
* The target artifact architecture. These are Node-style architecture names, for example:
* * `ia32`
* * `ia32` (Electron 43 and earlier)
* * `x64`
* * `armv7l`
* * `armv7l` (Electron 43 and earlier)
*
* @see Node.js {@link https://nodejs.org/api/process.html#processarch | process.arch} docs
*/
Expand Down
34 changes: 34 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ 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,
Expand Down Expand Up @@ -116,6 +117,39 @@ export function isOfficialLinuxIA32Download(
);
}

// 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: string,
arch: string,
version: string,
mirrorOptions?: object,
): boolean {
// 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.
Expand Down
66 changes: 66 additions & 0 deletions test/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,72 @@ describe('Public API', () => {
expect(await util.promisify(fs.readFile)(driverPath2, 'utf8')).toEqual('cached content');
});

describe('dropped 32-bit support', () => {
it('should throw for official win32/ia32 downloads of Electron >= 44.0.0-alpha.4', async () => {
await expect(
downloadArtifact({
cacheRoot,
downloader,
artifactName: 'electron',
version: '44.0.0',
platform: 'win32',
arch: 'ia32',
}),
).rejects.toThrow('Electron v44.0.0 does not have a published win32/ia32 artifact.');
});

it('should throw for official linux/armv7l downloads of Electron >= 44.0.0-alpha.4', async () => {
await expect(
downloadArtifact({
cacheRoot,
downloader,
artifactName: 'electron',
version: '44.0.0-alpha.4',
platform: 'linux',
arch: 'armv7l',
}),
).rejects.toThrow(
'Electron v44.0.0-alpha.4 does not have a published linux/armv7l artifact.',
);
});

it('should not throw for Electron 43 and earlier', async () => {
const zipPath = await downloadArtifact({
cacheRoot,
downloader,
artifactName: 'electron',
version: '2.0.9',
platform: 'linux',
arch: 'armv7l',
});
expect(fs.existsSync(zipPath)).toEqual(true);
expect(path.basename(zipPath)).toEqual('electron-v2.0.9-linux-armv7l.zip');
});

it('should not throw when a custom mirror is used', async () => {
const zipPath = await downloadArtifact({
cacheRoot,
unsafelyDisableChecksums: true,
artifactName: 'electron',
version: '44.0.0',
platform: 'win32',
arch: 'ia32',
mirrorOptions: {
mirror: 'https://mymirror.example.com/',
},
downloader: {
async download(url: string, targetPath: string): Promise<void> {
expect(url).toEqual(
'https://mymirror.example.com/v44.0.0/electron-v44.0.0-win32-ia32.zip',
);
await util.promisify(fs.writeFile)(targetPath, 'faked from mirror');
},
},
});
expect(await util.promisify(fs.readFile)(zipPath, 'utf8')).toEqual('faked from mirror');
});
});

describe('tempDirectory', () => {
let customTemp: string;

Expand Down
73 changes: 73 additions & 0 deletions test/utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
withTempDirectory,
getHostArch,
ensureIsTruthyString,
isOfficialDropped32BitDownload,
isOfficialLinuxIA32Download,
getEnv,
setEnv,
Expand Down Expand Up @@ -155,6 +156,78 @@ describe('utils', () => {
});
});

describe('isOfficialDropped32BitDownload()', () => {
it('should be true for win32/ia32 from v44.0.0-alpha.4 onward', () => {
expect(isOfficialDropped32BitDownload('win32', 'ia32', 'v44.0.0-alpha.4')).toEqual(true);
expect(isOfficialDropped32BitDownload('win32', 'ia32', 'v44.0.0-beta.1')).toEqual(true);
expect(isOfficialDropped32BitDownload('win32', 'ia32', 'v44.0.0')).toEqual(true);
expect(isOfficialDropped32BitDownload('win32', 'ia32', 'v45.1.2')).toEqual(true);
});

it('should be true for linux/armv7l from v44.0.0-alpha.4 onward', () => {
expect(isOfficialDropped32BitDownload('linux', 'armv7l', 'v44.0.0-alpha.4')).toEqual(true);
expect(isOfficialDropped32BitDownload('linux', 'armv7l', 'v44.0.0')).toEqual(true);
expect(isOfficialDropped32BitDownload('linux', 'armv7l', 'v45.1.2')).toEqual(true);
});

it('should be false for the Electron 44 prereleases that still shipped 32-bit builds', () => {
expect(isOfficialDropped32BitDownload('win32', 'ia32', 'v44.0.0-alpha.1')).toEqual(false);
expect(isOfficialDropped32BitDownload('win32', 'ia32', 'v44.0.0-alpha.3')).toEqual(false);
expect(isOfficialDropped32BitDownload('linux', 'armv7l', 'v44.0.0-alpha.3')).toEqual(false);
});

it('should be false for Electron 43 and earlier', () => {
expect(isOfficialDropped32BitDownload('win32', 'ia32', 'v43.0.0')).toEqual(false);
expect(isOfficialDropped32BitDownload('win32', 'ia32', 'v43.5.1')).toEqual(false);
expect(isOfficialDropped32BitDownload('linux', 'armv7l', 'v43.5.1')).toEqual(false);
expect(isOfficialDropped32BitDownload('linux', 'armv7l', 'v2.0.9')).toEqual(false);
});

it('should be true for nightlies from v45.0.0-nightly.20260714 onward', () => {
expect(isOfficialDropped32BitDownload('win32', 'ia32', 'v45.0.0-nightly.20260714')).toEqual(
true,
);
expect(isOfficialDropped32BitDownload('linux', 'armv7l', 'v45.0.0-nightly.20260714')).toEqual(
true,
);
expect(isOfficialDropped32BitDownload('win32', 'ia32', 'v46.0.0-nightly.20270101')).toEqual(
true,
);
});

it('should be false for nightlies that still shipped 32-bit builds', () => {
expect(isOfficialDropped32BitDownload('win32', 'ia32', 'v44.0.0-nightly.20260501')).toEqual(
false,
);
expect(isOfficialDropped32BitDownload('win32', 'ia32', 'v45.0.0-nightly.20260713')).toEqual(
false,
);
expect(isOfficialDropped32BitDownload('linux', 'armv7l', 'v45.0.0-nightly.20260713')).toEqual(
false,
);
});

it('should be false if mirrorOptions specified', () => {
expect(
isOfficialDropped32BitDownload('win32', 'ia32', 'v44.0.0', { mirror: 'mymirror' }),
).toEqual(false);
expect(
isOfficialDropped32BitDownload('linux', 'armv7l', 'v44.0.0', { mirror: 'mymirror' }),
).toEqual(false);
});

it('should be false for platform/arch combinations that were never dropped', () => {
expect(isOfficialDropped32BitDownload('linux', 'ia32', 'v44.0.0')).toEqual(false);
expect(isOfficialDropped32BitDownload('win32', 'armv7l', 'v44.0.0')).toEqual(false);
expect(isOfficialDropped32BitDownload('win32', 'x64', 'v44.0.0')).toEqual(false);
expect(isOfficialDropped32BitDownload('darwin', 'arm64', 'v44.0.0')).toEqual(false);
});

it('should be false for unparseable versions', () => {
expect(isOfficialDropped32BitDownload('win32', 'ia32', 'vnot-a-version')).toEqual(false);
});
});

describe('getEnv()', () => {
const [prefix, envName] = ['TeSt_EnV_vAr_', 'eNv_Key'];
const prefixEnvName = `${prefix}${envName}`;
Expand Down