forked from phenom/healer-man
67 lines
3.7 KiB
JavaScript
67 lines
3.7 KiB
JavaScript
import { copyFile, rm, writeFile } from "node:fs/promises";
|
|
import path from "node:path";
|
|
import {
|
|
BUNDLED_ANDROID_PACKS, DEFAULT_CONTENT_SOURCES, PROJECT_ROOT,
|
|
createContentManifest, loadCampaignDungeonPackDefinitions, scanContentSources,
|
|
} from "./publish-content.mjs";
|
|
import { prepareContentObjects } from "./content-objects.mjs";
|
|
import contentPolicy from "../../shared/content-policy.json" with { type: "json" };
|
|
|
|
export function selectBootstrapContent(files, packDefinitions) {
|
|
const manifest = createContentManifest(files, { packDefinitions });
|
|
const packs = new Map(manifest.packs.map((pack) => [pack.id, pack]));
|
|
const included = new Set();
|
|
function include(id) {
|
|
if (included.has(id)) return;
|
|
included.add(id);
|
|
for (const dependency of packs.get(id)?.dependencies ?? []) include(dependency);
|
|
}
|
|
for (const packId of BUNDLED_ANDROID_PACKS) include(packId);
|
|
return {
|
|
files: files.filter((file) => included.has(file.packId)),
|
|
packDefinitions: manifest.packs.filter((pack) => included.has(pack.id)).map((pack) => ({
|
|
...pack,
|
|
bundledOnAndroid: BUNDLED_ANDROID_PACKS.includes(pack.id),
|
|
})),
|
|
};
|
|
}
|
|
|
|
export async function prepareBootstrap(platform) {
|
|
if (!["web", "android"].includes(platform)) throw new Error(`Unknown bootstrap platform: ${platform}`);
|
|
const outputDirectory = path.resolve(PROJECT_ROOT, `.${platform}-public`);
|
|
if (path.dirname(outputDirectory) !== PROJECT_ROOT || path.basename(outputDirectory) !== `.${platform}-public`) {
|
|
throw new Error(`Refusing to replace unexpected staging directory: ${outputDirectory}`);
|
|
}
|
|
const files = await scanContentSources([
|
|
...DEFAULT_CONTENT_SOURCES,
|
|
{ directory: path.join(PROJECT_ROOT, "public/basis"), logicalPrefix: "basis" },
|
|
{ directory: path.join(PROJECT_ROOT, "public/data"), logicalPrefix: "data" },
|
|
]);
|
|
const selected = selectBootstrapContent(files, await loadCampaignDungeonPackDefinitions());
|
|
await rm(outputDirectory, { recursive: true, force: true });
|
|
const prepared = await prepareContentObjects(selected.files, {
|
|
directory: path.join(outputDirectory, "content/bundled"), baseUrl: "/content/bundled",
|
|
});
|
|
if (prepared.storedBytes > contentPolicy.maxBootstrapStoredBytes) {
|
|
throw new Error(
|
|
`Bootstrap content is ${prepared.storedBytes} bytes; the release limit is ${contentPolicy.maxBootstrapStoredBytes} bytes.`,
|
|
);
|
|
}
|
|
const manifest = createContentManifest(prepared.files, {
|
|
baseUrl: "/content/bundled", packDefinitions: selected.packDefinitions,
|
|
});
|
|
await writeFile(path.join(outputDirectory, "content/bootstrap-manifest.json"), `${JSON.stringify(manifest, null, 2)}\n`);
|
|
await copyFile(path.join(PROJECT_ROOT, "public/content-cache-sw.js"), path.join(outputDirectory, "content-cache-sw.js"));
|
|
const storage = {
|
|
logicalBytes: prepared.logicalBytes, uniqueBytes: prepared.uniqueBytes, storedBytes: prepared.storedBytes,
|
|
duplicateBytesRemoved: prepared.logicalBytes - prepared.uniqueBytes,
|
|
uniqueObjects: prepared.uniqueObjects, logicalFiles: selected.files.length,
|
|
bundledDungeons: manifest.packs.filter((pack) => pack.id.startsWith("dungeon:")).length,
|
|
bundledManastormPacks: manifest.packs.filter((pack) => pack.id.startsWith("manastorm:") && pack.bundledOnAndroid).length,
|
|
};
|
|
await writeFile(path.join(outputDirectory, "content/storage-report.json"), `${JSON.stringify(storage, null, 2)}\n`);
|
|
console.log(`Prepared ${platform} bootstrap: ${storage.bundledDungeons} dungeons, ${prepared.uniqueObjects} shared objects`);
|
|
console.log(`Original: ${storage.logicalBytes} bytes; duplicates removed: ${storage.duplicateBytesRemoved} bytes; shipped: ${storage.storedBytes} bytes`);
|
|
return { manifest, storage, outputDirectory };
|
|
}
|