fiberx-backend-toolkit 0.0.76 → 0.0.78

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.
@@ -1,4 +1,4 @@
1
- declare const GENERATE_NOTIFICATION_CODE_TYPE: (interface_name: string, static_obj: any, db_obj: any, code: string) => string;
1
+ declare const GENERATE_NOTIFICATION_CODE_TYPE: (interface_name: string, db_obj: any, code: string) => string;
2
2
  declare const GENERATE_UTIL_METHOD_CODE: (interface_name: string, method_name: string, code: string) => string;
3
3
  declare const GENERATE_UTIL_CLASS_CODE: (types_file_name: string, generated_content: string) => string;
4
4
  export { GENERATE_NOTIFICATION_CODE_TYPE, GENERATE_UTIL_METHOD_CODE, GENERATE_UTIL_CLASS_CODE };
@@ -12,18 +12,13 @@ const objectToType = (obj, indent) => {
12
12
  })
13
13
  .join("\n");
14
14
  };
15
- const GENERATE_NOTIFICATION_CODE_TYPE = (interface_name, static_obj, db_obj, code) => {
15
+ const GENERATE_NOTIFICATION_CODE_TYPE = (interface_name, db_obj, code) => {
16
16
  return `
17
17
  /**
18
18
  * @generated-notification-code: ${code}
19
19
  */
20
20
  export interface ${interface_name} {
21
- static_content?: {
22
- ${objectToType(static_obj, 8)}
23
- };
24
- db_content: {
25
21
  ${objectToType(db_obj, 8)}
26
- };
27
22
  }
28
23
  `;
29
24
  };
@@ -60,6 +60,8 @@ export declare const DEFAULT_TOTP_DIGITS = 6;
60
60
  export declare const DEFAULT_TOTP_WINDOW = 1;
61
61
  export declare const DEFAULT_RBAC_CACHE_KEY = "RBAC_SNAPSHOT";
62
62
  export declare const DEFAULT_RBAC_CACHE_TTL: number;
63
+ export declare const DEFAULT_MAILER_CACHE_KEY = "MAILER_SNAPSHOT";
64
+ export declare const DEFAULT_MAILER_CACHE_TTL: number;
63
65
  export declare const EMAIL_ENQUEUE_TYPES_FILE_NAME = "types/email_enqueue_type.generated.ts";
64
66
  export declare const EMAIL_ENQUEUE_UTIL_FILE_NAME = "utils/email_enqueue_util.generated.ts";
65
67
  export declare const CONTENT_CACHE_TTL_KEY = "CONTENT_CACHE_TTL";
@@ -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_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_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.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_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");
@@ -109,6 +109,8 @@ exports.DEFAULT_TOTP_DIGITS = 6;
109
109
  exports.DEFAULT_TOTP_WINDOW = 1;
110
110
  exports.DEFAULT_RBAC_CACHE_KEY = "RBAC_SNAPSHOT";
111
111
  exports.DEFAULT_RBAC_CACHE_TTL = (1000 * 60 * 60 * 24); // 24 hours
112
+ exports.DEFAULT_MAILER_CACHE_KEY = "MAILER_SNAPSHOT";
113
+ exports.DEFAULT_MAILER_CACHE_TTL = (1000 * 60 * 60 * 24); // 24 hours
112
114
  exports.EMAIL_ENQUEUE_TYPES_FILE_NAME = "types/email_enqueue_type.generated.ts";
113
115
  exports.EMAIL_ENQUEUE_UTIL_FILE_NAME = "utils/email_enqueue_util.generated.ts";
114
116
  exports.CONTENT_CACHE_TTL_KEY = "CONTENT_CACHE_TTL";
@@ -65,9 +65,9 @@ class EmailEnqueueGenerator {
65
65
  }
66
66
  }
67
67
  // Method to append generated to type to output file type
68
- appendType(interface_name, static_obj, db_obj, code) {
68
+ appendType(interface_name, db_obj, code) {
69
69
  try {
70
- const content = (0, email_enqueue_code_template_1.GENERATE_NOTIFICATION_CODE_TYPE)(interface_name, static_obj, db_obj, code);
70
+ const content = (0, email_enqueue_code_template_1.GENERATE_NOTIFICATION_CODE_TYPE)(interface_name, db_obj, code);
71
71
  fs_1.default.appendFileSync(this.types_file_path, content);
72
72
  this.logger.info(`🧩 Type generated → ${interface_name} (${code})`);
73
73
  return true;
@@ -112,10 +112,9 @@ class EmailEnqueueGenerator {
112
112
  const interface_name = main_1.InputTransformerUtil.toPascalCase(code.toLowerCase()) + "EmailPayload";
113
113
  const method_name = "send" + main_1.InputTransformerUtil.toPascalCase(code.toLowerCase()) + "Email";
114
114
  const placeholders = this.provider.getRequiredPlaceholders(template) ?? {};
115
- const static_obj = main_1.InputTransformerUtil.buildNestedObject(placeholders.static_content ?? []);
116
115
  const db_obj = main_1.InputTransformerUtil.buildNestedObject(placeholders.db_content ?? []);
117
116
  this.logger.info(`🚀 Generating email enqueue code for → ${code}`);
118
- const type_success = this.appendType(interface_name, static_obj, db_obj, code);
117
+ const type_success = this.appendType(interface_name, db_obj, code);
119
118
  const method_success = this.appendUtilMethod(interface_name, method_name, code);
120
119
  if (type_success && method_success) {
121
120
  this.logger.success?.(`✅ Successfully generated enqueue method for code → ${code}`);
@@ -1,3 +1,4 @@
1
1
  import EmailEnqueueGenerator from "./generators/email_enqueue_generator";
2
2
  import EmailEnqueueProcessor from "./processors/email_enqueue_processor";
3
- export { EmailEnqueueGenerator, EmailEnqueueProcessor };
3
+ import MailerDataLoaderUtil from "./utils/mailer_data_loader_util";
4
+ export { EmailEnqueueGenerator, EmailEnqueueProcessor, MailerDataLoaderUtil };
@@ -3,8 +3,10 @@ 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.EmailEnqueueProcessor = exports.EmailEnqueueGenerator = void 0;
6
+ exports.MailerDataLoaderUtil = exports.EmailEnqueueProcessor = exports.EmailEnqueueGenerator = void 0;
7
7
  const email_enqueue_generator_1 = __importDefault(require("./generators/email_enqueue_generator"));
8
8
  exports.EmailEnqueueGenerator = email_enqueue_generator_1.default;
9
9
  const email_enqueue_processor_1 = __importDefault(require("./processors/email_enqueue_processor"));
10
10
  exports.EmailEnqueueProcessor = email_enqueue_processor_1.default;
11
+ const mailer_data_loader_util_1 = __importDefault(require("./utils/mailer_data_loader_util"));
12
+ exports.MailerDataLoaderUtil = mailer_data_loader_util_1.default;
@@ -81,8 +81,8 @@ class EmailEnqueueProcessor {
81
81
  this.logger.error("Failed to fetch notification record from template", { notification });
82
82
  throw new Error("Failed to fetch notification record from template");
83
83
  }
84
- this.logger.info("Template record resolved", { notification_code });
85
- const content_payload = await this.LoadEmailContentPayload(notification_code);
84
+ this.logger.info("Notification record resolved", { notification_code });
85
+ const content_payload = await this.LoadEmailContentPayload(`${notification_code}_email`);
86
86
  const full_payload = { static_content: content_payload, db_content: data_payload };
87
87
  // 4️⃣ Validate
88
88
  this.validate(this.provider.getRequiredPlaceholders(template), full_payload);
@@ -0,0 +1,38 @@
1
+ import { MailerDataLoaderProvider, MailerDataLoaderOptionsInterface } from "../../types/mailer_type";
2
+ declare class MailerDataLoaderUtil<TMailerConfig, TBaseTemplate, TNotificationType, TEmailContentTempltae> {
3
+ private readonly provider;
4
+ private static instance;
5
+ private readonly logger;
6
+ private readonly cache;
7
+ private readonly CACHE_KEY;
8
+ private readonly DEFAULT_TTL;
9
+ private loading_promise;
10
+ private constructor();
11
+ /**
12
+ * ===============================
13
+ * BUILD SNAPSHOT
14
+ * ===============================
15
+ */
16
+ private buildSnapshot;
17
+ static initialize<TMailerConfig, TBaseTemplate, TNotificationType, TEmailContentTempltae>(provider: MailerDataLoaderProvider<TMailerConfig, TBaseTemplate, TNotificationType, TEmailContentTempltae>, options?: MailerDataLoaderOptionsInterface): MailerDataLoaderUtil<TMailerConfig, TBaseTemplate, TNotificationType, TEmailContentTempltae>;
18
+ static getInstance<TMailerConfig, TBaseTemplate, TNotificationType, TEmailContentTempltae>(): MailerDataLoaderUtil<TMailerConfig, TBaseTemplate, TNotificationType, TEmailContentTempltae>;
19
+ /**
20
+ * ===============================
21
+ * LOAD Mailer
22
+ * ===============================
23
+ */
24
+ load(force_refresh?: boolean): Promise<void>;
25
+ /**
26
+ * ===============================
27
+ * ACCESSORS
28
+ * ===============================
29
+ */
30
+ private getSnapshot;
31
+ getMailerConfig(): TMailerConfig | null;
32
+ getBaseTemplate(): TBaseTemplate | null;
33
+ getNotificationTypes(): TNotificationType[];
34
+ getEmailTemplates(): TEmailContentTempltae[];
35
+ getTemplateByNotificationCode(code: string): Promise<TEmailContentTempltae | null>;
36
+ refresh(): Promise<void>;
37
+ }
38
+ export default MailerDataLoaderUtil;
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const main_1 = require("../../utils/main");
4
+ const constants_1 = require("../../config/constants");
5
+ class MailerDataLoaderUtil {
6
+ provider;
7
+ static instance = null;
8
+ logger = new main_1.LoggerUtil("mailer_data_loader_util");
9
+ cache = new main_1.InMemoryCacheUtil();
10
+ CACHE_KEY;
11
+ DEFAULT_TTL;
12
+ loading_promise = null;
13
+ constructor(provider, options) {
14
+ this.provider = provider;
15
+ this.CACHE_KEY = options?.cache_key ?? constants_1.DEFAULT_MAILER_CACHE_KEY;
16
+ this.DEFAULT_TTL = options?.cache_ttl ?? constants_1.DEFAULT_MAILER_CACHE_TTL;
17
+ }
18
+ /**
19
+ * ===============================
20
+ * BUILD SNAPSHOT
21
+ * ===============================
22
+ */
23
+ async buildSnapshot() {
24
+ const mailer_config = await this.provider.fetchMailerConfig();
25
+ const base_template = await this.provider.fetchBaseTemplate();
26
+ const notification_types = await this.provider.fetchNotificationTypes();
27
+ const email_contents = await this.provider.fetchEmailContentTemplates();
28
+ const notification_by_code = new Map();
29
+ const templates_by_notification_code = new Map();
30
+ // RolePermissions
31
+ for (const notification of notification_types) {
32
+ const notification_code = this.provider.getNotificaionCodeFromNotification(notification);
33
+ notification_by_code.set(notification_code, notification);
34
+ }
35
+ for (const template of email_contents) {
36
+ const notification_code = this.provider.getNotificaionCodeFromTemplate(template);
37
+ templates_by_notification_code.set(notification_code, template);
38
+ }
39
+ return {
40
+ mailer_config,
41
+ base_template,
42
+ notification_types,
43
+ email_contents,
44
+ notification_by_code,
45
+ templates_by_notification_code
46
+ };
47
+ }
48
+ // Method to Initialize singleton (MUST be called once)
49
+ static initialize(provider, options) {
50
+ if (this.instance) {
51
+ throw new Error("MailerDataLoaderUtil already initialized.");
52
+ }
53
+ this.instance = new MailerDataLoaderUtil(provider, options);
54
+ return this.instance;
55
+ }
56
+ // Method to Get singleton instance
57
+ static getInstance() {
58
+ if (!this.instance) {
59
+ throw new Error("RBACLoaderUtil not initialized.");
60
+ }
61
+ return this.instance;
62
+ }
63
+ /**
64
+ * ===============================
65
+ * LOAD Mailer
66
+ * ===============================
67
+ */
68
+ async load(force_refresh = false) {
69
+ if (!force_refresh && this.cache.has(this.CACHE_KEY)) {
70
+ return;
71
+ }
72
+ if (this.loading_promise) {
73
+ return this.loading_promise;
74
+ }
75
+ this.loading_promise = (async () => {
76
+ try {
77
+ const snapshot = await this.buildSnapshot();
78
+ this.cache.set(this.CACHE_KEY, snapshot, this.DEFAULT_TTL);
79
+ }
80
+ catch (error) {
81
+ this.logger.error("Failed to load Mailer snapshot", { error });
82
+ throw error;
83
+ }
84
+ finally {
85
+ this.loading_promise = null;
86
+ }
87
+ })();
88
+ return this.loading_promise;
89
+ }
90
+ /**
91
+ * ===============================
92
+ * ACCESSORS
93
+ * ===============================
94
+ */
95
+ getSnapshot() {
96
+ const snapshot = this.cache.get(this.CACHE_KEY);
97
+ if (!snapshot) {
98
+ throw new Error("Mailer Data Loader Util snapshot not loaded. Call load() first.");
99
+ }
100
+ return snapshot;
101
+ }
102
+ getMailerConfig() {
103
+ return this.getSnapshot().mailer_config;
104
+ }
105
+ getBaseTemplate() {
106
+ return this.getSnapshot().base_template;
107
+ }
108
+ getNotificationTypes() {
109
+ return this.getSnapshot().notification_types;
110
+ }
111
+ getEmailTemplates() {
112
+ return this.getSnapshot().email_contents;
113
+ }
114
+ async getTemplateByNotificationCode(code) {
115
+ const templates_by_notification_code = this.getSnapshot().templates_by_notification_code;
116
+ if (templates_by_notification_code.has(code)) {
117
+ return templates_by_notification_code.get(code) ?? null;
118
+ }
119
+ return await this.provider.fetchEmailContentTemplateByNotificationcode(code);
120
+ }
121
+ // --------------------------
122
+ // Refresh
123
+ // --------------------------
124
+ async refresh() {
125
+ await this.load(true);
126
+ }
127
+ }
128
+ exports.default = MailerDataLoaderUtil;
@@ -39,3 +39,24 @@ export interface EmailQueueAdapter<TQueueEntity, TNotification, TTemplate, TMail
39
39
  created_by?: number | null;
40
40
  }): Promise<TQueueEntity>;
41
41
  }
42
+ export interface MailerDataLoaderProvider<TMailerConfig, TBaseTemplate, TNotificationType, TEmailContentTempltae> {
43
+ fetchMailerConfig(): Promise<TMailerConfig | null>;
44
+ fetchBaseTemplate(): Promise<TBaseTemplate | null>;
45
+ fetchNotificationTypes(): Promise<TNotificationType[]>;
46
+ fetchEmailContentTemplates(): Promise<TEmailContentTempltae[]>;
47
+ fetchEmailContentTemplateByNotificationcode(code: string): Promise<TEmailContentTempltae | null>;
48
+ getNotificaionCodeFromNotification(notification: TNotificationType): string;
49
+ getNotificaionCodeFromTemplate(email_content_template: TEmailContentTempltae): string;
50
+ }
51
+ export interface MailerDataLoaderSnapshot<TMailerConfig, TBaseTemplate, TNotificationType, TEmailContentTempltae> {
52
+ mailer_config: TMailerConfig | null;
53
+ base_template: TBaseTemplate | null;
54
+ notification_types: TNotificationType[];
55
+ email_contents: TEmailContentTempltae[];
56
+ notification_by_code: Map<string, TNotificationType>;
57
+ templates_by_notification_code: Map<string, TEmailContentTempltae>;
58
+ }
59
+ export interface MailerDataLoaderOptionsInterface {
60
+ cache_key?: string;
61
+ cache_ttl?: number;
62
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fiberx-backend-toolkit",
3
- "version": "0.0.76",
3
+ "version": "0.0.78",
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",