fiberx-backend-toolkit 0.1.9 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mailer/utils/mailer_data_loader_util.d.ts +4 -4
- package/dist/mailer/utils/mailer_data_loader_util.js +26 -12
- package/dist/rbac/rbac_loader_util.d.ts +4 -4
- package/dist/rbac/rbac_loader_util.js +22 -14
- package/dist/utils/input_validator_util.d.ts +1 -0
- package/dist/utils/input_validator_util.js +35 -0
- package/package.json +1 -1
|
@@ -28,10 +28,10 @@ declare class MailerDataLoaderUtil<TMailerConfig, TBaseTemplate, TNotificationTy
|
|
|
28
28
|
* ===============================
|
|
29
29
|
*/
|
|
30
30
|
private getSnapshot;
|
|
31
|
-
getMailerConfig(): TMailerConfig | null
|
|
32
|
-
getBaseTemplate(): TBaseTemplate | null
|
|
33
|
-
getNotificationTypes(): TNotificationType[]
|
|
34
|
-
getEmailTemplates(): TEmailContentTempltae[]
|
|
31
|
+
getMailerConfig(): Promise<TMailerConfig | null>;
|
|
32
|
+
getBaseTemplate(): Promise<TBaseTemplate | null>;
|
|
33
|
+
getNotificationTypes(): Promise<TNotificationType[]>;
|
|
34
|
+
getEmailTemplates(): Promise<TEmailContentTempltae[]>;
|
|
35
35
|
getTemplateByNotificationCode(code: string): Promise<TEmailContentTempltae | null>;
|
|
36
36
|
refresh(): Promise<void>;
|
|
37
37
|
}
|
|
@@ -92,27 +92,41 @@ class MailerDataLoaderUtil {
|
|
|
92
92
|
* ACCESSORS
|
|
93
93
|
* ===============================
|
|
94
94
|
*/
|
|
95
|
-
getSnapshot() {
|
|
96
|
-
|
|
95
|
+
async getSnapshot() {
|
|
96
|
+
let snapshot = this.cache.get(this.CACHE_KEY);
|
|
97
|
+
// ✅ If exists → return immediately
|
|
98
|
+
if (snapshot) {
|
|
99
|
+
return snapshot;
|
|
100
|
+
}
|
|
101
|
+
this.logger.alert("Mailer snapshot missing or expired. Rebuilding...");
|
|
102
|
+
// ✅ Trigger load (handles concurrency via loading_promise)
|
|
103
|
+
await this.load();
|
|
104
|
+
snapshot = this.cache.get(this.CACHE_KEY);
|
|
105
|
+
// ❌ Still missing → real failure
|
|
97
106
|
if (!snapshot) {
|
|
98
|
-
throw new Error("
|
|
107
|
+
throw new Error("Failed to rebuild Mailer snapshot.");
|
|
99
108
|
}
|
|
100
109
|
return snapshot;
|
|
101
110
|
}
|
|
102
|
-
getMailerConfig() {
|
|
103
|
-
|
|
111
|
+
async getMailerConfig() {
|
|
112
|
+
const snapshot = await this.getSnapshot();
|
|
113
|
+
return snapshot.mailer_config;
|
|
104
114
|
}
|
|
105
|
-
getBaseTemplate() {
|
|
106
|
-
|
|
115
|
+
async getBaseTemplate() {
|
|
116
|
+
const snapshot = await this.getSnapshot();
|
|
117
|
+
return snapshot.base_template;
|
|
107
118
|
}
|
|
108
|
-
getNotificationTypes() {
|
|
109
|
-
|
|
119
|
+
async getNotificationTypes() {
|
|
120
|
+
const snapshot = await this.getSnapshot();
|
|
121
|
+
return snapshot.notification_types;
|
|
110
122
|
}
|
|
111
|
-
getEmailTemplates() {
|
|
112
|
-
|
|
123
|
+
async getEmailTemplates() {
|
|
124
|
+
const snapshot = await this.getSnapshot();
|
|
125
|
+
return snapshot.email_contents;
|
|
113
126
|
}
|
|
114
127
|
async getTemplateByNotificationCode(code) {
|
|
115
|
-
const
|
|
128
|
+
const snapshot = await this.getSnapshot();
|
|
129
|
+
const templates_by_notification_code = snapshot.templates_by_notification_code;
|
|
116
130
|
if (templates_by_notification_code.has(code)) {
|
|
117
131
|
return templates_by_notification_code.get(code) ?? null;
|
|
118
132
|
}
|
|
@@ -28,10 +28,10 @@ declare class RBACLoaderUtil<TSafeRole> {
|
|
|
28
28
|
* ===============================
|
|
29
29
|
*/
|
|
30
30
|
private getSnapshot;
|
|
31
|
-
getRoleById(role_id: number): TSafeRole | undefined
|
|
32
|
-
getRoleBySymbol(symbol: string): TSafeRole | undefined
|
|
33
|
-
getPermissionsForRole(role_id: number): string[]
|
|
34
|
-
roleHasPermission(role_id: number, permission_key: string): boolean
|
|
31
|
+
getRoleById(role_id: number): Promise<TSafeRole | undefined>;
|
|
32
|
+
getRoleBySymbol(symbol: string): Promise<TSafeRole | undefined>;
|
|
33
|
+
getPermissionsForRole(role_id: number): Promise<string[]>;
|
|
34
|
+
roleHasPermission(role_id: number, permission_key: string): Promise<boolean>;
|
|
35
35
|
refresh(): Promise<void>;
|
|
36
36
|
}
|
|
37
37
|
export default RBACLoaderUtil;
|
|
@@ -109,27 +109,35 @@ class RBACLoaderUtil {
|
|
|
109
109
|
* ACCESSORS
|
|
110
110
|
* ===============================
|
|
111
111
|
*/
|
|
112
|
-
getSnapshot() {
|
|
113
|
-
|
|
112
|
+
async getSnapshot() {
|
|
113
|
+
let snapshot = this.cache.get(this.RBAC_CACHE_KEY);
|
|
114
|
+
if (snapshot) {
|
|
115
|
+
return snapshot;
|
|
116
|
+
}
|
|
117
|
+
// Cache miss (expired or never loaded)
|
|
118
|
+
this.logger.alert("RBAC snapshot cache miss. Rebuilding...");
|
|
119
|
+
await this.load(); // <-- handles concurrency already
|
|
120
|
+
snapshot = this.cache.get(this.RBAC_CACHE_KEY);
|
|
114
121
|
if (!snapshot) {
|
|
115
|
-
throw new Error("RBAC snapshot
|
|
122
|
+
throw new Error("RBAC snapshot rebuild failed.");
|
|
116
123
|
}
|
|
117
124
|
return snapshot;
|
|
118
125
|
}
|
|
119
|
-
getRoleById(role_id) {
|
|
120
|
-
|
|
126
|
+
async getRoleById(role_id) {
|
|
127
|
+
const snapshot = await this.getSnapshot();
|
|
128
|
+
return snapshot.role_by_id.get(role_id);
|
|
121
129
|
}
|
|
122
|
-
getRoleBySymbol(symbol) {
|
|
123
|
-
|
|
130
|
+
async getRoleBySymbol(symbol) {
|
|
131
|
+
const snapshot = await this.getSnapshot();
|
|
132
|
+
return snapshot.role_by_symbol.get(symbol);
|
|
124
133
|
}
|
|
125
|
-
getPermissionsForRole(role_id) {
|
|
126
|
-
|
|
134
|
+
async getPermissionsForRole(role_id) {
|
|
135
|
+
const snapshot = await this.getSnapshot();
|
|
136
|
+
return Array.from(snapshot.permissions_by_role_id.get(role_id) ?? []);
|
|
127
137
|
}
|
|
128
|
-
roleHasPermission(role_id, permission_key) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
.get(role_id)
|
|
132
|
-
?.has(permission_key) ?? false);
|
|
138
|
+
async roleHasPermission(role_id, permission_key) {
|
|
139
|
+
const snapshot = await this.getSnapshot();
|
|
140
|
+
return (snapshot.permissions_by_role_id.get(role_id)?.has(permission_key) ?? false);
|
|
133
141
|
}
|
|
134
142
|
async refresh() {
|
|
135
143
|
await this.load(true);
|
|
@@ -51,5 +51,6 @@ declare class InputValidatorUtil {
|
|
|
51
51
|
static dirExists(directory: string, create_directory?: boolean, return_dir_path?: boolean): boolean | string;
|
|
52
52
|
static isSafeHashCompare(a: string, b: string): boolean;
|
|
53
53
|
static isDeepEqual(a: any, b: any): boolean;
|
|
54
|
+
static hasInputChanged(new_input: Record<string, any>, existing_data: Record<string, any>, keys_to_check: string[]): boolean;
|
|
54
55
|
}
|
|
55
56
|
export default InputValidatorUtil;
|
|
@@ -174,5 +174,40 @@ class InputValidatorUtil {
|
|
|
174
174
|
}
|
|
175
175
|
return false;
|
|
176
176
|
}
|
|
177
|
+
static hasInputChanged(new_input, existing_data, keys_to_check) {
|
|
178
|
+
// Normalize values (booleans, "true"/"false", "1"/"0", null-like)
|
|
179
|
+
const normalize = (val) => {
|
|
180
|
+
if (val === "true")
|
|
181
|
+
return true;
|
|
182
|
+
if (val === "false")
|
|
183
|
+
return false;
|
|
184
|
+
if (val === "1")
|
|
185
|
+
return true;
|
|
186
|
+
if (val === "0")
|
|
187
|
+
return false;
|
|
188
|
+
return val;
|
|
189
|
+
};
|
|
190
|
+
// Utility to get nested value by dot notation
|
|
191
|
+
const getNestedValue = (obj, path) => {
|
|
192
|
+
return path.split('.').reduce((acc, part) => {
|
|
193
|
+
if (acc && typeof acc === 'object' && part in acc) {
|
|
194
|
+
return acc[part];
|
|
195
|
+
}
|
|
196
|
+
return undefined;
|
|
197
|
+
}, obj);
|
|
198
|
+
};
|
|
199
|
+
for (const key of keys_to_check) {
|
|
200
|
+
if (!(key in new_input)) {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
const new_val = normalize(getNestedValue(new_input, key));
|
|
204
|
+
const old_val = normalize(getNestedValue(existing_data, key));
|
|
205
|
+
if (!InputValidatorUtil.isDeepEqual(new_val, old_val)) {
|
|
206
|
+
console.log("🔺 CHANGED:", key, { new_val, old_val });
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
177
212
|
}
|
|
178
213
|
exports.default = InputValidatorUtil;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fiberx-backend-toolkit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
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",
|