@flusys/nestjs-shared 4.1.0 → 5.0.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 +96 -606
- package/cjs/classes/api-controller.class.js +81 -10
- package/cjs/classes/api-service.class.js +9 -7
- package/cjs/classes/index.js +0 -1
- package/cjs/constants/index.js +0 -4
- package/cjs/constants/message-keys.js +3 -21
- package/cjs/constants/permissions.js +0 -10
- package/cjs/decorators/api-response.decorator.js +1 -2
- package/cjs/decorators/index.js +0 -1
- package/cjs/decorators/require-permission.decorator.js +0 -4
- package/cjs/exceptions/base-app.exception.js +4 -4
- package/cjs/exceptions/permission.exception.js +1 -1
- package/cjs/filters/global-exception.filter.js +4 -4
- package/cjs/interfaces/index.js +0 -1
- package/cjs/modules/datasource/multi-tenant-datasource.service.js +2 -2
- package/cjs/utils/date-time.util.js +94 -0
- package/cjs/utils/index.js +1 -0
- package/cjs/utils/query-helpers.util.js +2 -2
- package/cjs/utils/request.util.js +25 -0
- package/classes/index.d.ts +0 -1
- package/constants/index.d.ts +0 -1
- package/constants/message-keys.d.ts +2 -44
- package/constants/permissions.d.ts +0 -12
- package/decorators/api-response.decorator.d.ts +1 -1
- package/decorators/index.d.ts +0 -1
- package/decorators/require-permission.decorator.d.ts +0 -1
- package/exceptions/base-app.exception.d.ts +2 -2
- package/fesm/classes/api-controller.class.js +82 -11
- package/fesm/classes/api-service.class.js +10 -8
- package/fesm/classes/index.js +0 -1
- package/fesm/constants/index.js +0 -1
- package/fesm/constants/message-keys.js +3 -19
- package/fesm/constants/permissions.js +0 -7
- package/fesm/decorators/api-response.decorator.js +2 -20
- package/fesm/decorators/index.js +0 -1
- package/fesm/decorators/require-permission.decorator.js +0 -1
- package/fesm/exceptions/base-app.exception.js +4 -4
- package/fesm/exceptions/permission.exception.js +1 -1
- package/fesm/filters/global-exception.filter.js +4 -4
- package/fesm/interfaces/index.js +0 -1
- package/fesm/modules/datasource/multi-tenant-datasource.service.js +2 -2
- package/fesm/utils/date-time.util.js +70 -0
- package/fesm/utils/index.js +1 -0
- package/fesm/utils/query-helpers.util.js +2 -2
- package/fesm/utils/request.util.js +22 -0
- package/interfaces/event-manager-adapter.interface.d.ts +12 -12
- package/interfaces/index.d.ts +0 -1
- package/package.json +2 -2
- package/utils/date-time.util.d.ts +8 -0
- package/utils/index.d.ts +1 -0
- package/utils/request.util.d.ts +2 -0
- package/cjs/classes/winston-logger-adapter.class.js +0 -99
- package/cjs/decorators/sanitize-html.decorator.js +0 -36
- package/cjs/interfaces/logger.interface.js +0 -4
- package/classes/winston-logger-adapter.class.d.ts +0 -23
- package/decorators/sanitize-html.decorator.d.ts +0 -2
- package/fesm/classes/winston-logger-adapter.class.js +0 -81
- package/fesm/decorators/sanitize-html.decorator.js +0 -45
- package/fesm/interfaces/logger.interface.js +0 -1
- package/interfaces/logger.interface.d.ts +0 -7
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
function getOffsetMinutes(utcDate, timezone) {
|
|
2
|
+
const extract = (tz)=>{
|
|
3
|
+
const parts = new Intl.DateTimeFormat('en-US', {
|
|
4
|
+
timeZone: tz,
|
|
5
|
+
year: 'numeric',
|
|
6
|
+
month: '2-digit',
|
|
7
|
+
day: '2-digit',
|
|
8
|
+
hour: '2-digit',
|
|
9
|
+
minute: '2-digit',
|
|
10
|
+
second: '2-digit',
|
|
11
|
+
hour12: false
|
|
12
|
+
}).formatToParts(utcDate);
|
|
13
|
+
const p = Object.fromEntries(parts.filter((x)=>x.type !== 'literal').map((x)=>[
|
|
14
|
+
x.type,
|
|
15
|
+
parseInt(x.value)
|
|
16
|
+
]));
|
|
17
|
+
return Date.UTC(p['year'], p['month'] - 1, p['day'], p['hour'], p['minute'], p['second']);
|
|
18
|
+
};
|
|
19
|
+
return (extract(timezone) - extract('UTC')) / 60_000;
|
|
20
|
+
}
|
|
21
|
+
export function localToUtc(dateStr, timeStr, timezone) {
|
|
22
|
+
const [year, month, day] = dateStr.split('-').map(Number);
|
|
23
|
+
const [hours, minutes] = timeStr.split(':').map(Number);
|
|
24
|
+
const approx = new Date(Date.UTC(year, month - 1, day, hours, minutes, 0));
|
|
25
|
+
const offset = getOffsetMinutes(approx, timezone);
|
|
26
|
+
const utcDate = new Date(approx.getTime() - offset * 60_000);
|
|
27
|
+
// DST boundary guard: re-check offset after adjustment
|
|
28
|
+
const finalOffset = getOffsetMinutes(utcDate, timezone);
|
|
29
|
+
return finalOffset !== offset ? new Date(approx.getTime() - finalOffset * 60_000) : utcDate;
|
|
30
|
+
}
|
|
31
|
+
export function utcToLocal(utcDate, timezone) {
|
|
32
|
+
const d = typeof utcDate === 'string' ? new Date(utcDate) : utcDate;
|
|
33
|
+
const parts = new Intl.DateTimeFormat('en-CA', {
|
|
34
|
+
timeZone: timezone,
|
|
35
|
+
year: 'numeric',
|
|
36
|
+
month: '2-digit',
|
|
37
|
+
day: '2-digit',
|
|
38
|
+
hour: '2-digit',
|
|
39
|
+
minute: '2-digit',
|
|
40
|
+
hour12: false
|
|
41
|
+
}).formatToParts(d);
|
|
42
|
+
const p = Object.fromEntries(parts.filter((x)=>x.type !== 'literal').map((x)=>[
|
|
43
|
+
x.type,
|
|
44
|
+
x.value
|
|
45
|
+
]));
|
|
46
|
+
// en-CA formats midnight hour as '24' — normalize to '00'
|
|
47
|
+
const hour = p['hour'] === '24' ? '00' : p['hour'];
|
|
48
|
+
return {
|
|
49
|
+
date: `${p['year']}-${p['month']}-${p['day']}`,
|
|
50
|
+
time: `${hour}:${p['minute']}`,
|
|
51
|
+
display: new Intl.DateTimeFormat('en-US', {
|
|
52
|
+
timeZone: timezone,
|
|
53
|
+
dateStyle: 'medium',
|
|
54
|
+
timeStyle: 'short'
|
|
55
|
+
}).format(d)
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export function formatInTimezone(utcDate, timezone, options = {
|
|
59
|
+
dateStyle: 'medium',
|
|
60
|
+
timeStyle: 'short'
|
|
61
|
+
}) {
|
|
62
|
+
const d = typeof utcDate === 'string' ? new Date(utcDate) : utcDate;
|
|
63
|
+
return new Intl.DateTimeFormat('en-US', {
|
|
64
|
+
...options,
|
|
65
|
+
timeZone: timezone
|
|
66
|
+
}).format(d);
|
|
67
|
+
}
|
|
68
|
+
export function getTodayInTimezone(timezone) {
|
|
69
|
+
return utcToLocal(new Date(), timezone).date;
|
|
70
|
+
}
|
package/fesm/utils/index.js
CHANGED
|
@@ -75,8 +75,8 @@ import { AUTH_MESSAGES } from '../constants';
|
|
|
75
75
|
if (entity.companyId && entity.companyId !== user.companyId) {
|
|
76
76
|
throw new BadRequestException({
|
|
77
77
|
message: `${entityName} belongs to another company`,
|
|
78
|
-
messageKey: AUTH_MESSAGES.
|
|
79
|
-
|
|
78
|
+
messageKey: AUTH_MESSAGES.ENTITY_BELOG_ANOTHER_COMPANY,
|
|
79
|
+
messageVariables: {
|
|
80
80
|
entity: entityName
|
|
81
81
|
}
|
|
82
82
|
});
|
|
@@ -57,3 +57,25 @@ import { CLIENT_TYPE_HEADER } from '../constants';
|
|
|
57
57
|
const unit = match[2];
|
|
58
58
|
return value * (TIME_UNIT_MS[unit] ?? TIME_UNIT_MS.d);
|
|
59
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Determine the frontend base URL for auth-related links.
|
|
62
|
+
* Uses allowed origins from envConfig first, then falls back to request host.
|
|
63
|
+
*/ export function extractFrontendUrl(req) {
|
|
64
|
+
const allowedOrigins = envConfig.getOrigins();
|
|
65
|
+
const origin = (req.get('origin') ?? req.get('referer') ?? '').trim();
|
|
66
|
+
if (origin && allowedOrigins.length) {
|
|
67
|
+
const matched = allowedOrigins.find((u)=>origin.startsWith(u));
|
|
68
|
+
if (matched) {
|
|
69
|
+
return matched;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const host = req.get('host');
|
|
73
|
+
if (!host) {
|
|
74
|
+
throw new Error('Unable to determine frontend URL from request');
|
|
75
|
+
}
|
|
76
|
+
return `${req.protocol}://${host}`;
|
|
77
|
+
}
|
|
78
|
+
export function buildFrontendUrl(req, path) {
|
|
79
|
+
const baseUrl = extractFrontendUrl(req);
|
|
80
|
+
return `${baseUrl}${path}`;
|
|
81
|
+
}
|
|
@@ -2,8 +2,6 @@ import { ParticipantStatus } from '../enums/participant-status.enum';
|
|
|
2
2
|
import { RecurrenceType } from '../enums/recurrence-type.enum';
|
|
3
3
|
export interface IEventManagerAdapter {
|
|
4
4
|
createEvent(options: CreateEventOptions): Promise<EventResult>;
|
|
5
|
-
addParticipants(eventId: string, userIds: string[], companyId?: string): Promise<void>;
|
|
6
|
-
removeParticipant(eventId: string, userId: string): Promise<void>;
|
|
7
5
|
updateParticipantStatus(participantId: string, status: ParticipantStatus): Promise<void>;
|
|
8
6
|
getEventsForUser?(userId: string, startDate: Date, endDate: Date, companyId?: string): Promise<EventResult[]>;
|
|
9
7
|
getEventById?(eventId: string): Promise<EventResult | null>;
|
|
@@ -11,14 +9,15 @@ export interface IEventManagerAdapter {
|
|
|
11
9
|
export interface CreateEventOptions {
|
|
12
10
|
title: string;
|
|
13
11
|
description?: string;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
eventDate: string;
|
|
13
|
+
startTime: string;
|
|
14
|
+
endTime: string;
|
|
17
15
|
isAllDay?: boolean;
|
|
18
16
|
recurrenceType?: RecurrenceType;
|
|
19
|
-
recurrenceEndDate?:
|
|
17
|
+
recurrenceEndDate?: string | null;
|
|
18
|
+
weekDays?: string[] | null;
|
|
20
19
|
color?: string;
|
|
21
|
-
|
|
20
|
+
meetingLink?: string | null;
|
|
22
21
|
participantIds?: string[];
|
|
23
22
|
organizerId?: string;
|
|
24
23
|
companyId?: string;
|
|
@@ -27,15 +26,16 @@ export interface EventResult {
|
|
|
27
26
|
id: string;
|
|
28
27
|
title: string;
|
|
29
28
|
description?: string | null;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
eventDate: string;
|
|
30
|
+
startTime: string;
|
|
31
|
+
endTime: string;
|
|
33
32
|
isAllDay: boolean;
|
|
34
33
|
recurrenceType: string;
|
|
35
|
-
recurrenceEndDate?:
|
|
34
|
+
recurrenceEndDate?: string | null;
|
|
35
|
+
weekDays?: string[] | null;
|
|
36
36
|
color: string;
|
|
37
|
+
meetingLink?: string | null;
|
|
37
38
|
isActive: boolean;
|
|
38
|
-
metadata?: Record<string, unknown> | null;
|
|
39
39
|
companyId?: string | null;
|
|
40
40
|
createdAt: Date;
|
|
41
41
|
updatedAt: Date;
|
package/interfaces/index.d.ts
CHANGED
|
@@ -3,7 +3,6 @@ export * from './datasource.interface';
|
|
|
3
3
|
export * from './event-manager-adapter.interface';
|
|
4
4
|
export * from './identity.interface';
|
|
5
5
|
export * from './logged-user-info.interface';
|
|
6
|
-
export * from './logger.interface';
|
|
7
6
|
export * from './module-config.interface';
|
|
8
7
|
export * from './notification-adapter.interface';
|
|
9
8
|
export * from './permission.interface';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flusys/nestjs-shared",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Common shared utilities for Flusys NestJS applications",
|
|
5
5
|
"main": "cjs/index.js",
|
|
6
6
|
"module": "fesm/index.js",
|
|
@@ -112,6 +112,6 @@
|
|
|
112
112
|
"rxjs": "^7.8.0"
|
|
113
113
|
},
|
|
114
114
|
"dependencies": {
|
|
115
|
-
"@flusys/nestjs-core": "
|
|
115
|
+
"@flusys/nestjs-core": "5.0.0"
|
|
116
116
|
}
|
|
117
117
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function localToUtc(dateStr: string, timeStr: string, timezone: string): Date;
|
|
2
|
+
export declare function utcToLocal(utcDate: Date | string, timezone: string): {
|
|
3
|
+
date: string;
|
|
4
|
+
time: string;
|
|
5
|
+
display: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function formatInTimezone(utcDate: Date | string, timezone: string, options?: Intl.DateTimeFormatOptions): string;
|
|
8
|
+
export declare function getTodayInTimezone(timezone: string): string;
|
package/utils/index.d.ts
CHANGED
package/utils/request.util.d.ts
CHANGED
|
@@ -2,3 +2,5 @@ import { CookieOptions, Request } from 'express';
|
|
|
2
2
|
export declare function isBrowserRequest(req: Request): boolean;
|
|
3
3
|
export declare function buildCookieOptions(req: Request): Pick<CookieOptions, 'secure' | 'sameSite' | 'domain'>;
|
|
4
4
|
export declare function parseDurationToMs(duration: string, defaultMs?: number): number;
|
|
5
|
+
export declare function extractFrontendUrl(req: Request): string;
|
|
6
|
+
export declare function buildFrontendUrl(req: Request, path: string): string;
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
function _export(target, all) {
|
|
6
|
-
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
-
enumerable: true,
|
|
8
|
-
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
_export(exports, {
|
|
12
|
-
get NestLoggerAdapter () {
|
|
13
|
-
return NestLoggerAdapter;
|
|
14
|
-
},
|
|
15
|
-
get WinstonLoggerAdapter () {
|
|
16
|
-
return WinstonLoggerAdapter;
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
const _winstonloggerclass = require("./winston.logger.class");
|
|
20
|
-
const _loggermiddleware = require("../middlewares/logger.middleware");
|
|
21
|
-
function _define_property(obj, key, value) {
|
|
22
|
-
if (key in obj) {
|
|
23
|
-
Object.defineProperty(obj, key, {
|
|
24
|
-
value: value,
|
|
25
|
-
enumerable: true,
|
|
26
|
-
configurable: true,
|
|
27
|
-
writable: true
|
|
28
|
-
});
|
|
29
|
-
} else {
|
|
30
|
-
obj[key] = value;
|
|
31
|
-
}
|
|
32
|
-
return obj;
|
|
33
|
-
}
|
|
34
|
-
function getCorrelationMeta() {
|
|
35
|
-
return Object.fromEntries(Object.entries({
|
|
36
|
-
requestId: (0, _loggermiddleware.getRequestId)(),
|
|
37
|
-
userId: (0, _loggermiddleware.getUserId)(),
|
|
38
|
-
tenantId: (0, _loggermiddleware.getTenantId)(),
|
|
39
|
-
companyId: (0, _loggermiddleware.getCompanyId)()
|
|
40
|
-
}).filter(([, v])=>v != null));
|
|
41
|
-
}
|
|
42
|
-
let WinstonLoggerAdapter = class WinstonLoggerAdapter {
|
|
43
|
-
buildLogMeta(context, args, extra) {
|
|
44
|
-
const meta = args?.length && typeof args[0] === 'object' ? args[0] : {};
|
|
45
|
-
return {
|
|
46
|
-
context: context || this.context,
|
|
47
|
-
...getCorrelationMeta(),
|
|
48
|
-
...meta,
|
|
49
|
-
...extra
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
log(message, context, ...args) {
|
|
53
|
-
this.logger.info(message, this.buildLogMeta(context, args));
|
|
54
|
-
}
|
|
55
|
-
error(message, trace, context, ...args) {
|
|
56
|
-
this.logger.error(message, this.buildLogMeta(context, args, {
|
|
57
|
-
stack: trace
|
|
58
|
-
}));
|
|
59
|
-
}
|
|
60
|
-
warn(message, context, ...args) {
|
|
61
|
-
this.logger.warn(message, this.buildLogMeta(context, args));
|
|
62
|
-
}
|
|
63
|
-
debug(message, context, ...args) {
|
|
64
|
-
this.logger.debug(message, this.buildLogMeta(context, args));
|
|
65
|
-
}
|
|
66
|
-
verbose(message, context, ...args) {
|
|
67
|
-
this.logger.verbose(message, this.buildLogMeta(context, args));
|
|
68
|
-
}
|
|
69
|
-
constructor(context, moduleName){
|
|
70
|
-
_define_property(this, "context", void 0);
|
|
71
|
-
_define_property(this, "logger", void 0);
|
|
72
|
-
this.context = context;
|
|
73
|
-
this.logger = moduleName ? (0, _winstonloggerclass.createModuleLogger)(moduleName) : _winstonloggerclass.instance;
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
let NestLoggerAdapter = class NestLoggerAdapter {
|
|
77
|
-
formatMessage(message, args) {
|
|
78
|
-
return args?.length ? `${message} ${JSON.stringify(args)}` : message;
|
|
79
|
-
}
|
|
80
|
-
log(message, context, ...args) {
|
|
81
|
-
this.logger.log(this.formatMessage(message, args), context);
|
|
82
|
-
}
|
|
83
|
-
error(message, trace, context, ...args) {
|
|
84
|
-
this.logger.error(this.formatMessage(message, args), trace, context);
|
|
85
|
-
}
|
|
86
|
-
warn(message, context, ...args) {
|
|
87
|
-
this.logger.warn(this.formatMessage(message, args), context);
|
|
88
|
-
}
|
|
89
|
-
debug(message, context, ...args) {
|
|
90
|
-
this.logger.debug(this.formatMessage(message, args), context);
|
|
91
|
-
}
|
|
92
|
-
verbose(message, context, ...args) {
|
|
93
|
-
this.logger.verbose(this.formatMessage(message, args), context);
|
|
94
|
-
}
|
|
95
|
-
constructor(logger){
|
|
96
|
-
_define_property(this, "logger", void 0);
|
|
97
|
-
this.logger = logger;
|
|
98
|
-
}
|
|
99
|
-
};
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
function _export(target, all) {
|
|
6
|
-
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
-
enumerable: true,
|
|
8
|
-
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
_export(exports, {
|
|
12
|
-
get SanitizeAndTrim () {
|
|
13
|
-
return SanitizeAndTrim;
|
|
14
|
-
},
|
|
15
|
-
get SanitizeHtml () {
|
|
16
|
-
return SanitizeHtml;
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
const _classtransformer = require("class-transformer");
|
|
20
|
-
const _htmlsanitizerutil = require("../utils/html-sanitizer.util");
|
|
21
|
-
function SanitizeHtml() {
|
|
22
|
-
return (0, _classtransformer.Transform)(({ value })=>{
|
|
23
|
-
if (typeof value === 'string') {
|
|
24
|
-
return (0, _htmlsanitizerutil.escapeHtml)(value);
|
|
25
|
-
}
|
|
26
|
-
return value;
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
function SanitizeAndTrim() {
|
|
30
|
-
return (0, _classtransformer.Transform)(({ value })=>{
|
|
31
|
-
if (typeof value === 'string') {
|
|
32
|
-
return (0, _htmlsanitizerutil.escapeHtml)(value.trim());
|
|
33
|
-
}
|
|
34
|
-
return value;
|
|
35
|
-
});
|
|
36
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { Logger } from '@nestjs/common';
|
|
2
|
-
import { ILogger } from '../interfaces/logger.interface';
|
|
3
|
-
export declare class WinstonLoggerAdapter implements ILogger {
|
|
4
|
-
private readonly context?;
|
|
5
|
-
private readonly logger;
|
|
6
|
-
constructor(context?: string, moduleName?: string);
|
|
7
|
-
private buildLogMeta;
|
|
8
|
-
log(message: string, context?: string, ...args: unknown[]): void;
|
|
9
|
-
error(message: string, trace?: string, context?: string, ...args: unknown[]): void;
|
|
10
|
-
warn(message: string, context?: string, ...args: unknown[]): void;
|
|
11
|
-
debug(message: string, context?: string, ...args: unknown[]): void;
|
|
12
|
-
verbose(message: string, context?: string, ...args: unknown[]): void;
|
|
13
|
-
}
|
|
14
|
-
export declare class NestLoggerAdapter implements ILogger {
|
|
15
|
-
private readonly logger;
|
|
16
|
-
constructor(logger: Logger);
|
|
17
|
-
private formatMessage;
|
|
18
|
-
log(message: string, context?: string, ...args: unknown[]): void;
|
|
19
|
-
error(message: string, trace?: string, context?: string, ...args: unknown[]): void;
|
|
20
|
-
warn(message: string, context?: string, ...args: unknown[]): void;
|
|
21
|
-
debug(message: string, context?: string, ...args: unknown[]): void;
|
|
22
|
-
verbose(message: string, context?: string, ...args: unknown[]): void;
|
|
23
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
function _define_property(obj, key, value) {
|
|
2
|
-
if (key in obj) {
|
|
3
|
-
Object.defineProperty(obj, key, {
|
|
4
|
-
value: value,
|
|
5
|
-
enumerable: true,
|
|
6
|
-
configurable: true,
|
|
7
|
-
writable: true
|
|
8
|
-
});
|
|
9
|
-
} else {
|
|
10
|
-
obj[key] = value;
|
|
11
|
-
}
|
|
12
|
-
return obj;
|
|
13
|
-
}
|
|
14
|
-
import { instance as winstonLogger, createModuleLogger } from './winston.logger.class';
|
|
15
|
-
import { getRequestId, getUserId, getTenantId, getCompanyId } from '../middlewares/logger.middleware';
|
|
16
|
-
function getCorrelationMeta() {
|
|
17
|
-
return Object.fromEntries(Object.entries({
|
|
18
|
-
requestId: getRequestId(),
|
|
19
|
-
userId: getUserId(),
|
|
20
|
-
tenantId: getTenantId(),
|
|
21
|
-
companyId: getCompanyId()
|
|
22
|
-
}).filter(([, v])=>v != null));
|
|
23
|
-
}
|
|
24
|
-
export class WinstonLoggerAdapter {
|
|
25
|
-
buildLogMeta(context, args, extra) {
|
|
26
|
-
const meta = args?.length && typeof args[0] === 'object' ? args[0] : {};
|
|
27
|
-
return {
|
|
28
|
-
context: context || this.context,
|
|
29
|
-
...getCorrelationMeta(),
|
|
30
|
-
...meta,
|
|
31
|
-
...extra
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
log(message, context, ...args) {
|
|
35
|
-
this.logger.info(message, this.buildLogMeta(context, args));
|
|
36
|
-
}
|
|
37
|
-
error(message, trace, context, ...args) {
|
|
38
|
-
this.logger.error(message, this.buildLogMeta(context, args, {
|
|
39
|
-
stack: trace
|
|
40
|
-
}));
|
|
41
|
-
}
|
|
42
|
-
warn(message, context, ...args) {
|
|
43
|
-
this.logger.warn(message, this.buildLogMeta(context, args));
|
|
44
|
-
}
|
|
45
|
-
debug(message, context, ...args) {
|
|
46
|
-
this.logger.debug(message, this.buildLogMeta(context, args));
|
|
47
|
-
}
|
|
48
|
-
verbose(message, context, ...args) {
|
|
49
|
-
this.logger.verbose(message, this.buildLogMeta(context, args));
|
|
50
|
-
}
|
|
51
|
-
constructor(context, moduleName){
|
|
52
|
-
_define_property(this, "context", void 0);
|
|
53
|
-
_define_property(this, "logger", void 0);
|
|
54
|
-
this.context = context;
|
|
55
|
-
this.logger = moduleName ? createModuleLogger(moduleName) : winstonLogger;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
export class NestLoggerAdapter {
|
|
59
|
-
formatMessage(message, args) {
|
|
60
|
-
return args?.length ? `${message} ${JSON.stringify(args)}` : message;
|
|
61
|
-
}
|
|
62
|
-
log(message, context, ...args) {
|
|
63
|
-
this.logger.log(this.formatMessage(message, args), context);
|
|
64
|
-
}
|
|
65
|
-
error(message, trace, context, ...args) {
|
|
66
|
-
this.logger.error(this.formatMessage(message, args), trace, context);
|
|
67
|
-
}
|
|
68
|
-
warn(message, context, ...args) {
|
|
69
|
-
this.logger.warn(this.formatMessage(message, args), context);
|
|
70
|
-
}
|
|
71
|
-
debug(message, context, ...args) {
|
|
72
|
-
this.logger.debug(this.formatMessage(message, args), context);
|
|
73
|
-
}
|
|
74
|
-
verbose(message, context, ...args) {
|
|
75
|
-
this.logger.verbose(this.formatMessage(message, args), context);
|
|
76
|
-
}
|
|
77
|
-
constructor(logger){
|
|
78
|
-
_define_property(this, "logger", void 0);
|
|
79
|
-
this.logger = logger;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { Transform } from 'class-transformer';
|
|
2
|
-
import { escapeHtml } from '../utils/html-sanitizer.util';
|
|
3
|
-
/**
|
|
4
|
-
* Decorator that sanitizes HTML content in string fields to prevent XSS attacks.
|
|
5
|
-
* Applies HTML escaping during transformation (when class-transformer processes the DTO).
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```typescript
|
|
9
|
-
* class CreateCommentDto {
|
|
10
|
-
* @SanitizeHtml()
|
|
11
|
-
* @IsString()
|
|
12
|
-
* content: string;
|
|
13
|
-
* }
|
|
14
|
-
* ```
|
|
15
|
-
*
|
|
16
|
-
* Input: '<script>alert("xss")</script>'
|
|
17
|
-
* Output: '<script>alert("xss")</script>'
|
|
18
|
-
*/ export function SanitizeHtml() {
|
|
19
|
-
return Transform(({ value })=>{
|
|
20
|
-
if (typeof value === 'string') {
|
|
21
|
-
return escapeHtml(value);
|
|
22
|
-
}
|
|
23
|
-
return value;
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Decorator that sanitizes HTML and trims whitespace from string fields.
|
|
28
|
-
* Combines sanitization with trimming for cleaner input handling.
|
|
29
|
-
*
|
|
30
|
-
* @example
|
|
31
|
-
* ```typescript
|
|
32
|
-
* class CreatePostDto {
|
|
33
|
-
* @SanitizeAndTrim()
|
|
34
|
-
* @IsString()
|
|
35
|
-
* title: string;
|
|
36
|
-
* }
|
|
37
|
-
* ```
|
|
38
|
-
*/ export function SanitizeAndTrim() {
|
|
39
|
-
return Transform(({ value })=>{
|
|
40
|
-
if (typeof value === 'string') {
|
|
41
|
-
return escapeHtml(value.trim());
|
|
42
|
-
}
|
|
43
|
-
return value;
|
|
44
|
-
});
|
|
45
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { };
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export interface ILogger {
|
|
2
|
-
log(message: string, context?: string, ...args: unknown[]): void;
|
|
3
|
-
error(message: string, trace?: string, context?: string, ...args: unknown[]): void;
|
|
4
|
-
warn(message: string, context?: string, ...args: unknown[]): void;
|
|
5
|
-
debug(message: string, context?: string, ...args: unknown[]): void;
|
|
6
|
-
verbose(message: string, context?: string, ...args: unknown[]): void;
|
|
7
|
-
}
|