|
1 | 1 | import { AuditAction, AuditResourceType, recordAudit } from '@sim/audit' |
2 | 2 | import { db } from '@sim/db' |
3 | | -import { workflow, workspaceFiles } from '@sim/db/schema' |
| 3 | +import { workflow, workspaceFileFolder, workspaceFiles } from '@sim/db/schema' |
4 | 4 | import { createLogger } from '@sim/logger' |
5 | 5 | import { getErrorMessage, toError } from '@sim/utils/errors' |
6 | 6 | import { generateId } from '@sim/utils/id' |
@@ -312,7 +312,6 @@ function archiveFolderBaseName(displayName: string): string { |
312 | 312 | const stripped = displayName |
313 | 313 | .replace(/\.zip$/i, '') |
314 | 314 | .normalize('NFC') |
315 | | - // biome-ignore lint/suspicious/noControlCharactersInRegex: intentionally stripping control chars |
316 | 315 | .replace(/[\x00-\x1f\x7f]/g, '') |
317 | 316 | .replace(/[/\\]/g, '-') |
318 | 317 | .trim() |
@@ -379,25 +378,40 @@ async function executeExtract( |
379 | 378 | const folderPath = `files/${encodeVfsPathSegments([baseName])}` |
380 | 379 |
|
381 | 380 | // Re-running extract must not silently duplicate the tree with " (1)"-suffixed |
382 | | - // copies: when the destination folder already holds files, report it as |
383 | | - // already extracted instead of extracting beside the previous run. |
| 381 | + // copies: when the destination folder already holds content, report it as |
| 382 | + // already extracted instead of extracting beside the previous run. Direct |
| 383 | + // files AND direct subfolders both count — extraction roots its whole tree |
| 384 | + // here, so a prior run of a nested-only zip (e.g. src/index.ts) leaves a |
| 385 | + // subfolder even when no file sits at the top level. |
384 | 386 | const existingFolderId = await findWorkspaceFileFolderIdByPath(workspaceId, [baseName]) |
385 | 387 | if (existingFolderId) { |
386 | | - const [existingFile] = await db |
387 | | - .select({ id: workspaceFiles.id }) |
388 | | - .from(workspaceFiles) |
389 | | - .where( |
390 | | - and( |
391 | | - eq(workspaceFiles.folderId, existingFolderId), |
392 | | - eq(workspaceFiles.context, 'workspace'), |
393 | | - isNull(workspaceFiles.deletedAt) |
| 388 | + const [[existingFile], [existingSubfolder]] = await Promise.all([ |
| 389 | + db |
| 390 | + .select({ id: workspaceFiles.id }) |
| 391 | + .from(workspaceFiles) |
| 392 | + .where( |
| 393 | + and( |
| 394 | + eq(workspaceFiles.folderId, existingFolderId), |
| 395 | + eq(workspaceFiles.context, 'workspace'), |
| 396 | + isNull(workspaceFiles.deletedAt) |
| 397 | + ) |
394 | 398 | ) |
395 | | - ) |
396 | | - .limit(1) |
397 | | - if (existingFile) { |
| 399 | + .limit(1), |
| 400 | + db |
| 401 | + .select({ id: workspaceFileFolder.id }) |
| 402 | + .from(workspaceFileFolder) |
| 403 | + .where( |
| 404 | + and( |
| 405 | + eq(workspaceFileFolder.parentId, existingFolderId), |
| 406 | + isNull(workspaceFileFolder.deletedAt) |
| 407 | + ) |
| 408 | + ) |
| 409 | + .limit(1), |
| 410 | + ]) |
| 411 | + if (existingFile || existingSubfolder) { |
398 | 412 | return { |
399 | 413 | success: false, |
400 | | - error: `"${fileName}" appears to be already extracted — ${folderPath}/ exists and contains files. List them with glob("${folderPath}/**"). To re-extract, delete that folder first.`, |
| 414 | + error: `"${fileName}" appears to be already extracted — ${folderPath}/ exists and contains content. List it with glob("${folderPath}/**"). To re-extract, delete that folder first.`, |
401 | 415 | } |
402 | 416 | } |
403 | 417 | } |
|
0 commit comments