[WEB-5093] improvement: adds content-based MIME type detection for uploads #7925
- Refactored file upload utilities to use async functions for better handling of file metadata. - Introduced MIME type detection using the file-type library. - Updated file service methods to await metadata retrieval. - Added new dependencies for file-type and updated package.json accordingly. - Removed deprecated file handling code from utils and adjusted imports across services.
This commit is contained in:
parent
f2539c5051
commit
0b257c8693
9 changed files with 352 additions and 82 deletions
|
|
@ -23,7 +23,8 @@
|
|||
"dependencies": {
|
||||
"@plane/constants": "workspace:*",
|
||||
"@plane/types": "workspace:*",
|
||||
"axios": "catalog:"
|
||||
"axios": "catalog:",
|
||||
"file-type": "^21.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@plane/eslint-config": "workspace:*",
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// external imports
|
||||
import { fileTypeFromBuffer } from "file-type";
|
||||
// plane imports
|
||||
import { TFileMetaDataLite, TFileSignedURLResponse } from "@plane/types";
|
||||
|
||||
/**
|
||||
|
|
@ -13,16 +16,63 @@ export const generateFileUploadPayload = (signedURLResponse: TFileSignedURLRespo
|
|||
return formData;
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Detect MIME type from file signature using file-type library
|
||||
* @param {File} file
|
||||
* @returns {Promise<string>} detected MIME type or empty string if unknown
|
||||
*/
|
||||
const detectMimeTypeFromSignature = async (file: File): Promise<string> => {
|
||||
try {
|
||||
// Read first 4KB which is usually sufficient for most file type detection
|
||||
const chunk = file.slice(0, 4096);
|
||||
const buffer = await chunk.arrayBuffer();
|
||||
const uint8Array = new Uint8Array(buffer);
|
||||
|
||||
const fileType = await fileTypeFromBuffer(uint8Array);
|
||||
return fileType?.mime || "";
|
||||
} catch (_error) {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Determine the MIME type of a file using multiple detection methods
|
||||
* @param {File} file
|
||||
* @returns {Promise<string>} detected MIME type
|
||||
*/
|
||||
const detectFileType = async (file: File): Promise<string> => {
|
||||
// check if the file has a MIME type
|
||||
if (file.type && file.type.trim() !== "") {
|
||||
return file.type;
|
||||
}
|
||||
|
||||
// detect from file signature using file-type library
|
||||
try {
|
||||
const signatureType = await detectMimeTypeFromSignature(file);
|
||||
if (signatureType) {
|
||||
return signatureType;
|
||||
}
|
||||
} catch (_error) {
|
||||
console.error("Error detecting file type from signature:", _error);
|
||||
}
|
||||
|
||||
// fallback for unknown files
|
||||
return "application/octet-stream";
|
||||
};
|
||||
|
||||
/**
|
||||
* @description returns the necessary file meta data to upload a file
|
||||
* @param {File} file
|
||||
* @returns {TFileMetaDataLite} payload with file info
|
||||
* @returns {Promise<TFileMetaDataLite>} payload with file info
|
||||
*/
|
||||
export const getFileMetaDataForUpload = (file: File): TFileMetaDataLite => ({
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
type: file.type,
|
||||
});
|
||||
export const getFileMetaDataForUpload = async (file: File): Promise<TFileMetaDataLite> => {
|
||||
const fileType = await detectFileType(file);
|
||||
return {
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
type: fileType,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @description this function returns the assetId from the asset source
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
export * from "./file-upload.service";
|
||||
export * from "./sites-file.service";
|
||||
export * from "./file.service";
|
||||
export * from "./helper";
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ export class SitesFileService extends FileService {
|
|||
* @throws {Error} If the request fails
|
||||
*/
|
||||
async uploadAsset(anchor: string, data: TFileEntityInfo, file: File): Promise<TFileSignedURLResponse> {
|
||||
const fileMetaData = getFileMetaDataForUpload(file);
|
||||
const fileMetaData = await getFileMetaDataForUpload(file);
|
||||
return this.post(`/api/public/assets/v2/anchor/${anchor}/`, {
|
||||
...data,
|
||||
...fileMetaData,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue