fiberx-backend-toolkit 0.0.1 → 0.0.7

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.
Files changed (46) hide show
  1. package/dist/chunk-BK6YPN2O.js +1029 -0
  2. package/dist/chunk-BK6YPN2O.js.map +1 -0
  3. package/dist/chunk-FKITWVZO.js +21 -0
  4. package/dist/chunk-FKITWVZO.js.map +1 -0
  5. package/dist/database/index.d.ts +126 -0
  6. package/dist/database/index.js +1105 -0
  7. package/dist/database/index.js.map +1 -0
  8. package/dist/env_manager_util-DLs1b9Q7.d.ts +45 -0
  9. package/dist/index.d.ts +3 -0
  10. package/dist/index.js +1 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/types/index.d.ts +94 -0
  13. package/dist/types/index.js +7 -0
  14. package/dist/types/index.js.map +1 -0
  15. package/dist/util_type-Yyo1nXmm.d.ts +39 -0
  16. package/dist/utils/index.d.ts +264 -0
  17. package/dist/utils/index.js +22 -0
  18. package/dist/utils/index.js.map +1 -0
  19. package/package.json +8 -2
  20. package/src/code_templates/sequelize_code_template.ts +0 -362
  21. package/src/config/constants.ts +0 -14
  22. package/src/database/connectors/base_connector.ts +0 -21
  23. package/src/database/connectors/sequelize_connector.ts +0 -66
  24. package/src/database/index.ts +0 -27
  25. package/src/database/schema/schema_diff_util.ts +0 -96
  26. package/src/database/schema/schema_normalizer_util.ts +0 -54
  27. package/src/database/scripts/create_schema_script.ts +0 -108
  28. package/src/database/scripts/create_seeder_script.ts +0 -118
  29. package/src/database/scripts/make_migrations_script.ts +0 -275
  30. package/src/database/scripts/migration_runner_script.ts +0 -184
  31. package/src/database/scripts/seeder_runner_script.ts +0 -167
  32. package/src/index.ts +0 -2
  33. package/src/types/index.ts +0 -3
  34. package/src/types/migration_type.ts +0 -7
  35. package/src/types/schema_type.ts +0 -101
  36. package/src/types/util_type.ts +0 -36
  37. package/src/utils/env_manager_util.ts +0 -90
  38. package/src/utils/index.ts +0 -15
  39. package/src/utils/input_transformer_util.ts +0 -433
  40. package/src/utils/input_validator_util.ts +0 -156
  41. package/src/utils/logger_util.ts +0 -119
  42. package/src/utils/server_util.ts +0 -71
  43. package/src/utils/sql_formatter_util.ts +0 -50
  44. package/test.js +0 -1
  45. package/tsconfig.json +0 -25
  46. package/tsup.config.ts +0 -14
@@ -0,0 +1,1029 @@
1
+ // src/utils/logger_util.ts
2
+ import fs from "fs";
3
+ import path2 from "path";
4
+
5
+ // src/config/constants.ts
6
+ import path from "path";
7
+ var BASE_DIR = process.cwd();
8
+ var LOG_DIR = path.join(BASE_DIR, "logs");
9
+ var ENV_VAR_DIR = path.join(BASE_DIR, "environment_varaiables");
10
+ var SCHEMAS_DIR = path.join(BASE_DIR, "src/database/schemas");
11
+ var SCHEMA_SNAPSHOTS_DIR = path.join(BASE_DIR, "src/database/schema_snapshots");
12
+ var MODELS_DIR = path.join(BASE_DIR, "src/database/models");
13
+ var MIGRATIONS_DIR = path.join(BASE_DIR, "src/database/migrations");
14
+ var SEEDERS_DIR = path.join(BASE_DIR, "src/database/seeders");
15
+ var SEQUELIZE_META_TABLE_NAME = "sequelize_database_tables_meta";
16
+ var SEQUELIZE_SEEDER_META_TABLE_NAME = "sequelize_database_table_seeder_meta";
17
+ var REQUEST_ID_COOKIE_MAX_AGE = 1e3 * 60 * 60 * 24 * 7;
18
+ var CORS_MAX_AGE_IN_MICRO_SECONDS = 1e3 * 60 * 10;
19
+ var REQUEST_RATE_LIMITTER_OPTIONS = {
20
+ window_ms: 60 * 1e3,
21
+ // 1 MINS
22
+ max_requests: 50,
23
+ message: "\u23F3 Too many requests from this IP, please try again later"
24
+ };
25
+
26
+ // src/utils/logger_util.ts
27
+ var LoggerUtil = class {
28
+ module_name;
29
+ base_dir;
30
+ log_file_path;
31
+ log_directory;
32
+ store_log_locally;
33
+ constructor(module_name) {
34
+ this.module_name = module_name;
35
+ this.store_log_locally = true;
36
+ this.base_dir = process.cwd();
37
+ this.log_directory = this.ensureDirExists(LOG_DIR);
38
+ this.log_file_path = this.getLogFilePath();
39
+ }
40
+ /**
41
+ * Ensures a directory exists. If it doesn't, creates it.
42
+ * @param directory_path - Path to the directory
43
+ * @returns The absolute path of the ensured directory
44
+ */
45
+ ensureDirExists(directory_path) {
46
+ const resolved_path = path2.resolve(directory_path);
47
+ if (!fs.existsSync(resolved_path)) {
48
+ fs.mkdirSync(resolved_path, { recursive: true });
49
+ }
50
+ return resolved_path;
51
+ }
52
+ /**
53
+ * Generate log unique log file name with timestamp and module name
54
+ * @returns The absolute path of the module log file
55
+ */
56
+ getLogFilePath() {
57
+ const timestamp = Math.floor(Date.now() / 1e3);
58
+ const file_name = `${this.module_name}-${timestamp}.log`;
59
+ const log_file_path = path2.join(this.log_directory, file_name);
60
+ return log_file_path;
61
+ }
62
+ // Safely stringify objects while avoiding circular references
63
+ safeStringify(obj, space = 2) {
64
+ const seen = /* @__PURE__ */ new WeakSet();
65
+ return JSON.stringify(
66
+ obj,
67
+ (key, value) => {
68
+ if (typeof value === "object" && value !== null) {
69
+ if (seen.has(value)) {
70
+ return "[Circular]";
71
+ }
72
+ seen.add(value);
73
+ }
74
+ return value;
75
+ },
76
+ space
77
+ );
78
+ }
79
+ // Log a message with optional error data and level
80
+ log(message = "", data_error = {}, status = "INFO") {
81
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
82
+ const error_str = data_error && typeof data_error === "object" && Object.keys(data_error).length ? this.safeStringify(data_error, 0) : "";
83
+ const formatted_message = message.startsWith(`[${this.module_name}]`) ? message : `[${this.module_name}] ${message}`;
84
+ const log_line = `${timestamp} [${status}] ${formatted_message} ${error_str}
85
+ `;
86
+ const log_entry = { timestamp, status, message, data_error };
87
+ if (this.store_log_locally) {
88
+ fs.appendFileSync(this.log_file_path, log_line);
89
+ }
90
+ console.log(`
91
+ ${timestamp} [${status}] ${formatted_message}
92
+ `);
93
+ if (data_error && typeof data_error === "object" && Object.keys(data_error).length) {
94
+ console.log({ ...data_error });
95
+ console.log("\n");
96
+ console.log("========================================");
97
+ }
98
+ return log_entry;
99
+ }
100
+ // Log info-level messages
101
+ info(message, data = "") {
102
+ return this.log(message, data, "INFO");
103
+ }
104
+ // Log error-level messages
105
+ error(message, error = "") {
106
+ return this.log(message, error, "ERROR");
107
+ }
108
+ // Log alert-level messages
109
+ alert(message, data = "") {
110
+ return this.log(message, data, "ALERT");
111
+ }
112
+ // Log success-level messages
113
+ success(message, data = "") {
114
+ return this.log(message, data, "SUCCESS");
115
+ }
116
+ // Log how long a method took to execute
117
+ logExecutionTime(start_time, class_name, method_name) {
118
+ const [seconds, nanoseconds] = process.hrtime(start_time);
119
+ const duration_ms = (seconds * 1e3 + nanoseconds / 1e6).toFixed(2);
120
+ this.info(`${class_name} - ${method_name} completed in ${duration_ms}ms`);
121
+ }
122
+ };
123
+ var logger_util_default = LoggerUtil;
124
+
125
+ // src/utils/input_transformer_util.ts
126
+ import axios from "axios";
127
+ import bcrypt from "bcrypt";
128
+ import dayjs from "dayjs";
129
+ var InputTransformerUtil = class {
130
+ /**
131
+ * Lookup table for number formatting suffixes
132
+ */
133
+ static count_lookup = [
134
+ { value: 1, symbol: "" },
135
+ { value: 1e3, symbol: "K" },
136
+ { value: 1e6, symbol: "M" },
137
+ { value: 1e9, symbol: "B" },
138
+ { value: 1e12, symbol: "T" }
139
+ ];
140
+ /**
141
+ * Capitalize the first letter of a string
142
+ */
143
+ static capitalize(input) {
144
+ return input ? input.charAt(0).toUpperCase() + input.slice(1).toLowerCase() : input;
145
+ }
146
+ /**
147
+ * Capitalize the first letter of each word in a string
148
+ */
149
+ static capitalizeEachWord(input) {
150
+ if (!input) {
151
+ return "";
152
+ }
153
+ return input.split(" ").map((word) => this.capitalize(word)).join(" ");
154
+ }
155
+ /**
156
+ * Format date of birth to YYYY-MM-DD
157
+ */
158
+ static formatDob(dob) {
159
+ return dob ? dayjs(dob).format("YYYY-MM-DD") : null;
160
+ }
161
+ /**
162
+ * Format full name from first and last name
163
+ */
164
+ static formatMemberFullName(first_name, last_name) {
165
+ return first_name && last_name ? `${first_name} ${last_name}` : null;
166
+ }
167
+ /**
168
+ * Format member preview string
169
+ */
170
+ static formatMemberPreview(first_name, last_name, public_id) {
171
+ return first_name && last_name && public_id ? `(${public_id}) - ${first_name} ${last_name}` : null;
172
+ }
173
+ /**
174
+ * Format a number with commas
175
+ */
176
+ static formatAmount(amount) {
177
+ if (!amount) {
178
+ return "0";
179
+ }
180
+ return amount > 0 ? Intl.NumberFormat("en-US").format(amount) : amount.toString();
181
+ }
182
+ /**
183
+ * Format large numbers with suffixes (K, M, B, T)
184
+ */
185
+ static nFormatter(num, digits = 1) {
186
+ const lookup_item = this.count_lookup.slice().reverse().find((item) => num >= item.value);
187
+ if (!lookup_item) {
188
+ return "0";
189
+ }
190
+ const formatted_value = (num / lookup_item.value).toFixed(digits).replace(/\.0+$|(\.[0-9]*[1-9])0+$/, "$1");
191
+ return `${formatted_value}${lookup_item.symbol}`;
192
+ }
193
+ /**
194
+ * Round a number to two decimal places
195
+ */
196
+ static roundToTwoDecimalPlaces(value) {
197
+ if (typeof value !== "number") {
198
+ throw new Error("Input must be a number");
199
+ }
200
+ return Math.round(value * 100) / 100;
201
+ }
202
+ /**
203
+ * Remove leading zeros from a number or string
204
+ */
205
+ static removeLeadingZeros(value) {
206
+ return value.toString().replace(/^0+/, "") || "0";
207
+ }
208
+ /**
209
+ * Get country/location based on IP address
210
+ */
211
+ static async ipAddressToLocation(ip_address = null) {
212
+ try {
213
+ const suffix = !ip_address || ip_address === "::1" ? "s" : `?ip=${ip_address}`;
214
+ const response = await axios.get(`https://ip2c.org/${suffix}`);
215
+ const response_text = response.data.toString();
216
+ if (response_text[0] === "1") {
217
+ const location_parts = response_text.split(";");
218
+ return location_parts[location_parts.length - 1];
219
+ }
220
+ return "Unknown";
221
+ } catch (error) {
222
+ console.error(
223
+ `Error fetching location for IP ${ip_address}:`,
224
+ error
225
+ );
226
+ return "Unknown";
227
+ }
228
+ }
229
+ /**
230
+ * Convert date of birth string to age
231
+ */
232
+ static dobToAge(dob_string) {
233
+ const dob_date = new Date(dob_string);
234
+ const today = /* @__PURE__ */ new Date();
235
+ let age = today.getFullYear() - dob_date.getFullYear();
236
+ const month_difference = today.getMonth() - dob_date.getMonth();
237
+ if (month_difference < 0 || month_difference === 0 && today.getDate() < dob_date.getDate()) {
238
+ age--;
239
+ }
240
+ return age;
241
+ }
242
+ /**
243
+ * Hash plain text password
244
+ */
245
+ static textToPasswordHash(password) {
246
+ return bcrypt.hashSync(password, bcrypt.genSaltSync(10));
247
+ }
248
+ /**
249
+ * Ensures singular, snake_case, and appends `_schema`
250
+ * Example:
251
+ * - "Users" → "user_schema"
252
+ * - "UserProfile" → "user_profile_schema"
253
+ */
254
+ static toSchemaFileName(input) {
255
+ const snake = this.toSnakeCase(input);
256
+ const singular = snake.endsWith("s") ? snake.slice(0, -1) : snake;
257
+ return `${singular}_schema`;
258
+ }
259
+ /**
260
+ * Convert snake_case to Title Case
261
+ */
262
+ static toTitleCase(input) {
263
+ return input.split("_").map(
264
+ (word) => word.charAt(0).toUpperCase() + word.slice(1)
265
+ ).join(" ");
266
+ }
267
+ /**
268
+ * Convert snake_case to PascalCase
269
+ */
270
+ static toPascalCase(input) {
271
+ return input.split("_").map(
272
+ (word) => word.charAt(0).toUpperCase() + word.slice(1)
273
+ ).join("");
274
+ }
275
+ /**
276
+ * Convert string to snake_case
277
+ */
278
+ static toSnakeCase(input) {
279
+ return input.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/([A-Z])([A-Z][a-z])/g, "$1_$2").toLowerCase();
280
+ }
281
+ /**
282
+ * Pluralize a snake_case string
283
+ */
284
+ static pluralizeSnakeCase(snake_str) {
285
+ const parts = snake_str.split("_");
286
+ const last_word = parts.pop();
287
+ let plural_word;
288
+ if (last_word.endsWith("y") && !/[aeiou]y$/.test(last_word)) {
289
+ plural_word = last_word.slice(0, -1) + "ies";
290
+ } else if (["s", "x", "z"].includes(last_word.slice(-1)) || last_word.endsWith("ch") || last_word.endsWith("sh")) {
291
+ plural_word = `${last_word}es`;
292
+ } else {
293
+ plural_word = `${last_word}s`;
294
+ }
295
+ return [...parts, plural_word].join("_");
296
+ }
297
+ /**
298
+ * Remove empty, null, or undefined fields from an object
299
+ */
300
+ static filterOutEmptyFields(obj) {
301
+ const filtered_object = {};
302
+ for (const [key, value] of Object.entries(obj)) {
303
+ if (value !== null && value !== void 0 && !(typeof value === "string" && value.trim() === "") && !(Array.isArray(value) && value.length === 0)) {
304
+ filtered_object[key] = value;
305
+ }
306
+ }
307
+ return filtered_object;
308
+ }
309
+ /**
310
+ * Safely parse JSON input
311
+ */
312
+ static toJson(json_input) {
313
+ try {
314
+ if (!json_input) {
315
+ return null;
316
+ }
317
+ if (typeof json_input === "string") {
318
+ return JSON.parse(json_input);
319
+ }
320
+ if (typeof json_input === "object") {
321
+ return json_input;
322
+ }
323
+ return null;
324
+ } catch {
325
+ return null;
326
+ }
327
+ }
328
+ /**
329
+ * Calculate pagination offset and limit
330
+ */
331
+ static calculatePaginationOffset(page, size) {
332
+ const page_number = page > 0 ? page - 1 : 0;
333
+ const adjusted_size = size > 200 ? 200 : size;
334
+ const limit = adjusted_size || 10;
335
+ const offset = page_number * limit;
336
+ return { limit, offset };
337
+ }
338
+ /**
339
+ * Format paginated response
340
+ */
341
+ static formatPaginatedResponse(page, limit, data) {
342
+ const { count: total_items, rows: records } = data;
343
+ const current_page = page || 0;
344
+ const total_pages = Math.ceil(total_items / limit);
345
+ return {
346
+ total_items,
347
+ records,
348
+ total_pages,
349
+ current_page
350
+ };
351
+ }
352
+ /**
353
+ * Compare two records and detect changes
354
+ */
355
+ static detectChanges(old_record = {}, new_record = {}, keys_to_check) {
356
+ const structured_diff = {};
357
+ const all_keys = keys_to_check ?? Object.keys(new_record);
358
+ for (const key of all_keys) {
359
+ const old_value = old_record[key];
360
+ const new_value = new_record[key];
361
+ if (old_value == new_value) {
362
+ continue;
363
+ }
364
+ const formatted_old = typeof old_value === "object" && old_value !== null ? JSON.stringify(old_value) : String(old_value ?? "null");
365
+ const formatted_new = typeof new_value === "object" && new_value !== null ? JSON.stringify(new_value) : String(new_value ?? "null");
366
+ structured_diff[key] = {
367
+ old: formatted_old,
368
+ new: formatted_new
369
+ };
370
+ }
371
+ const readable_changes = Object.entries(
372
+ structured_diff
373
+ ).map(
374
+ ([key, value]) => `${key} changed from '${value.old}' \u2192 '${value.new}'`
375
+ ).join("; ");
376
+ return {
377
+ readable: readable_changes || "No significant changes detected",
378
+ structured: structured_diff
379
+ };
380
+ }
381
+ /**
382
+ * Normalize social links object keys
383
+ */
384
+ static formatLinksObject(links) {
385
+ const formatted_links = {};
386
+ for (const [key, value] of Object.entries(links)) {
387
+ const normalized_key = key.toLowerCase().endsWith("_link") ? key.toLowerCase() : `${key.toLowerCase()}_link`;
388
+ formatted_links[normalized_key] = value;
389
+ }
390
+ return formatted_links;
391
+ }
392
+ };
393
+ var input_transformer_util_default = InputTransformerUtil;
394
+
395
+ // src/utils/input_validator_util.ts
396
+ import fs3 from "fs";
397
+ import dayjs2 from "dayjs";
398
+ import isSameOrAfter from "dayjs/plugin/isSameOrAfter";
399
+ import bcrypt2 from "bcrypt";
400
+ import axios3 from "axios";
401
+
402
+ // src/utils/env_manager_util.ts
403
+ import fs2 from "fs";
404
+ import path3 from "path";
405
+ import yaml from "js-yaml";
406
+ import axios2 from "axios";
407
+ var EnvManagerUtil = class _EnvManagerUtil {
408
+ name = "env_manager_util";
409
+ env_file_name = "env.yaml";
410
+ static instance;
411
+ yaml_env_file_path;
412
+ logger;
413
+ env_data;
414
+ // 🔒 Private constructor
415
+ constructor() {
416
+ this.env_file_name = this.getEnvFileName();
417
+ this.yaml_env_file_path = path3.join(ENV_VAR_DIR, this.env_file_name);
418
+ this.logger = new logger_util_default(this.name);
419
+ this.env_data = this.readENVData();
420
+ }
421
+ // Method to get env file name
422
+ getEnvFileName() {
423
+ if (process?.env?.MODE === "development") {
424
+ return "env.yaml";
425
+ } else if (process?.env?.MODE === "staging") {
426
+ return "staging_env.yaml";
427
+ } else if (process?.env?.MODE === "production") {
428
+ return "production_env.yaml";
429
+ } else {
430
+ return "env.yaml";
431
+ }
432
+ }
433
+ // ✅ Global access point
434
+ static getInstance() {
435
+ if (!_EnvManagerUtil.instance) {
436
+ _EnvManagerUtil.instance = new _EnvManagerUtil();
437
+ }
438
+ return _EnvManagerUtil.instance;
439
+ }
440
+ // Read environment data from YAML
441
+ readENVData() {
442
+ try {
443
+ if (!fs2.existsSync(this.yaml_env_file_path)) {
444
+ this.logger.info(`YAML file not found at: ${this.yaml_env_file_path}`);
445
+ return {};
446
+ }
447
+ const file_content = fs2.readFileSync(this.yaml_env_file_path, "utf8");
448
+ return yaml.load(file_content) || {};
449
+ } catch (error) {
450
+ this.logger.error(`${this.name} - readENVData`, { error });
451
+ return {};
452
+ }
453
+ }
454
+ // Get env var from YAML → process.env → default
455
+ getEnvVar(key, default_value) {
456
+ if (key in this.env_data) {
457
+ return this.env_data[key];
458
+ }
459
+ if (key in process.env) {
460
+ return process.env[key];
461
+ }
462
+ return default_value;
463
+ }
464
+ // Fetch remote env variables and merge
465
+ async fetchRemoteEnv(url) {
466
+ try {
467
+ const response = await axios2.get(url);
468
+ if (typeof response.data === "object" && response.data !== null) {
469
+ this.env_data = { ...this.env_data, ...response.data };
470
+ this.logger.success("Remote env variables loaded.");
471
+ } else {
472
+ this.logger.error("Unexpected response format from remote env endpoint.");
473
+ }
474
+ } catch (error) {
475
+ this.logger.error(`${this.name} - fetchRemoteEnv`, { error });
476
+ }
477
+ }
478
+ };
479
+ var env_manager_util_default = EnvManagerUtil;
480
+
481
+ // src/utils/input_validator_util.ts
482
+ dayjs2.extend(isSameOrAfter);
483
+ var InputValidatorUtil = class _InputValidatorUtil {
484
+ static optional_field_regex = /^[a-zA-Z0-9_\-]+$/;
485
+ static name_regex_reg_exp = /^[A-Za-z.'\s/_-]*$/;
486
+ static namey_regex_reg_exp = /^[A-Za-z0-9.'\s,/_\-()&]*$/;
487
+ static email_regex_reg_exp = /^(?=.{1,255}$)[a-zA-Z0-9._%+-]{1,64}@[a-zA-Z0-9.-]{1,190}\.[a-zA-Z]{2,}$/i;
488
+ static tel_regex_reg_exp = /^[\s()+-]*([0-9][\s()+-]*){6,20}$/;
489
+ static pass_regex_reg_exp = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{6,}$/;
490
+ static url_regex_reg_exp = /^(https?:\/\/)?((localhost|[a-zA-Z0-9-_.]+)(:[0-9]{1,5})?)(\/[a-zA-Z0-9-._~:/?#@!$&'()*+,;=%]*)?$/;
491
+ static text_area_regex_reg_exp = /^(?=.*[a-zA-Z])[\p{L}\p{N}\p{P}\p{Zs}–—“”‘’]*$/u;
492
+ static uuid_regex_reg_exp = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
493
+ static custom_uuid_regex_reg_exp = /^[A-Z0-9]{12}-[A-Z0-9]{12}-[A-Z0-9]{12}-[A-Z0-9]{12}$/;
494
+ static env_manager = env_manager_util_default.getInstance();
495
+ static isValidateIn = (value, allowed) => allowed.includes(value);
496
+ /** ✅ Check member roles */
497
+ static isAdmin(name) {
498
+ return ["SuperAdmin", "AdminI", "AdminT"].includes(name);
499
+ }
500
+ static isSuperAdmin(name) {
501
+ return name === "SuperAdmin";
502
+ }
503
+ static isLowerSnakeCase(str) {
504
+ return /^[a-z]+(_[a-z]+)*$/.test(str);
505
+ }
506
+ static isUpperPascalCase(str) {
507
+ return /^[A-Z][a-zA-Z]*$/.test(str);
508
+ }
509
+ static isEmpty(input) {
510
+ return !input || input.toString().trim() === "";
511
+ }
512
+ static isValidOptionalField(str) {
513
+ return this.optional_field_regex.test(str);
514
+ }
515
+ static isValidName(name) {
516
+ return this.name_regex_reg_exp.test(name);
517
+ }
518
+ static isValidNamey(name) {
519
+ return this.namey_regex_reg_exp.test(name);
520
+ }
521
+ static isValidEmail(email) {
522
+ return this.email_regex_reg_exp.test(email) && email.length <= 254;
523
+ }
524
+ static isValidPhoneNumber(tel) {
525
+ return this.tel_regex_reg_exp.test(tel);
526
+ }
527
+ static isValidPassword(password) {
528
+ return this.pass_regex_reg_exp.test(password);
529
+ }
530
+ static isDigit(input) {
531
+ return !isNaN(input);
532
+ }
533
+ static isValidInteger(input) {
534
+ return Number.isInteger(input) && input > 0;
535
+ }
536
+ static isValidFloat(input) {
537
+ return !isNaN(input) && parseFloat(input) > 0;
538
+ }
539
+ static isValidURLY(url) {
540
+ try {
541
+ new URL(url);
542
+ return true;
543
+ } catch (_) {
544
+ return false;
545
+ }
546
+ }
547
+ static isValidURL(url) {
548
+ return this.url_regex_reg_exp.test(url) && this.isValidURLY(url);
549
+ }
550
+ static isBoolean(value) {
551
+ return typeof value === "boolean" || ["1", "0"].includes(String(value));
552
+ }
553
+ static isValidLongText(text) {
554
+ if (!text || typeof text !== "string") {
555
+ return false;
556
+ }
557
+ const forbidden_pattern = /[<>{};`]/;
558
+ if (forbidden_pattern.test(text)) {
559
+ return false;
560
+ }
561
+ return this.text_area_regex_reg_exp.test(text.trim());
562
+ }
563
+ static isValidUUID(uuid) {
564
+ return this.uuid_regex_reg_exp.test(uuid);
565
+ }
566
+ static isValidCustomUUID(uuid) {
567
+ return this.custom_uuid_regex_reg_exp.test(uuid);
568
+ }
569
+ static isArrayUnique(arr) {
570
+ return new Set(arr).size === arr.length;
571
+ }
572
+ static isValidFutureDate(date_string) {
573
+ const date = dayjs2(date_string);
574
+ return date.isValid() && date.isAfter(dayjs2());
575
+ }
576
+ static isValidDateAndDifference(input, unit = "years") {
577
+ if (!input) {
578
+ return null;
579
+ }
580
+ const date = dayjs2(input);
581
+ if (!date.isValid()) {
582
+ return null;
583
+ }
584
+ return { date, difference: dayjs2().diff(date, unit) };
585
+ }
586
+ /** ✅ Validate password hash */
587
+ static async isValidHashPassword(password, hash_password) {
588
+ if (!password || !hash_password) {
589
+ return false;
590
+ }
591
+ return await bcrypt2.compare(password, hash_password);
592
+ }
593
+ /** ✅ Check environment */
594
+ static isProduction() {
595
+ return _InputValidatorUtil?.env_manager?.env_data?.MODE === "production";
596
+ }
597
+ static isStaging() {
598
+ return _InputValidatorUtil?.env_manager?.env_data?.MODE === "staging";
599
+ }
600
+ static isDevelopment() {
601
+ return _InputValidatorUtil?.env_manager?.env_data?.MODE === "development";
602
+ }
603
+ /** ✅ Validate ReCaptcha */
604
+ static async isValidReCaptcha(recpatcha_token) {
605
+ const {
606
+ RECAPTCHA_SECRET_KEY,
607
+ RECPATHA_VERIFY_URL
608
+ } = _InputValidatorUtil?.env_manager?.env_data;
609
+ try {
610
+ const secret_key = RECAPTCHA_SECRET_KEY;
611
+ const url = RECPATHA_VERIFY_URL;
612
+ const params = { secret: secret_key, response: recpatcha_token };
613
+ const response = await axios3.post(url, null, { params });
614
+ return response.data.success;
615
+ } catch (error) {
616
+ console.error("reCAPTCHA verification failed:", error);
617
+ return false;
618
+ }
619
+ }
620
+ // Method to check if a directory exists
621
+ static dirExists(directory, create_directory = false, return_dir_path = false) {
622
+ const exist = fs3.existsSync(directory);
623
+ if (!create_directory) {
624
+ return exist;
625
+ }
626
+ if (!exist) {
627
+ fs3.mkdirSync(directory);
628
+ }
629
+ return return_dir_path ? directory : true;
630
+ }
631
+ };
632
+ var input_validator_util_default = InputValidatorUtil;
633
+
634
+ // src/utils/sql_formatter_util.ts
635
+ var SqlFormatterUtil = class _SqlFormatterUtil {
636
+ // Basic ANSI color helpers
637
+ static AnsiColor = {
638
+ reset: "\x1B[0m",
639
+ cyan: (text) => `\x1B[36m${text}\x1B[0m`,
640
+ green: (text) => `\x1B[32m${text}\x1B[0m`,
641
+ yellow: (text) => `\x1B[33m${text}\x1B[0m`,
642
+ red: (text) => `\x1B[31m${text}\x1B[0m`
643
+ };
644
+ static sqlColors = {
645
+ SELECT: _SqlFormatterUtil.AnsiColor.cyan,
646
+ INSERT: _SqlFormatterUtil.AnsiColor.green,
647
+ UPDATE: _SqlFormatterUtil.AnsiColor.yellow,
648
+ DELETE: _SqlFormatterUtil.AnsiColor.red
649
+ };
650
+ /**
651
+ * Normalize SQL:
652
+ * - Collapse multiple whitespaces/newlines
653
+ * - Remove extra spaces inside parentheses
654
+ */
655
+ static normalize(sql) {
656
+ return sql.replace(/\s+/g, " ").replace(/\(\s+/g, "(").replace(/\s+\)/g, ")").trim();
657
+ }
658
+ /**
659
+ * Colorize SQL keywords (SELECT, INSERT, UPDATE, DELETE)
660
+ */
661
+ static colorize(sql) {
662
+ const first_word = sql.split(" ")[0].toUpperCase();
663
+ const colorFN = this.sqlColors[first_word];
664
+ return colorFN ? colorFN(sql) : sql;
665
+ }
666
+ /**
667
+ * Full formatting for logging
668
+ */
669
+ static format(sql) {
670
+ return this.colorize(this.normalize(sql));
671
+ }
672
+ };
673
+ var sql_formatter_util_default = SqlFormatterUtil;
674
+
675
+ // src/utils/server_util.ts
676
+ var ServerUtil = class {
677
+ name = "server_util";
678
+ logger = new logger_util_default(this.name);
679
+ port;
680
+ constructor(port) {
681
+ this.port = port || 4e3;
682
+ }
683
+ // Method to print app banner
684
+ printAppBanner(app_name) {
685
+ const raw = app_name.replace(/[-_]/g, " ");
686
+ const title = raw.toUpperCase();
687
+ const border_char = "\u2550";
688
+ const corner_tl = "\u2554";
689
+ const corner_tr = "\u2557";
690
+ const corner_bl = "\u255A";
691
+ const corner_br = "\u255D";
692
+ const side_char = "\u2551";
693
+ const padding = 4;
694
+ const content_width = title.length + padding * 2;
695
+ const border = border_char.repeat(content_width);
696
+ const line1 = `${corner_tl}${border}${corner_tr}`;
697
+ const line2 = `${side_char} ${" ".repeat(padding)}${title}${" ".repeat(padding)}${side_char} `;
698
+ const line3 = `${corner_bl}${border}${corner_br} `;
699
+ console.log("\n" + line1);
700
+ console.log(line2);
701
+ console.log(line3 + "\n");
702
+ }
703
+ // Method to handle server errors
704
+ onServerError(error) {
705
+ if (error.syscall !== "listen") {
706
+ this.logger.error("Unexpected server error", { error });
707
+ throw error;
708
+ }
709
+ const bind = `Port ${this.port}`;
710
+ switch (error.code) {
711
+ case "EACCES":
712
+ this.logger.error(`${bind} requires elevated privileges`);
713
+ process.exit(1);
714
+ break;
715
+ case "EADDRINUSE":
716
+ this.logger.error(`${bind} is already in use`);
717
+ process.exit(1);
718
+ break;
719
+ default:
720
+ throw error;
721
+ }
722
+ }
723
+ // Method to handle server listening
724
+ onServerListening = (server) => {
725
+ this.printAppBanner("fibase-server-app");
726
+ const addr = server.address();
727
+ const bind = typeof addr === "string" ? `pipe ${addr}` : `port ${addr?.port}`;
728
+ this.logger.info(`Listening on ${bind}`);
729
+ };
730
+ };
731
+ var server_util_default = ServerUtil;
732
+
733
+ // src/utils/safe_execute_util.ts
734
+ var SafeExecuteUtil = class _SafeExecuteUtil {
735
+ // Store instances by class constructor (WeakMap ensures GC can clean up)
736
+ static instances = /* @__PURE__ */ new WeakMap();
737
+ // Store instances by string keys (Map keeps strong references)
738
+ static named_insatnces = /* @__PURE__ */ new Map();
739
+ static setInstance(key, instance) {
740
+ _SafeExecuteUtil.instances.set(key, instance);
741
+ }
742
+ /** Set instance by string key */
743
+ static setNamedInstance(key, instance) {
744
+ _SafeExecuteUtil.named_insatnces.set(key, instance);
745
+ }
746
+ static getInstance(key, fallback) {
747
+ return _SafeExecuteUtil.instances.get(key) ?? fallback;
748
+ }
749
+ /** Get instance by string key */
750
+ static getNamedInstance(key, fallback) {
751
+ return _SafeExecuteUtil.named_insatnces.get(key) ?? fallback;
752
+ }
753
+ // Method to Safely stringify any object for logging
754
+ static safeStringify(obj) {
755
+ try {
756
+ return JSON.stringify(obj);
757
+ } catch {
758
+ return "[Unserializable Params]";
759
+ }
760
+ }
761
+ // 🔹 Method to Execution time logger
762
+ static logExecutionTime(start, class_name, method_name, logger) {
763
+ const [seconds, nanoseconds] = process.hrtime(start);
764
+ const ms = (seconds * 1e3 + nanoseconds / 1e6).toFixed(2);
765
+ logger.info(`[${class_name}] \u23F1\uFE0F ${method_name} executed in ${ms}ms`);
766
+ }
767
+ // Method to handle on error action
768
+ static handleOnErrorAction(error, strategy, default_value, controller_response) {
769
+ if (strategy === 3 /* CONTROLLER_ERROR */ && controller_response?.errResponse) {
770
+ return controller_response?.errResponse?.(500, "invalid_error_request");
771
+ }
772
+ switch (strategy) {
773
+ case 0 /* RETURN_DEFAULT */:
774
+ return default_value;
775
+ case 1 /* EXIT_PROCESS */:
776
+ process.exit(1);
777
+ case 2 /* THROW_ERROR */:
778
+ throw error;
779
+ }
780
+ return;
781
+ }
782
+ // 🔹 Method to Unifysafe execution wrapper (normal methods)
783
+ static createSafeFunction(class_name, method_name, original_method, strategy, default_value) {
784
+ return async function(...args) {
785
+ const class_instance = _SafeExecuteUtil.getNamedInstance(class_name, this);
786
+ const logger = class_instance?.logger || new logger_util_default(class_name);
787
+ const method_params = args;
788
+ try {
789
+ return await original_method.apply(class_instance, method_params);
790
+ } catch (error) {
791
+ const safely_stringified_error = _SafeExecuteUtil.safeStringify(error);
792
+ logger.error(`[${class_name}] \u274C Error in method ${method_name}`, { method_params, error, safely_stringified_error });
793
+ _SafeExecuteUtil.handleOnErrorAction(error, strategy, default_value);
794
+ }
795
+ };
796
+ }
797
+ // 🔹 Unified safe execution wrapper with timing (for controller/service)
798
+ static createTimedSafeFunction(class_name, method_name, original_method, strategy, default_value) {
799
+ return async function(...args) {
800
+ const class_instance = _SafeExecuteUtil.getNamedInstance(class_name, this);
801
+ const logger = class_instance?.logger || new logger_util_default(class_name);
802
+ const start_time = process.hrtime();
803
+ const method_params = args;
804
+ const controller_response = args && args.length ? args[1] : void 0;
805
+ try {
806
+ const result = await original_method.apply(class_instance, args);
807
+ return result;
808
+ } catch (error) {
809
+ const safely_stringified_error = _SafeExecuteUtil.safeStringify(error);
810
+ logger.error(`[${class_name}] \u274C Error in method ${method_name}`, { method_params, error, safely_stringified_error });
811
+ _SafeExecuteUtil.handleOnErrorAction(error, strategy, default_value, controller_response);
812
+ } finally {
813
+ _SafeExecuteUtil.logExecutionTime(start_time, class_name, method_name, logger);
814
+ }
815
+ };
816
+ }
817
+ // Decorator Method to handle wrapping cclass methods
818
+ static applySafeWrapper(target, class_name, property_key, descriptor, strategy, timed, default_value) {
819
+ if (typeof descriptor.value !== "function") {
820
+ return;
821
+ }
822
+ descriptor.value = timed ? _SafeExecuteUtil.createTimedSafeFunction(
823
+ class_name,
824
+ String(property_key),
825
+ descriptor.value,
826
+ strategy,
827
+ default_value
828
+ ) : _SafeExecuteUtil.createSafeFunction(
829
+ class_name,
830
+ String(property_key),
831
+ descriptor.value,
832
+ strategy,
833
+ default_value
834
+ );
835
+ }
836
+ // Decorator method to handle controller methods
837
+ static safeExecuteController(class_name) {
838
+ return function(target, property_key, descriptor) {
839
+ return _SafeExecuteUtil.applySafeWrapper(
840
+ target,
841
+ class_name,
842
+ property_key,
843
+ descriptor,
844
+ 3 /* CONTROLLER_ERROR */,
845
+ true
846
+ );
847
+ };
848
+ }
849
+ // Decorator Method to handle service methods
850
+ static safeExecuteService(class_name, default_value) {
851
+ return function(target, property_key, descriptor) {
852
+ return _SafeExecuteUtil.applySafeWrapper(
853
+ target,
854
+ class_name,
855
+ property_key,
856
+ descriptor,
857
+ 0 /* RETURN_DEFAULT */,
858
+ true,
859
+ default_value
860
+ );
861
+ };
862
+ }
863
+ // Decorator Method to wrap method with retrun value
864
+ static safeExecuteReturn(class_name, default_value) {
865
+ return function(target, property_key, descriptor) {
866
+ return _SafeExecuteUtil.applySafeWrapper(
867
+ target,
868
+ class_name,
869
+ property_key,
870
+ descriptor,
871
+ 0 /* RETURN_DEFAULT */,
872
+ false,
873
+ default_value
874
+ );
875
+ };
876
+ }
877
+ // Decorator Method to wrap method with retrun value
878
+ static safeExecuteTransaction(class_name, default_value) {
879
+ return function(target, property_key, descriptor) {
880
+ return _SafeExecuteUtil.applySafeWrapper(
881
+ target,
882
+ class_name,
883
+ property_key,
884
+ descriptor,
885
+ 0 /* RETURN_DEFAULT */,
886
+ false,
887
+ default_value
888
+ );
889
+ };
890
+ }
891
+ // Decorator method to wrap method with void return
892
+ static safeExecute(class_name) {
893
+ return function(target, property_key, descriptor) {
894
+ return _SafeExecuteUtil.applySafeWrapper(
895
+ target,
896
+ class_name,
897
+ property_key,
898
+ descriptor,
899
+ 0 /* RETURN_DEFAULT */,
900
+ false
901
+ );
902
+ };
903
+ }
904
+ // Decorator method to wrap method with void return
905
+ static safeExecuteExit(class_name) {
906
+ return function(target, property_key, descriptor) {
907
+ return _SafeExecuteUtil.applySafeWrapper(
908
+ target,
909
+ class_name,
910
+ property_key,
911
+ descriptor,
912
+ 1 /* EXIT_PROCESS */,
913
+ false
914
+ );
915
+ };
916
+ }
917
+ // Decorator method to wrap method with void return
918
+ static safeExecuteThrow(class_name) {
919
+ return function(target, property_key, descriptor) {
920
+ return _SafeExecuteUtil.applySafeWrapper(
921
+ target,
922
+ class_name,
923
+ property_key,
924
+ descriptor,
925
+ 2 /* THROW_ERROR */,
926
+ false
927
+ );
928
+ };
929
+ }
930
+ };
931
+ var safe_execute_util_default = SafeExecuteUtil;
932
+
933
+ // src/utils/cache_util.ts
934
+ var InMemoryCache = class {
935
+ store = /* @__PURE__ */ new Map();
936
+ /**
937
+ * Set a cache value with TTL (ms)
938
+ */
939
+ set(key, value, ttl_ms) {
940
+ if (!key) return;
941
+ const expires_at = Date.now() + ttl_ms;
942
+ this.store.set(key, { value, expires_at });
943
+ }
944
+ /**
945
+ * Get a cache value (returns undefined if missing or expired)
946
+ */
947
+ get(key) {
948
+ const entry = this.store.get(key);
949
+ if (!entry) return void 0;
950
+ if (Date.now() > entry.expires_at) {
951
+ this.store.delete(key);
952
+ return void 0;
953
+ }
954
+ return entry.value;
955
+ }
956
+ /**
957
+ * Check if a key exists and is valid
958
+ */
959
+ has(key) {
960
+ return this.get(key) !== void 0;
961
+ }
962
+ /**
963
+ * Update an existing cache entry (keeps old TTL)
964
+ */
965
+ update(key, value) {
966
+ const entry = this.store.get(key);
967
+ if (!entry) return false;
968
+ if (Date.now() > entry.expires_at) {
969
+ this.store.delete(key);
970
+ return false;
971
+ }
972
+ this.store.set(key, { ...entry, value });
973
+ return true;
974
+ }
975
+ /**
976
+ * Delete a single cache entry
977
+ */
978
+ delete(key) {
979
+ return this.store.delete(key);
980
+ }
981
+ /**
982
+ * Clear entire cache
983
+ */
984
+ clear() {
985
+ this.store.clear();
986
+ }
987
+ /**
988
+ * Manually expire a key immediately
989
+ */
990
+ expire(key) {
991
+ this.store.delete(key);
992
+ }
993
+ /**
994
+ * Cleanup expired entries (optional call)
995
+ */
996
+ cleanup() {
997
+ const now = Date.now();
998
+ for (const [key, entry] of this.store.entries()) {
999
+ if (now > entry.expires_at) {
1000
+ this.store.delete(key);
1001
+ }
1002
+ }
1003
+ }
1004
+ /**
1005
+ * Cache size (for metrics)
1006
+ */
1007
+ size() {
1008
+ return this.store.size;
1009
+ }
1010
+ };
1011
+ var cache_util_default = InMemoryCache;
1012
+
1013
+ export {
1014
+ SCHEMAS_DIR,
1015
+ SCHEMA_SNAPSHOTS_DIR,
1016
+ MIGRATIONS_DIR,
1017
+ SEEDERS_DIR,
1018
+ SEQUELIZE_META_TABLE_NAME,
1019
+ SEQUELIZE_SEEDER_META_TABLE_NAME,
1020
+ logger_util_default,
1021
+ input_transformer_util_default,
1022
+ env_manager_util_default,
1023
+ input_validator_util_default,
1024
+ sql_formatter_util_default,
1025
+ server_util_default,
1026
+ safe_execute_util_default,
1027
+ cache_util_default
1028
+ };
1029
+ //# sourceMappingURL=chunk-BK6YPN2O.js.map