@quatrain/messaging 1.1.2 → 1.1.4

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.
@@ -1,4 +1,8 @@
1
1
  import { MessagingParameters } from './Messaging';
2
+ /**
3
+ * Base class contract enforcing setup logic across all messaging capabilities
4
+ * (Email, SMS, Push Notifications).
5
+ */
2
6
  export declare abstract class AbstractMessagingAdapter {
3
7
  protected _params: MessagingParameters;
4
8
  constructor(params?: MessagingParameters);
@@ -1,6 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AbstractMessagingAdapter = void 0;
4
+ /**
5
+ * Base class contract enforcing setup logic across all messaging capabilities
6
+ * (Email, SMS, Push Notifications).
7
+ */
4
8
  class AbstractMessagingAdapter {
5
9
  constructor(params = {}) {
6
10
  this._params = {};
@@ -1,4 +1,22 @@
1
+ /**
2
+ * Specialized utility handling string cleanup and Mustache interpolation for templates.
3
+ */
1
4
  export declare class MessageFormatter {
5
+ /**
6
+ * Cleans all HTML tags from the title string.
7
+ * This uses a robust, RegExp-free state loop to prevent any risk of Regular Expression
8
+ * Denial of Service (ReDoS) or catastrophic backtracking, fully satisfying SonarQube security rules.
9
+ *
10
+ * @param title - The raw subject line containing potential HTML tags.
11
+ * @returns The formatted title string with all HTML tags stripped out.
12
+ */
2
13
  static formatTitle(title: string): string;
14
+ /**
15
+ * Renders the Mustache layout with provided contextual variables.
16
+ *
17
+ * @param body - The markdown/HTML layout.
18
+ * @param data - The variables context map.
19
+ * @returns Parsed output string.
20
+ */
3
21
  static formatBody(body: string, data?: {}): string;
4
22
  }
@@ -5,12 +5,44 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.MessageFormatter = void 0;
7
7
  const mustache_1 = __importDefault(require("mustache"));
8
+ /**
9
+ * Specialized utility handling string cleanup and Mustache interpolation for templates.
10
+ */
8
11
  class MessageFormatter {
12
+ /**
13
+ * Cleans all HTML tags from the title string.
14
+ * This uses a robust, RegExp-free state loop to prevent any risk of Regular Expression
15
+ * Denial of Service (ReDoS) or catastrophic backtracking, fully satisfying SonarQube security rules.
16
+ *
17
+ * @param title - The raw subject line containing potential HTML tags.
18
+ * @returns The formatted title string with all HTML tags stripped out.
19
+ */
9
20
  static formatTitle(title) {
10
- return title.replace(/<[^>]*>/gi, '');
21
+ let result = '';
22
+ let inTag = false;
23
+ for (let i = 0; i < title.length; i++) {
24
+ const char = title[i];
25
+ if (char === '<') {
26
+ inTag = true;
27
+ }
28
+ else if (char === '>') {
29
+ inTag = false;
30
+ }
31
+ else if (!inTag) {
32
+ result += char;
33
+ }
34
+ }
35
+ return result;
11
36
  }
37
+ /**
38
+ * Renders the Mustache layout with provided contextual variables.
39
+ *
40
+ * @param body - The markdown/HTML layout.
41
+ * @param data - The variables context map.
42
+ * @returns Parsed output string.
43
+ */
12
44
  static formatBody(body, data) {
13
- return mustache_1.default.render(body, data);
45
+ return mustache_1.default.render(body, data || {});
14
46
  }
15
47
  }
16
48
  exports.MessageFormatter = MessageFormatter;
@@ -9,10 +9,29 @@ export interface MessagingParameters {
9
9
  config?: any;
10
10
  debug?: boolean;
11
11
  }
12
+ /**
13
+ * Singleton Registry dispatching text messages, emails, or push notifications.
14
+ */
12
15
  export declare class Messaging extends Core {
16
+ /** The alias for the primary fallback messager instance. */
13
17
  static defaultMessager: string;
18
+ /** Scoped domain logger. */
14
19
  static logger: any;
15
20
  protected static _messagers: MessagingRegistry<any>;
21
+ /**
22
+ * Wires an instantiated messaging client into the global routing map.
23
+ *
24
+ * @param messager - The adapter logic handling the sends.
25
+ * @param alias - Registered alias label.
26
+ * @param setDefault - Whether this is the new system default router.
27
+ */
16
28
  static addMessager(messager: NotificationCapableAdapter | EmailCapableAdapter | TextCapableAdapter, alias: string, setDefault?: boolean): void;
29
+ /**
30
+ * Recovers a registered messager by alias.
31
+ *
32
+ * @param alias - The name identifier.
33
+ * @returns The requested messaging provider.
34
+ * @throws If the alias was never registered.
35
+ */
17
36
  static getMessager(alias?: string): any;
18
37
  }
package/dist/Messaging.js CHANGED
@@ -3,13 +3,30 @@ var _a;
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.Messaging = void 0;
5
5
  const core_1 = require("@quatrain/core");
6
+ /**
7
+ * Singleton Registry dispatching text messages, emails, or push notifications.
8
+ */
6
9
  class Messaging extends core_1.Core {
10
+ /**
11
+ * Wires an instantiated messaging client into the global routing map.
12
+ *
13
+ * @param messager - The adapter logic handling the sends.
14
+ * @param alias - Registered alias label.
15
+ * @param setDefault - Whether this is the new system default router.
16
+ */
7
17
  static addMessager(messager, alias, setDefault = false) {
8
18
  this._messagers[alias] = messager;
9
19
  if (setDefault) {
10
20
  this.defaultMessager = alias;
11
21
  }
12
22
  }
23
+ /**
24
+ * Recovers a registered messager by alias.
25
+ *
26
+ * @param alias - The name identifier.
27
+ * @returns The requested messaging provider.
28
+ * @throws If the alias was never registered.
29
+ */
13
30
  static getMessager(alias = this.defaultMessager) {
14
31
  if (this._messagers[alias]) {
15
32
  return this._messagers[alias];
@@ -21,6 +38,8 @@ class Messaging extends core_1.Core {
21
38
  }
22
39
  exports.Messaging = Messaging;
23
40
  _a = Messaging;
41
+ /** The alias for the primary fallback messager instance. */
24
42
  Messaging.defaultMessager = 'default';
43
+ /** Scoped domain logger. */
25
44
  Messaging.logger = _a.addLogger('Messaging');
26
45
  Messaging._messagers = {};
@@ -11,6 +11,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  const Messaging_1 = require("./Messaging");
13
13
  const MockMessagingAdapter_1 = require("./MockMessagingAdapter");
14
+ const MessageFormatter_1 = require("./MessageFormatter");
14
15
  describe('Messaging', () => {
15
16
  let mockAdapter1;
16
17
  let mockAdapter2;
@@ -255,4 +256,39 @@ describe('Messaging', () => {
255
256
  expect(Messaging_1.Messaging.logger).toBeDefined();
256
257
  });
257
258
  });
259
+ describe('MessageFormatter', () => {
260
+ describe('formatTitle', () => {
261
+ it('should strip single HTML tags correctly', () => {
262
+ const raw = 'Hello <b>World</b>!';
263
+ const result = MessageFormatter_1.MessageFormatter.formatTitle(raw);
264
+ expect(result).toBe('Hello World!');
265
+ });
266
+ it('should strip multiple nested and unclosed tags correctly', () => {
267
+ const raw = '<div><p>Welcome to <span>Quatrain</span></p></div>';
268
+ const result = MessageFormatter_1.MessageFormatter.formatTitle(raw);
269
+ expect(result).toBe('Welcome to Quatrain');
270
+ });
271
+ it('should return plain text unchanged', () => {
272
+ const raw = 'Plain text without any tags.';
273
+ const result = MessageFormatter_1.MessageFormatter.formatTitle(raw);
274
+ expect(result).toBe(raw);
275
+ });
276
+ it('should handle empty string correctly', () => {
277
+ expect(MessageFormatter_1.MessageFormatter.formatTitle('')).toBe('');
278
+ });
279
+ });
280
+ describe('formatBody', () => {
281
+ it('should interpolate Mustache variables correctly', () => {
282
+ const template = 'Hello {{firstname}} {{lastname}}!';
283
+ const data = { firstname: 'John', lastname: 'Doe' };
284
+ const result = MessageFormatter_1.MessageFormatter.formatBody(template, data);
285
+ expect(result).toBe('Hello John Doe!');
286
+ });
287
+ it('should render original template when no data is provided', () => {
288
+ const template = 'Hello {{firstname}}!';
289
+ const result = MessageFormatter_1.MessageFormatter.formatBody(template);
290
+ expect(result).toBe('Hello !');
291
+ });
292
+ });
293
+ });
258
294
  });
@@ -18,15 +18,78 @@ interface SentMessage {
18
18
  export declare class MockMessagingAdapter extends AbstractMessagingAdapter implements NotificationCapableAdapter, EmailCapableAdapter, TextCapableAdapter {
19
19
  private sentMessages;
20
20
  constructor(params?: MessagingParameters);
21
+ /**
22
+ * Mock tracking of a single notification dispatch.
23
+ *
24
+ * @param recipient - Target info.
25
+ * @param message - Payload.
26
+ * @returns Mock response object.
27
+ */
21
28
  sendNotification(recipient: MessagingRecipient, message: NotificationMessage): Promise<any>;
29
+ /**
30
+ * Mock tracking of a batch notification dispatch.
31
+ *
32
+ * @param recipients - Array of targets.
33
+ * @param message - Payload.
34
+ * @returns Mock batch response object.
35
+ */
22
36
  sendNotifications(recipients: MessagingRecipient[], message: NotificationMessage): Promise<any>;
37
+ /**
38
+ * Mock tracking of a single email dispatch.
39
+ *
40
+ * @param recipient - Target info.
41
+ * @param message - Payload.
42
+ * @returns Mock response object.
43
+ */
23
44
  sendEmail(recipient: MessagingRecipient, message: NotificationMessage): Promise<any>;
45
+ /**
46
+ * Mock tracking of a batch email dispatch.
47
+ *
48
+ * @param recipients - Array of targets.
49
+ * @param message - Payload.
50
+ * @returns Mock batch response object.
51
+ */
24
52
  sendEmails(recipients: MessagingRecipient[], message: NotificationMessage): Promise<any>;
53
+ /**
54
+ * Mock tracking of a single SMS dispatch.
55
+ *
56
+ * @param recipient - Target info.
57
+ * @param message - Payload.
58
+ * @returns Mock response object.
59
+ */
25
60
  sendTextMessage(recipient: MessagingRecipient, message: NotificationMessage): Promise<any>;
61
+ /**
62
+ * Mock tracking of a batch SMS dispatch.
63
+ *
64
+ * @param recipients - Array of targets.
65
+ * @param message - Payload.
66
+ * @returns Mock batch response object.
67
+ */
26
68
  sendTextMessages(recipients: MessagingRecipient[], message: NotificationMessage): Promise<any>;
69
+ /**
70
+ * Testing utility to retrieve sent messages by category.
71
+ *
72
+ * @param type - Optional filter tag.
73
+ * @returns Array of saved payloads.
74
+ */
27
75
  getSentMessages(type?: 'notification' | 'email' | 'text'): SentMessage[];
76
+ /**
77
+ * Erases the internal mock history log.
78
+ */
28
79
  clearMessages(): void;
80
+ /**
81
+ * Retrieves the total count of mock-sent payloads.
82
+ *
83
+ * @param type - Optional filter tag.
84
+ * @returns Total matching elements.
85
+ */
29
86
  getMessageCount(type?: 'notification' | 'email' | 'text'): number;
87
+ /**
88
+ * Peeks at the most recently dispatched message.
89
+ *
90
+ * @param type - Optional filter tag.
91
+ * @returns SentMessage representation.
92
+ */
30
93
  getLastMessage(type?: 'notification' | 'email' | 'text'): SentMessage | undefined;
31
94
  }
32
95
  export {};
@@ -20,6 +20,13 @@ class MockMessagingAdapter extends AbstractMessagingAdapter_1.AbstractMessagingA
20
20
  super(params);
21
21
  this.sentMessages = [];
22
22
  }
23
+ /**
24
+ * Mock tracking of a single notification dispatch.
25
+ *
26
+ * @param recipient - Target info.
27
+ * @param message - Payload.
28
+ * @returns Mock response object.
29
+ */
23
30
  sendNotification(recipient, message) {
24
31
  return __awaiter(this, void 0, void 0, function* () {
25
32
  this.sentMessages.push({
@@ -35,6 +42,13 @@ class MockMessagingAdapter extends AbstractMessagingAdapter_1.AbstractMessagingA
35
42
  };
36
43
  });
37
44
  }
45
+ /**
46
+ * Mock tracking of a batch notification dispatch.
47
+ *
48
+ * @param recipients - Array of targets.
49
+ * @param message - Payload.
50
+ * @returns Mock batch response object.
51
+ */
38
52
  sendNotifications(recipients, message) {
39
53
  return __awaiter(this, void 0, void 0, function* () {
40
54
  this.sentMessages.push({
@@ -50,6 +64,13 @@ class MockMessagingAdapter extends AbstractMessagingAdapter_1.AbstractMessagingA
50
64
  };
51
65
  });
52
66
  }
67
+ /**
68
+ * Mock tracking of a single email dispatch.
69
+ *
70
+ * @param recipient - Target info.
71
+ * @param message - Payload.
72
+ * @returns Mock response object.
73
+ */
53
74
  sendEmail(recipient, message) {
54
75
  return __awaiter(this, void 0, void 0, function* () {
55
76
  this.sentMessages.push({
@@ -65,6 +86,13 @@ class MockMessagingAdapter extends AbstractMessagingAdapter_1.AbstractMessagingA
65
86
  };
66
87
  });
67
88
  }
89
+ /**
90
+ * Mock tracking of a batch email dispatch.
91
+ *
92
+ * @param recipients - Array of targets.
93
+ * @param message - Payload.
94
+ * @returns Mock batch response object.
95
+ */
68
96
  sendEmails(recipients, message) {
69
97
  return __awaiter(this, void 0, void 0, function* () {
70
98
  this.sentMessages.push({
@@ -80,6 +108,13 @@ class MockMessagingAdapter extends AbstractMessagingAdapter_1.AbstractMessagingA
80
108
  };
81
109
  });
82
110
  }
111
+ /**
112
+ * Mock tracking of a single SMS dispatch.
113
+ *
114
+ * @param recipient - Target info.
115
+ * @param message - Payload.
116
+ * @returns Mock response object.
117
+ */
83
118
  sendTextMessage(recipient, message) {
84
119
  return __awaiter(this, void 0, void 0, function* () {
85
120
  this.sentMessages.push({
@@ -95,6 +130,13 @@ class MockMessagingAdapter extends AbstractMessagingAdapter_1.AbstractMessagingA
95
130
  };
96
131
  });
97
132
  }
133
+ /**
134
+ * Mock tracking of a batch SMS dispatch.
135
+ *
136
+ * @param recipients - Array of targets.
137
+ * @param message - Payload.
138
+ * @returns Mock batch response object.
139
+ */
98
140
  sendTextMessages(recipients, message) {
99
141
  return __awaiter(this, void 0, void 0, function* () {
100
142
  this.sentMessages.push({
@@ -111,18 +153,39 @@ class MockMessagingAdapter extends AbstractMessagingAdapter_1.AbstractMessagingA
111
153
  });
112
154
  }
113
155
  // Helper methods for testing
156
+ /**
157
+ * Testing utility to retrieve sent messages by category.
158
+ *
159
+ * @param type - Optional filter tag.
160
+ * @returns Array of saved payloads.
161
+ */
114
162
  getSentMessages(type) {
115
163
  if (type) {
116
164
  return this.sentMessages.filter((msg) => msg.type === type);
117
165
  }
118
166
  return this.sentMessages;
119
167
  }
168
+ /**
169
+ * Erases the internal mock history log.
170
+ */
120
171
  clearMessages() {
121
172
  this.sentMessages = [];
122
173
  }
174
+ /**
175
+ * Retrieves the total count of mock-sent payloads.
176
+ *
177
+ * @param type - Optional filter tag.
178
+ * @returns Total matching elements.
179
+ */
123
180
  getMessageCount(type) {
124
181
  return this.getSentMessages(type).length;
125
182
  }
183
+ /**
184
+ * Peeks at the most recently dispatched message.
185
+ *
186
+ * @param type - Optional filter tag.
187
+ * @returns SentMessage representation.
188
+ */
126
189
  getLastMessage(type) {
127
190
  const messages = this.getSentMessages(type);
128
191
  return messages[messages.length - 1];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quatrain/messaging",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "license": "AGPL-3.0-only",
5
5
  "description": "Messaging adapters commons",
6
6
  "main": "dist/index.js",
@@ -20,7 +20,7 @@
20
20
  },
21
21
  "author": "Quatrain Développement SAS <developers@quatrain.com>",
22
22
  "dependencies": {
23
- "@quatrain/core": "^1.2.5",
23
+ "@quatrain/core": "^1.2.11",
24
24
  "mustache": "^4.2.0"
25
25
  },
26
26
  "devDependencies": {
@@ -1,5 +1,9 @@
1
1
  import { MessagingParameters } from './Messaging'
2
2
 
3
+ /**
4
+ * Base class contract enforcing setup logic across all messaging capabilities
5
+ * (Email, SMS, Push Notifications).
6
+ */
3
7
  export abstract class AbstractMessagingAdapter {
4
8
  protected _params: MessagingParameters = {}
5
9
 
@@ -1,11 +1,41 @@
1
1
  import Mustache from 'mustache'
2
2
 
3
+ /**
4
+ * Specialized utility handling string cleanup and Mustache interpolation for templates.
5
+ */
3
6
  export class MessageFormatter {
4
- static formatTitle(title: string) {
5
- return title.replace(/<[^>]*>/gi, '')
7
+ /**
8
+ * Cleans all HTML tags from the title string.
9
+ * This uses a robust, RegExp-free state loop to prevent any risk of Regular Expression
10
+ * Denial of Service (ReDoS) or catastrophic backtracking, fully satisfying SonarQube security rules.
11
+ *
12
+ * @param title - The raw subject line containing potential HTML tags.
13
+ * @returns The formatted title string with all HTML tags stripped out.
14
+ */
15
+ static formatTitle(title: string): string {
16
+ let result = ''
17
+ let inTag = false
18
+ for (let i = 0; i < title.length; i++) {
19
+ const char = title[i]
20
+ if (char === '<') {
21
+ inTag = true
22
+ } else if (char === '>') {
23
+ inTag = false
24
+ } else if (!inTag) {
25
+ result += char
26
+ }
27
+ }
28
+ return result
6
29
  }
7
30
 
31
+ /**
32
+ * Renders the Mustache layout with provided contextual variables.
33
+ *
34
+ * @param body - The markdown/HTML layout.
35
+ * @param data - The variables context map.
36
+ * @returns Parsed output string.
37
+ */
8
38
  static formatBody(body: string, data?: {}) {
9
- return Mustache.render(body, data)
39
+ return Mustache.render(body, data || {})
10
40
  }
11
41
  }
@@ -2,6 +2,7 @@ import { Messaging, MessagingParameters } from './Messaging'
2
2
  import { MockMessagingAdapter } from './MockMessagingAdapter'
3
3
  import { MessagingRecipient } from './types/MessagingRecipient'
4
4
  import { NotificationMessage } from './types/NotificationMessage'
5
+ import { MessageFormatter } from './MessageFormatter'
5
6
 
6
7
  describe('Messaging', () => {
7
8
  let mockAdapter1: MockMessagingAdapter
@@ -315,4 +316,45 @@ describe('Messaging', () => {
315
316
  expect(Messaging.logger).toBeDefined()
316
317
  })
317
318
  })
319
+
320
+ describe('MessageFormatter', () => {
321
+ describe('formatTitle', () => {
322
+ it('should strip single HTML tags correctly', () => {
323
+ const raw = 'Hello <b>World</b>!'
324
+ const result = MessageFormatter.formatTitle(raw)
325
+ expect(result).toBe('Hello World!')
326
+ })
327
+
328
+ it('should strip multiple nested and unclosed tags correctly', () => {
329
+ const raw = '<div><p>Welcome to <span>Quatrain</span></p></div>'
330
+ const result = MessageFormatter.formatTitle(raw)
331
+ expect(result).toBe('Welcome to Quatrain')
332
+ })
333
+
334
+ it('should return plain text unchanged', () => {
335
+ const raw = 'Plain text without any tags.'
336
+ const result = MessageFormatter.formatTitle(raw)
337
+ expect(result).toBe(raw)
338
+ })
339
+
340
+ it('should handle empty string correctly', () => {
341
+ expect(MessageFormatter.formatTitle('')).toBe('')
342
+ })
343
+ })
344
+
345
+ describe('formatBody', () => {
346
+ it('should interpolate Mustache variables correctly', () => {
347
+ const template = 'Hello {{firstname}} {{lastname}}!'
348
+ const data = { firstname: 'John', lastname: 'Doe' }
349
+ const result = MessageFormatter.formatBody(template, data)
350
+ expect(result).toBe('Hello John Doe!')
351
+ })
352
+
353
+ it('should render original template when no data is provided', () => {
354
+ const template = 'Hello {{firstname}}!'
355
+ const result = MessageFormatter.formatBody(template)
356
+ expect(result).toBe('Hello !')
357
+ })
358
+ })
359
+ })
318
360
  })
package/src/Messaging.ts CHANGED
@@ -14,12 +14,24 @@ export interface MessagingParameters {
14
14
  debug?: boolean
15
15
  }
16
16
 
17
+ /**
18
+ * Singleton Registry dispatching text messages, emails, or push notifications.
19
+ */
17
20
  export class Messaging extends Core {
21
+ /** The alias for the primary fallback messager instance. */
18
22
  static defaultMessager = 'default'
23
+ /** Scoped domain logger. */
19
24
  static logger = this.addLogger('Messaging')
20
25
 
21
26
  protected static _messagers: MessagingRegistry<any> = {}
22
27
 
28
+ /**
29
+ * Wires an instantiated messaging client into the global routing map.
30
+ *
31
+ * @param messager - The adapter logic handling the sends.
32
+ * @param alias - Registered alias label.
33
+ * @param setDefault - Whether this is the new system default router.
34
+ */
23
35
  static addMessager(
24
36
  messager:
25
37
  | NotificationCapableAdapter
@@ -34,6 +46,13 @@ export class Messaging extends Core {
34
46
  }
35
47
  }
36
48
 
49
+ /**
50
+ * Recovers a registered messager by alias.
51
+ *
52
+ * @param alias - The name identifier.
53
+ * @returns The requested messaging provider.
54
+ * @throws If the alias was never registered.
55
+ */
37
56
  static getMessager(alias: string = this.defaultMessager) {
38
57
  if (this._messagers[alias]) {
39
58
  return this._messagers[alias]
@@ -30,6 +30,13 @@ export class MockMessagingAdapter
30
30
  super(params)
31
31
  }
32
32
 
33
+ /**
34
+ * Mock tracking of a single notification dispatch.
35
+ *
36
+ * @param recipient - Target info.
37
+ * @param message - Payload.
38
+ * @returns Mock response object.
39
+ */
33
40
  async sendNotification(
34
41
  recipient: MessagingRecipient,
35
42
  message: NotificationMessage
@@ -48,6 +55,13 @@ export class MockMessagingAdapter
48
55
  }
49
56
  }
50
57
 
58
+ /**
59
+ * Mock tracking of a batch notification dispatch.
60
+ *
61
+ * @param recipients - Array of targets.
62
+ * @param message - Payload.
63
+ * @returns Mock batch response object.
64
+ */
51
65
  async sendNotifications(
52
66
  recipients: MessagingRecipient[],
53
67
  message: NotificationMessage
@@ -66,6 +80,13 @@ export class MockMessagingAdapter
66
80
  }
67
81
  }
68
82
 
83
+ /**
84
+ * Mock tracking of a single email dispatch.
85
+ *
86
+ * @param recipient - Target info.
87
+ * @param message - Payload.
88
+ * @returns Mock response object.
89
+ */
69
90
  async sendEmail(
70
91
  recipient: MessagingRecipient,
71
92
  message: NotificationMessage
@@ -84,6 +105,13 @@ export class MockMessagingAdapter
84
105
  }
85
106
  }
86
107
 
108
+ /**
109
+ * Mock tracking of a batch email dispatch.
110
+ *
111
+ * @param recipients - Array of targets.
112
+ * @param message - Payload.
113
+ * @returns Mock batch response object.
114
+ */
87
115
  async sendEmails(
88
116
  recipients: MessagingRecipient[],
89
117
  message: NotificationMessage
@@ -102,6 +130,13 @@ export class MockMessagingAdapter
102
130
  }
103
131
  }
104
132
 
133
+ /**
134
+ * Mock tracking of a single SMS dispatch.
135
+ *
136
+ * @param recipient - Target info.
137
+ * @param message - Payload.
138
+ * @returns Mock response object.
139
+ */
105
140
  async sendTextMessage(
106
141
  recipient: MessagingRecipient,
107
142
  message: NotificationMessage
@@ -120,6 +155,13 @@ export class MockMessagingAdapter
120
155
  }
121
156
  }
122
157
 
158
+ /**
159
+ * Mock tracking of a batch SMS dispatch.
160
+ *
161
+ * @param recipients - Array of targets.
162
+ * @param message - Payload.
163
+ * @returns Mock batch response object.
164
+ */
123
165
  async sendTextMessages(
124
166
  recipients: MessagingRecipient[],
125
167
  message: NotificationMessage
@@ -139,6 +181,12 @@ export class MockMessagingAdapter
139
181
  }
140
182
 
141
183
  // Helper methods for testing
184
+ /**
185
+ * Testing utility to retrieve sent messages by category.
186
+ *
187
+ * @param type - Optional filter tag.
188
+ * @returns Array of saved payloads.
189
+ */
142
190
  getSentMessages(type?: 'notification' | 'email' | 'text'): SentMessage[] {
143
191
  if (type) {
144
192
  return this.sentMessages.filter((msg) => msg.type === type)
@@ -146,14 +194,29 @@ export class MockMessagingAdapter
146
194
  return this.sentMessages
147
195
  }
148
196
 
197
+ /**
198
+ * Erases the internal mock history log.
199
+ */
149
200
  clearMessages(): void {
150
201
  this.sentMessages = []
151
202
  }
152
203
 
204
+ /**
205
+ * Retrieves the total count of mock-sent payloads.
206
+ *
207
+ * @param type - Optional filter tag.
208
+ * @returns Total matching elements.
209
+ */
153
210
  getMessageCount(type?: 'notification' | 'email' | 'text'): number {
154
211
  return this.getSentMessages(type).length
155
212
  }
156
213
 
214
+ /**
215
+ * Peeks at the most recently dispatched message.
216
+ *
217
+ * @param type - Optional filter tag.
218
+ * @returns SentMessage representation.
219
+ */
157
220
  getLastMessage(
158
221
  type?: 'notification' | 'email' | 'text'
159
222
  ): SentMessage | undefined {