@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.
Files changed (47) hide show
  1. package/README.md +1 -0
  2. package/dist/auth/auth.interface.d.ts +8 -0
  3. package/dist/auth/auth.interface.js +2 -0
  4. package/dist/auth/decorators/get-user.decorator.d.ts +2 -0
  5. package/dist/auth/decorators/get-user.decorator.js +26 -0
  6. package/dist/auth/decorators/index.d.ts +1 -0
  7. package/dist/auth/decorators/index.js +1 -0
  8. package/dist/auth/index.d.ts +1 -0
  9. package/dist/auth/index.js +1 -0
  10. package/dist/common/utils/string.utils.d.ts +10 -2
  11. package/dist/common/utils/string.utils.js +30 -13
  12. package/dist/index.d.ts +1 -0
  13. package/dist/index.js +1 -0
  14. package/dist/metrics/metrics.interface.d.ts +0 -53
  15. package/dist/metrics/metrics.interface.js +0 -12
  16. package/dist/monitoring/alerting.service.d.ts +82 -0
  17. package/dist/monitoring/alerting.service.js +290 -0
  18. package/dist/monitoring/index.d.ts +5 -0
  19. package/dist/monitoring/index.js +21 -0
  20. package/dist/monitoring/monitoring.interface.d.ts +102 -0
  21. package/dist/monitoring/monitoring.interface.js +10 -0
  22. package/dist/monitoring/monitoring.module.d.ts +8 -0
  23. package/dist/monitoring/monitoring.module.js +44 -0
  24. package/dist/monitoring/sentry.service.d.ts +65 -0
  25. package/dist/monitoring/sentry.service.js +218 -0
  26. package/dist/monitoring/uptime.service.d.ts +59 -0
  27. package/dist/monitoring/uptime.service.js +213 -0
  28. package/dist/resilience/circuit-breaker.interface.d.ts +0 -75
  29. package/dist/resilience/circuit-breaker.interface.js +0 -6
  30. package/dist/tsconfig.tsbuildinfo +1 -1
  31. package/dist/utils/helpers/date.util.d.ts +8 -0
  32. package/dist/utils/helpers/date.util.js +30 -0
  33. package/dist/utils/helpers/decimal.util.d.ts +9 -0
  34. package/dist/utils/helpers/decimal.util.js +31 -0
  35. package/dist/utils/helpers/format.util.d.ts +64 -0
  36. package/dist/utils/helpers/format.util.js +162 -0
  37. package/dist/utils/helpers/penalty.util.d.ts +25 -0
  38. package/dist/utils/helpers/penalty.util.js +40 -0
  39. package/dist/utils/helpers/referral.util.d.ts +4 -0
  40. package/dist/utils/helpers/referral.util.js +53 -0
  41. package/dist/utils/helpers/role.util.d.ts +8 -0
  42. package/dist/utils/helpers/role.util.js +18 -0
  43. package/dist/utils/helpers/validation.util.d.ts +62 -0
  44. package/dist/utils/helpers/validation.util.js +138 -0
  45. package/dist/utils/index.d.ts +7 -0
  46. package/dist/utils/index.js +7 -0
  47. package/package.json +4 -1
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Calculate next date based on frequency
3
+ */
4
+ export declare const calculateNextDate: (frequency: "DAILY" | "WEEKLY" | "MONTHLY", lastDate: Date) => Date;
5
+ /**
6
+ * Check if a given date is today
7
+ */
8
+ export declare const isToday: (date: Date) => boolean;
@@ -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,4 @@
1
+ /**
2
+ * Generate a unique referral code in format TNT-XXXX-XXXX
3
+ */
4
+ export declare const generateReferralCode: () => string;
@@ -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,8 @@
1
+ /**
2
+ * Check if role is an admin role
3
+ */
4
+ export declare const isAdminRole: (roleName: string) => boolean;
5
+ /**
6
+ * Get base role
7
+ */
8
+ export declare const getBaseRole: () => string;
@@ -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;
@@ -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
  */