import { join } from 'path' import { existsSync } from 'fs' import { mkdir, writeFile, readFile, unlink, rm } from 'fs/promises' import { TMP_DIR } from '@/lib/constants' import { compressWithBlender } from '@/lib/blender' import { compressTextureBuffer } from '@/lib/texture-compression' import { classifyAssetCategory } from '@/lib/asset-classification' import type { ParsedFile, PreparedAssetSummary } from '@/lib/types' interface PushFile { path: string contentBase64: string } interface PrepareGitAssetsParams { folderName: string parsedFiles: ParsedFile[] } interface PrepareGitAssetsResult { filesToPush: PushFile[] modelFilename: string assetSummaries: PreparedAssetSummary[] compressed: boolean compressionError?: string } export async function prepareGitAssets({ folderName, parsedFiles, }: PrepareGitAssetsParams): Promise { const filesToPush: PushFile[] = [] const assetSummaries: PreparedAssetSummary[] = [] let modelFilename = '' let compressed = false let compressionError: string | undefined for (const pf of parsedFiles) { let content = pf.buffer if (pf.isModel) { modelFilename = pf.filename let modelCompressed = false const tmpFolder = join(TMP_DIR, folderName) await mkdir(tmpFolder, { recursive: true }) const tmpFilePath = join(tmpFolder, pf.filename) await writeFile(tmpFilePath, pf.buffer) const stem = pf.filename.replace(/\.[^.]+$/, '') const compressedPath = join(tmpFolder, `${stem}_compressed.glb`) try { const result = await compressWithBlender(tmpFilePath, compressedPath) if (result.success && existsSync(compressedPath)) { content = await readFile(compressedPath) compressed = true modelCompressed = true await unlink(compressedPath).catch(() => {}) } else { compressionError = result.error } } finally { await unlink(tmpFilePath).catch(() => {}) await rm(tmpFolder, { recursive: true, force: true }).catch(() => {}) } assetSummaries.push({ filename: pf.filename, kind: 'model', compressed: modelCompressed, }) } else { const category = classifyAssetCategory(pf.filename) const textureResult = await compressTextureBuffer(pf.filename, pf.buffer) content = textureResult.buffer if (textureResult.error && !compressionError) { compressionError = textureResult.error } assetSummaries.push({ filename: pf.filename, kind: category === 'assets' ? 'asset' : 'texture', category, compressed: textureResult.compressed, }) } filesToPush.push({ path: `public/models/${folderName}/${pf.filename}`, contentBase64: content.toString('base64'), }) } return { filesToPush, modelFilename, assetSummaries, compressed, compressionError, } }