@hazeljs/messaging 0.2.0-alpha.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 (123) hide show
  1. package/LICENSE +192 -0
  2. package/README.md +190 -0
  3. package/dist/adapters/slack.adapter.d.ts +20 -0
  4. package/dist/adapters/slack.adapter.d.ts.map +1 -0
  5. package/dist/adapters/slack.adapter.js +28 -0
  6. package/dist/adapters/slack.adapter.js.map +1 -0
  7. package/dist/adapters/slack.adapter.test.d.ts +2 -0
  8. package/dist/adapters/slack.adapter.test.d.ts.map +1 -0
  9. package/dist/adapters/slack.adapter.test.js +56 -0
  10. package/dist/adapters/slack.adapter.test.js.map +1 -0
  11. package/dist/adapters/teams.adapter.d.ts +20 -0
  12. package/dist/adapters/teams.adapter.d.ts.map +1 -0
  13. package/dist/adapters/teams.adapter.js +28 -0
  14. package/dist/adapters/teams.adapter.js.map +1 -0
  15. package/dist/adapters/teams.adapter.test.d.ts +2 -0
  16. package/dist/adapters/teams.adapter.test.d.ts.map +1 -0
  17. package/dist/adapters/teams.adapter.test.js +56 -0
  18. package/dist/adapters/teams.adapter.test.js.map +1 -0
  19. package/dist/adapters/telegram.adapter.d.ts +24 -0
  20. package/dist/adapters/telegram.adapter.d.ts.map +1 -0
  21. package/dist/adapters/telegram.adapter.js +70 -0
  22. package/dist/adapters/telegram.adapter.js.map +1 -0
  23. package/dist/adapters/telegram.adapter.test.d.ts +2 -0
  24. package/dist/adapters/telegram.adapter.test.d.ts.map +1 -0
  25. package/dist/adapters/telegram.adapter.test.js +154 -0
  26. package/dist/adapters/telegram.adapter.test.js.map +1 -0
  27. package/dist/adapters/viber.adapter.d.ts +29 -0
  28. package/dist/adapters/viber.adapter.d.ts.map +1 -0
  29. package/dist/adapters/viber.adapter.js +98 -0
  30. package/dist/adapters/viber.adapter.js.map +1 -0
  31. package/dist/adapters/viber.adapter.test.d.ts +2 -0
  32. package/dist/adapters/viber.adapter.test.d.ts.map +1 -0
  33. package/dist/adapters/viber.adapter.test.js +89 -0
  34. package/dist/adapters/viber.adapter.test.js.map +1 -0
  35. package/dist/adapters/whatsapp.adapter.d.ts +26 -0
  36. package/dist/adapters/whatsapp.adapter.d.ts.map +1 -0
  37. package/dist/adapters/whatsapp.adapter.js +87 -0
  38. package/dist/adapters/whatsapp.adapter.js.map +1 -0
  39. package/dist/adapters/whatsapp.adapter.test.d.ts +2 -0
  40. package/dist/adapters/whatsapp.adapter.test.d.ts.map +1 -0
  41. package/dist/adapters/whatsapp.adapter.test.js +198 -0
  42. package/dist/adapters/whatsapp.adapter.test.js.map +1 -0
  43. package/dist/index.d.ts +28 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +31 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/messaging-kafka.bootstrap.d.ts +14 -0
  48. package/dist/messaging-kafka.bootstrap.d.ts.map +1 -0
  49. package/dist/messaging-kafka.bootstrap.js +42 -0
  50. package/dist/messaging-kafka.bootstrap.js.map +1 -0
  51. package/dist/messaging-kafka.bootstrap.test.d.ts +2 -0
  52. package/dist/messaging-kafka.bootstrap.test.d.ts.map +1 -0
  53. package/dist/messaging-kafka.bootstrap.test.js +34 -0
  54. package/dist/messaging-kafka.bootstrap.test.js.map +1 -0
  55. package/dist/messaging-kafka.consumer.d.ts +10 -0
  56. package/dist/messaging-kafka.consumer.d.ts.map +1 -0
  57. package/dist/messaging-kafka.consumer.js +80 -0
  58. package/dist/messaging-kafka.consumer.js.map +1 -0
  59. package/dist/messaging-kafka.consumer.test.d.ts +2 -0
  60. package/dist/messaging-kafka.consumer.test.d.ts.map +1 -0
  61. package/dist/messaging-kafka.consumer.test.js +129 -0
  62. package/dist/messaging-kafka.consumer.test.js.map +1 -0
  63. package/dist/messaging-kafka.types.d.ts +10 -0
  64. package/dist/messaging-kafka.types.d.ts.map +1 -0
  65. package/dist/messaging-kafka.types.js +5 -0
  66. package/dist/messaging-kafka.types.js.map +1 -0
  67. package/dist/messaging-kafka.types.test.d.ts +2 -0
  68. package/dist/messaging-kafka.types.test.d.ts.map +1 -0
  69. package/dist/messaging-kafka.types.test.js +12 -0
  70. package/dist/messaging-kafka.types.test.js.map +1 -0
  71. package/dist/messaging.controller.d.ts +27 -0
  72. package/dist/messaging.controller.d.ts.map +1 -0
  73. package/dist/messaging.controller.js +151 -0
  74. package/dist/messaging.controller.js.map +1 -0
  75. package/dist/messaging.controller.test.d.ts +2 -0
  76. package/dist/messaging.controller.test.d.ts.map +1 -0
  77. package/dist/messaging.controller.test.js +221 -0
  78. package/dist/messaging.controller.test.js.map +1 -0
  79. package/dist/messaging.module.d.ts +75 -0
  80. package/dist/messaging.module.d.ts.map +1 -0
  81. package/dist/messaging.module.js +160 -0
  82. package/dist/messaging.module.js.map +1 -0
  83. package/dist/messaging.module.test.d.ts +2 -0
  84. package/dist/messaging.module.test.d.ts.map +1 -0
  85. package/dist/messaging.module.test.js +147 -0
  86. package/dist/messaging.module.test.js.map +1 -0
  87. package/dist/messaging.service.d.ts +42 -0
  88. package/dist/messaging.service.d.ts.map +1 -0
  89. package/dist/messaging.service.js +109 -0
  90. package/dist/messaging.service.js.map +1 -0
  91. package/dist/messaging.service.test.d.ts +2 -0
  92. package/dist/messaging.service.test.d.ts.map +1 -0
  93. package/dist/messaging.service.test.js +163 -0
  94. package/dist/messaging.service.test.js.map +1 -0
  95. package/dist/store/conversation-context.interface.d.ts +17 -0
  96. package/dist/store/conversation-context.interface.d.ts.map +1 -0
  97. package/dist/store/conversation-context.interface.js +7 -0
  98. package/dist/store/conversation-context.interface.js.map +1 -0
  99. package/dist/store/memory-conversation-context.d.ts +11 -0
  100. package/dist/store/memory-conversation-context.d.ts.map +1 -0
  101. package/dist/store/memory-conversation-context.js +22 -0
  102. package/dist/store/memory-conversation-context.js.map +1 -0
  103. package/dist/store/memory-conversation-context.test.d.ts +2 -0
  104. package/dist/store/memory-conversation-context.test.d.ts.map +1 -0
  105. package/dist/store/memory-conversation-context.test.js +69 -0
  106. package/dist/store/memory-conversation-context.test.js.map +1 -0
  107. package/dist/store/redis-conversation-context.d.ts +24 -0
  108. package/dist/store/redis-conversation-context.d.ts.map +1 -0
  109. package/dist/store/redis-conversation-context.js +37 -0
  110. package/dist/store/redis-conversation-context.js.map +1 -0
  111. package/dist/store/redis-conversation-context.test.d.ts +2 -0
  112. package/dist/store/redis-conversation-context.test.d.ts.map +1 -0
  113. package/dist/store/redis-conversation-context.test.js +85 -0
  114. package/dist/store/redis-conversation-context.test.js.map +1 -0
  115. package/dist/types/message.types.d.ts +55 -0
  116. package/dist/types/message.types.d.ts.map +1 -0
  117. package/dist/types/message.types.js +7 -0
  118. package/dist/types/message.types.js.map +1 -0
  119. package/dist/types/response-handler.types.d.ts +47 -0
  120. package/dist/types/response-handler.types.d.ts.map +1 -0
  121. package/dist/types/response-handler.types.js +3 -0
  122. package/dist/types/response-handler.types.js.map +1 -0
  123. package/package.json +88 -0
@@ -0,0 +1,198 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * WhatsAppAdapter tests
5
+ */
6
+ const whatsapp_adapter_1 = require("./whatsapp.adapter");
7
+ const originalFetch = globalThis.fetch;
8
+ describe('WhatsAppAdapter', () => {
9
+ let adapter;
10
+ let mockFetch;
11
+ beforeEach(() => {
12
+ mockFetch = jest.fn();
13
+ globalThis.fetch = mockFetch;
14
+ adapter = new whatsapp_adapter_1.WhatsAppAdapter({
15
+ accessToken: 'test-token',
16
+ phoneNumberId: '123456789',
17
+ });
18
+ });
19
+ afterEach(() => {
20
+ globalThis.fetch = originalFetch;
21
+ });
22
+ describe('channel', () => {
23
+ it('has channel whatsapp', () => {
24
+ expect(adapter.channel).toBe('whatsapp');
25
+ });
26
+ });
27
+ describe('parseIncoming', () => {
28
+ it('returns null for empty payload', () => {
29
+ expect(adapter.parseIncoming({})).toBeNull();
30
+ });
31
+ it('parses single text message', () => {
32
+ const payload = {
33
+ entry: [
34
+ {
35
+ changes: [
36
+ {
37
+ value: {
38
+ messages: [
39
+ {
40
+ id: 'wamid.abc',
41
+ from: '1234567890',
42
+ timestamp: '1609459200',
43
+ type: 'text',
44
+ text: { body: 'Hello from user' },
45
+ },
46
+ ],
47
+ },
48
+ },
49
+ ],
50
+ },
51
+ ],
52
+ };
53
+ const result = adapter.parseIncoming(payload);
54
+ expect(result).not.toBeNull();
55
+ const msg = Array.isArray(result) ? result[0] : result;
56
+ expect(msg).toBeDefined();
57
+ expect(msg.id).toBe('wamid.abc');
58
+ expect(msg.channel).toBe('whatsapp');
59
+ expect(msg.conversationId).toBe('1234567890');
60
+ expect(msg.userId).toBe('1234567890');
61
+ expect(msg.text).toBe('Hello from user');
62
+ expect(msg.sessionId).toBe('whatsapp:1234567890');
63
+ });
64
+ it('parses multiple messages', () => {
65
+ const payload = {
66
+ entry: [
67
+ {
68
+ changes: [
69
+ {
70
+ value: {
71
+ messages: [
72
+ { id: '1', from: 'u1', timestamp: '1', type: 'text', text: { body: 'A' } },
73
+ { id: '2', from: 'u1', timestamp: '2', type: 'text', text: { body: 'B' } },
74
+ ],
75
+ },
76
+ },
77
+ ],
78
+ },
79
+ ],
80
+ };
81
+ const result = adapter.parseIncoming(payload);
82
+ expect(Array.isArray(result)).toBe(true);
83
+ expect(result.length).toBe(2);
84
+ });
85
+ it('includes contact name when available', () => {
86
+ const payload = {
87
+ entry: [
88
+ {
89
+ changes: [
90
+ {
91
+ value: {
92
+ messages: [
93
+ {
94
+ id: '1',
95
+ from: '123',
96
+ timestamp: '1',
97
+ type: 'text',
98
+ text: { body: 'Hi' },
99
+ },
100
+ ],
101
+ contacts: [{ profile: { name: 'John Doe' } }],
102
+ },
103
+ },
104
+ ],
105
+ },
106
+ ],
107
+ };
108
+ const result = adapter.parseIncoming(payload);
109
+ const msg = Array.isArray(result) ? result[0] : result;
110
+ expect(msg?.userName).toBe('John Doe');
111
+ });
112
+ it('skips non-text messages', () => {
113
+ const payload = {
114
+ entry: [
115
+ {
116
+ changes: [
117
+ {
118
+ value: {
119
+ messages: [
120
+ { id: '1', from: 'u1', timestamp: '1', type: 'image' },
121
+ { id: '2', from: 'u1', timestamp: '2', type: 'text' },
122
+ ],
123
+ },
124
+ },
125
+ ],
126
+ },
127
+ ],
128
+ };
129
+ const result = adapter.parseIncoming(payload);
130
+ const msg = Array.isArray(result) ? result[0] : result;
131
+ expect(msg?.text).toBeUndefined();
132
+ expect(msg).toBeNull();
133
+ });
134
+ it('returns null when no messages in entry', () => {
135
+ const payload = { entry: [{ changes: [{ value: {} }] }] };
136
+ expect(adapter.parseIncoming(payload)).toBeNull();
137
+ });
138
+ });
139
+ describe('send', () => {
140
+ it('sends message via Graph API', async () => {
141
+ mockFetch.mockResolvedValue({ ok: true, json: async () => ({}) });
142
+ await adapter.send({
143
+ conversationId: '1234567890',
144
+ text: 'Hello back',
145
+ replyToMessageId: 'wamid.xyz',
146
+ });
147
+ expect(mockFetch).toHaveBeenCalledWith(expect.stringContaining('graph.facebook.com'), expect.objectContaining({
148
+ method: 'POST',
149
+ headers: expect.objectContaining({
150
+ Authorization: 'Bearer test-token',
151
+ 'Content-Type': 'application/json',
152
+ }),
153
+ body: expect.stringContaining('Hello back'),
154
+ }));
155
+ const body = JSON.parse(mockFetch.mock.calls[0][1].body);
156
+ expect(body.to).toBe('1234567890');
157
+ expect(body.context?.message_id).toBe('wamid.xyz');
158
+ });
159
+ it('strips non-digits from conversationId', async () => {
160
+ mockFetch.mockResolvedValue({ ok: true, json: async () => ({}) });
161
+ await adapter.send({
162
+ conversationId: '+1 (234) 567-8901',
163
+ text: 'Hi',
164
+ });
165
+ const body = JSON.parse(mockFetch.mock.calls[0][1].body);
166
+ expect(body.to).toBe('12345678901');
167
+ });
168
+ it('throws on API error', async () => {
169
+ mockFetch.mockResolvedValue({ ok: false, text: async () => 'Invalid token' });
170
+ await expect(adapter.send({ conversationId: '123', text: 'Hi' })).rejects.toThrow('WhatsApp API error');
171
+ });
172
+ });
173
+ describe('verifyWebhook', () => {
174
+ const originalEnv = process.env;
175
+ beforeEach(() => {
176
+ process.env = { ...originalEnv };
177
+ });
178
+ afterEach(() => {
179
+ process.env = originalEnv;
180
+ });
181
+ it('returns true when hub.mode=subscribe and verify_token matches', () => {
182
+ process.env.WHATSAPP_VERIFY_TOKEN = 'my-secret';
183
+ const q = { 'hub.mode': 'subscribe', 'hub.verify_token': 'my-secret' };
184
+ expect(adapter.verifyWebhook(q)).toBe(true);
185
+ });
186
+ it('returns false when verify_token does not match', () => {
187
+ process.env.WHATSAPP_VERIFY_TOKEN = 'my-secret';
188
+ const q = { 'hub.mode': 'subscribe', 'hub.verify_token': 'wrong' };
189
+ expect(adapter.verifyWebhook(q)).toBe(false);
190
+ });
191
+ it('returns false when WHATSAPP_VERIFY_TOKEN not set', () => {
192
+ delete process.env.WHATSAPP_VERIFY_TOKEN;
193
+ const q = { 'hub.mode': 'subscribe', 'hub.verify_token': 'x' };
194
+ expect(adapter.verifyWebhook(q)).toBe(false);
195
+ });
196
+ });
197
+ });
198
+ //# sourceMappingURL=whatsapp.adapter.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whatsapp.adapter.test.js","sourceRoot":"","sources":["../../src/adapters/whatsapp.adapter.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @hazeljs/messaging
3
+ * Multichannel messaging - WhatsApp, Telegram, Viber with LLM-powered bot responses
4
+ */
5
+ export { MessagingModule } from './messaging.module';
6
+ export type { MessagingModuleOptions, MessagingModuleChannelConfig } from './messaging.module';
7
+ export { MessagingService } from './messaging.service';
8
+ export type { MessagingServiceOptions } from './messaging.service';
9
+ export type { AgentHandler, AgentHandlerInput, AgentHandlerResult, IRAGSearch, } from './types/response-handler.types';
10
+ export { MessagingController, MESSAGING_ADAPTERS } from './messaging.controller';
11
+ export { TelegramAdapter } from './adapters/telegram.adapter';
12
+ export type { TelegramAdapterConfig } from './adapters/telegram.adapter';
13
+ export { WhatsAppAdapter } from './adapters/whatsapp.adapter';
14
+ export type { WhatsAppAdapterConfig } from './adapters/whatsapp.adapter';
15
+ export { ViberAdapter } from './adapters/viber.adapter';
16
+ export type { ViberAdapterConfig } from './adapters/viber.adapter';
17
+ export { SlackAdapter } from './adapters/slack.adapter';
18
+ export type { SlackAdapterConfig } from './adapters/slack.adapter';
19
+ export { TeamsAdapter } from './adapters/teams.adapter';
20
+ export type { TeamsAdapterConfig } from './adapters/teams.adapter';
21
+ export type { MessagingChannel, IncomingMessage, OutgoingMessage, IChannelAdapter, MessageHandler, ResponseMode, } from './types/message.types';
22
+ export { MemoryConversationContextStore } from './store/memory-conversation-context';
23
+ export { RedisConversationContextStore } from './store/redis-conversation-context';
24
+ export type { IConversationContextStore, ConversationTurn, } from './store/conversation-context.interface';
25
+ export type { RedisConversationContextConfig } from './store/redis-conversation-context';
26
+ export { MESSAGING_INCOMING_TOPIC } from './messaging-kafka.types';
27
+ export type { MessagingIncomingPayload } from './messaging-kafka.types';
28
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,YAAY,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAC;AAC/F,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,YAAY,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AACnE,YAAY,EACV,YAAY,EACZ,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,GACX,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEjF,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,YAAY,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,YAAY,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,YAAY,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,YAAY,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,YAAY,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAEnE,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,eAAe,EACf,cAAc,EACd,YAAY,GACb,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AACrF,OAAO,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAC;AACnF,YAAY,EACV,yBAAyB,EACzB,gBAAgB,GACjB,MAAM,wCAAwC,CAAC;AAChD,YAAY,EAAE,8BAA8B,EAAE,MAAM,oCAAoC,CAAC;AACzF,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,YAAY,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ /**
3
+ * @hazeljs/messaging
4
+ * Multichannel messaging - WhatsApp, Telegram, Viber with LLM-powered bot responses
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.MESSAGING_INCOMING_TOPIC = exports.RedisConversationContextStore = exports.MemoryConversationContextStore = exports.TeamsAdapter = exports.SlackAdapter = exports.ViberAdapter = exports.WhatsAppAdapter = exports.TelegramAdapter = exports.MESSAGING_ADAPTERS = exports.MessagingController = exports.MessagingService = exports.MessagingModule = void 0;
8
+ var messaging_module_1 = require("./messaging.module");
9
+ Object.defineProperty(exports, "MessagingModule", { enumerable: true, get: function () { return messaging_module_1.MessagingModule; } });
10
+ var messaging_service_1 = require("./messaging.service");
11
+ Object.defineProperty(exports, "MessagingService", { enumerable: true, get: function () { return messaging_service_1.MessagingService; } });
12
+ var messaging_controller_1 = require("./messaging.controller");
13
+ Object.defineProperty(exports, "MessagingController", { enumerable: true, get: function () { return messaging_controller_1.MessagingController; } });
14
+ Object.defineProperty(exports, "MESSAGING_ADAPTERS", { enumerable: true, get: function () { return messaging_controller_1.MESSAGING_ADAPTERS; } });
15
+ var telegram_adapter_1 = require("./adapters/telegram.adapter");
16
+ Object.defineProperty(exports, "TelegramAdapter", { enumerable: true, get: function () { return telegram_adapter_1.TelegramAdapter; } });
17
+ var whatsapp_adapter_1 = require("./adapters/whatsapp.adapter");
18
+ Object.defineProperty(exports, "WhatsAppAdapter", { enumerable: true, get: function () { return whatsapp_adapter_1.WhatsAppAdapter; } });
19
+ var viber_adapter_1 = require("./adapters/viber.adapter");
20
+ Object.defineProperty(exports, "ViberAdapter", { enumerable: true, get: function () { return viber_adapter_1.ViberAdapter; } });
21
+ var slack_adapter_1 = require("./adapters/slack.adapter");
22
+ Object.defineProperty(exports, "SlackAdapter", { enumerable: true, get: function () { return slack_adapter_1.SlackAdapter; } });
23
+ var teams_adapter_1 = require("./adapters/teams.adapter");
24
+ Object.defineProperty(exports, "TeamsAdapter", { enumerable: true, get: function () { return teams_adapter_1.TeamsAdapter; } });
25
+ var memory_conversation_context_1 = require("./store/memory-conversation-context");
26
+ Object.defineProperty(exports, "MemoryConversationContextStore", { enumerable: true, get: function () { return memory_conversation_context_1.MemoryConversationContextStore; } });
27
+ var redis_conversation_context_1 = require("./store/redis-conversation-context");
28
+ Object.defineProperty(exports, "RedisConversationContextStore", { enumerable: true, get: function () { return redis_conversation_context_1.RedisConversationContextStore; } });
29
+ var messaging_kafka_types_1 = require("./messaging-kafka.types");
30
+ Object.defineProperty(exports, "MESSAGING_INCOMING_TOPIC", { enumerable: true, get: function () { return messaging_kafka_types_1.MESSAGING_INCOMING_TOPIC; } });
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,uDAAqD;AAA5C,mHAAA,eAAe,OAAA;AAExB,yDAAuD;AAA9C,qHAAA,gBAAgB,OAAA;AAQzB,+DAAiF;AAAxE,2HAAA,mBAAmB,OAAA;AAAE,0HAAA,kBAAkB,OAAA;AAEhD,gEAA8D;AAArD,mHAAA,eAAe,OAAA;AAExB,gEAA8D;AAArD,mHAAA,eAAe,OAAA;AAExB,0DAAwD;AAA/C,6GAAA,YAAY,OAAA;AAErB,0DAAwD;AAA/C,6GAAA,YAAY,OAAA;AAErB,0DAAwD;AAA/C,6GAAA,YAAY,OAAA;AAYrB,mFAAqF;AAA5E,6IAAA,8BAA8B,OAAA;AACvC,iFAAmF;AAA1E,2IAAA,6BAA6B,OAAA;AAMtC,iEAAmE;AAA1D,iIAAA,wBAAwB,OAAA"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Registers MessagingKafkaConsumer with KafkaConsumerService on module init
3
+ */
4
+ import { type OnModuleInit } from '@hazeljs/core';
5
+ import { KafkaConsumerService } from '@hazeljs/kafka';
6
+ import { MessagingKafkaConsumer } from './messaging-kafka.consumer';
7
+ export declare class MessagingKafkaBootstrap implements OnModuleInit {
8
+ private readonly consumerService;
9
+ private readonly messagingConsumer;
10
+ private readonly useKafka;
11
+ constructor(consumerService: KafkaConsumerService, messagingConsumer: MessagingKafkaConsumer, useKafka: boolean);
12
+ onModuleInit(): Promise<void>;
13
+ }
14
+ //# sourceMappingURL=messaging-kafka.bootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messaging-kafka.bootstrap.d.ts","sourceRoot":"","sources":["../src/messaging-kafka.bootstrap.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAGpE,qBACa,uBAAwB,YAAW,YAAY;IAExD,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IACL,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAFrC,eAAe,EAAE,oBAAoB,EACrC,iBAAiB,EAAE,sBAAsB,EACZ,QAAQ,EAAE,OAAO;IAG3D,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;CAIpC"}
@@ -0,0 +1,42 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.MessagingKafkaBootstrap = void 0;
16
+ /**
17
+ * Registers MessagingKafkaConsumer with KafkaConsumerService on module init
18
+ */
19
+ const core_1 = require("@hazeljs/core");
20
+ const kafka_1 = require("@hazeljs/kafka");
21
+ const messaging_kafka_consumer_1 = require("./messaging-kafka.consumer");
22
+ const messaging_controller_1 = require("./messaging.controller");
23
+ let MessagingKafkaBootstrap = class MessagingKafkaBootstrap {
24
+ constructor(consumerService, messagingConsumer, useKafka) {
25
+ this.consumerService = consumerService;
26
+ this.messagingConsumer = messagingConsumer;
27
+ this.useKafka = useKafka;
28
+ }
29
+ async onModuleInit() {
30
+ if (!this.useKafka)
31
+ return;
32
+ await this.consumerService.registerFromProvider(this.messagingConsumer);
33
+ }
34
+ };
35
+ exports.MessagingKafkaBootstrap = MessagingKafkaBootstrap;
36
+ exports.MessagingKafkaBootstrap = MessagingKafkaBootstrap = __decorate([
37
+ (0, core_1.Injectable)(),
38
+ __param(2, (0, core_1.Inject)(messaging_controller_1.MESSAGING_USE_KAFKA)),
39
+ __metadata("design:paramtypes", [kafka_1.KafkaConsumerService,
40
+ messaging_kafka_consumer_1.MessagingKafkaConsumer, Boolean])
41
+ ], MessagingKafkaBootstrap);
42
+ //# sourceMappingURL=messaging-kafka.bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messaging-kafka.bootstrap.js","sourceRoot":"","sources":["../src/messaging-kafka.bootstrap.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA;;GAEG;AACH,wCAAsE;AACtE,0CAAsD;AACtD,yEAAoE;AACpE,iEAA6D;AAGtD,IAAM,uBAAuB,GAA7B,MAAM,uBAAuB;IAClC,YACmB,eAAqC,EACrC,iBAAyC,EACZ,QAAiB;QAF9C,oBAAe,GAAf,eAAe,CAAsB;QACrC,sBAAiB,GAAjB,iBAAiB,CAAwB;QACZ,aAAQ,GAAR,QAAQ,CAAS;IAC9D,CAAC;IAEJ,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC3B,MAAM,IAAI,CAAC,eAAe,CAAC,oBAAoB,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAC1E,CAAC;CACF,CAAA;AAXY,0DAAuB;kCAAvB,uBAAuB;IADnC,IAAA,iBAAU,GAAE;IAKR,WAAA,IAAA,aAAM,EAAC,0CAAmB,CAAC,CAAA;qCAFM,4BAAoB;QAClB,iDAAsB;GAHjD,uBAAuB,CAWnC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=messaging-kafka.bootstrap.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messaging-kafka.bootstrap.test.d.ts","sourceRoot":"","sources":["../src/messaging-kafka.bootstrap.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * MessagingKafkaBootstrap tests
5
+ */
6
+ const messaging_kafka_bootstrap_1 = require("./messaging-kafka.bootstrap");
7
+ jest.mock('@hazeljs/kafka', () => ({
8
+ KafkaConsumer: () => () => { },
9
+ KafkaSubscribe: () => (_target, _key, descriptor) => descriptor,
10
+ KafkaConsumerService: jest.fn().mockImplementation(() => ({
11
+ registerFromProvider: jest.fn().mockResolvedValue(undefined),
12
+ })),
13
+ }));
14
+ describe('MessagingKafkaBootstrap', () => {
15
+ it('does nothing when useKafka is false', async () => {
16
+ const mockConsumerService = {
17
+ registerFromProvider: jest.fn(),
18
+ };
19
+ const mockConsumer = {};
20
+ const bootstrap = new messaging_kafka_bootstrap_1.MessagingKafkaBootstrap(mockConsumerService, mockConsumer, false);
21
+ await bootstrap.onModuleInit();
22
+ expect(mockConsumerService.registerFromProvider).not.toHaveBeenCalled();
23
+ });
24
+ it('registers consumer when useKafka is true', async () => {
25
+ const mockConsumerService = {
26
+ registerFromProvider: jest.fn().mockResolvedValue(undefined),
27
+ };
28
+ const mockConsumer = {};
29
+ const bootstrap = new messaging_kafka_bootstrap_1.MessagingKafkaBootstrap(mockConsumerService, mockConsumer, true);
30
+ await bootstrap.onModuleInit();
31
+ expect(mockConsumerService.registerFromProvider).toHaveBeenCalledWith(mockConsumer);
32
+ });
33
+ });
34
+ //# sourceMappingURL=messaging-kafka.bootstrap.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messaging-kafka.bootstrap.test.js","sourceRoot":"","sources":["../src/messaging-kafka.bootstrap.test.ts"],"names":[],"mappings":";;AAAA;;GAEG;AACH,2EAAsE;AAEtE,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,GAAG,EAAE,CAAC,CAAC;IACjC,aAAa,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,GAAE,CAAC;IAC7B,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC,OAAgB,EAAE,IAAa,EAAE,UAA+B,EAAE,EAAE,CACzF,UAAU;IACZ,oBAAoB,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC,CAAC;QACxD,oBAAoB,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;KAC7D,CAAC,CAAC;CACJ,CAAC,CAAC,CAAC;AAEJ,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,mBAAmB,GAAG;YAC1B,oBAAoB,EAAE,IAAI,CAAC,EAAE,EAAE;SAChC,CAAC;QACF,MAAM,YAAY,GAAG,EAAE,CAAC;QACxB,MAAM,SAAS,GAAG,IAAI,mDAAuB,CAC3C,mBAA4B,EAC5B,YAAqB,EACrB,KAAK,CACN,CAAC;QAEF,MAAM,SAAS,CAAC,YAAY,EAAE,CAAC;QAE/B,MAAM,CAAC,mBAAmB,CAAC,oBAAoB,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QACxD,MAAM,mBAAmB,GAAG;YAC1B,oBAAoB,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;SAC7D,CAAC;QACF,MAAM,YAAY,GAAG,EAAE,CAAC;QACxB,MAAM,SAAS,GAAG,IAAI,mDAAuB,CAC3C,mBAA4B,EAC5B,YAAqB,EACrB,IAAI,CACL,CAAC;QAEF,MAAM,SAAS,CAAC,YAAY,EAAE,CAAC;QAE/B,MAAM,CAAC,mBAAmB,CAAC,oBAAoB,CAAC,CAAC,oBAAoB,CAAC,YAAY,CAAC,CAAC;IACtF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { KafkaMessagePayload } from '@hazeljs/kafka';
2
+ import { MessagingService } from './messaging.service';
3
+ import type { IChannelAdapter } from './types/message.types';
4
+ export declare class MessagingKafkaConsumer {
5
+ private readonly messagingService;
6
+ private readonly adapters;
7
+ constructor(messagingService: MessagingService, adapters: IChannelAdapter[]);
8
+ handleIncoming(payload: KafkaMessagePayload): Promise<void>;
9
+ }
10
+ //# sourceMappingURL=messaging-kafka.consumer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messaging-kafka.consumer.d.ts","sourceRoot":"","sources":["../src/messaging-kafka.consumer.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAK7D,qBAEa,sBAAsB;IAE/B,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACL,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBADpC,gBAAgB,EAAE,gBAAgB,EACN,QAAQ,EAAE,eAAe,EAAE;IAIpE,cAAc,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;CAiClE"}
@@ -0,0 +1,80 @@
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 __importDefault = (this && this.__importDefault) || function (mod) {
15
+ return (mod && mod.__esModule) ? mod : { "default": mod };
16
+ };
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.MessagingKafkaConsumer = void 0;
19
+ /**
20
+ * Kafka consumer for async message processing - horizontally scalable
21
+ */
22
+ const core_1 = require("@hazeljs/core");
23
+ const kafka_1 = require("@hazeljs/kafka");
24
+ const messaging_service_1 = require("./messaging.service");
25
+ const core_2 = __importDefault(require("@hazeljs/core"));
26
+ const messaging_controller_1 = require("./messaging.controller");
27
+ const messaging_kafka_types_1 = require("./messaging-kafka.types");
28
+ let MessagingKafkaConsumer = class MessagingKafkaConsumer {
29
+ constructor(messagingService, adapters) {
30
+ this.messagingService = messagingService;
31
+ this.adapters = adapters;
32
+ }
33
+ async handleIncoming(payload) {
34
+ const raw = payload.message.value?.toString();
35
+ if (!raw)
36
+ return;
37
+ let data;
38
+ try {
39
+ data = JSON.parse(raw);
40
+ }
41
+ catch {
42
+ core_2.default.error('MessagingKafkaConsumer: invalid JSON payload');
43
+ return;
44
+ }
45
+ const { message, channel } = data;
46
+ const adapter = this.adapters.find((a) => a.channel === channel);
47
+ if (!adapter) {
48
+ core_2.default.warn(`MessagingKafkaConsumer: no adapter for channel ${channel}`);
49
+ return;
50
+ }
51
+ try {
52
+ const response = await this.messagingService.handleMessage(message);
53
+ if (response) {
54
+ await adapter.send({
55
+ conversationId: message.conversationId,
56
+ text: response,
57
+ replyToMessageId: message.id,
58
+ });
59
+ }
60
+ }
61
+ catch (err) {
62
+ core_2.default.error(`MessagingKafkaConsumer error for ${channel}:`, err);
63
+ throw err; // Let Kafka retry
64
+ }
65
+ }
66
+ };
67
+ exports.MessagingKafkaConsumer = MessagingKafkaConsumer;
68
+ __decorate([
69
+ (0, kafka_1.KafkaSubscribe)(messaging_kafka_types_1.MESSAGING_INCOMING_TOPIC),
70
+ __metadata("design:type", Function),
71
+ __metadata("design:paramtypes", [Object]),
72
+ __metadata("design:returntype", Promise)
73
+ ], MessagingKafkaConsumer.prototype, "handleIncoming", null);
74
+ exports.MessagingKafkaConsumer = MessagingKafkaConsumer = __decorate([
75
+ (0, core_1.Service)(),
76
+ (0, kafka_1.KafkaConsumer)({ groupId: 'messaging-bot' }),
77
+ __param(1, (0, core_1.Inject)(messaging_controller_1.MESSAGING_ADAPTERS)),
78
+ __metadata("design:paramtypes", [messaging_service_1.MessagingService, Array])
79
+ ], MessagingKafkaConsumer);
80
+ //# sourceMappingURL=messaging-kafka.consumer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messaging-kafka.consumer.js","sourceRoot":"","sources":["../src/messaging-kafka.consumer.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA;;GAEG;AACH,wCAAgD;AAChD,0CAA+D;AAE/D,2DAAuD;AAEvD,yDAAmC;AACnC,iEAA4D;AAC5D,mEAAkG;AAI3F,IAAM,sBAAsB,GAA5B,MAAM,sBAAsB;IACjC,YACmB,gBAAkC,EACN,QAA2B;QADvD,qBAAgB,GAAhB,gBAAgB,CAAkB;QACN,aAAQ,GAAR,QAAQ,CAAmB;IACvE,CAAC;IAGE,AAAN,KAAK,CAAC,cAAc,CAAC,OAA4B;QAC/C,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC;QAC9C,IAAI,CAAC,GAAG;YAAE,OAAO;QAEjB,IAAI,IAA8B,CAAC;QACnC,IAAI,CAAC;YACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA6B,CAAC;QACrD,CAAC;QAAC,MAAM,CAAC;YACP,cAAM,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;YAC7D,OAAO;QACT,CAAC;QAED,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;QAClC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC;QACjE,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,cAAM,CAAC,IAAI,CAAC,kDAAkD,OAAO,EAAE,CAAC,CAAC;YACzE,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YACpE,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,OAAO,CAAC,IAAI,CAAC;oBACjB,cAAc,EAAE,OAAO,CAAC,cAAc;oBACtC,IAAI,EAAE,QAAQ;oBACd,gBAAgB,EAAE,OAAO,CAAC,EAAE;iBAC7B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,cAAM,CAAC,KAAK,CAAC,oCAAoC,OAAO,GAAG,EAAE,GAAG,CAAC,CAAC;YAClE,MAAM,GAAG,CAAC,CAAC,kBAAkB;QAC/B,CAAC;IACH,CAAC;CACF,CAAA;AAxCY,wDAAsB;AAO3B;IADL,IAAA,sBAAc,EAAC,gDAAwB,CAAC;;;;4DAiCxC;iCAvCU,sBAAsB;IAFlC,IAAA,cAAO,GAAE;IACT,IAAA,qBAAa,EAAC,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC;IAIvC,WAAA,IAAA,aAAM,EAAC,yCAAkB,CAAC,CAAA;qCADQ,oCAAgB;GAF1C,sBAAsB,CAwClC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=messaging-kafka.consumer.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messaging-kafka.consumer.test.d.ts","sourceRoot":"","sources":["../src/messaging-kafka.consumer.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * MessagingKafkaConsumer tests - tests handleIncoming logic without Kafka
5
+ */
6
+ const messaging_kafka_consumer_1 = require("./messaging-kafka.consumer");
7
+ const messaging_service_1 = require("./messaging.service");
8
+ describe('MessagingKafkaConsumer', () => {
9
+ let messagingService;
10
+ let mockAdapter;
11
+ beforeEach(() => {
12
+ messagingService = new messaging_service_1.MessagingService({
13
+ customHandler: jest.fn().mockResolvedValue('Kafka reply'),
14
+ });
15
+ mockAdapter = {
16
+ channel: 'telegram',
17
+ parseIncoming: jest.fn(),
18
+ send: jest.fn().mockResolvedValue(undefined),
19
+ };
20
+ });
21
+ it('processes valid payload and sends reply', async () => {
22
+ const consumer = new messaging_kafka_consumer_1.MessagingKafkaConsumer(messagingService, [mockAdapter]);
23
+ const payload = {
24
+ message: {
25
+ value: Buffer.from(JSON.stringify({
26
+ message: {
27
+ id: '1',
28
+ channel: 'telegram',
29
+ conversationId: 'conv-1',
30
+ userId: 'u1',
31
+ text: 'Hello',
32
+ timestamp: new Date().toISOString(),
33
+ },
34
+ channel: 'telegram',
35
+ })),
36
+ },
37
+ };
38
+ await consumer.handleIncoming(payload);
39
+ expect(mockAdapter.send).toHaveBeenCalledWith({
40
+ conversationId: 'conv-1',
41
+ text: 'Kafka reply',
42
+ replyToMessageId: '1',
43
+ });
44
+ });
45
+ it('does nothing when message value is empty', async () => {
46
+ const consumer = new messaging_kafka_consumer_1.MessagingKafkaConsumer(messagingService, [mockAdapter]);
47
+ const payload = { message: { value: null } };
48
+ await consumer.handleIncoming(payload);
49
+ expect(mockAdapter.send).not.toHaveBeenCalled();
50
+ });
51
+ it('does nothing when message value is undefined', async () => {
52
+ const consumer = new messaging_kafka_consumer_1.MessagingKafkaConsumer(messagingService, [mockAdapter]);
53
+ const payload = { message: {} };
54
+ await consumer.handleIncoming(payload);
55
+ expect(mockAdapter.send).not.toHaveBeenCalled();
56
+ });
57
+ it('handles invalid JSON gracefully', async () => {
58
+ const consumer = new messaging_kafka_consumer_1.MessagingKafkaConsumer(messagingService, [mockAdapter]);
59
+ const payload = { message: { value: Buffer.from('not json') } };
60
+ await expect(consumer.handleIncoming(payload)).resolves.not.toThrow();
61
+ expect(mockAdapter.send).not.toHaveBeenCalled();
62
+ });
63
+ it('does not send when no adapter for channel', async () => {
64
+ const consumer = new messaging_kafka_consumer_1.MessagingKafkaConsumer(messagingService, [mockAdapter]);
65
+ const payload = {
66
+ message: {
67
+ value: Buffer.from(JSON.stringify({
68
+ message: {
69
+ id: '1',
70
+ channel: 'whatsapp',
71
+ conversationId: 'c1',
72
+ userId: 'u1',
73
+ text: 'Hi',
74
+ timestamp: new Date().toISOString(),
75
+ },
76
+ channel: 'whatsapp',
77
+ })),
78
+ },
79
+ };
80
+ await consumer.handleIncoming(payload);
81
+ expect(mockAdapter.send).not.toHaveBeenCalled();
82
+ });
83
+ it('throws when handleMessage fails to allow Kafka retry', async () => {
84
+ const failingService = new messaging_service_1.MessagingService({
85
+ customHandler: jest.fn().mockRejectedValue(new Error('Service error')),
86
+ });
87
+ const consumer = new messaging_kafka_consumer_1.MessagingKafkaConsumer(failingService, [mockAdapter]);
88
+ const payload = {
89
+ message: {
90
+ value: Buffer.from(JSON.stringify({
91
+ message: {
92
+ id: '1',
93
+ channel: 'telegram',
94
+ conversationId: 'c1',
95
+ userId: 'u1',
96
+ text: 'Hi',
97
+ timestamp: new Date().toISOString(),
98
+ },
99
+ channel: 'telegram',
100
+ })),
101
+ },
102
+ };
103
+ await expect(consumer.handleIncoming(payload)).rejects.toThrow('Service error');
104
+ });
105
+ it('does not send when handleMessage returns empty', async () => {
106
+ const emptyService = new messaging_service_1.MessagingService({
107
+ customHandler: jest.fn().mockResolvedValue(''),
108
+ });
109
+ const consumer = new messaging_kafka_consumer_1.MessagingKafkaConsumer(emptyService, [mockAdapter]);
110
+ const payload = {
111
+ message: {
112
+ value: Buffer.from(JSON.stringify({
113
+ message: {
114
+ id: '1',
115
+ channel: 'telegram',
116
+ conversationId: 'c1',
117
+ userId: 'u1',
118
+ text: 'Hi',
119
+ timestamp: new Date().toISOString(),
120
+ },
121
+ channel: 'telegram',
122
+ })),
123
+ },
124
+ };
125
+ await consumer.handleIncoming(payload);
126
+ expect(mockAdapter.send).not.toHaveBeenCalled();
127
+ });
128
+ });
129
+ //# sourceMappingURL=messaging-kafka.consumer.test.js.map