fiberx-backend-toolkit 0.1.11 → 0.1.12

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.
@@ -71,3 +71,21 @@ export declare const CONTENT_LANG_KEY = "CONTENT_LANG";
71
71
  export declare const DEFAULT_CONTENT_URL = "http://localhost:4000/content/{{type}}_content/{{lang}}.json";
72
72
  export declare const DEFAULT_CONTENT_LANG = "en-GB";
73
73
  export declare const DEFAULT_CONTENT_CACHE_TTL: number;
74
+ export declare const FILE_UPLOAD_LIMITS: {
75
+ IMAGE_MAX_SIZE: number;
76
+ VIDEO_MAX_SIZE: number;
77
+ DOCUMENT_MAX_SIZE: number;
78
+ };
79
+ export declare const FILE_UPLOAD_ENV_KEYS: {
80
+ IMAGE_MAX_SIZE: string;
81
+ VIDEO_MAX_SIZE: string;
82
+ DOCUMENT_MAX_SIZE: string;
83
+ IMAGE_MIME_TYPES: string;
84
+ VIDEO_MIME_TYPES: string;
85
+ DOCUMENT_MIME_TYPES: string;
86
+ };
87
+ export declare const FILE_UPLOAD_ALLOWED_MIME_TYPES: {
88
+ image: string[];
89
+ video: string[];
90
+ document: string[];
91
+ };
@@ -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.DEFAULT_CONTENT_CACHE_TTL = exports.DEFAULT_CONTENT_LANG = exports.DEFAULT_CONTENT_URL = exports.CONTENT_LANG_KEY = exports.CONTENT_URL_KEY = exports.CONTENT_CACHE_TTL_KEY = exports.EMAIL_ENQUEUE_UTIL_FILE_NAME = exports.EMAIL_ENQUEUE_TYPES_FILE_NAME = exports.DEFAULT_MAILER_CACHE_TTL = exports.DEFAULT_MAILER_CACHE_KEY = exports.DEFAULT_RBAC_CACHE_TTL = exports.DEFAULT_RBAC_CACHE_KEY = exports.DEFAULT_TOTP_WINDOW = exports.DEFAULT_TOTP_DIGITS = exports.DEFAULT_TOTP_STEP = exports.ALPHABET_CORPUS = exports.CHARACTER_CORPUS = exports.REQUEST_RATE_LIMITTER_OPTIONS = exports.CORS_MAX_AGE_IN_MICRO_SECONDS = exports.CORS_MAX_AGE_IN_SECONDS = exports.CORS_ALLOWED_HEADERS = exports.HEADERS_KEY_NAME = exports.CORS_ALLOWED_METHODS = exports.DEVICE_ID_HEADERS_NAME = exports.DEVICE_ID_COOKIE_NAME = exports.DEVICE_ID_COOKIE_MAX_AGE = exports.REQUEST_ID_HEADERS_NAME = exports.REQUEST_ID_COOKIE_NAME = exports.REQUEST_ID_COOKIE_MAX_AGE = exports.SEQUELIZE_SEEDER_META_TABLE_NAME = exports.SEQUELIZE_META_TABLE_NAME = exports.EMAIL_PREVIEW_DIR = exports.EMAIL_ENQUEUE_DIR = exports.SEEDERS_DIR = exports.MIGRATIONS_DIR = exports.MODELS_DIR = exports.SCHEMA_SNAPSHOTS_DIR = exports.SCHEMAS_DIR = exports.ENV_VAR_DIR = exports.LOG_DIR = exports.BASE_DIR = void 0;
6
+ exports.FILE_UPLOAD_ALLOWED_MIME_TYPES = exports.FILE_UPLOAD_ENV_KEYS = exports.FILE_UPLOAD_LIMITS = exports.DEFAULT_CONTENT_CACHE_TTL = exports.DEFAULT_CONTENT_LANG = exports.DEFAULT_CONTENT_URL = exports.CONTENT_LANG_KEY = exports.CONTENT_URL_KEY = exports.CONTENT_CACHE_TTL_KEY = exports.EMAIL_ENQUEUE_UTIL_FILE_NAME = exports.EMAIL_ENQUEUE_TYPES_FILE_NAME = exports.DEFAULT_MAILER_CACHE_TTL = exports.DEFAULT_MAILER_CACHE_KEY = exports.DEFAULT_RBAC_CACHE_TTL = exports.DEFAULT_RBAC_CACHE_KEY = exports.DEFAULT_TOTP_WINDOW = exports.DEFAULT_TOTP_DIGITS = exports.DEFAULT_TOTP_STEP = exports.ALPHABET_CORPUS = exports.CHARACTER_CORPUS = exports.REQUEST_RATE_LIMITTER_OPTIONS = exports.CORS_MAX_AGE_IN_MICRO_SECONDS = exports.CORS_MAX_AGE_IN_SECONDS = exports.CORS_ALLOWED_HEADERS = exports.HEADERS_KEY_NAME = exports.CORS_ALLOWED_METHODS = exports.DEVICE_ID_HEADERS_NAME = exports.DEVICE_ID_COOKIE_NAME = exports.DEVICE_ID_COOKIE_MAX_AGE = exports.REQUEST_ID_HEADERS_NAME = exports.REQUEST_ID_COOKIE_NAME = exports.REQUEST_ID_COOKIE_MAX_AGE = exports.SEQUELIZE_SEEDER_META_TABLE_NAME = exports.SEQUELIZE_META_TABLE_NAME = exports.EMAIL_PREVIEW_DIR = exports.EMAIL_ENQUEUE_DIR = exports.SEEDERS_DIR = exports.MIGRATIONS_DIR = exports.MODELS_DIR = exports.SCHEMA_SNAPSHOTS_DIR = exports.SCHEMAS_DIR = exports.ENV_VAR_DIR = exports.LOG_DIR = exports.BASE_DIR = void 0;
7
7
  const path_1 = __importDefault(require("path"));
8
8
  exports.BASE_DIR = process.cwd();
9
9
  exports.LOG_DIR = path_1.default.join(exports.BASE_DIR, "logs");
@@ -120,3 +120,23 @@ exports.CONTENT_LANG_KEY = "CONTENT_LANG";
120
120
  exports.DEFAULT_CONTENT_URL = "http://localhost:4000/content/{{type}}_content/{{lang}}.json";
121
121
  exports.DEFAULT_CONTENT_LANG = "en-GB";
122
122
  exports.DEFAULT_CONTENT_CACHE_TTL = (1000 * 60 * 60 * 24); // 24 hours
123
+ // src/config/constants.ts
124
+ // src/config/constants.ts
125
+ exports.FILE_UPLOAD_LIMITS = {
126
+ IMAGE_MAX_SIZE: 5 * 1024 * 1024,
127
+ VIDEO_MAX_SIZE: 50 * 1024 * 1024,
128
+ DOCUMENT_MAX_SIZE: 10 * 1024 * 1024
129
+ };
130
+ exports.FILE_UPLOAD_ENV_KEYS = {
131
+ IMAGE_MAX_SIZE: "FILE_UPLOAD_IMAGE_MAX_SIZE",
132
+ VIDEO_MAX_SIZE: "FILE_UPLOAD_VIDEO_MAX_SIZE",
133
+ DOCUMENT_MAX_SIZE: "FILE_UPLOAD_DOCUMENT_MAX_SIZE",
134
+ IMAGE_MIME_TYPES: "FILE_UPLOAD_IMAGE_MIME_TYPES",
135
+ VIDEO_MIME_TYPES: "FILE_UPLOAD_VIDEO_MIME_TYPES",
136
+ DOCUMENT_MIME_TYPES: "FILE_UPLOAD_DOCUMENT_MIME_TYPES"
137
+ };
138
+ exports.FILE_UPLOAD_ALLOWED_MIME_TYPES = {
139
+ image: ["image/png", "image/jpeg", "image/webp"],
140
+ video: ["video/mp4", "video/webm"],
141
+ document: ["application/pdf", "application/msword"]
142
+ };
@@ -0,0 +1,11 @@
1
+ import { StorageDriver, StorageFile, StorageInitConfig } from "../../types/storage_type";
2
+ declare abstract class BaseStorageDriver implements StorageDriver {
3
+ abstract initialize(config: StorageInitConfig): Promise<void>;
4
+ abstract upload(...args: any[]): Promise<StorageFile>;
5
+ abstract get(key: string): Promise<StorageFile | null>;
6
+ abstract exists(key: string): Promise<boolean>;
7
+ abstract delete(key: string): Promise<void>;
8
+ abstract list(prefix?: string): Promise<StorageFile[]>;
9
+ abstract getPublicUrl(key: string): string;
10
+ }
11
+ export default BaseStorageDriver;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class BaseStorageDriver {
4
+ }
5
+ exports.default = BaseStorageDriver;
@@ -0,0 +1,21 @@
1
+ import BaseStorageDriver from "./base_storage_driver";
2
+ import { StorageInitConfig } from "../../types/storage_type";
3
+ declare class GCSStorageDriver extends BaseStorageDriver {
4
+ private bucket;
5
+ initialize(config: StorageInitConfig): Promise<void>;
6
+ upload(key: string, file: Buffer, mime_type: string, is_public?: boolean): Promise<{
7
+ key: string;
8
+ url: string;
9
+ mime_type: string;
10
+ size: number;
11
+ }>;
12
+ getPublicUrl(key: string): string;
13
+ exists(key: string): Promise<boolean>;
14
+ delete(key: string): Promise<void>;
15
+ get(key: string): Promise<{
16
+ key: string;
17
+ url: string;
18
+ } | null>;
19
+ list(prefix?: string): Promise<any>;
20
+ }
21
+ export default GCSStorageDriver;
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const storage_1 = require("@google-cloud/storage");
7
+ const base_storage_driver_1 = __importDefault(require("./base_storage_driver"));
8
+ class GCSStorageDriver extends base_storage_driver_1.default {
9
+ bucket;
10
+ async initialize(config) {
11
+ if (config.type !== "gcs") {
12
+ throw new Error("Invalid config for GCS");
13
+ }
14
+ const storage = new storage_1.Storage({
15
+ projectId: config.project_id,
16
+ credentials: config.credentials
17
+ });
18
+ this.bucket = storage.bucket(config.bucket_name);
19
+ }
20
+ async upload(key, file, mime_type, is_public = true) {
21
+ const file_ref = this.bucket.file(key);
22
+ await file_ref.save(file, {
23
+ contentType: mime_type
24
+ });
25
+ if (is_public) {
26
+ await file_ref.makePublic();
27
+ }
28
+ return {
29
+ key,
30
+ url: this.getPublicUrl(key),
31
+ mime_type,
32
+ size: file.length
33
+ };
34
+ }
35
+ getPublicUrl(key) {
36
+ return `https://storage.googleapis.com/${this.bucket.name}/${key}`;
37
+ }
38
+ async exists(key) {
39
+ const [exists] = await this.bucket.file(key).exists();
40
+ return exists;
41
+ }
42
+ async delete(key) {
43
+ await this.bucket.file(key).delete();
44
+ }
45
+ async get(key) {
46
+ const exists = await this.exists(key);
47
+ if (!exists)
48
+ return null;
49
+ return {
50
+ key,
51
+ url: this.getPublicUrl(key)
52
+ };
53
+ }
54
+ async list(prefix = "") {
55
+ const [files] = await this.bucket.getFiles({ prefix });
56
+ return files.map((f) => ({
57
+ key: f.name,
58
+ url: this.getPublicUrl(f.name)
59
+ }));
60
+ }
61
+ }
62
+ exports.default = GCSStorageDriver;
@@ -0,0 +1,22 @@
1
+ import BaseStorageDriver from "./base_storage_driver";
2
+ import { StorageInitConfig } from "../../types/storage_type";
3
+ declare class LocalStorageDriver extends BaseStorageDriver {
4
+ private base_dir;
5
+ private public_base_url;
6
+ initialize(config: StorageInitConfig): Promise<void>;
7
+ upload(key: string, file: Buffer, mime_type: string): Promise<{
8
+ key: string;
9
+ url: string;
10
+ mime_type: string;
11
+ size: number;
12
+ }>;
13
+ exists(key: string): Promise<boolean>;
14
+ getPublicUrl(key: string): string;
15
+ get(key: string): Promise<{
16
+ key: string;
17
+ url: string;
18
+ } | null>;
19
+ delete(key: string): Promise<void>;
20
+ list(prefix?: string): Promise<never[]>;
21
+ }
22
+ export default LocalStorageDriver;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const path_1 = __importDefault(require("path"));
7
+ const promises_1 = __importDefault(require("fs/promises"));
8
+ const base_storage_driver_1 = __importDefault(require("./base_storage_driver"));
9
+ class LocalStorageDriver extends base_storage_driver_1.default {
10
+ base_dir;
11
+ public_base_url;
12
+ async initialize(config) {
13
+ if (config.type !== "local") {
14
+ throw new Error("Invalid config for LocalStorageDriver");
15
+ }
16
+ this.base_dir = config.base_dir;
17
+ this.public_base_url = config.public_base_url || "";
18
+ await promises_1.default.mkdir(this.base_dir, { recursive: true });
19
+ }
20
+ async upload(key, file, mime_type) {
21
+ const full_path = path_1.default.join(this.base_dir, key);
22
+ await promises_1.default.mkdir(path_1.default.dirname(full_path), { recursive: true });
23
+ await promises_1.default.writeFile(full_path, file);
24
+ return {
25
+ key,
26
+ url: this.getPublicUrl(key),
27
+ mime_type,
28
+ size: file.length
29
+ };
30
+ }
31
+ async exists(key) {
32
+ try {
33
+ await promises_1.default.access(path_1.default.join(this.base_dir, key));
34
+ return true;
35
+ }
36
+ catch {
37
+ return false;
38
+ }
39
+ }
40
+ getPublicUrl(key) {
41
+ return `${this.public_base_url}/${key}`;
42
+ }
43
+ async get(key) {
44
+ const exists = await this.exists(key);
45
+ if (!exists)
46
+ return null;
47
+ return {
48
+ key,
49
+ url: this.getPublicUrl(key)
50
+ };
51
+ }
52
+ async delete(key) {
53
+ await promises_1.default.unlink(path_1.default.join(this.base_dir, key));
54
+ }
55
+ async list(prefix = "") {
56
+ // optional recursive implementation
57
+ return [];
58
+ }
59
+ }
60
+ exports.default = LocalStorageDriver;
@@ -0,0 +1,5 @@
1
+ import BaseStorageDriver from "./drivers/base_storage_driver";
2
+ import GCSStorageDriver from "./drivers/gcs_storage_driver";
3
+ import LocalStorageDriver from "./drivers/local_storage_driver";
4
+ import FileUploadProcessor from "./processors/file_upload_processor";
5
+ export { BaseStorageDriver, GCSStorageDriver, LocalStorageDriver, FileUploadProcessor, };
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.FileUploadProcessor = exports.LocalStorageDriver = exports.GCSStorageDriver = exports.BaseStorageDriver = void 0;
7
+ const base_storage_driver_1 = __importDefault(require("./drivers/base_storage_driver"));
8
+ exports.BaseStorageDriver = base_storage_driver_1.default;
9
+ const gcs_storage_driver_1 = __importDefault(require("./drivers/gcs_storage_driver"));
10
+ exports.GCSStorageDriver = gcs_storage_driver_1.default;
11
+ const local_storage_driver_1 = __importDefault(require("./drivers/local_storage_driver"));
12
+ exports.LocalStorageDriver = local_storage_driver_1.default;
13
+ const file_upload_processor_1 = __importDefault(require("./processors/file_upload_processor"));
14
+ exports.FileUploadProcessor = file_upload_processor_1.default;
@@ -0,0 +1,16 @@
1
+ import { FileUploadInput, FileUploadResult, StorageDriver } from "../../types/storage_type";
2
+ declare class FileUploadProcessor {
3
+ name: string;
4
+ private static instance;
5
+ private readonly driver;
6
+ private readonly logger;
7
+ private readonly env;
8
+ private readonly validator;
9
+ private constructor();
10
+ static initialize(driver: StorageDriver): FileUploadProcessor;
11
+ static getInstance(): FileUploadProcessor;
12
+ private getExtension;
13
+ private generateKey;
14
+ upload(input: FileUploadInput): Promise<FileUploadResult>;
15
+ }
16
+ export default FileUploadProcessor;
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const logger_util_1 = __importDefault(require("../../utils/logger_util"));
7
+ const env_manager_util_1 = __importDefault(require("../../utils/env_manager_util"));
8
+ const uuid_1 = require("uuid");
9
+ const file_validator_util_1 = __importDefault(require("../../validators/file_validator_util"));
10
+ class FileUploadProcessor {
11
+ name = "file_upload_processor";
12
+ static instance = null;
13
+ driver;
14
+ logger = new logger_util_1.default(this.name);
15
+ env = env_manager_util_1.default.getInstance();
16
+ validator = new file_validator_util_1.default();
17
+ constructor(driver) {
18
+ this.driver = driver;
19
+ }
20
+ static initialize(driver) {
21
+ if (this.instance) {
22
+ throw new Error("Already initialized");
23
+ }
24
+ this.instance = new FileUploadProcessor(driver);
25
+ return this.instance;
26
+ }
27
+ static getInstance() {
28
+ if (!this.instance) {
29
+ throw new Error("Not initialized");
30
+ }
31
+ return this.instance;
32
+ }
33
+ // ==============================
34
+ // EXTENSION HELPER
35
+ // ==============================
36
+ getExtension(file_name) {
37
+ const ext = file_name.split(".").pop();
38
+ return ext ? ext : "bin";
39
+ }
40
+ // ==============================
41
+ // KEY GENERATION
42
+ // ==============================
43
+ generateKey(category, ext, folder) {
44
+ return `${folder || "uploads"}/${category}/${(0, uuid_1.v4)()}.${ext}`;
45
+ }
46
+ // ==============================
47
+ // MAIN METHOD
48
+ // ==============================
49
+ async upload(input) {
50
+ try {
51
+ const category = this.validator.getCategory(input.mime_type);
52
+ // ✅ validate AFTER category detection
53
+ const { v_state, v_msg } = this.validator.validate(input, category);
54
+ if (!v_state) {
55
+ return { status: false, msg: v_msg };
56
+ }
57
+ const ext = this.getExtension(input.original_name);
58
+ const key = this.generateKey(category, ext, input.folder);
59
+ const stored = await this.driver.upload(key, input.file, input.mime_type, input.is_public ?? true);
60
+ if (!stored) {
61
+ return { status: false, msg: "failed_to_store_file" };
62
+ }
63
+ const result = {
64
+ key,
65
+ original_name: input.original_name,
66
+ mime_type: input.mime_type,
67
+ category,
68
+ size: input.size,
69
+ url: stored.url
70
+ };
71
+ this.logger.info("File uploaded successfully", {
72
+ key,
73
+ category,
74
+ size: input.size
75
+ });
76
+ return { status: true, msg: "file_uploaded_successfully", data: result };
77
+ }
78
+ catch (error) {
79
+ this.logger.error("Upload failed", {
80
+ error,
81
+ input_meta: {
82
+ name: input.original_name,
83
+ size: input.size,
84
+ mime: input.mime_type
85
+ }
86
+ });
87
+ return { status: false, msg: "file_upload_error_occured" };
88
+ }
89
+ }
90
+ }
91
+ exports.default = FileUploadProcessor;
@@ -8,3 +8,4 @@ export * from "./express_decelaration";
8
8
  export * from "./rbac_type";
9
9
  export * from "./mailer_type";
10
10
  export * from "./validator_type";
11
+ export * from "./storage_type";
@@ -24,3 +24,4 @@ __exportStar(require("./express_decelaration"), exports);
24
24
  __exportStar(require("./rbac_type"), exports);
25
25
  __exportStar(require("./mailer_type"), exports);
26
26
  __exportStar(require("./validator_type"), exports);
27
+ __exportStar(require("./storage_type"), exports);
@@ -0,0 +1,47 @@
1
+ export type StorageInitConfig = {
2
+ type: "gcs";
3
+ bucket_name: string;
4
+ project_id: string;
5
+ credentials: Record<string, any>;
6
+ } | {
7
+ type: "local";
8
+ base_dir: string;
9
+ public_base_url?: string;
10
+ };
11
+ export interface StorageFile {
12
+ key: string;
13
+ url: string;
14
+ size?: number;
15
+ mime_type?: string;
16
+ }
17
+ export interface StorageDriver {
18
+ initialize(config: StorageInitConfig): Promise<void>;
19
+ upload(key: string, file: Buffer, mime_type: string, is_public?: boolean): Promise<StorageFile | null>;
20
+ get(key: string): Promise<StorageFile | null>;
21
+ exists(key: string): Promise<boolean>;
22
+ delete(key: string): Promise<void>;
23
+ list(prefix?: string): Promise<StorageFile[]>;
24
+ getPublicUrl(key: string): string;
25
+ }
26
+ export type FileCategory = "image" | "video" | "document";
27
+ export interface FileUploadInput {
28
+ file: Buffer;
29
+ original_name: string;
30
+ mime_type: string;
31
+ size: number;
32
+ folder?: string;
33
+ is_public?: boolean;
34
+ }
35
+ export interface FileUploadDataPayloadInterface {
36
+ key: string;
37
+ original_name: string;
38
+ mime_type: string;
39
+ category: FileCategory;
40
+ size: number;
41
+ url: string;
42
+ }
43
+ export interface FileUploadResult {
44
+ status: boolean;
45
+ msg: string;
46
+ data?: FileUploadDataPayloadInterface;
47
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ // src/types/storage_type.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,12 @@
1
+ import { FileCategory, FileUploadInput } from "../types/storage_type";
2
+ import { QueryValidationResultInterface } from "../types/validator_type";
3
+ declare class FileValidatorUtil {
4
+ name: string;
5
+ private readonly logger;
6
+ private readonly env;
7
+ getCategory(mime: string): FileCategory;
8
+ private getMaxSize;
9
+ private getAllowedMimeTypes;
10
+ validate(input: FileUploadInput, category: FileCategory): QueryValidationResultInterface<null>;
11
+ }
12
+ export default FileValidatorUtil;
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ // src/storage/utils/file_validator_util.ts
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const logger_util_1 = __importDefault(require("../utils/logger_util"));
8
+ const env_manager_util_1 = __importDefault(require("../utils/env_manager_util"));
9
+ const constants_1 = require("../config/constants");
10
+ class FileValidatorUtil {
11
+ name = "file_validator_util";
12
+ logger = new logger_util_1.default(this.name);
13
+ env = env_manager_util_1.default.getInstance();
14
+ // ==============================
15
+ // CATEGORY
16
+ // ==============================
17
+ getCategory(mime) {
18
+ if (mime.startsWith("image/"))
19
+ return "image";
20
+ if (mime.startsWith("video/"))
21
+ return "video";
22
+ return "document";
23
+ }
24
+ // ==============================
25
+ // MAX SIZE
26
+ // ==============================
27
+ getMaxSize(category) {
28
+ switch (category) {
29
+ case "image":
30
+ return Number(this.env.getEnvVar(constants_1.FILE_UPLOAD_ENV_KEYS.IMAGE_MAX_SIZE, constants_1.FILE_UPLOAD_LIMITS.IMAGE_MAX_SIZE));
31
+ case "video":
32
+ return Number(this.env.getEnvVar(constants_1.FILE_UPLOAD_ENV_KEYS.VIDEO_MAX_SIZE, constants_1.FILE_UPLOAD_LIMITS.VIDEO_MAX_SIZE));
33
+ case "document":
34
+ default:
35
+ return Number(this.env.getEnvVar(constants_1.FILE_UPLOAD_ENV_KEYS.DOCUMENT_MAX_SIZE, constants_1.FILE_UPLOAD_LIMITS.DOCUMENT_MAX_SIZE));
36
+ }
37
+ }
38
+ // ==============================
39
+ // MIME TYPES
40
+ // ==============================
41
+ getAllowedMimeTypes(category) {
42
+ const env_value = this.env.getEnvVar(constants_1.FILE_UPLOAD_ENV_KEYS[`${category.toUpperCase()}_MIME_TYPES`]);
43
+ if (env_value) {
44
+ // allow both CSV string or array
45
+ if (Array.isArray(env_value))
46
+ return env_value;
47
+ return String(env_value)
48
+ .split(",")
49
+ .map((m) => m.trim());
50
+ }
51
+ return constants_1.FILE_UPLOAD_ALLOWED_MIME_TYPES[category];
52
+ }
53
+ // ==============================
54
+ // MAIN VALIDATION
55
+ // ==============================
56
+ validate(input, category) {
57
+ if (!input.mime_type) {
58
+ return { v_state: false, v_msg: "missing_mime_type" };
59
+ }
60
+ if (!input.original_name) {
61
+ return { v_state: false, v_msg: "missing_original_file_name" };
62
+ }
63
+ // 🔹 size validation
64
+ const max_size = this.getMaxSize(category);
65
+ if (input.size > max_size) {
66
+ this.logger.error("File size exceeds limit", {
67
+ size: input.size,
68
+ max_size,
69
+ category
70
+ });
71
+ return { v_state: false, v_msg: "file_size_to_large" };
72
+ }
73
+ // 🔹 mime validation
74
+ const allowed = this.getAllowedMimeTypes(category);
75
+ if (!allowed.includes(input.mime_type)) {
76
+ this.logger.error("Invalid mime type", {
77
+ mime: input.mime_type,
78
+ allowed,
79
+ category
80
+ });
81
+ return { v_state: false, v_msg: "invalid_file_mime_type" };
82
+ }
83
+ return { v_state: true, v_msg: "file_input_valid" };
84
+ }
85
+ }
86
+ exports.default = FileValidatorUtil;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fiberx-backend-toolkit",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "A TypeScript backend toolkit providing shared domain logic, infrastructure helpers, and utilities for FiberX server-side applications and services.",
5
5
  "type": "commonjs",
6
6
  "main": "./dist/index.js",
@@ -23,6 +23,7 @@
23
23
  "license": "ISC",
24
24
  "author": "David Matt-Ojo",
25
25
  "dependencies": {
26
+ "@google-cloud/storage": "^7.19.0",
26
27
  "@types/nodemailer": "^7.0.11",
27
28
  "axios": "^1.11.0",
28
29
  "bcrypt": "^6.0.0",