@flusys/nestjs-shared 4.1.1 → 5.0.1

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 (65) hide show
  1. package/README.md +96 -606
  2. package/cjs/classes/api-controller.class.js +81 -10
  3. package/cjs/classes/api-service.class.js +8 -6
  4. package/cjs/classes/handle-custome-db-column-type.js +17 -0
  5. package/cjs/classes/index.js +2 -2
  6. package/cjs/constants/index.js +0 -4
  7. package/cjs/constants/message-keys.js +3 -21
  8. package/cjs/constants/permissions.js +0 -10
  9. package/cjs/decorators/api-response.decorator.js +1 -2
  10. package/cjs/decorators/index.js +0 -1
  11. package/cjs/decorators/require-permission.decorator.js +0 -4
  12. package/cjs/entities/user-root.js +2 -1
  13. package/cjs/exceptions/base-app.exception.js +4 -4
  14. package/cjs/exceptions/permission.exception.js +1 -1
  15. package/cjs/filters/global-exception.filter.js +4 -4
  16. package/cjs/interfaces/index.js +0 -1
  17. package/cjs/modules/datasource/multi-tenant-datasource.service.js +2 -2
  18. package/cjs/utils/date-time.util.js +94 -0
  19. package/cjs/utils/index.js +1 -0
  20. package/cjs/utils/query-helpers.util.js +2 -2
  21. package/cjs/utils/request.util.js +25 -0
  22. package/classes/handle-custome-db-column-type.d.ts +1 -0
  23. package/classes/index.d.ts +2 -2
  24. package/constants/index.d.ts +0 -1
  25. package/constants/message-keys.d.ts +2 -44
  26. package/constants/permissions.d.ts +0 -12
  27. package/decorators/api-response.decorator.d.ts +1 -1
  28. package/decorators/index.d.ts +0 -1
  29. package/decorators/require-permission.decorator.d.ts +0 -1
  30. package/exceptions/base-app.exception.d.ts +2 -2
  31. package/fesm/classes/api-controller.class.js +82 -11
  32. package/fesm/classes/api-service.class.js +9 -7
  33. package/fesm/classes/handle-custome-db-column-type.js +7 -0
  34. package/fesm/classes/index.js +2 -2
  35. package/fesm/constants/index.js +0 -1
  36. package/fesm/constants/message-keys.js +3 -19
  37. package/fesm/constants/permissions.js +0 -7
  38. package/fesm/decorators/api-response.decorator.js +2 -20
  39. package/fesm/decorators/index.js +0 -1
  40. package/fesm/decorators/require-permission.decorator.js +0 -1
  41. package/fesm/entities/user-root.js +2 -1
  42. package/fesm/exceptions/base-app.exception.js +4 -4
  43. package/fesm/exceptions/permission.exception.js +1 -1
  44. package/fesm/filters/global-exception.filter.js +4 -4
  45. package/fesm/interfaces/index.js +0 -1
  46. package/fesm/modules/datasource/multi-tenant-datasource.service.js +2 -2
  47. package/fesm/utils/date-time.util.js +70 -0
  48. package/fesm/utils/index.js +1 -0
  49. package/fesm/utils/query-helpers.util.js +2 -2
  50. package/fesm/utils/request.util.js +22 -0
  51. package/interfaces/event-manager-adapter.interface.d.ts +12 -12
  52. package/interfaces/index.d.ts +0 -1
  53. package/package.json +5 -5
  54. package/utils/date-time.util.d.ts +8 -0
  55. package/utils/index.d.ts +1 -0
  56. package/utils/request.util.d.ts +2 -0
  57. package/cjs/classes/winston-logger-adapter.class.js +0 -99
  58. package/cjs/decorators/sanitize-html.decorator.js +0 -36
  59. package/cjs/interfaces/logger.interface.js +0 -4
  60. package/classes/winston-logger-adapter.class.d.ts +0 -23
  61. package/decorators/sanitize-html.decorator.d.ts +0 -2
  62. package/fesm/classes/winston-logger-adapter.class.js +0 -81
  63. package/fesm/decorators/sanitize-html.decorator.js +0 -45
  64. package/fesm/interfaces/logger.interface.js +0 -1
  65. package/interfaces/logger.interface.d.ts +0 -7
@@ -61,7 +61,7 @@ export class GlobalExceptionFilter {
61
61
  success: false,
62
62
  message: exception.message,
63
63
  messageKey: exception.messageKey,
64
- messageParams: exception.messageParams,
64
+ messageVariables: exception.messageVariables,
65
65
  errors: exception.errors,
66
66
  _meta: {
67
67
  requestId,
@@ -72,12 +72,12 @@ export class GlobalExceptionFilter {
72
72
  }
73
73
  if (exception instanceof HttpException) {
74
74
  const response = exception.getResponse();
75
- const { message, messageKey, messageParams, errors } = this.extractHttpExceptionDetails(response);
75
+ const { message, messageKey, messageVariables, errors } = this.extractHttpExceptionDetails(response);
76
76
  return {
77
77
  success: false,
78
78
  message,
79
79
  messageKey,
80
- messageParams,
80
+ messageVariables,
81
81
  errors,
82
82
  _meta: {
83
83
  requestId,
@@ -124,7 +124,7 @@ export class GlobalExceptionFilter {
124
124
  return {
125
125
  message: String(obj.message || 'Unknown error'),
126
126
  messageKey: String(obj.messageKey || ERROR_MESSAGES.HTTP),
127
- messageParams: obj.messageParams,
127
+ messageVariables: obj.messageVariables,
128
128
  errors: obj.errors
129
129
  };
130
130
  }
@@ -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';
@@ -88,7 +88,7 @@ export class MultiTenantDataSourceService {
88
88
  throw new BadRequestException({
89
89
  message: `Tenant '${tenantId}' not found`,
90
90
  messageKey: SYSTEM_MESSAGES.TENANT_NOT_FOUND,
91
- messageParams: {
91
+ messageVariables: {
92
92
  tenantId
93
93
  }
94
94
  });
@@ -183,7 +183,7 @@ export class MultiTenantDataSourceService {
183
183
  throw new BadRequestException({
184
184
  message: `Tenant not found. Ensure '${this.tenantHeader}' header is set.`,
185
185
  messageKey: SYSTEM_MESSAGES.TENANT_HEADER_REQUIRED,
186
- messageParams: {
186
+ messageVariables: {
187
187
  header: this.tenantHeader
188
188
  }
189
189
  });
@@ -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
+ }
@@ -1,3 +1,4 @@
1
+ export * from './date-time.util';
1
2
  export * from './html-sanitizer.util';
2
3
  export * from './query-helpers.util';
3
4
  export * from './request.util';
@@ -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.COMPANY_NO_ACCESS,
79
- messageParams: {
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
- meetingLink?: string;
15
- startDateTime: Date;
16
- endDateTime: Date;
12
+ eventDate: string;
13
+ startTime: string;
14
+ endTime: string;
17
15
  isAllDay?: boolean;
18
16
  recurrenceType?: RecurrenceType;
19
- recurrenceEndDate?: Date;
17
+ recurrenceEndDate?: string | null;
18
+ weekDays?: string[] | null;
20
19
  color?: string;
21
- metadata?: Record<string, unknown>;
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
- meetingLink?: string | null;
31
- startDateTime: Date;
32
- endDateTime: Date;
29
+ eventDate: string;
30
+ startTime: string;
31
+ endTime: string;
33
32
  isAllDay: boolean;
34
33
  recurrenceType: string;
35
- recurrenceEndDate?: Date | null;
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;
@@ -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": "4.1.1",
3
+ "version": "5.0.1",
4
4
  "description": "Common shared utilities for Flusys NestJS applications",
5
5
  "main": "cjs/index.js",
6
6
  "module": "fesm/index.js",
@@ -93,7 +93,7 @@
93
93
  }
94
94
  },
95
95
  "peerDependencies": {
96
- "@keyv/redis": "^5.0.0",
96
+ "@keyv/redis": "^5.0.1",
97
97
  "@nestjs/common": "^10.0.0 || ^11.0.0",
98
98
  "@nestjs/config": "^3.0.0 || ^4.0.0",
99
99
  "@nestjs/core": "^10.0.0 || ^11.0.0",
@@ -104,14 +104,14 @@
104
104
  "cacheable": "^2.0.0",
105
105
  "class-transformer": "^0.5.0",
106
106
  "class-validator": "^0.14.0",
107
- "keyv": "^5.0.0",
107
+ "keyv": "^5.0.1",
108
108
  "typeorm": "^0.3.0",
109
109
  "winston": "^3.0.0",
110
- "winston-daily-rotate-file": "^5.0.0",
110
+ "winston-daily-rotate-file": "^5.0.1",
111
111
  "express": "^4.18.0",
112
112
  "rxjs": "^7.8.0"
113
113
  },
114
114
  "dependencies": {
115
- "@flusys/nestjs-core": "4.1.1"
115
+ "@flusys/nestjs-core": "5.0.1"
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
@@ -1,3 +1,4 @@
1
+ export * from './date-time.util';
1
2
  export * from './html-sanitizer.util';
2
3
  export * from './query-helpers.util';
3
4
  export * from './request.util';
@@ -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,4 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
@@ -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,2 +0,0 @@
1
- export declare function SanitizeHtml(): PropertyDecorator;
2
- export declare function SanitizeAndTrim(): PropertyDecorator;
@@ -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: '&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;'
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
- }