@takentrade/takentrade-libs 3.0.0 → 3.2.0
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/README.md +1 -0
- package/dist/auth/auth.interface.d.ts +8 -0
- package/dist/auth/auth.interface.js +2 -0
- package/dist/auth/decorators/get-user.decorator.d.ts +2 -0
- package/dist/auth/decorators/get-user.decorator.js +26 -0
- package/dist/auth/decorators/index.d.ts +1 -0
- package/dist/auth/decorators/index.js +1 -0
- package/dist/auth/index.d.ts +1 -0
- package/dist/auth/index.js +1 -0
- package/dist/common/utils/string.utils.d.ts +10 -2
- package/dist/common/utils/string.utils.js +30 -13
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/metrics/metrics.interface.d.ts +0 -53
- package/dist/metrics/metrics.interface.js +0 -12
- package/dist/monitoring/alerting.service.d.ts +82 -0
- package/dist/monitoring/alerting.service.js +290 -0
- package/dist/monitoring/index.d.ts +5 -0
- package/dist/monitoring/index.js +21 -0
- package/dist/monitoring/monitoring.interface.d.ts +102 -0
- package/dist/monitoring/monitoring.interface.js +10 -0
- package/dist/monitoring/monitoring.module.d.ts +8 -0
- package/dist/monitoring/monitoring.module.js +44 -0
- package/dist/monitoring/sentry.service.d.ts +65 -0
- package/dist/monitoring/sentry.service.js +218 -0
- package/dist/monitoring/uptime.service.d.ts +59 -0
- package/dist/monitoring/uptime.service.js +213 -0
- package/dist/resilience/circuit-breaker.interface.d.ts +0 -75
- package/dist/resilience/circuit-breaker.interface.js +0 -6
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/helpers/date.util.d.ts +8 -0
- package/dist/utils/helpers/date.util.js +30 -0
- package/dist/utils/helpers/decimal.util.d.ts +9 -0
- package/dist/utils/helpers/decimal.util.js +31 -0
- package/dist/utils/helpers/format.util.d.ts +64 -0
- package/dist/utils/helpers/format.util.js +162 -0
- package/dist/utils/helpers/penalty.util.d.ts +25 -0
- package/dist/utils/helpers/penalty.util.js +40 -0
- package/dist/utils/helpers/referral.util.d.ts +4 -0
- package/dist/utils/helpers/referral.util.js +53 -0
- package/dist/utils/helpers/role.util.d.ts +8 -0
- package/dist/utils/helpers/role.util.js +18 -0
- package/dist/utils/helpers/validation.util.d.ts +62 -0
- package/dist/utils/helpers/validation.util.js +138 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/index.js +7 -0
- package/package.json +4 -1
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isToday = exports.calculateNextDate = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Calculate next date based on frequency
|
|
6
|
+
*/
|
|
7
|
+
const calculateNextDate = (frequency, lastDate) => {
|
|
8
|
+
const nextDate = new Date(lastDate);
|
|
9
|
+
const frequencyMap = {
|
|
10
|
+
DAILY: () => nextDate.setDate(nextDate.getDate() + 1),
|
|
11
|
+
WEEKLY: () => nextDate.setDate(nextDate.getDate() + 7),
|
|
12
|
+
MONTHLY: () => nextDate.setMonth(nextDate.getMonth() + 1),
|
|
13
|
+
};
|
|
14
|
+
const calculateFn = frequencyMap[frequency];
|
|
15
|
+
if (!calculateFn)
|
|
16
|
+
throw new Error('Invalid frequency');
|
|
17
|
+
calculateFn();
|
|
18
|
+
return nextDate;
|
|
19
|
+
};
|
|
20
|
+
exports.calculateNextDate = calculateNextDate;
|
|
21
|
+
/**
|
|
22
|
+
* Check if a given date is today
|
|
23
|
+
*/
|
|
24
|
+
const isToday = (date) => {
|
|
25
|
+
const today = new Date();
|
|
26
|
+
return (date.getDate() === today.getDate() &&
|
|
27
|
+
date.getMonth() === today.getMonth() &&
|
|
28
|
+
date.getFullYear() === today.getFullYear());
|
|
29
|
+
};
|
|
30
|
+
exports.isToday = isToday;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import Decimal from 'decimal.js';
|
|
2
|
+
/**
|
|
3
|
+
* Convert a value to Decimal
|
|
4
|
+
*/
|
|
5
|
+
export declare const toDecimal: (value: number | string | Decimal) => Decimal;
|
|
6
|
+
/**
|
|
7
|
+
* Convert Decimal to Prisma-compatible number
|
|
8
|
+
*/
|
|
9
|
+
export declare const toPrismaDecimal: (value: Decimal) => number;
|
|
@@ -0,0 +1,31 @@
|
|
|
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.toPrismaDecimal = exports.toDecimal = void 0;
|
|
7
|
+
const decimal_js_1 = __importDefault(require("decimal.js"));
|
|
8
|
+
const DEFAULT_DECIMAL_PLACES = 4;
|
|
9
|
+
decimal_js_1.default.set({ precision: 20, rounding: decimal_js_1.default.ROUND_HALF_UP });
|
|
10
|
+
/**
|
|
11
|
+
* Convert a value to Decimal
|
|
12
|
+
*/
|
|
13
|
+
const toDecimal = (value) => {
|
|
14
|
+
try {
|
|
15
|
+
return new decimal_js_1.default(value);
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
throw new Error(`Invalid decimal value: ${value}`);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
exports.toDecimal = toDecimal;
|
|
22
|
+
/**
|
|
23
|
+
* Convert Decimal to Prisma-compatible number
|
|
24
|
+
*/
|
|
25
|
+
const toPrismaDecimal = (value) => {
|
|
26
|
+
if (!decimal_js_1.default.isDecimal(value)) {
|
|
27
|
+
throw new Error('Value must be a Decimal instance');
|
|
28
|
+
}
|
|
29
|
+
return value.toDecimalPlaces(DEFAULT_DECIMAL_PLACES).toNumber();
|
|
30
|
+
};
|
|
31
|
+
exports.toPrismaDecimal = toPrismaDecimal;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formats currency (Naira)
|
|
3
|
+
* 1234.56 → ₦1,234.56
|
|
4
|
+
*/
|
|
5
|
+
export declare const formatCurrency: (amount: number, currency?: string, decimals?: number) => string;
|
|
6
|
+
/**
|
|
7
|
+
* Formats currency without symbol
|
|
8
|
+
* 1234.56 → 1,234.56
|
|
9
|
+
*/
|
|
10
|
+
export declare const formatAmount: (amount: number, decimals?: number) => string;
|
|
11
|
+
/**
|
|
12
|
+
* Formats account number for display
|
|
13
|
+
* 0123456789 → 0123 4567 89
|
|
14
|
+
*/
|
|
15
|
+
export declare const formatAccountNumber: (accountNumber: string) => string;
|
|
16
|
+
/**
|
|
17
|
+
* Masks account number for security
|
|
18
|
+
* 0123456789 → ****6789
|
|
19
|
+
*/
|
|
20
|
+
export declare const maskAccountNumber: (accountNumber: string) => string;
|
|
21
|
+
/**
|
|
22
|
+
* Masks email for security
|
|
23
|
+
* user@example.com → u***@example.com
|
|
24
|
+
*/
|
|
25
|
+
export declare const maskEmail: (email: string) => string;
|
|
26
|
+
/**
|
|
27
|
+
* Formats date to Nigerian format
|
|
28
|
+
* 2024-01-15 → 15/01/2024
|
|
29
|
+
*/
|
|
30
|
+
export declare const formatDate: (date: Date | string) => string;
|
|
31
|
+
/**
|
|
32
|
+
* Formats date and time
|
|
33
|
+
* → 15/01/2024 14:30
|
|
34
|
+
*/
|
|
35
|
+
export declare const formatDateTime: (date: Date | string) => string;
|
|
36
|
+
/**
|
|
37
|
+
* Formats relative time
|
|
38
|
+
* → "2 hours ago", "3 days ago"
|
|
39
|
+
*/
|
|
40
|
+
export declare const formatRelativeTime: (date: Date | string) => string;
|
|
41
|
+
/**
|
|
42
|
+
* Formats percentage
|
|
43
|
+
* 0.025 → 2.5%
|
|
44
|
+
*/
|
|
45
|
+
export declare const formatPercentage: (value: number, decimals?: number) => string;
|
|
46
|
+
/**
|
|
47
|
+
* Formats file size
|
|
48
|
+
* 1536 → 1.5 KB
|
|
49
|
+
*/
|
|
50
|
+
export declare const formatFileSize: (bytes: number) => string;
|
|
51
|
+
/**
|
|
52
|
+
* Truncates text with ellipsis
|
|
53
|
+
* "Long text here" → "Long te..."
|
|
54
|
+
*/
|
|
55
|
+
export declare const truncateText: (text: string, maxLength: number) => string;
|
|
56
|
+
/**
|
|
57
|
+
* Capitalizes first letter of each word
|
|
58
|
+
* "john doe" → "John Doe"
|
|
59
|
+
*/
|
|
60
|
+
export declare const toTitleCase: (text: string) => string;
|
|
61
|
+
/**
|
|
62
|
+
* Formats transaction status for display
|
|
63
|
+
*/
|
|
64
|
+
export declare const formatTransactionStatus: (status: string) => string;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatTransactionStatus = exports.toTitleCase = exports.truncateText = exports.formatFileSize = exports.formatPercentage = exports.formatRelativeTime = exports.formatDateTime = exports.formatDate = exports.maskEmail = exports.maskAccountNumber = exports.formatAccountNumber = exports.formatAmount = exports.formatCurrency = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Formats currency (Naira)
|
|
6
|
+
* 1234.56 → ₦1,234.56
|
|
7
|
+
*/
|
|
8
|
+
const formatCurrency = (amount, currency = '₦', decimals = 2) => {
|
|
9
|
+
const formatted = amount.toLocaleString('en-NG', {
|
|
10
|
+
minimumFractionDigits: decimals,
|
|
11
|
+
maximumFractionDigits: decimals,
|
|
12
|
+
});
|
|
13
|
+
return `${currency}${formatted}`;
|
|
14
|
+
};
|
|
15
|
+
exports.formatCurrency = formatCurrency;
|
|
16
|
+
/**
|
|
17
|
+
* Formats currency without symbol
|
|
18
|
+
* 1234.56 → 1,234.56
|
|
19
|
+
*/
|
|
20
|
+
const formatAmount = (amount, decimals = 2) => {
|
|
21
|
+
return amount.toLocaleString('en-NG', {
|
|
22
|
+
minimumFractionDigits: decimals,
|
|
23
|
+
maximumFractionDigits: decimals,
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
exports.formatAmount = formatAmount;
|
|
27
|
+
/**
|
|
28
|
+
* Formats account number for display
|
|
29
|
+
* 0123456789 → 0123 4567 89
|
|
30
|
+
*/
|
|
31
|
+
const formatAccountNumber = (accountNumber) => {
|
|
32
|
+
if (accountNumber.length !== 10)
|
|
33
|
+
return accountNumber;
|
|
34
|
+
return `${accountNumber.substring(0, 4)} ${accountNumber.substring(4, 8)} ${accountNumber.substring(8)}`;
|
|
35
|
+
};
|
|
36
|
+
exports.formatAccountNumber = formatAccountNumber;
|
|
37
|
+
/**
|
|
38
|
+
* Masks account number for security
|
|
39
|
+
* 0123456789 → ****6789
|
|
40
|
+
*/
|
|
41
|
+
const maskAccountNumber = (accountNumber) => {
|
|
42
|
+
if (accountNumber.length < 4)
|
|
43
|
+
return accountNumber;
|
|
44
|
+
return '*'.repeat(accountNumber.length - 4) + accountNumber.slice(-4);
|
|
45
|
+
};
|
|
46
|
+
exports.maskAccountNumber = maskAccountNumber;
|
|
47
|
+
/**
|
|
48
|
+
* Masks email for security
|
|
49
|
+
* user@example.com → u***@example.com
|
|
50
|
+
*/
|
|
51
|
+
const maskEmail = (email) => {
|
|
52
|
+
const [username, domain] = email.split('@');
|
|
53
|
+
if (!username || !domain)
|
|
54
|
+
return email;
|
|
55
|
+
const maskedUsername = username[0] + '*'.repeat(username.length - 1);
|
|
56
|
+
return `${maskedUsername}@${domain}`;
|
|
57
|
+
};
|
|
58
|
+
exports.maskEmail = maskEmail;
|
|
59
|
+
/**
|
|
60
|
+
* Formats date to Nigerian format
|
|
61
|
+
* 2024-01-15 → 15/01/2024
|
|
62
|
+
*/
|
|
63
|
+
const formatDate = (date) => {
|
|
64
|
+
const d = new Date(date);
|
|
65
|
+
const day = String(d.getDate()).padStart(2, '0');
|
|
66
|
+
const month = String(d.getMonth() + 1).padStart(2, '0');
|
|
67
|
+
const year = d.getFullYear();
|
|
68
|
+
return `${day}/${month}/${year}`;
|
|
69
|
+
};
|
|
70
|
+
exports.formatDate = formatDate;
|
|
71
|
+
/**
|
|
72
|
+
* Formats date and time
|
|
73
|
+
* → 15/01/2024 14:30
|
|
74
|
+
*/
|
|
75
|
+
const formatDateTime = (date) => {
|
|
76
|
+
const d = new Date(date);
|
|
77
|
+
const dateStr = (0, exports.formatDate)(d);
|
|
78
|
+
const hours = String(d.getHours()).padStart(2, '0');
|
|
79
|
+
const minutes = String(d.getMinutes()).padStart(2, '0');
|
|
80
|
+
return `${dateStr} ${hours}:${minutes}`;
|
|
81
|
+
};
|
|
82
|
+
exports.formatDateTime = formatDateTime;
|
|
83
|
+
/**
|
|
84
|
+
* Formats relative time
|
|
85
|
+
* → "2 hours ago", "3 days ago"
|
|
86
|
+
*/
|
|
87
|
+
const formatRelativeTime = (date) => {
|
|
88
|
+
const d = new Date(date);
|
|
89
|
+
const now = new Date();
|
|
90
|
+
const diffMs = now.getTime() - d.getTime();
|
|
91
|
+
const diffSecs = Math.floor(diffMs / 1000);
|
|
92
|
+
const diffMins = Math.floor(diffSecs / 60);
|
|
93
|
+
const diffHours = Math.floor(diffMins / 60);
|
|
94
|
+
const diffDays = Math.floor(diffHours / 24);
|
|
95
|
+
if (diffSecs < 60)
|
|
96
|
+
return 'Just now';
|
|
97
|
+
if (diffMins < 60)
|
|
98
|
+
return `${diffMins} minute${diffMins > 1 ? 's' : ''} ago`;
|
|
99
|
+
if (diffHours < 24)
|
|
100
|
+
return `${diffHours} hour${diffHours > 1 ? 's' : ''} ago`;
|
|
101
|
+
if (diffDays < 7)
|
|
102
|
+
return `${diffDays} day${diffDays > 1 ? 's' : ''} ago`;
|
|
103
|
+
return (0, exports.formatDate)(d);
|
|
104
|
+
};
|
|
105
|
+
exports.formatRelativeTime = formatRelativeTime;
|
|
106
|
+
/**
|
|
107
|
+
* Formats percentage
|
|
108
|
+
* 0.025 → 2.5%
|
|
109
|
+
*/
|
|
110
|
+
const formatPercentage = (value, decimals = 1) => {
|
|
111
|
+
return `${(value * 100).toFixed(decimals)}%`;
|
|
112
|
+
};
|
|
113
|
+
exports.formatPercentage = formatPercentage;
|
|
114
|
+
/**
|
|
115
|
+
* Formats file size
|
|
116
|
+
* 1536 → 1.5 KB
|
|
117
|
+
*/
|
|
118
|
+
const formatFileSize = (bytes) => {
|
|
119
|
+
if (bytes === 0)
|
|
120
|
+
return '0 Bytes';
|
|
121
|
+
const k = 1024;
|
|
122
|
+
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|
123
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
124
|
+
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
|
|
125
|
+
};
|
|
126
|
+
exports.formatFileSize = formatFileSize;
|
|
127
|
+
/**
|
|
128
|
+
* Truncates text with ellipsis
|
|
129
|
+
* "Long text here" → "Long te..."
|
|
130
|
+
*/
|
|
131
|
+
const truncateText = (text, maxLength) => {
|
|
132
|
+
if (text.length <= maxLength)
|
|
133
|
+
return text;
|
|
134
|
+
return text.substring(0, maxLength - 3) + '...';
|
|
135
|
+
};
|
|
136
|
+
exports.truncateText = truncateText;
|
|
137
|
+
/**
|
|
138
|
+
* Capitalizes first letter of each word
|
|
139
|
+
* "john doe" → "John Doe"
|
|
140
|
+
*/
|
|
141
|
+
const toTitleCase = (text) => {
|
|
142
|
+
return text
|
|
143
|
+
.toLowerCase()
|
|
144
|
+
.split(' ')
|
|
145
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
146
|
+
.join(' ');
|
|
147
|
+
};
|
|
148
|
+
exports.toTitleCase = toTitleCase;
|
|
149
|
+
/**
|
|
150
|
+
* Formats transaction status for display
|
|
151
|
+
*/
|
|
152
|
+
const formatTransactionStatus = (status) => {
|
|
153
|
+
const statusMap = {
|
|
154
|
+
PENDING: 'Pending',
|
|
155
|
+
SUCCESS: 'Successful',
|
|
156
|
+
FAILED: 'Failed',
|
|
157
|
+
REVERSED: 'Reversed',
|
|
158
|
+
PROCESSING: 'Processing',
|
|
159
|
+
};
|
|
160
|
+
return statusMap[status] || (0, exports.toTitleCase)(status);
|
|
161
|
+
};
|
|
162
|
+
exports.formatTransactionStatus = formatTransactionStatus;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
interface PenaltyTier {
|
|
2
|
+
maxDays: number;
|
|
3
|
+
rate: number;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Calculates the penalty rate based on the number of days a loan repayment is delayed.
|
|
7
|
+
* Uses predefined penalty tiers to determine the rate.
|
|
8
|
+
*
|
|
9
|
+
* @param delayInDays - The number of days the loan repayment is delayed.
|
|
10
|
+
* @returns The penalty rate as a decimal (e.g., 0.025 for 2.5%).
|
|
11
|
+
*/
|
|
12
|
+
export declare const calculatePenalty: (delayInDays: number) => number;
|
|
13
|
+
/**
|
|
14
|
+
* Calculates the penalty amount based on the principal and the number of days delayed.
|
|
15
|
+
*
|
|
16
|
+
* @param principal - The principal amount of the loan.
|
|
17
|
+
* @param delayInDays - The number of days the loan repayment is delayed.
|
|
18
|
+
* @returns The penalty amount.
|
|
19
|
+
*/
|
|
20
|
+
export declare const calculatePenaltyAmount: (principal: number, delayInDays: number) => number;
|
|
21
|
+
/**
|
|
22
|
+
* Get all penalty tiers
|
|
23
|
+
*/
|
|
24
|
+
export declare const getPenaltyTiers: () => PenaltyTier[];
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getPenaltyTiers = exports.calculatePenaltyAmount = exports.calculatePenalty = void 0;
|
|
4
|
+
const PENALTY_TIERS = [
|
|
5
|
+
{ maxDays: 7, rate: 0.025 }, // 2.5% for first week
|
|
6
|
+
{ maxDays: 14, rate: 0.05 }, // 5% for second week
|
|
7
|
+
{ maxDays: 21, rate: 0.075 }, // 7.5% for third week
|
|
8
|
+
{ maxDays: Infinity, rate: 0.1 }, // 10% for anything beyond
|
|
9
|
+
];
|
|
10
|
+
/**
|
|
11
|
+
* Calculates the penalty rate based on the number of days a loan repayment is delayed.
|
|
12
|
+
* Uses predefined penalty tiers to determine the rate.
|
|
13
|
+
*
|
|
14
|
+
* @param delayInDays - The number of days the loan repayment is delayed.
|
|
15
|
+
* @returns The penalty rate as a decimal (e.g., 0.025 for 2.5%).
|
|
16
|
+
*/
|
|
17
|
+
const calculatePenalty = (delayInDays) => {
|
|
18
|
+
const tier = PENALTY_TIERS.find((tier) => delayInDays <= tier.maxDays);
|
|
19
|
+
return tier ? tier.rate : PENALTY_TIERS[PENALTY_TIERS.length - 1].rate;
|
|
20
|
+
};
|
|
21
|
+
exports.calculatePenalty = calculatePenalty;
|
|
22
|
+
/**
|
|
23
|
+
* Calculates the penalty amount based on the principal and the number of days delayed.
|
|
24
|
+
*
|
|
25
|
+
* @param principal - The principal amount of the loan.
|
|
26
|
+
* @param delayInDays - The number of days the loan repayment is delayed.
|
|
27
|
+
* @returns The penalty amount.
|
|
28
|
+
*/
|
|
29
|
+
const calculatePenaltyAmount = (principal, delayInDays) => {
|
|
30
|
+
const rate = (0, exports.calculatePenalty)(delayInDays);
|
|
31
|
+
return principal * rate;
|
|
32
|
+
};
|
|
33
|
+
exports.calculatePenaltyAmount = calculatePenaltyAmount;
|
|
34
|
+
/**
|
|
35
|
+
* Get all penalty tiers
|
|
36
|
+
*/
|
|
37
|
+
const getPenaltyTiers = () => {
|
|
38
|
+
return [...PENALTY_TIERS];
|
|
39
|
+
};
|
|
40
|
+
exports.getPenaltyTiers = getPenaltyTiers;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.generateReferralCode = void 0;
|
|
37
|
+
const crypto = __importStar(require("crypto"));
|
|
38
|
+
/**
|
|
39
|
+
* Generate a unique referral code in format TNT-XXXX-XXXX
|
|
40
|
+
*/
|
|
41
|
+
const generateReferralCode = () => {
|
|
42
|
+
const chars = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ';
|
|
43
|
+
const generateRandomPart = (length) => {
|
|
44
|
+
const randomBytes = crypto.randomBytes(length);
|
|
45
|
+
return Array.from(randomBytes)
|
|
46
|
+
.map((x) => chars[x % chars.length])
|
|
47
|
+
.join('');
|
|
48
|
+
};
|
|
49
|
+
const firstPart = generateRandomPart(4);
|
|
50
|
+
const secondPart = generateRandomPart(4);
|
|
51
|
+
return `TNT-${firstPart}-${secondPart}`;
|
|
52
|
+
};
|
|
53
|
+
exports.generateReferralCode = generateReferralCode;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getBaseRole = exports.isAdminRole = void 0;
|
|
4
|
+
const BASE_ROLE = 'USER';
|
|
5
|
+
/**
|
|
6
|
+
* Check if role is an admin role
|
|
7
|
+
*/
|
|
8
|
+
const isAdminRole = (roleName) => {
|
|
9
|
+
return roleName !== BASE_ROLE;
|
|
10
|
+
};
|
|
11
|
+
exports.isAdminRole = isAdminRole;
|
|
12
|
+
/**
|
|
13
|
+
* Get base role
|
|
14
|
+
*/
|
|
15
|
+
const getBaseRole = () => {
|
|
16
|
+
return BASE_ROLE;
|
|
17
|
+
};
|
|
18
|
+
exports.getBaseRole = getBaseRole;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation utilities for common Nigerian/African fintech use cases
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Validates Nigerian phone number
|
|
6
|
+
* Accepts formats: 08012345678, +2348012345678, 2348012345678
|
|
7
|
+
*/
|
|
8
|
+
export declare const isValidNigerianPhone: (phone: string) => boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Validates email address
|
|
11
|
+
*/
|
|
12
|
+
export declare const isValidEmail: (email: string) => boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Validates Nigerian BVN (Bank Verification Number)
|
|
15
|
+
* Must be exactly 11 digits
|
|
16
|
+
*/
|
|
17
|
+
export declare const isValidBVN: (bvn: string) => boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Validates Nigerian NIN (National Identification Number)
|
|
20
|
+
* Must be exactly 11 digits
|
|
21
|
+
*/
|
|
22
|
+
export declare const isValidNIN: (nin: string) => boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Validates Nigerian account number
|
|
25
|
+
* Must be exactly 10 digits (NUBAN format)
|
|
26
|
+
*/
|
|
27
|
+
export declare const isValidAccountNumber: (accountNumber: string) => boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Validates amount (must be positive number)
|
|
30
|
+
*/
|
|
31
|
+
export declare const isValidAmount: (amount: number) => boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Validates password strength
|
|
34
|
+
* At least 8 characters, 1 uppercase, 1 lowercase, 1 number
|
|
35
|
+
*/
|
|
36
|
+
export declare const isStrongPassword: (password: string) => boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Validates referral code format
|
|
39
|
+
* 6-10 alphanumeric characters
|
|
40
|
+
*/
|
|
41
|
+
export declare const isValidReferralCode: (code: string) => boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Validates transaction reference format
|
|
44
|
+
*/
|
|
45
|
+
export declare const isValidTransactionReference: (ref: string) => boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Sanitizes phone number to standard format
|
|
48
|
+
* Converts to: 2348012345678
|
|
49
|
+
*/
|
|
50
|
+
export declare const sanitizePhoneNumber: (phone: string) => string;
|
|
51
|
+
/**
|
|
52
|
+
* Validates date is not in the past
|
|
53
|
+
*/
|
|
54
|
+
export declare const isNotPastDate: (date: Date) => boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Validates date is within range
|
|
57
|
+
*/
|
|
58
|
+
export declare const isDateInRange: (date: Date, minDate: Date, maxDate: Date) => boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Validates age is above minimum (for KYC)
|
|
61
|
+
*/
|
|
62
|
+
export declare const isValidAge: (dateOfBirth: Date, minAge?: number) => boolean;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Validation utilities for common Nigerian/African fintech use cases
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.isValidAge = exports.isDateInRange = exports.isNotPastDate = exports.sanitizePhoneNumber = exports.isValidTransactionReference = exports.isValidReferralCode = exports.isStrongPassword = exports.isValidAmount = exports.isValidAccountNumber = exports.isValidNIN = exports.isValidBVN = exports.isValidEmail = exports.isValidNigerianPhone = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* Validates Nigerian phone number
|
|
9
|
+
* Accepts formats: 08012345678, +2348012345678, 2348012345678
|
|
10
|
+
*/
|
|
11
|
+
const isValidNigerianPhone = (phone) => {
|
|
12
|
+
const cleaned = phone.replace(/[\s\-\(\)]/g, '');
|
|
13
|
+
const patterns = [
|
|
14
|
+
/^0[7-9][0-1]\d{8}$/, // 08012345678
|
|
15
|
+
/^\+234[7-9][0-1]\d{8}$/, // +2348012345678
|
|
16
|
+
/^234[7-9][0-1]\d{8}$/, // 2348012345678
|
|
17
|
+
];
|
|
18
|
+
return patterns.some((pattern) => pattern.test(cleaned));
|
|
19
|
+
};
|
|
20
|
+
exports.isValidNigerianPhone = isValidNigerianPhone;
|
|
21
|
+
/**
|
|
22
|
+
* Validates email address
|
|
23
|
+
*/
|
|
24
|
+
const isValidEmail = (email) => {
|
|
25
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
26
|
+
return emailRegex.test(email);
|
|
27
|
+
};
|
|
28
|
+
exports.isValidEmail = isValidEmail;
|
|
29
|
+
/**
|
|
30
|
+
* Validates Nigerian BVN (Bank Verification Number)
|
|
31
|
+
* Must be exactly 11 digits
|
|
32
|
+
*/
|
|
33
|
+
const isValidBVN = (bvn) => {
|
|
34
|
+
return /^\d{11}$/.test(bvn);
|
|
35
|
+
};
|
|
36
|
+
exports.isValidBVN = isValidBVN;
|
|
37
|
+
/**
|
|
38
|
+
* Validates Nigerian NIN (National Identification Number)
|
|
39
|
+
* Must be exactly 11 digits
|
|
40
|
+
*/
|
|
41
|
+
const isValidNIN = (nin) => {
|
|
42
|
+
return /^\d{11}$/.test(nin);
|
|
43
|
+
};
|
|
44
|
+
exports.isValidNIN = isValidNIN;
|
|
45
|
+
/**
|
|
46
|
+
* Validates Nigerian account number
|
|
47
|
+
* Must be exactly 10 digits (NUBAN format)
|
|
48
|
+
*/
|
|
49
|
+
const isValidAccountNumber = (accountNumber) => {
|
|
50
|
+
return /^\d{10}$/.test(accountNumber);
|
|
51
|
+
};
|
|
52
|
+
exports.isValidAccountNumber = isValidAccountNumber;
|
|
53
|
+
/**
|
|
54
|
+
* Validates amount (must be positive number)
|
|
55
|
+
*/
|
|
56
|
+
const isValidAmount = (amount) => {
|
|
57
|
+
return typeof amount === 'number' && amount > 0 && isFinite(amount);
|
|
58
|
+
};
|
|
59
|
+
exports.isValidAmount = isValidAmount;
|
|
60
|
+
/**
|
|
61
|
+
* Validates password strength
|
|
62
|
+
* At least 8 characters, 1 uppercase, 1 lowercase, 1 number
|
|
63
|
+
*/
|
|
64
|
+
const isStrongPassword = (password) => {
|
|
65
|
+
const minLength = 8;
|
|
66
|
+
const hasUpperCase = /[A-Z]/.test(password);
|
|
67
|
+
const hasLowerCase = /[a-z]/.test(password);
|
|
68
|
+
const hasNumber = /\d/.test(password);
|
|
69
|
+
return (password.length >= minLength &&
|
|
70
|
+
hasUpperCase &&
|
|
71
|
+
hasLowerCase &&
|
|
72
|
+
hasNumber);
|
|
73
|
+
};
|
|
74
|
+
exports.isStrongPassword = isStrongPassword;
|
|
75
|
+
/**
|
|
76
|
+
* Validates referral code format
|
|
77
|
+
* 6-10 alphanumeric characters
|
|
78
|
+
*/
|
|
79
|
+
const isValidReferralCode = (code) => {
|
|
80
|
+
return /^[A-Z0-9]{6,10}$/.test(code);
|
|
81
|
+
};
|
|
82
|
+
exports.isValidReferralCode = isValidReferralCode;
|
|
83
|
+
/**
|
|
84
|
+
* Validates transaction reference format
|
|
85
|
+
*/
|
|
86
|
+
const isValidTransactionReference = (ref) => {
|
|
87
|
+
return /^[A-Z0-9_-]{10,50}$/.test(ref);
|
|
88
|
+
};
|
|
89
|
+
exports.isValidTransactionReference = isValidTransactionReference;
|
|
90
|
+
/**
|
|
91
|
+
* Sanitizes phone number to standard format
|
|
92
|
+
* Converts to: 2348012345678
|
|
93
|
+
*/
|
|
94
|
+
const sanitizePhoneNumber = (phone) => {
|
|
95
|
+
const cleaned = phone.replace(/[\s\-\(\)]/g, '');
|
|
96
|
+
// Remove leading + if present
|
|
97
|
+
let sanitized = cleaned.replace(/^\+/, '');
|
|
98
|
+
// Convert 0801... to 234801...
|
|
99
|
+
if (sanitized.startsWith('0')) {
|
|
100
|
+
sanitized = '234' + sanitized.substring(1);
|
|
101
|
+
}
|
|
102
|
+
// Ensure it starts with 234
|
|
103
|
+
if (!sanitized.startsWith('234')) {
|
|
104
|
+
sanitized = '234' + sanitized;
|
|
105
|
+
}
|
|
106
|
+
return sanitized;
|
|
107
|
+
};
|
|
108
|
+
exports.sanitizePhoneNumber = sanitizePhoneNumber;
|
|
109
|
+
/**
|
|
110
|
+
* Validates date is not in the past
|
|
111
|
+
*/
|
|
112
|
+
const isNotPastDate = (date) => {
|
|
113
|
+
return date.getTime() >= new Date().getTime();
|
|
114
|
+
};
|
|
115
|
+
exports.isNotPastDate = isNotPastDate;
|
|
116
|
+
/**
|
|
117
|
+
* Validates date is within range
|
|
118
|
+
*/
|
|
119
|
+
const isDateInRange = (date, minDate, maxDate) => {
|
|
120
|
+
const timestamp = date.getTime();
|
|
121
|
+
return timestamp >= minDate.getTime() && timestamp <= maxDate.getTime();
|
|
122
|
+
};
|
|
123
|
+
exports.isDateInRange = isDateInRange;
|
|
124
|
+
/**
|
|
125
|
+
* Validates age is above minimum (for KYC)
|
|
126
|
+
*/
|
|
127
|
+
const isValidAge = (dateOfBirth, minAge = 18) => {
|
|
128
|
+
const today = new Date();
|
|
129
|
+
const birthDate = new Date(dateOfBirth);
|
|
130
|
+
let age = today.getFullYear() - birthDate.getFullYear();
|
|
131
|
+
const monthDiff = today.getMonth() - birthDate.getMonth();
|
|
132
|
+
if (monthDiff < 0 ||
|
|
133
|
+
(monthDiff === 0 && today.getDate() < birthDate.getDate())) {
|
|
134
|
+
age--;
|
|
135
|
+
}
|
|
136
|
+
return age >= minAge;
|
|
137
|
+
};
|
|
138
|
+
exports.isValidAge = isValidAge;
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -14,6 +14,13 @@ export * from './utils';
|
|
|
14
14
|
export * from './interfaces';
|
|
15
15
|
export * from './dto';
|
|
16
16
|
export * from './enums';
|
|
17
|
+
export * from './helpers/decimal.util';
|
|
18
|
+
export * from './helpers/date.util';
|
|
19
|
+
export * from './helpers/role.util';
|
|
20
|
+
export * from './helpers/referral.util';
|
|
21
|
+
export * from './helpers/penalty.util';
|
|
22
|
+
export * from './helpers/validation.util';
|
|
23
|
+
export * from './helpers/format.util';
|
|
17
24
|
/**
|
|
18
25
|
* A set of shared utilities across the application.
|
|
19
26
|
*/
|