import { createHash } from "node:crypto"; import { existsSync, readFileSync, readdirSync, statSync } from "node:fs"; import { homedir } from "node:os"; import { basename, extname, isAbsolute, join, relative, resolve, sep } from "node:path"; import { WP4_07_REAL_RESOURCE_VERSIONS } from "./wp4-07-fixture.mjs"; const dynamicFontTemplates = Object.freeze({ "15974853bc3294ef68e7e6d58fe74fd7": "DYN002", "46f8336813e4c48d06a1aef294fdccf6": "DYN016", "53ca6b704728520da50c145eabb2e635": "DYN007", cca5efc0e02fb1bf62349bd68ef30fc1: "DYN015", dd25b35dcb7ba4476cbaa9a9592e39e2: "DYN001", e4210c9872f0c279b35273f230809821: "DYN011", f4bfd4132df2d6be97ceabadf3853505: "DYN008", }); const dynamicImages = Object.freeze({ "DYN001-image28": ["DYN001", "image28.png"], "DYN002-image29": ["DYN002", "image29.png"], "DYN003-image30": ["DYN003", "image30.png"], "DYN004-image32": ["DYN004", "image32.png"], "DYN008-backendui0": ["DYN008", "backendui0.png"], "DYN011-backendui0": ["DYN011", "backendui0.png"], "DYN015-imager2": ["DYN015", "imager2_2.png"], "DYN016-image21": ["DYN016", "image21.png"], }); function sha256(path) { return createHash("sha256").update(readFileSync(path)).digest("hex").toUpperCase(); } function walkFiles(directory) { return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => { const path = join(directory, entry.name); return entry.isDirectory() ? walkFiles(path) : [path]; }); } function firstFile(directory, predicate) { const path = walkFiles(directory).find(predicate); if (!path) throw new Error(`WP4_07_REAL_ASSET_FILE_MISSING:${basename(directory)}`); return path; } function inside(root, path) { const delta = relative(resolve(root), resolve(path)); return delta !== ".." && !delta.startsWith(`..${sep}`) && !isAbsolute(delta); } function contentType(path) { const extension = extname(path).toLowerCase(); if (extension === ".png") return "image/png"; if (extension === ".otf") return "font/otf"; if (extension === ".woff") return "font/woff"; if (extension === ".woff2") return "font/woff2"; return "font/ttf"; } function assetRecord(assetId, path, sourceReference, expectedSha256) { if (!existsSync(path) || !statSync(path).isFile()) throw new Error(`WP4_07_REAL_ASSET_UNAVAILABLE:${assetId}`); const actualSha256 = sha256(path); if (expectedSha256 && actualSha256 !== expectedSha256) throw new Error(`WP4_07_REAL_ASSET_HASH_MISMATCH:${assetId}`); return { asset_id: assetId, bytes: statSync(path).size, content_type: contentType(path), path, sha256: actualSha256, source_reference: sourceReference, }; } export function loadWp407RealAssets() { const manifestPath = resolve(process.env.DADA_WP4_07_FINAL_ASSET_MANIFEST ?? ""); if (!process.env.DADA_WP4_07_FINAL_ASSET_MANIFEST || !existsSync(manifestPath)) throw new Error("WP4_07_FINAL_ASSET_MANIFEST_REQUIRED"); const handoffPath = resolve(process.env.DADA_COMPLEX_ASSET_MANIFEST ?? join(homedir(), "Desktop", "sticker_web_handoff", "sticker_web_catalog_manifest.json")); const staticRoot = resolve(process.env.DADA_STATIC_STICKER_ROOT ?? join(homedir(), "Desktop", "贴纸素材")); const backgroundPath = resolve(process.env.DADA_WP4_07_BACKGROUND_PATH ?? join(homedir(), "Documents", "贴纸脚本", "time_01_input_20260716.png")); if (!existsSync(handoffPath) || !existsSync(staticRoot)) throw new Error("WP4_07_REAL_ARCHIVE_ROOT_REQUIRED"); const manifestRaw = readFileSync(manifestPath, "utf8"); const manifest = JSON.parse(manifestRaw); const handoff = JSON.parse(readFileSync(handoffPath, "utf8")); const collectionRoots = Object.fromEntries(handoff.collections.map((collection) => [collection.id, resolve(collection.root)])); const fontRoot = collectionRoots.font_panel; const dynamicRoot = collectionRoots.interactive_stickers; if (!fontRoot || !dynamicRoot) throw new Error("WP4_07_REAL_ARCHIVE_COLLECTION_REQUIRED"); const publicAssets = new Map(); for (const item of manifest.assets.font_panel_items) { const packageDirectory = resolve(fontRoot, item.canonical_resource_reference.path); if (!inside(fontRoot, packageDirectory)) throw new Error(`WP4_07_UNSAFE_FONT_REFERENCE:${item.canonical_id}`); const path = firstFile(resolve(packageDirectory, "font_files"), (candidate) => /\.(?:otf|ttf|woff2?|ztf)$/i.test(candidate)); publicAssets.set(item.canonical_id, assetRecord(item.canonical_id, path, `font_panel/${item.canonical_id}/${basename(path)}`)); } for (const item of manifest.assets.static_stickers) { const path = resolve(staticRoot, item.relative_path); if (!inside(staticRoot, path)) throw new Error(`WP4_07_UNSAFE_STATIC_REFERENCE:${item.stable_id}`); publicAssets.set(item.stable_id, assetRecord(item.stable_id, path, `static/${item.stable_id}`, item.sha256)); } for (const [assetId, templateId] of Object.entries(dynamicFontTemplates)) { const directory = resolve(dynamicRoot, "templates", templateId, "fonts", assetId); const path = firstFile(directory, (candidate) => /\.(?:otf|ttf|woff2?|ztf)$/i.test(candidate)); publicAssets.set(assetId, assetRecord(assetId, path, `interactive/${templateId}/fonts/${assetId}/${basename(path)}`)); } for (const [assetId, [templateId, filename]] of Object.entries(dynamicImages)) { const path = resolve(dynamicRoot, "templates", templateId, "resource", filename); publicAssets.set(assetId, assetRecord(assetId, path, `interactive/${templateId}/resource/${filename}`)); } const background = assetRecord("private-background", backgroundPath, "private/background/time_01_input_20260716.png"); const manifestSha256 = createHash("sha256").update(manifestRaw).digest("hex").toUpperCase(); return { background, evidence: { asset_count: publicAssets.size, assets: [...publicAssets.values()].map(({ asset_id, bytes, content_type, sha256: hash, source_reference }) => ({ asset_id, bytes, content_type, sha256: hash, source_reference, })), background: { bytes: background.bytes, content_type: background.content_type, sha256: background.sha256, source_reference: background.source_reference }, manifest_sha256: manifestSha256, release_version: manifest.release_version, resource_versions: WP4_07_REAL_RESOURCE_VERSIONS, source_mutations: 0, }, publicAssets, }; }