@squiz/dx-common-lib 1.72.1 → 1.72.3

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.
@@ -0,0 +1,527 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const EventBusService_1 = require("./EventBusService");
4
+ describe('EventBusService', () => {
5
+ let eventBusService;
6
+ let mockLogger;
7
+ let mockConfig;
8
+ let mockFetch;
9
+ beforeEach(() => {
10
+ // Create mock logger
11
+ mockLogger = {
12
+ error: jest.fn(),
13
+ warn: jest.fn(),
14
+ info: jest.fn(),
15
+ };
16
+ // Create mock config
17
+ mockConfig = {
18
+ eventBusUrl: 'https://test-event-bus.com',
19
+ eventBusKey: 'test-api-key',
20
+ tenantId: 'test-tenant',
21
+ deploymentEnvironment: 'test',
22
+ squizRegion: 'us',
23
+ };
24
+ // Mock fetch globally
25
+ const mockApiResponse = [
26
+ {
27
+ statusCode: 202,
28
+ event: {
29
+ id: '12345678-1234-5678-9abc-123456789012',
30
+ source: 'component-service',
31
+ detailType: 'component.change.create',
32
+ time: '2023-01-01T00:00:05.000Z',
33
+ detail: {
34
+ metadata: { action: 'component.change.create' },
35
+ event: { name: 'test-component' },
36
+ },
37
+ },
38
+ },
39
+ ];
40
+ mockFetch = jest.fn().mockResolvedValue({
41
+ ok: true,
42
+ json: jest.fn().mockResolvedValue(mockApiResponse),
43
+ });
44
+ global.fetch = mockFetch;
45
+ eventBusService = new EventBusService_1.EventBusService(mockLogger, mockConfig);
46
+ });
47
+ afterEach(() => {
48
+ jest.clearAllMocks();
49
+ });
50
+ describe('publishEvent', () => {
51
+ const testDetailType = 'component.change.create';
52
+ const testDetail = { name: 'test-component', version: '1.0.0' };
53
+ it('should successfully publish an event and return API response', async () => {
54
+ // Mock Date constructor to make eventTime predictable
55
+ const mockDate = new Date('2023-01-01T00:00:00.000Z');
56
+ const originalDate = Date;
57
+ global.Date = jest.fn(() => mockDate);
58
+ global.Date.now = originalDate.now;
59
+ const response = await eventBusService.publishEvent(testDetailType, testDetail);
60
+ // Verify fetch was called with correct URL
61
+ expect(mockFetch).toHaveBeenCalledWith('https://test-event-bus.com/events', expect.objectContaining({
62
+ method: 'POST',
63
+ headers: {
64
+ 'x-api-key': 'test-api-key',
65
+ 'x-dxp-tenant': 'test-tenant',
66
+ 'Content-Type': 'application/json',
67
+ },
68
+ }));
69
+ // Verify the payload structure
70
+ const callArgs = mockFetch.mock.calls[0];
71
+ const payload = JSON.parse(callArgs[1].body);
72
+ expect(payload).toHaveLength(1);
73
+ expect(payload[0]).toMatchObject({
74
+ source: 'component-service',
75
+ 'detail-type': testDetailType,
76
+ action: testDetailType,
77
+ eventTime: '2023-01-01T00:00:00.000Z',
78
+ metadata: {
79
+ tenantID: 'test-tenant',
80
+ environment: 'test',
81
+ region: 'us',
82
+ },
83
+ event: testDetail,
84
+ });
85
+ expect(mockLogger.info).not.toHaveBeenCalled();
86
+ // Verify the response is returned correctly
87
+ expect(response).toEqual([
88
+ {
89
+ statusCode: 202,
90
+ event: {
91
+ id: '12345678-1234-5678-9abc-123456789012',
92
+ source: 'component-service',
93
+ detailType: 'component.change.create',
94
+ time: '2023-01-01T00:00:05.000Z',
95
+ detail: {
96
+ metadata: { action: 'component.change.create' },
97
+ event: { name: 'test-component' },
98
+ },
99
+ },
100
+ },
101
+ ]);
102
+ // Restore Date
103
+ global.Date = originalDate;
104
+ });
105
+ it('should throw error when eventBusUrl is not configured', async () => {
106
+ // Create service with config missing URL
107
+ const configWithoutUrl = { ...mockConfig, eventBusUrl: '' };
108
+ const serviceWithoutUrl = new EventBusService_1.EventBusService(mockLogger, configWithoutUrl);
109
+ await expect(serviceWithoutUrl.publishEvent(testDetailType, testDetail)).rejects.toThrow(/Event Bus is not configured: missing EVENT_BUS_URL/);
110
+ expect(mockFetch).not.toHaveBeenCalled();
111
+ });
112
+ it('should throw error when eventBusKey is not configured', async () => {
113
+ // Create service with config missing key
114
+ const configWithoutKey = { ...mockConfig, eventBusKey: '' };
115
+ const serviceWithoutKey = new EventBusService_1.EventBusService(mockLogger, configWithoutKey);
116
+ await expect(serviceWithoutKey.publishEvent(testDetailType, testDetail)).rejects.toThrow(/Event Bus is not configured: missing EVENT_BUS_KEY/);
117
+ expect(mockFetch).not.toHaveBeenCalled();
118
+ });
119
+ it('should throw error when tenantId is not set', async () => {
120
+ // Create service with config missing tenantId
121
+ const configWithoutTenantId = { ...mockConfig, tenantId: '' };
122
+ const serviceWithoutTenantId = new EventBusService_1.EventBusService(mockLogger, configWithoutTenantId);
123
+ await expect(serviceWithoutTenantId.publishEvent(testDetailType, testDetail)).rejects.toThrow(/Tenant ID is not set/);
124
+ expect(mockFetch).not.toHaveBeenCalled();
125
+ });
126
+ it('should handle HTTP errors when response is not ok', async () => {
127
+ mockFetch.mockResolvedValueOnce({
128
+ ok: false,
129
+ status: 500,
130
+ statusText: 'Internal Server Error',
131
+ text: jest.fn().mockResolvedValue('upstream failure body'),
132
+ });
133
+ await expect(eventBusService.publishEvent(testDetailType, testDetail)).rejects.toThrow('Event Bus API error: HTTP 500 Internal Server Error for POST https://test-event-bus.com/events. Response body (preview): upstream failure body');
134
+ });
135
+ it('should handle network errors', async () => {
136
+ const networkError = new Error('Network error');
137
+ mockFetch.mockRejectedValueOnce(networkError);
138
+ await expect(eventBusService.publishEvent(testDetailType, testDetail)).rejects.toThrow('Network error');
139
+ });
140
+ });
141
+ describe('publishEventSafely', () => {
142
+ const testDetailType = 'component.change.update';
143
+ const testDetail = { name: 'test-component', version: '2.0.0' };
144
+ it('should successfully publish an event and log success with event ID', async () => {
145
+ await expect(eventBusService.publishEventSafely(testDetailType, testDetail)).resolves.not.toThrow();
146
+ expect(mockFetch).toHaveBeenCalled();
147
+ expect(mockLogger.error).not.toHaveBeenCalled();
148
+ expect(mockLogger.info).toHaveBeenCalledWith(`Successfully published event: ${testDetailType} with IDs [12345678-1234-5678-9abc-123456789012] to https://test-event-bus.com/events`);
149
+ });
150
+ it('should fail silently when API returns non-202 status codes', async () => {
151
+ // Mock API response with failed status
152
+ const failedResponse = [
153
+ {
154
+ statusCode: 400,
155
+ event: {
156
+ id: 'failed-event-id',
157
+ source: 'component-service',
158
+ detailType: 'component.change.update',
159
+ time: '2023-01-01T00:00:05.000Z',
160
+ detail: { error: 'Invalid event data' },
161
+ },
162
+ },
163
+ ];
164
+ mockFetch.mockResolvedValueOnce({
165
+ ok: true,
166
+ json: jest.fn().mockResolvedValue(failedResponse),
167
+ });
168
+ await expect(eventBusService.publishEventSafely(testDetailType, testDetail)).resolves.not.toThrow();
169
+ expect(mockFetch).toHaveBeenCalled();
170
+ expect(mockLogger.error).toHaveBeenCalledWith(`Event publishing failed: received non-valid status codes [400] for event ${testDetailType}`);
171
+ expect(mockLogger.info).not.toHaveBeenCalled();
172
+ });
173
+ it('should fail silently when API returns mixed status codes', async () => {
174
+ // Mock API response with mixed statuses (batch)
175
+ const mixedResponse = [
176
+ {
177
+ statusCode: 202,
178
+ event: {
179
+ id: 'success-id',
180
+ source: 'component-service',
181
+ detailType: 'test',
182
+ time: '2023-01-01T00:00:05.000Z',
183
+ detail: {},
184
+ },
185
+ },
186
+ {
187
+ statusCode: 400,
188
+ event: {
189
+ id: 'failed-id',
190
+ source: 'component-service',
191
+ detailType: 'test',
192
+ time: '2023-01-01T00:00:05.000Z',
193
+ detail: {},
194
+ },
195
+ },
196
+ {
197
+ statusCode: 500,
198
+ event: {
199
+ id: 'error-id',
200
+ source: 'component-service',
201
+ detailType: 'test',
202
+ time: '2023-01-01T00:00:05.000Z',
203
+ detail: {},
204
+ },
205
+ },
206
+ ];
207
+ mockFetch.mockResolvedValueOnce({
208
+ ok: true,
209
+ json: jest.fn().mockResolvedValue(mixedResponse),
210
+ });
211
+ await expect(eventBusService.publishEventSafely(testDetailType, testDetail)).resolves.not.toThrow();
212
+ expect(mockFetch).toHaveBeenCalled();
213
+ expect(mockLogger.error).toHaveBeenCalledWith(`Event publishing failed: received non-valid status codes [400, 500] for event ${testDetailType}`);
214
+ expect(mockLogger.info).not.toHaveBeenCalled();
215
+ });
216
+ it('should catch errors and log them via the logger without throwing', async () => {
217
+ const publishError = new Error('Publish failed');
218
+ jest.spyOn(eventBusService, 'publishEvent').mockRejectedValue(publishError);
219
+ await expect(eventBusService.publishEventSafely(testDetailType, testDetail)).resolves.not.toThrow();
220
+ expect(mockLogger.error).toHaveBeenCalledWith(`Failed to publish event ${testDetailType} to event bus: Publish failed`, expect.objectContaining({ detailType: testDetailType }));
221
+ });
222
+ it('should handle Error objects in safe error logging', async () => {
223
+ const publishError = new Error('Connection timeout');
224
+ jest.spyOn(eventBusService, 'publishEvent').mockRejectedValue(publishError);
225
+ await eventBusService.publishEventSafely(testDetailType, testDetail);
226
+ expect(mockLogger.error).toHaveBeenCalledWith(`Failed to publish event ${testDetailType} to event bus: Connection timeout`, expect.objectContaining({ detailType: testDetailType }));
227
+ });
228
+ it('should handle string errors in safe error logging', async () => {
229
+ const publishError = 'String error message';
230
+ jest.spyOn(eventBusService, 'publishEvent').mockRejectedValue(publishError);
231
+ await eventBusService.publishEventSafely(testDetailType, testDetail);
232
+ expect(mockLogger.error).toHaveBeenCalledWith(`Failed to publish event ${testDetailType} to event bus: String error message`, expect.objectContaining({ detailType: testDetailType }));
233
+ });
234
+ it('should handle complex objects in safe error logging', async () => {
235
+ const publishError = { status: 500, data: { error: 'Internal error' } };
236
+ jest.spyOn(eventBusService, 'publishEvent').mockRejectedValue(publishError);
237
+ await eventBusService.publishEventSafely(testDetailType, testDetail);
238
+ expect(mockLogger.error).toHaveBeenCalledWith(`Failed to publish event ${testDetailType} to event bus: ${JSON.stringify(publishError)}`, expect.objectContaining({ detailType: testDetailType }));
239
+ });
240
+ it('should log error when eventBusUrl is not configured', async () => {
241
+ const configWithoutUrl = { ...mockConfig, eventBusUrl: '' };
242
+ const serviceWithoutUrl = new EventBusService_1.EventBusService(mockLogger, configWithoutUrl);
243
+ await serviceWithoutUrl.publishEventSafely(testDetailType, testDetail);
244
+ expect(mockLogger.error).toHaveBeenCalledWith(expect.stringMatching(/Failed to publish event component\.change\.update to event bus: Event Bus is not configured: missing EVENT_BUS_URL/), expect.objectContaining({ detailType: 'component.change.update' }));
245
+ expect(mockFetch).not.toHaveBeenCalled();
246
+ expect(mockLogger.info).not.toHaveBeenCalled();
247
+ });
248
+ it('should log error when eventBusKey is not configured', async () => {
249
+ const configWithoutKey = { ...mockConfig, eventBusKey: '' };
250
+ const serviceWithoutKey = new EventBusService_1.EventBusService(mockLogger, configWithoutKey);
251
+ await serviceWithoutKey.publishEventSafely(testDetailType, testDetail);
252
+ expect(mockLogger.error).toHaveBeenCalledWith(expect.stringMatching(/Failed to publish event component\.change\.update to event bus: Event Bus is not configured: missing EVENT_BUS_KEY/), expect.objectContaining({ detailType: 'component.change.update' }));
253
+ expect(mockFetch).not.toHaveBeenCalled();
254
+ expect(mockLogger.info).not.toHaveBeenCalled();
255
+ });
256
+ it('should log error when tenantId is not set', async () => {
257
+ const configWithoutTenantId = { ...mockConfig, tenantId: '' };
258
+ const serviceWithoutTenantId = new EventBusService_1.EventBusService(mockLogger, configWithoutTenantId);
259
+ await serviceWithoutTenantId.publishEventSafely(testDetailType, testDetail);
260
+ expect(mockLogger.error).toHaveBeenCalledWith(expect.stringMatching(/Failed to publish event component\.change\.update to event bus: Tenant ID is not set/), expect.objectContaining({ detailType: 'component.change.update' }));
261
+ });
262
+ });
263
+ describe('event payload structure', () => {
264
+ it('should create correct payload structure with all required fields', async () => {
265
+ const testDetailType = 'test.event';
266
+ const testDetail = { foo: 'bar', nested: { key: 'value' } };
267
+ await eventBusService.publishEvent(testDetailType, testDetail);
268
+ const callArgs = mockFetch.mock.calls[0];
269
+ const payload = JSON.parse(callArgs[1].body);
270
+ expect(payload).toHaveLength(1);
271
+ const event = payload[0];
272
+ expect(event).toMatchObject({
273
+ source: 'component-service',
274
+ 'detail-type': testDetailType,
275
+ action: testDetailType,
276
+ metadata: {
277
+ tenantID: 'test-tenant',
278
+ environment: 'test',
279
+ region: 'us',
280
+ },
281
+ event: testDetail,
282
+ });
283
+ // Verify eventTime is a valid ISO string
284
+ expect(event.eventTime).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/);
285
+ });
286
+ it('should include the event object in the request payload', async () => {
287
+ const complexDetail = {
288
+ componentName: 'my-component',
289
+ version: '1.2.3',
290
+ metadata: { author: 'test-user' },
291
+ tags: ['frontend', 'react'],
292
+ };
293
+ await eventBusService.publishEvent('component.created', complexDetail);
294
+ const callArgs = mockFetch.mock.calls[0];
295
+ const payload = JSON.parse(callArgs[1].body);
296
+ expect(payload[0].event).toEqual(complexDetail);
297
+ });
298
+ });
299
+ describe('integration with config', () => {
300
+ it('should use config values for URL and headers', async () => {
301
+ await eventBusService.publishEvent('test.event', {});
302
+ expect(mockFetch).toHaveBeenCalledWith('https://test-event-bus.com/events', expect.objectContaining({
303
+ headers: {
304
+ 'x-api-key': 'test-api-key',
305
+ 'x-dxp-tenant': 'test-tenant',
306
+ 'Content-Type': 'application/json',
307
+ },
308
+ }));
309
+ });
310
+ it('should include config values in event metadata', async () => {
311
+ await eventBusService.publishEvent('test.event', {});
312
+ const callArgs = mockFetch.mock.calls[0];
313
+ const payload = JSON.parse(callArgs[1].body);
314
+ const event = payload[0];
315
+ expect(event.metadata.tenantID).toBe('test-tenant');
316
+ expect(event.metadata.environment).toBe('test');
317
+ expect(event.metadata.region).toBe('us');
318
+ });
319
+ });
320
+ describe('publishEvents', () => {
321
+ it('should successfully publish multiple events and return API response', async () => {
322
+ const events = [
323
+ { detailType: 'component.change.create', detail: { name: 'comp1', version: '1.0.0' } },
324
+ { detailType: 'component.change.update', detail: { name: 'comp2', version: '2.0.0' } },
325
+ { detailType: 'component.change.delete', detail: { name: 'comp3', version: '3.0.0' } },
326
+ ];
327
+ const mockApiResponse = [
328
+ {
329
+ statusCode: 202,
330
+ event: {
331
+ id: 'event-1',
332
+ source: 'component-service',
333
+ detailType: 'component.change.create',
334
+ time: '2023-01-01T00:00:05.000Z',
335
+ detail: { metadata: {}, event: {} },
336
+ },
337
+ },
338
+ {
339
+ statusCode: 202,
340
+ event: {
341
+ id: 'event-2',
342
+ source: 'component-service',
343
+ detailType: 'component.change.update',
344
+ time: '2023-01-01T00:00:05.000Z',
345
+ detail: { metadata: {}, event: {} },
346
+ },
347
+ },
348
+ {
349
+ statusCode: 202,
350
+ event: {
351
+ id: 'event-3',
352
+ source: 'component-service',
353
+ detailType: 'component.change.delete',
354
+ time: '2023-01-01T00:00:05.000Z',
355
+ detail: { metadata: {}, event: {} },
356
+ },
357
+ },
358
+ ];
359
+ mockFetch.mockResolvedValueOnce({
360
+ ok: true,
361
+ json: jest.fn().mockResolvedValue(mockApiResponse),
362
+ });
363
+ const response = await eventBusService.publishEvents(events);
364
+ expect(mockFetch).toHaveBeenCalled();
365
+ expect(response).toEqual(mockApiResponse);
366
+ const callArgs = mockFetch.mock.calls[0];
367
+ const payload = JSON.parse(callArgs[1].body);
368
+ expect(payload).toHaveLength(3);
369
+ expect(payload[0]['detail-type']).toBe('component.change.create');
370
+ expect(payload[1]['detail-type']).toBe('component.change.update');
371
+ expect(payload[2]['detail-type']).toBe('component.change.delete');
372
+ });
373
+ it('should return empty array when events array is empty', async () => {
374
+ const response = await eventBusService.publishEvents([]);
375
+ expect(response).toEqual([]);
376
+ expect(mockFetch).not.toHaveBeenCalled();
377
+ });
378
+ it('should throw error when tenantId is not set', async () => {
379
+ const configWithoutTenantId = { ...mockConfig, tenantId: '' };
380
+ const serviceWithoutTenantId = new EventBusService_1.EventBusService(mockLogger, configWithoutTenantId);
381
+ const events = [{ detailType: 'test.event', detail: { test: 'data' } }];
382
+ await expect(serviceWithoutTenantId.publishEvents(events)).rejects.toThrow(/Tenant ID is not set/);
383
+ });
384
+ it('should throw error when eventBusUrl is not configured', async () => {
385
+ const configWithoutUrl = { ...mockConfig, eventBusUrl: '' };
386
+ const serviceWithoutUrl = new EventBusService_1.EventBusService(mockLogger, configWithoutUrl);
387
+ const events = [{ detailType: 'test.event', detail: { test: 'data' } }];
388
+ await expect(serviceWithoutUrl.publishEvents(events)).rejects.toThrow(/Event Bus is not configured: missing EVENT_BUS_URL/);
389
+ });
390
+ it('should throw error when HTTP response is not ok', async () => {
391
+ mockFetch.mockResolvedValueOnce({
392
+ ok: false,
393
+ status: 400,
394
+ statusText: 'Bad Request',
395
+ text: jest.fn().mockResolvedValue('bad request detail'),
396
+ });
397
+ const events = [{ detailType: 'test.event', detail: { test: 'data' } }];
398
+ await expect(eventBusService.publishEvents(events)).rejects.toThrow('Event Bus API error: HTTP 400 Bad Request for POST https://test-event-bus.com/events. Response body (preview): bad request detail');
399
+ });
400
+ });
401
+ describe('publishEventsSafely', () => {
402
+ it('should successfully publish multiple events and log success', async () => {
403
+ const events = [
404
+ { detailType: 'component.change.create', detail: { name: 'comp1', version: '1.0.0' } },
405
+ { detailType: 'component.change.update', detail: { name: 'comp2', version: '2.0.0' } },
406
+ ];
407
+ const mockApiResponse = [
408
+ {
409
+ statusCode: 202,
410
+ event: {
411
+ id: 'event-1',
412
+ source: 'component-service',
413
+ detailType: 'test',
414
+ time: '2023-01-01T00:00:05.000Z',
415
+ detail: {},
416
+ },
417
+ },
418
+ {
419
+ statusCode: 202,
420
+ event: {
421
+ id: 'event-2',
422
+ source: 'component-service',
423
+ detailType: 'test',
424
+ time: '2023-01-01T00:00:05.000Z',
425
+ detail: {},
426
+ },
427
+ },
428
+ ];
429
+ mockFetch.mockResolvedValueOnce({
430
+ ok: true,
431
+ json: jest.fn().mockResolvedValue(mockApiResponse),
432
+ });
433
+ await expect(eventBusService.publishEventsSafely(events)).resolves.not.toThrow();
434
+ expect(mockLogger.info).toHaveBeenCalledWith(`Successfully published batch of ${events.length} events with IDs [event-1, event-2] to https://test-event-bus.com/events`);
435
+ expect(mockLogger.error).not.toHaveBeenCalled();
436
+ });
437
+ it('should throw error when batch publishing fails', async () => {
438
+ const events = [
439
+ { detailType: 'component.change.create', detail: { name: 'comp1', version: '1.0.0' } },
440
+ { detailType: 'component.change.update', detail: { name: 'comp2', version: '2.0.0' } },
441
+ ];
442
+ mockFetch.mockResolvedValueOnce({
443
+ ok: false,
444
+ status: 500,
445
+ statusText: 'Internal Server Error',
446
+ text: jest.fn().mockResolvedValue('batch error body'),
447
+ });
448
+ await expect(eventBusService.publishEventsSafely(events)).rejects.toThrow(/Event Bus API error: HTTP 500 Internal Server Error for POST https:\/\/test-event-bus\.com\/events/);
449
+ expect(mockLogger.error).toHaveBeenCalled();
450
+ });
451
+ it('should throw error when one or more events in batch fail', async () => {
452
+ const events = [
453
+ { detailType: 'component.change.create', detail: { name: 'comp1', version: '1.0.0' } },
454
+ { detailType: 'component.change.update', detail: { name: 'comp2', version: '2.0.0' } },
455
+ ];
456
+ const mixedResponse = [
457
+ {
458
+ statusCode: 202,
459
+ event: {
460
+ id: 'event-1',
461
+ source: 'component-service',
462
+ detailType: 'test',
463
+ time: '2023-01-01T00:00:05.000Z',
464
+ detail: {},
465
+ },
466
+ },
467
+ {
468
+ statusCode: 400,
469
+ event: {
470
+ id: 'event-2',
471
+ source: 'component-service',
472
+ detailType: 'test',
473
+ time: '2023-01-01T00:00:05.000Z',
474
+ detail: {},
475
+ },
476
+ },
477
+ ];
478
+ mockFetch.mockResolvedValueOnce({
479
+ ok: true,
480
+ json: jest.fn().mockResolvedValue(mixedResponse),
481
+ });
482
+ await expect(eventBusService.publishEventsSafely(events)).rejects.toThrow(`Event publishing failed: received non-valid status codes [400] for batch of ${events.length} events`);
483
+ expect(mockLogger.error).toHaveBeenCalled();
484
+ });
485
+ it('should log error when network error occurs during batch publishing', async () => {
486
+ const events = [{ detailType: 'component.change.create', detail: { name: 'comp1', version: '1.0.0' } }];
487
+ const networkError = new Error('Network timeout');
488
+ mockFetch.mockRejectedValueOnce(networkError);
489
+ await expect(eventBusService.publishEventsSafely(events)).rejects.toThrow(`Failed to publish batch of ${events.length} events to event bus: Network timeout`);
490
+ expect(mockLogger.error).toHaveBeenCalled();
491
+ });
492
+ it('should throw error when tenantId is not set', async () => {
493
+ const configWithoutTenantId = { ...mockConfig, tenantId: '' };
494
+ const serviceWithoutTenantId = new EventBusService_1.EventBusService(mockLogger, configWithoutTenantId);
495
+ const events = [{ detailType: 'test.event', detail: { test: 'data' } }];
496
+ await expect(serviceWithoutTenantId.publishEventsSafely(events)).rejects.toThrow(/Failed to publish batch of 1 events to event bus: Tenant ID is not set/);
497
+ expect(mockLogger.error).toHaveBeenCalled();
498
+ });
499
+ it('should correctly set tenant ID before publishing', async () => {
500
+ const events = [{ detailType: 'component.change.create', detail: { name: 'comp1', version: '1.0.0' } }];
501
+ // Create service without tenant ID initially
502
+ const configWithoutTenantId = { ...mockConfig, tenantId: '' };
503
+ const service = new EventBusService_1.EventBusService(mockLogger, configWithoutTenantId);
504
+ // Set tenant ID
505
+ service.setTenantId('new-tenant');
506
+ mockFetch.mockResolvedValueOnce({
507
+ ok: true,
508
+ json: jest.fn().mockResolvedValue([
509
+ {
510
+ statusCode: 202,
511
+ event: {
512
+ id: 'event-1',
513
+ source: 'component-service',
514
+ detailType: 'test',
515
+ time: '2023-01-01T00:00:05.000Z',
516
+ detail: {},
517
+ },
518
+ },
519
+ ]),
520
+ });
521
+ await expect(service.publishEventsSafely(events)).resolves.not.toThrow();
522
+ const callArgs = mockFetch.mock.calls[0];
523
+ expect(callArgs[1].headers['x-dxp-tenant']).toBe('new-tenant');
524
+ });
525
+ });
526
+ });
527
+ //# sourceMappingURL=EventBusService.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EventBusService.spec.js","sourceRoot":"","sources":["../../src/events/EventBusService.spec.ts"],"names":[],"mappings":"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"}
package/lib/index.d.ts CHANGED
@@ -18,3 +18,6 @@ export * from './esi-mac-token-generator/EsiMacTokenGenerator';
18
18
  export * from './secret-api-key-service/SecretApiKeyService';
19
19
  export * from './secret-api-key-service/DevSecretApiKeyService';
20
20
  export * from './secret-api-key-service/getSecretApiKeyService';
21
+ export * from './events/EventBusService';
22
+ export * from './stream/EventStreamHandler';
23
+ export * from './stream/StreamUtils';
package/lib/index.js CHANGED
@@ -34,4 +34,7 @@ __exportStar(require("./esi-mac-token-generator/EsiMacTokenGenerator"), exports)
34
34
  __exportStar(require("./secret-api-key-service/SecretApiKeyService"), exports);
35
35
  __exportStar(require("./secret-api-key-service/DevSecretApiKeyService"), exports);
36
36
  __exportStar(require("./secret-api-key-service/getSecretApiKeyService"), exports);
37
+ __exportStar(require("./events/EventBusService"), exports);
38
+ __exportStar(require("./stream/EventStreamHandler"), exports);
39
+ __exportStar(require("./stream/StreamUtils"), exports);
37
40
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,gDAA8B;AAC9B,0CAAwB;AACxB,yCAAuB;AACvB,qDAAmC;AACnC,iEAA+C;AAC/C,+DAA6C;AAC7C,+EAA6D;AAC7D,+EAA6D;AAC7D,gFAA8D;AAC9D,wEAAsD;AACtD,0CAAwB;AACxB,+CAA6B;AAC7B,iHAA+F;AAC/F,gHAA8F;AAC9F,sGAAoF;AACpF,sGAAoF;AACpF,iFAA+D;AAC/D,+EAA6D;AAC7D,kFAAgE;AAChE,kFAAgE"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,gDAA8B;AAC9B,0CAAwB;AACxB,yCAAuB;AACvB,qDAAmC;AACnC,iEAA+C;AAC/C,+DAA6C;AAC7C,+EAA6D;AAC7D,+EAA6D;AAC7D,gFAA8D;AAC9D,wEAAsD;AACtD,0CAAwB;AACxB,+CAA6B;AAC7B,iHAA+F;AAC/F,gHAA8F;AAC9F,sGAAoF;AACpF,sGAAoF;AACpF,iFAA+D;AAC/D,+EAA6D;AAC7D,kFAAgE;AAChE,kFAAgE;AAChE,2DAAyC;AACzC,8DAA4C;AAC5C,uDAAqC"}
@@ -0,0 +1,38 @@
1
+ /*!
2
+ * @license
3
+ * Copyright Squiz Australia Pty Ltd. All Rights Reserved.
4
+ */
5
+ import { DynamoDBStreamEvent, DynamoDBRecord, Context, DynamoDBBatchResponse } from 'aws-lambda';
6
+ import { Logger } from '@squiz/dx-logger-lib';
7
+ import { EventBusService } from '../events/EventBusService';
8
+ export interface EventPayload {
9
+ detailType: string;
10
+ detail: object;
11
+ }
12
+ export type EventMapper = (record: DynamoDBRecord) => Promise<EventPayload[]>;
13
+ /** Resolves tenant id for publishing; use `record` when tenant is carried on the item rather than derivable from the table ARN. */
14
+ export type ExtractTenantId = (arn: string, tableServiceIdentifier: string, record: DynamoDBRecord) => string;
15
+ interface EventStreamHandlerConfig<T extends string> {
16
+ logger: Logger;
17
+ eventBusService: EventBusService;
18
+ /** Matches the table name segment in ARNs (e.g. `cmp` for `*.cmp-service.*`); also used as log field `service`. */
19
+ tableServiceIdentifier: string;
20
+ entityTypePrefixMap: Record<string, T>;
21
+ mappers: Partial<Record<T, EventMapper>>;
22
+ extractTenantId: ExtractTenantId;
23
+ batchSize?: number;
24
+ }
25
+ /**
26
+ * DynamoDB stream Lambda handler factory for mapping stream records to domain events and publishing via the event bus.
27
+ *
28
+ * Handles:
29
+ * - Record batching by configurable size
30
+ * - Tenant extraction from stream ARN and/or stream record (via `extractTenantId`)
31
+ * - Entity type detection via prefix matching
32
+ * - Mapper invocation for known entity types
33
+ * - Event grouping by tenant
34
+ * - Batch event publishing with retry tracking
35
+ * - Failure reporting for Lambda retry mechanism
36
+ */
37
+ export declare function createEventStreamHandler<T extends string>(config: EventStreamHandlerConfig<T>): (event: DynamoDBStreamEvent, context: Context) => Promise<DynamoDBBatchResponse>;
38
+ export {};