File size: 2,666 Bytes
87cb242 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | import WebSocket from 'ws';
import { ClientMessage, safeSend } from '../utils/protocol';
import {
generateUploadUrl,
validateFileRequest,
validateFileCount,
FileUploadRequest,
} from '../services/supabaseService';
import { logger } from '../utils/logger';
/**
* Handles type: 'get-upload-url'
*
* Client sends:
* {
* files: Array<{ fileName: string, mimeType: string, sizeBytes: number }>
* }
*
* Server responds with:
* {
* urls: Array<{ signedUrl, objectPath, publicUrl, fileName }>
* }
*
* The client then PUTs each file directly to Supabase using the signedUrl.
* HF server never sees any file bytes β memory usage stays near 0.
*
* After upload, the client sends a type: 'message' with type: 'media' and
* the publicUrl as the content field.
*/
export async function handleFileRequest(
ws: WebSocket,
uid: string,
msg: ClientMessage
): Promise<void> {
const files = msg.payload.files as FileUploadRequest[] | undefined;
// ββ Validate count ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
if (!Array.isArray(files)) {
safeSend(ws, 'error', { message: 'files must be an array' }, msg.requestId);
return;
}
const countError = validateFileCount(files.length);
if (countError) {
safeSend(ws, 'error', { message: countError }, msg.requestId);
return;
}
// ββ Validate each file ββββββββββββββββββββββββββββββββββββββββββββββββββββ
for (const f of files) {
const fileError = validateFileRequest(f);
if (fileError) {
safeSend(ws, 'error', { message: fileError }, msg.requestId);
return;
}
}
// ββ Generate signed URLs ββββββββββββββββββββββββββββββββββββββββββββββββββ
try {
const results = await Promise.all(
files.map(async (f) => {
const result = await generateUploadUrl(uid, f);
return {
fileName: f.fileName,
signedUrl: result.signedUrl,
objectPath: result.objectPath,
publicUrl: result.publicUrl,
};
})
);
safeSend(ws, 'upload-url', { urls: results }, msg.requestId);
logger.info('Signed URLs generated', { uid, count: results.length });
} catch (err) {
logger.error('generateUploadUrl failed', { uid, error: String(err) });
safeSend(ws, 'error', { message: 'Failed to generate upload URL' }, msg.requestId);
}
}
|