import { createRequire } from 'node:module'; import { mkdirSync, writeFileSync } from 'node:fs'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; const require = createRequire(import.meta.url); const { deserialize } = require('../packages/tts/node_modules/bson'); const __dirname = dirname(fileURLToPath(import.meta.url)); const DEFAULT_MOD_ID = '2668570240'; const modId = process.argv[2] ?? DEFAULT_MOD_ID; /** * Resolve the authoritative `file_url` via the Steam Web API. The item page's * embedded `file_url` can point to a preview image instead of the save, so the * API is the reliable source. */ async function getFileUrlFromApi(id) { const params = new URLSearchParams(); params.append('itemcount', '1'); params.append('publishedfileids[0]', id); const res = await fetch( 'https://api.steampowered.com/ISteamRemoteStorage/GetPublishedFileDetails/v1/', { method: 'POST', body: params }, ); if (!res.ok) { console.log(` Steam API responded ${res.status}`); return null; } const json = await res.json(); const d = json?.response?.publishedfiledetails?.[0]; if (!d?.file_url) { console.log(' Steam API returned no file_url'); return null; } return d.file_url; } /** True if the bytes look like a BSON document whose length matches. */ function looksLikeBson(buf) { if (buf.length < 5) return false; const len = buf.readInt32LE(0); return len === buf.length; } async function main() { console.log(`Resolving file_url for mod ${modId} via Steam API...`); const fileUrl = await getFileUrlFromApi(modId); if (!fileUrl) { console.error('Could not resolve a file_url'); process.exit(1); } console.log(`file_url: ${fileUrl}`); const res = await fetch(fileUrl); if (!res.ok) { console.error(`Download failed ${res.status}`); process.exit(1); } const buf = Buffer.from(await res.arrayBuffer()); console.log(`downloaded ${buf.length} bytes`); if (!looksLikeBson(buf)) { console.error( `Not a BSON save (magic ${buf.slice(0, 4).toString('hex')})`, ); process.exit(1); } const mod = deserialize(buf); const outDir = join(__dirname, 'dumps'); mkdirSync(outDir, { recursive: true }); const outPath = join(outDir, `${modId}.json`); writeFileSync(outPath, JSON.stringify(mod, null, 2)); console.log(`wrote ${outPath}`); } main().catch((err) => { console.error(err); process.exit(1); });