@flusys/nestjs-shared 7.0.0 → 7.0.2
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.
- package/README.md +132 -84
- package/cjs/classes/api-service.class.js +37 -47
- package/cjs/classes/api-service.class.spec.js +120 -12
- package/cjs/classes/event-bus.registry.js +2 -3
- package/cjs/classes/event-bus.registry.spec.js +49 -24
- package/cjs/classes/event-transports/kafka-transport.optional.spec.js +1 -2
- package/cjs/classes/event-transports/memory-transport.js +3 -4
- package/cjs/classes/event-transports/memory-transport.spec.js +1 -2
- package/cjs/classes/event-transports/rabbitmq-transport.optional.spec.js +1 -2
- package/cjs/classes/hybrid-event-bus.class.js +23 -3
- package/cjs/classes/hybrid-event-bus.class.spec.js +31 -2
- package/cjs/enums/index.js +0 -1
- package/cjs/modules/event-bus/event-bus.integration.spec.js +1 -2
- package/cjs/utils/event-pattern.util.js +6 -1
- package/cjs/utils/event-pattern.util.spec.js +20 -3
- package/classes/api-service.class.d.ts +8 -12
- package/classes/domain-event.publisher.d.ts +2 -2
- package/classes/event-bus.registry.d.ts +2 -2
- package/classes/event-transports/memory-transport.d.ts +1 -1
- package/classes/hybrid-event-bus.class.d.ts +2 -0
- package/enums/index.d.ts +0 -1
- package/fesm/classes/api-service.class.js +37 -47
- package/fesm/classes/api-service.class.spec.js +120 -12
- package/fesm/classes/event-bus.registry.js +2 -3
- package/fesm/classes/event-bus.registry.spec.js +49 -24
- package/fesm/classes/event-transports/kafka-transport.optional.spec.js +1 -2
- package/fesm/classes/event-transports/memory-transport.js +7 -4
- package/fesm/classes/event-transports/memory-transport.spec.js +1 -2
- package/fesm/classes/event-transports/rabbitmq-transport.optional.spec.js +1 -2
- package/fesm/classes/hybrid-event-bus.class.js +23 -3
- package/fesm/classes/hybrid-event-bus.class.spec.js +31 -2
- package/fesm/enums/index.js +0 -1
- package/fesm/modules/event-bus/event-bus.integration.spec.js +1 -2
- package/fesm/utils/event-pattern.util.js +6 -1
- package/fesm/utils/event-pattern.util.spec.js +20 -3
- package/interfaces/event-bus.interface.d.ts +3 -6
- package/package.json +2 -2
- package/cjs/enums/event-action.enum.js +0 -18
- package/enums/event-action.enum.d.ts +0 -7
- package/fesm/enums/event-action.enum.js +0 -8
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { EventAction } from '../enums/event-action.enum';
|
|
2
1
|
import { EventBusRegistry } from './event-bus.registry';
|
|
3
2
|
const bus = {
|
|
4
3
|
publish: jest.fn(),
|
|
@@ -22,39 +21,39 @@ describe('EventBusRegistry', ()=>{
|
|
|
22
21
|
enabled: true
|
|
23
22
|
});
|
|
24
23
|
expect(EventBusRegistry.getBus()).toBeUndefined();
|
|
25
|
-
expect(EventBusRegistry.isEnabled('storage', 'folder',
|
|
24
|
+
expect(EventBusRegistry.isEnabled('storage', 'folder', 'created')).toBe(true);
|
|
26
25
|
});
|
|
27
26
|
it('should report disabled for a module that never registered a config', ()=>{
|
|
28
|
-
expect(EventBusRegistry.isEnabled('storage', 'folder',
|
|
27
|
+
expect(EventBusRegistry.isEnabled('storage', 'folder', 'created')).toBe(false);
|
|
29
28
|
});
|
|
30
29
|
it('should enable every action of an enabled module by default', ()=>{
|
|
31
30
|
EventBusRegistry.configureModule('storage', {
|
|
32
31
|
enabled: true
|
|
33
32
|
});
|
|
34
|
-
expect(EventBusRegistry.isEnabled('storage', 'folder',
|
|
35
|
-
expect(EventBusRegistry.isEnabled('storage', 'folder',
|
|
33
|
+
expect(EventBusRegistry.isEnabled('storage', 'folder', 'created')).toBe(true);
|
|
34
|
+
expect(EventBusRegistry.isEnabled('storage', 'folder', 'deleted')).toBe(true);
|
|
36
35
|
});
|
|
37
36
|
it('should honour an action allowlist', ()=>{
|
|
38
37
|
EventBusRegistry.configureModule('storage', {
|
|
39
38
|
enabled: true,
|
|
40
39
|
actions: [
|
|
41
|
-
|
|
40
|
+
'created'
|
|
42
41
|
]
|
|
43
42
|
});
|
|
44
|
-
expect(EventBusRegistry.isEnabled('storage', 'folder',
|
|
45
|
-
expect(EventBusRegistry.isEnabled('storage', 'folder',
|
|
43
|
+
expect(EventBusRegistry.isEnabled('storage', 'folder', 'created')).toBe(true);
|
|
44
|
+
expect(EventBusRegistry.isEnabled('storage', 'folder', 'updated')).toBe(false);
|
|
46
45
|
});
|
|
47
46
|
it('should honour an allowlist that mixes CRUD lifecycle and domain actions', ()=>{
|
|
48
47
|
EventBusRegistry.configureModule('auth', {
|
|
49
48
|
enabled: true,
|
|
50
49
|
actions: [
|
|
51
|
-
|
|
50
|
+
'created',
|
|
52
51
|
'logged-in'
|
|
53
52
|
]
|
|
54
53
|
});
|
|
55
|
-
expect(EventBusRegistry.isEnabled('auth', 'appuser',
|
|
54
|
+
expect(EventBusRegistry.isEnabled('auth', 'appuser', 'created')).toBe(true);
|
|
56
55
|
expect(EventBusRegistry.isEnabled('auth', 'session', 'logged-in')).toBe(true);
|
|
57
|
-
expect(EventBusRegistry.isEnabled('auth', 'appuser',
|
|
56
|
+
expect(EventBusRegistry.isEnabled('auth', 'appuser', 'updated')).toBe(false);
|
|
58
57
|
expect(EventBusRegistry.isEnabled('auth', 'session', 'logged-out')).toBe(false);
|
|
59
58
|
});
|
|
60
59
|
it('should silence CRUD when the allowlist names only domain actions', ()=>{
|
|
@@ -65,28 +64,54 @@ describe('EventBusRegistry', ()=>{
|
|
|
65
64
|
]
|
|
66
65
|
});
|
|
67
66
|
expect(EventBusRegistry.isEnabled('auth', 'session', 'logged-in')).toBe(true);
|
|
68
|
-
expect(EventBusRegistry.isEnabled('auth', 'appuser',
|
|
67
|
+
expect(EventBusRegistry.isEnabled('auth', 'appuser', 'created')).toBe(false);
|
|
69
68
|
});
|
|
70
|
-
it('should
|
|
71
|
-
EventBusRegistry.configureModule('
|
|
69
|
+
it('should scope an action to one entity when the entry names it', ()=>{
|
|
70
|
+
EventBusRegistry.configureModule('iam', {
|
|
71
|
+
enabled: true,
|
|
72
|
+
actions: [
|
|
73
|
+
'created',
|
|
74
|
+
'role.updated'
|
|
75
|
+
]
|
|
76
|
+
});
|
|
77
|
+
expect(EventBusRegistry.isEnabled('iam', 'role', 'updated')).toBe(true);
|
|
78
|
+
expect(EventBusRegistry.isEnabled('iam', 'action', 'updated')).toBe(false);
|
|
79
|
+
expect(EventBusRegistry.isEnabled('iam', 'action', 'created')).toBe(true);
|
|
80
|
+
});
|
|
81
|
+
it('should treat a scoped entry as a routing pattern', ()=>{
|
|
82
|
+
EventBusRegistry.configureModule('iam', {
|
|
72
83
|
enabled: true,
|
|
73
|
-
|
|
74
|
-
'
|
|
75
|
-
'
|
|
76
|
-
],
|
|
77
|
-
excludeEntities: [
|
|
78
|
-
'file_manager'
|
|
84
|
+
actions: [
|
|
85
|
+
'role.*',
|
|
86
|
+
'*.purged'
|
|
79
87
|
]
|
|
80
88
|
});
|
|
81
|
-
expect(EventBusRegistry.isEnabled('
|
|
82
|
-
expect(EventBusRegistry.isEnabled('
|
|
83
|
-
expect(EventBusRegistry.isEnabled('
|
|
89
|
+
expect(EventBusRegistry.isEnabled('iam', 'role', 'updated')).toBe(true);
|
|
90
|
+
expect(EventBusRegistry.isEnabled('iam', 'role', 'permissions-assigned')).toBe(true);
|
|
91
|
+
expect(EventBusRegistry.isEnabled('iam', 'action', 'purged')).toBe(true);
|
|
92
|
+
expect(EventBusRegistry.isEnabled('iam', 'action', 'updated')).toBe(false);
|
|
93
|
+
});
|
|
94
|
+
it('should publish only the entity and action pairs an app lists', ()=>{
|
|
95
|
+
EventBusRegistry.configureModule('auth', {
|
|
96
|
+
enabled: true,
|
|
97
|
+
actions: [
|
|
98
|
+
'company.created',
|
|
99
|
+
'company.updated',
|
|
100
|
+
'session.logged-in'
|
|
101
|
+
]
|
|
102
|
+
});
|
|
103
|
+
expect(EventBusRegistry.isEnabled('auth', 'company', 'created')).toBe(true);
|
|
104
|
+
expect(EventBusRegistry.isEnabled('auth', 'company', 'updated')).toBe(true);
|
|
105
|
+
expect(EventBusRegistry.isEnabled('auth', 'company', 'purged')).toBe(false);
|
|
106
|
+
expect(EventBusRegistry.isEnabled('auth', 'appuser', 'created')).toBe(false);
|
|
107
|
+
expect(EventBusRegistry.isEnabled('auth', 'session', 'logged-in')).toBe(true);
|
|
108
|
+
expect(EventBusRegistry.isEnabled('auth', 'session', 'logged-out')).toBe(false);
|
|
84
109
|
});
|
|
85
110
|
it('should fall back to the default config for unregistered modules', ()=>{
|
|
86
111
|
EventBusRegistry.setDefaultModuleEvents({
|
|
87
112
|
enabled: true
|
|
88
113
|
});
|
|
89
|
-
expect(EventBusRegistry.isEnabled('unknown-module', 'thing',
|
|
114
|
+
expect(EventBusRegistry.isEnabled('unknown-module', 'thing', 'created')).toBe(true);
|
|
90
115
|
});
|
|
91
116
|
it('should include the payload unless a module opts out', ()=>{
|
|
92
117
|
EventBusRegistry.configureModule('storage', {
|
|
@@ -3,7 +3,6 @@ jest.mock('../../utils/optional-module.util', ()=>({
|
|
|
3
3
|
loadOptionalModule: (...args)=>mockLoadOptionalModule(...args)
|
|
4
4
|
}));
|
|
5
5
|
import { InternalServerErrorException, Logger } from '@nestjs/common';
|
|
6
|
-
import { EventAction } from '../../enums/event-action.enum';
|
|
7
6
|
import { KafkaTransport } from './kafka-transport.optional';
|
|
8
7
|
function buildEvent() {
|
|
9
8
|
return {
|
|
@@ -11,7 +10,7 @@ function buildEvent() {
|
|
|
11
10
|
name: 'storage.folder.created',
|
|
12
11
|
module: 'storage',
|
|
13
12
|
entity: 'folder',
|
|
14
|
-
action:
|
|
13
|
+
action: 'created',
|
|
15
14
|
payload: {
|
|
16
15
|
ids: [
|
|
17
16
|
'1'
|
|
@@ -12,10 +12,14 @@ function _define_property(obj, key, value) {
|
|
|
12
12
|
return obj;
|
|
13
13
|
}
|
|
14
14
|
import { EventEmitter } from 'events';
|
|
15
|
-
import { EventTransportRegistry } from './event-transport.registry';
|
|
16
15
|
const CHANNEL = 'domain-event';
|
|
16
|
+
const MAX_LISTENERS = 100;
|
|
17
17
|
/**
|
|
18
18
|
* In-process transport. Always available, needs no broker, and is the default.
|
|
19
|
+
*
|
|
20
|
+
* HybridEventBus constructs it directly rather than through
|
|
21
|
+
* EventTransportRegistry, which exists for the broker transports it must not
|
|
22
|
+
* depend on at build time.
|
|
19
23
|
*/ export class MemoryTransport {
|
|
20
24
|
async connect() {
|
|
21
25
|
this.ready = true;
|
|
@@ -36,11 +40,10 @@ const CHANNEL = 'domain-event';
|
|
|
36
40
|
isReady() {
|
|
37
41
|
return this.ready;
|
|
38
42
|
}
|
|
39
|
-
constructor(
|
|
43
|
+
constructor(){
|
|
40
44
|
_define_property(this, "name", 'memory');
|
|
41
45
|
_define_property(this, "emitter", new EventEmitter());
|
|
42
46
|
_define_property(this, "ready", false);
|
|
43
|
-
this.emitter.setMaxListeners(
|
|
47
|
+
this.emitter.setMaxListeners(MAX_LISTENERS);
|
|
44
48
|
}
|
|
45
49
|
}
|
|
46
|
-
EventTransportRegistry.register('memory', (config)=>new MemoryTransport(config['maxListeners']));
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { EventAction } from '../../enums/event-action.enum';
|
|
2
1
|
import { MemoryTransport } from './memory-transport';
|
|
3
2
|
function buildEvent(name = 'storage.folder.created') {
|
|
4
3
|
return {
|
|
@@ -6,7 +5,7 @@ function buildEvent(name = 'storage.folder.created') {
|
|
|
6
5
|
name,
|
|
7
6
|
module: 'storage',
|
|
8
7
|
entity: 'folder',
|
|
9
|
-
action:
|
|
8
|
+
action: 'created',
|
|
10
9
|
payload: {
|
|
11
10
|
ids: [
|
|
12
11
|
'1'
|
|
@@ -3,7 +3,6 @@ jest.mock('../../utils/optional-module.util', ()=>({
|
|
|
3
3
|
loadOptionalModule: (...args)=>mockLoadOptionalModule(...args)
|
|
4
4
|
}));
|
|
5
5
|
import { InternalServerErrorException, Logger } from '@nestjs/common';
|
|
6
|
-
import { EventAction } from '../../enums/event-action.enum';
|
|
7
6
|
import { RabbitMqTransport } from './rabbitmq-transport.optional';
|
|
8
7
|
function buildEvent() {
|
|
9
8
|
return {
|
|
@@ -11,7 +10,7 @@ function buildEvent() {
|
|
|
11
10
|
name: 'storage.folder.created',
|
|
12
11
|
module: 'storage',
|
|
13
12
|
entity: 'folder',
|
|
14
|
-
action:
|
|
13
|
+
action: 'created',
|
|
15
14
|
payload: {
|
|
16
15
|
ids: [
|
|
17
16
|
'1'
|
|
@@ -55,14 +55,13 @@ const DEFAULT_DEDUPE_SIZE = 5000;
|
|
|
55
55
|
handler: handler
|
|
56
56
|
});
|
|
57
57
|
if (!await this.ensureConnected()) return;
|
|
58
|
-
await
|
|
59
|
-
this.logger.warn(`Bind failed on ${transport.name}: ${error.message}`);
|
|
60
|
-
})));
|
|
58
|
+
await this.bindSubscriptions();
|
|
61
59
|
}
|
|
62
60
|
async close() {
|
|
63
61
|
await Promise.allSettled(this.transports.map((transport)=>transport.close()));
|
|
64
62
|
this.transports.length = 0;
|
|
65
63
|
this.subscriptions.length = 0;
|
|
64
|
+
this.boundPatterns.clear();
|
|
66
65
|
this.seenIds.clear();
|
|
67
66
|
this.seenOrder.length = 0;
|
|
68
67
|
this.memory = undefined;
|
|
@@ -88,6 +87,8 @@ const DEFAULT_DEDUPE_SIZE = 5000;
|
|
|
88
87
|
return value;
|
|
89
88
|
}
|
|
90
89
|
async buildTransports() {
|
|
90
|
+
// Fresh transports know nothing of what was bound on the ones they replace
|
|
91
|
+
this.boundPatterns.clear();
|
|
91
92
|
if (this.label === 'memory' || this.label === 'hybrid') {
|
|
92
93
|
this.memory = new MemoryTransport();
|
|
93
94
|
await this.memory.connect();
|
|
@@ -106,6 +107,23 @@ const DEFAULT_DEDUPE_SIZE = 5000;
|
|
|
106
107
|
}
|
|
107
108
|
}
|
|
108
109
|
}
|
|
110
|
+
await this.bindSubscriptions();
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Binds every pattern the bus knows about, skipping the ones already bound.
|
|
114
|
+
*
|
|
115
|
+
* Called once the transports are built, not only from `subscribe`: a
|
|
116
|
+
* subscription taken while the bus was down returns before any transport
|
|
117
|
+
* exists, so nothing would ever bind its routing key on the broker that
|
|
118
|
+
* finally comes up, leaving the process publishing but never consuming.
|
|
119
|
+
*/ async bindSubscriptions() {
|
|
120
|
+
for (const { pattern } of this.subscriptions){
|
|
121
|
+
if (this.boundPatterns.has(pattern)) continue;
|
|
122
|
+
this.boundPatterns.add(pattern);
|
|
123
|
+
await Promise.all(this.transports.map((transport)=>transport.bind(pattern).catch((error)=>{
|
|
124
|
+
this.logger.warn(`Bind failed on ${transport.name}: ${error.message}`);
|
|
125
|
+
})));
|
|
126
|
+
}
|
|
109
127
|
}
|
|
110
128
|
async createBrokerTransport(label) {
|
|
111
129
|
const name = label === 'hybrid' ? this.resolveHybridBrokerName() : label;
|
|
@@ -197,6 +215,7 @@ const DEFAULT_DEDUPE_SIZE = 5000;
|
|
|
197
215
|
_define_property(this, "logger", void 0);
|
|
198
216
|
_define_property(this, "subscriptions", void 0);
|
|
199
217
|
_define_property(this, "transports", void 0);
|
|
218
|
+
_define_property(this, "boundPatterns", void 0);
|
|
200
219
|
_define_property(this, "seenIds", void 0);
|
|
201
220
|
_define_property(this, "seenOrder", void 0);
|
|
202
221
|
_define_property(this, "label", void 0);
|
|
@@ -208,6 +227,7 @@ const DEFAULT_DEDUPE_SIZE = 5000;
|
|
|
208
227
|
this.logger = new Logger(HybridEventBus.name);
|
|
209
228
|
this.subscriptions = [];
|
|
210
229
|
this.transports = [];
|
|
230
|
+
this.boundPatterns = new Set();
|
|
211
231
|
this.seenIds = new Set();
|
|
212
232
|
this.seenOrder = [];
|
|
213
233
|
this.connected = false;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { EventAction } from '../enums/event-action.enum';
|
|
2
1
|
import { EventTransportRegistry } from './event-transports/event-transport.registry';
|
|
3
2
|
import { MemoryTransport } from './event-transports/memory-transport';
|
|
4
3
|
import { HybridEventBus } from './hybrid-event-bus.class';
|
|
@@ -8,7 +7,7 @@ function buildEvent(name = 'storage.folder.created', id = 'event-1') {
|
|
|
8
7
|
name,
|
|
9
8
|
module: 'storage',
|
|
10
9
|
entity: 'folder',
|
|
11
|
-
action:
|
|
10
|
+
action: 'created',
|
|
12
11
|
payload: {
|
|
13
12
|
ids: [
|
|
14
13
|
'1'
|
|
@@ -174,6 +173,36 @@ describe('HybridEventBus', ()=>{
|
|
|
174
173
|
expect(handler).toHaveBeenCalledTimes(1);
|
|
175
174
|
await bus.close();
|
|
176
175
|
});
|
|
176
|
+
it('should bind a subscription taken while disconnected on the broker that comes up later', async ()=>{
|
|
177
|
+
const broker = createFakeTransport('rabbitmq');
|
|
178
|
+
EventTransportRegistry.register('rabbitmq', ()=>broker);
|
|
179
|
+
const connectSpy = jest.spyOn(MemoryTransport.prototype, 'connect').mockRejectedValueOnce(new Error('boot failure'));
|
|
180
|
+
const bus = new HybridEventBus({
|
|
181
|
+
transport: 'hybrid'
|
|
182
|
+
});
|
|
183
|
+
await bus.subscribe('storage.#', jest.fn());
|
|
184
|
+
expect(broker.bind).not.toHaveBeenCalled();
|
|
185
|
+
connectSpy.mockRestore();
|
|
186
|
+
// Anything that reconnects must bind what is already subscribed, or the
|
|
187
|
+
// queue stays unbound and this process publishes without ever consuming
|
|
188
|
+
await bus.publish(buildEvent());
|
|
189
|
+
expect(broker.bind).toHaveBeenCalledWith('storage.#');
|
|
190
|
+
await bus.close();
|
|
191
|
+
});
|
|
192
|
+
it('should bind each pattern once, not again on every later subscribe', async ()=>{
|
|
193
|
+
const broker = createFakeTransport('rabbitmq');
|
|
194
|
+
EventTransportRegistry.register('rabbitmq', ()=>broker);
|
|
195
|
+
const bus = new HybridEventBus({
|
|
196
|
+
transport: 'rabbitmq'
|
|
197
|
+
});
|
|
198
|
+
await bus.subscribe('storage.#', jest.fn());
|
|
199
|
+
await bus.subscribe('auth.#', jest.fn());
|
|
200
|
+
expect(broker.bind.mock.calls.map(([pattern])=>pattern)).toEqual([
|
|
201
|
+
'storage.#',
|
|
202
|
+
'auth.#'
|
|
203
|
+
]);
|
|
204
|
+
await bus.close();
|
|
205
|
+
});
|
|
177
206
|
it('should forget its transports after close', async ()=>{
|
|
178
207
|
const bus = new HybridEventBus({
|
|
179
208
|
transport: 'memory'
|
package/fesm/enums/index.js
CHANGED
|
@@ -26,7 +26,6 @@ import { publishDomainEvent } from '../../classes/domain-event.publisher';
|
|
|
26
26
|
import { EventBusRegistry } from '../../classes/event-bus.registry';
|
|
27
27
|
import { EVENT_BUS_INSTANCE } from '../../constants';
|
|
28
28
|
import { OnDomainEvent } from '../../decorators/on-domain-event.decorator';
|
|
29
|
-
import { EventAction } from '../../enums/event-action.enum';
|
|
30
29
|
import { DomainEvent } from '../../interfaces';
|
|
31
30
|
import { EventBusModule } from './event-bus.module';
|
|
32
31
|
import { createModuleEventsProvider } from './module-events.provider';
|
|
@@ -152,7 +151,7 @@ describe('EventBusModule (integration)', ()=>{
|
|
|
152
151
|
await publishDomainEvent({
|
|
153
152
|
module: 'storage',
|
|
154
153
|
entity: 'folder',
|
|
155
|
-
action:
|
|
154
|
+
action: 'created',
|
|
156
155
|
ids: [
|
|
157
156
|
'folder-1'
|
|
158
157
|
]
|
|
@@ -16,9 +16,14 @@ const SENSITIVE_KEYS = [
|
|
|
16
16
|
/**
|
|
17
17
|
* Matched whole, not as a substring - `pass` must be redacted without also
|
|
18
18
|
* redacting `bypassCache`, and a storage row's `key` is a path, not a secret.
|
|
19
|
+
*
|
|
20
|
+
* `config` is the provider settings blob on the storage and email config rows:
|
|
21
|
+
* S3, Azure, SFTP and SMTP credentials live in it, so it never leaves the
|
|
22
|
+
* process, even though the row itself still publishes.
|
|
19
23
|
*/ const SENSITIVE_EXACT_KEYS = [
|
|
20
24
|
'pass',
|
|
21
|
-
'pwd'
|
|
25
|
+
'pwd',
|
|
26
|
+
'config'
|
|
22
27
|
];
|
|
23
28
|
const REDACTED = '[REDACTED]';
|
|
24
29
|
const CIRCULAR = '[CIRCULAR]';
|
|
@@ -57,10 +57,28 @@ describe('sanitizeEventPayload', ()=>{
|
|
|
57
57
|
apiKey: '[REDACTED]'
|
|
58
58
|
});
|
|
59
59
|
});
|
|
60
|
-
it('should redact the
|
|
60
|
+
it('should redact the whole provider settings blob of a storage or email config row', ()=>{
|
|
61
61
|
const result = sanitizeEventPayload({
|
|
62
62
|
name: 'primary-s3',
|
|
63
|
+
provider: 's3',
|
|
64
|
+
isActive: true,
|
|
63
65
|
config: {
|
|
66
|
+
region: 'us-east-1',
|
|
67
|
+
bucket: 'assets',
|
|
68
|
+
accessKeyId: 'AKIA...',
|
|
69
|
+
secretAccessKey: 's3cr3t'
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
expect(result).toEqual({
|
|
73
|
+
name: 'primary-s3',
|
|
74
|
+
provider: 's3',
|
|
75
|
+
isActive: true,
|
|
76
|
+
config: '[REDACTED]'
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
it('should redact the credential keys used by the storage and email providers', ()=>{
|
|
80
|
+
const result = sanitizeEventPayload({
|
|
81
|
+
settings: {
|
|
64
82
|
region: 'us-east-1',
|
|
65
83
|
bucket: 'assets',
|
|
66
84
|
accessKeyId: 'AKIA...',
|
|
@@ -75,8 +93,7 @@ describe('sanitizeEventPayload', ()=>{
|
|
|
75
93
|
}
|
|
76
94
|
});
|
|
77
95
|
expect(result).toEqual({
|
|
78
|
-
|
|
79
|
-
config: {
|
|
96
|
+
settings: {
|
|
80
97
|
region: 'us-east-1',
|
|
81
98
|
bucket: 'assets',
|
|
82
99
|
accessKeyId: '[REDACTED]',
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { EventAction } from '../enums/event-action.enum';
|
|
2
1
|
export type EventTransportLabel = 'memory' | 'rabbitmq' | 'kafka' | 'hybrid';
|
|
3
|
-
export type
|
|
2
|
+
export type CrudEventActionName = 'created' | 'updated' | 'deleted' | 'restored' | 'purged';
|
|
4
3
|
export interface IDomainEventActor {
|
|
5
4
|
userId?: string | null;
|
|
6
5
|
companyId?: string | null;
|
|
@@ -17,7 +16,7 @@ export interface IDomainEvent<T = unknown> {
|
|
|
17
16
|
name: string;
|
|
18
17
|
module: string;
|
|
19
18
|
entity: string;
|
|
20
|
-
action:
|
|
19
|
+
action: string;
|
|
21
20
|
payload: T;
|
|
22
21
|
actor: IDomainEventActor;
|
|
23
22
|
occurredAt: string;
|
|
@@ -41,10 +40,8 @@ export interface IEventBus {
|
|
|
41
40
|
}
|
|
42
41
|
export interface IModuleEventsConfig {
|
|
43
42
|
enabled?: boolean;
|
|
44
|
-
actions?:
|
|
43
|
+
actions?: string[];
|
|
45
44
|
includePayload?: boolean;
|
|
46
|
-
entities?: string[];
|
|
47
|
-
excludeEntities?: string[];
|
|
48
45
|
}
|
|
49
46
|
export interface IRabbitMqTransportConfig {
|
|
50
47
|
url?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flusys/nestjs-shared",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.2",
|
|
4
4
|
"description": "Common shared utilities for Flusys NestJS applications",
|
|
5
5
|
"main": "cjs/index.js",
|
|
6
6
|
"module": "fesm/index.js",
|
|
@@ -112,6 +112,6 @@
|
|
|
112
112
|
"rxjs": "^7.8.0"
|
|
113
113
|
},
|
|
114
114
|
"dependencies": {
|
|
115
|
-
"@flusys/nestjs-core": "7.0.
|
|
115
|
+
"@flusys/nestjs-core": "7.0.2"
|
|
116
116
|
}
|
|
117
117
|
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
Object.defineProperty(exports, "EventAction", {
|
|
6
|
-
enumerable: true,
|
|
7
|
-
get: function() {
|
|
8
|
-
return EventAction;
|
|
9
|
-
}
|
|
10
|
-
});
|
|
11
|
-
var EventAction = /*#__PURE__*/ function(EventAction) {
|
|
12
|
-
EventAction["CREATED"] = "created";
|
|
13
|
-
EventAction["UPDATED"] = "updated";
|
|
14
|
-
EventAction["DELETED"] = "deleted";
|
|
15
|
-
EventAction["RESTORED"] = "restored";
|
|
16
|
-
EventAction["PURGED"] = "purged";
|
|
17
|
-
return EventAction;
|
|
18
|
-
}({});
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export var EventAction = /*#__PURE__*/ function(EventAction) {
|
|
2
|
-
EventAction["CREATED"] = "created";
|
|
3
|
-
EventAction["UPDATED"] = "updated";
|
|
4
|
-
EventAction["DELETED"] = "deleted";
|
|
5
|
-
EventAction["RESTORED"] = "restored";
|
|
6
|
-
EventAction["PURGED"] = "purged";
|
|
7
|
-
return EventAction;
|
|
8
|
-
}({});
|