import { existsSync } from "node:fs"; import path from "node:path"; import { siteSettings } from "@/lib/services/site-settings"; export const DEFAULT_NITRO_FILES_ROOT = path.join( /*turbopackIgnore: true*/ path.dirname(process.cwd()), "DEV", "Nitro-Files", ); export const DEFAULT_FURNI_ICON_DIR = path.join( /*turbopackIgnore: true*/ process.cwd(), "public/swf/dcr/hof_furni/icons", ); export const DEFAULT_FURNI_SWF_DIR = path.join( /*turbopackIgnore: true*/ process.cwd(), "public/swf/dcr/hof_furni/swf", ); export const DEFAULT_FURNI_NITRO_DIR = path.join( /*turbopackIgnore: true*/ process.cwd(), "public/nitro-assets/bundled/furniture", ); export interface FurniAssetDirs { swfDir: string; iconDir: string; nitroDir: string; } export interface FurniAssetWriteTargets extends FurniAssetDirs { mirrorDirs: FurniAssetDirs[]; } function normalizeDir(value: string | undefined, fallback: string): string { const raw = value?.trim() || fallback; let normalized = path.normalize(raw); const root = path.parse(normalized).root; while (normalized.length > root.length && /[\\/]$/.test(normalized)) { normalized = normalized.slice(0, -1); } return normalized; } function uniqueDirs(dirs: string[]): string[] { const seen = new Set(); const out: string[] = []; for (const dir of dirs) { const normalized = normalizeDir(dir, dir); const key = process.platform === "win32" ? normalized.toLowerCase() : normalized; if (seen.has(key)) continue; seen.add(key); out.push(normalized); } return out; } export async function getNitroFilesRoot(): Promise { const configured = (await siteSettings.get("nitro_files_root", "")) ?? ""; if (configured.trim()) return normalizeDir(configured, configured); return existsSync(/*turbopackIgnore: true*/ DEFAULT_NITRO_FILES_ROOT) ? normalizeDir(DEFAULT_NITRO_FILES_ROOT, DEFAULT_NITRO_FILES_ROOT) : ""; } function dirsFromNitroFilesRoot(root: string): FurniAssetDirs { return { swfDir: path.join(/*turbopackIgnore: true*/ root, "swf/dcr/hof_furni"), iconDir: path.join( /*turbopackIgnore: true*/ root, "swf/dcr/hof_furni/icons", ), nitroDir: path.join( /*turbopackIgnore: true*/ root, "nitro-assets/bundled/furniture", ), }; } export async function getFurniAssetDirs(): Promise { const [swfDir, iconDir, nitroDir] = await Promise.all([ siteSettings .get("furni_swf_dir", DEFAULT_FURNI_SWF_DIR) .then((v) => v ?? DEFAULT_FURNI_SWF_DIR), siteSettings .get("furni_icon_dir", DEFAULT_FURNI_ICON_DIR) .then((v) => v ?? DEFAULT_FURNI_ICON_DIR), siteSettings .get("furni_nitro_dir", DEFAULT_FURNI_NITRO_DIR) .then((v) => v ?? DEFAULT_FURNI_NITRO_DIR), ]); return { swfDir: normalizeDir(swfDir, DEFAULT_FURNI_SWF_DIR), iconDir: normalizeDir(iconDir, DEFAULT_FURNI_ICON_DIR), nitroDir: normalizeDir(nitroDir, DEFAULT_FURNI_NITRO_DIR), }; } export async function getFurniAssetWriteTargets(): Promise { const primary = await getFurniAssetDirs(); const nitroFilesRoot = await getNitroFilesRoot(); const mirrorCandidates = nitroFilesRoot ? [dirsFromNitroFilesRoot(nitroFilesRoot)] : []; const primaryKey = { swfDir: process.platform === "win32" ? primary.swfDir.toLowerCase() : primary.swfDir, iconDir: process.platform === "win32" ? primary.iconDir.toLowerCase() : primary.iconDir, nitroDir: process.platform === "win32" ? primary.nitroDir.toLowerCase() : primary.nitroDir, }; const mirrorDirs = mirrorCandidates.filter((dirs) => { const swfDir = normalizeDir(dirs.swfDir, dirs.swfDir); const iconDir = normalizeDir(dirs.iconDir, dirs.iconDir); const nitroDir = normalizeDir(dirs.nitroDir, dirs.nitroDir); return ( (process.platform === "win32" ? swfDir.toLowerCase() : swfDir) !== primaryKey.swfDir || (process.platform === "win32" ? iconDir.toLowerCase() : iconDir) !== primaryKey.iconDir || (process.platform === "win32" ? nitroDir.toLowerCase() : nitroDir) !== primaryKey.nitroDir ); }); return { ...primary, mirrorDirs: mirrorDirs.map((dirs) => ({ swfDir: uniqueDirs([dirs.swfDir])[0], iconDir: uniqueDirs([dirs.iconDir])[0], nitroDir: uniqueDirs([dirs.nitroDir])[0], })), }; }