diff --git a/apps/backend/src/config.ts b/apps/backend/src/config.ts index cd713b4..cab146f 100644 --- a/apps/backend/src/config.ts +++ b/apps/backend/src/config.ts @@ -15,6 +15,18 @@ export const EnvSchema = z.object({ JWT_SECRET: z.string().min(1, 'JWT_SECRET is required'), PORT: z.coerce.number().int('PORT must be an integer').positive('PORT must be positive'), TOKEN_TRANSFER_CONTRACT_ID: z.string().min(1, 'TOKEN_TRANSFER_CONTRACT_ID is required'), + S3_ENDPOINT: z.string().optional(), + S3_REGION: z.string().optional(), + S3_ACCESS_KEY_ID: z.string().optional(), + S3_SECRET_ACCESS_KEY: z.string().optional(), + S3_BUCKET: z.string().optional(), + S3_FORCE_PATH_STYLE: z + .preprocess((val) => { + if (val === 'true' || val === true) return true; + if (val === 'false' || val === false) return false; + return undefined; + }, z.boolean()) + .optional(), OBJECT_STORE_ENDPOINT: z.string().min(1, 'OBJECT_STORE_ENDPOINT is required'), OBJECT_STORE_BUCKET: z.string().min(1, 'OBJECT_STORE_BUCKET is required'), OBJECT_STORE_ACCESS_KEY: z.string().min(1, 'OBJECT_STORE_ACCESS_KEY is required'), diff --git a/apps/backend/src/routes/files.ts b/apps/backend/src/routes/files.ts index 76c354b..c8f5cf8 100644 --- a/apps/backend/src/routes/files.ts +++ b/apps/backend/src/routes/files.ts @@ -4,6 +4,7 @@ import { eq, and } from 'drizzle-orm'; import { db } from '../db/index.js'; import { messages, conversationMembers, files } from '../db/schema.js'; import { requireAuth, type AuthRequest } from '../middleware/auth.js'; +import { objectStore } from '../lib/objectStore.js'; import { S3Client, GetObjectCommand, PutObjectCommand } from '@aws-sdk/client-s3'; import { getSignedUrl } from '@aws-sdk/s3-request-presigner'; import { randomUUID } from 'node:crypto'; @@ -148,7 +149,7 @@ filesRouter.get('/:fileId', async (req: AuthRequest, res) => { Key: fileRecord.storageKey, }); // Short-lived URL: 5 minutes - const presignedUrl = await getSignedUrl(s3, command, { expiresIn: 300 }); + const presignedUrl = await objectStore.getDownloadUrl(fileId, 300); res.json({ url: presignedUrl }); } catch { res.status(500).json({ error: 'Failed to generate download URL' });