storemw-core-api 1.0.165 → 1.0.167

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -20,7 +20,8 @@ exports.FileStorageHook = {
20
20
  "audio/x-wav",
21
21
  "audio/webm",
22
22
  "audio/m4a",
23
- "audio/mpeg"
23
+ "audio/mpeg",
24
+ "audio/mp4"
24
25
  ],
25
26
  imageMaxWidth: 800,
26
27
  imageQuality: 80,
@@ -1 +1 @@
1
- {"version":3,"file":"fileStorageRegistry.js","sourceRoot":"","sources":["../../../src/features/file_storage/fileStorageRegistry.ts"],"names":[],"mappings":";;;AACA,mCAAoC;AACpC,0BAA0B;AAE1B,oCAAoC;AACvB,QAAA,eAAe,GAA4B;IACpD,OAAO,EAAE,KAAK,IAAwC,EAAE;QAEpD,MAAM,oBAAoB,GAAsD;YAC5E,aAAa,EAAE,QAAQ;YACvB,gBAAgB,EAAE;gBACd,YAAY;gBACZ,WAAW;gBACX,iBAAiB;gBACjB,WAAW;gBACX,WAAW;gBACX,WAAW;gBACX,WAAW;gBACX,YAAY;gBACZ,aAAa;gBACb,YAAY;gBACZ,WAAW;gBACX,YAAY;aACf;YACD,aAAa,EAAE,GAAG;YAClB,YAAY,EAAE,EAAE;YAChB,QAAQ,EAAE,EAAE;YACZ,WAAW,EAAE,UAAU;YACvB,eAAe,EAAE,IAAI;SACxB,CAAA;QAED,QAAQ;QACR,OAAO;YACH,WAAW,EAAE,OAAO;YACpB,oBAAoB;YACpB,mBAAmB,EAAE;gBACjB,OAAO,EAAE,sCAAsC;gBAC/C,QAAQ,EAAE,gBAAgB;gBAC1B,uBAAuB,EAAE,KAAK;gBAC9B,uBAAuB,EAAE,KAAK;aACjC;SACJ,CAAA;QAED,SAAS;QACT,WAAW;QACX,6BAA6B;QAC7B,4BAA4B;QAC5B,8BAA8B;QAC9B,0EAA0E;QAC1E,wBAAwB;QACxB,8CAA8C;QAC9C,sEAAsE;QACtE,0CAA0C;QAC1C,yCAAyC;QACzC,QAAQ;QACR,IAAI;IAER,CAAC;IACD,aAAa,EAAE,KAAK,EAAE,KAAyC,EAAE,EAAE;QAC/D,IAAA,kBAAU,EAAC,uDAAuD,CAAC,CAAA;IACvE,CAAC;IACD,eAAe,EAAE,KAAK,EAAE,KAA2C,EAAE,EAAE;QACnE,IAAA,kBAAU,EAAC,yDAAyD,CAAC,CAAA;IACzE,CAAC;CACJ,CAAA","sourcesContent":["import { FeatureFileStorageProps, FeatureFileStorageOptions, FeatureFileStorageSuccessUploadProps, FeatureFileStorageStartUploadProps } from './fileStorageType'\nimport { throwError } from '@/utils'\n// import path from 'path'\n\n// Runtime storage for injected hook\nexport const FileStorageHook: FeatureFileStorageProps = {\n onSetup: async (): Promise<FeatureFileStorageOptions> => {\n\n const storageConfiguration: FeatureFileStorageOptions[\"storageConfiguration\"] = {\n uploadMaxSize: 52428800,\n allowedFileTypes: [\n \"image/jpeg\",\n \"image/png\",\n \"application/pdf\",\n \"video/mp4\",\n \"audio/ogg\",\n \"audio/wav\",\n \"audio/wav\",\n \"audio/wave\",\n \"audio/x-wav\",\n \"audio/webm\",\n \"audio/m4a\",\n \"audio/mpeg\"\n ],\n imageMaxWidth: 800,\n imageQuality: 80,\n videoCRF: 28,\n videoPreset: \"veryfast\",\n videoResolution: 1280\n }\n\n // local\n return {\n storageType: \"local\",\n storageConfiguration,\n localStorageOptions: {\n baseUrl: \"http://localhost:8080/public/uploads\",\n basePath: \"public/uploads\",\n skipFolderNameModuleRef: false,\n skipFolderNameYearMonth: false\n }\n }\n\n // gcloud\n // return {\n // storageType: \"gcloud\",\n // storageConfiguration,\n // gcloudStorageOptions: {\n // baseUrl: \"https://storage.googleapis.com/chinlai-erp-delivery\",\n // basePath: \"\",\n // bucketName: \"chinlai-erp-delivery\",\n // credentialPath: \"config/chinlai-erp-api-253ac2637a8e.json\",\n // skipFolderNameModuleRef: false,\n // skipFolderNameYearMonth: false\n // }\n // }\n\n },\n onStartUpload: async (props: FeatureFileStorageStartUploadProps) => {\n throwError(`Invalid settings for onStartUpload in FileStorageHook`)\n },\n onSuccessUpload: async (props: FeatureFileStorageSuccessUploadProps) => {\n throwError(`Invalid settings for onSuccessUpload in FileStorageHook`)\n }\n}"]}
1
+ {"version":3,"file":"fileStorageRegistry.js","sourceRoot":"","sources":["../../../src/features/file_storage/fileStorageRegistry.ts"],"names":[],"mappings":";;;AACA,mCAAoC;AACpC,0BAA0B;AAE1B,oCAAoC;AACvB,QAAA,eAAe,GAA4B;IACpD,OAAO,EAAE,KAAK,IAAwC,EAAE;QAEpD,MAAM,oBAAoB,GAAsD;YAC5E,aAAa,EAAE,QAAQ;YACvB,gBAAgB,EAAE;gBACd,YAAY;gBACZ,WAAW;gBACX,iBAAiB;gBACjB,WAAW;gBACX,WAAW;gBACX,WAAW;gBACX,WAAW;gBACX,YAAY;gBACZ,aAAa;gBACb,YAAY;gBACZ,WAAW;gBACX,YAAY;gBACZ,WAAW;aACd;YACD,aAAa,EAAE,GAAG;YAClB,YAAY,EAAE,EAAE;YAChB,QAAQ,EAAE,EAAE;YACZ,WAAW,EAAE,UAAU;YACvB,eAAe,EAAE,IAAI;SACxB,CAAA;QAED,QAAQ;QACR,OAAO;YACH,WAAW,EAAE,OAAO;YACpB,oBAAoB;YACpB,mBAAmB,EAAE;gBACjB,OAAO,EAAE,sCAAsC;gBAC/C,QAAQ,EAAE,gBAAgB;gBAC1B,uBAAuB,EAAE,KAAK;gBAC9B,uBAAuB,EAAE,KAAK;aACjC;SACJ,CAAA;QAED,SAAS;QACT,WAAW;QACX,6BAA6B;QAC7B,4BAA4B;QAC5B,8BAA8B;QAC9B,0EAA0E;QAC1E,wBAAwB;QACxB,8CAA8C;QAC9C,sEAAsE;QACtE,0CAA0C;QAC1C,yCAAyC;QACzC,QAAQ;QACR,IAAI;IAER,CAAC;IACD,aAAa,EAAE,KAAK,EAAE,KAAyC,EAAE,EAAE;QAC/D,IAAA,kBAAU,EAAC,uDAAuD,CAAC,CAAA;IACvE,CAAC;IACD,eAAe,EAAE,KAAK,EAAE,KAA2C,EAAE,EAAE;QACnE,IAAA,kBAAU,EAAC,yDAAyD,CAAC,CAAA;IACzE,CAAC;CACJ,CAAA","sourcesContent":["import { FeatureFileStorageProps, FeatureFileStorageOptions, FeatureFileStorageSuccessUploadProps, FeatureFileStorageStartUploadProps } from './fileStorageType'\nimport { throwError } from '@/utils'\n// import path from 'path'\n\n// Runtime storage for injected hook\nexport const FileStorageHook: FeatureFileStorageProps = {\n onSetup: async (): Promise<FeatureFileStorageOptions> => {\n\n const storageConfiguration: FeatureFileStorageOptions[\"storageConfiguration\"] = {\n uploadMaxSize: 52428800,\n allowedFileTypes: [\n \"image/jpeg\",\n \"image/png\",\n \"application/pdf\",\n \"video/mp4\",\n \"audio/ogg\",\n \"audio/wav\",\n \"audio/wav\",\n \"audio/wave\",\n \"audio/x-wav\",\n \"audio/webm\",\n \"audio/m4a\",\n \"audio/mpeg\",\n \"audio/mp4\"\n ],\n imageMaxWidth: 800,\n imageQuality: 80,\n videoCRF: 28,\n videoPreset: \"veryfast\",\n videoResolution: 1280\n }\n\n // local\n return {\n storageType: \"local\",\n storageConfiguration,\n localStorageOptions: {\n baseUrl: \"http://localhost:8080/public/uploads\",\n basePath: \"public/uploads\",\n skipFolderNameModuleRef: false,\n skipFolderNameYearMonth: false\n }\n }\n\n // gcloud\n // return {\n // storageType: \"gcloud\",\n // storageConfiguration,\n // gcloudStorageOptions: {\n // baseUrl: \"https://storage.googleapis.com/chinlai-erp-delivery\",\n // basePath: \"\",\n // bucketName: \"chinlai-erp-delivery\",\n // credentialPath: \"config/chinlai-erp-api-253ac2637a8e.json\",\n // skipFolderNameModuleRef: false,\n // skipFolderNameYearMonth: false\n // }\n // }\n\n },\n onStartUpload: async (props: FeatureFileStorageStartUploadProps) => {\n throwError(`Invalid settings for onStartUpload in FileStorageHook`)\n },\n onSuccessUpload: async (props: FeatureFileStorageSuccessUploadProps) => {\n throwError(`Invalid settings for onSuccessUpload in FileStorageHook`)\n }\n}"]}
@@ -31,7 +31,7 @@ const validateRouteFilesUpload = async (req, res, next) => {
31
31
  fileFilter: (req, file, cb) => {
32
32
  if (!allowedFileTypes.includes(file.mimetype)) {
33
33
  // Reject immediately with an Error, providing which file is invalid
34
- return cb(new Error(`Unsupported file type: ${file.originalname}`));
34
+ return cb(new Error(`Unsupported file type: ${file.originalname}, required: ${file.mimetype}`));
35
35
  }
36
36
  cb(null, true);
37
37
  }
@@ -1 +1 @@
1
- {"version":3,"file":"validateFile.js","sourceRoot":"","sources":["../../../src/middlewares/route/validateFile.ts"],"names":[],"mappings":"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","sourcesContent":["\nimport {\n Request,\n Response,\n NextFunction\n} from \"express\";\n\nimport multer from 'multer';\n\nimport { validateMultipleSchemas, HTTP_STATUS, sendError } from \"@/utils\";\nimport { schemaRouteFileList } from \"@/schema/middleware/route\";\n\nimport { schemaQueryList, schemaQueryGet } from \"@/schema/common\";\n\nimport { FileStorageHook } from \"@/features\";\n\nexport const validateRouteFileGet = validateMultipleSchemas([\n [schemaQueryGet, \"query\"]\n])\n\nexport const validateRouteFileList = validateMultipleSchemas([\n [schemaRouteFileList, \"params\"],\n [schemaQueryList, \"query\"]\n])\n\nexport const validateRouteFilesUpload = async (req: Request, res: Response, next: NextFunction) => {\n\n const hookSetup = await FileStorageHook.onSetup()\n\n // const allowedFileTypes = config.FILE_UPLOAD_ALLOWED_TYPES?.split(\",\") || [];\n // const maxFileSize = Number(config.FILE_UPLOAD_MAX_SIZE) || 50 * 1024 * 1024;\n\n const allowedFileTypes = hookSetup.storageConfiguration.allowedFileTypes ?? [];\n const maxFileSize = Number(hookSetup.storageConfiguration.uploadMaxSize) || 50 * 1024 * 1024;\n\n const upload = multer({\n storage: multer.memoryStorage(),\n limits: {\n fieldSize: maxFileSize,\n fileSize: maxFileSize,\n },\n fileFilter: (req, file, cb) => {\n if (!allowedFileTypes.includes(file.mimetype)) {\n // Reject immediately with an Error, providing which file is invalid\n return cb(new Error(`Unsupported file type: ${file.originalname}`));\n }\n cb(null, true);\n }\n }).array(\"files\"); // 👈 define field here\n\n upload(req, res, (err: any) => {\n\n if (err instanceof multer.MulterError) {\n let message = err.message;\n\n if (err.code === \"LIMIT_FILE_SIZE\") {\n message = `File too large. Max size is ${maxFileSize / (1024 * 1024)} MB`;\n }\n\n sendError(res, \"BAD_REQUEST\", message, \"\", JSON.stringify(err), HTTP_STATUS.BAD_REQUEST);\n return;\n\n } else if (err) {\n\n // This captures the invalid file type error we threw in fileFilter\n sendError(res, \"BAD_REQUEST\", err.message || \"Invalid file\", \"\", JSON.stringify(err), HTTP_STATUS.BAD_REQUEST);\n return;\n\n }\n\n // Check if at least one file passed the filter\n if (!req.files || req.files.length === 0) {\n sendError(res, \"BAD_REQUEST\", \"At least one valid file must be uploaded\", \"\", \"\", HTTP_STATUS.BAD_REQUEST);\n return;\n }\n\n next();\n\n });\n\n};\n\n// export const validateRouteFileUpdate = (req: Request, res: Response, next: NextFunction) => {\n// next();\n// };\n\nexport const validateRouteFileDelete = (req: Request, res: Response, next: NextFunction) => next()"]}
1
+ {"version":3,"file":"validateFile.js","sourceRoot":"","sources":["../../../src/middlewares/route/validateFile.ts"],"names":[],"mappings":"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","sourcesContent":["\nimport {\n Request,\n Response,\n NextFunction\n} from \"express\";\n\nimport multer from 'multer';\n\nimport { validateMultipleSchemas, HTTP_STATUS, sendError } from \"@/utils\";\nimport { schemaRouteFileList } from \"@/schema/middleware/route\";\n\nimport { schemaQueryList, schemaQueryGet } from \"@/schema/common\";\n\nimport { FileStorageHook } from \"@/features\";\n\nexport const validateRouteFileGet = validateMultipleSchemas([\n [schemaQueryGet, \"query\"]\n])\n\nexport const validateRouteFileList = validateMultipleSchemas([\n [schemaRouteFileList, \"params\"],\n [schemaQueryList, \"query\"]\n])\n\nexport const validateRouteFilesUpload = async (req: Request, res: Response, next: NextFunction) => {\n\n const hookSetup = await FileStorageHook.onSetup()\n\n // const allowedFileTypes = config.FILE_UPLOAD_ALLOWED_TYPES?.split(\",\") || [];\n // const maxFileSize = Number(config.FILE_UPLOAD_MAX_SIZE) || 50 * 1024 * 1024;\n\n const allowedFileTypes = hookSetup.storageConfiguration.allowedFileTypes ?? [];\n const maxFileSize = Number(hookSetup.storageConfiguration.uploadMaxSize) || 50 * 1024 * 1024;\n\n const upload = multer({\n storage: multer.memoryStorage(),\n limits: {\n fieldSize: maxFileSize,\n fileSize: maxFileSize,\n },\n fileFilter: (req, file, cb) => {\n if (!allowedFileTypes.includes(file.mimetype)) {\n // Reject immediately with an Error, providing which file is invalid\n return cb(new Error(`Unsupported file type: ${file.originalname}, required: ${file.mimetype}`));\n }\n cb(null, true);\n }\n }).array(\"files\"); // 👈 define field here\n\n upload(req, res, (err: any) => {\n\n if (err instanceof multer.MulterError) {\n let message = err.message;\n\n if (err.code === \"LIMIT_FILE_SIZE\") {\n message = `File too large. Max size is ${maxFileSize / (1024 * 1024)} MB`;\n }\n\n sendError(res, \"BAD_REQUEST\", message, \"\", JSON.stringify(err), HTTP_STATUS.BAD_REQUEST);\n return;\n\n } else if (err) {\n\n // This captures the invalid file type error we threw in fileFilter\n sendError(res, \"BAD_REQUEST\", err.message || \"Invalid file\", \"\", JSON.stringify(err), HTTP_STATUS.BAD_REQUEST);\n return;\n\n }\n\n // Check if at least one file passed the filter\n if (!req.files || req.files.length === 0) {\n sendError(res, \"BAD_REQUEST\", \"At least one valid file must be uploaded\", \"\", \"\", HTTP_STATUS.BAD_REQUEST);\n return;\n }\n\n next();\n\n });\n\n};\n\n// export const validateRouteFileUpdate = (req: Request, res: Response, next: NextFunction) => {\n// next();\n// };\n\nexport const validateRouteFileDelete = (req: Request, res: Response, next: NextFunction) => next()"]}
@@ -8,6 +8,7 @@ const client_s3_1 = require("@aws-sdk/client-s3");
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const crypto_1 = require("crypto");
10
10
  const utils_1 = require("../../utils");
11
+ const FileService_1 = require("./FileService");
11
12
  const FileAwsS3StorageProvider = (options) => {
12
13
  const { bucketName, region, basePath = "", skipFoldernameByModuleRef = false, skipFoldernameByDate = false, publicBaseUrl, credentials, } = options;
13
14
  const s3 = new client_s3_1.S3Client({ region, credentials });
@@ -60,7 +61,8 @@ const FileAwsS3StorageProvider = (options) => {
60
61
  Bucket: bucketName,
61
62
  Key: objectPath,
62
63
  Body: buffer,
63
- ContentType: mimeType,
64
+ ContentType: (0, FileService_1.getBrowserSafeContentType)(mimeType)
65
+ // ContentType: mimeType,
64
66
  // ACL: "public-read"
65
67
  }));
66
68
  let thumbnailUrl = ``;
@@ -1 +1 @@
1
- {"version":3,"file":"FileAwsS3StorageProvider.js","sourceRoot":"","sources":["../../../src/services/file/FileAwsS3StorageProvider.ts"],"names":[],"mappings":"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","sourcesContent":["import { S3Client, PutObjectCommand, DeleteObjectCommand } from \"@aws-sdk/client-s3\";\nimport path from \"path\";\nimport { randomUUID } from \"crypto\";\nimport { dayjs } from \"@/utils\";\nimport { FileModuleRef } from \"./FileService\";\nimport { FileStorageProviderResult } from \"./FileStorageProviderRegistry\";\n\nexport type FileAwsS3ProviderOptions = {\n bucketName: string;\n region?: string; // AWS region\n basePath?: string; // optional folder prefix\n skipFoldernameByModuleRef?: boolean;\n skipFoldernameByDate?: boolean;\n publicBaseUrl?: string; // optional, e.g., https://bucket-name.s3.amazonaws.com\n credentials?: {\n accessKeyId: string;\n secretAccessKey: string;\n sessionToken?: string;\n }\n}\n\nexport type FileAwsS3UploadFileProps = {\n buffer: Buffer;\n bufferThumbnail: Buffer;\n thumbnailOptions: {\n suffix: string;\n ext: string;\n mimeType: string;\n };\n mimeType: string;\n foldernameDate?: string;\n fileName: string;\n}\n\nexport const FileAwsS3StorageProvider = (options: FileAwsS3ProviderOptions) => {\n const {\n bucketName,\n region,\n basePath = \"\",\n skipFoldernameByModuleRef = false,\n skipFoldernameByDate = false,\n publicBaseUrl,\n credentials,\n } = options;\n\n const s3 = new S3Client({ region, credentials });\n\n const uploadFile = async <T extends FileModuleRef>({\n field_ref,\n field_module,\n buffer,\n bufferThumbnail,\n thumbnailOptions,\n mimeType,\n foldernameDate,\n fileName,\n }: T & FileAwsS3UploadFileProps): Promise<FileStorageProviderResult> => {\n\n // const now = dayjs(foldernameDate).isValid() ? dayjs(foldernameDate) : dayjs();\n // const year = now.format(\"YYYY\");\n // const month = now.format(\"MM\");\n // const day = now.format(\"DD\");\n\n // const dirParts = [];\n // if (!skipFoldernameByModuleRef) dirParts.push(field_ref, field_module);\n // if (!skipFoldernameByDate) dirParts.push(year, month, day);\n\n const now = dayjs(foldernameDate).isValid() ? dayjs(foldernameDate) : dayjs();\n const year = now.format(\"YYYY\");\n const month = now.format(\"MM\");\n const day = now.format(\"DD\");\n\n let finalPublicBaseUrl = `${publicBaseUrl}`\n let dirParts = []\n\n if (skipFoldernameByModuleRef === false) {\n dirParts.push(field_ref, field_module)\n }\n\n if (skipFoldernameByDate === false) {\n dirParts.push(year, month, day)\n }\n\n let finalBasePath = path.join(basePath, ...dirParts)\n\n // basePath is empty & dirParts are nothing\n if (!basePath && dirParts.length <= 0) {\n finalBasePath = ``\n }\n\n // finalPublicBaseUrl = [finalPublicBaseUrl, basePath, ...dirParts].filter(Boolean).join('/');\n\n // ✅ Cross-platform safe public URL\n finalPublicBaseUrl = [finalPublicBaseUrl, basePath, ...dirParts]\n .filter(Boolean)\n .map(p => p.replace(/\\\\/g, '/')) // converts Windows '\\' to '/'\n .join('/');\n\n const uniqueId = randomUUID();\n const ext = path.extname(fileName);\n const uniqueName = `${uniqueId}${ext}`;\n const uniqueNameThumbnail = `${uniqueId}${thumbnailOptions.suffix}.${thumbnailOptions.ext}`;\n\n // const objectPath = finalBasePath ? `${finalBasePath}/${uniqueName}` : uniqueName;\n // const objectThumbnailPath = finalBasePath ? `${finalBasePath}/${uniqueNameThumbnail}` : uniqueNameThumbnail;\n\n // ✅ Cross-platform safe object paths for S3\n const objectPath = finalBasePath\n ? path.posix.join(finalBasePath.split(path.sep).join('/'), uniqueName)\n : uniqueName;\n\n const objectThumbnailPath = finalBasePath\n ? path.posix.join(finalBasePath.split(path.sep).join('/'), uniqueNameThumbnail)\n : uniqueNameThumbnail;\n\n // Upload main file\n await s3.send(new PutObjectCommand({\n Bucket: bucketName,\n Key: objectPath,\n Body: buffer,\n ContentType: mimeType,\n // ACL: \"public-read\"\n }));\n\n let thumbnailUrl = ``;\n\n // Upload thumbnail if exists\n if (bufferThumbnail) {\n await s3.send(new PutObjectCommand({\n Bucket: bucketName,\n Key: objectThumbnailPath,\n Body: bufferThumbnail,\n ContentType: thumbnailOptions.mimeType,\n // ACL: \"public-read\"\n }));\n thumbnailUrl = `${finalPublicBaseUrl}/${uniqueNameThumbnail}`;\n }\n\n const assetUrl = `${finalPublicBaseUrl}/${uniqueName}`;\n\n return {\n assetPath: objectPath,\n assetUrl,\n thumbnailUrl,\n filename: uniqueName,\n basePath: finalBasePath,\n ...(skipFoldernameByDate === false ? {\n folderName: { day: Number(day), month: Number(month), year: Number(year) }\n } : {})\n };\n\n };\n\n const removeFile = async (assetUrl: string, thumbnailUrl?: string) => {\n const removeObject = async (url: string) => {\n const key = url.split(`/${bucketName}/`)[1]; // naive extraction\n if (!key) return;\n await s3.send(new DeleteObjectCommand({ Bucket: bucketName, Key: key }));\n }\n\n await removeObject(assetUrl);\n if (thumbnailUrl) await removeObject(thumbnailUrl);\n\n return { success: true };\n };\n\n return { uploadFile, removeFile };\n}"]}
1
+ {"version":3,"file":"FileAwsS3StorageProvider.js","sourceRoot":"","sources":["../../../src/services/file/FileAwsS3StorageProvider.ts"],"names":[],"mappings":"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","sourcesContent":["import { S3Client, PutObjectCommand, DeleteObjectCommand } from \"@aws-sdk/client-s3\";\nimport path from \"path\";\nimport { randomUUID } from \"crypto\";\nimport { dayjs } from \"@/utils\";\nimport { FileModuleRef, getBrowserSafeContentType } from \"./FileService\";\nimport { FileStorageProviderResult } from \"./FileStorageProviderRegistry\";\n\nexport type FileAwsS3ProviderOptions = {\n bucketName: string;\n region?: string; // AWS region\n basePath?: string; // optional folder prefix\n skipFoldernameByModuleRef?: boolean;\n skipFoldernameByDate?: boolean;\n publicBaseUrl?: string; // optional, e.g., https://bucket-name.s3.amazonaws.com\n credentials?: {\n accessKeyId: string;\n secretAccessKey: string;\n sessionToken?: string;\n }\n}\n\nexport type FileAwsS3UploadFileProps = {\n buffer: Buffer;\n bufferThumbnail: Buffer;\n thumbnailOptions: {\n suffix: string;\n ext: string;\n mimeType: string;\n };\n mimeType: string;\n foldernameDate?: string;\n fileName: string;\n}\n\nexport const FileAwsS3StorageProvider = (options: FileAwsS3ProviderOptions) => {\n const {\n bucketName,\n region,\n basePath = \"\",\n skipFoldernameByModuleRef = false,\n skipFoldernameByDate = false,\n publicBaseUrl,\n credentials,\n } = options;\n\n const s3 = new S3Client({ region, credentials });\n\n const uploadFile = async <T extends FileModuleRef>({\n field_ref,\n field_module,\n buffer,\n bufferThumbnail,\n thumbnailOptions,\n mimeType,\n foldernameDate,\n fileName,\n }: T & FileAwsS3UploadFileProps): Promise<FileStorageProviderResult> => {\n\n // const now = dayjs(foldernameDate).isValid() ? dayjs(foldernameDate) : dayjs();\n // const year = now.format(\"YYYY\");\n // const month = now.format(\"MM\");\n // const day = now.format(\"DD\");\n\n // const dirParts = [];\n // if (!skipFoldernameByModuleRef) dirParts.push(field_ref, field_module);\n // if (!skipFoldernameByDate) dirParts.push(year, month, day);\n\n const now = dayjs(foldernameDate).isValid() ? dayjs(foldernameDate) : dayjs();\n const year = now.format(\"YYYY\");\n const month = now.format(\"MM\");\n const day = now.format(\"DD\");\n\n let finalPublicBaseUrl = `${publicBaseUrl}`\n let dirParts = []\n\n if (skipFoldernameByModuleRef === false) {\n dirParts.push(field_ref, field_module)\n }\n\n if (skipFoldernameByDate === false) {\n dirParts.push(year, month, day)\n }\n\n let finalBasePath = path.join(basePath, ...dirParts)\n\n // basePath is empty & dirParts are nothing\n if (!basePath && dirParts.length <= 0) {\n finalBasePath = ``\n }\n\n // finalPublicBaseUrl = [finalPublicBaseUrl, basePath, ...dirParts].filter(Boolean).join('/');\n\n // ✅ Cross-platform safe public URL\n finalPublicBaseUrl = [finalPublicBaseUrl, basePath, ...dirParts]\n .filter(Boolean)\n .map(p => p.replace(/\\\\/g, '/')) // converts Windows '\\' to '/'\n .join('/');\n\n const uniqueId = randomUUID();\n const ext = path.extname(fileName);\n const uniqueName = `${uniqueId}${ext}`;\n const uniqueNameThumbnail = `${uniqueId}${thumbnailOptions.suffix}.${thumbnailOptions.ext}`;\n\n // const objectPath = finalBasePath ? `${finalBasePath}/${uniqueName}` : uniqueName;\n // const objectThumbnailPath = finalBasePath ? `${finalBasePath}/${uniqueNameThumbnail}` : uniqueNameThumbnail;\n\n // ✅ Cross-platform safe object paths for S3\n const objectPath = finalBasePath\n ? path.posix.join(finalBasePath.split(path.sep).join('/'), uniqueName)\n : uniqueName;\n\n const objectThumbnailPath = finalBasePath\n ? path.posix.join(finalBasePath.split(path.sep).join('/'), uniqueNameThumbnail)\n : uniqueNameThumbnail;\n\n // Upload main file\n await s3.send(new PutObjectCommand({\n Bucket: bucketName,\n Key: objectPath,\n Body: buffer,\n ContentType: getBrowserSafeContentType(mimeType)\n // ContentType: mimeType,\n // ACL: \"public-read\"\n }));\n\n let thumbnailUrl = ``;\n\n // Upload thumbnail if exists\n if (bufferThumbnail) {\n await s3.send(new PutObjectCommand({\n Bucket: bucketName,\n Key: objectThumbnailPath,\n Body: bufferThumbnail,\n ContentType: thumbnailOptions.mimeType,\n // ACL: \"public-read\"\n }));\n thumbnailUrl = `${finalPublicBaseUrl}/${uniqueNameThumbnail}`;\n }\n\n const assetUrl = `${finalPublicBaseUrl}/${uniqueName}`;\n\n return {\n assetPath: objectPath,\n assetUrl,\n thumbnailUrl,\n filename: uniqueName,\n basePath: finalBasePath,\n ...(skipFoldernameByDate === false ? {\n folderName: { day: Number(day), month: Number(month), year: Number(year) }\n } : {})\n };\n\n };\n\n const removeFile = async (assetUrl: string, thumbnailUrl?: string) => {\n const removeObject = async (url: string) => {\n const key = url.split(`/${bucketName}/`)[1]; // naive extraction\n if (!key) return;\n await s3.send(new DeleteObjectCommand({ Bucket: bucketName, Key: key }));\n }\n\n await removeObject(assetUrl);\n if (thumbnailUrl) await removeObject(thumbnailUrl);\n\n return { success: true };\n };\n\n return { uploadFile, removeFile };\n}"]}
@@ -8,6 +8,7 @@ const storage_1 = require("@google-cloud/storage");
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const utils_1 = require("../../utils");
10
10
  const crypto_1 = require("crypto");
11
+ const FileService_1 = require("./FileService");
11
12
  function extractBucketName(url) {
12
13
  try {
13
14
  const match = url.match(/^https?:\/\/storage\.googleapis\.com\/([^/]+)/);
@@ -65,7 +66,8 @@ const FileGoogleCloudStorageProvider = (options) => {
65
66
  await file.save(buffer, {
66
67
  resumable: false,
67
68
  metadata: {
68
- contentType: mimeType || "application/octet-stream",
69
+ contentType: (0, FileService_1.getBrowserSafeContentType)(mimeType || "application/octet-stream"),
70
+ // contentType: mimeType || "application/octet-stream",
69
71
  },
70
72
  });
71
73
  let fileThumbnail;
@@ -1 +1 @@
1
- {"version":3,"file":"FileGoogleCloudStorageProvider.js","sourceRoot":"","sources":["../../../src/services/file/FileGoogleCloudStorageProvider.ts"],"names":[],"mappings":"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","sourcesContent":["import { Storage } from \"@google-cloud/storage\";\nimport path from \"path\";\n\nimport { dayjs } from \"@/utils\";\n\nimport { randomUUID } from \"crypto\";\n\nimport { FileModuleRef } from \"./FileService\";\n\nimport { FileStorageProviderResult } from \"./FileStorageProviderRegistry\"\n\nexport type FileGoogleCloudProviderOptions = {\n bucketName: string;\n basePath?: string; // e.g. \"uploads\"\n skipFoldernameByModuleRef?: boolean; // skip the folder [ref]/[module]\n skipFoldernameByDate?: boolean; // skip the yyyy/mm/dd folder structure\n publicBaseUrl?: string; // e.g. \"[https://storage.googleapis.com/](https://storage.googleapis.com/)<bucket>\"\n credentials?: string; // path to service account key JSON\n}\n\nexport type FileGoogleCloudUploadFileProps = {\n buffer: Buffer;\n bufferThumbnail: Buffer;\n thumbnailOptions: {\n suffix: string,\n ext: string,\n mimeType: string,\n },\n mimeType: string;\n foldernameDate?: string; // organize the foldername y/m/d using this date\n fileName: string;\n}\n\nfunction extractBucketName(url: string) {\n try {\n const match = url.match(/^https?:\\/\\/storage\\.googleapis\\.com\\/([^/]+)/);\n return match ? match[1] : null;\n } catch (err) {\n console.error(\"Invalid URL:\", err);\n return null;\n }\n}\n\nfunction extractFilePathFromUrl(url: string, bucketName: string): string | null {\n // Remove everything up to and including the bucket name\n const prefix = `https://storage.googleapis.com/${bucketName}/`;\n return url.startsWith(prefix) ? url.slice(prefix.length) : null;\n}\n\nexport const FileGoogleCloudStorageProvider = (options: FileGoogleCloudProviderOptions) => {\n\n const {\n bucketName,\n basePath = \"\",\n skipFoldernameByModuleRef = false,\n skipFoldernameByDate = false,\n publicBaseUrl,\n credentials,\n } = options;\n\n let storage: any\n let bucket: any\n\n if (bucketName) {\n storage = new Storage(credentials ? { keyFilename: credentials } : undefined);\n bucket = storage.bucket(bucketName);\n }\n\n /**\n * Upload file to Google Cloud Storage.\n * Files will be stored under: basePath/ref/module/YYYY/MM/DD/\n */\n const uploadFile = async <\n T extends FileModuleRef\n >({\n field_ref,\n field_module,\n buffer,\n bufferThumbnail,\n thumbnailOptions,\n mimeType,\n foldernameDate,\n fileName,\n }: T & FileGoogleCloudUploadFileProps): Promise<FileStorageProviderResult> => {\n\n const now = dayjs(foldernameDate).isValid() ? dayjs(foldernameDate) : dayjs();\n const year = now.format(\"YYYY\");\n const month = now.format(\"MM\");\n const day = now.format(\"DD\");\n\n // let finalPublicBaseUrl = `https://storage.googleapis.com/${bucketName}`\n let finalPublicBaseUrl = `${publicBaseUrl}`\n let dirParts = []\n\n if (skipFoldernameByModuleRef === false) {\n dirParts.push(field_ref, field_module)\n }\n\n if (skipFoldernameByDate === false) {\n dirParts.push(year, month, day)\n }\n\n let finalBasePath = path.join(basePath, ...dirParts)\n\n // basePath is empty & dirParts are nothing\n if (!basePath && dirParts.length <= 0) {\n finalBasePath = ``\n }\n\n finalPublicBaseUrl = [finalPublicBaseUrl, basePath, ...dirParts].filter(Boolean).join('/');\n\n const ext = path.extname(fileName);\n\n const unidId = randomUUID()\n const uniqueName = `${unidId}${ext}`; // `${base}-${randomUUID()}${ext}`;\n const uniqueNameThumbnail = `${unidId}${thumbnailOptions.suffix}.${thumbnailOptions.ext}`; // `${base}-${randomUUID()}${ext}`;\n\n // create file\n let objectPath = finalBasePath ? `${finalBasePath}/${uniqueName}` : `${uniqueName}`\n const file = bucket.file(objectPath);\n await file.save(buffer, {\n resumable: false,\n metadata: {\n contentType: mimeType || \"application/octet-stream\",\n },\n });\n\n let fileThumbnail: any\n let thumbnailUrl = ``;\n\n // create thumbnail\n if (bufferThumbnail) {\n let objectThumbnailPath = finalBasePath ? `${finalBasePath}/${uniqueNameThumbnail}` : `${uniqueNameThumbnail}`\n fileThumbnail = bucket.file(objectThumbnailPath);\n await fileThumbnail.save(bufferThumbnail, {\n resumable: false,\n metadata: {\n contentType: thumbnailOptions.mimeType || \"application/octet-stream\",\n },\n });\n thumbnailUrl = `${finalPublicBaseUrl}/${uniqueNameThumbnail}`;\n }\n\n try {\n await file.makePublic();\n\n if (bufferThumbnail) {\n await fileThumbnail.makePublic();\n }\n\n } catch (err) {\n console.warn(\"⚠️ Failed to make file public:\", err);\n }\n\n const assetPath = objectPath;\n const assetUrl = `${finalPublicBaseUrl}/${uniqueName}`;\n\n\n return {\n assetPath,\n assetUrl,\n thumbnailUrl,\n filename: uniqueName,\n basePath: finalBasePath,\n ...(skipFoldernameByDate === false ? {\n folderName: {\n day: Number(day),\n month: Number(month),\n year: Number(year)\n }\n } : {})\n };\n };\n\n // const removeFile = async (assetUrl: string, credentials: any) => {\n\n // const bucketName = extractBucketName(assetUrl);\n\n // if (!bucketName) {\n // throw new Error(`Could not extract bucket name from: ${assetUrl}`)\n // }\n\n // const storage = new Storage(credentials ? { keyFilename: credentials } : undefined);\n\n // const filePath = extractFilePathFromUrl(assetUrl, bucketName);\n\n // if (!filePath) {\n // throw new Error(`Could not extract file path from: ${assetUrl}`)\n // }\n\n // const bucket = storage.bucket(bucketName);\n\n // // console.log(`Deleted from GCloud: gs://${bucketName}/${filePath}`);\n\n // return await bucket.file(filePath).delete();\n\n // }\n\n const removeFile = async (\n assetUrl: string,\n thumbnailUrl: string,\n credentials?: string\n ) => {\n try {\n const bucketName = extractBucketName(assetUrl);\n if (!bucketName) throw new Error(`Could not extract bucket name from: ${assetUrl}`);\n\n const filePath = extractFilePathFromUrl(assetUrl, bucketName);\n if (!filePath) throw new Error(`Could not extract file path from: ${assetUrl}`);\n\n let fileThumbnailPath: any\n\n if (thumbnailUrl) {\n fileThumbnailPath = extractFilePathFromUrl(thumbnailUrl, bucketName);\n if (!fileThumbnailPath) throw new Error(`Could not extract file thumbnail path from: ${thumbnailUrl}`);\n }\n\n // Initialize GCS client\n const storage = new Storage(credentials ? { keyFilename: credentials } : undefined);\n const bucket = storage.bucket(bucketName);\n\n // Attempt delete\n await bucket.file(filePath).delete({ ignoreNotFound: true });\n\n if (fileThumbnailPath) {\n // Attempt delete thumbnail\n await bucket.file(fileThumbnailPath).delete({ ignoreNotFound: true });\n }\n\n // console.log(`✅ Deleted from GCloud: gs://${bucketName}/${filePath}`);\n return { success: true, bucketName, filePath, fileThumbnailPath };\n } catch (err: any) {\n // Don’t rethrow — log and return structured error instead\n // console.error(`❌ Failed to delete from GCloud (${assetUrl}):`, err.message || err);\n return { success: false, error: err.message || String(err), assetUrl };\n }\n };\n\n return { uploadFile, removeFile };\n\n};\n"]}
1
+ {"version":3,"file":"FileGoogleCloudStorageProvider.js","sourceRoot":"","sources":["../../../src/services/file/FileGoogleCloudStorageProvider.ts"],"names":[],"mappings":"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","sourcesContent":["import { Storage } from \"@google-cloud/storage\";\nimport path from \"path\";\n\nimport { dayjs } from \"@/utils\";\n\nimport { randomUUID } from \"crypto\";\n\nimport { FileModuleRef, getBrowserSafeContentType } from \"./FileService\";\n\nimport { FileStorageProviderResult } from \"./FileStorageProviderRegistry\"\n\nexport type FileGoogleCloudProviderOptions = {\n bucketName: string;\n basePath?: string; // e.g. \"uploads\"\n skipFoldernameByModuleRef?: boolean; // skip the folder [ref]/[module]\n skipFoldernameByDate?: boolean; // skip the yyyy/mm/dd folder structure\n publicBaseUrl?: string; // e.g. \"[https://storage.googleapis.com/](https://storage.googleapis.com/)<bucket>\"\n credentials?: string; // path to service account key JSON\n}\n\nexport type FileGoogleCloudUploadFileProps = {\n buffer: Buffer;\n bufferThumbnail: Buffer;\n thumbnailOptions: {\n suffix: string,\n ext: string,\n mimeType: string,\n },\n mimeType: string;\n foldernameDate?: string; // organize the foldername y/m/d using this date\n fileName: string;\n}\n\nfunction extractBucketName(url: string) {\n try {\n const match = url.match(/^https?:\\/\\/storage\\.googleapis\\.com\\/([^/]+)/);\n return match ? match[1] : null;\n } catch (err) {\n console.error(\"Invalid URL:\", err);\n return null;\n }\n}\n\nfunction extractFilePathFromUrl(url: string, bucketName: string): string | null {\n // Remove everything up to and including the bucket name\n const prefix = `https://storage.googleapis.com/${bucketName}/`;\n return url.startsWith(prefix) ? url.slice(prefix.length) : null;\n}\n\nexport const FileGoogleCloudStorageProvider = (options: FileGoogleCloudProviderOptions) => {\n\n const {\n bucketName,\n basePath = \"\",\n skipFoldernameByModuleRef = false,\n skipFoldernameByDate = false,\n publicBaseUrl,\n credentials,\n } = options;\n\n let storage: any\n let bucket: any\n\n if (bucketName) {\n storage = new Storage(credentials ? { keyFilename: credentials } : undefined);\n bucket = storage.bucket(bucketName);\n }\n\n /**\n * Upload file to Google Cloud Storage.\n * Files will be stored under: basePath/ref/module/YYYY/MM/DD/\n */\n const uploadFile = async <\n T extends FileModuleRef\n >({\n field_ref,\n field_module,\n buffer,\n bufferThumbnail,\n thumbnailOptions,\n mimeType,\n foldernameDate,\n fileName,\n }: T & FileGoogleCloudUploadFileProps): Promise<FileStorageProviderResult> => {\n\n const now = dayjs(foldernameDate).isValid() ? dayjs(foldernameDate) : dayjs();\n const year = now.format(\"YYYY\");\n const month = now.format(\"MM\");\n const day = now.format(\"DD\");\n\n // let finalPublicBaseUrl = `https://storage.googleapis.com/${bucketName}`\n let finalPublicBaseUrl = `${publicBaseUrl}`\n let dirParts = []\n\n if (skipFoldernameByModuleRef === false) {\n dirParts.push(field_ref, field_module)\n }\n\n if (skipFoldernameByDate === false) {\n dirParts.push(year, month, day)\n }\n\n let finalBasePath = path.join(basePath, ...dirParts)\n\n // basePath is empty & dirParts are nothing\n if (!basePath && dirParts.length <= 0) {\n finalBasePath = ``\n }\n\n finalPublicBaseUrl = [finalPublicBaseUrl, basePath, ...dirParts].filter(Boolean).join('/');\n\n const ext = path.extname(fileName);\n\n const unidId = randomUUID()\n const uniqueName = `${unidId}${ext}`; // `${base}-${randomUUID()}${ext}`;\n const uniqueNameThumbnail = `${unidId}${thumbnailOptions.suffix}.${thumbnailOptions.ext}`; // `${base}-${randomUUID()}${ext}`;\n\n // create file\n let objectPath = finalBasePath ? `${finalBasePath}/${uniqueName}` : `${uniqueName}`\n const file = bucket.file(objectPath);\n await file.save(buffer, {\n resumable: false,\n metadata: {\n contentType: getBrowserSafeContentType(mimeType || \"application/octet-stream\"),\n // contentType: mimeType || \"application/octet-stream\",\n\n },\n });\n\n let fileThumbnail: any\n let thumbnailUrl = ``;\n\n // create thumbnail\n if (bufferThumbnail) {\n let objectThumbnailPath = finalBasePath ? `${finalBasePath}/${uniqueNameThumbnail}` : `${uniqueNameThumbnail}`\n fileThumbnail = bucket.file(objectThumbnailPath);\n await fileThumbnail.save(bufferThumbnail, {\n resumable: false,\n metadata: {\n contentType: thumbnailOptions.mimeType || \"application/octet-stream\",\n },\n });\n thumbnailUrl = `${finalPublicBaseUrl}/${uniqueNameThumbnail}`;\n }\n\n try {\n await file.makePublic();\n\n if (bufferThumbnail) {\n await fileThumbnail.makePublic();\n }\n\n } catch (err) {\n console.warn(\"⚠️ Failed to make file public:\", err);\n }\n\n const assetPath = objectPath;\n const assetUrl = `${finalPublicBaseUrl}/${uniqueName}`;\n\n\n return {\n assetPath,\n assetUrl,\n thumbnailUrl,\n filename: uniqueName,\n basePath: finalBasePath,\n ...(skipFoldernameByDate === false ? {\n folderName: {\n day: Number(day),\n month: Number(month),\n year: Number(year)\n }\n } : {})\n };\n };\n\n // const removeFile = async (assetUrl: string, credentials: any) => {\n\n // const bucketName = extractBucketName(assetUrl);\n\n // if (!bucketName) {\n // throw new Error(`Could not extract bucket name from: ${assetUrl}`)\n // }\n\n // const storage = new Storage(credentials ? { keyFilename: credentials } : undefined);\n\n // const filePath = extractFilePathFromUrl(assetUrl, bucketName);\n\n // if (!filePath) {\n // throw new Error(`Could not extract file path from: ${assetUrl}`)\n // }\n\n // const bucket = storage.bucket(bucketName);\n\n // // console.log(`Deleted from GCloud: gs://${bucketName}/${filePath}`);\n\n // return await bucket.file(filePath).delete();\n\n // }\n\n const removeFile = async (\n assetUrl: string,\n thumbnailUrl: string,\n credentials?: string\n ) => {\n try {\n const bucketName = extractBucketName(assetUrl);\n if (!bucketName) throw new Error(`Could not extract bucket name from: ${assetUrl}`);\n\n const filePath = extractFilePathFromUrl(assetUrl, bucketName);\n if (!filePath) throw new Error(`Could not extract file path from: ${assetUrl}`);\n\n let fileThumbnailPath: any\n\n if (thumbnailUrl) {\n fileThumbnailPath = extractFilePathFromUrl(thumbnailUrl, bucketName);\n if (!fileThumbnailPath) throw new Error(`Could not extract file thumbnail path from: ${thumbnailUrl}`);\n }\n\n // Initialize GCS client\n const storage = new Storage(credentials ? { keyFilename: credentials } : undefined);\n const bucket = storage.bucket(bucketName);\n\n // Attempt delete\n await bucket.file(filePath).delete({ ignoreNotFound: true });\n\n if (fileThumbnailPath) {\n // Attempt delete thumbnail\n await bucket.file(fileThumbnailPath).delete({ ignoreNotFound: true });\n }\n\n // console.log(`✅ Deleted from GCloud: gs://${bucketName}/${filePath}`);\n return { success: true, bucketName, filePath, fileThumbnailPath };\n } catch (err: any) {\n // Don’t rethrow — log and return structured error instead\n // console.error(`❌ Failed to delete from GCloud (${assetUrl}):`, err.message || err);\n return { success: false, error: err.message || String(err), assetUrl };\n }\n };\n\n return { uploadFile, removeFile };\n\n};\n"]}
@@ -77,6 +77,7 @@ export type FileUploadProps = FileModuleRef & {
77
77
  files: FileUploadItem[];
78
78
  storageSetup?: FeatureFileStorageOptions;
79
79
  };
80
+ export declare const getBrowserSafeContentType: (incomingMime: string | undefined | null) => string;
80
81
  export declare const getFileCategoryNameByMimeType: (mimeType: string) => FileCategoryName;
81
82
  export declare const FileService: (props: FileServiceProps) => {
82
83
  uploadFiles: ({ field_ref, field_module, tagName, label, refId, refId2, refLabel, refLabel2, remark, description, foldernameDate, files, storageSetup }: FileUploadProps) => Promise<any[]>;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.FileService = exports.getFileCategoryNameByMimeType = exports.fileDataTypes = void 0;
6
+ exports.FileService = exports.getFileCategoryNameByMimeType = exports.getBrowserSafeContentType = exports.fileDataTypes = void 0;
7
7
  const utils_1 = require("../../utils");
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const models_1 = require("../../models");
@@ -52,6 +52,73 @@ const getCreatePayload = (data) => {
52
52
  [`${models_1.ModelFileFields.storage_provider_name}`]: data.storageProviderName,
53
53
  };
54
54
  };
55
+ // compatible to browser mimetype
56
+ const getBrowserSafeContentType = (incomingMime) => {
57
+ if (!incomingMime) {
58
+ return 'application/octet-stream'; // Safe fallback for missing or empty headers
59
+ }
60
+ const cleanMime = incomingMime.toLowerCase().trim();
61
+ // 1. M4A / AAC Audio Container Variations (iOS / Android recording formats)
62
+ const m4aVariations = [
63
+ 'audio/x-m4a',
64
+ 'audio/m4a',
65
+ 'audio/mp4',
66
+ 'audio/aac',
67
+ 'audio/x-aac'
68
+ ];
69
+ if (m4aVariations.includes(cleanMime)) {
70
+ return 'audio/mp4'; // Standard web-streaming type for M4A containers
71
+ }
72
+ // 2. Legacy Mobile Voice Recording Extensions (3GPP and AMR)
73
+ const legacyAudioMobileVariations = [
74
+ 'audio/3gpp',
75
+ 'audio/3gpp2',
76
+ 'audio/3gp',
77
+ 'audio/amr',
78
+ 'audio/amr-wb'
79
+ ];
80
+ if (legacyAudioMobileVariations.includes(cleanMime)) {
81
+ return 'audio/mp4'; // Map to mp4 so browser hardware layers can play them
82
+ }
83
+ // 3. WebM Audio (Commonly sent by desktop Chrome / Firefox microphone inputs)
84
+ const webmAudioVariations = [
85
+ 'audio/x-webm',
86
+ 'audio/webm;codecs=opus'
87
+ ];
88
+ if (webmAudioVariations.includes(cleanMime)) {
89
+ return 'audio/webm';
90
+ }
91
+ // 4. Video Formats (Fixes iOS QuickTime `.mov` and older `.3gp` video links)
92
+ const videoVariations = [
93
+ 'video/quicktime', // iOS recorded .mov files
94
+ 'video/3gpp', // Older Android recorded videos
95
+ 'video/3gpp2',
96
+ 'video/x-m4v' // Apple video format
97
+ ];
98
+ if (videoVariations.includes(cleanMime)) {
99
+ return 'video/mp4'; // Forces standard HTML5 inline web video rendering
100
+ }
101
+ // 5. Modern Image Formats (Fixes iOS `.heic` and camera `.tiff` uploads)
102
+ const imageVariations = [
103
+ 'image/heic',
104
+ 'image/heif',
105
+ 'image/tiff',
106
+ 'image/x-tiff'
107
+ ];
108
+ if (imageVariations.includes(cleanMime)) {
109
+ return 'image/jpeg'; // Ensures browsers show image previews instead of downloading files
110
+ }
111
+ // 6. Generic App Binary Blocks (Stops S3 from forcing downloads if file headers get lost)
112
+ const genericBinaryVariations = [
113
+ 'application/octet-stream',
114
+ 'binary/octet-stream'
115
+ ];
116
+ if (genericBinaryVariations.includes(cleanMime)) {
117
+ return 'audio/mp4'; // Safe default assuming core mobile app asset streams
118
+ }
119
+ return incomingMime; // Keeps standard valid web-types (image/png, audio/mpeg, application/pdf, etc.) intact
120
+ };
121
+ exports.getBrowserSafeContentType = getBrowserSafeContentType;
55
122
  const getFileCategoryNameByMimeType = (mimeType) => {
56
123
  const lower = mimeType.toLowerCase();
57
124
  if (lower.startsWith("image/"))
@@ -1 +1 @@
1
- {"version":3,"file":"FileService.js","sourceRoot":"","sources":["../../../src/services/file/FileService.ts"],"names":[],"mappings":"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","sourcesContent":["import { _, logError, throwError, generateFileThumbnailBuffer, buildFeatureCallbackProps } from \"@/utils\";\n\nimport path from \"path\";\n\nimport {\n FileModel,\n ModelFileFields,\n} from \"@/models\";\n\nimport { FileLocalProviderOptions, FileLocalStorageProvider, FileLocalUploadFileProps } from \"./FileLocalStorageProvider\"\nimport { FileGoogleCloudProviderOptions, FileGoogleCloudStorageProvider, FileGoogleCloudUploadFileProps } from \"./FileGoogleCloudStorageProvider\"\nimport { FileAwsS3ProviderOptions, FileAwsS3StorageProvider, FileAwsS3UploadFileProps } from \"./FileAwsS3StorageProvider\"\nimport { getFileStorageProvider, FileStorageProviderType } from \"./FileStorageProviderRegistry\";\n\nimport { InjectionFieldModuleRef } from \"@/services\"\n\nimport { QueryList, QueryGet } from \"@/schema/common\";\n\nimport { DefaultServiceProps } from \"@/utils\";\n\nimport { getFileSqlRelationMaps, buildSqlSelect, buildSqlLimitOffset, buildSqlOrderBy, getListWithCount } from \"@/lib\";\n\nimport {\n buildFileMainSqlSelect,\n buildFileDefaultSqlSelect\n} from \"@/lib\";\n\nimport { FileImageCompressionOptions, compressImageBuffer } from \"./ImageCompression\";\nexport { FileImageCompressionOptions } from \"./ImageCompression\"\nimport { FileVideoCompressionOptions, compressVideoBuffer } from \"./VideoCompression\";\nimport { FeatureFileStorageOptions, FileStorageHook } from \"@/features\";\nexport { FileVideoCompressionOptions } from \"./VideoCompression\"\n\nexport { FileStorageProviderType } from \"./FileStorageProviderRegistry\";\nexport { FileLocalProviderOptions } from \"./FileLocalStorageProvider\";\nexport { FileGoogleCloudProviderOptions } from \"./FileGoogleCloudStorageProvider\";\nexport { FileAwsS3ProviderOptions } from \"./FileAwsS3StorageProvider\";\n\nexport const fileDataTypes = {\n}\n\nexport type FileModuleRef = InjectionFieldModuleRef\n\nexport type FileDataType = keyof typeof fileDataTypes;\n\nexport type FileServiceProps = DefaultServiceProps & {\n};\n\nexport type FileCategoryName =\n | \"image\"\n | \"video\"\n | \"audio\"\n | \"document\"\n | \"archive\"\n | \"code\"\n | \"other\";\n\n\nexport type FileGetProps = Omit<QueryGet, \"datatypes\"> & {\n id: number,\n // datatypes: FileDataType[]\n};\n\nexport type FileGetUsageSummaryProps = {\n accountId: number,\n};\n\nexport type FileListProps = Omit<QueryList, \"datatypes\"> & {\n // datatypes: FileDataType[]\n}\n\nexport type FileRemoveProps = {\n fileIds: BigInt[],\n // storageProviderOptions: any\n storageSetup?: FeatureFileStorageOptions\n};\n\nexport type File = {\n tagName: string;\n description: string;\n folderPath: string;\n assetUrl: string;\n thumbnailUrl: string;\n assetPath: string;\n fileLabel: string;\n fileName: string;\n contentType: string;\n fileCategoryName: string;\n inputType: string;\n inputFileSizeBytes: number;\n inputFileName: string;\n fileSizeBytes: number;\n fileDurationSeconds: number;\n fileCompressFormat: string;\n storageProviderName: string;\n foldernameDay: number;\n foldernameMonth: number;\n foldernameYear: number;\n batchCode: string;\n referId1: number;\n referId2: number;\n referLabel1: string;\n referLabel2: string;\n remark: string;\n}\n\nexport type FileUploadItem = {\n buffer: Buffer; // Raw file data\n originalName: string; // Client filename\n mimeType: string; // e.g. \"image/png\"\n sizeBytes: number; // File size in bytes\n // providerName?: FileStorageProviderType; // optional: override global provider\n};\n\n\nexport type FileCreateProps = {\n data: File & {\n fieldRef: FileModuleRef[\"field_ref\"],\n fieldModule: FileModuleRef[\"field_module\"]\n }\n}\n\nexport type FileUploadProps = FileModuleRef & {\n description?: string,\n tagName?: string,\n label?: string,\n refId: number\n refId2?: number\n refLabel?: string\n refLabel2?: string\n remark: string\n foldernameDate?: string,\n files: FileUploadItem[]\n storageSetup?: FeatureFileStorageOptions\n}\n\nlet mainSqlSelect = buildFileMainSqlSelect()\nlet defaultSqlSelect = buildFileDefaultSqlSelect()\n\nconst { relationKeys, sqlRelationMaps } = getFileSqlRelationMaps(``)\n\nconst getCreatePayload = (data: FileCreateProps[\"data\"]) => {\n\n return {\n // [`${ModelFileFields.file_id}`]: fileType,\n [`${ModelFileFields.asset_path}`]: data.assetPath,\n [`${ModelFileFields.asset_url}`]: data.assetUrl,\n [`${ModelFileFields.thumbnail_url}`]: data.thumbnailUrl,\n [`${ModelFileFields.batch_code}`]: data.batchCode,\n [`${ModelFileFields.content_type}`]: data.contentType,\n [`${ModelFileFields.file_category_name}`]: data.fileCategoryName,\n [`${ModelFileFields.field_module}`]: data.fieldModule,\n [`${ModelFileFields.field_ref}`]: data.fieldRef,\n [`${ModelFileFields.file_compress_format}`]: data.fileCompressFormat,\n [`${ModelFileFields.file_label}`]: data.fileLabel,\n [`${ModelFileFields.file_name}`]: data.fileName,\n [`${ModelFileFields.file_size_bytes}`]: data.fileSizeBytes,\n [`${ModelFileFields.file_duration_seconds}`]: data.fileDurationSeconds,\n [`${ModelFileFields.tag_name}`]: data.tagName,\n [`${ModelFileFields.description}`]: data.description,\n [`${ModelFileFields.foldername_day}`]: Number(data.foldernameDay),\n [`${ModelFileFields.foldername_month}`]: Number(data.foldernameMonth),\n [`${ModelFileFields.foldername_year}`]: Number(data.foldernameYear),\n [`${ModelFileFields.input_file_name}`]: data.inputFileName,\n [`${ModelFileFields.input_file_size_bytes}`]: data.inputFileSizeBytes,\n [`${ModelFileFields.input_type}`]: data.inputType,\n [`${ModelFileFields.refer_id_1}`]: data.referId1,\n [`${ModelFileFields.refer_id_2}`]: data.referId2,\n [`${ModelFileFields.refer_label_1}`]: data.referLabel1,\n [`${ModelFileFields.refer_label_2}`]: data.referLabel2,\n [`${ModelFileFields.remark}`]: data.remark,\n [`${ModelFileFields.storage_provider_name}`]: data.storageProviderName,\n }\n\n}\n\nexport const getFileCategoryNameByMimeType = (mimeType: string): FileCategoryName => {\n const lower = mimeType.toLowerCase();\n\n if (lower.startsWith(\"image/\")) return \"image\";\n if (lower.startsWith(\"video/\")) return \"video\";\n if (lower.startsWith(\"audio/\")) return \"audio\";\n\n // Edge-case audio MIME types\n if ([\"application/ogg\"].includes(lower)) return \"audio\";\n\n if (\n lower.startsWith(\"text/\") ||\n [\n \"application/pdf\",\n \"application/msword\",\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n \"application/vnd.ms-excel\",\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n \"application/vnd.ms-powerpoint\",\n \"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\n \"application/rtf\",\n ].includes(lower)\n ) {\n return \"document\";\n }\n\n if (\n [\n \"application/zip\",\n \"application/x-7z-compressed\",\n \"application/x-rar-compressed\",\n \"application/x-tar\",\n \"application/gzip\",\n ].includes(lower)\n ) {\n return \"archive\";\n }\n\n if (\n lower.startsWith(\"application/json\") ||\n lower.startsWith(\"application/javascript\") ||\n lower.startsWith(\"text/html\") ||\n lower.startsWith(\"text/css\") ||\n lower.startsWith(\"text/x-python\") ||\n lower.startsWith(\"text/x-c\") ||\n lower.startsWith(\"text/x-java\")\n ) {\n return \"code\";\n }\n\n return \"other\";\n};\n\nexport const FileService = (props: FileServiceProps) => {\n\n const {\n ...rest\n } = props\n\n const fileModel = FileModel({ ...rest })\n\n const fileGoogleCloudStorageProvider = FileGoogleCloudStorageProvider({\n basePath: ``,\n bucketName: ``\n })\n\n const fileAwsS3StorageProvider = FileAwsS3StorageProvider({\n basePath: ``,\n bucketName: ``\n })\n\n const fileLocalStorageProvider = FileLocalStorageProvider({})\n\n const thumbnailOptions = {\n suffix: \"-thumb\",\n ext: \"jpg\",\n mimeType: \"image/jpeg\",\n }\n\n const initBatchCode = () => {\n return `${Date.now()}_${_.random(0, 999)}`;\n }\n\n const getStorageSetup = async (overrideStorageSetup?: FeatureFileStorageOptions) => {\n\n const hookSetup = overrideStorageSetup ?\n overrideStorageSetup\n :\n await FileStorageHook.onSetup()\n\n if (hookSetup.storageType === \"local\") {\n return {\n storageConfiguration: hookSetup.storageConfiguration,\n storageProviderName: hookSetup.storageType,\n storageProviderOptions: {\n // basePath: `${config.FILE_STORAGE_LOCAL_BASE_PATH}`,\n basePath: `${hookSetup.localStorageOptions.basePath}`,\n // publicBaseUrl: `${config.FILE_STORAGE_LOCAL_BASE_URL}`,\n publicBaseUrl: `${hookSetup.localStorageOptions.baseUrl}`,\n // skipFoldernameByModuleRef: Boolean(config.FILE_STORAGE_LOCAL_SKIP_FOLDERNAME_MODULE_REF),\n skipFoldernameByModuleRef: Boolean(hookSetup.localStorageOptions.skipFolderNameModuleRef),\n // skipFoldernameByDate: Boolean(config.FILE_STORAGE_LOCAL_SKIP_FOLDERNAME_YEAR_MONTH)\n skipFoldernameByDate: Boolean(hookSetup.localStorageOptions.skipFolderNameYearMonth)\n }\n }\n }\n\n if (hookSetup.storageType === \"gcloud\") {\n return {\n storageConfiguration: hookSetup.storageConfiguration,\n storageProviderName: hookSetup.storageType,\n storageProviderOptions: {\n // basePath: `${config.FILE_STORAGE_GCLOUD_BASE_PATH}`,\n basePath: `${hookSetup.gcloudStorageOptions.basePath}`,\n // publicBaseUrl: `${config.FILE_STORAGE_GCLOUD_BASE_URL}`,\n publicBaseUrl: `${hookSetup.gcloudStorageOptions.baseUrl}`,\n // bucketName: `${config.FILE_STORAGE_GCLOUD_BUCKET_NAME}`,\n bucketName: `${hookSetup.gcloudStorageOptions.bucketName}`,\n // credentials: `${path.resolve(process.cwd(), `${config.FILE_STORAGE_GCLOUD_CREDENTIAL_PATH}`)}`,\n credentials: `${path.resolve(process.cwd(), `${hookSetup.gcloudStorageOptions.credentialPath}`)}`,\n // skipFoldernameByModuleRef: Boolean(config.FILE_STORAGE_GCLOUD_SKIP_FOLDERNAME_MODULE_REF),\n skipFoldernameByModuleRef: Boolean(hookSetup.gcloudStorageOptions.skipFolderNameModuleRef),\n // skipFoldernameByDate: Boolean(config.FILE_STORAGE_GCLOUD_SKIP_FOLDERNAME_YEAR_MONTH)\n skipFoldernameByDate: Boolean(hookSetup.gcloudStorageOptions.skipFolderNameYearMonth)\n }\n\n }\n }\n\n if (hookSetup.storageType === \"aws\") {\n return {\n storageConfiguration: hookSetup.storageConfiguration,\n storageProviderName: hookSetup.storageType,\n storageProviderOptions: {\n basePath: `${hookSetup.awsStorageOptions.basePath}`,\n publicBaseUrl: `${hookSetup.awsStorageOptions.baseUrl}`,\n bucketName: `${hookSetup.awsStorageOptions.bucketName}`,\n region: hookSetup.awsStorageOptions?.region ?? \"\",\n credentials: {\n accessKeyId: hookSetup.awsStorageOptions.credentials.accessKeyId,\n secretAccessKey: hookSetup.awsStorageOptions.credentials.secretAccessKey,\n },\n skipFoldernameByModuleRef: Boolean(hookSetup.awsStorageOptions.skipFolderNameModuleRef),\n skipFoldernameByDate: Boolean(hookSetup.awsStorageOptions.skipFolderNameYearMonth)\n }\n\n }\n }\n\n throw new Error(\"Unsupported storage type\")\n }\n\n const uploadFiles = async ({\n field_ref = \"item\",\n field_module = \"item\",\n tagName,\n label,\n refId,\n refId2,\n refLabel,\n refLabel2,\n remark,\n description,\n foldernameDate,\n files = [],\n storageSetup\n }: FileUploadProps) => {\n\n const {\n storageProviderName,\n storageProviderOptions,\n storageConfiguration\n } = await getStorageSetup(storageSetup)\n\n // get the correct provider\n const provider = await getFileStorageProvider(storageProviderName, storageProviderOptions);\n\n // Image Compression\n const imageCompressionOptions: FileImageCompressionOptions | undefined\n = storageConfiguration?.imageMaxWidth && storageConfiguration?.imageMaxWidth\n ? {\n maxWidth: Number(storageConfiguration.imageMaxWidth),\n quality: Number(storageConfiguration.imageQuality),\n }\n : undefined;\n\n // Video Compression\n const videoCompressionOptions: FileVideoCompressionOptions | undefined =\n storageConfiguration?.videoCRF &&\n storageConfiguration?.videoPreset &&\n storageConfiguration?.videoResolution\n ? {\n crf: Number(storageConfiguration.videoCRF),\n preset: storageConfiguration.videoPreset as FileVideoCompressionOptions[\"preset\"],\n resolution: Number(storageConfiguration.videoResolution),\n }\n : undefined;\n\n const allResponses = []\n\n const batchCode = initBatchCode();\n\n const fileLabel = label ?? \"\"\n const referId1 = refId ?? 0\n const referId2 = refId2 ?? 0\n const referLabel1 = refLabel ?? \"\"\n const referLabel2 = refLabel2 ?? \"\"\n const fileRemark = remark ?? \"\"\n\n for (const file of files) {\n\n let bufferToUpload = file.buffer;\n let mimeType = file.mimeType ?? \"\"\n let sizeBytes = file?.sizeBytes\n let fileOriginalName = file.originalName;\n\n let outputSizeBytes = sizeBytes // output file size\n let fileCompressFormat = `` // output image compress\n\n const fileCategoryName = getFileCategoryNameByMimeType(mimeType)\n\n // const ext = file.originalName?.split(\".\").pop()?.toLowerCase() ?? \"\";\n\n // Image :: Only compress if image and options provided\n if (fileCategoryName === \"image\" && imageCompressionOptions) {\n const compressed = await compressImageBuffer(\n bufferToUpload,\n mimeType,\n imageCompressionOptions\n );\n\n fileCompressFormat = compressed.compressFormat,\n bufferToUpload = compressed.buffer;\n outputSizeBytes = compressed.sizeBytes; // update the file size\n }\n\n // Vide :: Only compress if video and options provided\n if (fileCategoryName === \"video\" && videoCompressionOptions) {\n const compressed = await compressVideoBuffer(\n bufferToUpload,\n mimeType,\n videoCompressionOptions\n );\n\n fileCompressFormat = compressed.compressFormat,\n bufferToUpload = compressed.buffer;\n outputSizeBytes = compressed.sizeBytes; // update the file size\n }\n\n // generate thumbnail buffer\n const bufferThumbnail = await generateFileThumbnailBuffer(bufferToUpload, mimeType)\n\n // Call the consumer hook, if registered\n if (FileStorageHook.onStartUpload) {\n\n await FileStorageHook.onStartUpload(buildFeatureCallbackProps({\n defaultServiceProps: rest,\n callbackParams: {\n fieldRef: field_ref,\n fieldModule: field_module,\n tagName,\n label,\n refId,\n refId2,\n refLabel,\n refLabel2,\n remark,\n description,\n foldernameDate,\n file,\n storageProviderName,\n storageProviderOptions,\n fileCategoryName,\n batchCode,\n mimeType,\n bufferFilebuffer: bufferToUpload,\n bufferFileThumbnail: bufferThumbnail?.buffer,\n outputSizeBytes,\n fileCompressFormat: fileCompressFormat ? JSON.parse(fileCompressFormat) : \"\",\n imageCompressionOptions,\n videoCompressionOptions\n }\n }))\n }\n\n // upload using the provider - buffer\n const uploadResult = await provider.uploadFile({\n field_ref,\n field_module,\n buffer: bufferToUpload,\n bufferThumbnail: bufferThumbnail.buffer,\n thumbnailOptions,\n ...(foldernameDate ? { foldernameDate } : {}),\n mimeType,\n fileName: fileOriginalName\n } as FileModuleRef & (\n FileLocalUploadFileProps |\n FileGoogleCloudUploadFileProps |\n FileAwsS3UploadFileProps\n ));\n\n const fieldRef = field_ref\n const fieldModule = field_module\n\n const fileName = uploadResult?.filename ?? \"\"\n const contentType = mimeType ?? \"\"\n const folderPath = uploadResult.assetPath ?? \"\"\n const assetUrl = uploadResult.assetUrl ?? \"\"\n const thumbnailUrl = uploadResult?.thumbnailUrl ?? \"\"\n const assetPath = uploadResult.assetPath ?? \"\"\n\n const fileDurationSeconds = bufferThumbnail?.durationSeconds ?? 0\n\n const inputType = `buffer`\n const inputFileSizeBytes = sizeBytes ?? 0\n const inputFileName = fileOriginalName ?? \"\"\n\n const fileSizeBytes = outputSizeBytes ?? 0\n // const fileCompressFormat = ``\n\n const foldernameDay = uploadResult?.folderName?.day ?? \"\"\n const foldernameMonth = uploadResult?.folderName?.month ?? \"\"\n const foldernameYear = uploadResult?.folderName?.year ?? \"\"\n\n const payload: FileCreateProps = {\n data: {\n fieldRef,\n fieldModule,\n tagName,\n description,\n remark: fileRemark,\n folderPath,\n assetUrl,\n thumbnailUrl,\n assetPath,\n fileLabel,\n fileName,\n fileCategoryName,\n contentType,\n inputType,\n inputFileSizeBytes,\n inputFileName,\n fileSizeBytes,\n fileDurationSeconds,\n fileCompressFormat,\n storageProviderName,\n foldernameDay,\n foldernameMonth,\n foldernameYear,\n batchCode,\n referId1,\n referId2,\n referLabel1,\n referLabel2\n } as FileCreateProps[\"data\"],\n };\n\n let responseFile = await createFile(payload);\n\n // Call the consumer hook, if registered\n if (FileStorageHook.onSuccessUpload) {\n await FileStorageHook.onSuccessUpload(buildFeatureCallbackProps({\n defaultServiceProps: rest,\n callbackParams: {\n fileId: Number(responseFile?.file_id),\n fileThumbnailUrl: thumbnailUrl,\n fileAssetUrl: assetUrl,\n fileDurationSeconds,\n fieldRef: field_ref,\n fieldModule: field_module,\n tagName,\n label,\n refId,\n refId2,\n refLabel,\n refLabel2,\n remark,\n description,\n foldernameDate,\n file,\n storageProviderName,\n storageProviderOptions,\n fileCategoryName,\n batchCode,\n mimeType,\n bufferFilebuffer: bufferToUpload,\n bufferFileThumbnail: bufferThumbnail.buffer,\n outputSizeBytes,\n fileCompressFormat: fileCompressFormat ? JSON.parse(fileCompressFormat) : \"\",\n imageCompressionOptions,\n videoCompressionOptions\n }\n }))\n }\n\n allResponses.push(responseFile)\n }\n\n return allResponses\n\n }\n\n // private\n const createFile = async ({ data }: FileCreateProps) => {\n\n const _data = getCreatePayload(data)\n\n if (!_data) {\n throw new Error(`Invalid create file payload: ${JSON.stringify(_data)}`);\n }\n\n const response = await fileModel.create({ data: _data })\n\n const newFileId = response?.file_id ?? \"\"\n\n return newFileId ? await getFile({ id: Number(newFileId) }) : null\n\n }\n\n const getFile = async ({ id }: FileGetProps) => {\n\n let { data } = await listFiles({\n limit: 1,\n offset: 0,\n filters: [{ field: `${ModelFileFields.file_id}`, operator: \"=\", value: id }],\n sortfield: `${ModelFileFields.file_id}`,\n sortorder: \"ASC\"\n })\n\n return data[0] ?? null;\n\n };\n\n const listFiles = async ({ limit, offset, filters = [], sortfield, sortorder }: FileListProps) => {\n\n let sqlSelect: string[] = []\n let sqlRelation: string[] = []\n let sqlGroupBy: string[] = []\n\n let sqlSelectAgg: string[] = []\n let sqlRelationAgg: string[] = []\n\n sqlSelect = [\n buildSqlSelect(``, mainSqlSelect),\n buildSqlSelect(``, defaultSqlSelect)\n ]\n\n sqlRelation = [\n sqlRelationMaps.creator,\n sqlRelationMaps.updater\n ]\n\n // sqlRelationAgg = []\n\n sqlGroupBy = [\n ...Object.keys(mainSqlSelect),\n ...Object.keys(defaultSqlSelect)\n ]\n\n let filterColumns = {\n ...mainSqlSelect,\n ...defaultSqlSelect\n }\n\n let sqlWhere = [\n `mainfile.isdelete = false`,\n `mainfile.istrash = false`,\n // `LOWER(mainfile.doc_type) = LOWER('${documentTypeKey}')`\n ]\n\n let sqlOrderby = buildSqlOrderBy(sortfield, sortorder)\n let sqlLimitOffset = buildSqlLimitOffset(limit, offset)\n\n // get the listing data & count\n const { data, total } = await getListWithCount({\n model: fileModel,\n tableName: \"files\",\n mainAlias: \"mainfile\",\n countKey: `${ModelFileFields.file_id}`,\n accountId: rest.accountId,\n sqlRelationMaps,\n filters,\n filterColumns,\n sqlSelect,\n sqlSelectAgg,\n sqlRelation,\n sqlRelationAgg,\n sqlWhere,\n sqlGroupBy,\n sqlOrderby,\n sqlLimitOffset\n })\n\n const response = {\n data,\n total\n }\n\n return response\n\n };\n\n const removeFiles = async ({ fileIds, storageSetup }: FileRemoveProps) => {\n\n const {\n // storageProviderName,\n storageProviderOptions\n } = await getStorageSetup(storageSetup)\n\n if (!fileIds.length) throwError('fileIds is required');\n\n const filesToDelete = await fileModel.list({\n where: {\n file_id: { in: fileIds }\n }\n });\n\n // console.log('filesToDelete', filesToDelete)\n\n let providerResponse: any[] = []\n\n // 2️⃣ Delete the physical files\n for (const file of filesToDelete) {\n\n // check the provider to choose delete method\n const storageProviderName = file.storage_provider_name as FileStorageProviderType\n const assetUrl = file.asset_url\n const thumbnailUrl = file.thumbnail_url ?? \"\"\n const assetPath = file.asset_path\n\n if (storageProviderName === \"local\" && assetPath) {\n\n try {\n providerResponse.push(\n await fileLocalStorageProvider.removeFile(assetPath, thumbnailOptions)\n )\n } catch (err) {\n providerResponse.push(\n `Failed to delete from Local: ${assetUrl}`\n )\n }\n\n }\n\n if (storageProviderName === \"gcloud\" && assetUrl) {\n\n try {\n providerResponse.push(\n await fileGoogleCloudStorageProvider.removeFile(assetUrl, thumbnailUrl, storageProviderOptions.credentials as any)\n )\n } catch (err) {\n providerResponse.push(\n `Failed to delete from GCloud: ${assetUrl}`\n )\n }\n\n }\n\n if (storageProviderName === \"aws\" && assetUrl) {\n\n try {\n providerResponse.push(\n await fileAwsS3StorageProvider.removeFile(assetUrl, thumbnailUrl)\n )\n } catch (err) {\n providerResponse.push(\n `Failed to delete from Aws S3: ${assetUrl}`\n )\n }\n\n }\n\n }\n\n // remove files\n const response = await fileModel.remove({ where: { [`${ModelFileFields.file_id}`]: { in: fileIds } } });\n\n return {\n files: response,\n providerResponse\n }\n };\n\n const getFileUsageSummary = async ({ accountId = 0 }: FileGetUsageSummaryProps) => {\n\n const summaryCount = await fileModel.aggregate({\n field: `file_id`,\n operation: `count`,\n where: {\n [`${ModelFileFields.accountid}`]: accountId,\n [`${ModelFileFields.istrash}`]: false,\n [`${ModelFileFields.isdelete}`]: false,\n }\n });\n\n const summarySize = await fileModel.aggregate({\n field: `file_size_bytes`,\n operation: `sum`,\n where: {\n [`${ModelFileFields.accountid}`]: accountId,\n [`${ModelFileFields.istrash}`]: false,\n [`${ModelFileFields.isdelete}`]: false,\n }\n });\n\n const totalFiles = summaryCount ?? 0;\n const totalBytes = summarySize ?? 0;\n // const totalFiles = summary._count.id;\n\n // Optional: convert bytes to MB or GB\n const totalMB = totalBytes / (1024 * 1024);\n const totalGB = totalBytes / (1024 * 1024 * 1024);\n\n return {\n totalFiles,\n totalBytes,\n totalMB: parseFloat(totalMB.toFixed(2)), // now decimal\n totalGB: parseFloat(totalGB.toFixed(2)), // now decimal\n };\n }\n\n // const getDataTypes = () => {\n // return Object.values(fileDataTypes);\n // }\n\n return {\n uploadFiles,\n // createFile,\n // updateFile,\n getFile,\n listFiles,\n removeFiles,\n // getDataTypes,\n getFileUsageSummary\n }\n\n}\n\n"]}
1
+ {"version":3,"file":"FileService.js","sourceRoot":"","sources":["../../../src/services/file/FileService.ts"],"names":[],"mappings":"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","sourcesContent":["import { _, logError, throwError, generateFileThumbnailBuffer, buildFeatureCallbackProps } from \"@/utils\";\n\nimport path from \"path\";\n\nimport {\n FileModel,\n ModelFileFields,\n} from \"@/models\";\n\nimport { FileLocalProviderOptions, FileLocalStorageProvider, FileLocalUploadFileProps } from \"./FileLocalStorageProvider\"\nimport { FileGoogleCloudProviderOptions, FileGoogleCloudStorageProvider, FileGoogleCloudUploadFileProps } from \"./FileGoogleCloudStorageProvider\"\nimport { FileAwsS3ProviderOptions, FileAwsS3StorageProvider, FileAwsS3UploadFileProps } from \"./FileAwsS3StorageProvider\"\nimport { getFileStorageProvider, FileStorageProviderType } from \"./FileStorageProviderRegistry\";\n\nimport { InjectionFieldModuleRef } from \"@/services\"\n\nimport { QueryList, QueryGet } from \"@/schema/common\";\n\nimport { DefaultServiceProps } from \"@/utils\";\n\nimport { getFileSqlRelationMaps, buildSqlSelect, buildSqlLimitOffset, buildSqlOrderBy, getListWithCount } from \"@/lib\";\n\nimport {\n buildFileMainSqlSelect,\n buildFileDefaultSqlSelect\n} from \"@/lib\";\n\nimport { FileImageCompressionOptions, compressImageBuffer } from \"./ImageCompression\";\nexport { FileImageCompressionOptions } from \"./ImageCompression\"\nimport { FileVideoCompressionOptions, compressVideoBuffer } from \"./VideoCompression\";\nimport { FeatureFileStorageOptions, FileStorageHook } from \"@/features\";\nexport { FileVideoCompressionOptions } from \"./VideoCompression\"\n\nexport { FileStorageProviderType } from \"./FileStorageProviderRegistry\";\nexport { FileLocalProviderOptions } from \"./FileLocalStorageProvider\";\nexport { FileGoogleCloudProviderOptions } from \"./FileGoogleCloudStorageProvider\";\nexport { FileAwsS3ProviderOptions } from \"./FileAwsS3StorageProvider\";\n\nexport const fileDataTypes = {\n}\n\nexport type FileModuleRef = InjectionFieldModuleRef\n\nexport type FileDataType = keyof typeof fileDataTypes;\n\nexport type FileServiceProps = DefaultServiceProps & {\n};\n\nexport type FileCategoryName =\n | \"image\"\n | \"video\"\n | \"audio\"\n | \"document\"\n | \"archive\"\n | \"code\"\n | \"other\";\n\n\nexport type FileGetProps = Omit<QueryGet, \"datatypes\"> & {\n id: number,\n // datatypes: FileDataType[]\n};\n\nexport type FileGetUsageSummaryProps = {\n accountId: number,\n};\n\nexport type FileListProps = Omit<QueryList, \"datatypes\"> & {\n // datatypes: FileDataType[]\n}\n\nexport type FileRemoveProps = {\n fileIds: BigInt[],\n // storageProviderOptions: any\n storageSetup?: FeatureFileStorageOptions\n};\n\nexport type File = {\n tagName: string;\n description: string;\n folderPath: string;\n assetUrl: string;\n thumbnailUrl: string;\n assetPath: string;\n fileLabel: string;\n fileName: string;\n contentType: string;\n fileCategoryName: string;\n inputType: string;\n inputFileSizeBytes: number;\n inputFileName: string;\n fileSizeBytes: number;\n fileDurationSeconds: number;\n fileCompressFormat: string;\n storageProviderName: string;\n foldernameDay: number;\n foldernameMonth: number;\n foldernameYear: number;\n batchCode: string;\n referId1: number;\n referId2: number;\n referLabel1: string;\n referLabel2: string;\n remark: string;\n}\n\nexport type FileUploadItem = {\n buffer: Buffer; // Raw file data\n originalName: string; // Client filename\n mimeType: string; // e.g. \"image/png\"\n sizeBytes: number; // File size in bytes\n // providerName?: FileStorageProviderType; // optional: override global provider\n};\n\n\nexport type FileCreateProps = {\n data: File & {\n fieldRef: FileModuleRef[\"field_ref\"],\n fieldModule: FileModuleRef[\"field_module\"]\n }\n}\n\nexport type FileUploadProps = FileModuleRef & {\n description?: string,\n tagName?: string,\n label?: string,\n refId: number\n refId2?: number\n refLabel?: string\n refLabel2?: string\n remark: string\n foldernameDate?: string,\n files: FileUploadItem[]\n storageSetup?: FeatureFileStorageOptions\n}\n\nlet mainSqlSelect = buildFileMainSqlSelect()\nlet defaultSqlSelect = buildFileDefaultSqlSelect()\n\nconst { relationKeys, sqlRelationMaps } = getFileSqlRelationMaps(``)\n\nconst getCreatePayload = (data: FileCreateProps[\"data\"]) => {\n\n return {\n // [`${ModelFileFields.file_id}`]: fileType,\n [`${ModelFileFields.asset_path}`]: data.assetPath,\n [`${ModelFileFields.asset_url}`]: data.assetUrl,\n [`${ModelFileFields.thumbnail_url}`]: data.thumbnailUrl,\n [`${ModelFileFields.batch_code}`]: data.batchCode,\n [`${ModelFileFields.content_type}`]: data.contentType,\n [`${ModelFileFields.file_category_name}`]: data.fileCategoryName,\n [`${ModelFileFields.field_module}`]: data.fieldModule,\n [`${ModelFileFields.field_ref}`]: data.fieldRef,\n [`${ModelFileFields.file_compress_format}`]: data.fileCompressFormat,\n [`${ModelFileFields.file_label}`]: data.fileLabel,\n [`${ModelFileFields.file_name}`]: data.fileName,\n [`${ModelFileFields.file_size_bytes}`]: data.fileSizeBytes,\n [`${ModelFileFields.file_duration_seconds}`]: data.fileDurationSeconds,\n [`${ModelFileFields.tag_name}`]: data.tagName,\n [`${ModelFileFields.description}`]: data.description,\n [`${ModelFileFields.foldername_day}`]: Number(data.foldernameDay),\n [`${ModelFileFields.foldername_month}`]: Number(data.foldernameMonth),\n [`${ModelFileFields.foldername_year}`]: Number(data.foldernameYear),\n [`${ModelFileFields.input_file_name}`]: data.inputFileName,\n [`${ModelFileFields.input_file_size_bytes}`]: data.inputFileSizeBytes,\n [`${ModelFileFields.input_type}`]: data.inputType,\n [`${ModelFileFields.refer_id_1}`]: data.referId1,\n [`${ModelFileFields.refer_id_2}`]: data.referId2,\n [`${ModelFileFields.refer_label_1}`]: data.referLabel1,\n [`${ModelFileFields.refer_label_2}`]: data.referLabel2,\n [`${ModelFileFields.remark}`]: data.remark,\n [`${ModelFileFields.storage_provider_name}`]: data.storageProviderName,\n }\n\n}\n\n// compatible to browser mimetype\nexport const getBrowserSafeContentType = (incomingMime: string | undefined | null): string => {\n\n if (!incomingMime) {\n return 'application/octet-stream'; // Safe fallback for missing or empty headers\n }\n\n const cleanMime = incomingMime.toLowerCase().trim();\n\n // 1. M4A / AAC Audio Container Variations (iOS / Android recording formats)\n const m4aVariations: string[] = [\n 'audio/x-m4a',\n 'audio/m4a',\n 'audio/mp4',\n 'audio/aac',\n 'audio/x-aac'\n ];\n if (m4aVariations.includes(cleanMime)) {\n return 'audio/mp4'; // Standard web-streaming type for M4A containers\n }\n\n // 2. Legacy Mobile Voice Recording Extensions (3GPP and AMR)\n const legacyAudioMobileVariations: string[] = [\n 'audio/3gpp',\n 'audio/3gpp2',\n 'audio/3gp',\n 'audio/amr',\n 'audio/amr-wb'\n ];\n if (legacyAudioMobileVariations.includes(cleanMime)) {\n return 'audio/mp4'; // Map to mp4 so browser hardware layers can play them\n }\n\n // 3. WebM Audio (Commonly sent by desktop Chrome / Firefox microphone inputs)\n const webmAudioVariations: string[] = [\n 'audio/x-webm',\n 'audio/webm;codecs=opus'\n ];\n if (webmAudioVariations.includes(cleanMime)) {\n return 'audio/webm';\n }\n\n // 4. Video Formats (Fixes iOS QuickTime `.mov` and older `.3gp` video links)\n const videoVariations: string[] = [\n 'video/quicktime', // iOS recorded .mov files\n 'video/3gpp', // Older Android recorded videos\n 'video/3gpp2',\n 'video/x-m4v' // Apple video format\n ];\n if (videoVariations.includes(cleanMime)) {\n return 'video/mp4'; // Forces standard HTML5 inline web video rendering\n }\n\n // 5. Modern Image Formats (Fixes iOS `.heic` and camera `.tiff` uploads)\n const imageVariations: string[] = [\n 'image/heic',\n 'image/heif',\n 'image/tiff',\n 'image/x-tiff'\n ];\n if (imageVariations.includes(cleanMime)) {\n return 'image/jpeg'; // Ensures browsers show image previews instead of downloading files\n }\n\n // 6. Generic App Binary Blocks (Stops S3 from forcing downloads if file headers get lost)\n const genericBinaryVariations: string[] = [\n 'application/octet-stream',\n 'binary/octet-stream'\n ];\n if (genericBinaryVariations.includes(cleanMime)) {\n return 'audio/mp4'; // Safe default assuming core mobile app asset streams\n }\n\n return incomingMime; // Keeps standard valid web-types (image/png, audio/mpeg, application/pdf, etc.) intact\n};\n\nexport const getFileCategoryNameByMimeType = (mimeType: string): FileCategoryName => {\n const lower = mimeType.toLowerCase();\n\n if (lower.startsWith(\"image/\")) return \"image\";\n if (lower.startsWith(\"video/\")) return \"video\";\n if (lower.startsWith(\"audio/\")) return \"audio\";\n\n // Edge-case audio MIME types\n if ([\"application/ogg\"].includes(lower)) return \"audio\";\n\n if (\n lower.startsWith(\"text/\") ||\n [\n \"application/pdf\",\n \"application/msword\",\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n \"application/vnd.ms-excel\",\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n \"application/vnd.ms-powerpoint\",\n \"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\n \"application/rtf\",\n ].includes(lower)\n ) {\n return \"document\";\n }\n\n if (\n [\n \"application/zip\",\n \"application/x-7z-compressed\",\n \"application/x-rar-compressed\",\n \"application/x-tar\",\n \"application/gzip\",\n ].includes(lower)\n ) {\n return \"archive\";\n }\n\n if (\n lower.startsWith(\"application/json\") ||\n lower.startsWith(\"application/javascript\") ||\n lower.startsWith(\"text/html\") ||\n lower.startsWith(\"text/css\") ||\n lower.startsWith(\"text/x-python\") ||\n lower.startsWith(\"text/x-c\") ||\n lower.startsWith(\"text/x-java\")\n ) {\n return \"code\";\n }\n\n return \"other\";\n};\n\nexport const FileService = (props: FileServiceProps) => {\n\n const {\n ...rest\n } = props\n\n const fileModel = FileModel({ ...rest })\n\n const fileGoogleCloudStorageProvider = FileGoogleCloudStorageProvider({\n basePath: ``,\n bucketName: ``\n })\n\n const fileAwsS3StorageProvider = FileAwsS3StorageProvider({\n basePath: ``,\n bucketName: ``\n })\n\n const fileLocalStorageProvider = FileLocalStorageProvider({})\n\n const thumbnailOptions = {\n suffix: \"-thumb\",\n ext: \"jpg\",\n mimeType: \"image/jpeg\",\n }\n\n const initBatchCode = () => {\n return `${Date.now()}_${_.random(0, 999)}`;\n }\n\n const getStorageSetup = async (overrideStorageSetup?: FeatureFileStorageOptions) => {\n\n const hookSetup = overrideStorageSetup ?\n overrideStorageSetup\n :\n await FileStorageHook.onSetup()\n\n if (hookSetup.storageType === \"local\") {\n return {\n storageConfiguration: hookSetup.storageConfiguration,\n storageProviderName: hookSetup.storageType,\n storageProviderOptions: {\n // basePath: `${config.FILE_STORAGE_LOCAL_BASE_PATH}`,\n basePath: `${hookSetup.localStorageOptions.basePath}`,\n // publicBaseUrl: `${config.FILE_STORAGE_LOCAL_BASE_URL}`,\n publicBaseUrl: `${hookSetup.localStorageOptions.baseUrl}`,\n // skipFoldernameByModuleRef: Boolean(config.FILE_STORAGE_LOCAL_SKIP_FOLDERNAME_MODULE_REF),\n skipFoldernameByModuleRef: Boolean(hookSetup.localStorageOptions.skipFolderNameModuleRef),\n // skipFoldernameByDate: Boolean(config.FILE_STORAGE_LOCAL_SKIP_FOLDERNAME_YEAR_MONTH)\n skipFoldernameByDate: Boolean(hookSetup.localStorageOptions.skipFolderNameYearMonth)\n }\n }\n }\n\n if (hookSetup.storageType === \"gcloud\") {\n return {\n storageConfiguration: hookSetup.storageConfiguration,\n storageProviderName: hookSetup.storageType,\n storageProviderOptions: {\n // basePath: `${config.FILE_STORAGE_GCLOUD_BASE_PATH}`,\n basePath: `${hookSetup.gcloudStorageOptions.basePath}`,\n // publicBaseUrl: `${config.FILE_STORAGE_GCLOUD_BASE_URL}`,\n publicBaseUrl: `${hookSetup.gcloudStorageOptions.baseUrl}`,\n // bucketName: `${config.FILE_STORAGE_GCLOUD_BUCKET_NAME}`,\n bucketName: `${hookSetup.gcloudStorageOptions.bucketName}`,\n // credentials: `${path.resolve(process.cwd(), `${config.FILE_STORAGE_GCLOUD_CREDENTIAL_PATH}`)}`,\n credentials: `${path.resolve(process.cwd(), `${hookSetup.gcloudStorageOptions.credentialPath}`)}`,\n // skipFoldernameByModuleRef: Boolean(config.FILE_STORAGE_GCLOUD_SKIP_FOLDERNAME_MODULE_REF),\n skipFoldernameByModuleRef: Boolean(hookSetup.gcloudStorageOptions.skipFolderNameModuleRef),\n // skipFoldernameByDate: Boolean(config.FILE_STORAGE_GCLOUD_SKIP_FOLDERNAME_YEAR_MONTH)\n skipFoldernameByDate: Boolean(hookSetup.gcloudStorageOptions.skipFolderNameYearMonth)\n }\n\n }\n }\n\n if (hookSetup.storageType === \"aws\") {\n return {\n storageConfiguration: hookSetup.storageConfiguration,\n storageProviderName: hookSetup.storageType,\n storageProviderOptions: {\n basePath: `${hookSetup.awsStorageOptions.basePath}`,\n publicBaseUrl: `${hookSetup.awsStorageOptions.baseUrl}`,\n bucketName: `${hookSetup.awsStorageOptions.bucketName}`,\n region: hookSetup.awsStorageOptions?.region ?? \"\",\n credentials: {\n accessKeyId: hookSetup.awsStorageOptions.credentials.accessKeyId,\n secretAccessKey: hookSetup.awsStorageOptions.credentials.secretAccessKey,\n },\n skipFoldernameByModuleRef: Boolean(hookSetup.awsStorageOptions.skipFolderNameModuleRef),\n skipFoldernameByDate: Boolean(hookSetup.awsStorageOptions.skipFolderNameYearMonth)\n }\n\n }\n }\n\n throw new Error(\"Unsupported storage type\")\n }\n\n const uploadFiles = async ({\n field_ref = \"item\",\n field_module = \"item\",\n tagName,\n label,\n refId,\n refId2,\n refLabel,\n refLabel2,\n remark,\n description,\n foldernameDate,\n files = [],\n storageSetup\n }: FileUploadProps) => {\n\n const {\n storageProviderName,\n storageProviderOptions,\n storageConfiguration\n } = await getStorageSetup(storageSetup)\n\n // get the correct provider\n const provider = await getFileStorageProvider(storageProviderName, storageProviderOptions);\n\n // Image Compression\n const imageCompressionOptions: FileImageCompressionOptions | undefined\n = storageConfiguration?.imageMaxWidth && storageConfiguration?.imageMaxWidth\n ? {\n maxWidth: Number(storageConfiguration.imageMaxWidth),\n quality: Number(storageConfiguration.imageQuality),\n }\n : undefined;\n\n // Video Compression\n const videoCompressionOptions: FileVideoCompressionOptions | undefined =\n storageConfiguration?.videoCRF &&\n storageConfiguration?.videoPreset &&\n storageConfiguration?.videoResolution\n ? {\n crf: Number(storageConfiguration.videoCRF),\n preset: storageConfiguration.videoPreset as FileVideoCompressionOptions[\"preset\"],\n resolution: Number(storageConfiguration.videoResolution),\n }\n : undefined;\n\n const allResponses = []\n\n const batchCode = initBatchCode();\n\n const fileLabel = label ?? \"\"\n const referId1 = refId ?? 0\n const referId2 = refId2 ?? 0\n const referLabel1 = refLabel ?? \"\"\n const referLabel2 = refLabel2 ?? \"\"\n const fileRemark = remark ?? \"\"\n\n for (const file of files) {\n\n let bufferToUpload = file.buffer;\n let mimeType = file.mimeType ?? \"\"\n let sizeBytes = file?.sizeBytes\n let fileOriginalName = file.originalName;\n\n let outputSizeBytes = sizeBytes // output file size\n let fileCompressFormat = `` // output image compress\n\n const fileCategoryName = getFileCategoryNameByMimeType(mimeType)\n\n // const ext = file.originalName?.split(\".\").pop()?.toLowerCase() ?? \"\";\n\n // Image :: Only compress if image and options provided\n if (fileCategoryName === \"image\" && imageCompressionOptions) {\n const compressed = await compressImageBuffer(\n bufferToUpload,\n mimeType,\n imageCompressionOptions\n );\n\n fileCompressFormat = compressed.compressFormat,\n bufferToUpload = compressed.buffer;\n outputSizeBytes = compressed.sizeBytes; // update the file size\n }\n\n // Vide :: Only compress if video and options provided\n if (fileCategoryName === \"video\" && videoCompressionOptions) {\n const compressed = await compressVideoBuffer(\n bufferToUpload,\n mimeType,\n videoCompressionOptions\n );\n\n fileCompressFormat = compressed.compressFormat,\n bufferToUpload = compressed.buffer;\n outputSizeBytes = compressed.sizeBytes; // update the file size\n }\n\n // generate thumbnail buffer\n const bufferThumbnail = await generateFileThumbnailBuffer(bufferToUpload, mimeType)\n\n // Call the consumer hook, if registered\n if (FileStorageHook.onStartUpload) {\n\n await FileStorageHook.onStartUpload(buildFeatureCallbackProps({\n defaultServiceProps: rest,\n callbackParams: {\n fieldRef: field_ref,\n fieldModule: field_module,\n tagName,\n label,\n refId,\n refId2,\n refLabel,\n refLabel2,\n remark,\n description,\n foldernameDate,\n file,\n storageProviderName,\n storageProviderOptions,\n fileCategoryName,\n batchCode,\n mimeType,\n bufferFilebuffer: bufferToUpload,\n bufferFileThumbnail: bufferThumbnail?.buffer,\n outputSizeBytes,\n fileCompressFormat: fileCompressFormat ? JSON.parse(fileCompressFormat) : \"\",\n imageCompressionOptions,\n videoCompressionOptions\n }\n }))\n }\n\n // upload using the provider - buffer\n const uploadResult = await provider.uploadFile({\n field_ref,\n field_module,\n buffer: bufferToUpload,\n bufferThumbnail: bufferThumbnail.buffer,\n thumbnailOptions,\n ...(foldernameDate ? { foldernameDate } : {}),\n mimeType,\n fileName: fileOriginalName\n } as FileModuleRef & (\n FileLocalUploadFileProps |\n FileGoogleCloudUploadFileProps |\n FileAwsS3UploadFileProps\n ));\n\n const fieldRef = field_ref\n const fieldModule = field_module\n\n const fileName = uploadResult?.filename ?? \"\"\n const contentType = mimeType ?? \"\"\n const folderPath = uploadResult.assetPath ?? \"\"\n const assetUrl = uploadResult.assetUrl ?? \"\"\n const thumbnailUrl = uploadResult?.thumbnailUrl ?? \"\"\n const assetPath = uploadResult.assetPath ?? \"\"\n\n const fileDurationSeconds = bufferThumbnail?.durationSeconds ?? 0\n\n const inputType = `buffer`\n const inputFileSizeBytes = sizeBytes ?? 0\n const inputFileName = fileOriginalName ?? \"\"\n\n const fileSizeBytes = outputSizeBytes ?? 0\n // const fileCompressFormat = ``\n\n const foldernameDay = uploadResult?.folderName?.day ?? \"\"\n const foldernameMonth = uploadResult?.folderName?.month ?? \"\"\n const foldernameYear = uploadResult?.folderName?.year ?? \"\"\n\n const payload: FileCreateProps = {\n data: {\n fieldRef,\n fieldModule,\n tagName,\n description,\n remark: fileRemark,\n folderPath,\n assetUrl,\n thumbnailUrl,\n assetPath,\n fileLabel,\n fileName,\n fileCategoryName,\n contentType,\n inputType,\n inputFileSizeBytes,\n inputFileName,\n fileSizeBytes,\n fileDurationSeconds,\n fileCompressFormat,\n storageProviderName,\n foldernameDay,\n foldernameMonth,\n foldernameYear,\n batchCode,\n referId1,\n referId2,\n referLabel1,\n referLabel2\n } as FileCreateProps[\"data\"],\n };\n\n let responseFile = await createFile(payload);\n\n // Call the consumer hook, if registered\n if (FileStorageHook.onSuccessUpload) {\n await FileStorageHook.onSuccessUpload(buildFeatureCallbackProps({\n defaultServiceProps: rest,\n callbackParams: {\n fileId: Number(responseFile?.file_id),\n fileThumbnailUrl: thumbnailUrl,\n fileAssetUrl: assetUrl,\n fileDurationSeconds,\n fieldRef: field_ref,\n fieldModule: field_module,\n tagName,\n label,\n refId,\n refId2,\n refLabel,\n refLabel2,\n remark,\n description,\n foldernameDate,\n file,\n storageProviderName,\n storageProviderOptions,\n fileCategoryName,\n batchCode,\n mimeType,\n bufferFilebuffer: bufferToUpload,\n bufferFileThumbnail: bufferThumbnail.buffer,\n outputSizeBytes,\n fileCompressFormat: fileCompressFormat ? JSON.parse(fileCompressFormat) : \"\",\n imageCompressionOptions,\n videoCompressionOptions\n }\n }))\n }\n\n allResponses.push(responseFile)\n }\n\n return allResponses\n\n }\n\n // private\n const createFile = async ({ data }: FileCreateProps) => {\n\n const _data = getCreatePayload(data)\n\n if (!_data) {\n throw new Error(`Invalid create file payload: ${JSON.stringify(_data)}`);\n }\n\n const response = await fileModel.create({ data: _data })\n\n const newFileId = response?.file_id ?? \"\"\n\n return newFileId ? await getFile({ id: Number(newFileId) }) : null\n\n }\n\n const getFile = async ({ id }: FileGetProps) => {\n\n let { data } = await listFiles({\n limit: 1,\n offset: 0,\n filters: [{ field: `${ModelFileFields.file_id}`, operator: \"=\", value: id }],\n sortfield: `${ModelFileFields.file_id}`,\n sortorder: \"ASC\"\n })\n\n return data[0] ?? null;\n\n };\n\n const listFiles = async ({ limit, offset, filters = [], sortfield, sortorder }: FileListProps) => {\n\n let sqlSelect: string[] = []\n let sqlRelation: string[] = []\n let sqlGroupBy: string[] = []\n\n let sqlSelectAgg: string[] = []\n let sqlRelationAgg: string[] = []\n\n sqlSelect = [\n buildSqlSelect(``, mainSqlSelect),\n buildSqlSelect(``, defaultSqlSelect)\n ]\n\n sqlRelation = [\n sqlRelationMaps.creator,\n sqlRelationMaps.updater\n ]\n\n // sqlRelationAgg = []\n\n sqlGroupBy = [\n ...Object.keys(mainSqlSelect),\n ...Object.keys(defaultSqlSelect)\n ]\n\n let filterColumns = {\n ...mainSqlSelect,\n ...defaultSqlSelect\n }\n\n let sqlWhere = [\n `mainfile.isdelete = false`,\n `mainfile.istrash = false`,\n // `LOWER(mainfile.doc_type) = LOWER('${documentTypeKey}')`\n ]\n\n let sqlOrderby = buildSqlOrderBy(sortfield, sortorder)\n let sqlLimitOffset = buildSqlLimitOffset(limit, offset)\n\n // get the listing data & count\n const { data, total } = await getListWithCount({\n model: fileModel,\n tableName: \"files\",\n mainAlias: \"mainfile\",\n countKey: `${ModelFileFields.file_id}`,\n accountId: rest.accountId,\n sqlRelationMaps,\n filters,\n filterColumns,\n sqlSelect,\n sqlSelectAgg,\n sqlRelation,\n sqlRelationAgg,\n sqlWhere,\n sqlGroupBy,\n sqlOrderby,\n sqlLimitOffset\n })\n\n const response = {\n data,\n total\n }\n\n return response\n\n };\n\n const removeFiles = async ({ fileIds, storageSetup }: FileRemoveProps) => {\n\n const {\n // storageProviderName,\n storageProviderOptions\n } = await getStorageSetup(storageSetup)\n\n if (!fileIds.length) throwError('fileIds is required');\n\n const filesToDelete = await fileModel.list({\n where: {\n file_id: { in: fileIds }\n }\n });\n\n // console.log('filesToDelete', filesToDelete)\n\n let providerResponse: any[] = []\n\n // 2️⃣ Delete the physical files\n for (const file of filesToDelete) {\n\n // check the provider to choose delete method\n const storageProviderName = file.storage_provider_name as FileStorageProviderType\n const assetUrl = file.asset_url\n const thumbnailUrl = file.thumbnail_url ?? \"\"\n const assetPath = file.asset_path\n\n if (storageProviderName === \"local\" && assetPath) {\n\n try {\n providerResponse.push(\n await fileLocalStorageProvider.removeFile(assetPath, thumbnailOptions)\n )\n } catch (err) {\n providerResponse.push(\n `Failed to delete from Local: ${assetUrl}`\n )\n }\n\n }\n\n if (storageProviderName === \"gcloud\" && assetUrl) {\n\n try {\n providerResponse.push(\n await fileGoogleCloudStorageProvider.removeFile(assetUrl, thumbnailUrl, storageProviderOptions.credentials as any)\n )\n } catch (err) {\n providerResponse.push(\n `Failed to delete from GCloud: ${assetUrl}`\n )\n }\n\n }\n\n if (storageProviderName === \"aws\" && assetUrl) {\n\n try {\n providerResponse.push(\n await fileAwsS3StorageProvider.removeFile(assetUrl, thumbnailUrl)\n )\n } catch (err) {\n providerResponse.push(\n `Failed to delete from Aws S3: ${assetUrl}`\n )\n }\n\n }\n\n }\n\n // remove files\n const response = await fileModel.remove({ where: { [`${ModelFileFields.file_id}`]: { in: fileIds } } });\n\n return {\n files: response,\n providerResponse\n }\n };\n\n const getFileUsageSummary = async ({ accountId = 0 }: FileGetUsageSummaryProps) => {\n\n const summaryCount = await fileModel.aggregate({\n field: `file_id`,\n operation: `count`,\n where: {\n [`${ModelFileFields.accountid}`]: accountId,\n [`${ModelFileFields.istrash}`]: false,\n [`${ModelFileFields.isdelete}`]: false,\n }\n });\n\n const summarySize = await fileModel.aggregate({\n field: `file_size_bytes`,\n operation: `sum`,\n where: {\n [`${ModelFileFields.accountid}`]: accountId,\n [`${ModelFileFields.istrash}`]: false,\n [`${ModelFileFields.isdelete}`]: false,\n }\n });\n\n const totalFiles = summaryCount ?? 0;\n const totalBytes = summarySize ?? 0;\n // const totalFiles = summary._count.id;\n\n // Optional: convert bytes to MB or GB\n const totalMB = totalBytes / (1024 * 1024);\n const totalGB = totalBytes / (1024 * 1024 * 1024);\n\n return {\n totalFiles,\n totalBytes,\n totalMB: parseFloat(totalMB.toFixed(2)), // now decimal\n totalGB: parseFloat(totalGB.toFixed(2)), // now decimal\n };\n }\n\n // const getDataTypes = () => {\n // return Object.values(fileDataTypes);\n // }\n\n return {\n uploadFiles,\n // createFile,\n // updateFile,\n getFile,\n listFiles,\n removeFiles,\n // getDataTypes,\n getFileUsageSummary\n }\n\n}\n\n"]}
@@ -16,6 +16,7 @@ export type UserMeChangePasswordProps = {
16
16
  currentPassword: string;
17
17
  newPassword: string;
18
18
  confirmPassword: string;
19
+ skipLoginPasswordValidation?: boolean;
19
20
  };
20
21
  export type UserMeUpdateProps = {
21
22
  firstName: string;
@@ -116,7 +116,7 @@ const UserMeService = (props) => {
116
116
  }
117
117
  return response;
118
118
  };
119
- const changePasswordUserMe = async ({ currentPassword, confirmPassword, newPassword }) => {
119
+ const changePasswordUserMe = async ({ currentPassword, confirmPassword, newPassword, skipLoginPasswordValidation = false }) => {
120
120
  const accountId = rest?.accountId ?? 0;
121
121
  const accountService = (0, services_1.AccountService)({ ...rest, isOperator: true });
122
122
  const user = await userService.getUser({ id: Number(userId), datatypes: [], includePassword: true });
@@ -139,7 +139,9 @@ const UserMeService = (props) => {
139
139
  (0, utils_1.throwError)(`New and confirm password not matched`);
140
140
  }
141
141
  // validate the login password new format
142
- (0, utils_1.validateLoginPasswordFormat)(newPassword);
142
+ if (skipLoginPasswordValidation === false) {
143
+ (0, utils_1.validateLoginPasswordFormat)(newPassword);
144
+ }
143
145
  // check the current password
144
146
  try {
145
147
  const decryptedPass = await (0, utils_1.verifyPassword)(currentPassword, user?.password);