Leon4gr45/builder
0
1// lib/server-generate/file-sync-handler.ts2import { vfs } from '@/lib/vfs';3import { logger } from '@/lib/utils';4 5const projectSyncState = new Map<string, { pending: Promise<void>; cancelled: boolean }>();6 7function getState(projectId: string) {8 let s = projectSyncState.get(projectId);9 if (!s) {10 s = { pending: Promise.resolve(), cancelled: false };11 projectSyncState.set(projectId, s);12 }13 return s;14}15 16export function cancelPendingFileSync(projectId?: string): void {17 if (projectId) {18 const s = projectSyncState.get(projectId);19 if (s) s.cancelled = true;20 } else {21 for (const s of projectSyncState.values()) s.cancelled = true;22 }23}24 25export async function handleFilesChanged(data: { sourceProjectId: string; paths: string[]; taskId: string }): Promise<void> {26 const state = getState(data.sourceProjectId);27 state.cancelled = false;28 state.pending = state.pending.then(() => doSync(data)).catch((err) => {29 logger.warn('[file-sync] Sync error:', err);30 });31 return state.pending;32}33 34async function doSync(data: { sourceProjectId: string; paths: string[]; taskId: string }): Promise<void> {35 const state = projectSyncState.get(data.sourceProjectId);36 if (state?.cancelled) return;37 const { paths, taskId } = data;38 if (!paths?.length || !taskId) return;39 40 const response = await fetch('/api/server-generate/files', {41 method: 'POST',42 headers: { 'Content-Type': 'application/json' },43 body: JSON.stringify({ taskId, paths }),44 });45 46 if (!response.ok) return;47 48 const { files, deleted } = await response.json();49 50 // Write all files silently (no per-file DOM events or save-manager marking)51 for (const file of files) {52 const content = file.binary53 ? Uint8Array.from(atob(file.content), (c) => c.charCodeAt(0)).buffer54 : file.content;55 56 const exists = await vfs.fileExists(data.sourceProjectId, file.path);57 if (exists) {58 await vfs.updateFile(data.sourceProjectId, file.path, content, { silent: true });59 } else {60 await vfs.createFile(data.sourceProjectId, file.path, content, { silent: true });61 }62 }63 64 if (deleted?.length) {65 for (const path of deleted) {66 try {67 await vfs.deleteFile(data.sourceProjectId, path, { silent: true });68 } catch {69 // Already deleted on client70 }71 }72 }73 74 if (typeof window !== 'undefined') {75 window.dispatchEvent(new Event('filesChanged'));76 }77}78 