arkos 2.0.0-next.29 → 2.0.0-next.30
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.
- package/dist/esm/app.js +2 -0
- package/dist/esm/app.js.map +1 -1
- package/dist/esm/components/arkos-gateway/arkos-gateway.js +22 -5
- package/dist/esm/components/arkos-gateway/arkos-gateway.js.map +1 -1
- package/dist/esm/components/arkos-gateway/types.js.map +1 -1
- package/dist/esm/components/arkos-route-hook/index.js +9 -3
- package/dist/esm/components/arkos-route-hook/index.js.map +1 -1
- package/dist/esm/components/arkos-route-hook/reader.js.map +1 -1
- package/dist/esm/components/arkos-route-hook/types.js.map +1 -1
- package/dist/esm/exports/file-upload.js +2 -0
- package/dist/esm/exports/file-upload.js.map +1 -0
- package/dist/esm/exports/index.js.map +1 -1
- package/dist/esm/exports/websockets.js.map +1 -1
- package/dist/esm/generated.js.map +1 -1
- package/dist/esm/modules/auth/auth.controller.js +84 -141
- package/dist/esm/modules/auth/auth.controller.js.map +1 -1
- package/dist/esm/modules/auth/auth.router.js +1 -1
- package/dist/esm/modules/auth/auth.router.js.map +1 -1
- package/dist/esm/modules/auth/auth.service.js +93 -15
- package/dist/esm/modules/auth/auth.service.js.map +1 -1
- package/dist/esm/modules/auth/auth.types.js +2 -0
- package/dist/esm/modules/auth/auth.types.js.map +1 -0
- package/dist/esm/modules/auth/utils/helpers/auth.controller.helpers.js +1 -0
- package/dist/esm/modules/auth/utils/helpers/auth.controller.helpers.js.map +1 -1
- package/dist/esm/modules/auth/utils/token-extraction.js +57 -0
- package/dist/esm/modules/auth/utils/token-extraction.js.map +1 -0
- package/dist/esm/modules/base/base.controller.js +5 -0
- package/dist/esm/modules/base/base.controller.js.map +1 -1
- package/dist/esm/modules/base/base.middlewares.js +4 -4
- package/dist/esm/modules/base/base.middlewares.js.map +1 -1
- package/dist/esm/modules/base/utils/error-prettifier.js +64 -0
- package/dist/esm/modules/base/utils/error-prettifier.js.map +1 -1
- package/dist/esm/modules/error-handler/utils/error-handler.helpers.js +52 -8
- package/dist/esm/modules/error-handler/utils/error-handler.helpers.js.map +1 -1
- package/dist/esm/modules/error-handler/utils/get-handled-error.js +5 -0
- package/dist/esm/modules/error-handler/utils/get-handled-error.js.map +1 -1
- package/dist/esm/modules/file-upload/file-upload.controller.js +25 -7
- package/dist/esm/modules/file-upload/file-upload.controller.js.map +1 -1
- package/dist/esm/modules/file-upload/file-upload.router.js +21 -5
- package/dist/esm/modules/file-upload/file-upload.router.js.map +1 -1
- package/dist/esm/modules/file-upload/file-upload.service.js +28 -18
- package/dist/esm/modules/file-upload/file-upload.service.js.map +1 -1
- package/dist/esm/modules/file-upload/utils/file-upload-json-schema-generator.js +37 -12
- package/dist/esm/modules/file-upload/utils/file-upload-json-schema-generator.js.map +1 -1
- package/dist/esm/modules/file-upload/utils/helpers/file-upload.helpers.js +73 -35
- package/dist/esm/modules/file-upload/utils/helpers/file-upload.helpers.js.map +1 -1
- package/dist/esm/modules/file-upload/utils/helpers/serve-upload-dir.js +206 -0
- package/dist/esm/modules/file-upload/utils/helpers/serve-upload-dir.js.map +1 -0
- package/dist/esm/modules/file-upload/utils/helpers/upload-path.helper.js +103 -0
- package/dist/esm/modules/file-upload/utils/helpers/upload-path.helper.js.map +1 -0
- package/dist/esm/modules/file-upload/utils/helpers/upload-serving-validation.js +212 -0
- package/dist/esm/modules/file-upload/utils/helpers/upload-serving-validation.js.map +1 -0
- package/dist/esm/modules/file-upload/utils/helpers/upload-serving.registry.js +30 -0
- package/dist/esm/modules/file-upload/utils/helpers/upload-serving.registry.js.map +1 -0
- package/dist/esm/modules/swagger/utils/helpers/get-swagger-default-configs.js +1 -1
- package/dist/esm/modules/swagger/utils/helpers/get-swagger-default-configs.js.map +1 -1
- package/dist/esm/modules/swagger/utils/helpers/openapi-schema-converter.js +7 -8
- package/dist/esm/modules/swagger/utils/helpers/openapi-schema-converter.js.map +1 -1
- package/dist/esm/types/index.js.map +1 -1
- package/dist/esm/types/internal.js +2 -0
- package/dist/esm/types/internal.js.map +1 -0
- package/dist/esm/types/new-arkos-config.js.map +1 -1
- package/dist/esm/types/upload.js.map +1 -1
- package/dist/esm/types/validation/validation-manager.js +18 -10
- package/dist/esm/types/validation/validation-manager.js.map +1 -1
- package/dist/esm/types/validation/validator.js.map +1 -1
- package/dist/esm/utils/arkos-router/arkos-router-openapi-manager.js.map +1 -1
- package/dist/esm/utils/arkos-router/index.js +2 -11
- package/dist/esm/utils/arkos-router/index.js.map +1 -1
- package/dist/esm/utils/arkos-router/route-config-validator.js +11 -10
- package/dist/esm/utils/arkos-router/route-config-validator.js.map +1 -1
- package/dist/esm/utils/arkos-router/types/index.js.map +1 -1
- package/dist/esm/utils/arkos-router/types/upload-config.js.map +1 -1
- package/dist/esm/utils/arkos-router/utils/helpers/index.js +1 -0
- package/dist/esm/utils/arkos-router/utils/helpers/index.js.map +1 -1
- package/dist/esm/utils/arkos-router/utils/helpers/upload-manager.js +326 -37
- package/dist/esm/utils/arkos-router/utils/helpers/upload-manager.js.map +1 -1
- package/dist/esm/utils/cli/dev.js +15 -2
- package/dist/esm/utils/cli/dev.js.map +1 -1
- package/dist/esm/utils/cli/generate.js +8 -3
- package/dist/esm/utils/cli/generate.js.map +1 -1
- package/dist/esm/utils/cli/index.js +21 -20
- package/dist/esm/utils/cli/index.js.map +1 -1
- package/dist/esm/utils/cli/prisma-generate.js +24 -5
- package/dist/esm/utils/cli/prisma-generate.js.map +1 -1
- package/dist/esm/utils/cli/start.js +2 -0
- package/dist/esm/utils/cli/start.js.map +1 -1
- package/dist/esm/utils/cli/utils/cli.helpers.js +1 -1
- package/dist/esm/utils/cli/utils/dependency-version-check.js +39 -0
- package/dist/esm/utils/cli/utils/dependency-version-check.js.map +1 -0
- package/dist/esm/utils/cli/utils/template-generator/templates/router-template.js.map +1 -1
- package/dist/esm/utils/define-config.js +1 -0
- package/dist/esm/utils/define-config.js.map +1 -1
- package/dist/esm/utils/initialize-app.js +2 -0
- package/dist/esm/utils/initialize-app.js.map +1 -1
- package/dist/types/app.d.ts +5 -2
- package/dist/types/components/arkos-gateway/arkos-gateway.d.ts +19 -7
- package/dist/types/components/arkos-gateway/types.d.ts +19 -2
- package/dist/types/components/arkos-route-hook/index.d.ts +4 -3
- package/dist/types/components/arkos-route-hook/reader.d.ts +1 -1
- package/dist/types/components/arkos-route-hook/types.d.ts +4 -1
- package/dist/types/exports/file-upload.d.ts +1 -0
- package/dist/types/exports/index.d.ts +1 -2
- package/dist/types/exports/websockets.d.ts +1 -1
- package/dist/types/modules/auth/auth.controller.d.ts +10 -3
- package/dist/types/modules/auth/auth.service.d.ts +90 -0
- package/dist/types/modules/auth/auth.types.d.ts +72 -0
- package/dist/types/modules/auth/utils/helpers/auth.controller.helpers.d.ts +1 -0
- package/dist/types/modules/auth/utils/token-extraction.d.ts +53 -0
- package/dist/types/modules/base/base.controller.d.ts +1 -0
- package/dist/types/modules/base/utils/error-prettifier.d.ts +8 -0
- package/dist/types/modules/error-handler/utils/error-handler.helpers.d.ts +1 -0
- package/dist/types/modules/file-upload/file-upload.service.d.ts +2 -6
- package/dist/types/modules/file-upload/utils/helpers/file-upload.helpers.d.ts +21 -1
- package/dist/types/modules/file-upload/utils/helpers/serve-upload-dir.d.ts +43 -0
- package/dist/types/modules/file-upload/utils/helpers/upload-path.helper.d.ts +14 -0
- package/dist/types/modules/file-upload/utils/helpers/upload-serving-validation.d.ts +5 -0
- package/dist/types/modules/file-upload/utils/helpers/upload-serving.registry.d.ts +31 -0
- package/dist/types/modules/swagger/utils/helpers/openapi-schema-converter.d.ts +1 -1
- package/dist/types/types/index.d.ts +5 -0
- package/dist/types/types/internal.d.ts +25 -0
- package/dist/types/types/new-arkos-config.d.ts +24 -2
- package/dist/types/types/upload.d.ts +35 -0
- package/dist/types/types/validation/validation-manager.d.ts +6 -8
- package/dist/types/types/validation/validator.d.ts +2 -2
- package/dist/types/utils/arkos-router/types/index.d.ts +3 -2
- package/dist/types/utils/arkos-router/types/upload-config.d.ts +102 -11
- package/dist/types/utils/arkos-router/utils/helpers/upload-manager.d.ts +20 -0
- package/dist/types/utils/cli/utils/dependency-version-check.d.ts +15 -0
- package/dist/types/utils/define-config.d.ts +56 -2
- package/dist/types/utils/helpers/prisma.helpers.d.ts +1 -1
- package/package.json +15 -38
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-upload.controller.js","sourceRoot":"","sources":["../../../../src/modules/file-upload/file-upload.controller.ts"],"names":[],"mappings":"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","sourcesContent":["import AppError from \"../error-handler/utils/app-error\";\nimport {\n FileUploadService,\n getFileUploadServices,\n} from \"./file-upload.service\";\nimport path from \"path\";\nimport fs from \"fs\";\nimport catchAsync from \"../error-handler/utils/catch-async\";\nimport { getArkosConfig } from \"../../server\";\nimport { processFile, processImage } from \"./utils/helpers/file-upload.helpers\";\nimport { ArkosNextFunction, ArkosRequest, ArkosResponse } from \"../../types\";\nimport loadableRegistry from \"../../components/arkos-loadable-registry\";\nimport { routeHookReader } from \"../../components/arkos-route-hook/reader\";\n\nfunction matchesUploadUrl(\n originalUrl: string,\n baseUploadRoute: string,\n fileType: string,\n fileName: string\n): boolean {\n const expectedPath = `${baseUploadRoute}/${fileType}/${fileName}`;\n return (\n (originalUrl === expectedPath || originalUrl.startsWith(expectedPath)) &&\n new RegExp(`${baseUploadRoute}/${fileType}/${fileName}`).test(originalUrl)\n );\n}\n\n/**\n * Handles file uploads and allows to be extended via route hooks.\n */\nexport class FileUploadController {\n private getRouteHook() {\n return loadableRegistry.getItem(\"ArkosRouteHook\", \"file-upload\");\n }\n\n private getAfterHook(operation: string) {\n const hook = this.getRouteHook();\n if (!hook) return null;\n return (\n routeHookReader.getHooks(\"file-upload\", operation as any)?.after ?? null\n );\n }\n\n /**\n * Handles file upload requests, processes images if needed, and returns URLs.\n *\n * @param {ArkosRequest} req - Arkos request object\n * @param {ArkosResponse} res - Arkos response object\n * @param {ArkosNextFunction} next - Arkos next middleware function\n */\n uploadFile = catchAsync(\n async (req: ArkosRequest, res: ArkosResponse, next: ArkosNextFunction) => {\n const { fileType } = req.params;\n const { format, width, height, resizeTo } = req.query;\n const options = { format, width, height, resizeTo };\n\n const {\n documentUploadService,\n fileUploadService,\n imageUploadService,\n videoUploadService,\n } = getFileUploadServices();\n\n const { fileUpload } = getArkosConfig();\n const baseUploadDir = fileUpload?.baseUploadDir || \"/uploads\";\n\n const uploadPath = path.resolve(\n path.join(process.cwd(), baseUploadDir, fileType)\n );\n try {\n await fs.promises.access(uploadPath);\n } catch {\n await fs.promises.mkdir(uploadPath, { recursive: true });\n }\n\n let uploader: FileUploadService;\n switch (fileType) {\n case \"images\":\n uploader = imageUploadService;\n break;\n case \"videos\":\n uploader = videoUploadService;\n break;\n case \"documents\":\n uploader = documentUploadService;\n break;\n case \"files\":\n uploader = fileUploadService;\n break;\n default:\n return next(\n new AppError(\"Invalid file type\", 400, \"InvalidFileType\")\n );\n }\n\n uploader.handleMultipleUpload()(req, res, async (err) => {\n if (err) throw err;\n\n let data;\n if (req.files && Array.isArray(req.files) && req.files.length > 0) {\n if (fileType === \"images\") {\n data = await Promise.all(\n req.files.map((file) =>\n processImage(req, next, file.path, options)\n )\n );\n } else {\n data = req.files.map((file) => processFile(req, file.path));\n }\n data = data.filter((url) => url !== null);\n } else if (req.file) {\n if (fileType === \"images\") {\n data = await processImage(req, next, req.file.path, options);\n } else {\n data = processFile(req, req.file.path);\n }\n } else {\n return next(\n new AppError(\n `No file or files were attached on field ${fileType} on the request body as form data.`,\n 400,\n \"NoFileOrFilesAttached\"\n )\n );\n }\n\n const jsonContent = {\n success: true,\n data,\n message: Array.isArray(data)\n ? `${data.length} files uploaded successfully`\n : \"File uploaded successfully\",\n };\n\n const afterHook = this.getAfterHook(\"uploadFile\");\n if (afterHook) {\n (res as any).originalData = jsonContent;\n req.responseData = jsonContent;\n res.locals.data = jsonContent;\n (res as any).originalStatus = 200;\n req.responseStatus = 200;\n res.locals.status = 200;\n return next();\n }\n\n res.status(200).json(jsonContent);\n });\n }\n );\n\n /**\n * Handles file deletion requests.\n *\n * @param {ArkosRequest} req - Arkos request object\n * @param {ArkosResponse} res - Arkos response object\n * @param {ArkosNextFunction} next - Arkos next middleware function\n */\n deleteFile = catchAsync(\n async (req: ArkosRequest, res: ArkosResponse, next: ArkosNextFunction) => {\n const { fileType, fileName } = req.params;\n\n const {\n documentUploadService,\n fileUploadService,\n imageUploadService,\n videoUploadService,\n } = getFileUploadServices();\n\n let uploader: FileUploadService;\n switch (fileType) {\n case \"images\":\n uploader = imageUploadService;\n break;\n case \"videos\":\n uploader = videoUploadService;\n break;\n case \"documents\":\n uploader = documentUploadService;\n break;\n case \"files\":\n uploader = fileUploadService;\n break;\n default:\n return next(\n new AppError(\"Invalid file type\", 400, \"InvalidFileType\")\n );\n }\n // top of file or a shared utils import\n const escapeRegExp = (value: string) =>\n value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n\n try {\n const { fileUpload } = getArkosConfig();\n\n const baseUploadRoute = fileUpload?.baseRoute || \"/api/uploads\";\n const urlPattern = new RegExp(\n `${escapeRegExp(baseUploadRoute)}/${escapeRegExp(fileType)}/${escapeRegExp(fileName)}`\n );\n\n const isExpectedUrlPattern = urlPattern.test(req.originalUrl);\n if (isExpectedUrlPattern) {\n const fullUrl = `${req.protocol}://${req.get(\"host\")}${req.originalUrl}`;\n await uploader.deleteFileByUrl(fullUrl);\n } else {\n await uploader.deleteFileByName(fileName, fileType);\n }\n\n const afterHook = this.getAfterHook(\"deleteFile\");\n if (afterHook) {\n req.responseStatus = 204;\n return next();\n }\n\n res.status(204).json();\n } catch (error) {\n if (error instanceof AppError) return next(error);\n return next(new AppError(\"File not found\", 404, \"FileNotFound\"));\n }\n }\n );\n\n /**\n * Handles file update requests by deleting the old file and uploading a new one.\n *\n * @param {ArkosRequest} req - Arkos request object\n * @param {ArkosResponse} res - Arkos response object\n * @param {ArkosNextFunction} next - Arkos next middleware function\n */\n updateFile = catchAsync(\n async (req: ArkosRequest, res: ArkosResponse, next: ArkosNextFunction) => {\n const { fileType, fileName } = req.params;\n const { format, width, height, resizeTo } = req.query;\n const options = { format, width, height, resizeTo };\n\n const {\n documentUploadService,\n fileUploadService,\n imageUploadService,\n videoUploadService,\n } = getFileUploadServices();\n\n const { fileUpload } = getArkosConfig();\n const baseUploadDir = fileUpload?.baseUploadDir || \"/uploads\";\n\n const uploadPath = path.resolve(\n path.join(process.cwd(), baseUploadDir, fileType)\n );\n try {\n await fs.promises.access(uploadPath);\n } catch {\n await fs.promises.mkdir(uploadPath, { recursive: true });\n }\n\n let uploader: FileUploadService;\n switch (fileType) {\n case \"images\":\n uploader = imageUploadService;\n break;\n case \"videos\":\n uploader = videoUploadService;\n break;\n case \"documents\":\n uploader = documentUploadService;\n break;\n case \"files\":\n uploader = fileUploadService;\n break;\n default:\n return next(\n new AppError(\"Invalid file type\", 400, \"InvalidFileType\")\n );\n }\n\n uploader.handleMultipleUpload()(req, res, async (err) => {\n if (err) throw err;\n\n if (\n !req.file &&\n (!req.files || !Array.isArray(req.files) || req.files.length === 0)\n )\n return next(\n new AppError(\"No new file uploaded\", 400, \"MissingNewFile\")\n );\n\n if (fileName && fileName.trim() !== \"\") {\n try {\n const isExpectedUrlPattern = matchesUploadUrl(\n req.originalUrl,\n fileUpload?.baseRoute || \"/api/uploads\",\n fileType,\n fileName\n );\n\n if (isExpectedUrlPattern) {\n const oldFileUrl = `${req.protocol}://${req.get(\"host\")}${req.originalUrl}`;\n await uploader.deleteFileByUrl(oldFileUrl);\n } else {\n await uploader.deleteFileByName(fileName, fileType);\n }\n } catch (error) {\n console.warn(`Could not delete old file: ${fileName}`, error);\n }\n }\n\n let data;\n if (req.files && Array.isArray(req.files) && req.files.length > 0) {\n if (fileType === \"images\") {\n data = await Promise.all(\n req.files.map((file) =>\n processImage(req, next, file.path, options)\n )\n );\n } else {\n data = req.files.map((file) => processFile(req, file.path));\n }\n data = data.filter((url) => url !== null);\n } else if (req.file) {\n if (fileType === \"images\") {\n data = await processImage(req, next, req.file.path, options);\n } else {\n data = processFile(req, req.file.path);\n }\n }\n\n const jsonContent = {\n success: true,\n data,\n message: Array.isArray(data)\n ? fileName && fileName.trim() !== \"\"\n ? `File updated successfully. ${data.length} new files uploaded`\n : `${data.length} files uploaded successfully`\n : fileName && fileName.trim() !== \"\"\n ? \"File updated successfully\"\n : \"File uploaded successfully\",\n };\n\n const afterHook = this.getAfterHook(\"updateFile\");\n if (afterHook) {\n (res as any).originalData = jsonContent;\n req.responseData = jsonContent;\n res.locals.data = jsonContent;\n (res as any).originalStatus = 200;\n req.responseStatus = 200;\n res.locals.status = 200;\n return next();\n }\n\n res.status(200).json(jsonContent);\n });\n }\n );\n}\n\n/**\n * Controller instance responsible for handling file upload operations.\n *\n * @remarks\n * This controller handles various file upload operations including validation,\n * storage, and response management.\n *\n * @instance\n * @constant\n * @see {@link https://www.arkosjs.com/docs/reference/file-upload-controller-object}\n */\nconst fileUploadController = new FileUploadController();\n\nexport default fileUploadController;\n"]}
|
|
1
|
+
{"version":3,"file":"file-upload.controller.js","sourceRoot":"","sources":["../../../../src/modules/file-upload/file-upload.controller.ts"],"names":[],"mappings":"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","sourcesContent":["import AppError from \"../error-handler/utils/app-error\";\nimport {\n FileUploadService,\n getFileUploadServices,\n} from \"./file-upload.service\";\nimport path from \"path\";\nimport fs from \"fs\";\nimport catchAsync from \"../error-handler/utils/catch-async\";\nimport { getArkosConfig } from \"../../server\";\nimport {\n ImageOptimizationOptions,\n processFile,\n processImage,\n} from \"./utils/helpers/file-upload.helpers\";\nimport { ArkosNextFunction, ArkosRequest, ArkosResponse } from \"../../types\";\nimport loadableRegistry from \"../../components/arkos-loadable-registry\";\nimport { routeHookReader } from \"../../components/arkos-route-hook/reader\";\n\nfunction matchesUploadUrl(\n originalUrl: string,\n baseUploadRoute: string,\n fileType: string,\n fileName: string\n): boolean {\n const expectedPath = `${baseUploadRoute}/${fileType}/${fileName}`;\n return (\n (originalUrl === expectedPath || originalUrl.startsWith(expectedPath)) &&\n new RegExp(`${baseUploadRoute}/${fileType}/${fileName}`).test(originalUrl)\n );\n}\n\n/**\n * Handles file uploads and allows to be extended via route hooks.\n */\nexport class FileUploadController {\n private getRouteHook() {\n return loadableRegistry.getItem(\"ArkosRouteHook\", \"file-upload\");\n }\n\n private getAfterHook(operation: string) {\n const hook = this.getRouteHook();\n if (!hook) return null;\n return (\n routeHookReader.getHooks(\"file-upload\", operation as any)?.after ?? null\n );\n }\n\n /**\n * Handles file upload requests, processes images if needed, and returns URLs.\n *\n * @param {ArkosRequest} req - Arkos request object\n * @param {ArkosResponse} res - Arkos response object\n * @param {ArkosNextFunction} next - Arkos next middleware function\n */\n uploadFile = catchAsync(\n async (req: ArkosRequest, res: ArkosResponse, next: ArkosNextFunction) => {\n const { fileType } = req.params;\n const { format, width, height, resizeTo, quality } = req.query;\n const options = {\n format,\n width,\n height,\n resizeTo,\n quality,\n } as ImageOptimizationOptions;\n\n const {\n documentUploadService,\n fileUploadService,\n imageUploadService,\n videoUploadService,\n } = getFileUploadServices();\n\n const { fileUpload } = getArkosConfig();\n const baseUploadDir = fileUpload?.baseUploadDir || \"/uploads\";\n\n const uploadPath = path.resolve(\n path.join(process.cwd(), baseUploadDir, fileType)\n );\n try {\n await fs.promises.access(uploadPath);\n } catch {\n await fs.promises.mkdir(uploadPath, { recursive: true });\n }\n\n let uploader: FileUploadService;\n switch (fileType) {\n case \"images\":\n uploader = imageUploadService;\n break;\n case \"videos\":\n uploader = videoUploadService;\n break;\n case \"documents\":\n uploader = documentUploadService;\n break;\n case \"files\":\n uploader = fileUploadService;\n break;\n default:\n return next(\n new AppError(\"Invalid file type\", 400, \"InvalidFileType\")\n );\n }\n\n uploader.handleMultipleUpload()(req, res, async (err) => {\n if (err) throw err;\n\n let data;\n if (req.files && Array.isArray(req.files) && req.files.length > 0) {\n if (fileType === \"images\") {\n data = await Promise.all(\n req.files.map((file) =>\n processImage(req, next, file.path, options)\n )\n );\n } else {\n data = req.files.map((file) => processFile(req, file.path));\n }\n data = data.filter((url) => url !== null);\n } else if (req.file) {\n if (fileType === \"images\") {\n data = await processImage(req, next, req.file.path, options);\n } else {\n data = processFile(req, req.file.path);\n }\n } else {\n return next(\n new AppError(\n `No file or files were attached on field ${fileType} on the request body as form data.`,\n 400,\n \"NoFileOrFilesAttached\"\n )\n );\n }\n\n const jsonContent = {\n success: true,\n data,\n message: Array.isArray(data)\n ? `${data.length} files uploaded successfully`\n : \"File uploaded successfully\",\n };\n\n const afterHook = this.getAfterHook(\"uploadFile\");\n if (afterHook) {\n (res as any).originalData = jsonContent;\n req.responseData = jsonContent;\n res.locals.data = jsonContent;\n (res as any).originalStatus = 200;\n req.responseStatus = 200;\n res.locals.status = 200;\n return next();\n }\n\n res.status(200).json(jsonContent);\n });\n }\n );\n\n /**\n * Handles file deletion requests.\n *\n * @param {ArkosRequest} req - Arkos request object\n * @param {ArkosResponse} res - Arkos response object\n * @param {ArkosNextFunction} next - Arkos next middleware function\n */\n deleteFile = catchAsync(\n async (req: ArkosRequest, res: ArkosResponse, next: ArkosNextFunction) => {\n const { fileType } = req.params;\n const fileName = Array.isArray(req.params.fileName)\n ? req.params.fileName.join(\"/\")\n : req.params.fileName;\n\n const {\n documentUploadService,\n fileUploadService,\n imageUploadService,\n videoUploadService,\n } = getFileUploadServices();\n\n let uploader: FileUploadService;\n switch (fileType) {\n case \"images\":\n uploader = imageUploadService;\n break;\n case \"videos\":\n uploader = videoUploadService;\n break;\n case \"documents\":\n uploader = documentUploadService;\n break;\n case \"files\":\n uploader = fileUploadService;\n break;\n default:\n return next(\n new AppError(\"Invalid file type\", 400, \"InvalidFileType\")\n );\n }\n // top of file or a shared utils import\n const escapeRegExp = (value: string) =>\n value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n\n try {\n const { fileUpload } = getArkosConfig();\n\n const baseUploadRoute = fileUpload?.baseRoute || \"/api/uploads\";\n const urlPattern = new RegExp(\n `${escapeRegExp(baseUploadRoute)}/${escapeRegExp(fileType)}/${escapeRegExp(fileName)}`\n );\n\n const isExpectedUrlPattern = urlPattern.test(req.originalUrl);\n if (isExpectedUrlPattern) {\n const fullUrl = `${req.protocol}://${req.get(\"host\")}${req.originalUrl}`;\n await uploader.deleteFileByUrl(fullUrl);\n } else {\n await uploader.deleteFileByName(fileName, fileType);\n }\n\n const afterHook = this.getAfterHook(\"deleteFile\");\n if (afterHook) {\n req.responseStatus = 204;\n return next();\n }\n\n res.status(204).json();\n } catch (error) {\n if (error instanceof AppError) return next(error);\n return next(new AppError(\"File not found\", 404, \"FileNotFound\"));\n }\n }\n );\n\n /**\n * Handles file update requests by deleting the old file and uploading a new one.\n *\n * @param {ArkosRequest} req - Arkos request object\n * @param {ArkosResponse} res - Arkos response object\n * @param {ArkosNextFunction} next - Arkos next middleware function\n */\n updateFile = catchAsync(\n async (req: ArkosRequest, res: ArkosResponse, next: ArkosNextFunction) => {\n const { fileType } = req.params;\n const fileName = Array.isArray(req.params.fileName)\n ? req.params.fileName.join(\"/\")\n : req.params.fileName;\n const { format, width, height, resizeTo, quality } = req.query;\n const options = {\n format,\n width,\n height,\n resizeTo,\n quality,\n } as ImageOptimizationOptions;\n\n const {\n documentUploadService,\n fileUploadService,\n imageUploadService,\n videoUploadService,\n } = getFileUploadServices();\n\n const { fileUpload } = getArkosConfig();\n const baseUploadDir = fileUpload?.baseUploadDir || \"/uploads\";\n\n const uploadPath = path.resolve(\n path.join(process.cwd(), baseUploadDir, fileType)\n );\n try {\n await fs.promises.access(uploadPath);\n } catch {\n await fs.promises.mkdir(uploadPath, { recursive: true });\n }\n\n let uploader: FileUploadService;\n switch (fileType) {\n case \"images\":\n uploader = imageUploadService;\n break;\n case \"videos\":\n uploader = videoUploadService;\n break;\n case \"documents\":\n uploader = documentUploadService;\n break;\n case \"files\":\n uploader = fileUploadService;\n break;\n default:\n return next(\n new AppError(\"Invalid file type\", 400, \"InvalidFileType\")\n );\n }\n\n uploader.handleMultipleUpload()(req, res, async (err) => {\n if (err) throw err;\n\n if (\n !req.file &&\n (!req.files || !Array.isArray(req.files) || req.files.length === 0)\n )\n return next(\n new AppError(\"No new file uploaded\", 400, \"MissingNewFile\")\n );\n\n if (fileName && fileName.trim() !== \"\") {\n try {\n const isExpectedUrlPattern = matchesUploadUrl(\n req.originalUrl,\n fileUpload?.baseRoute || \"/api/uploads\",\n fileType,\n fileName\n );\n\n if (isExpectedUrlPattern) {\n const oldFileUrl = `${req.protocol}://${req.get(\"host\")}${req.originalUrl}`;\n await uploader.deleteFileByUrl(oldFileUrl);\n } else {\n await uploader.deleteFileByName(fileName, fileType);\n }\n } catch (error) {\n console.warn(`Could not delete old file: ${fileName}`, error);\n }\n }\n\n let data;\n if (req.files && Array.isArray(req.files) && req.files.length > 0) {\n if (fileType === \"images\") {\n data = await Promise.all(\n req.files.map((file) =>\n processImage(req, next, file.path, options)\n )\n );\n } else {\n data = req.files.map((file) => processFile(req, file.path));\n }\n data = data.filter((url) => url !== null);\n } else if (req.file) {\n if (fileType === \"images\") {\n data = await processImage(req, next, req.file.path, options);\n } else {\n data = processFile(req, req.file.path);\n }\n }\n\n const jsonContent = {\n success: true,\n data,\n message: Array.isArray(data)\n ? fileName && fileName.trim() !== \"\"\n ? `File updated successfully. ${data.length} new files uploaded`\n : `${data.length} files uploaded successfully`\n : fileName && fileName.trim() !== \"\"\n ? \"File updated successfully\"\n : \"File uploaded successfully\",\n };\n\n const afterHook = this.getAfterHook(\"updateFile\");\n if (afterHook) {\n (res as any).originalData = jsonContent;\n req.responseData = jsonContent;\n res.locals.data = jsonContent;\n (res as any).originalStatus = 200;\n req.responseStatus = 200;\n res.locals.status = 200;\n return next();\n }\n\n res.status(200).json(jsonContent);\n });\n }\n );\n}\n\n/**\n * Controller instance responsible for handling file upload operations.\n *\n * @remarks\n * This controller handles various file upload operations including validation,\n * storage, and response management.\n *\n * @instance\n * @constant\n * @see {@link https://www.arkosjs.com/docs/reference/file-upload-controller-object}\n */\nconst fileUploadController = new FileUploadController();\n\nexport default fileUploadController;\n"]}
|
|
@@ -11,11 +11,15 @@ import { routeHookReader, } from "../../components/arkos-route-hook/reader.js";
|
|
|
11
11
|
import { getArkosConfig } from "../../server.js";
|
|
12
12
|
import fileUploadJsonSchemaGenerator from "./utils/file-upload-json-schema-generator.js";
|
|
13
13
|
import AppError from "../error-handler/utils/app-error.js";
|
|
14
|
+
import { DEFAULT_UPLOAD_DIRS } from "./utils/helpers/upload-path.helper.js";
|
|
15
|
+
import { uploadServingRegistry } from "./utils/helpers/upload-serving.registry.js";
|
|
14
16
|
export function getFileUploadRouter() {
|
|
15
17
|
const router = ArkosRouter();
|
|
16
18
|
const { fileUpload, globalPrefix } = getArkosConfig();
|
|
17
|
-
if (
|
|
19
|
+
if (fileUpload?.enabled === false) {
|
|
20
|
+
uploadServingRegistry.setFindFileServingEnabled(false);
|
|
18
21
|
return router;
|
|
22
|
+
}
|
|
19
23
|
const routeHook = loadableRegistry.getItem("ArkosRouteHook", "file-upload");
|
|
20
24
|
const op = (operation) => {
|
|
21
25
|
let components = routeHook
|
|
@@ -45,14 +49,26 @@ export function getFileUploadRouter() {
|
|
|
45
49
|
basePathname = basePathname + "/";
|
|
46
50
|
{
|
|
47
51
|
const { before, onError, routeConfig } = op("findFile");
|
|
52
|
+
const servingMode = fileUpload?.serving || "all";
|
|
53
|
+
uploadServingRegistry.setFindFileServingEnabled(!routeConfig?.disabled);
|
|
48
54
|
const baseUploadDirFullPath = path.resolve(path
|
|
49
55
|
.join(process.cwd(), fileUpload?.baseUploadDir || "uploads")
|
|
50
56
|
.replaceAll("//", "/"));
|
|
51
57
|
router.get({
|
|
52
58
|
authentication: { action: "View", resource: "file-upload" },
|
|
53
59
|
...routeConfig,
|
|
54
|
-
path:
|
|
55
|
-
|
|
60
|
+
path: servingMode === "registered"
|
|
61
|
+
? `${basePathname}:fileType/*slug`
|
|
62
|
+
: `${basePathname}*slug`,
|
|
63
|
+
}, ...processMiddleware(before), adjustRequestUrl, ...(servingMode === "registered"
|
|
64
|
+
? [
|
|
65
|
+
(req, _res, next) => {
|
|
66
|
+
if (!DEFAULT_UPLOAD_DIRS.includes(req.params.fileType))
|
|
67
|
+
return next(new AppError(`File ${req.path} was not found`, 404, "FileNotFound", { filepath: req.path }));
|
|
68
|
+
next();
|
|
69
|
+
},
|
|
70
|
+
]
|
|
71
|
+
: []), express.static(baseUploadDirFullPath, deepmerge({
|
|
56
72
|
maxAge: "1y",
|
|
57
73
|
etag: true,
|
|
58
74
|
lastModified: true,
|
|
@@ -81,7 +97,7 @@ export function getFileUploadRouter() {
|
|
|
81
97
|
router.patch({
|
|
82
98
|
authentication: { action: "Update", resource: "file-upload" },
|
|
83
99
|
...routeConfig,
|
|
84
|
-
path: `${basePathname}:fileType
|
|
100
|
+
path: `${basePathname}:fileType/*fileName`,
|
|
85
101
|
}, ...processMiddleware(before), fileUploadController.updateFile, ...processMiddleware(after), sendResponse, ...processMiddleware(onError, { type: "error" }));
|
|
86
102
|
}
|
|
87
103
|
{
|
|
@@ -89,7 +105,7 @@ export function getFileUploadRouter() {
|
|
|
89
105
|
router.delete({
|
|
90
106
|
authentication: { action: "Delete", resource: "file-upload" },
|
|
91
107
|
...routeConfig,
|
|
92
|
-
path: `${basePathname}:fileType
|
|
108
|
+
path: `${basePathname}:fileType/*fileName`,
|
|
93
109
|
}, ...processMiddleware(before), fileUploadController.deleteFile, ...processMiddleware(after), sendResponse, ...processMiddleware(onError, { type: "error" }));
|
|
94
110
|
}
|
|
95
111
|
return router;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-upload.router.js","sourceRoot":"","sources":["../../../../src/modules/file-upload/file-upload.router.ts"],"names":[],"mappings":"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","sourcesContent":["import fileUploadController from \"./file-upload.controller\";\nimport express from \"express\";\nimport deepmerge from \"../../utils/helpers/deepmerge.helper\";\nimport { sendResponse } from \"../base/base.middlewares\";\nimport { processMiddleware } from \"../../utils/helpers/routers.helpers\";\nimport { adjustRequestUrl } from \"./utils/helpers/file-upload.helpers\";\nimport { ArkosNextFunction, ArkosRequest, ArkosResponse } from \"../../exports\";\nimport path from \"path\";\nimport ArkosRouter from \"../../utils/arkos-router\";\nimport loadableRegistry from \"../../components/arkos-loadable-registry\";\nimport {\n OperationByModule,\n routeHookReader,\n} from \"../../components/arkos-route-hook/reader\";\nimport { getArkosConfig } from \"../../server\";\nimport fileUploadJsonSchemaGenerator from \"./utils/file-upload-json-schema-generator\";\nimport AppError from \"../error-handler/utils/app-error\";\n\nexport function getFileUploadRouter() {\n const router = ArkosRouter();\n const { fileUpload, globalPrefix } = getArkosConfig();\n\n if (!fileUpload?.enabled === false) return router;\n\n const routeHook = loadableRegistry.getItem(\"ArkosRouteHook\", \"file-upload\");\n\n const op = (operation: OperationByModule<\"file-upload\">) => {\n let components = routeHook\n ? routeHookReader.forOperation(\"file-upload\", operation)\n : {\n before: [],\n after: [],\n onError: [],\n routeConfig: {},\n };\n\n let endpointConfig = components.routeConfig || {};\n if (endpointConfig?.experimental?.openapi !== false)\n endpointConfig = {\n ...(endpointConfig || {}),\n experimental: {\n ...(endpointConfig?.experimental || {}),\n openapi: fileUploadJsonSchemaGenerator.getOpenApiConfig(\n endpointConfig,\n operation\n ),\n },\n };\n\n components.routeConfig = endpointConfig;\n return components;\n };\n\n let basePathname = fileUpload?.baseRoute || \"/api/uploads/\";\n if (!basePathname.startsWith(\"/\")) basePathname = \"/\" + basePathname;\n if (!basePathname.endsWith(\"/\")) basePathname = basePathname + \"/\";\n\n // FIND FILE\n {\n const { before, onError, routeConfig } = op(\"findFile\");\n const baseUploadDirFullPath = path.resolve(\n path\n .join(process.cwd(), fileUpload?.baseUploadDir || \"uploads\")\n .replaceAll(\"//\", \"/\")\n );\n router.get(\n {\n authentication: { action: \"View\", resource: \"file-upload\" },\n ...routeConfig,\n path: `${basePathname}*slug`,\n },\n ...processMiddleware(before),\n adjustRequestUrl,\n express.static(\n baseUploadDirFullPath,\n deepmerge(\n {\n maxAge: \"1y\",\n etag: true,\n lastModified: true,\n dotfiles: \"ignore\",\n fallthrough: false,\n index: false,\n cacheControl: true,\n },\n fileUpload?.expressStatic || {}\n )\n ),\n (\n err: any,\n req: ArkosRequest,\n _res: ArkosResponse,\n next: ArkosNextFunction\n ) => {\n if (err.code === \"ENOENT\") {\n const filepath = req.path.replace(\n `${globalPrefix}/${fileUpload?.baseRoute}`.replace(\"//\", \"/\"),\n \"\"\n );\n throw new AppError(\n `File ${filepath} was not found`,\n 404,\n \"FileNotFound\",\n { filepath }\n );\n }\n\n next(err);\n },\n ...processMiddleware(onError, { type: \"error\" })\n );\n }\n\n // UPLOAD FILE\n {\n const { before, after, onError, routeConfig } = op(\"uploadFile\");\n router.post(\n {\n authentication: { action: \"Create\", resource: \"file-upload\" },\n ...routeConfig,\n path: `${basePathname}:fileType`,\n },\n ...processMiddleware(before),\n fileUploadController.uploadFile,\n ...processMiddleware(after),\n sendResponse,\n ...processMiddleware(onError, { type: \"error\" })\n );\n }\n\n // UPDATE FILE\n {\n const { before, after, onError, routeConfig } = op(\"updateFile\");\n router.patch(\n {\n authentication: { action: \"Update\", resource: \"file-upload\" },\n ...routeConfig,\n path: `${basePathname}:fileType/:fileName`,\n },\n ...processMiddleware(before),\n fileUploadController.updateFile,\n ...processMiddleware(after),\n sendResponse,\n ...processMiddleware(onError, { type: \"error\" })\n );\n }\n\n // DELETE FILE\n {\n const { before, after, onError, routeConfig } = op(\"deleteFile\");\n router.delete(\n {\n authentication: { action: \"Delete\", resource: \"file-upload\" },\n ...routeConfig,\n path: `${basePathname}:fileType/:fileName`,\n },\n ...processMiddleware(before),\n fileUploadController.deleteFile,\n ...processMiddleware(after),\n sendResponse,\n ...processMiddleware(onError, { type: \"error\" })\n );\n }\n\n return router;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"file-upload.router.js","sourceRoot":"","sources":["../../../../src/modules/file-upload/file-upload.router.ts"],"names":[],"mappings":"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","sourcesContent":["import fileUploadController from \"./file-upload.controller\";\nimport express from \"express\";\nimport deepmerge from \"../../utils/helpers/deepmerge.helper\";\nimport { sendResponse } from \"../base/base.middlewares\";\nimport { processMiddleware } from \"../../utils/helpers/routers.helpers\";\nimport { adjustRequestUrl } from \"./utils/helpers/file-upload.helpers\";\nimport { ArkosNextFunction, ArkosRequest, ArkosResponse } from \"../../exports\";\nimport path from \"path\";\nimport ArkosRouter from \"../../utils/arkos-router\";\nimport loadableRegistry from \"../../components/arkos-loadable-registry\";\nimport {\n OperationByModule,\n routeHookReader,\n} from \"../../components/arkos-route-hook/reader\";\nimport { getArkosConfig } from \"../../server\";\nimport fileUploadJsonSchemaGenerator from \"./utils/file-upload-json-schema-generator\";\nimport AppError from \"../error-handler/utils/app-error\";\nimport { DEFAULT_UPLOAD_DIRS } from \"./utils/helpers/upload-path.helper\";\nimport { uploadServingRegistry } from \"./utils/helpers/upload-serving.registry\";\n\nexport function getFileUploadRouter() {\n const router = ArkosRouter();\n const { fileUpload, globalPrefix } = getArkosConfig();\n\n if (fileUpload?.enabled === false) {\n uploadServingRegistry.setFindFileServingEnabled(false);\n return router;\n }\n\n const routeHook = loadableRegistry.getItem(\"ArkosRouteHook\", \"file-upload\");\n\n const op = (operation: OperationByModule<\"file-upload\">) => {\n let components = routeHook\n ? routeHookReader.forOperation(\"file-upload\", operation)\n : {\n before: [],\n after: [],\n onError: [],\n routeConfig: {},\n };\n\n let endpointConfig = components.routeConfig || {};\n if (endpointConfig?.experimental?.openapi !== false)\n endpointConfig = {\n ...(endpointConfig || {}),\n experimental: {\n ...(endpointConfig?.experimental || {}),\n openapi: fileUploadJsonSchemaGenerator.getOpenApiConfig(\n endpointConfig,\n operation\n ),\n },\n };\n\n components.routeConfig = endpointConfig;\n return components;\n };\n\n let basePathname = fileUpload?.baseRoute || \"/api/uploads/\";\n if (!basePathname.startsWith(\"/\")) basePathname = \"/\" + basePathname;\n if (!basePathname.endsWith(\"/\")) basePathname = basePathname + \"/\";\n\n // FIND FILE\n {\n const { before, onError, routeConfig } = op(\"findFile\");\n const servingMode = fileUpload?.serving || \"all\";\n uploadServingRegistry.setFindFileServingEnabled(!routeConfig?.disabled);\n const baseUploadDirFullPath = path.resolve(\n path\n .join(process.cwd(), fileUpload?.baseUploadDir || \"uploads\")\n .replaceAll(\"//\", \"/\")\n );\n router.get(\n {\n authentication: { action: \"View\", resource: \"file-upload\" },\n ...routeConfig,\n path:\n servingMode === \"registered\"\n ? `${basePathname}:fileType/*slug`\n : `${basePathname}*slug`,\n },\n ...processMiddleware(before),\n adjustRequestUrl,\n ...(servingMode === \"registered\"\n ? [\n (req: ArkosRequest, _res: ArkosResponse, next: ArkosNextFunction) => {\n if (\n !(DEFAULT_UPLOAD_DIRS as readonly string[]).includes(\n req.params.fileType\n )\n )\n return next(\n new AppError(\n `File ${req.path} was not found`,\n 404,\n \"FileNotFound\",\n { filepath: req.path }\n )\n );\n\n next();\n },\n ]\n : []),\n express.static(\n baseUploadDirFullPath,\n deepmerge(\n {\n maxAge: \"1y\",\n etag: true,\n lastModified: true,\n dotfiles: \"ignore\",\n fallthrough: false,\n index: false,\n cacheControl: true,\n },\n fileUpload?.expressStatic || {}\n )\n ),\n (\n err: any,\n req: ArkosRequest,\n _res: ArkosResponse,\n next: ArkosNextFunction\n ) => {\n if (err.code === \"ENOENT\") {\n const filepath = req.path.replace(\n `${globalPrefix}/${fileUpload?.baseRoute}`.replace(\"//\", \"/\"),\n \"\"\n );\n throw new AppError(\n `File ${filepath} was not found`,\n 404,\n \"FileNotFound\",\n { filepath }\n );\n }\n\n next(err);\n },\n ...processMiddleware(onError, { type: \"error\" })\n );\n }\n\n // UPLOAD FILE\n {\n const { before, after, onError, routeConfig } = op(\"uploadFile\");\n router.post(\n {\n authentication: { action: \"Create\", resource: \"file-upload\" },\n ...routeConfig,\n path: `${basePathname}:fileType`,\n },\n ...processMiddleware(before),\n fileUploadController.uploadFile,\n ...processMiddleware(after),\n sendResponse,\n ...processMiddleware(onError, { type: \"error\" })\n );\n }\n\n // UPDATE FILE\n {\n const { before, after, onError, routeConfig } = op(\"updateFile\");\n router.patch(\n {\n authentication: { action: \"Update\", resource: \"file-upload\" },\n ...routeConfig,\n path: `${basePathname}:fileType/*fileName`,\n },\n ...processMiddleware(before),\n fileUploadController.updateFile,\n ...processMiddleware(after),\n sendResponse,\n ...processMiddleware(onError, { type: \"error\" })\n );\n }\n\n // DELETE FILE\n {\n const { before, after, onError, routeConfig } = op(\"deleteFile\");\n router.delete(\n {\n authentication: { action: \"Delete\", resource: \"file-upload\" },\n ...routeConfig,\n path: `${basePathname}:fileType/*fileName`,\n },\n ...processMiddleware(before),\n fileUploadController.deleteFile,\n ...processMiddleware(after),\n sendResponse,\n ...processMiddleware(onError, { type: \"error\" })\n );\n }\n\n return router;\n}\n"]}
|
|
@@ -5,9 +5,18 @@ import AppError from "../error-handler/utils/app-error.js";
|
|
|
5
5
|
import { promisify } from "util";
|
|
6
6
|
import { getArkosConfig } from "../../server.js";
|
|
7
7
|
import deepmerge from "../../utils/helpers/deepmerge.helper.js";
|
|
8
|
-
import { processFile, processImage } from "./utils/helpers/file-upload.helpers.js";
|
|
8
|
+
import { processFile, processImage, } from "./utils/helpers/file-upload.helpers.js";
|
|
9
9
|
import { removeBothSlashes } from "../../utils/helpers/text.helpers.js";
|
|
10
10
|
import { pascalCase } from "../../exports/utils/index.js";
|
|
11
|
+
import { resolveUploadPath } from "./utils/helpers/upload-path.helper.js";
|
|
12
|
+
function decodeUploadFileName(fileName) {
|
|
13
|
+
try {
|
|
14
|
+
return decodeURIComponent(fileName);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return fileName;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
11
20
|
export class FileUploadService {
|
|
12
21
|
uploadDir;
|
|
13
22
|
fileSizeLimit;
|
|
@@ -116,37 +125,36 @@ export class FileUploadService {
|
|
|
116
125
|
? pathAfterBaseRoute.substring(1)
|
|
117
126
|
: pathAfterBaseRoute;
|
|
118
127
|
const fileTypes = ["images", "videos", "documents", "files"];
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (typeIndex !== -1) {
|
|
124
|
-
fileType = type;
|
|
125
|
-
fileName = cleanPath.substring(typeIndex + type.length + 1);
|
|
126
|
-
break;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
if (!fileType || !fileName) {
|
|
128
|
+
const [fileType, ...fileNameSegments] = cleanPath.split("/");
|
|
129
|
+
if (!fileType ||
|
|
130
|
+
!fileTypes.includes(fileType) ||
|
|
131
|
+
fileNameSegments.length === 0) {
|
|
130
132
|
throw new AppError("Unable to determine file type or file name from URL", 400, "UnableToProcessFileURL");
|
|
131
133
|
}
|
|
134
|
+
const fileName = fileNameSegments
|
|
135
|
+
.map(decodeUploadFileName)
|
|
136
|
+
.join("/");
|
|
132
137
|
const { documentUploadService, fileUploadService, imageUploadService, videoUploadService, } = getFileUploadServices();
|
|
133
|
-
let
|
|
138
|
+
let targetService;
|
|
134
139
|
switch (fileType) {
|
|
135
140
|
case "images":
|
|
136
|
-
|
|
141
|
+
targetService = imageUploadService;
|
|
137
142
|
break;
|
|
138
143
|
case "videos":
|
|
139
|
-
|
|
144
|
+
targetService = videoUploadService;
|
|
140
145
|
break;
|
|
141
146
|
case "documents":
|
|
142
|
-
|
|
147
|
+
targetService = documentUploadService;
|
|
143
148
|
break;
|
|
144
149
|
case "files":
|
|
145
|
-
|
|
150
|
+
targetService = fileUploadService;
|
|
146
151
|
break;
|
|
147
152
|
default:
|
|
148
153
|
throw new AppError(`Unsupported file type: ${fileType}`, 400, "UnsupportedFileType");
|
|
149
154
|
}
|
|
155
|
+
const filePath = resolveUploadPath(targetService.uploadDir, fileName);
|
|
156
|
+
if (!filePath)
|
|
157
|
+
throw new AppError("File not found", 404, "FileNotFound");
|
|
150
158
|
await promisify(fs.stat)(filePath);
|
|
151
159
|
await promisify(fs.unlink)(filePath);
|
|
152
160
|
return true;
|
|
@@ -250,7 +258,9 @@ export class FileUploadService {
|
|
|
250
258
|
default:
|
|
251
259
|
throw new AppError(`Unsupported file type: ${fileType}`, 400);
|
|
252
260
|
}
|
|
253
|
-
const filePath =
|
|
261
|
+
const filePath = resolveUploadPath(targetService.uploadDir, fileName);
|
|
262
|
+
if (!filePath)
|
|
263
|
+
throw new AppError("File not found", 404, "FileNotFound");
|
|
254
264
|
await promisify(fs.stat)(filePath);
|
|
255
265
|
await promisify(fs.unlink)(filePath);
|
|
256
266
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-upload.service.js","sourceRoot":"","sources":["../../../../src/modules/file-upload/file-upload.service.ts"],"names":[],"mappings":"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","sourcesContent":["import multer, { MulterError, StorageEngine } from \"multer\";\nimport path from \"path\";\nimport fs from \"fs\";\nimport { NextFunction } from \"express\";\nimport AppError from \"../error-handler/utils/app-error\";\nimport { promisify } from \"util\";\nimport { getArkosConfig } from \"../../server\";\nimport deepmerge from \"../../utils/helpers/deepmerge.helper\";\nimport {\n ArkosNextFunction,\n ArkosRequest,\n ArkosRequestHandler,\n ArkosResponse,\n} from \"../../types\";\nimport { processFile, processImage } from \"./utils/helpers/file-upload.helpers\";\nimport { removeBothSlashes } from \"../../utils/helpers/text.helpers\";\nimport { pascalCase } from \"../../exports/utils\";\n\n/**\n * Service to handle file uploads, including single and multiple file uploads,\n * file validation (type, size), and file deletion.\n */\nexport class FileUploadService {\n public readonly uploadDir: string;\n private fileSizeLimit: number;\n private allowedFileTypes: RegExp;\n private storage: StorageEngine;\n private maxCount: number;\n\n private handleUploadError(err: any, next: ArkosNextFunction) {\n if (err instanceof MulterError)\n return next(\n new AppError(\n err.message,\n 400,\n pascalCase(err.code || \"FileUploadError\")\n )\n );\n else return next(err);\n }\n\n /**\n * Constructor to initialize the file uploader service.\n * @param {string} uploadDir - The directory where files will be uploaded.\n * @param {number} fileSizeLimit - The maximum allowed file size.\n * @param {RegExp} allowedFileTypes - The regular expression for allowed file types.\n */\n constructor(\n uploadDir: string,\n fileSizeLimit: number = 1024 * 1024 * 5,\n allowedFileTypes: RegExp = /.*/,\n maxCount: number = 30\n ) {\n uploadDir = uploadDir.startsWith(\"/\") ? uploadDir.substring(1) : uploadDir;\n uploadDir = uploadDir.endsWith(\"/\") ? uploadDir.slice(0, -1) : uploadDir;\n\n this.uploadDir = path.resolve(process.cwd(), `${uploadDir}/`);\n this.fileSizeLimit = fileSizeLimit;\n this.allowedFileTypes = allowedFileTypes;\n this.maxCount = maxCount;\n\n if (!fs.existsSync(this.uploadDir))\n fs.mkdirSync(this.uploadDir, { recursive: true });\n\n this.storage = multer.diskStorage({\n destination: (_, _1, cb) => {\n cb(null, this.uploadDir);\n },\n filename: (_, file, cb) => {\n const uniqueSuffix = Date.now() + \"-\" + Math.round(Math.random() * 1e9);\n const ext = path.extname(file.originalname);\n cb(null, `${file.originalname.replace(ext, \"\")}-${uniqueSuffix}${ext}`);\n },\n });\n }\n\n /**\n * Validates the file's type and MIME type.\n * @param {Express.Multer.File} file - The uploaded file.\n * @param {Function} cb - The callback function to indicate if file is valid.\n */\n private fileFilter = (_: any, file: any, cb: any) => {\n const extName = this.allowedFileTypes.test(\n path.extname(file.originalname).toLowerCase()\n );\n\n if (extName) cb(null, true);\n else\n cb(\n new AppError(\n `File type not allowed, allowed files are ${String(this.allowedFileTypes).replaceAll(\"/\", \"\").split(\"|\").join(\", \")}`,\n 400,\n \"FileTypeNotAllowed\",\n { filename: file.originalname }\n )\n );\n };\n\n /**\n * Returns the multer upload configuration.\n * @returns {multer.Multer} The multer instance configured for file uploads.\n */\n public getUpload(): multer.Multer {\n return multer({\n storage: this.storage,\n fileFilter: this.fileFilter,\n limits: { fileSize: this.fileSizeLimit },\n });\n }\n\n /**\n * Middleware to handle single file upload.\n * @param {string} [oldFilePath] - The path to the file to delete before uploading.\n * @returns {Function} Middleware function for handling file upload.\n */\n public handleSingleUpload(oldFilePath?: string): ArkosRequestHandler {\n return (req: ArkosRequest, res: ArkosResponse, next: NextFunction) => {\n const upload = this.getUpload().single(this.getFieldName());\n upload(req, res, async (err) => {\n if (err) return this.handleUploadError(err, next);\n\n if (oldFilePath) {\n const { fileUpload: configs } = getArkosConfig();\n\n const filePath = path.resolve(\n process.cwd(),\n removeBothSlashes(configs?.baseUploadDir!),\n removeBothSlashes(oldFilePath)\n );\n try {\n const stats = await promisify(fs.stat)(filePath);\n if (stats) await promisify(fs.unlink)(filePath);\n } catch (err) {\n console.error(err);\n }\n }\n\n next();\n });\n };\n }\n\n /**\n * Middleware to handle multiple file uploads.\n * @returns {Function} Middleware function for handling multiple file uploads.\n */\n public handleMultipleUpload(): ArkosRequestHandler {\n return (req: ArkosRequest, res: ArkosResponse, next: NextFunction) => {\n const upload = this.getUpload().array(this.getFieldName(), this.maxCount);\n upload(req, res, next);\n };\n }\n\n /**\n * Middleware to handle deletion of a single file from the filesystem.\n * @param {string} oldFilePath - The path to the file to be deleted.\n * @returns {Function} Middleware function for handling file deletion.\n */\n public handleDeleteSingleFile(oldFilePath: string): ArkosRequestHandler {\n return async (_: ArkosRequest, _1: ArkosResponse, next: NextFunction) => {\n const filePath = path.join(oldFilePath);\n try {\n const stats = await promisify(fs.stat)(filePath);\n if (stats) {\n await promisify(fs.unlink)(filePath);\n }\n } catch (err) {\n console.error(err);\n }\n\n next();\n };\n }\n\n /**\n * Deletes a file based on its URL by identifying the appropriate uploader service\n * @param {string} fileUrl - The URL of the file to delete\n * @returns {Promise<boolean>} - True if deletion successful, false otherwise\n */\n public async deleteFileByUrl(fileUrl: string): Promise<boolean> {\n try {\n const { fileUpload } = getArkosConfig();\n const baseRoute = fileUpload?.baseRoute || \"/api/uploads\";\n\n let urlPath: string;\n if (fileUrl.startsWith(\"http\")) {\n const url = new URL(fileUrl);\n urlPath = url.pathname;\n } else urlPath = fileUrl;\n\n const baseRouteIndex = urlPath.indexOf(baseRoute);\n if (baseRouteIndex === -1)\n throw new AppError(\n \"Invalid file URL: base route not found\",\n 400,\n \"InvalidFileUrl\"\n );\n\n const pathAfterBaseRoute = urlPath.substring(\n baseRouteIndex + baseRoute.length\n );\n const cleanPath = pathAfterBaseRoute.startsWith(\"/\")\n ? pathAfterBaseRoute.substring(1)\n : pathAfterBaseRoute;\n\n const fileTypes = [\"images\", \"videos\", \"documents\", \"files\"];\n let fileType: string | null = null;\n let fileName: string | null = null;\n\n for (const type of fileTypes) {\n const typeIndex = cleanPath.indexOf(type + \"/\");\n if (typeIndex !== -1) {\n fileType = type;\n fileName = cleanPath.substring(typeIndex + type.length + 1);\n break;\n }\n }\n\n if (!fileType || !fileName) {\n throw new AppError(\n \"Unable to determine file type or file name from URL\",\n 400,\n \"UnableToProcessFileURL\"\n );\n }\n\n // Get the appropriate uploader service based on file type\n const {\n documentUploadService,\n fileUploadService,\n imageUploadService,\n videoUploadService,\n } = getFileUploadServices();\n\n let filePath: string;\n switch (fileType) {\n case \"images\":\n filePath = path.join(imageUploadService.uploadDir, fileName);\n break;\n case \"videos\":\n filePath = path.join(videoUploadService.uploadDir, fileName);\n break;\n case \"documents\":\n filePath = path.join(documentUploadService.uploadDir, fileName);\n break;\n case \"files\":\n filePath = path.join(fileUploadService.uploadDir, fileName);\n break;\n default:\n throw new AppError(\n `Unsupported file type: ${fileType}`,\n 400,\n \"UnsupportedFileType\"\n );\n }\n\n await promisify(fs.stat)(filePath);\n await promisify(fs.unlink)(filePath);\n\n return true;\n } catch (error: any) {\n if (error instanceof AppError) {\n throw error;\n }\n\n if (error.code === \"ENOENT\")\n throw new AppError(\"File not found\", 404, \"FileNotFound\");\n\n throw new AppError(\n `Failed to delete file: ${error.message}`,\n 500,\n \"UnableToDeleteFile\"\n );\n }\n }\n\n private getFieldName() {\n let fieldName = \"files\";\n if (this.uploadDir.endsWith(\"images\") || this.uploadDir.endsWith(\"images/\"))\n fieldName = \"images\";\n if (this.uploadDir.endsWith(\"videos\") || this.uploadDir.endsWith(\"videos/\"))\n fieldName = \"videos\";\n if (\n this.uploadDir.endsWith(\"documents\") ||\n this.uploadDir.endsWith(\"documents/\")\n )\n fieldName = \"documents\";\n if (this.uploadDir.endsWith(\"files\") || this.uploadDir.endsWith(\"files/\"))\n fieldName = \"files\";\n return fieldName;\n }\n\n /**\n * Handles the upload process and returns the full URLs of uploaded files\n * @param {ArkosRequest} req - Arkos request object containing the files\n * @param {ArkosResponse} res - Arkos response object\n * @param {object} options - Optional parameters for image processing\n * @returns {Promise<string|string[]>} URL or array of URLs to the uploaded files\n */\n public async upload(\n req: ArkosRequest,\n res: ArkosResponse,\n next: ArkosNextFunction,\n options: {\n format?: string;\n width?: number;\n height?: number;\n resizeTo?: number;\n } = {}\n ): Promise<string | string[] | null> {\n const { fileUpload } = getArkosConfig();\n fileUpload?.baseRoute || \"/api/uploads\";\n\n return new Promise((resolve, reject) => {\n const isMultiple = Array.isArray(req.query.multiple)\n ? req.query.multiple[0] == \"true\"\n : req.query.multiple == \"true\";\n\n const uploadHandler = isMultiple\n ? this.getUpload().array(this.getFieldName(), this.maxCount)\n : this.getUpload().single(this.getFieldName());\n\n uploadHandler(req, res, async (err) => {\n if (err && err instanceof MulterError)\n return reject(\n new AppError(\n err.message,\n 400,\n pascalCase(err.code || \"FileUploadError\")\n )\n );\n else if (err) reject(err);\n\n try {\n const dirParts = this.uploadDir.split(\"/\");\n (this.uploadDir.endsWith(\"/\")\n ? dirParts[dirParts.length - 2]\n : dirParts[dirParts.length - 1]) || \"files\";\n\n let data;\n if (req.files && Array.isArray(req.files) && req.files.length > 0) {\n const isImageUpload = this.uploadDir?.includes?.(\"/images\");\n if (isImageUpload) {\n data = await Promise.all(\n req.files.map((file) =>\n processImage(req, next, file.path, options)\n )\n );\n } else {\n data = await Promise.all(\n req.files.map((file) => processFile(req, file.path))\n );\n }\n\n data = data.filter((url) => url !== null);\n } else if (req.file) {\n const isImageUpload = this.uploadDir?.includes?.(\"/images\");\n if (isImageUpload) {\n data = await processImage(req, next, req.file.path, options);\n } else {\n data = processFile(req, req.file.path);\n }\n } else {\n return reject(\n new AppError(\n `No file or files were attached on field ${req.params.fileType} on the request body as form data.`,\n 400,\n \"NoFileOrFilesAttached\"\n )\n );\n }\n\n resolve(data);\n } catch (error) {\n reject(error);\n }\n });\n });\n }\n\n /**\n * Deletes a file based on filename and file type from request parameters\n * @param {string} fileName - The name of the file to delete\n * @returns {Promise<boolean>} - True if deletion successful, false otherwise\n */\n public async deleteFileByName(\n fileName: string,\n fileType: \"images\" | \"videos\" | \"documents\" | \"files\"\n ): Promise<boolean> {\n try {\n if (!fileType)\n throw new AppError(\n \"File type parameter is required\",\n 400,\n \"MissingFileType\"\n );\n\n const validFileTypes = [\"images\", \"videos\", \"documents\", \"files\"];\n if (!validFileTypes.includes(fileType)) {\n throw new AppError(\n `Invalid file type: ${fileType}. Must be one of: ${validFileTypes.join(\n \", \"\n )}`,\n 400\n );\n }\n\n const {\n documentUploadService,\n fileUploadService,\n imageUploadService,\n videoUploadService,\n } = getFileUploadServices();\n\n let targetService: FileUploadService;\n switch (fileType) {\n case \"images\":\n targetService = imageUploadService;\n break;\n case \"videos\":\n targetService = videoUploadService;\n break;\n case \"documents\":\n targetService = documentUploadService;\n break;\n case \"files\":\n targetService = fileUploadService;\n break;\n default:\n throw new AppError(`Unsupported file type: ${fileType}`, 400);\n }\n\n // Construct the full file path\n const filePath = path.join(targetService.uploadDir, fileName);\n\n // Check if file exists and delete it\n await promisify(fs.stat)(filePath);\n await promisify(fs.unlink)(filePath);\n\n return true;\n } catch (error: any) {\n if (error instanceof AppError) {\n throw error;\n }\n\n if (error.code === \"ENOENT\")\n throw new AppError(\"File not found\", 404, \"FileNotFound\");\n\n throw new AppError(\n `Failed to delete file: ${error.message}`,\n 500,\n \"UnableToDeleteFile\"\n );\n }\n }\n}\n\n/**\n * Creates and returns all file uploader services based on config\n * @returns Object containing all specialized file uploader services\n */\nexport const getFileUploadServices = () => {\n const { fileUpload } = getArkosConfig();\n const baseUploadDir = fileUpload?.baseUploadDir || \"/uploads\";\n\n const restrictions = fileUpload?.restrictions\n ? deepmerge(fileUploadDefaultRestrictions, fileUpload.restrictions)\n : fileUploadDefaultRestrictions;\n\n /**\n * Specialized file uploader service for handling image uploads.\n */\n const imageUploadService = new FileUploadService(\n `${baseUploadDir}/images`,\n restrictions.images.maxSize,\n restrictions.images.supportedFilesRegex,\n restrictions.images.maxCount\n );\n\n /**\n * Specialized file uploader service for handling video uploads.\n */\n const videoUploadService = new FileUploadService(\n `${baseUploadDir}/videos`,\n restrictions.videos.maxSize,\n restrictions.videos.supportedFilesRegex,\n restrictions.videos.maxCount\n );\n\n /**\n * Specialized file uploader service for handling document uploads.\n */\n const documentUploadService = new FileUploadService(\n `${baseUploadDir}/documents`,\n restrictions.documents.maxSize,\n restrictions.documents.supportedFilesRegex,\n restrictions.documents.maxCount\n );\n\n /**\n * Generic file uploader service for handling all file uploads.\n */\n const fileUploadService = new FileUploadService(\n `${baseUploadDir}/files`,\n restrictions.files.maxSize,\n restrictions.files.supportedFilesRegex,\n restrictions.files.maxCount\n );\n\n return {\n imageUploadService,\n videoUploadService,\n documentUploadService,\n fileUploadService,\n };\n};\n\nexport const fileUploadDefaultRestrictions = {\n images: {\n maxCount: 30,\n maxSize: 1024 * 1024 * 15, // 15 MB\n supportedFilesRegex:\n /jpeg|jpg|png|gif|webp|svg|bmp|tiff|heif|heic|ico|jfif|raw|cr2|nef|orf|sr2|arw|dng|pef|raf|rw2|psd|ai|eps|xcf|jxr|wdp|hdp|jp2|j2k|jpf|jpx|jpm|mj2|avif/,\n },\n videos: {\n maxCount: 10,\n maxSize: 1024 * 1024 * 5096, // 5 GB\n supportedFilesRegex:\n /mp4|avi|mov|mkv|flv|wmv|webm|mpg|mpeg|3gp|m4v|ts|rm|rmvb|vob|ogv|dv|qt|asf|m2ts|mts|divx|f4v|swf|mxf|roq|nsv|mvb|svi|mpe|m2v|mp2|mpv|h264|h265|hevc/,\n },\n documents: {\n maxCount: 30,\n maxSize: 1024 * 1024 * 50, // 50 MB\n supportedFilesRegex:\n /pdf|doc|docx|xls|xlsx|ppt|pptx|odt|ods|odg|odp|txt|rtf|csv|epub|md|tex|pages|numbers|key|xml|json|yaml|yml|ini|cfg|conf|log|html|htm|xhtml|djvu|mobi|azw|azw3|fb2|lit|ps|wpd|wps|dot|dotx|xlt|xltx|pot|potx|oft|one|onetoc2|opf|oxps|hwp/,\n },\n files: {\n maxCount: 10,\n maxSize: 1024 * 1024 * 5096, // 5 GB\n supportedFilesRegex: /.*/,\n },\n};\n"]}
|
|
1
|
+
{"version":3,"file":"file-upload.service.js","sourceRoot":"","sources":["../../../../src/modules/file-upload/file-upload.service.ts"],"names":[],"mappings":"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","sourcesContent":["import multer, { MulterError, StorageEngine } from \"multer\";\nimport path from \"path\";\nimport fs from \"fs\";\nimport { NextFunction } from \"express\";\nimport AppError from \"../error-handler/utils/app-error\";\nimport { promisify } from \"util\";\nimport { getArkosConfig } from \"../../server\";\nimport deepmerge from \"../../utils/helpers/deepmerge.helper\";\nimport {\n ArkosNextFunction,\n ArkosRequest,\n ArkosRequestHandler,\n ArkosResponse,\n} from \"../../types\";\nimport {\n ImageOptimizationOptions,\n processFile,\n processImage,\n} from \"./utils/helpers/file-upload.helpers\";\nimport { removeBothSlashes } from \"../../utils/helpers/text.helpers\";\nimport { pascalCase } from \"../../exports/utils\";\nimport { resolveUploadPath } from \"./utils/helpers/upload-path.helper\";\n\nfunction decodeUploadFileName(fileName: string): string {\n try {\n return decodeURIComponent(fileName);\n } catch {\n return fileName;\n }\n}\n\n/**\n * Service to handle file uploads, including single and multiple file uploads,\n * file validation (type, size), and file deletion.\n */\nexport class FileUploadService {\n public readonly uploadDir: string;\n private fileSizeLimit: number;\n private allowedFileTypes: RegExp;\n private storage: StorageEngine;\n private maxCount: number;\n\n private handleUploadError(err: any, next: ArkosNextFunction) {\n if (err instanceof MulterError)\n return next(\n new AppError(\n err.message,\n 400,\n pascalCase(err.code || \"FileUploadError\")\n )\n );\n else return next(err);\n }\n\n /**\n * Constructor to initialize the file uploader service.\n * @param {string} uploadDir - The directory where files will be uploaded.\n * @param {number} fileSizeLimit - The maximum allowed file size.\n * @param {RegExp} allowedFileTypes - The regular expression for allowed file types.\n */\n constructor(\n uploadDir: string,\n fileSizeLimit: number = 1024 * 1024 * 5,\n allowedFileTypes: RegExp = /.*/,\n maxCount: number = 30\n ) {\n uploadDir = uploadDir.startsWith(\"/\") ? uploadDir.substring(1) : uploadDir;\n uploadDir = uploadDir.endsWith(\"/\") ? uploadDir.slice(0, -1) : uploadDir;\n\n this.uploadDir = path.resolve(process.cwd(), `${uploadDir}/`);\n this.fileSizeLimit = fileSizeLimit;\n this.allowedFileTypes = allowedFileTypes;\n this.maxCount = maxCount;\n\n if (!fs.existsSync(this.uploadDir))\n fs.mkdirSync(this.uploadDir, { recursive: true });\n\n this.storage = multer.diskStorage({\n destination: (_, _1, cb) => {\n cb(null, this.uploadDir);\n },\n filename: (_, file, cb) => {\n const uniqueSuffix = Date.now() + \"-\" + Math.round(Math.random() * 1e9);\n const ext = path.extname(file.originalname);\n cb(null, `${file.originalname.replace(ext, \"\")}-${uniqueSuffix}${ext}`);\n },\n });\n }\n\n /**\n * Validates the file's type and MIME type.\n * @param {Express.Multer.File} file - The uploaded file.\n * @param {Function} cb - The callback function to indicate if file is valid.\n */\n private fileFilter = (_: any, file: any, cb: any) => {\n const extName = this.allowedFileTypes.test(\n path.extname(file.originalname).toLowerCase()\n );\n\n if (extName) cb(null, true);\n else\n cb(\n new AppError(\n `File type not allowed, allowed files are ${String(this.allowedFileTypes).replaceAll(\"/\", \"\").split(\"|\").join(\", \")}`,\n 400,\n \"FileTypeNotAllowed\",\n { filename: file.originalname }\n )\n );\n };\n\n /**\n * Returns the multer upload configuration.\n * @returns {multer.Multer} The multer instance configured for file uploads.\n */\n public getUpload(): multer.Multer {\n return multer({\n storage: this.storage,\n fileFilter: this.fileFilter,\n limits: { fileSize: this.fileSizeLimit },\n });\n }\n\n /**\n * Middleware to handle single file upload.\n * @param {string} [oldFilePath] - The path to the file to delete before uploading.\n * @returns {Function} Middleware function for handling file upload.\n */\n public handleSingleUpload(oldFilePath?: string): ArkosRequestHandler {\n return (req: ArkosRequest, res: ArkosResponse, next: NextFunction) => {\n const upload = this.getUpload().single(this.getFieldName());\n upload(req, res, async (err) => {\n if (err) return this.handleUploadError(err, next);\n\n if (oldFilePath) {\n const { fileUpload: configs } = getArkosConfig();\n\n const filePath = path.resolve(\n process.cwd(),\n removeBothSlashes(configs?.baseUploadDir!),\n removeBothSlashes(oldFilePath)\n );\n try {\n const stats = await promisify(fs.stat)(filePath);\n if (stats) await promisify(fs.unlink)(filePath);\n } catch (err) {\n console.error(err);\n }\n }\n\n next();\n });\n };\n }\n\n /**\n * Middleware to handle multiple file uploads.\n * @returns {Function} Middleware function for handling multiple file uploads.\n */\n public handleMultipleUpload(): ArkosRequestHandler {\n return (req: ArkosRequest, res: ArkosResponse, next: NextFunction) => {\n const upload = this.getUpload().array(this.getFieldName(), this.maxCount);\n upload(req, res, next);\n };\n }\n\n /**\n * Middleware to handle deletion of a single file from the filesystem.\n * @param {string} oldFilePath - The path to the file to be deleted.\n * @returns {Function} Middleware function for handling file deletion.\n */\n public handleDeleteSingleFile(oldFilePath: string): ArkosRequestHandler {\n return async (_: ArkosRequest, _1: ArkosResponse, next: NextFunction) => {\n const filePath = path.join(oldFilePath);\n try {\n const stats = await promisify(fs.stat)(filePath);\n if (stats) {\n await promisify(fs.unlink)(filePath);\n }\n } catch (err) {\n console.error(err);\n }\n\n next();\n };\n }\n\n /**\n * Deletes a file based on its URL by identifying the appropriate uploader service\n * @param {string} fileUrl - The URL of the file to delete\n * @returns {Promise<boolean>} - True if deletion successful, false otherwise\n */\n public async deleteFileByUrl(fileUrl: string): Promise<boolean> {\n try {\n const { fileUpload } = getArkosConfig();\n const baseRoute = fileUpload?.baseRoute || \"/api/uploads\";\n\n let urlPath: string;\n if (fileUrl.startsWith(\"http\")) {\n const url = new URL(fileUrl);\n urlPath = url.pathname;\n } else urlPath = fileUrl;\n\n const baseRouteIndex = urlPath.indexOf(baseRoute);\n if (baseRouteIndex === -1)\n throw new AppError(\n \"Invalid file URL: base route not found\",\n 400,\n \"InvalidFileUrl\"\n );\n\n const pathAfterBaseRoute = urlPath.substring(\n baseRouteIndex + baseRoute.length\n );\n const cleanPath = pathAfterBaseRoute.startsWith(\"/\")\n ? pathAfterBaseRoute.substring(1)\n : pathAfterBaseRoute;\n\n const fileTypes = [\"images\", \"videos\", \"documents\", \"files\"];\n const [fileType, ...fileNameSegments] = cleanPath.split(\"/\");\n\n if (\n !fileType ||\n !fileTypes.includes(fileType) ||\n fileNameSegments.length === 0\n ) {\n throw new AppError(\n \"Unable to determine file type or file name from URL\",\n 400,\n \"UnableToProcessFileURL\"\n );\n }\n\n const fileName = fileNameSegments\n .map(decodeUploadFileName)\n .join(\"/\");\n\n // Get the appropriate uploader service based on file type\n const {\n documentUploadService,\n fileUploadService,\n imageUploadService,\n videoUploadService,\n } = getFileUploadServices();\n\n let targetService: FileUploadService;\n switch (fileType) {\n case \"images\":\n targetService = imageUploadService;\n break;\n case \"videos\":\n targetService = videoUploadService;\n break;\n case \"documents\":\n targetService = documentUploadService;\n break;\n case \"files\":\n targetService = fileUploadService;\n break;\n default:\n throw new AppError(\n `Unsupported file type: ${fileType}`,\n 400,\n \"UnsupportedFileType\"\n );\n }\n\n const filePath = resolveUploadPath(targetService.uploadDir, fileName);\n\n if (!filePath) throw new AppError(\"File not found\", 404, \"FileNotFound\");\n\n await promisify(fs.stat)(filePath);\n await promisify(fs.unlink)(filePath);\n\n return true;\n } catch (error: any) {\n if (error instanceof AppError) {\n throw error;\n }\n\n if (error.code === \"ENOENT\")\n throw new AppError(\"File not found\", 404, \"FileNotFound\");\n\n throw new AppError(\n `Failed to delete file: ${error.message}`,\n 500,\n \"UnableToDeleteFile\"\n );\n }\n }\n\n private getFieldName() {\n let fieldName = \"files\";\n if (this.uploadDir.endsWith(\"images\") || this.uploadDir.endsWith(\"images/\"))\n fieldName = \"images\";\n if (this.uploadDir.endsWith(\"videos\") || this.uploadDir.endsWith(\"videos/\"))\n fieldName = \"videos\";\n if (\n this.uploadDir.endsWith(\"documents\") ||\n this.uploadDir.endsWith(\"documents/\")\n )\n fieldName = \"documents\";\n if (this.uploadDir.endsWith(\"files\") || this.uploadDir.endsWith(\"files/\"))\n fieldName = \"files\";\n return fieldName;\n }\n\n /**\n * Handles the upload process and returns the full URLs of uploaded files\n * @param {ArkosRequest} req - Arkos request object containing the files\n * @param {ArkosResponse} res - Arkos response object\n * @param {object} options - Optional parameters for image processing\n * @returns {Promise<string|string[]>} URL or array of URLs to the uploaded files\n */\n public async upload(\n req: ArkosRequest,\n res: ArkosResponse,\n next: ArkosNextFunction,\n options: ImageOptimizationOptions = {}\n ): Promise<string | string[] | null> {\n const { fileUpload } = getArkosConfig();\n fileUpload?.baseRoute || \"/api/uploads\";\n\n return new Promise((resolve, reject) => {\n const isMultiple = Array.isArray(req.query.multiple)\n ? req.query.multiple[0] == \"true\"\n : req.query.multiple == \"true\";\n\n const uploadHandler = isMultiple\n ? this.getUpload().array(this.getFieldName(), this.maxCount)\n : this.getUpload().single(this.getFieldName());\n\n uploadHandler(req, res, async (err) => {\n if (err && err instanceof MulterError)\n return reject(\n new AppError(\n err.message,\n 400,\n pascalCase(err.code || \"FileUploadError\")\n )\n );\n else if (err) reject(err);\n\n try {\n const dirParts = this.uploadDir.split(\"/\");\n (this.uploadDir.endsWith(\"/\")\n ? dirParts[dirParts.length - 2]\n : dirParts[dirParts.length - 1]) || \"files\";\n\n let data;\n if (req.files && Array.isArray(req.files) && req.files.length > 0) {\n const isImageUpload = this.uploadDir?.includes?.(\"/images\");\n if (isImageUpload) {\n data = await Promise.all(\n req.files.map((file) =>\n processImage(req, next, file.path, options)\n )\n );\n } else {\n data = await Promise.all(\n req.files.map((file) => processFile(req, file.path))\n );\n }\n\n data = data.filter((url) => url !== null);\n } else if (req.file) {\n const isImageUpload = this.uploadDir?.includes?.(\"/images\");\n if (isImageUpload) {\n data = await processImage(req, next, req.file.path, options);\n } else {\n data = processFile(req, req.file.path);\n }\n } else {\n return reject(\n new AppError(\n `No file or files were attached on field ${req.params.fileType} on the request body as form data.`,\n 400,\n \"NoFileOrFilesAttached\"\n )\n );\n }\n\n resolve(data);\n } catch (error) {\n reject(error);\n }\n });\n });\n }\n\n /**\n * Deletes a file based on filename and file type from request parameters\n * @param {string} fileName - The name of the file to delete\n * @returns {Promise<boolean>} - True if deletion successful, false otherwise\n */\n public async deleteFileByName(\n fileName: string,\n fileType: \"images\" | \"videos\" | \"documents\" | \"files\"\n ): Promise<boolean> {\n try {\n if (!fileType)\n throw new AppError(\n \"File type parameter is required\",\n 400,\n \"MissingFileType\"\n );\n\n const validFileTypes = [\"images\", \"videos\", \"documents\", \"files\"];\n if (!validFileTypes.includes(fileType)) {\n throw new AppError(\n `Invalid file type: ${fileType}. Must be one of: ${validFileTypes.join(\n \", \"\n )}`,\n 400\n );\n }\n\n const {\n documentUploadService,\n fileUploadService,\n imageUploadService,\n videoUploadService,\n } = getFileUploadServices();\n\n let targetService: FileUploadService;\n switch (fileType) {\n case \"images\":\n targetService = imageUploadService;\n break;\n case \"videos\":\n targetService = videoUploadService;\n break;\n case \"documents\":\n targetService = documentUploadService;\n break;\n case \"files\":\n targetService = fileUploadService;\n break;\n default:\n throw new AppError(`Unsupported file type: ${fileType}`, 400);\n }\n\n const filePath = resolveUploadPath(targetService.uploadDir, fileName);\n\n if (!filePath) throw new AppError(\"File not found\", 404, \"FileNotFound\");\n\n // Check if file exists and delete it\n await promisify(fs.stat)(filePath);\n await promisify(fs.unlink)(filePath);\n\n return true;\n } catch (error: any) {\n if (error instanceof AppError) {\n throw error;\n }\n\n if (error.code === \"ENOENT\")\n throw new AppError(\"File not found\", 404, \"FileNotFound\");\n\n throw new AppError(\n `Failed to delete file: ${error.message}`,\n 500,\n \"UnableToDeleteFile\"\n );\n }\n }\n}\n\n/**\n * Creates and returns all file uploader services based on config\n * @returns Object containing all specialized file uploader services\n */\nexport const getFileUploadServices = () => {\n const { fileUpload } = getArkosConfig();\n const baseUploadDir = fileUpload?.baseUploadDir || \"/uploads\";\n\n const restrictions = fileUpload?.restrictions\n ? deepmerge(fileUploadDefaultRestrictions, fileUpload.restrictions)\n : fileUploadDefaultRestrictions;\n\n /**\n * Specialized file uploader service for handling image uploads.\n */\n const imageUploadService = new FileUploadService(\n `${baseUploadDir}/images`,\n restrictions.images.maxSize,\n restrictions.images.supportedFilesRegex,\n restrictions.images.maxCount\n );\n\n /**\n * Specialized file uploader service for handling video uploads.\n */\n const videoUploadService = new FileUploadService(\n `${baseUploadDir}/videos`,\n restrictions.videos.maxSize,\n restrictions.videos.supportedFilesRegex,\n restrictions.videos.maxCount\n );\n\n /**\n * Specialized file uploader service for handling document uploads.\n */\n const documentUploadService = new FileUploadService(\n `${baseUploadDir}/documents`,\n restrictions.documents.maxSize,\n restrictions.documents.supportedFilesRegex,\n restrictions.documents.maxCount\n );\n\n /**\n * Generic file uploader service for handling all file uploads.\n */\n const fileUploadService = new FileUploadService(\n `${baseUploadDir}/files`,\n restrictions.files.maxSize,\n restrictions.files.supportedFilesRegex,\n restrictions.files.maxCount\n );\n\n return {\n imageUploadService,\n videoUploadService,\n documentUploadService,\n fileUploadService,\n };\n};\n\nexport const fileUploadDefaultRestrictions = {\n images: {\n maxCount: 30,\n maxSize: 1024 * 1024 * 15, // 15 MB\n supportedFilesRegex:\n /jpeg|jpg|png|gif|webp|svg|bmp|tiff|heif|heic|ico|jfif|raw|cr2|nef|orf|sr2|arw|dng|pef|raf|rw2|psd|ai|eps|xcf|jxr|wdp|hdp|jp2|j2k|jpf|jpx|jpm|mj2|avif/,\n },\n videos: {\n maxCount: 10,\n maxSize: 1024 * 1024 * 5096, // 5 GB\n supportedFilesRegex:\n /mp4|avi|mov|mkv|flv|wmv|webm|mpg|mpeg|3gp|m4v|ts|rm|rmvb|vob|ogv|dv|qt|asf|m2ts|mts|divx|f4v|swf|mxf|roq|nsv|mvb|svi|mpe|m2v|mp2|mpv|h264|h265|hevc/,\n },\n documents: {\n maxCount: 30,\n maxSize: 1024 * 1024 * 50, // 50 MB\n supportedFilesRegex:\n /pdf|doc|docx|xls|xlsx|ppt|pptx|odt|ods|odg|odp|txt|rtf|csv|epub|md|tex|pages|numbers|key|xml|json|yaml|yml|ini|cfg|conf|log|html|htm|xhtml|djvu|mobi|azw|azw3|fb2|lit|ps|wpd|wps|dot|dotx|xlt|xltx|pot|potx|oft|one|onetoc2|opf|oxps|hwp/,\n },\n files: {\n maxCount: 10,\n maxSize: 1024 * 1024 * 5096, // 5 GB\n supportedFilesRegex: /.*/,\n },\n};\n"]}
|
|
@@ -89,11 +89,15 @@ class FileUploadJsonSchemaGenerator {
|
|
|
89
89
|
name: "resizeTo",
|
|
90
90
|
in: "query",
|
|
91
91
|
required: false,
|
|
92
|
-
schema: {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
92
|
+
schema: { type: "integer", minimum: 1 },
|
|
93
|
+
description: "Target size in pixels to fit within, keeps aspect ratio (only applicable for fileType=images)",
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: "quality",
|
|
97
|
+
in: "query",
|
|
98
|
+
required: false,
|
|
99
|
+
schema: { type: "integer", minimum: 1, maximum: 100 },
|
|
100
|
+
description: "Output quality for lossy formats like webp/jpeg/avif (only applicable for fileType=images)",
|
|
97
101
|
},
|
|
98
102
|
];
|
|
99
103
|
}
|
|
@@ -106,7 +110,10 @@ class FileUploadJsonSchemaGenerator {
|
|
|
106
110
|
const existingOpenApi = endpointRouterConfig?.experimental?.openapi || {};
|
|
107
111
|
switch (endpoint) {
|
|
108
112
|
case "findFile": {
|
|
109
|
-
const
|
|
113
|
+
const isRegistered = arkosConfig.fileUpload?.serving === "registered";
|
|
114
|
+
const pathname = isRegistered
|
|
115
|
+
? `${cleanBasePath}/:fileType/*`
|
|
116
|
+
: `${cleanBasePath}/*`;
|
|
110
117
|
return {
|
|
111
118
|
...existingOpenApi,
|
|
112
119
|
tags: ["File Upload", ...(existingOpenApi?.tags || [])].filter((tag) => tag !== "Defaults"),
|
|
@@ -114,7 +121,9 @@ class FileUploadJsonSchemaGenerator {
|
|
|
114
121
|
? "Retrieve uploaded file"
|
|
115
122
|
: existingOpenApi.summary,
|
|
116
123
|
description: existingOpenApi?.description ||
|
|
117
|
-
|
|
124
|
+
(isRegistered
|
|
125
|
+
? `Serves files from the registered upload directories (${arkosConfig.fileUpload?.baseUploadDir || "uploads"}/images, videos, documents, files).`
|
|
126
|
+
: `Serves static files from the upload directory (${arkosConfig.fileUpload?.baseUploadDir || "uploads"}). Uses wildcard path matching to serve files from any subdirectory.`),
|
|
118
127
|
operationId: existingOpenApi?.operationId?.includes(pathname) ||
|
|
119
128
|
!existingOpenApi?.operationId
|
|
120
129
|
? "findFile"
|
|
@@ -122,12 +131,28 @@ class FileUploadJsonSchemaGenerator {
|
|
|
122
131
|
parameters: [
|
|
123
132
|
...(existingOpenApi?.parameters || []),
|
|
124
133
|
...[
|
|
134
|
+
...(isRegistered
|
|
135
|
+
? [
|
|
136
|
+
{
|
|
137
|
+
name: "fileType",
|
|
138
|
+
in: "path",
|
|
139
|
+
required: true,
|
|
140
|
+
schema: {
|
|
141
|
+
type: "string",
|
|
142
|
+
enum: ["images", "videos", "documents", "files"],
|
|
143
|
+
},
|
|
144
|
+
description: "Type of file being retrieved",
|
|
145
|
+
},
|
|
146
|
+
]
|
|
147
|
+
: []),
|
|
125
148
|
{
|
|
126
149
|
name: "slug",
|
|
127
150
|
in: "path",
|
|
128
151
|
required: true,
|
|
129
152
|
schema: { type: "string" },
|
|
130
|
-
description:
|
|
153
|
+
description: isRegistered
|
|
154
|
+
? "Path to the file within the file type directory (e.g., photo.jpg)"
|
|
155
|
+
: "Path to the file including file type directory (e.g., images/photo.jpg)",
|
|
131
156
|
},
|
|
132
157
|
].filter((p) => !(existingOpenApi?.parameters || []).find((ep) => ep.name === p.name && ep.in === p.in)),
|
|
133
158
|
],
|
|
@@ -214,7 +239,7 @@ class FileUploadJsonSchemaGenerator {
|
|
|
214
239
|
};
|
|
215
240
|
}
|
|
216
241
|
case "updateFile": {
|
|
217
|
-
const pathname = `${cleanBasePath}/:fileType/:fileName`;
|
|
242
|
+
const pathname = `${cleanBasePath}/:fileType/:fileName(.+)`;
|
|
218
243
|
return {
|
|
219
244
|
...existingOpenApi,
|
|
220
245
|
tags: ["File Upload", ...(existingOpenApi?.tags || [])].filter((tag) => tag !== "Defaults"),
|
|
@@ -245,7 +270,7 @@ class FileUploadJsonSchemaGenerator {
|
|
|
245
270
|
in: "path",
|
|
246
271
|
required: true,
|
|
247
272
|
schema: { type: "string" },
|
|
248
|
-
description: "Name of the file to update",
|
|
273
|
+
description: "Name of the file to update, including its subdirectory (e.g., profile/photo.jpg)",
|
|
249
274
|
},
|
|
250
275
|
...this.getImageQueryParameters(),
|
|
251
276
|
].filter((p) => !(existingOpenApi?.parameters || []).find((ep) => ep.name === p.name && ep.in === p.in)),
|
|
@@ -290,7 +315,7 @@ class FileUploadJsonSchemaGenerator {
|
|
|
290
315
|
};
|
|
291
316
|
}
|
|
292
317
|
case "deleteFile": {
|
|
293
|
-
const pathname = `${cleanBasePath}/:fileType/:fileName`;
|
|
318
|
+
const pathname = `${cleanBasePath}/:fileType/:fileName(.+)`;
|
|
294
319
|
return {
|
|
295
320
|
...existingOpenApi,
|
|
296
321
|
tags: ["File Upload", ...(existingOpenApi?.tags || [])].filter((tag) => tag !== "Defaults"),
|
|
@@ -321,7 +346,7 @@ class FileUploadJsonSchemaGenerator {
|
|
|
321
346
|
in: "path",
|
|
322
347
|
required: true,
|
|
323
348
|
schema: { type: "string" },
|
|
324
|
-
description: "Name of the file to delete",
|
|
349
|
+
description: "Name of the file to delete, including its subdirectory (e.g., profile/photo.jpg)",
|
|
325
350
|
},
|
|
326
351
|
].filter((p) => !(existingOpenApi?.parameters || []).find((ep) => ep.name === p.name && ep.in === p.in)),
|
|
327
352
|
],
|