217 lines
6.2 KiB
JavaScript
217 lines
6.2 KiB
JavaScript
const { execFileSync } = require('child_process');
|
|
const { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } = require('fs');
|
|
const { join } = require('path');
|
|
|
|
const MEOWA_RELEASE_CREDENTIAL_FILE_NAME = 'meowa-game-assets-credential.json';
|
|
|
|
exports.default = async function afterPack(context) {
|
|
const platform = context.electronPlatformName;
|
|
console.log(`[after-pack] Target: ${platform}/${context.arch}`);
|
|
|
|
writeMeowaReleaseCredential(context);
|
|
assertNoPersistedUserData(context.appOutDir);
|
|
|
|
if (platform !== 'win32') {
|
|
return;
|
|
}
|
|
|
|
patchWindowsExecutableResources(context);
|
|
patchNsisExtractionMacro();
|
|
};
|
|
|
|
function writeMeowaReleaseCredential(context) {
|
|
const apiKey = process.env.MEOWART_API_KEY?.trim();
|
|
if (!apiKey) {
|
|
console.log('[after-pack] Meowa release credential not included; MEOWART_API_KEY is unset.');
|
|
return false;
|
|
}
|
|
|
|
const resourcesDir = context.packager.getResourcesDir(context.appOutDir);
|
|
const target = join(resourcesDir, 'resources', MEOWA_RELEASE_CREDENTIAL_FILE_NAME);
|
|
mkdirSync(join(resourcesDir, 'resources'), { recursive: true });
|
|
writeFileSync(
|
|
target,
|
|
`${JSON.stringify({ schemaVersion: 1, apiKey })}\n`,
|
|
{ encoding: 'utf8', mode: 0o600 },
|
|
);
|
|
console.log('[after-pack] Meowa release credential included in packaged Main resources.');
|
|
return true;
|
|
}
|
|
|
|
const PERSISTED_USER_DATA_FILES = new Set([
|
|
'gateway-prelaunch-maintenance-cache.json',
|
|
'niancode-device-identity.json',
|
|
'niancode-providers.json',
|
|
'opencode-projects.json',
|
|
'settings.json',
|
|
]);
|
|
|
|
function assertNoPersistedUserData(appOutDir) {
|
|
const offenders = [];
|
|
collectPersistedUserDataFiles(appOutDir, offenders);
|
|
|
|
if (offenders.length > 0) {
|
|
throw new Error(
|
|
[
|
|
'Persisted Makelore user data must not be packaged.',
|
|
'Remove these files from the package input:',
|
|
...offenders.map((file) => `- ${file}`),
|
|
].join('\n'),
|
|
);
|
|
}
|
|
}
|
|
|
|
function collectPersistedUserDataFiles(dir, offenders) {
|
|
if (!existsSync(dir)) return;
|
|
|
|
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
const path = join(dir, entry.name);
|
|
if (entry.isDirectory()) {
|
|
collectPersistedUserDataFiles(path, offenders);
|
|
continue;
|
|
}
|
|
|
|
if (entry.isFile() && PERSISTED_USER_DATA_FILES.has(entry.name)) {
|
|
offenders.push(path);
|
|
}
|
|
}
|
|
}
|
|
|
|
function patchWindowsExecutableResources(context) {
|
|
const rcedit = findRcedit();
|
|
if (!rcedit) {
|
|
console.log('[after-pack] rcedit-x64.exe not found; skipping executable resource patch.');
|
|
return;
|
|
}
|
|
|
|
const appInfo = context.packager.appInfo;
|
|
const executable = join(context.appOutDir, `${appInfo.productFilename}.exe`);
|
|
if (!existsSync(executable)) {
|
|
console.log(`[after-pack] ${appInfo.productFilename}.exe not found; skipping executable resource patch.`);
|
|
return;
|
|
}
|
|
|
|
const icon = join(context.packager.info.buildResourcesDir, 'icons', 'icon.ico');
|
|
const version = typeof appInfo.getVersionInWeirdWindowsForm === 'function'
|
|
? appInfo.getVersionInWeirdWindowsForm()
|
|
: normalizeWindowsVersion(appInfo.version);
|
|
|
|
const args = [
|
|
executable,
|
|
'--set-version-string',
|
|
'FileDescription',
|
|
appInfo.productName,
|
|
'--set-version-string',
|
|
'ProductName',
|
|
appInfo.productName,
|
|
'--set-version-string',
|
|
'LegalCopyright',
|
|
appInfo.copyright,
|
|
'--set-file-version',
|
|
version,
|
|
'--set-product-version',
|
|
version,
|
|
'--set-version-string',
|
|
'InternalName',
|
|
appInfo.productFilename,
|
|
'--set-version-string',
|
|
'OriginalFilename',
|
|
'',
|
|
];
|
|
|
|
if (existsSync(icon)) {
|
|
args.push('--set-icon', icon);
|
|
}
|
|
|
|
execFileSync(rcedit, args, { stdio: 'inherit' });
|
|
console.log(`[after-pack] Patched ${appInfo.productFilename}.exe resources with ${appInfo.productName}.`);
|
|
}
|
|
|
|
function normalizeWindowsVersion(version) {
|
|
const parts = String(version ?? '0.0.0')
|
|
.split('.')
|
|
.map((part) => Number.parseInt(part, 10))
|
|
.filter((part) => Number.isFinite(part));
|
|
|
|
while (parts.length < 4) parts.push(0);
|
|
return parts.slice(0, 4).join('.');
|
|
}
|
|
|
|
function findRcedit() {
|
|
const explicitDir = process.env.ELECTRON_BUILDER_RCEDIT_PATH;
|
|
if (explicitDir) {
|
|
const explicit = join(explicitDir, 'rcedit-x64.exe');
|
|
if (existsSync(explicit)) return explicit;
|
|
}
|
|
|
|
const cacheRoots = [
|
|
process.env.ELECTRON_BUILDER_CACHE,
|
|
process.env.LOCALAPPDATA ? join(process.env.LOCALAPPDATA, 'electron-builder', 'Cache') : null,
|
|
join(__dirname, '..', '.cache', 'electron-builder', 'Cache'),
|
|
].filter(Boolean);
|
|
|
|
for (const root of cacheRoots) {
|
|
const winCodeSign = join(root, 'winCodeSign');
|
|
const found = findRceditInWinCodeSignCache(winCodeSign);
|
|
if (found) return found;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function findRceditInWinCodeSignCache(winCodeSign) {
|
|
if (!existsSync(winCodeSign)) return null;
|
|
|
|
for (const entry of readdirSync(winCodeSign)) {
|
|
const candidate = join(winCodeSign, entry, 'rcedit-x64.exe');
|
|
if (!existsSync(candidate)) continue;
|
|
if (!statSync(candidate).isFile()) continue;
|
|
return candidate;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function patchNsisExtractionMacro() {
|
|
const extractNsh = join(
|
|
__dirname,
|
|
'..',
|
|
'node_modules',
|
|
'app-builder-lib',
|
|
'templates',
|
|
'nsis',
|
|
'include',
|
|
'extractAppPackage.nsh',
|
|
);
|
|
|
|
if (!existsSync(extractNsh)) {
|
|
console.log('[after-pack] NSIS extractAppPackage.nsh not found; skipping patch.');
|
|
return;
|
|
}
|
|
|
|
const original = readFileSync(extractNsh, 'utf8');
|
|
if (original.includes('Makelore-patched')) {
|
|
console.log('[after-pack] NSIS extractAppPackage.nsh already patched.');
|
|
return;
|
|
}
|
|
|
|
const replacement = [
|
|
'!macro extractUsing7za file',
|
|
' ; Makelore-patched: extract directly to $INSTDIR.',
|
|
' Nsis7z::Extract "$PLUGINSDIR\\\\${file}" "$INSTDIR"',
|
|
'!macroend',
|
|
].join('\n');
|
|
|
|
const patched = original.replace(/!macro extractUsing7za file[\s\S]*?!macroend/, replacement);
|
|
if (patched === original) {
|
|
console.log('[after-pack] NSIS extractUsing7za macro not found; skipping patch.');
|
|
return;
|
|
}
|
|
|
|
writeFileSync(extractNsh, patched, 'utf8');
|
|
console.log('[after-pack] Patched NSIS extractAppPackage.nsh for direct extraction.');
|
|
}
|
|
|
|
exports.assertNoPersistedUserData = assertNoPersistedUserData;
|
|
exports.writeMeowaReleaseCredential = writeMeowaReleaseCredential;
|