import * as r from './install_common.mjs'; const { e } =r; export const NAMES=['rounds.json', 'tutorial.json', 'levels.json', 'rounds_raw.json', 'levels_raw.json']; export const replace=r.replace; export function install(a){ const provenance=e.loadJSON(e.path.join(a.stage, 'provenance.json')); return r.withLock(a['launcher-root'], ()=>{ const launcher=a['launcher-root'], registryPath=e.path.join(launcher, 'client-profiles.json'), registry=e.loadJSON(registryPath), profile=registry.beta, bundle=profile.bundle_dir, runtime=profile.runtime_dir, version=profile.version, client=profile.client_dir, identity=e.loadJSON(e.path.join(bundle, 'dump/client.json')); if(e.json(identity)!==e.json(provenance.client)||identity.version!==version||!version.includes('BETA'))e.fail('Extraction is not for the installed BETA profile'); r.verify_bundle(bundle, version); r.verify_client(bundle, client, version, 'beta'); r.verify_runtime(runtime, bundle, version); for(const name of NAMES)if(r.digest(e.path.join(a.stage, name))!==provenance.outputs[name])e.fail('Extracted resource hash changed'); const proofs=new Map([...provenance.collections, provenance.node_textmap].map(p=>[p.blob, p])); for(const proof of proofs.values())if(r.digest(e.path.join(client, 'StarRail_Data', proof.blob))!==proof.blob_sha256)e.fail('Client DesignData changed after extraction'); for(const proof of provenance.catalogues)if(r.digest(e.path.join(client, proof.path))!==proof.sha256)e.fail('Installed active DesignV changed'); const token=r.token(), backup=e.path.join(launcher, '.pearl-cache/gridfight-data-backups', token), roots={ source:e.path.join(a['server-root'], 'resources/grid_fight'), bundle:e.path.join(bundle, 'server/resources/grid_fight'), runtime:e.path.join(runtime, 'resources/grid_fight') }, targets=Object.entries(roots).flatMap(([area, root])=>NAMES.map(n=>[area, e.path.join(root, n), e.path.join(a.stage, n)])); targets.push(['bundle', e.path.join(bundle, 'SHA256SUMS'), null]); const excluded=new Set(targets.map(([, p])=>p)), bundleBefore=r.snapshot(bundle, excluded), runtimeBefore=r.snapshot(e.path.join(runtime, 'resources'), excluded), binaries=Object.fromEntries(['gameserver', 'dispatch'].map(n=>[n, r.digest(e.path.join(runtime, 'zig-out/bin', n))])), registryBefore=r.digest(registryPath), liveBundle=registry.live.bundle_dir, liveBefore=r.snapshot(liveBundle, excluded); r.transaction(targets, backup, write=>{ for(const [, p, incoming]of targets)if(incoming)write(p, e.fs.readFileSync(incoming)); write(e.path.join(bundle, 'SHA256SUMS'), r.manifest(bundle)); }, ()=>{ r.verify_bundle(bundle, version); r.verify_runtime(runtime, bundle, version); for(const name of NAMES)if(new Set(Object.values(roots).map(root=>r.digest(e.path.join(root, name)))).size!==1||r.digest(e.path.join(roots.source, name))!==provenance.outputs[name])e.fail('Source/bundle/runtime resource mismatch'); if(!r.equal(r.snapshot(bundle, excluded), bundleBefore)||!r.equal(r.snapshot(e.path.join(runtime, 'resources'), excluded), runtimeBefore))e.fail('An unrelated managed resource changed'); if(!r.equal(r.snapshot(liveBundle, excluded), liveBefore)||r.digest(registryPath)!==registryBefore)e.fail('LIVE bundle or profile registry changed'); for(const [name, d]of Object.entries(binaries))if(r.digest(e.path.join(runtime, 'zig-out/bin', name))!==d)e.fail('Runtime binaries changed'); }, 'gridfight-data'); const cache=e.path.join(launcher, '.pearl-cache/gridfight-rounds', version, token); e.fs.cpSync(a.stage, cache, { recursive:true, errorOnExist:true, force:false }); const evidence=e.path.join(a['server-root'], 'tools/gridfight-extract-node/evidence/rounds'); e.fs.cpSync(e.path.join(a.stage, 'evidence'), evidence, { recursive:true }); for(const name of ['schemas.json', 'provenance.json'])r.replace(e.path.join(evidence, name), e.fs.readFileSync(e.path.join(a.stage, name))); const report={ version, token, outputs:provenance.outputs, counts:provenance.counts, backup:e.path.relative(launcher, backup), bundle_manifest_verified:true, source_bundle_runtime_match:true, beta_non_target_resources_preserved:Object.keys(runtimeBefore).length, live_bundle_files_preserved:Object.keys(liveBefore).length, runtime_binaries_preserved:true, registry_preserved:true, processes_started_or_stopped:0, gameplay_verified:false }; e.atomic_json(e.path.join(evidence, 'validation.json'), report, 2, true); e.atomic_json(e.path.join(cache, 'install.json'), report, 2, true); console.log(e.json(report)); return report; }); } export function main(){ install(e.cli(['server-root', 'launcher-root', 'stage'])); } e.runMain(import.meta.url, main);