Skip to content

Commit ff97b62

Browse files
committed
cycle detect
1 parent 0215555 commit ff97b62

4 files changed

Lines changed: 28 additions & 8 deletions

File tree

apps/sim/app/api/workspaces/[id]/files/download/route.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { parseRequest } from '@/lib/api/server'
66
import { getSession } from '@/lib/auth'
77
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
88
import {
9+
buildWorkspaceFileFolderPathMap,
910
fetchWorkspaceFileBuffer,
1011
listWorkspaceFileFolders,
1112
listWorkspaceFiles,
@@ -65,9 +66,10 @@ export const GET = withRouteHandler(
6566

6667
try {
6768
const [files, folders] = await Promise.all([
68-
listWorkspaceFiles(workspaceId),
69+
listWorkspaceFiles(workspaceId, { hydrateFolderPaths: false }),
6970
listWorkspaceFileFolders(workspaceId),
7071
])
72+
const folderPaths = buildWorkspaceFileFolderPathMap(folders)
7173
const selectedFolderIds = collectDescendantFolderIds(folderIds, folders)
7274
const requestedFileIds = new Set(fileIds)
7375
const filesToZip = files.filter(
@@ -102,8 +104,9 @@ export const GET = withRouteHandler(
102104
const usedPaths = new Set<string>()
103105
for (const file of filesToZip) {
104106
const buffer = await fetchWorkspaceFileBuffer(file)
107+
const folderPath = file.folderId ? folderPaths.get(file.folderId) : null
105108
const basePath =
106-
safeZipPath(file.folderPath ? `${file.folderPath}/${file.name}` : file.name) ||
109+
safeZipPath(folderPath ? `${folderPath}/${file.name}` : file.name) ||
107110
safeZipPath(file.name) ||
108111
file.id
109112
let zipPath = basePath

apps/sim/app/workspace/[workspaceId]/files/files.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -534,14 +534,18 @@ export function Files() {
534534
}
535535

536536
const result = new Map<string, Set<string>>()
537-
const collect = (folderId: string): Set<string> => {
537+
const collect = (folderId: string, seen = new Set<string>()): Set<string> => {
538538
const cached = result.get(folderId)
539539
if (cached) return cached
540+
if (seen.has(folderId)) return new Set<string>()
540541

542+
const nextSeen = new Set(seen)
543+
nextSeen.add(folderId)
541544
const descendants = new Set<string>()
542545
for (const childId of childrenByParent.get(folderId) ?? []) {
546+
if (nextSeen.has(childId)) continue
543547
descendants.add(childId)
544-
for (const nestedId of collect(childId)) {
548+
for (const nestedId of collect(childId, nextSeen)) {
545549
descendants.add(nestedId)
546550
}
547551
}

apps/sim/lib/uploads/contexts/workspace/workspace-file-folder-manager.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,8 +446,11 @@ function collectDescendantFolderIds(
446446
}
447447

448448
const descendants: string[] = []
449+
const seen = new Set([folderId])
449450
const visit = (id: string) => {
450451
for (const childId of childrenByParent.get(id) ?? []) {
452+
if (seen.has(childId)) continue
453+
seen.add(childId)
451454
descendants.push(childId)
452455
visit(childId)
453456
}

apps/sim/lib/uploads/contexts/workspace/workspace-file-manager.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import { MAX_WORKSPACE_FILE_SIZE } from '@/lib/uploads/shared/types'
2929
import { getWorkspaceWithOwner } from '@/lib/workspaces/permissions/utils'
3030
import { isUuid, sanitizeFileName } from '@/executor/constants'
3131
import type { UserFile } from '@/executor/types'
32+
import type { WorkspaceFileFolderRecord } from './workspace-file-folder-manager'
3233
import {
3334
assertWorkspaceFileFolderTarget,
3435
buildWorkspaceFileFolderPathMap,
@@ -69,6 +70,12 @@ export interface WorkspaceFileRecord {
6970
storageContext?: 'workspace' | 'mothership'
7071
}
7172

73+
interface ListWorkspaceFilesOptions {
74+
scope?: WorkspaceFileScope
75+
folders?: WorkspaceFileFolderRecord[]
76+
hydrateFolderPaths?: boolean
77+
}
78+
7279
/**
7380
* Workspace file key pattern: workspace/{workspaceId}/{timestamp}-{random}-{filename}
7481
*/
@@ -620,10 +627,10 @@ export async function getWorkspaceFileByName(
620627
*/
621628
export async function listWorkspaceFiles(
622629
workspaceId: string,
623-
options?: { scope?: WorkspaceFileScope }
630+
options?: ListWorkspaceFilesOptions
624631
): Promise<WorkspaceFileRecord[]> {
625632
try {
626-
const { scope = 'active' } = options ?? {}
633+
const { scope = 'active', hydrateFolderPaths = true } = options ?? {}
627634
const files = await db
628635
.select()
629636
.from(workspaceFiles)
@@ -647,8 +654,11 @@ export async function listWorkspaceFiles(
647654
)
648655
.orderBy(workspaceFiles.uploadedAt)
649656

650-
const folders = await listWorkspaceFileFolders(workspaceId, { scope: 'all' })
651-
const folderPaths = buildWorkspaceFileFolderPathMap(folders)
657+
const needsFolderPaths = hydrateFolderPaths && files.some((file) => file.folderId)
658+
const folders = needsFolderPaths
659+
? (options?.folders ?? (await listWorkspaceFileFolders(workspaceId, { scope: 'all' })))
660+
: []
661+
const folderPaths = needsFolderPaths ? buildWorkspaceFileFolderPathMap(folders) : new Map()
652662

653663
return files.map((file) => mapWorkspaceFileRecord(file, workspaceId, folderPaths))
654664
} catch (error) {

0 commit comments

Comments
 (0)