feat: add basic storage usage tracking

This commit is contained in:
2025-11-02 18:12:33 +00:00
parent d2c09f5d0f
commit 9b8367ade4
8 changed files with 129 additions and 22 deletions

View File

@@ -20,6 +20,7 @@ import * as Directories from "./directories"
import * as FilePreview from "./filepreview"
import * as Files from "./files"
import * as FileShare from "./fileshare"
import * as User from "./user"
export const VDirectoryHandle = v.object({
kind: v.literal(FileType.Directory),
@@ -266,6 +267,60 @@ export async function openFile(
}
}
export async function saveFile(
ctx: AuthenticatedMutationCtx,
{
name,
storageId,
directoryId,
}: {
name: string
storageId: Id<"_storage">
directoryId: Id<"directories">
},
) {
const directory = await authorizedGet(ctx, directoryId)
if (!directory) {
throw Err.create(Err.Code.NotFound, "directory not found")
}
const [fileMetadata, userInfo] = await Promise.all([
ctx.db.system.get(storageId),
User.queryInfo(ctx),
])
if (!fileMetadata || !userInfo) {
throw Err.create(Err.Code.Internal, "Internal server error")
}
if (
userInfo.storageUsageBytes + fileMetadata.size >
userInfo.storageQuotaBytes
) {
await ctx.storage.delete(storageId)
throw Err.create(Err.Code.StorageQuotaExceeded, "Storage quota exceeded")
}
const now = Date.now()
const [fileId] = await Promise.all([
ctx.db.insert("files", {
name,
userId: ctx.user._id,
createdAt: now,
updatedAt: now,
storageId,
directoryId,
size: fileMetadata.size,
mimeType: fileMetadata.contentType,
}),
ctx.db.patch(userInfo._id, {
storageUsageBytes: userInfo.storageUsageBytes + fileMetadata.size,
}),
])
return fileId
}
export async function fetchRecentFiles(
ctx: AuthenticatedQueryCtx,
{ limit }: { limit: number },

View File

@@ -1,5 +1,7 @@
import type { MutationCtx, QueryCtx } from "@fileone/convex/server"
import type { Doc } from "../_generated/dataModel"
import { authComponent } from "../auth"
import { type AuthenticatedQueryCtx, authorizedGet } from "../functions"
import * as Err from "../shared/error"
export type AuthUser = Awaited<ReturnType<typeof authComponent.getAuthUser>>
@@ -23,3 +25,10 @@ export async function userOrThrow(ctx: QueryCtx | MutationCtx) {
const user = await authComponent.getAuthUser(ctx)
return user
}
export async function queryInfo(ctx: AuthenticatedQueryCtx) {
return await ctx.db
.query("userInfo")
.withIndex("byUserId", (q) => q.eq("userId", ctx.user._id))
.first()
}