import { zipSync, unzipSync, strToU8 } from "fflate"; import { gameArchive, readBytes } from "./archive.ts"; import type { Project } from "./schema.ts"; import { normalizeOptions } from "../native/options.mjs"; export async function buildKit( project: Project, raw: unknown, read = readBytes, ) { const options = normalizeOptions(raw as any); const game = unzipSync(await gameArchive(project, read)); const files: Record = {}; for (const [name, data] of Object.entries(game)) files["native/game/" + name] = data; const manifest = JSON.parse( new TextDecoder().decode(await read("/build-targets/manifest.json")), ) as string[]; for (const name of manifest) { if ( !/^[a-zA-Z0-9_./-]+$/.test(name) || name.includes("..") || name.startsWith("/") ) throw Error("Invalid build template path"); files["native/" + name] = await read("/build-targets/" + name); } files["native/build-config.json"] = strToU8(JSON.stringify(options, null, 2)); files["README.txt"] = strToU8( "Forma Engine 0.2 — application build kit\n\nThis archive contains your game and a real build toolchain configuration. It is NOT an executable application yet.\n\nLinux / Windows desktop:\n npm ci --prefix native\n node native/build.mjs\n\nAndroid (Linux build host, JDK 17 + curl + unzip required):\n node native/setup-android.mjs\n node native/build.mjs\n\nCheck prerequisites: node native/build.mjs --doctor\nBuild output: native/output//artifacts/\n\nFirst setup/build needs Internet to download toolchains. Finished games are offline.\nFor release APK set FORMA_KEYSTORE, FORMA_KEYSTORE_PASSWORD, FORMA_KEY_ALIAS, FORMA_KEY_PASSWORD in the build environment. Keep the signing key for future updates. Never put secrets in build-config.json.\nWindows EXE is unsigned. Linux AppImage requires working Chromium sandbox/user namespaces.\n\nProject revision: " + project.revision + "\n", ); return zipSync(files, { level: 6 }); }