feat(launcher): bundle Bun and use it across all launchers (#243)

This commit is contained in:
2026-09-11 00:21:10 -07:00
committed by GitHub
parent fb2d1a512b
commit 016a43b804
61 changed files with 6814 additions and 294 deletions
@@ -0,0 +1,75 @@
const MANAGED_LAUNCHER_MARKER = 'SubMiner managed launcher (bundled runtime)';
function windowsBatchLiteral(value: string): string {
if (/["\r\n]/.test(value)) {
throw new Error('Launcher paths cannot contain quotes or newlines.');
}
return value.replaceAll('%', '%%');
}
function configuredAppCandidate(appPath: string | undefined): string[] {
if (!appPath) return [];
const literal = windowsBatchLiteral(appPath);
return [
`if not exist "${literal}" goto subminer_check_local_app`,
`set "SUBMINER_BINARY_PATH=${literal}"`,
'goto subminer_app_found',
];
}
// This command file stays valid across app updates. It locates the current app
// and only starts Electron in Node mode when that version's private Bun is absent.
export function windowsLauncherBootstrapContent(appPath?: string): string {
return [
'@echo off',
`rem ${MANAGED_LAUNCHER_MARKER}`,
'setlocal DisableDelayedExpansion',
'set "SUBMINER_MANAGED_LAUNCHER=1"',
'set "SUBMINER_LAUNCHER_PATH=%~f0"',
'if defined SUBMINER_BINARY_PATH goto subminer_app_found',
...configuredAppCandidate(appPath),
':subminer_check_local_app',
'if not defined LOCALAPPDATA goto subminer_check_program_files',
'if not exist "%LOCALAPPDATA%\\Programs\\SubMiner\\SubMiner.exe" goto subminer_check_program_files',
'set "SUBMINER_BINARY_PATH=%LOCALAPPDATA%\\Programs\\SubMiner\\SubMiner.exe"',
'goto subminer_app_found',
':subminer_check_program_files',
'if not defined ProgramFiles goto subminer_app_missing',
'if not exist "%ProgramFiles%\\SubMiner\\SubMiner.exe" goto subminer_app_missing',
'set "SUBMINER_BINARY_PATH=%ProgramFiles%\\SubMiner\\SubMiner.exe"',
':subminer_app_found',
'if not exist "%SUBMINER_BINARY_PATH%" goto subminer_app_missing',
'if not defined LOCALAPPDATA goto subminer_local_app_data_missing',
'for %%I in ("%SUBMINER_BINARY_PATH%") do set "SUBMINER_RESOURCES_PATH=%%~dpIresources"',
'if not exist "%SUBMINER_RESOURCES_PATH%\\launcher\\subminer.js" goto subminer_resources_missing',
'set "SUBMINER_APP_VERSION="',
'if not exist "%SUBMINER_RESOURCES_PATH%\\launcher\\version" goto subminer_resources_missing',
'set /p "SUBMINER_APP_VERSION="<"%SUBMINER_RESOURCES_PATH%\\launcher\\version"',
'if not defined SUBMINER_APP_VERSION goto subminer_resources_missing',
'set "SUBMINER_BUN_PATH=%LOCALAPPDATA%\\SubMiner\\launcher-runtime\\%SUBMINER_APP_VERSION%\\bun.exe"',
'if exist "%SUBMINER_BUN_PATH%" goto subminer_run',
'if not exist "%SUBMINER_RESOURCES_PATH%\\launcher\\prepare.cjs" goto subminer_resources_missing',
'set "ELECTRON_RUN_AS_NODE=1"',
"\"%SUBMINER_BINARY_PATH%\" -e \"const p=require('node:path');try{require(p.join(process.env.SUBMINER_RESOURCES_PATH,'launcher','prepare.cjs')).prepareLauncherRuntime({appPath:process.env.SUBMINER_BINARY_PATH,resourcesPath:process.env.SUBMINER_RESOURCES_PATH});}catch(error){console.error('Cannot prepare SubMiner launcher. Update or reinstall the SubMiner app.',error instanceof Error?error.message:String(error));process.exit(1);}\"",
'set "SUBMINER_PREPARE_EXIT=%errorlevel%"',
'set "ELECTRON_RUN_AS_NODE="',
'if not "%SUBMINER_PREPARE_EXIT%"=="0" exit /b %SUBMINER_PREPARE_EXIT%',
'if not exist "%SUBMINER_BUN_PATH%" goto subminer_prepare_missing',
':subminer_run',
'"%SUBMINER_BUN_PATH%" "%SUBMINER_RESOURCES_PATH%\\launcher\\subminer.js" %*',
'exit /b %errorlevel%',
':subminer_app_missing',
'>&2 echo SubMiner app not found. Install the app or set SUBMINER_BINARY_PATH to its executable.',
'exit /b 1',
':subminer_local_app_data_missing',
'>&2 echo LOCALAPPDATA is unavailable. SubMiner cannot locate its private launcher runtime.',
'exit /b 1',
':subminer_resources_missing',
'>&2 echo This launcher requires a SubMiner app with the included Bun runtime. Update SubMiner.',
'exit /b 1',
':subminer_prepare_missing',
'>&2 echo SubMiner did not create its private launcher runtime. Update or reinstall SubMiner.',
'exit /b 1',
'',
].join('\r\n');
}