Files
shd.build/scripts/stage-bootstrap-export.mjs
T
JB 548d19d9ea
Validate and deploy staging / validate (push) Successful in 27s
Validate and deploy staging / deploy (push) Successful in 52s
Add containerized staging deployment
2026-07-26 10:31:24 -04:00

55 lines
2.1 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 outputArgument = process.argv[2];
const timestamp = new Date().toISOString().replaceAll(':', '-').replace(/\.\d{3}Z$/, 'Z');
const outputPath = resolve(outputArgument || `./data/backups/shd-stage-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 staging 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-stage-bootstrap',
version: 1,
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(`Staging bootstrap bundle includes ${avatars.length} avatars and ${gameIcons.length} game-data icons.`);
console.log(`Bootstrap bundle: ${outputPath}`);
} finally {
await rm(temporaryBackupPath, { force: true });
}