( chatIds: string[], label: string )
| 182 | * await cleanup.execute() |
| 183 | */ |
| 184 | export async function prepareChatCleanup( |
| 185 | chatIds: string[], |
| 186 | label: string |
| 187 | ): Promise<{ execute: () => Promise<void> }> { |
| 188 | // Collect file refs BEFORE DB deletion (keys + context are lost after cascade) |
| 189 | const files = await collectChatFiles(chatIds) |
| 190 | if (files.length > 0) { |
| 191 | logger.info(`[${label}] Collected ${files.length} files for cleanup`, { |
| 192 | files: files.map((f) => ({ key: f.key, context: f.context })), |
| 193 | }) |
| 194 | } |
| 195 | |
| 196 | return { |
| 197 | execute: async () => { |
| 198 | // Call copilot backend |
| 199 | if (chatIds.length > 0) { |
| 200 | const copilotResult = await cleanupCopilotBackend(chatIds, label) |
| 201 | logger.info( |
| 202 | `[${label}] Copilot backend: ${copilotResult.deleted} deleted, ${copilotResult.failed} failed` |
| 203 | ) |
| 204 | } |
| 205 | |
| 206 | // Delete storage files with correct context per file |
| 207 | if (files.length > 0) { |
| 208 | const fileStats = await deleteStorageFiles(files, label) |
| 209 | logger.info( |
| 210 | `[${label}] Storage cleanup: ${fileStats.filesDeleted} deleted, ${fileStats.filesFailed} failed` |
| 211 | ) |
| 212 | } |
| 213 | }, |
| 214 | } |
| 215 | } |
no test coverage detected