nesthub 1.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.
Files changed (143) hide show
  1. package/README.md +108 -0
  2. package/dist/cache/README.md +91 -0
  3. package/dist/cache/index.d.ts +10 -0
  4. package/dist/cache/index.js +75 -0
  5. package/dist/cache/index.js.map +1 -0
  6. package/dist/cache/index.spec.d.ts +1 -0
  7. package/dist/cache/index.spec.js +61 -0
  8. package/dist/cache/index.spec.js.map +1 -0
  9. package/dist/excel/README.md +132 -0
  10. package/dist/excel/excel.module.d.ts +2 -0
  11. package/dist/excel/excel.module.js +21 -0
  12. package/dist/excel/excel.module.js.map +1 -0
  13. package/dist/excel/excel.service.d.ts +23 -0
  14. package/dist/excel/excel.service.js +124 -0
  15. package/dist/excel/excel.service.js.map +1 -0
  16. package/dist/excel/index.d.ts +2 -0
  17. package/dist/excel/index.js +8 -0
  18. package/dist/excel/index.js.map +1 -0
  19. package/dist/excel/interfaces.d.ts +19 -0
  20. package/dist/excel/interfaces.js +3 -0
  21. package/dist/excel/interfaces.js.map +1 -0
  22. package/dist/index.d.ts +1 -0
  23. package/dist/index.js +5 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/index.spec.d.ts +1 -0
  26. package/dist/index.spec.js +11 -0
  27. package/dist/index.spec.js.map +1 -0
  28. package/dist/notification/README.md +237 -0
  29. package/dist/notification/channels/channel.interface.d.ts +10 -0
  30. package/dist/notification/channels/channel.interface.js +3 -0
  31. package/dist/notification/channels/channel.interface.js.map +1 -0
  32. package/dist/notification/channels/email.channel.d.ts +11 -0
  33. package/dist/notification/channels/email.channel.js +58 -0
  34. package/dist/notification/channels/email.channel.js.map +1 -0
  35. package/dist/notification/channels/firebase.channel.d.ts +11 -0
  36. package/dist/notification/channels/firebase.channel.js +69 -0
  37. package/dist/notification/channels/firebase.channel.js.map +1 -0
  38. package/dist/notification/channels/index.d.ts +5 -0
  39. package/dist/notification/channels/index.js +12 -0
  40. package/dist/notification/channels/index.js.map +1 -0
  41. package/dist/notification/channels/sms.channel.d.ts +8 -0
  42. package/dist/notification/channels/sms.channel.js +90 -0
  43. package/dist/notification/channels/sms.channel.js.map +1 -0
  44. package/dist/notification/channels/telegram.channel.d.ts +10 -0
  45. package/dist/notification/channels/telegram.channel.js +59 -0
  46. package/dist/notification/channels/telegram.channel.js.map +1 -0
  47. package/dist/notification/email/index.d.ts +62 -0
  48. package/dist/notification/email/index.js +253 -0
  49. package/dist/notification/email/index.js.map +1 -0
  50. package/dist/notification/email/index.spec.d.ts +1 -0
  51. package/dist/notification/email/index.spec.js +121 -0
  52. package/dist/notification/email/index.spec.js.map +1 -0
  53. package/dist/notification/entities/notification-log.entity.d.ts +15 -0
  54. package/dist/notification/entities/notification-log.entity.js +82 -0
  55. package/dist/notification/entities/notification-log.entity.js.map +1 -0
  56. package/dist/notification/firebase/index.d.ts +52 -0
  57. package/dist/notification/firebase/index.js +261 -0
  58. package/dist/notification/firebase/index.js.map +1 -0
  59. package/dist/notification/firebase/index.spec.d.ts +1 -0
  60. package/dist/notification/firebase/index.spec.js +114 -0
  61. package/dist/notification/firebase/index.spec.js.map +1 -0
  62. package/dist/notification/index.d.ts +12 -0
  63. package/dist/notification/index.js +26 -0
  64. package/dist/notification/index.js.map +1 -0
  65. package/dist/notification/index.spec.d.ts +1 -0
  66. package/dist/notification/index.spec.js +336 -0
  67. package/dist/notification/index.spec.js.map +1 -0
  68. package/dist/notification/interfaces.d.ts +98 -0
  69. package/dist/notification/interfaces.js +3 -0
  70. package/dist/notification/interfaces.js.map +1 -0
  71. package/dist/notification/notification.constants.d.ts +4 -0
  72. package/dist/notification/notification.constants.js +8 -0
  73. package/dist/notification/notification.constants.js.map +1 -0
  74. package/dist/notification/notification.module.d.ts +10 -0
  75. package/dist/notification/notification.module.js +160 -0
  76. package/dist/notification/notification.module.js.map +1 -0
  77. package/dist/notification/notification.service.d.ts +14 -0
  78. package/dist/notification/notification.service.js +184 -0
  79. package/dist/notification/notification.service.js.map +1 -0
  80. package/dist/notification/queue/index.d.ts +2 -0
  81. package/dist/notification/queue/index.js +6 -0
  82. package/dist/notification/queue/index.js.map +1 -0
  83. package/dist/notification/queue/notification-queue.service.d.ts +31 -0
  84. package/dist/notification/queue/notification-queue.service.js +134 -0
  85. package/dist/notification/queue/notification-queue.service.js.map +1 -0
  86. package/dist/notification/services/index.d.ts +1 -0
  87. package/dist/notification/services/index.js +6 -0
  88. package/dist/notification/services/index.js.map +1 -0
  89. package/dist/notification/services/template.service.d.ts +13 -0
  90. package/dist/notification/services/template.service.js +75 -0
  91. package/dist/notification/services/template.service.js.map +1 -0
  92. package/dist/notification/shared.d.ts +48 -0
  93. package/dist/notification/shared.js +95 -0
  94. package/dist/notification/shared.js.map +1 -0
  95. package/dist/notification/sms/index.d.ts +52 -0
  96. package/dist/notification/sms/index.js +234 -0
  97. package/dist/notification/sms/index.js.map +1 -0
  98. package/dist/notification/sms/index.spec.d.ts +1 -0
  99. package/dist/notification/sms/index.spec.js +123 -0
  100. package/dist/notification/sms/index.spec.js.map +1 -0
  101. package/dist/notification/telegram/index.d.ts +50 -0
  102. package/dist/notification/telegram/index.js +248 -0
  103. package/dist/notification/telegram/index.js.map +1 -0
  104. package/dist/notification/telegram/index.spec.d.ts +1 -0
  105. package/dist/notification/telegram/index.spec.js +108 -0
  106. package/dist/notification/telegram/index.spec.js.map +1 -0
  107. package/dist/notification/typeorm-storage.d.ts +28 -0
  108. package/dist/notification/typeorm-storage.js +56 -0
  109. package/dist/notification/typeorm-storage.js.map +1 -0
  110. package/dist/notification/unified.d.ts +47 -0
  111. package/dist/notification/unified.js +207 -0
  112. package/dist/notification/unified.js.map +1 -0
  113. package/dist/queue/README.md +82 -0
  114. package/dist/queue/index.d.ts +14 -0
  115. package/dist/queue/index.js +17 -0
  116. package/dist/queue/index.js.map +1 -0
  117. package/dist/queue/index.spec.d.ts +1 -0
  118. package/dist/queue/index.spec.js +76 -0
  119. package/dist/queue/index.spec.js.map +1 -0
  120. package/dist/tsconfig.build.tsbuildinfo +1 -0
  121. package/dist/tsconfig.tsbuildinfo +1 -0
  122. package/dist/typeorm/README.md +197 -0
  123. package/dist/typeorm/crud-controller.d.ts +4 -0
  124. package/dist/typeorm/crud-controller.js +81 -0
  125. package/dist/typeorm/crud-controller.js.map +1 -0
  126. package/dist/typeorm/crud-service.d.ts +6 -0
  127. package/dist/typeorm/crud-service.js +53 -0
  128. package/dist/typeorm/crud-service.js.map +1 -0
  129. package/dist/typeorm/crud.interface.d.ts +9 -0
  130. package/dist/typeorm/crud.interface.js +3 -0
  131. package/dist/typeorm/crud.interface.js.map +1 -0
  132. package/dist/typeorm/index.d.ts +23 -0
  133. package/dist/typeorm/index.js +66 -0
  134. package/dist/typeorm/index.js.map +1 -0
  135. package/dist/typeorm/index.spec.d.ts +1 -0
  136. package/dist/typeorm/index.spec.js +109 -0
  137. package/dist/typeorm/index.spec.js.map +1 -0
  138. package/package.json +229 -0
  139. package/src/cache/README.md +91 -0
  140. package/src/excel/README.md +132 -0
  141. package/src/notification/README.md +237 -0
  142. package/src/queue/README.md +82 -0
  143. package/src/typeorm/README.md +197 -0
@@ -0,0 +1,10 @@
1
+ import type { SendNotificationInput, TelegramChannelConfig } from '../interfaces';
2
+ import type { NotificationChannel, SendChannelResult } from './channel.interface';
3
+ export declare class TelegramChannel implements NotificationChannel {
4
+ private config;
5
+ readonly channelType = "telegram";
6
+ private apiBase;
7
+ constructor(config: TelegramChannelConfig);
8
+ send(input: SendNotificationInput): Promise<SendChannelResult>;
9
+ private sendToChat;
10
+ }
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TelegramChannel = void 0;
4
+ class TelegramChannel {
5
+ config;
6
+ channelType = 'telegram';
7
+ apiBase;
8
+ constructor(config) {
9
+ this.config = config;
10
+ this.apiBase =
11
+ config.apiBaseUrl ?? `https://api.telegram.org/bot${config.botToken}`;
12
+ }
13
+ async send(input) {
14
+ try {
15
+ const to = Array.isArray(input.to) ? input.to : [input.to];
16
+ const results = await Promise.all(to.map((chatId) => this.sendToChat(chatId, input)));
17
+ const success = results.some((r) => r.success);
18
+ const firstSuccess = results.find((r) => r.success);
19
+ const errors = results.filter((r) => !r.success).map((r) => r.error);
20
+ return {
21
+ success,
22
+ messageId: firstSuccess?.messageId,
23
+ error: errors.length > 0 ? errors.join('; ') : undefined,
24
+ };
25
+ }
26
+ catch (error) {
27
+ const message = error instanceof Error ? error.message : String(error);
28
+ return { success: false, error: message };
29
+ }
30
+ }
31
+ async sendToChat(chatId, input) {
32
+ const payload = {
33
+ chat_id: chatId,
34
+ text: input.content,
35
+ parse_mode: 'HTML',
36
+ };
37
+ if (input.sender)
38
+ payload.username = input.sender;
39
+ const response = await fetch(`${this.apiBase}/sendMessage`, {
40
+ method: 'POST',
41
+ headers: { 'Content-Type': 'application/json' },
42
+ body: JSON.stringify(payload),
43
+ });
44
+ if (!response.ok) {
45
+ const body = await response.text();
46
+ return {
47
+ success: false,
48
+ error: `Telegram API ${response.status}: ${body}`,
49
+ };
50
+ }
51
+ const data = (await response.json());
52
+ if (!data.ok) {
53
+ return { success: false, error: 'Telegram API returned not ok' };
54
+ }
55
+ return { success: true, messageId: String(data.result?.message_id) };
56
+ }
57
+ }
58
+ exports.TelegramChannel = TelegramChannel;
59
+ //# sourceMappingURL=telegram.channel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telegram.channel.js","sourceRoot":"","sources":["../../../src/notification/channels/telegram.channel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ import type { DynamicModule, InjectionToken, OptionalFactoryDependency } from '@nestjs/common';
2
+ import type { SendMode, SendResult, NotificationStorage, NotificationTemplate } from '../shared';
3
+ export declare const EMAIL_SERVICE = "EMAIL_SERVICE";
4
+ export interface SendEmailOptions {
5
+ to: string | string[];
6
+ subject?: string;
7
+ template?: string;
8
+ context?: Record<string, unknown>;
9
+ locale?: string;
10
+ from?: string;
11
+ fromName?: string;
12
+ html?: string;
13
+ text?: string;
14
+ mode?: SendMode;
15
+ expiresAt?: Date | string;
16
+ dedupId?: string;
17
+ attachments?: Array<{
18
+ content: string;
19
+ filename: string;
20
+ type?: string;
21
+ disposition?: string;
22
+ contentId?: string;
23
+ }>;
24
+ }
25
+ export interface IEmailService {
26
+ sendEmail(options: SendEmailOptions): Promise<SendResult>;
27
+ cancelJob(dedupId: string): Promise<void>;
28
+ }
29
+ export interface EmailModuleOptions {
30
+ defaultFrom?: string;
31
+ defaultLocale?: string;
32
+ sendgrid?: {
33
+ apiKey?: string;
34
+ from?: string;
35
+ fromName?: string;
36
+ };
37
+ queue?: {
38
+ useQueue?: boolean;
39
+ connection?: {
40
+ url: string;
41
+ };
42
+ prefix?: string;
43
+ defaultJobOptions?: Record<string, unknown>;
44
+ worker?: boolean;
45
+ concurrency?: number;
46
+ };
47
+ templates?: {
48
+ dir?: string;
49
+ templates?: Record<string, NotificationTemplate>;
50
+ };
51
+ storage?: {
52
+ provider?: NotificationStorage;
53
+ typeorm?: boolean;
54
+ };
55
+ }
56
+ export declare class EmailModule {
57
+ static forRoot(options?: EmailModuleOptions): DynamicModule;
58
+ static forRootAsync(options: {
59
+ useFactory: (...args: unknown[]) => EmailModuleOptions | Promise<EmailModuleOptions>;
60
+ inject?: (InjectionToken | OptionalFactoryDependency)[];
61
+ }): DynamicModule;
62
+ }
@@ -0,0 +1,253 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ var EmailModule_1;
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.EmailModule = exports.EMAIL_SERVICE = void 0;
17
+ const common_1 = require("@nestjs/common");
18
+ const shared_1 = require("../shared");
19
+ const typeorm_storage_1 = require("../typeorm-storage");
20
+ exports.EMAIL_SERVICE = 'EMAIL_SERVICE';
21
+ let EmailServiceImpl = class EmailServiceImpl {
22
+ options;
23
+ injectedStorage;
24
+ templateService = new shared_1.TemplateService();
25
+ sendgridClient;
26
+ queueClient;
27
+ workerClient;
28
+ storage;
29
+ constructor(options, injectedStorage) {
30
+ this.options = options;
31
+ this.injectedStorage = injectedStorage;
32
+ this.storage =
33
+ injectedStorage ??
34
+ options.storage?.provider ??
35
+ new shared_1.ConsoleNotificationStorage();
36
+ }
37
+ async onModuleInit() {
38
+ const { templates, sendgrid, queue } = this.options;
39
+ if (templates?.dir)
40
+ await this.templateService.loadFromDir(templates.dir);
41
+ if (templates?.templates)
42
+ this.templateService.loadFromRecord(templates.templates);
43
+ if (sendgrid?.apiKey) {
44
+ try {
45
+ const sgModule = (await (0, shared_1.dynamicImport)('@sendgrid/mail'));
46
+ sgModule.default.setApiKey(sendgrid.apiKey);
47
+ this.sendgridClient = sgModule.default;
48
+ }
49
+ catch {
50
+ console.warn('[EmailModule] @sendgrid/mail not installed. Falling back to console.');
51
+ }
52
+ }
53
+ if (queue?.useQueue && queue?.connection?.url) {
54
+ try {
55
+ const bullmqModule = (await (0, shared_1.dynamicImport)('bullmq'));
56
+ const queueName = queue.prefix ?? 'email-notifications';
57
+ this.queueClient = new bullmqModule.Queue(queueName, {
58
+ connection: { url: queue.connection.url },
59
+ defaultJobOptions: queue.defaultJobOptions,
60
+ });
61
+ if (queue.worker !== false) {
62
+ this.workerClient = new bullmqModule.Worker(queueName, async (job) => this.processQueuedJob(job), {
63
+ connection: { url: queue.connection.url },
64
+ concurrency: queue.concurrency ?? 1,
65
+ });
66
+ }
67
+ }
68
+ catch {
69
+ console.warn('[EmailModule] bullmq not installed. Queue mode disabled.');
70
+ }
71
+ }
72
+ }
73
+ async onModuleDestroy() {
74
+ await this.workerClient?.close();
75
+ await this.queueClient?.close();
76
+ }
77
+ async sendEmail(options) {
78
+ if ((options.mode ?? 'direct') === 'queue' && this.queueClient) {
79
+ return this.enqueue(options);
80
+ }
81
+ return this.sendNow(options);
82
+ }
83
+ async cancelJob(dedupId) {
84
+ if (!this.queueClient)
85
+ return;
86
+ const record = await this.storage.findByDedupId(dedupId);
87
+ if (!record || record.status !== 'pending')
88
+ return;
89
+ try {
90
+ await this.queueClient.remove(record.id);
91
+ }
92
+ catch {
93
+ }
94
+ await this.storage.update(record.id, { status: 'cancelled' });
95
+ }
96
+ async processQueuedJob(job) {
97
+ const { data } = job;
98
+ if (data.expiresAt && new Date(data.expiresAt) < new Date()) {
99
+ await this.storage.update(job.id, {
100
+ status: 'expired',
101
+ error: 'Expired before processing',
102
+ });
103
+ return;
104
+ }
105
+ if (data.dedupId) {
106
+ const record = await this.storage.findByDedupId(data.dedupId);
107
+ if (record &&
108
+ (record.status === 'cancelled' || record.status === 'expired'))
109
+ return;
110
+ }
111
+ const result = await this.sendNow(data);
112
+ await this.storage.update(job.id, {
113
+ status: result.success ? 'sent' : 'failed',
114
+ messageId: result.messageId,
115
+ error: result.error,
116
+ sentAt: new Date().toISOString(),
117
+ });
118
+ }
119
+ async sendNow(options) {
120
+ try {
121
+ const { to, subject, template, context = {}, locale, from, fromName, html, text, attachments, } = options;
122
+ const resolvedLocale = locale ?? this.options.defaultLocale ?? 'en';
123
+ const ctx = { ...context, locale: resolvedLocale };
124
+ let resolvedHtml = html;
125
+ let resolvedText = text;
126
+ let resolvedSubject = subject;
127
+ if (template) {
128
+ const tmplName = this.templateService.resolveName(template, resolvedLocale);
129
+ if (!resolvedHtml) {
130
+ const htmlKey = `html:${tmplName}`;
131
+ resolvedHtml = this.templateService.hasTemplate(`html:${tmplName}`)
132
+ ? this.templateService.render(htmlKey, ctx)
133
+ : this.templateService.render(tmplName, ctx);
134
+ }
135
+ if (!resolvedSubject)
136
+ resolvedSubject = this.templateService.render(`subject:${tmplName}`, ctx);
137
+ if (!resolvedText)
138
+ resolvedText = this.templateService.render(`text:${tmplName}`, ctx);
139
+ }
140
+ if (!resolvedSubject && !resolvedHtml && !resolvedText) {
141
+ return { success: false, error: 'No content to send' };
142
+ }
143
+ const msg = {
144
+ to,
145
+ from: from ?? this.options.sendgrid?.from ?? this.options.defaultFrom,
146
+ subject: resolvedSubject,
147
+ };
148
+ if (resolvedHtml)
149
+ msg.html = resolvedHtml;
150
+ if (resolvedText)
151
+ msg.text = resolvedText;
152
+ if (attachments)
153
+ msg.attachments = attachments;
154
+ if (fromName)
155
+ msg.fromName = fromName;
156
+ if (this.sendgridClient) {
157
+ const [response] = await this.sendgridClient.send(msg);
158
+ const headers = response;
159
+ const messageId = headers.headers?.['x-message-id'];
160
+ return { success: true, messageId };
161
+ }
162
+ console.log('[EmailService] Email:', JSON.stringify(msg, null, 2));
163
+ return { success: true, messageId: `mock-${Date.now()}` };
164
+ }
165
+ catch (error) {
166
+ const message = error instanceof Error ? error.message : 'Unknown error';
167
+ return { success: false, error: message };
168
+ }
169
+ }
170
+ async enqueue(options) {
171
+ try {
172
+ const jobOpts = {};
173
+ if (options.dedupId)
174
+ jobOpts.deduplication = { id: options.dedupId };
175
+ const job = await this.queueClient.add('send-email', options, jobOpts);
176
+ await this.storage.save({
177
+ id: job.id ?? '',
178
+ to: Array.isArray(options.to) ? options.to.join(', ') : options.to,
179
+ subject: options.subject,
180
+ template: options.template,
181
+ channel: 'email',
182
+ status: 'pending',
183
+ expiresAt: options.expiresAt
184
+ ? new Date(options.expiresAt).toISOString()
185
+ : undefined,
186
+ dedupId: options.dedupId,
187
+ createdAt: new Date().toISOString(),
188
+ });
189
+ return { success: true, messageId: job.id, jobId: job.id };
190
+ }
191
+ catch (error) {
192
+ const message = error instanceof Error ? error.message : 'Unknown error';
193
+ return { success: false, error: message };
194
+ }
195
+ }
196
+ };
197
+ EmailServiceImpl = __decorate([
198
+ (0, common_1.Injectable)(),
199
+ __param(0, (0, common_1.Inject)('EMAIL_MODULE_OPTIONS')),
200
+ __param(1, (0, common_1.Optional)()),
201
+ __param(1, (0, common_1.Inject)(shared_1.NOTIFICATION_STORAGE)),
202
+ __metadata("design:paramtypes", [Object, Object])
203
+ ], EmailServiceImpl);
204
+ let EmailModule = EmailModule_1 = class EmailModule {
205
+ static forRoot(options = {}) {
206
+ const providers = [
207
+ { provide: 'EMAIL_MODULE_OPTIONS', useValue: options },
208
+ { provide: exports.EMAIL_SERVICE, useClass: EmailServiceImpl },
209
+ ];
210
+ const imports = [];
211
+ if (options.storage?.typeorm) {
212
+ try {
213
+ const { TypeOrmModule, getRepositoryToken } = (0, typeorm_storage_1.getTypeOrmHelpers)();
214
+ const entity = (0, typeorm_storage_1.getOrCreateEntity)();
215
+ imports.push(TypeOrmModule.forFeature([entity]));
216
+ providers.push({
217
+ provide: shared_1.NOTIFICATION_STORAGE,
218
+ useFactory: (repo) => new typeorm_storage_1.TypeOrmNotificationStorage(repo),
219
+ inject: [getRepositoryToken(entity)],
220
+ });
221
+ }
222
+ catch {
223
+ throw new Error('EmailModule: @nestjs/typeorm and typeorm must be installed when storage.typeorm is true');
224
+ }
225
+ }
226
+ return {
227
+ module: EmailModule_1,
228
+ imports,
229
+ providers,
230
+ exports: [exports.EMAIL_SERVICE],
231
+ };
232
+ }
233
+ static forRootAsync(options) {
234
+ return {
235
+ module: EmailModule_1,
236
+ providers: [
237
+ {
238
+ provide: 'EMAIL_MODULE_OPTIONS',
239
+ useFactory: options.useFactory,
240
+ inject: options.inject ?? [],
241
+ },
242
+ { provide: exports.EMAIL_SERVICE, useClass: EmailServiceImpl },
243
+ ],
244
+ exports: [exports.EMAIL_SERVICE],
245
+ };
246
+ }
247
+ };
248
+ exports.EmailModule = EmailModule;
249
+ exports.EmailModule = EmailModule = EmailModule_1 = __decorate([
250
+ (0, common_1.Global)(),
251
+ (0, common_1.Module)({})
252
+ ], EmailModule);
253
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/notification/email/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ let nextJobId = 1;
4
+ jest.mock('bullmq', () => ({
5
+ Queue: jest.fn().mockImplementation(() => ({
6
+ add: jest
7
+ .fn()
8
+ .mockImplementation(() => Promise.resolve({ id: `email-job-${nextJobId++}` })),
9
+ remove: jest.fn().mockResolvedValue(undefined),
10
+ close: jest.fn().mockResolvedValue(undefined),
11
+ })),
12
+ Worker: jest.fn().mockImplementation(() => ({
13
+ close: jest.fn().mockResolvedValue(undefined),
14
+ })),
15
+ }));
16
+ const testing_1 = require("@nestjs/testing");
17
+ const index_1 = require("./index");
18
+ describe('@vn.chemgio/nestjs-utilities/notification/email', () => {
19
+ let service;
20
+ let module;
21
+ afterEach(async () => {
22
+ if (module)
23
+ await module.close();
24
+ });
25
+ it('should send email via console fallback', async () => {
26
+ module = await testing_1.Test.createTestingModule({
27
+ imports: [index_1.EmailModule.forRoot({ defaultFrom: 'test@example.com' })],
28
+ }).compile();
29
+ await module.init();
30
+ service = module.get(index_1.EMAIL_SERVICE);
31
+ const result = await service.sendEmail({
32
+ to: 'user@example.com',
33
+ subject: 'Test',
34
+ html: '<p>Hi</p>',
35
+ });
36
+ expect(result.success).toBe(true);
37
+ expect(result.messageId).toMatch(/^mock-/);
38
+ });
39
+ it('should return no-content error', async () => {
40
+ module = await testing_1.Test.createTestingModule({
41
+ imports: [index_1.EmailModule.forRoot({})],
42
+ }).compile();
43
+ await module.init();
44
+ service = module.get(index_1.EMAIL_SERVICE);
45
+ const result = await service.sendEmail({ to: 'user@example.com' });
46
+ expect(result.success).toBe(false);
47
+ expect(result.error).toBe('No content to send');
48
+ });
49
+ it('should render handlebars template', async () => {
50
+ module = await testing_1.Test.createTestingModule({
51
+ imports: [
52
+ index_1.EmailModule.forRoot({
53
+ defaultFrom: 'test@example.com',
54
+ templates: {
55
+ templates: {
56
+ hello: { subject: 'Hi {{name}}', html: '<p>Hello {{name}}</p>' },
57
+ },
58
+ },
59
+ }),
60
+ ],
61
+ }).compile();
62
+ await module.init();
63
+ service = module.get(index_1.EMAIL_SERVICE);
64
+ const result = await service.sendEmail({
65
+ to: 'u@e.com',
66
+ template: 'hello',
67
+ context: { name: 'Alice' },
68
+ });
69
+ expect(result.success).toBe(true);
70
+ });
71
+ it('should queue email and save pending record', async () => {
72
+ module = await testing_1.Test.createTestingModule({
73
+ imports: [
74
+ index_1.EmailModule.forRoot({
75
+ defaultFrom: 'test@example.com',
76
+ queue: {
77
+ useQueue: true,
78
+ connection: { url: 'redis://localhost:6379' },
79
+ worker: false,
80
+ },
81
+ }),
82
+ ],
83
+ }).compile();
84
+ await module.init();
85
+ service = module.get(index_1.EMAIL_SERVICE);
86
+ const result = await service.sendEmail({
87
+ to: 'user@example.com',
88
+ subject: 'Queued',
89
+ html: '<p>Queued</p>',
90
+ mode: 'queue',
91
+ });
92
+ expect(result.success).toBe(true);
93
+ expect(result.jobId).toMatch(/^email-job-/);
94
+ });
95
+ it('should cancel a pending job by dedupId', async () => {
96
+ module = await testing_1.Test.createTestingModule({
97
+ imports: [
98
+ index_1.EmailModule.forRoot({
99
+ defaultFrom: 'test@example.com',
100
+ queue: {
101
+ useQueue: true,
102
+ connection: { url: 'redis://localhost:6379' },
103
+ worker: false,
104
+ },
105
+ }),
106
+ ],
107
+ }).compile();
108
+ await module.init();
109
+ service = module.get(index_1.EMAIL_SERVICE);
110
+ const sendResult = await service.sendEmail({
111
+ to: 'user@example.com',
112
+ subject: 'Cancel test',
113
+ html: '<p>Test</p>',
114
+ mode: 'queue',
115
+ dedupId: 'email-cancel-test',
116
+ });
117
+ expect(sendResult.success).toBe(true);
118
+ await service.cancelJob('email-cancel-test');
119
+ });
120
+ });
121
+ //# sourceMappingURL=index.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.spec.js","sourceRoot":"","sources":["../../../src/notification/email/index.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export type NotificationStatus = 'pending' | 'sending' | 'sent' | 'failed' | 'expired';
2
+ export declare class NotificationLog {
3
+ id: string;
4
+ channel: string;
5
+ to: string | string[];
6
+ subject?: string;
7
+ status: NotificationStatus;
8
+ content?: string;
9
+ messageId?: string;
10
+ error?: string;
11
+ metadata?: Record<string, unknown>;
12
+ createdAt: Date;
13
+ updatedAt: Date;
14
+ sentAt?: Date;
15
+ }
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.NotificationLog = void 0;
13
+ const typeorm_1 = require("typeorm");
14
+ let NotificationLog = class NotificationLog {
15
+ id;
16
+ channel;
17
+ to;
18
+ subject;
19
+ status;
20
+ content;
21
+ messageId;
22
+ error;
23
+ metadata;
24
+ createdAt;
25
+ updatedAt;
26
+ sentAt;
27
+ };
28
+ exports.NotificationLog = NotificationLog;
29
+ __decorate([
30
+ (0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
31
+ __metadata("design:type", String)
32
+ ], NotificationLog.prototype, "id", void 0);
33
+ __decorate([
34
+ (0, typeorm_1.Column)({ name: 'channel', length: 20 }),
35
+ (0, typeorm_1.Index)(),
36
+ __metadata("design:type", String)
37
+ ], NotificationLog.prototype, "channel", void 0);
38
+ __decorate([
39
+ (0, typeorm_1.Column)('simple-json', { name: 'recipient_to' }),
40
+ __metadata("design:type", Object)
41
+ ], NotificationLog.prototype, "to", void 0);
42
+ __decorate([
43
+ (0, typeorm_1.Column)({ name: 'subject', nullable: true }),
44
+ __metadata("design:type", String)
45
+ ], NotificationLog.prototype, "subject", void 0);
46
+ __decorate([
47
+ (0, typeorm_1.Column)({ name: 'status', length: 20, default: 'pending' }),
48
+ (0, typeorm_1.Index)(),
49
+ __metadata("design:type", String)
50
+ ], NotificationLog.prototype, "status", void 0);
51
+ __decorate([
52
+ (0, typeorm_1.Column)('text', { name: 'content', nullable: true }),
53
+ __metadata("design:type", String)
54
+ ], NotificationLog.prototype, "content", void 0);
55
+ __decorate([
56
+ (0, typeorm_1.Column)({ name: 'message_id', nullable: true }),
57
+ __metadata("design:type", String)
58
+ ], NotificationLog.prototype, "messageId", void 0);
59
+ __decorate([
60
+ (0, typeorm_1.Column)('text', { name: 'error', nullable: true }),
61
+ __metadata("design:type", String)
62
+ ], NotificationLog.prototype, "error", void 0);
63
+ __decorate([
64
+ (0, typeorm_1.Column)('simple-json', { name: 'metadata', nullable: true }),
65
+ __metadata("design:type", Object)
66
+ ], NotificationLog.prototype, "metadata", void 0);
67
+ __decorate([
68
+ (0, typeorm_1.CreateDateColumn)({ name: 'created_at' }),
69
+ __metadata("design:type", Date)
70
+ ], NotificationLog.prototype, "createdAt", void 0);
71
+ __decorate([
72
+ (0, typeorm_1.UpdateDateColumn)({ name: 'updated_at' }),
73
+ __metadata("design:type", Date)
74
+ ], NotificationLog.prototype, "updatedAt", void 0);
75
+ __decorate([
76
+ (0, typeorm_1.Column)({ name: 'sent_at', nullable: true }),
77
+ __metadata("design:type", Date)
78
+ ], NotificationLog.prototype, "sentAt", void 0);
79
+ exports.NotificationLog = NotificationLog = __decorate([
80
+ (0, typeorm_1.Entity)('notification_logs')
81
+ ], NotificationLog);
82
+ //# sourceMappingURL=notification-log.entity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notification-log.entity.js","sourceRoot":"","sources":["../../../src/notification/entities/notification-log.entity.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qCAOiB;AAUV,IAAM,eAAe,GAArB,MAAM,eAAe;IAE1B,EAAE,CAAS;IAIX,OAAO,CAAS;IAGhB,EAAE,CAAoB;IAGtB,OAAO,CAAU;IAIjB,MAAM,CAAqB;IAG3B,OAAO,CAAU;IAGjB,SAAS,CAAU;IAGnB,KAAK,CAAU;IAGf,QAAQ,CAA2B;IAGnC,SAAS,CAAO;IAGhB,SAAS,CAAO;IAGhB,MAAM,CAAQ;CACf,CAAA;AAtCY,0CAAe;AAE1B;IADC,IAAA,gCAAsB,EAAC,MAAM,CAAC;;2CACpB;AAIX;IAFC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACvC,IAAA,eAAK,GAAE;;gDACQ;AAGhB;IADC,IAAA,gBAAM,EAAC,aAAa,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;;2CAC1B;AAGtB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;gDAC3B;AAIjB;IAFC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;IAC1D,IAAA,eAAK,GAAE;;+CACmB;AAG3B;IADC,IAAA,gBAAM,EAAC,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;gDACnC;AAGjB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;kDAC5B;AAGnB;IADC,IAAA,gBAAM,EAAC,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;8CACnC;AAGf;IADC,IAAA,gBAAM,EAAC,aAAa,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;iDACzB;AAGnC;IADC,IAAA,0BAAgB,EAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;8BAC9B,IAAI;kDAAC;AAGhB;IADC,IAAA,0BAAgB,EAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;8BAC9B,IAAI;kDAAC;AAGhB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;8BACnC,IAAI;+CAAC;0BArCH,eAAe;IAD3B,IAAA,gBAAM,EAAC,mBAAmB,CAAC;GACf,eAAe,CAsC3B"}