@nest-omni/core 4.1.3-29 → 4.1.3-30

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 (51) hide show
  1. package/audit/interceptors/audit-action.interceptor.js +1 -1
  2. package/audit/services/audit-action.service.js +1 -1
  3. package/audit/services/operation-description.service.js +1 -1
  4. package/audit/services/transaction-audit.service.js +1 -1
  5. package/email-log/email-log.constants.d.ts +8 -0
  6. package/email-log/email-log.constants.js +11 -0
  7. package/email-log/email-log.module.d.ts +47 -0
  8. package/email-log/email-log.module.js +140 -0
  9. package/email-log/index.d.ts +11 -0
  10. package/email-log/index.js +48 -0
  11. package/email-log/interfaces/email-log-options.interface.d.ts +61 -0
  12. package/email-log/interfaces/email-log-options.interface.js +134 -0
  13. package/email-log/interfaces/email-log-transport.interface.d.ts +20 -0
  14. package/email-log/interfaces/email-log-transport.interface.js +2 -0
  15. package/email-log/interfaces/index.d.ts +2 -0
  16. package/email-log/interfaces/index.js +18 -0
  17. package/email-log/providers/email-provider.d.ts +42 -0
  18. package/email-log/providers/email-provider.js +127 -0
  19. package/email-log/providers/index.d.ts +1 -0
  20. package/email-log/providers/index.js +17 -0
  21. package/email-log/services/email-log-alert.service.d.ts +46 -0
  22. package/email-log/services/email-log-alert.service.js +162 -0
  23. package/email-log/services/email-log-formatter.service.d.ts +78 -0
  24. package/email-log/services/email-log-formatter.service.js +442 -0
  25. package/email-log/services/email-log-logger.service.d.ts +85 -0
  26. package/email-log/services/email-log-logger.service.js +168 -0
  27. package/email-log/services/email-log-rate-limiter.service.d.ts +42 -0
  28. package/email-log/services/email-log-rate-limiter.service.js +110 -0
  29. package/email-log/services/email-log-transport.service.d.ts +80 -0
  30. package/email-log/services/email-log-transport.service.js +271 -0
  31. package/email-log/services/index.d.ts +5 -0
  32. package/email-log/services/index.js +21 -0
  33. package/email-log/transports/index.d.ts +1 -0
  34. package/email-log/transports/index.js +17 -0
  35. package/email-log/transports/pino-email.transport.d.ts +56 -0
  36. package/email-log/transports/pino-email.transport.js +188 -0
  37. package/email-log/utils/index.d.ts +2 -0
  38. package/email-log/utils/index.js +18 -0
  39. package/email-log/utils/log-level.helper.d.ts +46 -0
  40. package/email-log/utils/log-level.helper.js +74 -0
  41. package/email-log/utils/pino-transport.utils.d.ts +135 -0
  42. package/email-log/utils/pino-transport.utils.js +238 -0
  43. package/filters/bad-request.filter.d.ts +9 -0
  44. package/filters/bad-request.filter.js +38 -12
  45. package/index.d.ts +1 -0
  46. package/index.js +2 -0
  47. package/package.json +3 -1
  48. package/setup/bootstrap.setup.js +1 -1
  49. package/shared/service-registry.module.js +14 -0
  50. package/shared/services/api-config.service.d.ts +41 -0
  51. package/shared/services/api-config.service.js +163 -6
@@ -0,0 +1,442 @@
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 __rest = (this && this.__rest) || function (s, e) {
9
+ var t = {};
10
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
11
+ t[p] = s[p];
12
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
13
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
14
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
15
+ t[p[i]] = s[p[i]];
16
+ }
17
+ return t;
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.EmailLogFormatterService = void 0;
21
+ const common_1 = require("@nestjs/common");
22
+ const log_level_helper_1 = require("../utils/log-level.helper");
23
+ /**
24
+ * Formats log entries for email delivery
25
+ * Supports both HTML and plain text formats
26
+ */
27
+ let EmailLogFormatterService = class EmailLogFormatterService {
28
+ /**
29
+ * Format log entry as HTML email
30
+ */
31
+ formatHtml(log, appName, subjectPrefix) {
32
+ const { level, time, msg, err } = log, rest = __rest(log, ["level", "time", "msg", "err"]);
33
+ const levelLabel = this.getLevelLabel(level);
34
+ const levelColor = this.getLevelColor(level);
35
+ const timestamp = new Date(time || Date.now()).toISOString();
36
+ const subject = `${subjectPrefix} ${appName} - ${levelLabel.toUpperCase()}: ${msg || 'No message'}`;
37
+ // Separate HTTP context from other metadata
38
+ const httpContext = this.extractHttpContext(rest);
39
+ const otherMetadata = this.excludeHttpContext(rest);
40
+ const html = `
41
+ <!DOCTYPE html>
42
+ <html>
43
+ <head>
44
+ <meta charset="utf-8">
45
+ <style>
46
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif; }
47
+ .container { max-width: 900px; margin: 0 auto; padding: 20px; }
48
+ .header { border-bottom: 3px solid ${levelColor}; padding-bottom: 15px; margin-bottom: 20px; }
49
+ .level { display: inline-block; padding: 6px 14px; background: ${levelColor}; color: white; border-radius: 4px; font-weight: bold; font-size: 14px; }
50
+ .timestamp { color: #666; font-size: 14px; margin-top: 8px; }
51
+ .message { font-size: 18px; margin: 20px 0; }
52
+ .section { margin: 25px 0; }
53
+ .section-title { font-weight: bold; margin-bottom: 12px; color: #333; font-size: 16px; }
54
+ .code-block { background: #f5f5f5; border: 1px solid #ddd; border-radius: 4px; padding: 15px; overflow-x: auto; }
55
+ .code-block pre { margin: 0; white-space: pre-wrap; word-wrap: break-word; font-family: 'Monaco', 'Menlo', monospace; font-size: 13px; }
56
+ .error-stack { color: #d32f2f; }
57
+ .metadata { background: #f9f9f9; border-left: 3px solid #ddd; padding: 12px 15px; margin-top: 10px; border-radius: 4px; }
58
+ .metadata-section { background: #fafafa; border: 1px solid #e0e0e0; border-radius: 6px; padding: 15px; margin: 15px 0; }
59
+ .metadata-section-title { font-weight: bold; margin-bottom: 12px; color: #444; font-size: 15px; border-bottom: 2px solid #e0e0e0; padding-bottom: 8px; }
60
+ table { width: 100%; border-collapse: collapse; margin-top: 10px; }
61
+ th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid #ddd; }
62
+ th { background: #f5f5f5; font-weight: bold; color: #333; font-size: 13px; text-transform: uppercase; font-size: 11px; letter-spacing: 0.5px; }
63
+ td { font-size: 14px; }
64
+ tr:last-child td { border-bottom: none; }
65
+ .label { color: #666; font-size: 12px; }
66
+ .value { color: #333; }
67
+ .highlight { background: #fff3cd; padding: 2px 6px; border-radius: 3px; }
68
+ .user-info { background: #e3f2fd; border-left: 4px solid #2196f3; padding: 12px; margin: 10px 0; border-radius: 4px; }
69
+ .request-info { background: #f3e5f5; border-left: 4px solid #9c27b0; padding: 12px; margin: 10px 0; border-radius: 4px; }
70
+ </style>
71
+ </head>
72
+ <body>
73
+ <div class="container">
74
+ <div class="header">
75
+ <span class="level">${levelLabel.toUpperCase()}</span>
76
+ <div class="timestamp">${timestamp}</div>
77
+ </div>
78
+
79
+ <div class="message">${this.escapeHtml(msg || 'No message')}</div>
80
+
81
+ ${err ? this.formatError(err) : ''}
82
+
83
+ ${httpContext.request ? this.formatRequestInfo(httpContext.request) : ''}
84
+
85
+ ${httpContext.user ? this.formatUserInfo(httpContext.user) : ''}
86
+
87
+ ${Object.keys(otherMetadata).length > 0 ? this.formatMetadata('Additional Metadata', otherMetadata) : ''}
88
+ </div>
89
+ </body>
90
+ </html>`;
91
+ return { subject, html: html.trim() };
92
+ }
93
+ /**
94
+ * Format log entry as plain text
95
+ */
96
+ formatText(log, appName, subjectPrefix) {
97
+ const { level, time, msg, err } = log, rest = __rest(log, ["level", "time", "msg", "err"]);
98
+ const levelLabel = this.getLevelLabel(level);
99
+ const timestamp = new Date(time || Date.now()).toISOString();
100
+ const subject = `${subjectPrefix} ${appName} - ${levelLabel.toUpperCase()}: ${msg || 'No message'}`;
101
+ // Separate HTTP context from other metadata
102
+ const httpContext = this.extractHttpContext(rest);
103
+ const otherMetadata = this.excludeHttpContext(rest);
104
+ let text = `${levelLabel.toUpperCase()}: ${msg || 'No message'}\n`;
105
+ text += `Time: ${timestamp}\n`;
106
+ text += `App: ${appName}\n`;
107
+ if (err) {
108
+ text += `\nError:\n${this.formatErrorText(err)}`;
109
+ }
110
+ if (httpContext.request) {
111
+ text += `\n${this.formatRequestInfoText(httpContext.request)}`;
112
+ }
113
+ if (httpContext.user) {
114
+ text += `\n${this.formatUserInfoText(httpContext.user)}`;
115
+ }
116
+ if (Object.keys(otherMetadata).length > 0) {
117
+ text += `\nAdditional Metadata:\n${JSON.stringify(otherMetadata, null, 2)}`;
118
+ }
119
+ return { subject, text };
120
+ }
121
+ /**
122
+ * Extract HTTP context from log metadata
123
+ */
124
+ extractHttpContext(metadata) {
125
+ const context = {};
126
+ // Extract request information - prefer 'request' from customProps over 'req' from Pino
127
+ if (metadata.request) {
128
+ context.request = metadata.request;
129
+ }
130
+ else if (metadata.req) {
131
+ context.request = metadata.req;
132
+ }
133
+ // Extract user information
134
+ if (metadata.user) {
135
+ context.user = metadata.user;
136
+ }
137
+ // Extract response information
138
+ if (metadata.response) {
139
+ context.response = metadata.response;
140
+ }
141
+ else if (metadata.res) {
142
+ context.response = metadata.res;
143
+ }
144
+ return context;
145
+ }
146
+ /**
147
+ * Exclude HTTP context from general metadata
148
+ */
149
+ excludeHttpContext(metadata) {
150
+ const _a = metadata, { request, req, response, res, user } = _a, rest = __rest(_a, ["request", "req", "response", "res", "user"]);
151
+ return rest;
152
+ }
153
+ /**
154
+ * Format request information for HTML
155
+ */
156
+ formatRequestInfo(request) {
157
+ var _a, _b;
158
+ const info = [
159
+ { key: 'Method', value: request.method || 'N/A', highlight: true },
160
+ { key: 'Full URL', value: (request.baseUrl || '') + (request.url || 'N/A'), highlight: true },
161
+ { key: 'Path', value: request.url || 'N/A', highlight: true },
162
+ { key: 'IP Address', value: request.ip || request.remoteAddress || 'N/A' },
163
+ { key: 'Protocol', value: request.protocol || 'http' },
164
+ { key: 'Host', value: request.host || ((_a = request.headers) === null || _a === void 0 ? void 0 : _a.host) || 'N/A' },
165
+ { key: 'Port', value: ((_b = request.port) === null || _b === void 0 ? void 0 : _b.toString()) || 'N/A' },
166
+ { key: 'Request ID', value: request.id || request.requestId || 'N/A' },
167
+ ];
168
+ // Add query parameters if present
169
+ if (request.query && Object.keys(request.query).length > 0) {
170
+ info.push({
171
+ key: 'Query Params',
172
+ value: JSON.stringify(request.query, null, 2)
173
+ });
174
+ }
175
+ // Add path parameters if present
176
+ if (request.params && Object.keys(request.params).length > 0) {
177
+ info.push({
178
+ key: 'Path Params',
179
+ value: JSON.stringify(request.params, null, 2)
180
+ });
181
+ }
182
+ // Generate curl command
183
+ const curlCommand = this.generateCurlCommand(request);
184
+ return `
185
+ <div class="section">
186
+ <div class="metadata-section request-info">
187
+ <div class="metadata-section-title">🌐 HTTP Request Information</div>
188
+ <table>
189
+ ${info.map(({ key, value, highlight }) => `
190
+ <tr>
191
+ <td width="150">${key}</td>
192
+ <td class="${highlight ? 'highlight' : 'value'}">${this.escapeHtml(String(value))}</td>
193
+ </tr>
194
+ `).join('')}
195
+ </table>
196
+ ${curlCommand ? `
197
+ <div style="margin-top: 15px;">
198
+ <strong>🔧 Curl Command (click to copy):</strong>
199
+ <div class="code-block" style="background: #1e1e1e; color: #d4d4d4; position: relative;">
200
+ <pre style="color: #4ec9b0; white-space: pre-wrap; word-wrap: break-word; font-family: 'Monaco', 'Menlo', 'Courier New', monospace; font-size: 13px;">${this.escapeHtml(curlCommand)}</pre>
201
+ </div>
202
+ </div>
203
+ ` : ''}
204
+ ${request.body && Object.keys(request.body).length > 0 ? `
205
+ <div style="margin-top: 12px;">
206
+ <strong>Request Body:</strong>
207
+ <div class="code-block"><pre>${this.escapeHtml(JSON.stringify(request.body, null, 2))}</pre></div>
208
+ </div>
209
+ ` : ''}
210
+ </div>
211
+ </div>`;
212
+ }
213
+ /**
214
+ * Format request information for text
215
+ */
216
+ formatRequestInfoText(request) {
217
+ var _a;
218
+ let text = 'HTTP Request Information:\n';
219
+ text += ` Method: ${request.method || 'N/A'}\n`;
220
+ text += ` Full URL: ${(request.baseUrl || '') + (request.url || 'N/A')}\n`;
221
+ text += ` Path: ${request.url || 'N/A'}\n`;
222
+ text += ` IP: ${request.ip || request.remoteAddress || 'N/A'}\n`;
223
+ text += ` Protocol: ${request.protocol || 'http'}\n`;
224
+ text += ` Host: ${request.host || ((_a = request.headers) === null || _a === void 0 ? void 0 : _a.host) || 'N/A'}\n`;
225
+ text += ` Port: ${request.port || 'N/A'}\n`;
226
+ text += ` Request ID: ${request.id || request.requestId || 'N/A'}\n`;
227
+ if (request.query && Object.keys(request.query).length > 0) {
228
+ text += ` Query: ${JSON.stringify(request.query)}\n`;
229
+ }
230
+ if (request.params && Object.keys(request.params).length > 0) {
231
+ text += ` Params: ${JSON.stringify(request.params)}\n`;
232
+ }
233
+ if (request.body && Object.keys(request.body).length > 0) {
234
+ text += ` Body: ${JSON.stringify(request.body, null, 2)}\n`;
235
+ }
236
+ // Add curl command (single line for easy copying)
237
+ const curlCommand = this.generateCurlCommand(request);
238
+ if (curlCommand) {
239
+ text += `\n Curl Command (copy & paste):\n ${curlCommand}\n`;
240
+ }
241
+ return text;
242
+ }
243
+ /**
244
+ * Generate a curl command for the request (single line for easy copying)
245
+ */
246
+ generateCurlCommand(request) {
247
+ var _a;
248
+ if (!request.method || !request.url) {
249
+ return '';
250
+ }
251
+ // Build full URL with baseUrl (includes protocol, host, port)
252
+ const baseUrl = request.baseUrl || ((_a = request.headers) === null || _a === void 0 ? void 0 : _a.host) || '';
253
+ let fullUrl = baseUrl ? `${baseUrl}${request.url}` : request.url;
254
+ // Add query parameters to URL
255
+ if (request.query && Object.keys(request.query).length > 0) {
256
+ const queryParams = Object.entries(request.query)
257
+ .filter(([_, v]) => v !== undefined && v !== null)
258
+ .map(([k, v]) => [k, String(v)]);
259
+ const queryString = new URLSearchParams(queryParams).toString();
260
+ if (queryString) {
261
+ fullUrl += (fullUrl.includes('?') ? '&' : '?') + queryString;
262
+ }
263
+ }
264
+ // Start building curl command
265
+ const parts = [];
266
+ // Method (only show if not GET)
267
+ if (request.method && request.method.toUpperCase() !== 'GET') {
268
+ parts.push(`-X ${request.method.toUpperCase()}`);
269
+ }
270
+ // Add headers (include important headers from request)
271
+ if (request.headers) {
272
+ const headerMap = {
273
+ 'authorization': 'Authorization',
274
+ 'content-type': 'Content-Type',
275
+ 'user-agent': 'User-Agent',
276
+ 'x-request-id': 'X-Request-ID',
277
+ 'referer': 'Referer',
278
+ 'cookie': 'Cookie',
279
+ 'host': 'Host',
280
+ };
281
+ for (const [key, headerName] of Object.entries(headerMap)) {
282
+ const value = request.headers[key];
283
+ if (value) {
284
+ parts.push(`-H '${headerName}: ${value}'`);
285
+ }
286
+ }
287
+ }
288
+ // Add body if present
289
+ if (request.body && Object.keys(request.body).length > 0) {
290
+ const bodyStr = JSON.stringify(request.body);
291
+ parts.push(`-d '${bodyStr}'`);
292
+ }
293
+ // Combine all parts
294
+ let curl = 'curl';
295
+ if (parts.length > 0) {
296
+ curl += ' ' + parts.join(' ');
297
+ }
298
+ curl += ` '${fullUrl}'`;
299
+ return curl;
300
+ }
301
+ /**
302
+ * Format user information for HTML
303
+ */
304
+ formatUserInfo(user) {
305
+ const info = [
306
+ { key: 'User ID', value: user.uid || user.id || user.userId || user.sub || 'N/A' },
307
+ { key: 'Username', value: user.username || user.name || user.email || 'N/A' },
308
+ { key: 'Roles', value: user.roles ? user.roles.join(', ') : (user.role || 'N/A') },
309
+ { key: 'Tenant', value: user.tenantId || user.tenant || 'N/A' },
310
+ ];
311
+ return `
312
+ <div class="section">
313
+ <div class="metadata-section user-info">
314
+ <div class="metadata-section-title">👤 User Information</div>
315
+ <table>
316
+ ${info.map(({ key, value }) => `
317
+ <tr>
318
+ <td width="150">${key}</td>
319
+ <td class="value">${this.escapeHtml(String(value))}</td>
320
+ </tr>
321
+ `).join('')}
322
+ </table>
323
+ </div>
324
+ </div>`;
325
+ }
326
+ /**
327
+ * Format user information for text
328
+ */
329
+ formatUserInfoText(user) {
330
+ let text = 'User Information:\n';
331
+ text += ` ID: ${user.uid || user.id || user.userId || user.sub || 'N/A'}\n`;
332
+ text += ` Username: ${user.username || user.name || user.email || 'N/A'}\n`;
333
+ text += ` Roles: ${user.roles ? user.roles.join(', ') : (user.role || 'N/A')}\n`;
334
+ text += ` Tenant: ${user.tenantId || user.tenant || 'N/A'}\n`;
335
+ return text;
336
+ }
337
+ /**
338
+ * Format error object for HTML
339
+ */
340
+ formatError(err) {
341
+ const errorObj = typeof err === 'string' ? { message: err } : err;
342
+ // Get the stack trace or message
343
+ let stackTrace = errorObj.stack || errorObj.message || String(err);
344
+ // Ensure proper line breaks for stack traces that use \n
345
+ if (typeof stackTrace === 'string') {
346
+ stackTrace = stackTrace.replace(/\\n/g, '\n');
347
+ }
348
+ return `
349
+ <div class="section">
350
+ <div class="section-title">❌ Error Details</div>
351
+ ${errorObj.message && errorObj.message !== stackTrace ? `<div style="margin-bottom: 10px;"><strong>Message:</strong> <span class="highlight">${this.escapeHtml(errorObj.message)}</span></div>` : ''}
352
+ <div class="code-block error-stack">
353
+ <pre style="white-space: pre-wrap; word-wrap: break-word;">${this.escapeHtml(String(stackTrace))}</pre>
354
+ </div>
355
+ ${errorObj.type ? `<div style="margin-top: 10px;"><strong>Type:</strong> <span class="highlight">${this.escapeHtml(errorObj.type)}</span></div>` : ''}
356
+ ${errorObj.code ? `<div><strong>Code:</strong> <span class="highlight">${this.escapeHtml(String(errorObj.code))}</span></div>` : ''}
357
+ </div>`;
358
+ }
359
+ /**
360
+ * Format error object for text
361
+ */
362
+ formatErrorText(err) {
363
+ const errorObj = typeof err === 'string' ? { message: err } : err;
364
+ let text = errorObj.stack || errorObj.message || String(err);
365
+ // Fix escaped newlines in stack traces
366
+ text = text.replace(/\\n/g, '\n');
367
+ if (errorObj.type && errorObj.type !== text)
368
+ text += `\nType: ${errorObj.type}`;
369
+ if (errorObj.code)
370
+ text += `\nCode: ${errorObj.code}`;
371
+ return text;
372
+ }
373
+ /**
374
+ * Format metadata object for HTML
375
+ */
376
+ formatMetadata(title, metadata) {
377
+ const rows = Object.entries(metadata)
378
+ .filter(([_, value]) => value !== undefined && value !== null)
379
+ .map(([key, value]) => {
380
+ const displayValue = this.formatValue(value);
381
+ return `<tr><td><strong>${this.escapeHtml(key)}</strong></td><td>${displayValue}</td></tr>`;
382
+ })
383
+ .join('');
384
+ return `
385
+ <div class="section">
386
+ <div class="metadata-section">
387
+ <div class="metadata-section-title">📋 ${title}</div>
388
+ <table>
389
+ ${rows}
390
+ </table>
391
+ </div>
392
+ </div>`;
393
+ }
394
+ /**
395
+ * Format a value for HTML display
396
+ */
397
+ formatValue(value) {
398
+ if (typeof value === 'object') {
399
+ return `<div class="code-block"><pre>${this.escapeHtml(JSON.stringify(value, null, 2))}</pre></div>`;
400
+ }
401
+ return this.escapeHtml(String(value));
402
+ }
403
+ /**
404
+ * Get human-readable log level label
405
+ * Uses shared utility from log-level.helper
406
+ */
407
+ getLevelLabel(level) {
408
+ return (0, log_level_helper_1.getLevelLabel)(level);
409
+ }
410
+ /**
411
+ * Get color for log level
412
+ */
413
+ getLevelColor(level) {
414
+ const levelNum = (0, log_level_helper_1.getLevelValue)(level);
415
+ const colors = {
416
+ 10: '#9e9e9e', // trace - gray
417
+ 20: '#2196f3', // debug - blue
418
+ 30: '#4caf50', // info - green
419
+ 40: '#ff9800', // warn - orange
420
+ 50: '#f44336', // error - red
421
+ 60: '#d32f2f', // fatal - dark red
422
+ };
423
+ return colors[levelNum] || '#666';
424
+ }
425
+ /**
426
+ * Escape HTML special characters
427
+ */
428
+ escapeHtml(text) {
429
+ const map = {
430
+ '&': '&amp;',
431
+ '<': '&lt;',
432
+ '>': '&gt;',
433
+ '"': '&quot;',
434
+ "'": '&#039;',
435
+ };
436
+ return text.replace(/[&<>"']/g, (char) => map[char]);
437
+ }
438
+ };
439
+ exports.EmailLogFormatterService = EmailLogFormatterService;
440
+ exports.EmailLogFormatterService = EmailLogFormatterService = __decorate([
441
+ (0, common_1.Injectable)()
442
+ ], EmailLogFormatterService);
@@ -0,0 +1,85 @@
1
+ import { Logger, LoggerService, OnModuleInit } from '@nestjs/common';
2
+ import type { EmailLogTransportService } from './email-log-transport.service';
3
+ import type { EmailLogOptions } from '../interfaces';
4
+ /**
5
+ * Enhanced Logger service with email alert support
6
+ * This service wraps the standard NestJS Logger and adds email alert functionality
7
+ * for error and fatal level logs.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { EmailLogLogger } from '@nest-omni/core';
12
+ *
13
+ * @Injectable()
14
+ * export class MyService {
15
+ * private readonly logger = new EmailLogLogger(MyService.name);
16
+ *
17
+ * handleError() {
18
+ * this.logger.error('Something went wrong!', error.stack);
19
+ * // This will both log to console and send an email alert
20
+ * }
21
+ * }
22
+ * ```
23
+ */
24
+ export declare class EmailLogLogger extends Logger implements LoggerService, OnModuleInit {
25
+ private emailTransportService?;
26
+ private emailTransport?;
27
+ private emailOptions?;
28
+ private minLevel;
29
+ constructor(context?: string, emailTransportService?: EmailLogTransportService);
30
+ /**
31
+ * Initialize with email transport from DI
32
+ */
33
+ onModuleInit(): Promise<void>;
34
+ /**
35
+ * Set email transport manually (alternative to DI)
36
+ */
37
+ setEmailTransport(transport: EmailLogTransportService, options: EmailLogOptions): void;
38
+ /**
39
+ * Log message
40
+ */
41
+ log(message: any, context?: string): void;
42
+ /**
43
+ * Log error message
44
+ */
45
+ error(message: any, stack?: string, context?: string): void;
46
+ /**
47
+ * Log warn message
48
+ */
49
+ warn(message: any, context?: string): void;
50
+ /**
51
+ * Log debug message
52
+ */
53
+ debug(message: any, context?: string): void;
54
+ /**
55
+ * Log verbose message
56
+ */
57
+ verbose(message: any, context?: string): void;
58
+ /**
59
+ * Log fatal error message
60
+ */
61
+ fatal(message: any, stack?: string, context?: string): void;
62
+ /**
63
+ * Send email alert if needed based on log level
64
+ */
65
+ private sendEmailIfNeeded;
66
+ /**
67
+ * Check if email should be sent for the given log level
68
+ */
69
+ private shouldSendEmail;
70
+ }
71
+ /**
72
+ * Factory function to create an EmailLogLogger with email transport
73
+ * Use this in your services to get a logger with email alert support
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * import { createEmailLogger } from '@nest-omni/core';
78
+ *
79
+ * @Injectable()
80
+ * export class MyService {
81
+ * private readonly logger = createEmailLogger(MyService.name);
82
+ * }
83
+ * ```
84
+ */
85
+ export declare function createEmailLogger(context: string, emailTransport?: EmailLogTransportService, options?: EmailLogOptions): EmailLogLogger;