Skip to content

Commit 9840f37

Browse files
committed
fix(files): attach the download anchor and handle a finalize rejection
A detached anchor's click() works in current browsers, but every other download helper in the app attaches first, and a silent no-op on this path would look exactly like a download that never started. Not worth the ambiguity for two DOM operations. archive.finalize() was fired with void, so a failure after the response had started became an unhandled rejection on top of the stream error event that already fails the response. It is caught and logged now.
1 parent 91c343e commit 9840f37

2 files changed

Lines changed: 10 additions & 1 deletion

File tree

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,11 @@ export const GET = withRouteHandler(
238238
const rendered = renderedDocuments.get(file.id)
239239
archive.append(rendered ?? lazyWorkspaceFileStream(file), { name: entryPaths[index] })
240240
})
241-
void archive.finalize()
241+
archive.finalize().catch((error) => {
242+
// The archive's `error` event already fails the response stream; this keeps the
243+
// same failure from also surfacing as an unhandled rejection.
244+
logger.error('Failed to finalize workspace file archive', { error })
245+
})
242246

243247
recordAudit({
244248
workspaceId,

apps/sim/lib/uploads/client/download.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@ export function saveBlob(blob: Blob, fileName: string): void {
77
const anchor = document.createElement('a')
88
anchor.href = objectUrl
99
anchor.download = fileName
10+
// Attached before clicking: a detached anchor works in current browsers, but every
11+
// other download helper in the app attaches, and a silent no-op here would look
12+
// exactly like a download that never started.
13+
document.body.appendChild(anchor)
1014
anchor.click()
15+
document.body.removeChild(anchor)
1116
// Deferred: revoking synchronously after click() can race the download starting.
1217
setTimeout(() => URL.revokeObjectURL(objectUrl), 0)
1318
}

0 commit comments

Comments
 (0)