diff --git a/apps/api/src/group-files/group-files.controller.ts b/apps/api/src/group-files/group-files.controller.ts index 84afe64..8c2233e 100644 --- a/apps/api/src/group-files/group-files.controller.ts +++ b/apps/api/src/group-files/group-files.controller.ts @@ -7,7 +7,7 @@ import { GroupFilesService, type FilePage } from "./group-files.service.js"; import type { GroupFile } from "@tactical-media-broadcast-hub/core"; import { verifyWhileStreaming } from "./ocis-webdav.js"; -const MAX_FILE_UPLOAD_BYTES = 20 * 1024 * 1024; +const MAX_FILE_UPLOAD_BYTES = 2 * 1024 * 1024 * 1024; interface FileUpload { buffer: Buffer; @@ -20,7 +20,7 @@ interface FileUpload { * * GET /files list/search, keyset (groupId, senderMxid, * mimeClass, origin, name, from, to, cursor, limit) - * POST /files/groups/:groupId/upload direct web upload (≤20 MiB, multipart) + * POST /files/groups/:groupId/upload direct web upload (≤2 GiB, multipart) * GET /files/:id one GroupFile * GET /files/:id/download stream payload (sha256 re-verified) * POST /files/:id/retention set retention (keep/until/legalHold) diff --git a/apps/api/src/group-files/ocis-webdav.ts b/apps/api/src/group-files/ocis-webdav.ts index 8db8678..af576c4 100644 --- a/apps/api/src/group-files/ocis-webdav.ts +++ b/apps/api/src/group-files/ocis-webdav.ts @@ -184,7 +184,7 @@ export class OcisWebdavClient { async upload(groupId: string, safeName: string, body: Readable, contentType: string): Promise { await this.ensureGroupFolder(groupId); // reva rejects chunked PUTs, so the source drains into a bounded buffer - // (the upload cap is 20 MiB) and goes out with an explicit content-length. + // (the upload cap is 2 GiB) and goes out with an explicit content-length. const hash = createHash("sha256"); const chunks: Buffer[] = []; let sizeBytes = 0; diff --git a/apps/api/src/video/video.service.ts b/apps/api/src/video/video.service.ts index 72cfd68..5e56a97 100644 --- a/apps/api/src/video/video.service.ts +++ b/apps/api/src/video/video.service.ts @@ -453,7 +453,7 @@ function validateUpload(storageKey: string, mimeType: string, sizeBytes: number) if (!Number.isSafeInteger(sizeBytes) || sizeBytes < 1) { throw new BadRequestException("sizeBytes must be a positive safe integer"); } - if (sizeBytes > MAX_VIDEO_UPLOAD_BYTES) throw new BadRequestException("video exceeds the 100 MiB upload limit"); + if (sizeBytes > MAX_VIDEO_UPLOAD_BYTES) throw new BadRequestException("video exceeds the 2 GiB upload limit"); } function requiredRow(row: unknown, description: string): Record { diff --git a/apps/web/src/components/files/upload-dropzone.tsx b/apps/web/src/components/files/upload-dropzone.tsx index 1150d1b..a5c564c 100644 --- a/apps/web/src/components/files/upload-dropzone.tsx +++ b/apps/web/src/components/files/upload-dropzone.tsx @@ -10,11 +10,12 @@ import type { GroupFile } from "./types"; /** * Drag-drop + picker for POST /files/groups/:groupId/upload. The API accepts a - * single `file` field capped at 20 MiB; the cap is enforced here too so an + * single `file` field capped at 2 GiB; the cap is enforced here too so an * oversized pick fails fast with a friendly message instead of a 413. */ -const MAX_UPLOAD_BYTES = 20 * 1024 * 1024; +const MAX_UPLOAD_BYTES = 2 * 1024 * 1024 * 1024; +const MAX_LABEL = "2 GiB"; export function UploadDropzone({ groupId, live, onUploaded }: { groupId: string; @@ -41,8 +42,8 @@ export function UploadDropzone({ groupId, live, onUploaded }: { if (file.size > MAX_UPLOAD_BYTES) { setError( t({ - en: `${file.name} is ${formatBytes(file.size)} — the limit is 20 MiB.`, - es: `${file.name} pesa ${formatBytes(file.size)} — el límite es 20 MiB.`, + en: `${file.name} is ${formatBytes(file.size)} — the limit is ${MAX_LABEL}.`, + es: `${file.name} pesa ${formatBytes(file.size)} — el límite es ${MAX_LABEL}.`, }), ); return; @@ -73,8 +74,8 @@ export function UploadDropzone({ groupId, live, onUploaded }: { : groupId === "" ? t({ en: "Choose a group first.", es: "Elige un grupo primero." }) : t({ - en: "Drop a file, paste one, or browse. Up to 20 MiB; stored with re-verified bytes.", - es: "Arrastra un archivo, pega uno o búscalo. Hasta 20 MiB; guardado con bytes reverificados.", + en: `Drop a file, paste one, or browse. Up to ${MAX_LABEL}; stored with re-verified bytes.`, + es: `Arrastra un archivo, pega uno o búscalo. Hasta ${MAX_LABEL}; guardado con bytes reverificados.`, }); return (