@viardex/viardex-libs 1.0.7 → 1.0.9
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 +69 -0
- package/dist/common/cards/card.utils.d.ts +9 -0
- package/dist/common/cards/card.utils.js +48 -0
- package/dist/common/cards/index.d.ts +1 -0
- package/dist/common/cards/index.js +17 -0
- package/dist/common/crypto/crypto.utils.d.ts +7 -0
- package/dist/common/crypto/crypto.utils.js +42 -0
- package/dist/common/crypto/index.d.ts +1 -0
- package/dist/common/crypto/index.js +17 -0
- package/dist/common/dto/index.d.ts +1 -0
- package/dist/common/dto/index.js +17 -0
- package/dist/common/dto/pagination-query.dto.d.ts +7 -0
- package/dist/common/dto/pagination-query.dto.js +51 -0
- package/dist/common/index.d.ts +6 -0
- package/dist/common/index.js +6 -0
- package/dist/common/interfaces/index.d.ts +1 -0
- package/dist/common/interfaces/index.js +17 -0
- package/dist/common/interfaces/response.interface.d.ts +27 -0
- package/dist/common/interfaces/response.interface.js +2 -0
- package/dist/common/pipes/file-validation.pipe.d.ts +22 -0
- package/dist/common/pipes/file-validation.pipe.js +78 -0
- package/dist/common/pipes/index.d.ts +2 -0
- package/dist/common/pipes/index.js +18 -0
- package/dist/common/pipes/pagination-query-cleaner.pipe.d.ts +4 -0
- package/dist/common/pipes/pagination-query-cleaner.pipe.js +24 -0
- package/dist/common/response/http-exception.filter.d.ts +6 -0
- package/dist/common/response/http-exception.filter.js +61 -0
- package/dist/common/response/index.d.ts +3 -0
- package/dist/common/response/index.js +19 -0
- package/dist/common/response/response.interceptor.d.ts +6 -0
- package/dist/common/response/response.interceptor.js +57 -0
- package/dist/common/response/response.utils.d.ts +6 -0
- package/dist/common/response/response.utils.js +34 -0
- package/dist/common/utils/country.utils.d.ts +1 -0
- package/dist/common/utils/country.utils.js +38 -0
- package/dist/common/utils/date.utils.d.ts +6 -0
- package/dist/common/utils/date.utils.js +48 -0
- package/dist/common/utils/decimal.utils.d.ts +3 -0
- package/dist/common/utils/decimal.utils.js +22 -0
- package/dist/common/utils/format.utils.d.ts +13 -0
- package/dist/common/utils/format.utils.js +127 -0
- package/dist/common/utils/index.d.ts +5 -0
- package/dist/common/utils/index.js +5 -0
- package/dist/common/utils/validation.utils.d.ts +8 -0
- package/dist/common/utils/validation.utils.js +44 -0
- package/dist/logger/logger.module.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -119,6 +119,75 @@ Preferred APIs:
|
|
|
119
119
|
- `scan()` instead of `keys()` for production-safe pattern reads
|
|
120
120
|
- `ping()` for lightweight health checks
|
|
121
121
|
|
|
122
|
+
## Common
|
|
123
|
+
|
|
124
|
+
`@viardex/viardex-libs` also exposes shared DTOs, pipes, response helpers, and safe formatting utilities through the root barrel.
|
|
125
|
+
|
|
126
|
+
### Response Shape
|
|
127
|
+
|
|
128
|
+
Use the shared response helpers to keep HTTP payloads consistent across Nest services.
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
import { AppResponse } from '@viardex/viardex-libs';
|
|
132
|
+
|
|
133
|
+
return AppResponse.success('User fetched successfully', user);
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
For paginated endpoints:
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
return AppResponse.paginated('Users fetched successfully', items, {
|
|
140
|
+
page,
|
|
141
|
+
limit,
|
|
142
|
+
totalItems,
|
|
143
|
+
totalPages,
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Shared response exports include:
|
|
148
|
+
|
|
149
|
+
- `ApiResponse`
|
|
150
|
+
- `PaginationMeta`
|
|
151
|
+
- `ResponseMeta`
|
|
152
|
+
- `ErrorDetail`
|
|
153
|
+
- `AppResponse`
|
|
154
|
+
- `ResponseInterceptor`
|
|
155
|
+
- `HttpExceptionFilter`
|
|
156
|
+
|
|
157
|
+
### DTOs And Pipes
|
|
158
|
+
|
|
159
|
+
Shared request helpers include:
|
|
160
|
+
|
|
161
|
+
- `PaginationQueryDto`
|
|
162
|
+
- `PaginationQueryCleanerPipe`
|
|
163
|
+
- `FileValidationPipe`
|
|
164
|
+
|
|
165
|
+
### Cards
|
|
166
|
+
|
|
167
|
+
Shared card-safe helpers are available for masking and display use cases:
|
|
168
|
+
|
|
169
|
+
- `maskPan`
|
|
170
|
+
- `extractLast4`
|
|
171
|
+
- `extractBin`
|
|
172
|
+
- `formatCardExpiry`
|
|
173
|
+
- `normalizeCardExpiry`
|
|
174
|
+
- `formatCardLabel`
|
|
175
|
+
|
|
176
|
+
These are for safe formatting and display only. Sensitive authentication data like CVV must never be stored or handled through shared helpers.
|
|
177
|
+
|
|
178
|
+
### Crypto
|
|
179
|
+
|
|
180
|
+
Shared crypto helpers are intentionally limited to generic amount and formatting concerns:
|
|
181
|
+
|
|
182
|
+
- `toAtomicUnits`
|
|
183
|
+
- `fromAtomicUnits`
|
|
184
|
+
- `formatCryptoAmount`
|
|
185
|
+
- `normalizeTxHash`
|
|
186
|
+
- `isHexTxHash`
|
|
187
|
+
- `isPositiveAmount`
|
|
188
|
+
|
|
189
|
+
They are useful for asset formatting and validation, but custody, compliance, signing, and chain-specific business logic should stay inside the owning service.
|
|
190
|
+
|
|
122
191
|
## Nest And Go Mapping
|
|
123
192
|
|
|
124
193
|
The Go shared package in `viardex-go` follows the same auth concepts, but uses middleware and request context instead of Nest metadata and guards.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const maskPan: (pan: string, visiblePrefix?: number, visibleSuffix?: number) => string;
|
|
2
|
+
export declare const extractLast4: (pan: string) => string;
|
|
3
|
+
export declare const extractBin: (pan: string, length?: number) => string;
|
|
4
|
+
export declare const formatCardExpiry: (month: number | string, year: number | string) => string;
|
|
5
|
+
export declare const normalizeCardExpiry: (expiry: string) => {
|
|
6
|
+
month: string;
|
|
7
|
+
year: string;
|
|
8
|
+
} | null;
|
|
9
|
+
export declare const formatCardLabel: (brand: string | undefined, last4: string) => string;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatCardLabel = exports.normalizeCardExpiry = exports.formatCardExpiry = exports.extractBin = exports.extractLast4 = exports.maskPan = void 0;
|
|
4
|
+
const maskPan = (pan, visiblePrefix = 0, visibleSuffix = 4) => {
|
|
5
|
+
const digits = pan.replace(/\s+/g, '');
|
|
6
|
+
if (digits.length <= visibleSuffix) {
|
|
7
|
+
return digits;
|
|
8
|
+
}
|
|
9
|
+
const prefix = digits.slice(0, visiblePrefix);
|
|
10
|
+
const suffix = digits.slice(-visibleSuffix);
|
|
11
|
+
const maskedLength = Math.max(0, digits.length - visiblePrefix - visibleSuffix);
|
|
12
|
+
return `${prefix}${'*'.repeat(maskedLength)}${suffix}`;
|
|
13
|
+
};
|
|
14
|
+
exports.maskPan = maskPan;
|
|
15
|
+
const extractLast4 = (pan) => {
|
|
16
|
+
const digits = pan.replace(/\s+/g, '');
|
|
17
|
+
return digits.slice(-4);
|
|
18
|
+
};
|
|
19
|
+
exports.extractLast4 = extractLast4;
|
|
20
|
+
const extractBin = (pan, length = 6) => {
|
|
21
|
+
const digits = pan.replace(/\s+/g, '');
|
|
22
|
+
return digits.slice(0, length);
|
|
23
|
+
};
|
|
24
|
+
exports.extractBin = extractBin;
|
|
25
|
+
const formatCardExpiry = (month, year) => {
|
|
26
|
+
const normalizedMonth = String(month).padStart(2, '0');
|
|
27
|
+
const normalizedYear = String(year).slice(-2);
|
|
28
|
+
return `${normalizedMonth}/${normalizedYear}`;
|
|
29
|
+
};
|
|
30
|
+
exports.formatCardExpiry = formatCardExpiry;
|
|
31
|
+
const normalizeCardExpiry = (expiry) => {
|
|
32
|
+
const normalized = expiry.trim();
|
|
33
|
+
const match = normalized.match(/^(\d{1,2})\s*\/\s*(\d{2,4})$/);
|
|
34
|
+
if (!match) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
const month = match[1].padStart(2, '0');
|
|
38
|
+
const year = match[2].length === 2 ? `20${match[2]}` : match[2];
|
|
39
|
+
if (Number(month) < 1 || Number(month) > 12) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
return { month, year };
|
|
43
|
+
};
|
|
44
|
+
exports.normalizeCardExpiry = normalizeCardExpiry;
|
|
45
|
+
const formatCardLabel = (brand, last4) => {
|
|
46
|
+
return `${brand?.trim() || 'Card'} •••• ${last4}`;
|
|
47
|
+
};
|
|
48
|
+
exports.formatCardLabel = formatCardLabel;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './card.utils';
|
|
@@ -0,0 +1,17 @@
|
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./card.utils"), exports);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import Decimal from 'decimal.js';
|
|
2
|
+
export declare const toAtomicUnits: (value: string | number | Decimal, decimals: number) => string;
|
|
3
|
+
export declare const fromAtomicUnits: (value: string | number | Decimal, decimals: number) => string;
|
|
4
|
+
export declare const formatCryptoAmount: (value: string | number | Decimal, decimals?: number) => string;
|
|
5
|
+
export declare const normalizeTxHash: (hash: string) => string;
|
|
6
|
+
export declare const isHexTxHash: (hash: string, expectedLength?: number) => boolean;
|
|
7
|
+
export declare const isPositiveAmount: (value: string | number | Decimal) => boolean;
|
|
@@ -0,0 +1,42 @@
|
|
|
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.isPositiveAmount = exports.isHexTxHash = exports.normalizeTxHash = exports.formatCryptoAmount = exports.fromAtomicUnits = exports.toAtomicUnits = void 0;
|
|
7
|
+
const decimal_js_1 = __importDefault(require("decimal.js"));
|
|
8
|
+
const DECIMAL_ZERO = new decimal_js_1.default(0);
|
|
9
|
+
const toAtomicUnits = (value, decimals) => {
|
|
10
|
+
return new decimal_js_1.default(value)
|
|
11
|
+
.mul(new decimal_js_1.default(10).pow(decimals))
|
|
12
|
+
.toDecimalPlaces(0, decimal_js_1.default.ROUND_DOWN)
|
|
13
|
+
.toFixed(0);
|
|
14
|
+
};
|
|
15
|
+
exports.toAtomicUnits = toAtomicUnits;
|
|
16
|
+
const fromAtomicUnits = (value, decimals) => {
|
|
17
|
+
return new decimal_js_1.default(value).div(new decimal_js_1.default(10).pow(decimals)).toFixed();
|
|
18
|
+
};
|
|
19
|
+
exports.fromAtomicUnits = fromAtomicUnits;
|
|
20
|
+
const formatCryptoAmount = (value, decimals = 8) => {
|
|
21
|
+
return new decimal_js_1.default(value).toDecimalPlaces(decimals).toString();
|
|
22
|
+
};
|
|
23
|
+
exports.formatCryptoAmount = formatCryptoAmount;
|
|
24
|
+
const normalizeTxHash = (hash) => {
|
|
25
|
+
return hash.trim().toLowerCase();
|
|
26
|
+
};
|
|
27
|
+
exports.normalizeTxHash = normalizeTxHash;
|
|
28
|
+
const isHexTxHash = (hash, expectedLength) => {
|
|
29
|
+
const normalized = hash.trim().toLowerCase();
|
|
30
|
+
if (!/^0x[a-f0-9]+$/.test(normalized)) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
if (expectedLength && normalized.length !== expectedLength) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
return true;
|
|
37
|
+
};
|
|
38
|
+
exports.isHexTxHash = isHexTxHash;
|
|
39
|
+
const isPositiveAmount = (value) => {
|
|
40
|
+
return new decimal_js_1.default(value).greaterThan(DECIMAL_ZERO);
|
|
41
|
+
};
|
|
42
|
+
exports.isPositiveAmount = isPositiveAmount;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './crypto.utils';
|
|
@@ -0,0 +1,17 @@
|
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./crypto.utils"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './pagination-query.dto';
|
|
@@ -0,0 +1,17 @@
|
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./pagination-query.dto"), exports);
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.PaginationQueryDto = void 0;
|
|
13
|
+
const class_transformer_1 = require("class-transformer");
|
|
14
|
+
const class_validator_1 = require("class-validator");
|
|
15
|
+
class PaginationQueryDto {
|
|
16
|
+
page;
|
|
17
|
+
limit;
|
|
18
|
+
search;
|
|
19
|
+
sortBy;
|
|
20
|
+
sortOrder;
|
|
21
|
+
}
|
|
22
|
+
exports.PaginationQueryDto = PaginationQueryDto;
|
|
23
|
+
__decorate([
|
|
24
|
+
(0, class_transformer_1.Type)(() => Number),
|
|
25
|
+
(0, class_validator_1.IsInt)(),
|
|
26
|
+
(0, class_validator_1.Min)(1),
|
|
27
|
+
(0, class_validator_1.IsOptional)(),
|
|
28
|
+
__metadata("design:type", Number)
|
|
29
|
+
], PaginationQueryDto.prototype, "page", void 0);
|
|
30
|
+
__decorate([
|
|
31
|
+
(0, class_transformer_1.Type)(() => Number),
|
|
32
|
+
(0, class_validator_1.IsInt)(),
|
|
33
|
+
(0, class_validator_1.Min)(1),
|
|
34
|
+
(0, class_validator_1.IsOptional)(),
|
|
35
|
+
__metadata("design:type", Number)
|
|
36
|
+
], PaginationQueryDto.prototype, "limit", void 0);
|
|
37
|
+
__decorate([
|
|
38
|
+
(0, class_validator_1.IsString)(),
|
|
39
|
+
(0, class_validator_1.IsOptional)(),
|
|
40
|
+
__metadata("design:type", String)
|
|
41
|
+
], PaginationQueryDto.prototype, "search", void 0);
|
|
42
|
+
__decorate([
|
|
43
|
+
(0, class_validator_1.IsString)(),
|
|
44
|
+
(0, class_validator_1.IsOptional)(),
|
|
45
|
+
__metadata("design:type", String)
|
|
46
|
+
], PaginationQueryDto.prototype, "sortBy", void 0);
|
|
47
|
+
__decorate([
|
|
48
|
+
(0, class_validator_1.IsIn)(['asc', 'desc']),
|
|
49
|
+
(0, class_validator_1.IsOptional)(),
|
|
50
|
+
__metadata("design:type", String)
|
|
51
|
+
], PaginationQueryDto.prototype, "sortOrder", void 0);
|
package/dist/common/index.d.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
export * from './constants';
|
|
2
|
+
export * from './cards';
|
|
3
|
+
export * from './crypto';
|
|
2
4
|
export * from './enums';
|
|
5
|
+
export * from './dto';
|
|
6
|
+
export * from './interfaces';
|
|
7
|
+
export * from './pipes';
|
|
8
|
+
export * from './response';
|
|
3
9
|
export * from './utils';
|
|
4
10
|
export * from './config';
|
package/dist/common/index.js
CHANGED
|
@@ -15,6 +15,12 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./constants"), exports);
|
|
18
|
+
__exportStar(require("./cards"), exports);
|
|
19
|
+
__exportStar(require("./crypto"), exports);
|
|
18
20
|
__exportStar(require("./enums"), exports);
|
|
21
|
+
__exportStar(require("./dto"), exports);
|
|
22
|
+
__exportStar(require("./interfaces"), exports);
|
|
23
|
+
__exportStar(require("./pipes"), exports);
|
|
24
|
+
__exportStar(require("./response"), exports);
|
|
19
25
|
__exportStar(require("./utils"), exports);
|
|
20
26
|
__exportStar(require("./config"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './response.interface';
|
|
@@ -0,0 +1,17 @@
|
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./response.interface"), exports);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface PaginationMeta {
|
|
2
|
+
page: number;
|
|
3
|
+
limit: number;
|
|
4
|
+
totalItems: number;
|
|
5
|
+
totalPages: number;
|
|
6
|
+
hasNextPage: boolean;
|
|
7
|
+
hasPreviousPage: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface ResponseMeta {
|
|
10
|
+
requestId?: string;
|
|
11
|
+
path?: string;
|
|
12
|
+
timestamp?: string;
|
|
13
|
+
pagination?: PaginationMeta;
|
|
14
|
+
[key: string]: unknown;
|
|
15
|
+
}
|
|
16
|
+
export interface ErrorDetail {
|
|
17
|
+
field?: string;
|
|
18
|
+
message: string;
|
|
19
|
+
code?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface ApiResponse<T = unknown> {
|
|
22
|
+
success: boolean;
|
|
23
|
+
message: string;
|
|
24
|
+
data: T;
|
|
25
|
+
meta?: ResponseMeta;
|
|
26
|
+
errors?: ErrorDetail[];
|
|
27
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { PipeTransform } from '@nestjs/common';
|
|
2
|
+
export interface FileValidationOptions {
|
|
3
|
+
allowedMimeTypes?: string[];
|
|
4
|
+
maxSizeBytes?: number;
|
|
5
|
+
requiredFields?: string[];
|
|
6
|
+
}
|
|
7
|
+
type UploadedFile = {
|
|
8
|
+
mimetype?: string;
|
|
9
|
+
size?: number;
|
|
10
|
+
fieldname?: string;
|
|
11
|
+
originalname?: string;
|
|
12
|
+
};
|
|
13
|
+
type UploadedFilesValue = UploadedFile[] | Record<string, UploadedFile[] | undefined> | undefined | null;
|
|
14
|
+
export declare class FileValidationPipe implements PipeTransform {
|
|
15
|
+
private readonly options;
|
|
16
|
+
constructor(options?: FileValidationOptions);
|
|
17
|
+
transform(value: UploadedFilesValue): UploadedFilesValue;
|
|
18
|
+
private validateRequiredFields;
|
|
19
|
+
private normalizeFiles;
|
|
20
|
+
private formatFileSize;
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.FileValidationPipe = void 0;
|
|
13
|
+
const common_1 = require("@nestjs/common");
|
|
14
|
+
const DEFAULT_ALLOWED_MIME_TYPES = ['image/jpeg', 'image/jpg', 'image/png'];
|
|
15
|
+
const DEFAULT_MAX_SIZE_BYTES = 5 * 1024 * 1024;
|
|
16
|
+
let FileValidationPipe = class FileValidationPipe {
|
|
17
|
+
options;
|
|
18
|
+
constructor(options = {}) {
|
|
19
|
+
this.options = options;
|
|
20
|
+
}
|
|
21
|
+
transform(value) {
|
|
22
|
+
const files = this.normalizeFiles(value);
|
|
23
|
+
if (files.length === 0) {
|
|
24
|
+
throw new common_1.BadRequestException('No files uploaded');
|
|
25
|
+
}
|
|
26
|
+
this.validateRequiredFields(value);
|
|
27
|
+
const allowedMimeTypes = this.options.allowedMimeTypes ?? DEFAULT_ALLOWED_MIME_TYPES;
|
|
28
|
+
const maxSizeBytes = this.options.maxSizeBytes ?? DEFAULT_MAX_SIZE_BYTES;
|
|
29
|
+
for (const file of files) {
|
|
30
|
+
const label = file.fieldname || file.originalname || 'file';
|
|
31
|
+
if (file.mimetype && !allowedMimeTypes.includes(file.mimetype)) {
|
|
32
|
+
throw new common_1.BadRequestException(`${label} must be one of: ${allowedMimeTypes.join(', ')}`);
|
|
33
|
+
}
|
|
34
|
+
if (typeof file.size === 'number' && file.size > maxSizeBytes) {
|
|
35
|
+
throw new common_1.BadRequestException(`${label} size must not exceed ${this.formatFileSize(maxSizeBytes)}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
validateRequiredFields(value) {
|
|
41
|
+
const requiredFields = this.options.requiredFields ?? [];
|
|
42
|
+
if (requiredFields.length === 0 ||
|
|
43
|
+
!value ||
|
|
44
|
+
Array.isArray(value) ||
|
|
45
|
+
typeof value !== 'object') {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
for (const field of requiredFields) {
|
|
49
|
+
const files = value[field];
|
|
50
|
+
if (!files || files.length === 0) {
|
|
51
|
+
throw new common_1.BadRequestException(`${field} file is required`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
normalizeFiles(value) {
|
|
56
|
+
if (!value) {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
if (Array.isArray(value)) {
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
return Object.values(value).flatMap((files) => files ?? []);
|
|
63
|
+
}
|
|
64
|
+
formatFileSize(bytes) {
|
|
65
|
+
if (bytes < 1024) {
|
|
66
|
+
return `${bytes} Bytes`;
|
|
67
|
+
}
|
|
68
|
+
if (bytes < 1024 * 1024) {
|
|
69
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
70
|
+
}
|
|
71
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
exports.FileValidationPipe = FileValidationPipe;
|
|
75
|
+
exports.FileValidationPipe = FileValidationPipe = __decorate([
|
|
76
|
+
(0, common_1.Injectable)(),
|
|
77
|
+
__metadata("design:paramtypes", [Object])
|
|
78
|
+
], FileValidationPipe);
|
|
@@ -0,0 +1,18 @@
|
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./file-validation.pipe"), exports);
|
|
18
|
+
__exportStar(require("./pagination-query-cleaner.pipe"), exports);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.PaginationQueryCleanerPipe = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
let PaginationQueryCleanerPipe = class PaginationQueryCleanerPipe {
|
|
12
|
+
transform(value, _metadata) {
|
|
13
|
+
if (!value || typeof value !== 'object') {
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
delete value.page;
|
|
17
|
+
delete value.limit;
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
exports.PaginationQueryCleanerPipe = PaginationQueryCleanerPipe;
|
|
22
|
+
exports.PaginationQueryCleanerPipe = PaginationQueryCleanerPipe = __decorate([
|
|
23
|
+
(0, common_1.Injectable)()
|
|
24
|
+
], PaginationQueryCleanerPipe);
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var HttpExceptionFilter_1;
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.HttpExceptionFilter = void 0;
|
|
11
|
+
const common_1 = require("@nestjs/common");
|
|
12
|
+
const response_utils_1 = require("./response.utils");
|
|
13
|
+
let HttpExceptionFilter = HttpExceptionFilter_1 = class HttpExceptionFilter {
|
|
14
|
+
logger = new common_1.Logger(HttpExceptionFilter_1.name);
|
|
15
|
+
catch(exception, host) {
|
|
16
|
+
const ctx = host.switchToHttp();
|
|
17
|
+
const response = ctx.getResponse();
|
|
18
|
+
const request = ctx.getRequest();
|
|
19
|
+
const status = exception instanceof common_1.HttpException
|
|
20
|
+
? exception.getStatus()
|
|
21
|
+
: common_1.HttpStatus.INTERNAL_SERVER_ERROR;
|
|
22
|
+
const message = exception instanceof common_1.HttpException
|
|
23
|
+
? exception.message
|
|
24
|
+
: 'An unexpected error occurred';
|
|
25
|
+
const errors = this.getValidationErrors(exception);
|
|
26
|
+
this.logger.error({
|
|
27
|
+
method: request.method,
|
|
28
|
+
url: request.url,
|
|
29
|
+
statusCode: status,
|
|
30
|
+
error: message,
|
|
31
|
+
stack: exception instanceof Error ? exception.stack : undefined,
|
|
32
|
+
}, 'HTTP request failed');
|
|
33
|
+
const body = response_utils_1.AppResponse.error(message, errors, {
|
|
34
|
+
path: request.url ? `${request.method ?? 'GET'} ${request.url}` : undefined,
|
|
35
|
+
requestId: request.requestId ?? request.id,
|
|
36
|
+
timestamp: new Date().toISOString(),
|
|
37
|
+
});
|
|
38
|
+
response.status(status).send(body);
|
|
39
|
+
}
|
|
40
|
+
getValidationErrors(exception) {
|
|
41
|
+
if (!(exception instanceof common_1.BadRequestException)) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
const payload = exception.getResponse();
|
|
45
|
+
if (typeof payload === 'object' && payload !== null) {
|
|
46
|
+
const errors = payload.errors;
|
|
47
|
+
if (Array.isArray(errors)) {
|
|
48
|
+
return errors;
|
|
49
|
+
}
|
|
50
|
+
const message = payload.message;
|
|
51
|
+
if (Array.isArray(message)) {
|
|
52
|
+
return message.map((item) => ({ message: String(item) }));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
exports.HttpExceptionFilter = HttpExceptionFilter;
|
|
59
|
+
exports.HttpExceptionFilter = HttpExceptionFilter = HttpExceptionFilter_1 = __decorate([
|
|
60
|
+
(0, common_1.Catch)()
|
|
61
|
+
], HttpExceptionFilter);
|
|
@@ -0,0 +1,19 @@
|
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./http-exception.filter"), exports);
|
|
18
|
+
__exportStar(require("./response.interceptor"), exports);
|
|
19
|
+
__exportStar(require("./response.utils"), exports);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import type { ApiResponse } from '../interfaces';
|
|
4
|
+
export declare class ResponseInterceptor<T> implements NestInterceptor<T, ApiResponse<T>> {
|
|
5
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<ApiResponse<T>>;
|
|
6
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.ResponseInterceptor = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
const operators_1 = require("rxjs/operators");
|
|
12
|
+
const response_utils_1 = require("./response.utils");
|
|
13
|
+
function isApiResponse(value) {
|
|
14
|
+
return (typeof value === 'object' &&
|
|
15
|
+
value !== null &&
|
|
16
|
+
'success' in value &&
|
|
17
|
+
'message' in value &&
|
|
18
|
+
'data' in value);
|
|
19
|
+
}
|
|
20
|
+
function isPaginatedPayload(value) {
|
|
21
|
+
return (typeof value === 'object' &&
|
|
22
|
+
value !== null &&
|
|
23
|
+
'items' in value &&
|
|
24
|
+
Array.isArray(value.items) &&
|
|
25
|
+
'pagination' in value);
|
|
26
|
+
}
|
|
27
|
+
let ResponseInterceptor = class ResponseInterceptor {
|
|
28
|
+
intercept(context, next) {
|
|
29
|
+
if (context.getType() !== 'http') {
|
|
30
|
+
return next.handle();
|
|
31
|
+
}
|
|
32
|
+
const request = context.switchToHttp().getRequest();
|
|
33
|
+
return next.handle().pipe((0, operators_1.map)((data) => {
|
|
34
|
+
if (isApiResponse(data)) {
|
|
35
|
+
return data;
|
|
36
|
+
}
|
|
37
|
+
const meta = {
|
|
38
|
+
path: request.url
|
|
39
|
+
? `${request.method ?? 'GET'} ${request.url}`
|
|
40
|
+
: undefined,
|
|
41
|
+
requestId: request.requestId ?? request.id,
|
|
42
|
+
timestamp: new Date().toISOString(),
|
|
43
|
+
};
|
|
44
|
+
if (isPaginatedPayload(data)) {
|
|
45
|
+
return response_utils_1.AppResponse.paginated(data.message ?? 'Request successful', data.items, data.pagination, {
|
|
46
|
+
...meta,
|
|
47
|
+
...data.meta,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return response_utils_1.AppResponse.success('Request successful', data, meta);
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
exports.ResponseInterceptor = ResponseInterceptor;
|
|
55
|
+
exports.ResponseInterceptor = ResponseInterceptor = __decorate([
|
|
56
|
+
(0, common_1.Injectable)()
|
|
57
|
+
], ResponseInterceptor);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ApiResponse, ErrorDetail, PaginationMeta, ResponseMeta } from '../interfaces';
|
|
2
|
+
export declare class AppResponse {
|
|
3
|
+
static success<T>(message: string, data: T, meta?: ResponseMeta): ApiResponse<T>;
|
|
4
|
+
static paginated<T>(message: string, items: T[], pagination: PaginationMeta, meta?: Omit<ResponseMeta, 'pagination'>): ApiResponse<T[]>;
|
|
5
|
+
static error(message: string, errors?: ErrorDetail[], meta?: ResponseMeta, data?: null): ApiResponse<null>;
|
|
6
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AppResponse = void 0;
|
|
4
|
+
class AppResponse {
|
|
5
|
+
static success(message, data, meta) {
|
|
6
|
+
return {
|
|
7
|
+
success: true,
|
|
8
|
+
message,
|
|
9
|
+
data,
|
|
10
|
+
...(meta ? { meta } : {}),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
static paginated(message, items, pagination, meta) {
|
|
14
|
+
return {
|
|
15
|
+
success: true,
|
|
16
|
+
message,
|
|
17
|
+
data: items,
|
|
18
|
+
meta: {
|
|
19
|
+
...meta,
|
|
20
|
+
pagination,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
static error(message, errors, meta, data = null) {
|
|
25
|
+
return {
|
|
26
|
+
success: false,
|
|
27
|
+
message,
|
|
28
|
+
data,
|
|
29
|
+
...(meta ? { meta } : {}),
|
|
30
|
+
...(errors?.length ? { errors } : {}),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.AppResponse = AppResponse;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const countryDialCodes: string[];
|
|
@@ -0,0 +1,38 @@
|
|
|
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.countryDialCodes = void 0;
|
|
37
|
+
const CountryCodeList = __importStar(require("country-codes-list"));
|
|
38
|
+
exports.countryDialCodes = Object.keys(CountryCodeList.customList('countryCallingCode')).map((code) => `+${code}`);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type RecurrenceFrequency = 'DAILY' | 'WEEKLY' | 'MONTHLY';
|
|
2
|
+
export declare const calculateNextDate: (frequency: RecurrenceFrequency, lastDate: Date) => Date;
|
|
3
|
+
export declare const isToday: (date: Date | string) => boolean;
|
|
4
|
+
export declare const isNotPastDate: (date: Date | string) => boolean;
|
|
5
|
+
export declare const isDateInRange: (date: Date | string, minDate: Date | string, maxDate: Date | string) => boolean;
|
|
6
|
+
export declare const isValidAge: (dateOfBirth: Date | string, minAge?: number) => boolean;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isValidAge = exports.isDateInRange = exports.isNotPastDate = exports.isToday = exports.calculateNextDate = void 0;
|
|
4
|
+
const calculateNextDate = (frequency, lastDate) => {
|
|
5
|
+
const nextDate = new Date(lastDate);
|
|
6
|
+
switch (frequency) {
|
|
7
|
+
case 'DAILY':
|
|
8
|
+
nextDate.setDate(nextDate.getDate() + 1);
|
|
9
|
+
return nextDate;
|
|
10
|
+
case 'WEEKLY':
|
|
11
|
+
nextDate.setDate(nextDate.getDate() + 7);
|
|
12
|
+
return nextDate;
|
|
13
|
+
case 'MONTHLY':
|
|
14
|
+
nextDate.setMonth(nextDate.getMonth() + 1);
|
|
15
|
+
return nextDate;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
exports.calculateNextDate = calculateNextDate;
|
|
19
|
+
const isToday = (date) => {
|
|
20
|
+
const currentDate = new Date(date);
|
|
21
|
+
const today = new Date();
|
|
22
|
+
return (currentDate.getDate() === today.getDate() &&
|
|
23
|
+
currentDate.getMonth() === today.getMonth() &&
|
|
24
|
+
currentDate.getFullYear() === today.getFullYear());
|
|
25
|
+
};
|
|
26
|
+
exports.isToday = isToday;
|
|
27
|
+
const isNotPastDate = (date) => {
|
|
28
|
+
return new Date(date).getTime() >= Date.now();
|
|
29
|
+
};
|
|
30
|
+
exports.isNotPastDate = isNotPastDate;
|
|
31
|
+
const isDateInRange = (date, minDate, maxDate) => {
|
|
32
|
+
const timestamp = new Date(date).getTime();
|
|
33
|
+
return (timestamp >= new Date(minDate).getTime() &&
|
|
34
|
+
timestamp <= new Date(maxDate).getTime());
|
|
35
|
+
};
|
|
36
|
+
exports.isDateInRange = isDateInRange;
|
|
37
|
+
const isValidAge = (dateOfBirth, minAge = 18) => {
|
|
38
|
+
const today = new Date();
|
|
39
|
+
const birthDate = new Date(dateOfBirth);
|
|
40
|
+
let age = today.getFullYear() - birthDate.getFullYear();
|
|
41
|
+
const monthDiff = today.getMonth() - birthDate.getMonth();
|
|
42
|
+
if (monthDiff < 0 ||
|
|
43
|
+
(monthDiff === 0 && today.getDate() < birthDate.getDate())) {
|
|
44
|
+
age--;
|
|
45
|
+
}
|
|
46
|
+
return age >= minAge;
|
|
47
|
+
};
|
|
48
|
+
exports.isValidAge = isValidAge;
|
|
@@ -0,0 +1,22 @@
|
|
|
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.toRoundedNumber = 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
|
+
const toDecimal = (value) => {
|
|
11
|
+
try {
|
|
12
|
+
return new decimal_js_1.default(value);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
throw new Error(`Invalid decimal value: ${value}`);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
exports.toDecimal = toDecimal;
|
|
19
|
+
const toRoundedNumber = (value, decimalPlaces = DEFAULT_DECIMAL_PLACES) => {
|
|
20
|
+
return (0, exports.toDecimal)(value).toDecimalPlaces(decimalPlaces).toNumber();
|
|
21
|
+
};
|
|
22
|
+
exports.toRoundedNumber = toRoundedNumber;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const formatCurrency: (amount: number, currencySymbol?: string, decimals?: number) => string;
|
|
2
|
+
export declare const formatAmount: (amount: number, decimals?: number, locale?: string) => string;
|
|
3
|
+
export declare const formatAccountNumber: (accountNumber: string) => string;
|
|
4
|
+
export declare const maskAccountNumber: (accountNumber: string) => string;
|
|
5
|
+
export declare const maskEmail: (email: string) => string;
|
|
6
|
+
export declare const formatDate: (date: Date | string) => string;
|
|
7
|
+
export declare const formatDateTime: (date: Date | string) => string;
|
|
8
|
+
export declare const formatRelativeTime: (date: Date | string) => string;
|
|
9
|
+
export declare const formatPercentage: (value: number, decimals?: number) => string;
|
|
10
|
+
export declare const formatFileSize: (bytes: number) => string;
|
|
11
|
+
export declare const truncateText: (text: string, maxLength: number) => string;
|
|
12
|
+
export declare const toTitleCase: (text: string) => string;
|
|
13
|
+
export declare const normalizeNigerianPhone: (phone: string | number, withPlus?: boolean) => string;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeNigerianPhone = 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
|
+
const formatCurrency = (amount, currencySymbol = '₦', decimals = 2) => {
|
|
5
|
+
const formatted = amount.toLocaleString('en-NG', {
|
|
6
|
+
minimumFractionDigits: decimals,
|
|
7
|
+
maximumFractionDigits: decimals,
|
|
8
|
+
});
|
|
9
|
+
return `${currencySymbol}${formatted}`;
|
|
10
|
+
};
|
|
11
|
+
exports.formatCurrency = formatCurrency;
|
|
12
|
+
const formatAmount = (amount, decimals = 2, locale = 'en-NG') => {
|
|
13
|
+
return amount.toLocaleString(locale, {
|
|
14
|
+
minimumFractionDigits: decimals,
|
|
15
|
+
maximumFractionDigits: decimals,
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
exports.formatAmount = formatAmount;
|
|
19
|
+
const formatAccountNumber = (accountNumber) => {
|
|
20
|
+
if (accountNumber.length !== 10) {
|
|
21
|
+
return accountNumber;
|
|
22
|
+
}
|
|
23
|
+
return `${accountNumber.slice(0, 4)} ${accountNumber.slice(4, 8)} ${accountNumber.slice(8)}`;
|
|
24
|
+
};
|
|
25
|
+
exports.formatAccountNumber = formatAccountNumber;
|
|
26
|
+
const maskAccountNumber = (accountNumber) => {
|
|
27
|
+
if (accountNumber.length < 4) {
|
|
28
|
+
return accountNumber;
|
|
29
|
+
}
|
|
30
|
+
return '*'.repeat(accountNumber.length - 4) + accountNumber.slice(-4);
|
|
31
|
+
};
|
|
32
|
+
exports.maskAccountNumber = maskAccountNumber;
|
|
33
|
+
const maskEmail = (email) => {
|
|
34
|
+
const [username, domain] = email.split('@');
|
|
35
|
+
if (!username || !domain) {
|
|
36
|
+
return email;
|
|
37
|
+
}
|
|
38
|
+
return `${username[0]}${'*'.repeat(Math.max(0, username.length - 1))}@${domain}`;
|
|
39
|
+
};
|
|
40
|
+
exports.maskEmail = maskEmail;
|
|
41
|
+
const formatDate = (date) => {
|
|
42
|
+
const currentDate = new Date(date);
|
|
43
|
+
const day = String(currentDate.getDate()).padStart(2, '0');
|
|
44
|
+
const month = String(currentDate.getMonth() + 1).padStart(2, '0');
|
|
45
|
+
const year = currentDate.getFullYear();
|
|
46
|
+
return `${day}/${month}/${year}`;
|
|
47
|
+
};
|
|
48
|
+
exports.formatDate = formatDate;
|
|
49
|
+
const formatDateTime = (date) => {
|
|
50
|
+
const currentDate = new Date(date);
|
|
51
|
+
const hours = String(currentDate.getHours()).padStart(2, '0');
|
|
52
|
+
const minutes = String(currentDate.getMinutes()).padStart(2, '0');
|
|
53
|
+
return `${(0, exports.formatDate)(currentDate)} ${hours}:${minutes}`;
|
|
54
|
+
};
|
|
55
|
+
exports.formatDateTime = formatDateTime;
|
|
56
|
+
const formatRelativeTime = (date) => {
|
|
57
|
+
const currentDate = new Date(date);
|
|
58
|
+
const diffMs = Date.now() - currentDate.getTime();
|
|
59
|
+
const diffSeconds = Math.floor(diffMs / 1000);
|
|
60
|
+
const diffMinutes = Math.floor(diffSeconds / 60);
|
|
61
|
+
const diffHours = Math.floor(diffMinutes / 60);
|
|
62
|
+
const diffDays = Math.floor(diffHours / 24);
|
|
63
|
+
if (diffSeconds < 60) {
|
|
64
|
+
return 'Just now';
|
|
65
|
+
}
|
|
66
|
+
if (diffMinutes < 60) {
|
|
67
|
+
return `${diffMinutes} minute${diffMinutes > 1 ? 's' : ''} ago`;
|
|
68
|
+
}
|
|
69
|
+
if (diffHours < 24) {
|
|
70
|
+
return `${diffHours} hour${diffHours > 1 ? 's' : ''} ago`;
|
|
71
|
+
}
|
|
72
|
+
if (diffDays < 7) {
|
|
73
|
+
return `${diffDays} day${diffDays > 1 ? 's' : ''} ago`;
|
|
74
|
+
}
|
|
75
|
+
return (0, exports.formatDate)(currentDate);
|
|
76
|
+
};
|
|
77
|
+
exports.formatRelativeTime = formatRelativeTime;
|
|
78
|
+
const formatPercentage = (value, decimals = 1) => {
|
|
79
|
+
return `${(value * 100).toFixed(decimals)}%`;
|
|
80
|
+
};
|
|
81
|
+
exports.formatPercentage = formatPercentage;
|
|
82
|
+
const formatFileSize = (bytes) => {
|
|
83
|
+
if (bytes === 0) {
|
|
84
|
+
return '0 Bytes';
|
|
85
|
+
}
|
|
86
|
+
const unit = 1024;
|
|
87
|
+
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
|
88
|
+
const sizeIndex = Math.floor(Math.log(bytes) / Math.log(unit));
|
|
89
|
+
return `${Number((bytes / unit ** sizeIndex).toFixed(2))} ${sizes[sizeIndex]}`;
|
|
90
|
+
};
|
|
91
|
+
exports.formatFileSize = formatFileSize;
|
|
92
|
+
const truncateText = (text, maxLength) => {
|
|
93
|
+
if (text.length <= maxLength) {
|
|
94
|
+
return text;
|
|
95
|
+
}
|
|
96
|
+
return `${text.slice(0, maxLength - 3)}...`;
|
|
97
|
+
};
|
|
98
|
+
exports.truncateText = truncateText;
|
|
99
|
+
const toTitleCase = (text) => {
|
|
100
|
+
return text
|
|
101
|
+
.toLowerCase()
|
|
102
|
+
.split(' ')
|
|
103
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
104
|
+
.join(' ');
|
|
105
|
+
};
|
|
106
|
+
exports.toTitleCase = toTitleCase;
|
|
107
|
+
const normalizeNigerianPhone = (phone, withPlus = false) => {
|
|
108
|
+
const digits = `${phone}`.replace(/\D/g, '').trim();
|
|
109
|
+
if (digits === '') {
|
|
110
|
+
return '';
|
|
111
|
+
}
|
|
112
|
+
let normalized = digits;
|
|
113
|
+
if (digits.startsWith('234') && digits.length === 13) {
|
|
114
|
+
normalized = digits;
|
|
115
|
+
}
|
|
116
|
+
else if (digits.startsWith('0') && digits.length === 11) {
|
|
117
|
+
normalized = `234${digits.slice(1)}`;
|
|
118
|
+
}
|
|
119
|
+
else if (digits.length === 10 && /^[789]/.test(digits)) {
|
|
120
|
+
normalized = `234${digits}`;
|
|
121
|
+
}
|
|
122
|
+
else if (!digits.startsWith('234') && digits.length === 10) {
|
|
123
|
+
normalized = `234${digits}`;
|
|
124
|
+
}
|
|
125
|
+
return withPlus ? `+${normalized}` : normalized;
|
|
126
|
+
};
|
|
127
|
+
exports.normalizeNigerianPhone = normalizeNigerianPhone;
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
export * from './country.utils';
|
|
2
|
+
export * from './date.utils';
|
|
3
|
+
export * from './decimal.utils';
|
|
4
|
+
export * from './format.utils';
|
|
1
5
|
export * from './string.utils';
|
|
2
6
|
export * from './random.utils';
|
|
3
7
|
export * from './reference.utils';
|
|
8
|
+
export * from './validation.utils';
|
|
@@ -14,6 +14,11 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./country.utils"), exports);
|
|
18
|
+
__exportStar(require("./date.utils"), exports);
|
|
19
|
+
__exportStar(require("./decimal.utils"), exports);
|
|
20
|
+
__exportStar(require("./format.utils"), exports);
|
|
17
21
|
__exportStar(require("./string.utils"), exports);
|
|
18
22
|
__exportStar(require("./random.utils"), exports);
|
|
19
23
|
__exportStar(require("./reference.utils"), exports);
|
|
24
|
+
__exportStar(require("./validation.utils"), exports);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const isValidNigerianPhone: (phone: string) => boolean;
|
|
2
|
+
export declare const isValidEmail: (email: string) => boolean;
|
|
3
|
+
export declare const isValidBVN: (bvn: string) => boolean;
|
|
4
|
+
export declare const isValidNIN: (nin: string) => boolean;
|
|
5
|
+
export declare const isValidAccountNumber: (accountNumber: string) => boolean;
|
|
6
|
+
export declare const isValidAmount: (amount: number) => boolean;
|
|
7
|
+
export declare const isStrongPassword: (password: string) => boolean;
|
|
8
|
+
export declare const isValidTransactionReference: (reference: string) => boolean;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isValidTransactionReference = exports.isStrongPassword = exports.isValidAmount = exports.isValidAccountNumber = exports.isValidNIN = exports.isValidBVN = exports.isValidEmail = exports.isValidNigerianPhone = void 0;
|
|
4
|
+
const isValidNigerianPhone = (phone) => {
|
|
5
|
+
const cleaned = phone.replace(/[\s\-()]/g, '');
|
|
6
|
+
const patterns = [
|
|
7
|
+
/^0[7-9][0-1]\d{8}$/,
|
|
8
|
+
/^\+234[7-9][0-1]\d{8}$/,
|
|
9
|
+
/^234[7-9][0-1]\d{8}$/,
|
|
10
|
+
];
|
|
11
|
+
return patterns.some((pattern) => pattern.test(cleaned));
|
|
12
|
+
};
|
|
13
|
+
exports.isValidNigerianPhone = isValidNigerianPhone;
|
|
14
|
+
const isValidEmail = (email) => {
|
|
15
|
+
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
|
16
|
+
};
|
|
17
|
+
exports.isValidEmail = isValidEmail;
|
|
18
|
+
const isValidBVN = (bvn) => {
|
|
19
|
+
return /^\d{11}$/.test(bvn);
|
|
20
|
+
};
|
|
21
|
+
exports.isValidBVN = isValidBVN;
|
|
22
|
+
const isValidNIN = (nin) => {
|
|
23
|
+
return /^\d{11}$/.test(nin);
|
|
24
|
+
};
|
|
25
|
+
exports.isValidNIN = isValidNIN;
|
|
26
|
+
const isValidAccountNumber = (accountNumber) => {
|
|
27
|
+
return /^\d{10}$/.test(accountNumber);
|
|
28
|
+
};
|
|
29
|
+
exports.isValidAccountNumber = isValidAccountNumber;
|
|
30
|
+
const isValidAmount = (amount) => {
|
|
31
|
+
return typeof amount === 'number' && Number.isFinite(amount) && amount > 0;
|
|
32
|
+
};
|
|
33
|
+
exports.isValidAmount = isValidAmount;
|
|
34
|
+
const isStrongPassword = (password) => {
|
|
35
|
+
return (password.length >= 8 &&
|
|
36
|
+
/[A-Z]/.test(password) &&
|
|
37
|
+
/[a-z]/.test(password) &&
|
|
38
|
+
/\d/.test(password));
|
|
39
|
+
};
|
|
40
|
+
exports.isStrongPassword = isStrongPassword;
|
|
41
|
+
const isValidTransactionReference = (reference) => {
|
|
42
|
+
return /^[A-Z0-9_-]{10,50}$/.test(reference);
|
|
43
|
+
};
|
|
44
|
+
exports.isValidTransactionReference = isValidTransactionReference;
|
|
@@ -67,6 +67,6 @@ exports.LoggerModule = LoggerModule = __decorate([
|
|
|
67
67
|
useExisting: nestjs_pino_1.PinoLogger,
|
|
68
68
|
},
|
|
69
69
|
],
|
|
70
|
-
exports: [nestjs_pino_1.LoggerModule, logging_interceptor_1.LoggingInterceptor, common_1.Logger
|
|
70
|
+
exports: [nestjs_pino_1.LoggerModule, logging_interceptor_1.LoggingInterceptor, common_1.Logger],
|
|
71
71
|
})
|
|
72
72
|
], LoggerModule);
|