Skip to content

Commit 5a2191d

Browse files
committed
fix(storage): meter copilot ingest centrally for path symmetry
Address Cursor review: only uploadCopilotFile incremented storage, but copilot files also enter via the generic upload route and presigned uploads — all of which persist metadata through insertFileMetadata. Move the increment into insertFileMetadata (scoped to context='copilot', on genuine insert/restore) so every ingest path is symmetric with the delete-time decrement, and drop the now redundant per-path increment in uploadCopilotFile. Other contexts are metered by their own managers and remain unaffected.
1 parent 8064b9a commit 5a2191d

2 files changed

Lines changed: 28 additions & 11 deletions

File tree

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

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
import { createLogger } from '@sim/logger'
2-
import {
3-
checkStorageQuota,
4-
incrementStorageUsage,
5-
releaseDeletedFileStorage,
6-
} from '@/lib/billing/storage'
2+
import { checkStorageQuota, releaseDeletedFileStorage } from '@/lib/billing/storage'
73
import { getBaseUrl } from '@/lib/core/utils/urls'
84
import {
95
deleteFile,
@@ -148,12 +144,9 @@ export async function uploadCopilotFile(options: {
148144
userId: options.userId,
149145
})
150146

151-
try {
152-
await incrementStorageUsage(options.userId, options.buffer.length)
153-
} catch (storageError) {
154-
logger.error('Failed to update storage tracking:', storageError)
155-
}
156-
147+
// Storage is metered centrally when the copilot metadata row is created
148+
// (see insertFileMetadata), so every ingest path stays symmetric — no
149+
// per-path increment here.
157150
return {
158151
id: fileInfo.key,
159152
key: fileInfo.key,

apps/sim/lib/uploads/server/metadata.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,28 @@ import type { StorageContext } from '../shared/types'
77

88
const logger = createLogger('FileMetadata')
99

10+
/**
11+
* Meter a copilot file's bytes against the owner's storage quota when its
12+
* metadata row is first created or restored. Copilot is the one context metered
13+
* here so that every ingest path (tool output, the upload route, presigned
14+
* uploads) is symmetric with the decrement on delete. Other contexts are metered
15+
* by their own managers (workspace, knowledge-base) or intentionally unmetered
16+
* (execution), so they are skipped. Best-effort: never blocks the metadata write.
17+
*/
18+
async function meterCopilotIngest(
19+
context: StorageContext,
20+
userId: string,
21+
size: number
22+
): Promise<void> {
23+
if (context !== 'copilot' || size <= 0) return
24+
try {
25+
const { incrementStorageUsage } = await import('@/lib/billing/storage')
26+
await incrementStorageUsage(userId, size)
27+
} catch (error) {
28+
logger.error('Failed to meter copilot file storage on ingest', { error })
29+
}
30+
}
31+
1032
export type FileMetadataRecord = typeof workspaceFiles.$inferSelect
1133

1234
export interface FileMetadataInsertOptions {
@@ -57,6 +79,7 @@ export async function insertFileMetadata(
5779
.returning()
5880

5981
if (restored) {
82+
await meterCopilotIngest(context, userId, size)
6083
return restored
6184
}
6285
}
@@ -92,6 +115,7 @@ export async function insertFileMetadata(
92115
})
93116
.returning()
94117

118+
await meterCopilotIngest(context, userId, size)
95119
return inserted
96120
} catch (error) {
97121
const code = (error as { code?: string } | null)?.code

0 commit comments

Comments
 (0)