@flusys/nestjs-shared 1.1.0 → 1.2.0-rc.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 (158) hide show
  1. package/README.md +139 -1103
  2. package/cjs/classes/api-controller.class.js +320 -29
  3. package/cjs/classes/api-service.class.js +219 -64
  4. package/cjs/classes/handle-custome-db.js +37 -0
  5. package/cjs/classes/index.js +1 -2
  6. package/cjs/classes/winston.logger.class.js +103 -70
  7. package/cjs/constants/index.js +1 -4
  8. package/cjs/constants/message-keys.js +68 -0
  9. package/cjs/constants/permissions.js +114 -11
  10. package/cjs/decorators/api-response.decorator.js +1 -2
  11. package/cjs/decorators/index.js +1 -1
  12. package/cjs/decorators/log-action.decorator.js +149 -0
  13. package/cjs/decorators/require-permission.decorator.js +5 -5
  14. package/cjs/dtos/get-by-ids.dto.js +65 -0
  15. package/cjs/dtos/identity-response.dto.js +4 -8
  16. package/cjs/dtos/index.js +1 -0
  17. package/cjs/dtos/response-payload.dto.js +72 -0
  18. package/cjs/entities/identity.js +8 -2
  19. package/cjs/entities/index.js +1 -0
  20. package/cjs/entities/raw-type.js +4 -0
  21. package/cjs/entities/user-root.js +2 -1
  22. package/cjs/enums/index.js +20 -0
  23. package/cjs/enums/notification-type.enum.js +17 -0
  24. package/cjs/enums/participant-status.enum.js +17 -0
  25. package/cjs/enums/recurrence-type.enum.js +18 -0
  26. package/cjs/exceptions/base-app.exception.js +151 -0
  27. package/cjs/exceptions/index.js +1 -0
  28. package/cjs/exceptions/permission.exception.js +13 -9
  29. package/cjs/filters/global-exception.filter.js +279 -0
  30. package/cjs/filters/index.js +18 -0
  31. package/cjs/guards/jwt-auth.guard.js +4 -1
  32. package/cjs/guards/permission.guard.js +71 -77
  33. package/cjs/index.js +2 -0
  34. package/cjs/interceptors/idempotency.interceptor.js +1 -1
  35. package/cjs/interceptors/index.js +0 -1
  36. package/cjs/interfaces/event-manager-adapter.interface.js +11 -0
  37. package/cjs/interfaces/index.js +2 -1
  38. package/cjs/interfaces/notification-adapter.interface.js +11 -0
  39. package/cjs/interfaces/permission.interface.js +1 -1
  40. package/cjs/middlewares/logger.middleware.js +83 -26
  41. package/cjs/modules/datasource/index.js +0 -1
  42. package/cjs/modules/datasource/multi-tenant-datasource.service.js +46 -85
  43. package/cjs/modules/utils/utils.service.js +4 -20
  44. package/cjs/utils/date-time.util.js +94 -0
  45. package/cjs/utils/index.js +1 -1
  46. package/cjs/utils/query-helpers.util.js +8 -1
  47. package/cjs/utils/request.util.js +25 -0
  48. package/classes/api-controller.class.d.ts +14 -6
  49. package/classes/api-service.class.d.ts +25 -22
  50. package/classes/handle-custome-db.d.ts +3 -0
  51. package/classes/index.d.ts +1 -2
  52. package/classes/winston.logger.class.d.ts +1 -0
  53. package/constants/index.d.ts +1 -1
  54. package/constants/message-keys.d.ts +45 -0
  55. package/constants/permissions.d.ts +127 -0
  56. package/decorators/api-response.decorator.d.ts +1 -1
  57. package/decorators/current-user.decorator.d.ts +1 -1
  58. package/decorators/index.d.ts +1 -1
  59. package/decorators/log-action.decorator.d.ts +8 -0
  60. package/decorators/require-permission.decorator.d.ts +2 -2
  61. package/dtos/get-by-ids.dto.d.ts +4 -0
  62. package/dtos/index.d.ts +1 -0
  63. package/dtos/response-payload.dto.d.ts +8 -0
  64. package/entities/index.d.ts +1 -0
  65. package/entities/raw-type.d.ts +1 -0
  66. package/enums/index.d.ts +3 -0
  67. package/enums/notification-type.enum.d.ts +6 -0
  68. package/enums/participant-status.enum.d.ts +6 -0
  69. package/enums/recurrence-type.enum.d.ts +7 -0
  70. package/exceptions/base-app.exception.d.ts +41 -0
  71. package/exceptions/index.d.ts +1 -0
  72. package/exceptions/permission.exception.d.ts +2 -2
  73. package/fesm/classes/api-controller.class.js +321 -30
  74. package/fesm/classes/api-service.class.js +222 -67
  75. package/fesm/classes/handle-custome-db.js +19 -0
  76. package/fesm/classes/index.js +1 -2
  77. package/fesm/classes/winston.logger.class.js +100 -68
  78. package/fesm/constants/index.js +2 -1
  79. package/fesm/constants/message-keys.js +49 -0
  80. package/fesm/constants/permissions.js +86 -14
  81. package/fesm/decorators/api-response.decorator.js +2 -20
  82. package/fesm/decorators/index.js +1 -1
  83. package/fesm/decorators/log-action.decorator.js +139 -0
  84. package/fesm/decorators/require-permission.decorator.js +17 -65
  85. package/fesm/dtos/get-by-ids.dto.js +55 -0
  86. package/fesm/dtos/identity-response.dto.js +4 -8
  87. package/fesm/dtos/index.js +1 -0
  88. package/fesm/dtos/response-payload.dto.js +72 -0
  89. package/fesm/entities/identity.js +8 -2
  90. package/fesm/entities/index.js +1 -0
  91. package/fesm/entities/raw-type.js +1 -0
  92. package/fesm/entities/user-root.js +2 -1
  93. package/fesm/enums/index.js +3 -0
  94. package/fesm/enums/notification-type.enum.js +7 -0
  95. package/fesm/enums/participant-status.enum.js +7 -0
  96. package/fesm/enums/recurrence-type.enum.js +8 -0
  97. package/fesm/exceptions/base-app.exception.js +115 -0
  98. package/fesm/exceptions/index.js +1 -0
  99. package/fesm/exceptions/permission.exception.js +16 -18
  100. package/fesm/filters/global-exception.filter.js +269 -0
  101. package/fesm/filters/index.js +1 -0
  102. package/fesm/guards/jwt-auth.guard.js +5 -2
  103. package/fesm/guards/permission.guard.js +73 -79
  104. package/fesm/index.js +2 -0
  105. package/fesm/interceptors/idempotency.interceptor.js +2 -2
  106. package/fesm/interceptors/index.js +0 -1
  107. package/fesm/interfaces/datasource.interface.js +1 -20
  108. package/fesm/interfaces/event-manager-adapter.interface.js +1 -0
  109. package/fesm/interfaces/index.js +2 -1
  110. package/fesm/interfaces/notification-adapter.interface.js +1 -0
  111. package/fesm/interfaces/permission.interface.js +1 -3
  112. package/fesm/middlewares/logger.middleware.js +83 -26
  113. package/fesm/modules/datasource/index.js +0 -1
  114. package/fesm/modules/datasource/multi-tenant-datasource.service.js +47 -86
  115. package/fesm/modules/utils/utils.service.js +5 -21
  116. package/fesm/utils/date-time.util.js +70 -0
  117. package/fesm/utils/index.js +1 -1
  118. package/fesm/utils/query-helpers.util.js +8 -1
  119. package/fesm/utils/request.util.js +22 -0
  120. package/filters/global-exception.filter.d.ts +9 -0
  121. package/filters/index.d.ts +1 -0
  122. package/guards/permission.guard.d.ts +3 -7
  123. package/index.d.ts +2 -0
  124. package/interceptors/idempotency.interceptor.d.ts +1 -1
  125. package/interceptors/index.d.ts +0 -1
  126. package/interfaces/api.interface.d.ts +2 -0
  127. package/interfaces/event-manager-adapter.interface.d.ts +43 -0
  128. package/interfaces/index.d.ts +2 -1
  129. package/interfaces/notification-adapter.interface.d.ts +21 -0
  130. package/interfaces/permission.interface.d.ts +13 -8
  131. package/modules/datasource/index.d.ts +0 -1
  132. package/modules/datasource/multi-tenant-datasource.service.d.ts +5 -15
  133. package/modules/utils/utils.service.d.ts +0 -1
  134. package/package.json +21 -14
  135. package/utils/date-time.util.d.ts +8 -0
  136. package/utils/index.d.ts +1 -1
  137. package/utils/request.util.d.ts +2 -0
  138. package/cjs/classes/request-scoped-api.service.js +0 -61
  139. package/cjs/classes/winston-logger-adapter.class.js +0 -104
  140. package/cjs/decorators/sanitize-html.decorator.js +0 -36
  141. package/cjs/interceptors/query-performance.interceptor.js +0 -66
  142. package/cjs/interfaces/logger.interface.js +0 -7
  143. package/cjs/modules/datasource/datasource.module.js +0 -117
  144. package/cjs/utils/error-handler.util.js +0 -90
  145. package/classes/request-scoped-api.service.d.ts +0 -14
  146. package/classes/winston-logger-adapter.class.d.ts +0 -22
  147. package/decorators/sanitize-html.decorator.d.ts +0 -2
  148. package/fesm/classes/request-scoped-api.service.js +0 -51
  149. package/fesm/classes/winston-logger-adapter.class.js +0 -107
  150. package/fesm/decorators/sanitize-html.decorator.js +0 -45
  151. package/fesm/interceptors/query-performance.interceptor.js +0 -56
  152. package/fesm/interfaces/logger.interface.js +0 -4
  153. package/fesm/modules/datasource/datasource.module.js +0 -107
  154. package/fesm/utils/error-handler.util.js +0 -82
  155. package/interceptors/query-performance.interceptor.d.ts +0 -8
  156. package/interfaces/logger.interface.d.ts +0 -7
  157. package/modules/datasource/datasource.module.d.ts +0 -19
  158. package/utils/error-handler.util.d.ts +0 -19
@@ -2,9 +2,17 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
- Object.defineProperty(exports, "instance", {
6
- enumerable: true,
7
- get: function() {
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 createModuleLogger () {
13
+ return createModuleLogger;
14
+ },
15
+ get instance () {
8
16
  return instance;
9
17
  }
10
18
  });
@@ -12,8 +20,8 @@ const _config = require("@flusys/nestjs-core/config");
12
20
  const _fs = require("fs");
13
21
  const _path = require("path");
14
22
  const _winston = require("winston");
15
- const _winstontransport = /*#__PURE__*/ _interop_require_wildcard(require("winston-transport"));
16
23
  const _winstondailyrotatefile = /*#__PURE__*/ _interop_require_wildcard(require("winston-daily-rotate-file"));
24
+ const _winstontransport = /*#__PURE__*/ _interop_require_wildcard(require("winston-transport"));
17
25
  function _define_property(obj, key, value) {
18
26
  if (key in obj) {
19
27
  Object.defineProperty(obj, key, {
@@ -85,33 +93,48 @@ if (!(0, _fs.existsSync)(LOG_DIR)) {
85
93
  }
86
94
  // Custom Formats
87
95
  /**
88
- * Custom format for structured logging
89
- * Includes: timestamp, level, context, requestId, userId, message, metadata
90
- */ const structuredFormat = _winston.format.printf(({ timestamp, level, message, context, requestId, userId, stack, ...metadata })=>{
91
- const logEntry = {
92
- timestamp,
93
- level: level.toUpperCase(),
94
- context: context || 'App',
95
- message
96
- };
97
- if (requestId) logEntry.requestId = requestId;
98
- if (userId) logEntry.userId = userId;
99
- if (Object.keys(metadata).length > 0) logEntry.metadata = metadata;
100
- if (stack) logEntry.stack = stack;
101
- return JSON.stringify(logEntry);
102
- });
103
- /**
104
- * Custom format for development console output
105
- * Human-readable format with colors
106
- */ const devConsoleFormat = _winston.format.printf(({ timestamp, level, message, context, requestId, userId, method, url, path, statusCode, duration, stack })=>{
107
- const ctx = context || 'App';
108
- const reqId = requestId ? ` [${requestId}]` : '';
109
- const user = userId ? ` (user:${userId})` : '';
110
- const endpoint = method && (path || url) ? ` [${method} ${path || url}]` : '';
111
- const status = statusCode ? ` [${statusCode}]` : '';
112
- const time = duration ? ` (${duration})` : '';
113
- const stackTrace = stack ? `\n${stack}` : '';
114
- return `${timestamp} [${level.toUpperCase().padEnd(7)}] [${ctx}]${endpoint}${status}${time}${reqId}${user} ${message}${stackTrace}`;
96
+ * Custom format for structured logging (production)
97
+ * Multi-line format:
98
+ * - Line 1: Timestamp
99
+ * - Line 2: Log Level
100
+ * - Line 3: [RequestId]
101
+ * - Line 4: Empty
102
+ * - Line 5+: Message with context
103
+ */ const LEVEL_MAP = {
104
+ error: 'Error',
105
+ warn: 'Warning',
106
+ info: 'Information',
107
+ debug: 'Debug',
108
+ verbose: 'Verbose'
109
+ };
110
+ const LOG_SEPARATOR = '─'.repeat(80);
111
+ const structuredFormat = _winston.format.printf(({ timestamp, level, message, context, requestId, userId, tenantId, companyId, method, url, path, statusCode, duration, stack, ...metadata })=>{
112
+ const reqId = requestId || 'no-request-id';
113
+ const levelFormatted = LEVEL_MAP[level] || level.charAt(0).toUpperCase() + level.slice(1);
114
+ const contextParts = [];
115
+ if (context) contextParts.push(`Context: ${context}`);
116
+ if (method && (path || url)) contextParts.push(`Endpoint: ${method} ${path || url}`);
117
+ if (statusCode) contextParts.push(`Status: ${statusCode}`);
118
+ if (duration) contextParts.push(`Duration: ${duration}`);
119
+ if (userId) contextParts.push(`UserId: ${userId}`);
120
+ if (tenantId) contextParts.push(`TenantId: ${tenantId}`);
121
+ if (companyId) contextParts.push(`CompanyId: ${companyId}`);
122
+ let content = message;
123
+ if (contextParts.length > 0) {
124
+ content = `${contextParts.join(' | ')}\n${message}`;
125
+ }
126
+ const metaKeys = Object.keys(metadata).filter((k)=>k !== 'splat');
127
+ if (metaKeys.length > 0) {
128
+ const metaStr = JSON.stringify(metaKeys.reduce((acc, k)=>({
129
+ ...acc,
130
+ [k]: metadata[k]
131
+ }), {}));
132
+ content += `\nMetadata: ${metaStr}`;
133
+ }
134
+ if (stack) {
135
+ content += `\nStack: ${stack}`;
136
+ }
137
+ return `${LOG_SEPARATOR}\n${timestamp} | ${levelFormatted} | [${reqId}]\n${content}`;
115
138
  });
116
139
  // Transports
117
140
  /**
@@ -134,63 +157,44 @@ if (!(0, _fs.existsSync)(LOG_DIR)) {
134
157
  maxFiles: LOG_MAX_FILES,
135
158
  level: 'error'
136
159
  });
137
- // Tenant-Aware Transport
138
- /**
139
- * Cache for tenant-specific transports
140
- * Avoids creating new transport instances for each log entry
141
- */ const tenantTransportCache = new Map();
142
- /**
143
- * Get or create a tenant-specific transport
144
- * Creates logs in: logs/{tenantId}/combined-YYYY-MM-DD.log
145
- */ function getTenantTransport(tenantId) {
146
- if (tenantTransportCache.has(tenantId)) {
147
- return tenantTransportCache.get(tenantId);
148
- }
149
- const tenantLogDir = (0, _path.join)(LOG_DIR, tenantId);
150
- if (!(0, _fs.existsSync)(tenantLogDir)) {
151
- (0, _fs.mkdirSync)(tenantLogDir, {
160
+ // Transport Caches
161
+ const moduleTransportCache = new Map();
162
+ const tenantTransportCache = new Map();
163
+ function getCachedTransport(cache, name) {
164
+ const cached = cache.get(name);
165
+ if (cached) return cached;
166
+ const logDir = (0, _path.join)(LOG_DIR, name);
167
+ if (!(0, _fs.existsSync)(logDir)) {
168
+ (0, _fs.mkdirSync)(logDir, {
152
169
  recursive: true
153
170
  });
154
171
  }
155
172
  const transport = new DailyRotateFile({
156
- filename: `${tenantLogDir}/combined-%DATE%.log`,
173
+ filename: `${logDir}/combined-%DATE%.log`,
157
174
  datePattern: 'YYYY-MM-DD',
158
175
  zippedArchive: true,
159
176
  maxSize: LOG_MAX_SIZE,
160
177
  maxFiles: LOG_MAX_FILES,
161
178
  level: LOG_LEVEL
162
179
  });
163
- tenantTransportCache.set(tenantId, transport);
180
+ cache.set(name, transport);
164
181
  return transport;
165
182
  }
166
- /**
167
- * Tenant-aware transport wrapper
168
- * Routes logs to tenant-specific folders when tenantId is present
169
- */ let TenantAwareTransport = class TenantAwareTransport extends Transport {
183
+ const getModuleTransport = (name)=>getCachedTransport(moduleTransportCache, name);
184
+ const getTenantTransport = (name)=>getCachedTransport(tenantTransportCache, name);
185
+ let TenantAwareTransport = class TenantAwareTransport extends Transport {
170
186
  log(info, callback) {
171
187
  setImmediate(()=>this.emit('logged', info));
172
188
  const tenantId = info.tenantId || info.metadata?.tenantId;
173
- if (USE_TENANT_MODE && tenantId) {
174
- // Write to tenant-specific folder
175
- const tenantTransport = getTenantTransport(tenantId);
176
- tenantTransport.log(info, callback);
177
- } else {
178
- // Write to default log folder
179
- this.defaultTransport.log(info, callback);
180
- }
189
+ const transport = USE_TENANT_MODE && tenantId ? getTenantTransport(tenantId) : this.defaultTransport;
190
+ transport.log(info, callback);
181
191
  }
182
192
  constructor(defaultTransport){
183
- super(), _define_property(this, "defaultTransport", void 0);
184
- this.defaultTransport = defaultTransport;
193
+ super(), _define_property(this, "defaultTransport", void 0), this.defaultTransport = defaultTransport;
185
194
  }
186
195
  };
187
- /**
188
- * Tenant-aware combined transport
189
- * When USE_TENANT_MODE=true, routes to tenant folders (like database mode)
190
- */ const tenantAwareCombinedTransport = new TenantAwareTransport(combinedRotateTransport);
191
- /**
192
- * Console transport for development
193
- */ const consoleTransport = new _winston.transports.Console({
196
+ const tenantAwareCombinedTransport = new TenantAwareTransport(combinedRotateTransport);
197
+ const consoleTransport = new _winston.transports.Console({
194
198
  level: LOG_LEVEL,
195
199
  format: _winston.format.combine(_winston.format.colorize({
196
200
  all: true
@@ -198,7 +202,7 @@ if (!(0, _fs.existsSync)(LOG_DIR)) {
198
202
  format: 'YYYY-MM-DD HH:mm:ss'
199
203
  }), _winston.format.errors({
200
204
  stack: true
201
- }), devConsoleFormat)
205
+ }), structuredFormat)
202
206
  });
203
207
  // Logger Instances
204
208
  /**
@@ -239,3 +243,32 @@ if (!(0, _fs.existsSync)(LOG_DIR)) {
239
243
  exitOnError: false
240
244
  });
241
245
  const instance = _config.envConfig.isProduction() ? prodLogger : devLogger;
246
+ /**
247
+ * Module logger cache to avoid creating multiple loggers for the same module
248
+ */ const moduleLoggerCache = new Map();
249
+ function createModuleLogger(moduleName) {
250
+ // In dev mode, use global console logger
251
+ if (!_config.envConfig.isProduction()) {
252
+ return devLogger;
253
+ }
254
+ // Check cache first
255
+ if (moduleLoggerCache.has(moduleName)) {
256
+ return moduleLoggerCache.get(moduleName);
257
+ }
258
+ // Create module-specific logger for production
259
+ const moduleLogger = (0, _winston.createLogger)({
260
+ level: LOG_LEVEL,
261
+ format: _winston.format.combine(_winston.format.timestamp({
262
+ format: 'YYYY-MM-DD HH:mm:ss.SSS'
263
+ }), _winston.format.errors({
264
+ stack: true
265
+ }), structuredFormat),
266
+ transports: [
267
+ getModuleTransport(moduleName),
268
+ errorRotateTransport
269
+ ],
270
+ exitOnError: false
271
+ });
272
+ moduleLoggerCache.set(moduleName, moduleLogger);
273
+ return moduleLogger;
274
+ }
@@ -25,9 +25,6 @@ _export(exports, {
25
25
  get IS_PUBLIC_KEY () {
26
26
  return IS_PUBLIC_KEY;
27
27
  },
28
- get LOGGER_INSTANCE () {
29
- return LOGGER_INSTANCE;
30
- },
31
28
  get PERMISSIONS_CACHE_PREFIX () {
32
29
  return PERMISSIONS_CACHE_PREFIX;
33
30
  },
@@ -42,6 +39,7 @@ _export(exports, {
42
39
  }
43
40
  });
44
41
  _export_star(require("./permissions"), exports);
42
+ _export_star(require("./message-keys"), exports);
45
43
  function _export_star(from, to) {
46
44
  Object.keys(from).forEach(function(k) {
47
45
  if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
@@ -59,7 +57,6 @@ const IS_PUBLIC_KEY = 'isPublic';
59
57
  const PERMISSIONS_KEY = 'permissions';
60
58
  const CACHE_INSTANCE = 'CACHE_INSTANCE';
61
59
  const PERMISSION_GUARD_CONFIG = 'PERMISSION_GUARD_CONFIG';
62
- const LOGGER_INSTANCE = 'LOGGER_INSTANCE';
63
60
  const IDEMPOTENCY_KEY_HEADER = 'x-idempotency-key';
64
61
  const REQUEST_ID_HEADER = 'x-request-id';
65
62
  const CLIENT_TYPE_HEADER = 'x-client-type';
@@ -0,0 +1,68 @@
1
+ // ==================== AUTH (Shared across guards/interceptors) ====================
2
+ // These are duplicated in nestjs-auth but needed here to avoid circular dependencies
3
+ "use strict";
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ function _export(target, all) {
8
+ for(var name in all)Object.defineProperty(target, name, {
9
+ enumerable: true,
10
+ get: Object.getOwnPropertyDescriptor(all, name).get
11
+ });
12
+ }
13
+ _export(exports, {
14
+ get AUTH_MESSAGES () {
15
+ return AUTH_MESSAGES;
16
+ },
17
+ get ERROR_MESSAGES () {
18
+ return ERROR_MESSAGES;
19
+ },
20
+ get SYSTEM_MESSAGES () {
21
+ return SYSTEM_MESSAGES;
22
+ }
23
+ });
24
+ const AUTH_MESSAGES = {
25
+ TOKEN_REQUIRED: 'auth.token.required',
26
+ TOKEN_INVALID: 'auth.token.invalid',
27
+ ENTITY_BELOG_ANOTHER_COMPANY: 'entity.belongs.another.company',
28
+ COMPANY_NO_ACCESS: 'auth.company.no.access'
29
+ };
30
+ const ERROR_MESSAGES = {
31
+ NOT_FOUND: 'error.not.found',
32
+ VALIDATION: 'error.validation',
33
+ UNAUTHORIZED: 'error.unauthorized',
34
+ FORBIDDEN: 'error.forbidden',
35
+ CONFLICT: 'error.conflict',
36
+ DB_FOREIGN_KEY: 'error.db.foreign.key',
37
+ DB_NOT_NULL: 'error.db.not.null',
38
+ DB_INVALID_INPUT: 'error.db.invalid.input',
39
+ DB_VALUE_TOO_LONG: 'error.db.value.too.long',
40
+ DB_CHECK_CONSTRAINT: 'error.db.check.constraint',
41
+ DB_DEADLOCK: 'error.db.deadlock',
42
+ INTERNAL: 'error.internal',
43
+ SERVICE_UNAVAILABLE: 'error.service.unavailable',
44
+ UNKNOWN: 'error.unknown',
45
+ HTTP: 'error.http',
46
+ GENERIC: 'error.generic',
47
+ PERMISSION_SYSTEM_UNAVAILABLE: 'error.permission.system.unavailable',
48
+ INSUFFICIENT_PERMISSIONS: 'error.insufficient.permissions',
49
+ INSUFFICIENT_PERMISSIONS_OR: 'error.insufficient.permissions.or',
50
+ NO_PERMISSIONS_FOUND: 'error.no.permissions.found',
51
+ ENDPOINT_DISABLED: 'error.endpoint.disabled'
52
+ };
53
+ const SYSTEM_MESSAGES = {
54
+ REPOSITORY_NOT_AVAILABLE: 'system.repository.not.available',
55
+ DATASOURCE_NOT_AVAILABLE: 'system.datasource.not.available',
56
+ DATABASE_CONFIG_NOT_AVAILABLE: 'system.database.config.not.available',
57
+ SERVICE_NOT_AVAILABLE: 'system.service.not.available',
58
+ CONFIG_REQUIRED: 'system.config.required',
59
+ INTERNAL_ERROR: 'system.internal.error',
60
+ DUPLICATE_REQUEST: 'system.duplicate.request',
61
+ INVALID_TENANT_ID: 'system.invalid.tenant.id',
62
+ TENANT_NOT_FOUND: 'system.tenant.not.found',
63
+ TENANT_HEADER_REQUIRED: 'system.tenant.header.required',
64
+ MISSING_PARAMETER: 'system.missing.parameter',
65
+ SDK_NOT_INSTALLED: 'system.sdk.not.installed',
66
+ PATH_TRAVERSAL_DETECTED: 'system.path.traversal.detected',
67
+ INVALID_FILE_KEY: 'system.invalid.file.key'
68
+ };
@@ -1,13 +1,4 @@
1
- /**
2
- * Centralized Permission Codes
3
- *
4
- * Single source of truth for all permission codes used across the application.
5
- * Use these constants instead of hardcoded strings to prevent typos and enable easy refactoring.
6
- *
7
- * Naming Convention: <entity>.<action>
8
- * - entity: The resource being accessed (e.g., user, role, company)
9
- * - action: The operation being performed (create, read, update, delete, assign)
10
- */ // ==================== AUTH MODULE ====================
1
+ // ==================== AUTH MODULE ====================
11
2
  "use strict";
12
3
  Object.defineProperty(exports, "__esModule", {
13
4
  value: true
@@ -37,6 +28,9 @@ _export(exports, {
37
28
  get EMAIL_TEMPLATE_PERMISSIONS () {
38
29
  return EMAIL_TEMPLATE_PERMISSIONS;
39
30
  },
31
+ get EVENT_PERMISSIONS () {
32
+ return EVENT_PERMISSIONS;
33
+ },
40
34
  get FILE_PERMISSIONS () {
41
35
  return FILE_PERMISSIONS;
42
36
  },
@@ -49,6 +43,12 @@ _export(exports, {
49
43
  get FORM_RESULT_PERMISSIONS () {
50
44
  return FORM_RESULT_PERMISSIONS;
51
45
  },
46
+ get LANGUAGE_PERMISSIONS () {
47
+ return LANGUAGE_PERMISSIONS;
48
+ },
49
+ get NOTIFICATION_PERMISSIONS () {
50
+ return NOTIFICATION_PERMISSIONS;
51
+ },
52
52
  get PERMISSIONS () {
53
53
  return PERMISSIONS;
54
54
  },
@@ -61,6 +61,30 @@ _export(exports, {
61
61
  get STORAGE_CONFIG_PERMISSIONS () {
62
62
  return STORAGE_CONFIG_PERMISSIONS;
63
63
  },
64
+ get TASK_BOARD_PERMISSIONS () {
65
+ return TASK_BOARD_PERMISSIONS;
66
+ },
67
+ get TASK_COMMENT_PERMISSIONS () {
68
+ return TASK_COMMENT_PERMISSIONS;
69
+ },
70
+ get TASK_LABEL_PERMISSIONS () {
71
+ return TASK_LABEL_PERMISSIONS;
72
+ },
73
+ get TASK_LIST_PERMISSIONS () {
74
+ return TASK_LIST_PERMISSIONS;
75
+ },
76
+ get TASK_PERMISSIONS () {
77
+ return TASK_PERMISSIONS;
78
+ },
79
+ get TRANSLATION_KEY_PERMISSIONS () {
80
+ return TRANSLATION_KEY_PERMISSIONS;
81
+ },
82
+ get TRANSLATION_PERMISSIONS () {
83
+ return TRANSLATION_PERMISSIONS;
84
+ },
85
+ get UPLOAD_CONFIG_PERMISSIONS () {
86
+ return UPLOAD_CONFIG_PERMISSIONS;
87
+ },
64
88
  get USER_ACTION_PERMISSIONS () {
65
89
  return USER_ACTION_PERMISSIONS;
66
90
  },
@@ -135,6 +159,9 @@ const STORAGE_CONFIG_PERMISSIONS = {
135
159
  UPDATE: 'storage-config.update',
136
160
  DELETE: 'storage-config.delete'
137
161
  };
162
+ const UPLOAD_CONFIG_PERMISSIONS = {
163
+ DELETE: 'upload-config.delete'
164
+ };
138
165
  const EMAIL_CONFIG_PERMISSIONS = {
139
166
  CREATE: 'email-config.create',
140
167
  READ: 'email-config.read',
@@ -159,6 +186,68 @@ const FORM_RESULT_PERMISSIONS = {
159
186
  UPDATE: 'form-result.update',
160
187
  DELETE: 'form-result.delete'
161
188
  };
189
+ const EVENT_PERMISSIONS = {
190
+ CREATE: 'event.create',
191
+ READ: 'event.read',
192
+ UPDATE: 'event.update',
193
+ DELETE: 'event.delete'
194
+ };
195
+ const NOTIFICATION_PERMISSIONS = {
196
+ CREATE: 'notification.create',
197
+ READ: 'notification.read',
198
+ UPDATE: 'notification.update',
199
+ DELETE: 'notification.delete'
200
+ };
201
+ const LANGUAGE_PERMISSIONS = {
202
+ CREATE: 'language.create',
203
+ READ: 'language.read',
204
+ UPDATE: 'language.update',
205
+ DELETE: 'language.delete'
206
+ };
207
+ const TRANSLATION_KEY_PERMISSIONS = {
208
+ CREATE: 'translation-key.create',
209
+ READ: 'translation-key.read',
210
+ UPDATE: 'translation-key.update',
211
+ DELETE: 'translation-key.delete'
212
+ };
213
+ const TRANSLATION_PERMISSIONS = {
214
+ CREATE: 'translation.create',
215
+ READ: 'translation.read',
216
+ UPDATE: 'translation.update',
217
+ DELETE: 'translation.delete'
218
+ };
219
+ const TASK_BOARD_PERMISSIONS = {
220
+ CREATE: 'task-board.create',
221
+ READ: 'task-board.read',
222
+ UPDATE: 'task-board.update',
223
+ DELETE: 'task-board.delete',
224
+ MANAGE_MEMBERS: 'task-board.manage-members'
225
+ };
226
+ const TASK_LIST_PERMISSIONS = {
227
+ CREATE: 'task-list.create',
228
+ READ: 'task-list.read',
229
+ UPDATE: 'task-list.update',
230
+ DELETE: 'task-list.delete'
231
+ };
232
+ const TASK_PERMISSIONS = {
233
+ CREATE: 'task.create',
234
+ READ: 'task.read',
235
+ UPDATE: 'task.update',
236
+ DELETE: 'task.delete',
237
+ MOVE: 'task.move',
238
+ ASSIGN: 'task.assign'
239
+ };
240
+ const TASK_LABEL_PERMISSIONS = {
241
+ CREATE: 'task-label.create',
242
+ READ: 'task-label.read',
243
+ UPDATE: 'task-label.update',
244
+ DELETE: 'task-label.delete'
245
+ };
246
+ const TASK_COMMENT_PERMISSIONS = {
247
+ CREATE: 'task-comment.create',
248
+ READ: 'task-comment.read',
249
+ DELETE: 'task-comment.delete'
250
+ };
162
251
  const PERMISSIONS = {
163
252
  // Auth
164
253
  USER: USER_PERMISSIONS,
@@ -180,5 +269,19 @@ const PERMISSIONS = {
180
269
  EMAIL_TEMPLATE: EMAIL_TEMPLATE_PERMISSIONS,
181
270
  // Form Builder
182
271
  FORM: FORM_PERMISSIONS,
183
- FORM_RESULT: FORM_RESULT_PERMISSIONS
272
+ FORM_RESULT: FORM_RESULT_PERMISSIONS,
273
+ // Event Manager
274
+ EVENT: EVENT_PERMISSIONS,
275
+ // Notification
276
+ NOTIFICATION: NOTIFICATION_PERMISSIONS,
277
+ // Localization
278
+ LANGUAGE: LANGUAGE_PERMISSIONS,
279
+ TRANSLATION_KEY: TRANSLATION_KEY_PERMISSIONS,
280
+ TRANSLATION: TRANSLATION_PERMISSIONS,
281
+ // Task Manager
282
+ TASK_BOARD: TASK_BOARD_PERMISSIONS,
283
+ TASK_LIST: TASK_LIST_PERMISSIONS,
284
+ TASK: TASK_PERMISSIONS,
285
+ TASK_LABEL: TASK_LABEL_PERMISSIONS,
286
+ TASK_COMMENT: TASK_COMMENT_PERMISSIONS
184
287
  };
@@ -12,10 +12,9 @@ const _dtos = require("../dtos");
12
12
  const _common = require("@nestjs/common");
13
13
  const _swagger = require("@nestjs/swagger");
14
14
  const ApiResponseDto = (dto, isArray = false, arrayType = 'list')=>{
15
- // Select appropriate wrapper based on response type
16
15
  let wrapperDto;
17
16
  let metaDto = null;
18
- if (!isArray) {
17
+ if (!isArray || arrayType === 'single') {
19
18
  wrapperDto = _dtos.SingleResponseDto;
20
19
  } else if (arrayType === 'bulk') {
21
20
  wrapperDto = _dtos.BulkResponseDto;
@@ -4,9 +4,9 @@ Object.defineProperty(exports, "__esModule", {
4
4
  });
5
5
  _export_star(require("./api-response.decorator"), exports);
6
6
  _export_star(require("./current-user.decorator"), exports);
7
+ _export_star(require("./log-action.decorator"), exports);
7
8
  _export_star(require("./public.decorator"), exports);
8
9
  _export_star(require("./require-permission.decorator"), exports);
9
- _export_star(require("./sanitize-html.decorator"), exports);
10
10
  function _export_star(from, to) {
11
11
  Object.keys(from).forEach(function(k) {
12
12
  if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "LogAction", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return LogAction;
9
+ }
10
+ });
11
+ const _common = require("@nestjs/common");
12
+ const _winstonloggerclass = require("../classes/winston.logger.class");
13
+ const _loggermiddleware = require("../middlewares/logger.middleware");
14
+ function createLoggerAdapter(className, moduleName) {
15
+ if (moduleName) {
16
+ const winstonLogger = (0, _winstonloggerclass.createModuleLogger)(moduleName);
17
+ return {
18
+ log: (level, message, meta)=>{
19
+ winstonLogger.log(level, message, {
20
+ context: className,
21
+ ...meta
22
+ });
23
+ },
24
+ error: (message, stack, meta)=>{
25
+ winstonLogger.error(message, {
26
+ context: className,
27
+ stack,
28
+ ...meta
29
+ });
30
+ }
31
+ };
32
+ }
33
+ const nestLogger = new _common.Logger(className);
34
+ return {
35
+ log: (level, message, meta)=>{
36
+ nestLogger[level](message, meta);
37
+ },
38
+ error: (message, stack, meta)=>{
39
+ nestLogger.error(message, stack, meta);
40
+ }
41
+ };
42
+ }
43
+ function LogAction(options = {}) {
44
+ return function(target, propertyKey, descriptor) {
45
+ const originalMethod = descriptor.value;
46
+ const className = target.constructor.name;
47
+ const methodName = String(propertyKey);
48
+ descriptor.value = async function(...args) {
49
+ const startTime = Date.now();
50
+ // Resolve module: decorator option > instance property > undefined
51
+ const moduleName = options.module || this.moduleName;
52
+ const logger = createLoggerAdapter(className, moduleName);
53
+ const action = options.action || `${this.entityName || className}.${methodName}`;
54
+ const logLevel = options.logLevel || 'debug';
55
+ const context = {
56
+ requestId: (0, _loggermiddleware.getRequestId)(),
57
+ userId: (0, _loggermiddleware.getUserId)(),
58
+ tenantId: (0, _loggermiddleware.getTenantId)(),
59
+ companyId: (0, _loggermiddleware.getCompanyId)(),
60
+ method: methodName,
61
+ module: moduleName
62
+ };
63
+ const startMessage = `Executing action method "${action}"`;
64
+ const startContext = options.includeParams ? {
65
+ ...context,
66
+ params: sanitizeParams(args)
67
+ } : context;
68
+ logger.log(logLevel, startMessage, startContext);
69
+ try {
70
+ const result = await originalMethod.apply(this, args);
71
+ const duration = Date.now() - startTime;
72
+ const resultType = getResultType(result);
73
+ const successMessage = `Executed action method "${action}", returned result "${resultType}" in ${duration.toFixed(2)}ms.`;
74
+ const successContext = options.includeResult && result ? {
75
+ ...context,
76
+ duration: `${duration}ms`,
77
+ resultType,
78
+ resultPreview: getResultPreview(result)
79
+ } : {
80
+ ...context,
81
+ duration: `${duration}ms`,
82
+ resultType
83
+ };
84
+ logger.log(logLevel, successMessage, successContext);
85
+ return result;
86
+ } catch (error) {
87
+ const duration = Date.now() - startTime;
88
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
89
+ logger.error(`Failed action method "${action}" after ${duration.toFixed(2)}ms: ${errorMessage}`, error instanceof Error ? error.stack : undefined, {
90
+ ...context,
91
+ duration: `${duration}ms`,
92
+ error: errorMessage
93
+ });
94
+ throw error;
95
+ }
96
+ };
97
+ return descriptor;
98
+ };
99
+ }
100
+ function sanitizeParams(args) {
101
+ return args.map((arg)=>{
102
+ if (arg === null || arg === undefined) return arg;
103
+ if (typeof arg === 'object') {
104
+ const sanitized = {
105
+ ...arg
106
+ };
107
+ const sensitiveKeys = [
108
+ 'password',
109
+ 'secret',
110
+ 'token',
111
+ 'apiKey',
112
+ 'authorization'
113
+ ];
114
+ for (const key of Object.keys(sanitized)){
115
+ if (sensitiveKeys.some((sk)=>key.toLowerCase().includes(sk))) {
116
+ sanitized[key] = '[REDACTED]';
117
+ }
118
+ }
119
+ return sanitized;
120
+ }
121
+ return arg;
122
+ });
123
+ }
124
+ function getResultType(result) {
125
+ if (result === null) return 'null';
126
+ if (result === undefined) return 'undefined';
127
+ if (Array.isArray(result)) return `Array<${result.length} items>`;
128
+ if (typeof result === 'object') {
129
+ const name = result.constructor?.name;
130
+ return name && name !== 'Object' ? name : 'Object';
131
+ }
132
+ return typeof result;
133
+ }
134
+ function getResultPreview(result) {
135
+ if (Array.isArray(result)) {
136
+ return {
137
+ count: result.length,
138
+ sample: result.slice(0, 2)
139
+ };
140
+ }
141
+ if (typeof result === 'object' && result !== null) {
142
+ const keys = Object.keys(result).slice(0, 5);
143
+ return {
144
+ keys,
145
+ hasMore: Object.keys(result).length > 5
146
+ };
147
+ }
148
+ return result;
149
+ }