Files
shd.build/scripts/environment-bootstrap-export.mjs
jb dd84dff055
Validate and deploy production / validate (push) Successful in 23s
Validate and deploy staging / validate (push) Successful in 50s
Validate and deploy production / deploy (push) Failing after 40s
Validate and deploy staging / deploy (push) Failing after 7s
feat: add community publishing and news syndication
2026-08-01 21:42:09 -04:00

86 lines
2.5 KiB
JavaScript

import { spawnSync } from 'node:child_process';
import { mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises';
import { dirname, join, resolve } from 'node:path';
import process from 'node:process';
const target = process.argv[2];
if (!['staging', 'production'].includes(target)) {
console.error(
'Usage: node scripts/environment-bootstrap-export.mjs <staging|production> [output.json]',
);
process.exit(2);
}
const outputArgument = process.argv[3];
const timestamp = new Date()
.toISOString()
.replaceAll(':', '-')
.replace(/\.\d{3}Z$/, 'Z');
const outputPath = resolve(
outputArgument || `./data/backups/shd-${target}-bootstrap-${timestamp}.json`,
);
const temporaryBackupPath = `${outputPath}.database.json`;
const databaseBackup = spawnSync(
process.execPath,
['scripts/db-backup.mjs', temporaryBackupPath],
{
cwd: process.cwd(),
stdio: 'inherit',
env: process.env,
},
);
if (databaseBackup.error) throw databaseBackup.error;
if (databaseBackup.status !== 0)
throw new Error(
`Database backup failed; no ${target} bootstrap bundle was created.`,
);
async function collectFiles(directory, pattern) {
try {
const names = (await readdir(directory))
.filter((name) => pattern.test(name))
.sort();
return await Promise.all(
names.map(async (name) => ({
name,
contentBase64: (await readFile(join(directory, name))).toString(
'base64',
),
})),
);
} catch (error) {
if (error?.code === 'ENOENT') return [];
throw error;
}
}
try {
const database = JSON.parse(await readFile(temporaryBackupPath, 'utf8'));
const avatars = await collectFiles(
resolve(process.env.TDR_AVATAR_STORAGE_PATH || './data/avatars'),
/^[0-9a-f-]{36}\.webp$/i,
);
const gameIcons = await collectFiles(
resolve(process.env.TDR_GAME_ICON_STORAGE_PATH || './data/game-icons'),
/^[a-z_]+-[0-9a-f-]{36}\.webp$/i,
);
const bundle = {
format: 'shd-build-environment-bootstrap',
version: 1,
target,
createdAt: new Date().toISOString(),
database,
files: { avatars, gameIcons },
};
await mkdir(dirname(outputPath), { recursive: true });
await writeFile(outputPath, `${JSON.stringify(bundle, null, 2)}\n`, {
encoding: 'utf8',
flag: 'wx',
});
console.log(
`${target} bootstrap bundle includes ${avatars.length} avatars and ${gameIcons.length} managed image assets.`,
);
console.log(`Bootstrap bundle: ${outputPath}`);
} finally {
await rm(temporaryBackupPath, { force: true });
}