Makelore 2.0 initial clean snapshot
This commit is contained in:
216
scripts/after-pack.cjs
Normal file
216
scripts/after-pack.cjs
Normal file
@@ -0,0 +1,216 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user