fiberx-backend-toolkit 0.1.11 → 0.1.13

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,28 @@ 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
+ LOCAL_STORAGE_BASE_DIR: string;
87
+ LOCAL_STORAGE_PUBLIC_URL: string;
88
+ GCS_PROJECT_ID: string;
89
+ GCS_BUCKET_NAME: string;
90
+ GCS_CLIENT_EMAIL: string;
91
+ GCS_PRIVATE_KEY: string;
92
+ STORAGE_DRIVER_NAME: string;
93
+ };
94
+ export declare const FILE_UPLOAD_ALLOWED_MIME_TYPES: {
95
+ image: string[];
96
+ video: string[];
97
+ document: string[];
98
+ };
@@ -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,30 @@ 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
+ LOCAL_STORAGE_BASE_DIR: "FILE_UPLOAD_LOCAL_STORAGE_BASE_DIR",
138
+ LOCAL_STORAGE_PUBLIC_URL: "FILE_UPLOAD_LOCAL_STORAGE_PUBLIC_URL",
139
+ GCS_PROJECT_ID: "FILE_UPLOAD_GCS_PROJECT_ID",
140
+ GCS_BUCKET_NAME: "FILE_UPLOAD_GCS_BUCKET_NAME",
141
+ GCS_CLIENT_EMAIL: "FILE_UPLOAD_GCS_CLIENT_EMAIL",
142
+ GCS_PRIVATE_KEY: "FILE_UPLOAD_GCS_PRIVATE_KEY",
143
+ STORAGE_DRIVER_NAME: "FILE_UPLOAD_STORAGE_DRIVER_NAME"
144
+ };
145
+ exports.FILE_UPLOAD_ALLOWED_MIME_TYPES = {
146
+ image: ["image/png", "image/jpeg", "image/webp"],
147
+ video: ["video/mp4", "video/webm"],
148
+ document: ["application/pdf", "application/msword"]
149
+ };
@@ -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,6 @@
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
+ import StorageDriverUtil from "./utils/storage_driver_util";
6
+ export { BaseStorageDriver, GCSStorageDriver, LocalStorageDriver, FileUploadProcessor, StorageDriverUtil };
@@ -0,0 +1,16 @@
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.StorageDriverUtil = 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;
15
+ const storage_driver_util_1 = __importDefault(require("./utils/storage_driver_util"));
16
+ exports.StorageDriverUtil = storage_driver_util_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;
@@ -0,0 +1,23 @@
1
+ import BaseStorageDriver from "../../storage/drivers/base_storage_driver";
2
+ declare class StorageDriverUtil {
3
+ private static instance;
4
+ private static logger;
5
+ private static env_manager;
6
+ /**
7
+ * Get initialized storage driver (singleton)
8
+ */
9
+ static getDriver(): Promise<BaseStorageDriver>;
10
+ /**
11
+ * Initialize driver based on environment
12
+ */
13
+ private static initializeDriver;
14
+ /**
15
+ * Local driver (development)
16
+ */
17
+ private static initLocalDriver;
18
+ /**
19
+ * GCS driver (staging/production)
20
+ */
21
+ private static initGCSDriver;
22
+ }
23
+ export default StorageDriverUtil;
@@ -0,0 +1,97 @@
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 main_1 = require("../../utils/main");
7
+ const constants_1 = require("../../config/constants");
8
+ const gcs_storage_driver_1 = __importDefault(require("../../storage/drivers/gcs_storage_driver"));
9
+ const local_storage_driver_1 = __importDefault(require("../../storage/drivers/local_storage_driver"));
10
+ class StorageDriverUtil {
11
+ static instance = null;
12
+ static logger = new main_1.LoggerUtil("storage_driver_util");
13
+ static env_manager = main_1.EnvManagerUtil.getInstance();
14
+ /**
15
+ * Get initialized storage driver (singleton)
16
+ */
17
+ static async getDriver() {
18
+ if (this.instance) {
19
+ return this.instance;
20
+ }
21
+ const driver = await this.initializeDriver();
22
+ this.instance = driver;
23
+ return driver;
24
+ }
25
+ /**
26
+ * Initialize driver based on environment
27
+ */
28
+ static async initializeDriver() {
29
+ try {
30
+ if (main_1.InputValidatorUtil.isDevelopment()) {
31
+ return await StorageDriverUtil.initLocalDriver();
32
+ }
33
+ if (main_1.InputValidatorUtil.isLive()) {
34
+ const driver_type = StorageDriverUtil.env_manager.getEnvVar(constants_1.FILE_UPLOAD_ENV_KEYS.STORAGE_DRIVER_NAME, "");
35
+ switch (driver_type?.toLowerCase()) {
36
+ case "local": return StorageDriverUtil.initLocalDriver();
37
+ case "gcs": return await StorageDriverUtil.initGCSDriver();
38
+ default: throw new Error(`Unsupported storage driver type '${driver_type}' in live environment`);
39
+ }
40
+ }
41
+ throw new Error("Unsupported environment for storage driver");
42
+ }
43
+ catch (error) {
44
+ this.logger.error("Failed to initialize storage driver", { error });
45
+ throw error;
46
+ }
47
+ }
48
+ /**
49
+ * Local driver (development)
50
+ */
51
+ static async initLocalDriver() {
52
+ const base_dir = StorageDriverUtil.env_manager.getEnvVar(constants_1.FILE_UPLOAD_ENV_KEYS.LOCAL_STORAGE_BASE_DIR, "");
53
+ const public_base_url = StorageDriverUtil.env_manager.getEnvVar(constants_1.FILE_UPLOAD_ENV_KEYS.LOCAL_STORAGE_PUBLIC_URL, "");
54
+ if (!base_dir) {
55
+ throw new Error("LOCAL_STORAGE_BASE_DIR is required for local storage");
56
+ }
57
+ const config = {
58
+ type: "local",
59
+ base_dir,
60
+ public_base_url
61
+ };
62
+ const driver = new local_storage_driver_1.default();
63
+ await driver.initialize(config);
64
+ this.logger.info("Initialized Local Storage Driver");
65
+ return driver;
66
+ }
67
+ /**
68
+ * GCS driver (staging/production)
69
+ */
70
+ static async initGCSDriver() {
71
+ const project_id = StorageDriverUtil.env_manager.getEnvVar(constants_1.FILE_UPLOAD_ENV_KEYS.GCS_PROJECT_ID, "");
72
+ const bucket_name = StorageDriverUtil.env_manager.getEnvVar(constants_1.FILE_UPLOAD_ENV_KEYS.GCS_BUCKET_NAME, "");
73
+ ;
74
+ const client_email = StorageDriverUtil.env_manager.getEnvVar(constants_1.FILE_UPLOAD_ENV_KEYS.GCS_CLIENT_EMAIL, "");
75
+ ;
76
+ const private_key = StorageDriverUtil.env_manager.getEnvVar(constants_1.FILE_UPLOAD_ENV_KEYS.GCS_PRIVATE_KEY, "");
77
+ ;
78
+ if (!project_id || !bucket_name || !client_email || !private_key) {
79
+ throw new Error("Missing required GCS environment variables");
80
+ }
81
+ const credentials = {
82
+ client_email,
83
+ private_key: private_key.replace(/\\n/g, "\n")
84
+ };
85
+ const config = {
86
+ type: "gcs",
87
+ project_id,
88
+ bucket_name,
89
+ credentials
90
+ };
91
+ const driver = new gcs_storage_driver_1.default();
92
+ await driver.initialize(config);
93
+ this.logger.info("Initialized GCS Storage Driver");
94
+ return driver;
95
+ }
96
+ }
97
+ exports.default = StorageDriverUtil;
@@ -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.13",
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",