mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 04:55:42 +09:00
fix(desktop): stop requiring the removed win-toast at startup (#3345)
This commit is contained in:
1 parent
cadf7ea532
commit
48a19dedd8
4 files changed
+203
-109
No files matched your search
@@ -1074,11 +1074,91 @@ async function verifyLinuxGlibcCompatibility(context) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const NATIVE_MODULE_PREFLIGHT_MODULES = require('./src/main/NativeModulePreflightModules.json');
|
||||||
|
|
||||||
|
function packagedResourcesDir(context) {
|
||||||
|
if (context.electronPlatformName === 'darwin' || context.electronPlatformName === 'mas') {
|
||||||
|
return path.join(context.appOutDir, `${context.packager.appInfo.productFilename}.app`, 'Contents', 'Resources');
|
||||||
|
}
|
||||||
|
return path.join(context.appOutDir, 'resources');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function readAsarFileList(asarPath) {
|
||||||
|
const handle = await fs.open(asarPath, 'r');
|
||||||
|
try {
|
||||||
|
const prefix = Buffer.alloc(16);
|
||||||
|
await handle.read(prefix, 0, 16, 0);
|
||||||
|
const header = Buffer.alloc(prefix.readUInt32LE(12));
|
||||||
|
await handle.read(header, 0, header.length, 16);
|
||||||
|
const files = new Set();
|
||||||
|
const walk = (node, prefixPath) => {
|
||||||
|
for (const [name, child] of Object.entries(node.files ?? {})) {
|
||||||
|
const childPath = prefixPath ? `${prefixPath}/${name}` : name;
|
||||||
|
if (child.files) walk(child, childPath);
|
||||||
|
else files.add(childPath);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
walk(JSON.parse(header.toString('utf8')), '');
|
||||||
|
return files;
|
||||||
|
} finally {
|
||||||
|
await handle.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function verifyPreflightModulesPackaged(context) {
|
||||||
|
const platform = context.electronPlatformName === 'mas' ? 'darwin' : context.electronPlatformName;
|
||||||
|
const asarPath = path.join(packagedResourcesDir(context), 'app.asar');
|
||||||
|
const files = await readAsarFileList(asarPath);
|
||||||
|
const missing = [];
|
||||||
|
for (const spec of NATIVE_MODULE_PREFLIGHT_MODULES) {
|
||||||
|
if (!spec.platforms.includes(platform)) continue;
|
||||||
|
const manifestPath = `node_modules/${spec.name}/package.json`;
|
||||||
|
if (!files.has(manifestPath)) {
|
||||||
|
missing.push(spec.name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const manifest = JSON.parse((await readAsarEntry(asarPath, manifestPath)).toString('utf8'));
|
||||||
|
const entry = path.posix.normalize(`node_modules/${spec.name}/${manifest.main ?? 'index.js'}`);
|
||||||
|
if (!files.has(entry)) {
|
||||||
|
missing.push(`${spec.name} (${entry})`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (missing.length > 0) {
|
||||||
|
throw new Error(
|
||||||
|
[
|
||||||
|
`The packaged app for ${platform} is missing native module(s) that the startup preflight requires:`,
|
||||||
|
...missing.map((entry) => ` - ${entry}`),
|
||||||
|
'Package them or remove them from src/main/NativeModulePreflightModules.json.',
|
||||||
|
].join('\n'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function readAsarEntry(asarPath, entryPath) {
|
||||||
|
const handle = await fs.open(asarPath, 'r');
|
||||||
|
try {
|
||||||
|
const prefix = Buffer.alloc(16);
|
||||||
|
await handle.read(prefix, 0, 16, 0);
|
||||||
|
const headerSize = prefix.readUInt32LE(4);
|
||||||
|
const header = Buffer.alloc(prefix.readUInt32LE(12));
|
||||||
|
await handle.read(header, 0, header.length, 16);
|
||||||
|
let node = JSON.parse(header.toString('utf8'));
|
||||||
|
for (const part of entryPath.split('/')) node = node.files[part];
|
||||||
|
if (node.unpacked) return await fs.readFile(path.join(`${asarPath}.unpacked`, ...entryPath.split('/')));
|
||||||
|
const data = Buffer.alloc(node.size);
|
||||||
|
await handle.read(data, 0, node.size, 8 + headerSize + Number(node.offset));
|
||||||
|
return data;
|
||||||
|
} finally {
|
||||||
|
await handle.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function afterPack(context) {
|
async function afterPack(context) {
|
||||||
await copyMissingPackagedNativeArtifacts(context);
|
await copyMissingPackagedNativeArtifacts(context);
|
||||||
await cleanupNativeBuildIntermediates(context);
|
await cleanupNativeBuildIntermediates(context);
|
||||||
await addLinuxLegacyBinarySymlink(context);
|
await addLinuxLegacyBinarySymlink(context);
|
||||||
await verifyPackagedNativeArtifacts(context);
|
await verifyPackagedNativeArtifacts(context);
|
||||||
|
await verifyPreflightModulesPackaged(context);
|
||||||
await verifyLinuxGlibcCompatibility(context);
|
await verifyLinuxGlibcCompatibility(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,9 @@ function loadPreflight({
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (specifier === '@electron/main/NativeModulePreflightModules.json') {
|
||||||
|
return JSON.parse(readFileSync(new URL('./NativeModulePreflightModules.json', import.meta.url), 'utf8'));
|
||||||
|
}
|
||||||
if (specifier === '@electron/main/AppStoreNativeBoundary') return {APP_STORE_ADDON_PACKAGE: '@fluxer/app-store'};
|
if (specifier === '@electron/main/AppStoreNativeBoundary') return {APP_STORE_ADDON_PACKAGE: '@fluxer/app-store'};
|
||||||
if (specifier === '@electron/main/GatewaySocketNativeBoundary') {
|
if (specifier === '@electron/main/GatewaySocketNativeBoundary') {
|
||||||
return {GATEWAY_SOCKET_ADDON_PACKAGE: '@fluxer/gateway-socket'};
|
return {GATEWAY_SOCKET_ADDON_PACKAGE: '@fluxer/gateway-socket'};
|
||||||
@@ -166,3 +169,13 @@ describe('NativeModulePreflight', () => {
|
|||||||
assert.equal(preflight.spawns.length, 1);
|
assert.equal(preflight.spawns.length, 1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('every module the preflight requires is a dependency of the desktop app', () => {
|
||||||
|
const modules = JSON.parse(readFileSync(new URL('./NativeModulePreflightModules.json', import.meta.url), 'utf8'));
|
||||||
|
const manifest = JSON.parse(readFileSync(new URL('../../package.json', import.meta.url), 'utf8'));
|
||||||
|
const dependencies = {...manifest.dependencies, ...manifest.optionalDependencies};
|
||||||
|
assert.deepEqual(
|
||||||
|
modules.map((spec) => spec.name).filter((name) => !Object.hasOwn(dependencies, name)),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
});
|
||||||
@@ -5,8 +5,7 @@ import {createHash} from 'node:crypto';
|
|||||||
import {existsSync, mkdirSync, readFileSync, writeFileSync} from 'node:fs';
|
import {existsSync, mkdirSync, readFileSync, writeFileSync} from 'node:fs';
|
||||||
import {createRequire} from 'node:module';
|
import {createRequire} from 'node:module';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import {APP_STORE_ADDON_PACKAGE} from '@electron/main/AppStoreNativeBoundary';
|
import NATIVE_MODULE_PREFLIGHT_MODULES from '@electron/main/NativeModulePreflightModules.json';
|
||||||
import {GATEWAY_SOCKET_ADDON_PACKAGE} from '@electron/main/GatewaySocketNativeBoundary';
|
|
||||||
import {app} from 'electron';
|
import {app} from 'electron';
|
||||||
import log from 'electron-log';
|
import log from 'electron-log';
|
||||||
|
|
||||||
@@ -43,113 +42,13 @@ export interface NativeModulePreflightResult {
|
|||||||
readonly degraded: ReadonlyArray<string>;
|
readonly degraded: ReadonlyArray<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const NATIVE_MODULE_PREFLIGHT_SPECS: ReadonlyArray<NativeModulePreflightSpec> = [
|
const NATIVE_MODULE_PREFLIGHT_SPECS: ReadonlyArray<NativeModulePreflightSpec> = NATIVE_MODULE_PREFLIGHT_MODULES.map(
|
||||||
{
|
(spec) => ({
|
||||||
name: '@fluxer/webauthn',
|
name: spec.name,
|
||||||
platforms: new Set(['darwin', 'linux', 'win32']),
|
platforms: new Set(spec.platforms as ReadonlyArray<NodeJS.Platform>),
|
||||||
severity: 'fatal',
|
severity: spec.severity as NativeModuleSeverity,
|
||||||
},
|
}),
|
||||||
{
|
);
|
||||||
name: '@fluxer/platform-info',
|
|
||||||
platforms: new Set(['darwin', 'linux', 'win32']),
|
|
||||||
severity: 'fatal',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '@fluxer/mac-app-audio',
|
|
||||||
platforms: new Set(['darwin']),
|
|
||||||
severity: 'fatal',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '@fluxer/mac-clipboard',
|
|
||||||
platforms: new Set(['darwin']),
|
|
||||||
severity: 'fatal',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '@fluxer/mac-sysctl',
|
|
||||||
platforms: new Set(['darwin']),
|
|
||||||
severity: 'fatal',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '@fluxer/mac-tcc',
|
|
||||||
platforms: new Set(['darwin']),
|
|
||||||
severity: 'fatal',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '@fluxer/macos-input-hook',
|
|
||||||
platforms: new Set(['darwin']),
|
|
||||||
severity: 'fatal',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '@fluxer/linux-audio-capture',
|
|
||||||
platforms: new Set(['linux']),
|
|
||||||
severity: 'fatal',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '@fluxer/linux-evdev',
|
|
||||||
platforms: new Set(['linux']),
|
|
||||||
severity: 'fatal',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '@fluxer/linux-input-hook',
|
|
||||||
platforms: new Set(['linux']),
|
|
||||||
severity: 'fatal',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '@fluxer/linux-notifications',
|
|
||||||
platforms: new Set(['linux']),
|
|
||||||
severity: 'fatal',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '@fluxer/linux-portals',
|
|
||||||
platforms: new Set(['linux']),
|
|
||||||
severity: 'fatal',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '@fluxer/linux-screen-capture',
|
|
||||||
platforms: new Set(['linux']),
|
|
||||||
severity: 'fatal',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '@fluxer/system-hunspell',
|
|
||||||
platforms: new Set(['linux']),
|
|
||||||
severity: 'fatal',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '@fluxer/win-clipboard',
|
|
||||||
platforms: new Set(['win32']),
|
|
||||||
severity: 'fatal',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '@fluxer/win-process-loopback',
|
|
||||||
platforms: new Set(['win32']),
|
|
||||||
severity: 'fatal',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '@fluxer/win-shell',
|
|
||||||
platforms: new Set(['win32']),
|
|
||||||
severity: 'fatal',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '@fluxer/win-toast',
|
|
||||||
platforms: new Set(['win32']),
|
|
||||||
severity: 'fatal',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '@fluxer/windows-input-hook',
|
|
||||||
platforms: new Set(['win32']),
|
|
||||||
severity: 'fatal',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: APP_STORE_ADDON_PACKAGE,
|
|
||||||
platforms: new Set(['darwin', 'linux', 'win32']),
|
|
||||||
severity: 'degraded',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: GATEWAY_SOCKET_ADDON_PACKAGE,
|
|
||||||
platforms: new Set(['darwin', 'linux', 'win32']),
|
|
||||||
severity: 'degraded',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const PROBE_SCRIPT = `
|
const PROBE_SCRIPT = `
|
||||||
const modulePaths = process.argv.slice(1);
|
const modulePaths = process.argv.slice(1);
|
||||||
function write(obj) {
|
function write(obj) {
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "@fluxer/webauthn",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"severity": "fatal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "@fluxer/platform-info",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"severity": "fatal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "@fluxer/mac-app-audio",
|
||||||
|
"platforms": ["darwin"],
|
||||||
|
"severity": "fatal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "@fluxer/mac-clipboard",
|
||||||
|
"platforms": ["darwin"],
|
||||||
|
"severity": "fatal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "@fluxer/mac-sysctl",
|
||||||
|
"platforms": ["darwin"],
|
||||||
|
"severity": "fatal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "@fluxer/mac-tcc",
|
||||||
|
"platforms": ["darwin"],
|
||||||
|
"severity": "fatal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "@fluxer/macos-input-hook",
|
||||||
|
"platforms": ["darwin"],
|
||||||
|
"severity": "fatal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "@fluxer/linux-audio-capture",
|
||||||
|
"platforms": ["linux"],
|
||||||
|
"severity": "fatal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "@fluxer/linux-evdev",
|
||||||
|
"platforms": ["linux"],
|
||||||
|
"severity": "fatal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "@fluxer/linux-input-hook",
|
||||||
|
"platforms": ["linux"],
|
||||||
|
"severity": "fatal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "@fluxer/linux-notifications",
|
||||||
|
"platforms": ["linux"],
|
||||||
|
"severity": "fatal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "@fluxer/linux-portals",
|
||||||
|
"platforms": ["linux"],
|
||||||
|
"severity": "fatal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "@fluxer/linux-screen-capture",
|
||||||
|
"platforms": ["linux"],
|
||||||
|
"severity": "fatal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "@fluxer/system-hunspell",
|
||||||
|
"platforms": ["linux"],
|
||||||
|
"severity": "fatal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "@fluxer/win-clipboard",
|
||||||
|
"platforms": ["win32"],
|
||||||
|
"severity": "fatal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "@fluxer/win-process-loopback",
|
||||||
|
"platforms": ["win32"],
|
||||||
|
"severity": "fatal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "@fluxer/win-shell",
|
||||||
|
"platforms": ["win32"],
|
||||||
|
"severity": "fatal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "@fluxer/windows-input-hook",
|
||||||
|
"platforms": ["win32"],
|
||||||
|
"severity": "fatal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "@fluxer/app-store",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"severity": "degraded"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "@fluxer/gateway-socket",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"severity": "degraded"
|
||||||
|
}
|
||||||
|
]
|
||||||
Reference in new issue
Block a user