@privateaim/server-kit 0.8.15 → 0.8.16

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 (105) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/core/component/handler/check.d.ts +4 -0
  3. package/dist/core/component/handler/check.d.ts.map +1 -0
  4. package/dist/core/component/handler/index.d.ts +3 -0
  5. package/dist/core/component/handler/index.d.ts.map +1 -0
  6. package/dist/core/component/handler/module.d.ts +11 -0
  7. package/dist/core/component/handler/module.d.ts.map +1 -0
  8. package/dist/core/component/handler/types.d.ts +11 -0
  9. package/dist/core/component/handler/types.d.ts.map +1 -0
  10. package/dist/core/component/index.d.ts +1 -0
  11. package/dist/core/component/index.d.ts.map +1 -1
  12. package/dist/core/queue-router/module.d.ts +3 -2
  13. package/dist/core/queue-router/module.d.ts.map +1 -1
  14. package/dist/core/queue-router/types.d.ts +7 -4
  15. package/dist/core/queue-router/types.d.ts.map +1 -1
  16. package/dist/index.cjs +214 -526
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.mjs +208 -484
  19. package/dist/index.mjs.map +1 -1
  20. package/dist/services/amqp/index.d.ts +1 -0
  21. package/dist/services/amqp/index.d.ts.map +1 -1
  22. package/dist/services/amqp/module.d.ts +2 -5
  23. package/dist/services/amqp/module.d.ts.map +1 -1
  24. package/dist/services/amqp/singleton.d.ts +6 -0
  25. package/dist/services/amqp/singleton.d.ts.map +1 -0
  26. package/dist/services/domain-event/module.d.ts +3 -3
  27. package/dist/services/domain-event/module.d.ts.map +1 -1
  28. package/dist/services/domain-event/redis/helpers.d.ts +2 -0
  29. package/dist/services/domain-event/redis/helpers.d.ts.map +1 -0
  30. package/dist/services/domain-event/redis/index.d.ts +1 -0
  31. package/dist/services/domain-event/redis/index.d.ts.map +1 -1
  32. package/dist/services/domain-event/redis/module.d.ts +3 -3
  33. package/dist/services/domain-event/redis/module.d.ts.map +1 -1
  34. package/dist/services/domain-event/socket/helpers.d.ts +3 -0
  35. package/dist/services/domain-event/socket/helpers.d.ts.map +1 -0
  36. package/dist/services/domain-event/socket/index.d.ts +1 -0
  37. package/dist/services/domain-event/socket/index.d.ts.map +1 -1
  38. package/dist/services/domain-event/socket/module.d.ts +3 -3
  39. package/dist/services/domain-event/socket/module.d.ts.map +1 -1
  40. package/dist/services/domain-event/types.d.ts +22 -14
  41. package/dist/services/domain-event/types.d.ts.map +1 -1
  42. package/dist/services/domain-event/utils.d.ts +0 -2
  43. package/dist/services/domain-event/utils.d.ts.map +1 -1
  44. package/dist/services/index.d.ts +0 -2
  45. package/dist/services/index.d.ts.map +1 -1
  46. package/dist/services/logger/module.d.ts.map +1 -1
  47. package/dist/services/logger/types.d.ts +2 -5
  48. package/dist/services/logger/types.d.ts.map +1 -1
  49. package/package.json +3 -5
  50. package/src/core/component/handler/check.ts +23 -0
  51. package/src/{services/loki → core/component/handler}/index.ts +2 -2
  52. package/src/core/component/handler/module.ts +57 -0
  53. package/src/core/component/handler/types.ts +28 -0
  54. package/src/core/component/index.ts +1 -0
  55. package/src/core/queue-router/module.ts +30 -4
  56. package/src/core/queue-router/types.ts +12 -5
  57. package/src/services/amqp/index.ts +1 -0
  58. package/src/services/amqp/module.ts +5 -19
  59. package/src/services/{loki → amqp}/singleton.ts +6 -6
  60. package/src/services/domain-event/module.ts +25 -8
  61. package/src/services/domain-event/redis/helpers.ts +28 -0
  62. package/src/services/domain-event/redis/index.ts +1 -0
  63. package/src/services/domain-event/redis/module.ts +10 -22
  64. package/src/services/domain-event/singleton.ts +3 -3
  65. package/src/services/domain-event/socket/helpers.ts +26 -0
  66. package/src/services/domain-event/socket/index.ts +1 -0
  67. package/src/services/domain-event/socket/module.ts +21 -36
  68. package/src/services/domain-event/types.ts +30 -21
  69. package/src/services/domain-event/utils.ts +0 -12
  70. package/src/services/index.ts +0 -2
  71. package/src/services/logger/module.ts +6 -31
  72. package/src/services/logger/types.ts +3 -6
  73. package/dist/services/log-store/entities/base.d.ts +0 -7
  74. package/dist/services/log-store/entities/base.d.ts.map +0 -1
  75. package/dist/services/log-store/entities/index.d.ts +0 -3
  76. package/dist/services/log-store/entities/index.d.ts.map +0 -1
  77. package/dist/services/log-store/entities/loki.d.ts +0 -13
  78. package/dist/services/log-store/entities/loki.d.ts.map +0 -1
  79. package/dist/services/log-store/entities/memory.d.ts +0 -11
  80. package/dist/services/log-store/entities/memory.d.ts.map +0 -1
  81. package/dist/services/log-store/index.d.ts +0 -4
  82. package/dist/services/log-store/index.d.ts.map +0 -1
  83. package/dist/services/log-store/singleton.d.ts +0 -6
  84. package/dist/services/log-store/singleton.d.ts.map +0 -1
  85. package/dist/services/log-store/types.d.ts +0 -27
  86. package/dist/services/log-store/types.d.ts.map +0 -1
  87. package/dist/services/logger/store.d.ts +0 -14
  88. package/dist/services/logger/store.d.ts.map +0 -1
  89. package/dist/services/loki/index.d.ts +0 -3
  90. package/dist/services/loki/index.d.ts.map +0 -1
  91. package/dist/services/loki/module.d.ts +0 -3
  92. package/dist/services/loki/module.d.ts.map +0 -1
  93. package/dist/services/loki/singleton.d.ts +0 -6
  94. package/dist/services/loki/singleton.d.ts.map +0 -1
  95. package/src/services/log-store/entities/base.ts +0 -25
  96. package/src/services/log-store/entities/index.ts +0 -9
  97. package/src/services/log-store/entities/loki.ts +0 -158
  98. package/src/services/log-store/entities/memory.ts +0 -100
  99. package/src/services/log-store/index.ts +0 -10
  100. package/src/services/log-store/singleton.ts +0 -36
  101. package/src/services/log-store/types.ts +0 -42
  102. package/src/services/logger/store.ts +0 -70
  103. package/src/services/loki/module.ts +0 -30
  104. package/test/unit/log-store.spec.ts +0 -21
  105. package/test/unit/logger.spec.ts +0 -36
@@ -1,11 +1,8 @@
1
1
  import type { Logger, LoggerOptions } from 'winston';
2
- import type { LogStore } from '../log-store';
2
+ export type LoggerTransports = LoggerOptions['transports'];
3
3
  export type LoggerCreateContext = {
4
- directory?: string;
5
4
  options?: Partial<LoggerOptions>;
6
- store?: LogStore;
7
- labels?: Record<string, string>;
5
+ transports?: LoggerTransports;
8
6
  };
9
- export type LoggerTransports = LoggerOptions['transports'];
10
7
  export type { Logger, };
11
8
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/services/logger/types.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,MAAM,mBAAmB,GAAG;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,aAAa,CAAC,YAAY,CAAC,CAAC;AAE3D,YAAY,EACR,MAAM,GACT,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/services/logger/types.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAErD,MAAM,MAAM,gBAAgB,GAAG,aAAa,CAAC,YAAY,CAAC,CAAC;AAE3D,MAAM,MAAM,mBAAmB,GAAG;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IACjC,UAAU,CAAC,EAAE,gBAAgB,CAAA;CAChC,CAAC;AAEF,YAAY,EACR,MAAM,GACT,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@privateaim/server-kit",
3
- "version": "0.8.15",
3
+ "version": "0.8.16",
4
4
  "exports": {
5
5
  "./package.json": "./package.json",
6
6
  ".": {
@@ -28,16 +28,14 @@
28
28
  },
29
29
  "dependencies": {
30
30
  "@ebec/http": "^2.3.0",
31
- "@hapic/loki": "^1.2.0",
32
31
  "@isaacs/ttlcache": "^1.4.1",
33
- "@privateaim/kit": "^0.8.15",
32
+ "@privateaim/kit": "^0.8.16",
34
33
  "@socket.io/redis-emitter": "^5.1.0",
35
34
  "envix": "^1.5.0",
36
35
  "hapic": "^2.7.0",
37
36
  "singa": "^1.1.0",
38
37
  "triple-beam": "^1.4.1",
39
- "winston": "^3.17.0",
40
- "winston-transport": "^4.9.0"
38
+ "winston": "^3.17.0"
41
39
  },
42
40
  "devDependencies": {
43
41
  "@authup/core-http-kit": "^1.0.0-beta.27",
@@ -0,0 +1,23 @@
1
+ /*
2
+ * Copyright (c) 2025.
3
+ * Author Peter Placzek (tada5hi)
4
+ * For the full copyright and license information,
5
+ * view the LICENSE file that was distributed with this source code.
6
+ */
7
+
8
+ import { isObject } from '@privateaim/kit';
9
+ import { hasOwnProperty } from '../../../utils';
10
+
11
+ import type { ComponentHandler, ComponentHandlerFn } from './types';
12
+
13
+ export function isComponentHandler(input: unknown) : input is ComponentHandler {
14
+ if (!isObject(input)) {
15
+ return false;
16
+ }
17
+
18
+ return !(!hasOwnProperty(input, 'execute') || typeof input.execute !== 'function');
19
+ }
20
+
21
+ export function isComponentHandlerFn(input: unknown) : input is ComponentHandlerFn {
22
+ return typeof input === 'function';
23
+ }
@@ -1,9 +1,9 @@
1
1
  /*
2
- * Copyright (c) 2024.
2
+ * Copyright (c) 2025.
3
3
  * Author Peter Placzek (tada5hi)
4
4
  * For the full copyright and license information,
5
5
  * view the LICENSE file that was distributed with this source code.
6
6
  */
7
7
 
8
8
  export * from './module';
9
- export * from './singleton';
9
+ export * from './types';
@@ -0,0 +1,57 @@
1
+ /*
2
+ * Copyright (c) 2025.
3
+ * Author Peter Placzek (tada5hi)
4
+ * For the full copyright and license information,
5
+ * view the LICENSE file that was distributed with this source code.
6
+ */
7
+
8
+ import type { ObjectLiteral } from '../../../type';
9
+ import { isComponentHandlerFn } from './check';
10
+ import type { ComponentHandler, ComponentHandlerFn } from './types';
11
+
12
+ export class ComponentHandlers {
13
+ protected handlers: Record<string, ComponentHandlerFn | ComponentHandler>;
14
+
15
+ constructor() {
16
+ this.handlers = {};
17
+ }
18
+
19
+ mount<K extends string>(key: K, fn: ComponentHandler<K, any> | ComponentHandlerFn<K, any>) {
20
+ this.handlers[key] = fn;
21
+ }
22
+
23
+ unmount(key: string) {
24
+ delete this.handlers[key];
25
+ }
26
+
27
+ async setup() : Promise<void> {
28
+ const keys = Object.keys(this.handlers);
29
+ for (let i = 0; i < keys.length; i++) {
30
+ const handler = this.handlers[keys[i]];
31
+
32
+ if (
33
+ !isComponentHandlerFn(handler) &&
34
+ handler.setup
35
+ ) {
36
+ await handler.setup();
37
+ }
38
+ }
39
+ }
40
+
41
+ async execute(
42
+ key: string,
43
+ value: ObjectLiteral = {},
44
+ metadata: ObjectLiteral = {},
45
+ ) : Promise<void> {
46
+ const handler = this.handlers[key];
47
+ if (!handler) {
48
+ return;
49
+ }
50
+
51
+ if (isComponentHandlerFn(handler)) {
52
+ await handler(value, { key, metadata });
53
+ } else {
54
+ await handler.handle(value, { key, metadata });
55
+ }
56
+ }
57
+ }
@@ -0,0 +1,28 @@
1
+ /*
2
+ * Copyright (c) 2025.
3
+ * Author Peter Placzek (tada5hi)
4
+ * For the full copyright and license information,
5
+ * view the LICENSE file that was distributed with this source code.
6
+ */
7
+
8
+ import type { ObjectLiteral } from '../../../type';
9
+
10
+ export type ComponentHandlerContext<
11
+ KEY extends string = string,
12
+ > = {
13
+ key: KEY,
14
+ metadata: ObjectLiteral
15
+ };
16
+
17
+ export type ComponentHandlerFn<
18
+ KEY extends string = string,
19
+ VALUE extends ObjectLiteral = ObjectLiteral,
20
+ > = (value: VALUE, context: ComponentHandlerContext<KEY>) => Promise<void> | void;
21
+
22
+ export type ComponentHandler<
23
+ KEY extends string = string,
24
+ VALUE extends ObjectLiteral = ObjectLiteral,
25
+ > = {
26
+ setup?: () => Promise<void> | void;
27
+ handle: ComponentHandlerFn<KEY, VALUE>
28
+ };
@@ -6,5 +6,6 @@
6
6
  */
7
7
 
8
8
  export * from './error';
9
+ export * from './handler';
9
10
  export * from './helper';
10
11
  export * from './type';
@@ -13,7 +13,7 @@ import { isQueueRouterPayload } from './helpers';
13
13
  import type {
14
14
  QueueRouterHandler,
15
15
  QueueRouterHandlers,
16
- QueueRouterPayload, QueueRouterRouting,
16
+ QueueRouterPayload, QueueRouterPublishOptions, QueueRouterRouting,
17
17
  } from './types';
18
18
 
19
19
  export class QueueRouter {
@@ -27,7 +27,12 @@ export class QueueRouter {
27
27
 
28
28
  //----------------------------------------------------------------
29
29
 
30
- publish(message: QueueRouterPayload) : Promise<boolean> {
30
+ publish(
31
+ message: QueueRouterPayload,
32
+ options: QueueRouterPublishOptions = {},
33
+ ) : Promise<boolean> {
34
+ options.logging ??= true;
35
+
31
36
  let exchange : Client;
32
37
  if (message.metadata.routing.type === 'work') {
33
38
  exchange = this.driver.of({
@@ -41,7 +46,10 @@ export class QueueRouter {
41
46
  });
42
47
  }
43
48
 
44
- if (isLoggerUsable()) {
49
+ if (
50
+ options.logging &&
51
+ isLoggerUsable()
52
+ ) {
45
53
  useLogger()
46
54
  .debug(`Publishing queue message ${message.type} in ${message.metadata.routing.key}`);
47
55
  }
@@ -54,6 +62,15 @@ export class QueueRouter {
54
62
  });
55
63
  }
56
64
 
65
+ consumeAny(
66
+ routing: QueueRouterRouting,
67
+ fn: (payload: QueueRouterPayload) => Promise<void> | void,
68
+ ) {
69
+ return this.consume(routing, {
70
+ $any: (payload) => fn(payload),
71
+ });
72
+ }
73
+
57
74
  consume(routing: QueueRouterRouting, handlers: QueueRouterHandlers) : Promise<void> {
58
75
  let exchange : Client;
59
76
  if (routing.type === 'work') {
@@ -113,7 +130,16 @@ export class QueueRouter {
113
130
  return;
114
131
  }
115
132
 
116
- await handler(payload);
133
+ try {
134
+ await handler(payload);
135
+ } catch (e) {
136
+ if (isLoggerUsable()) {
137
+ useLogger()
138
+ .error(e);
139
+ }
140
+
141
+ throw e;
142
+ }
117
143
  },
118
144
  });
119
145
  }
@@ -26,6 +26,10 @@ export type QueueRouterPayloadMetadata = {
26
26
  routing: QueueRouterRouting
27
27
  };
28
28
 
29
+ export type QueueRouterPublishOptions = {
30
+ logging?: boolean
31
+ };
32
+
29
33
  export type QueueRouterPayload<
30
34
  T = string,
31
35
  D = Record<string, any>,
@@ -36,18 +40,21 @@ export type QueueRouterPayload<
36
40
  metadata: QueueRouterPayloadMetadata
37
41
  };
38
42
 
39
- export type QueueRouterPayloadInput<T = string, D = Record<string, any>> = {
43
+ export type QueueRouterPayloadInput<
44
+ KEY = string,
45
+ VALUE = Record<string, any>,
46
+ > = {
40
47
  id?: string,
41
- type: T,
42
- data?: D,
48
+ type: KEY,
49
+ data?: VALUE,
43
50
  metadata: Partial<Pick<QueueRouterPayloadMetadata, 'timestamp'>> &
44
51
  Omit<QueueRouterPayloadMetadata, 'timestamp'>
45
52
  };
46
53
 
47
54
  export type QueueRouterHandler<
48
- T = string,
55
+ KEY = string,
49
56
  D = Record<string, any>,
50
- > = (message: QueueRouterPayload<T, D>) => Promise<void> | void;
57
+ > = (message: QueueRouterPayload<KEY, D>) => Promise<void> | void;
51
58
 
52
59
  export type QueueRouterHandlers<
53
60
  R extends Record<string, Record<string, any>> = Record<string, Record<string, any>>,
@@ -6,3 +6,4 @@
6
6
  */
7
7
 
8
8
  export * from './module';
9
+ export * from './singleton';
@@ -1,26 +1,12 @@
1
1
  /*
2
- * Copyright (c) 2024.
2
+ * Copyright (c) 2025.
3
3
  * Author Peter Placzek (tada5hi)
4
4
  * For the full copyright and license information,
5
5
  * view the LICENSE file that was distributed with this source code.
6
6
  */
7
7
 
8
- import type { Client } from 'amqp-extension';
9
- import type { Factory } from 'singa';
10
- import { singa } from 'singa';
8
+ import { Client as AmqpClient } from 'amqp-extension';
11
9
 
12
- const instance = singa<Client>({
13
- name: 'amqp',
14
- });
15
-
16
- export function setAmqpClientFactory(factory: Factory<Client>) {
17
- instance.setFactory(factory);
18
- }
19
-
20
- export function isAmqpClientUsable() {
21
- return instance.has() || instance.hasFactory();
22
- }
23
-
24
- export function useAmqpClient() {
25
- return instance.use();
26
- }
10
+ export {
11
+ AmqpClient,
12
+ };
@@ -5,22 +5,22 @@
5
5
  * view the LICENSE file that was distributed with this source code.
6
6
  */
7
7
 
8
+ import type { Client } from 'amqp-extension';
8
9
  import type { Factory } from 'singa';
9
10
  import { singa } from 'singa';
10
- import type { LokiClient } from '@hapic/loki';
11
11
 
12
- const instance = singa<LokiClient>({
13
- name: 'loki',
12
+ const instance = singa<Client>({
13
+ name: 'amqp',
14
14
  });
15
15
 
16
- export function setLokiFactory(factory: Factory<LokiClient>) {
16
+ export function setAmqpClientFactory(factory: Factory<Client>) {
17
17
  instance.setFactory(factory);
18
18
  }
19
19
 
20
- export function isLokiClientUsable() {
20
+ export function isAmqpClientUsable() {
21
21
  return instance.has() || instance.hasFactory();
22
22
  }
23
23
 
24
- export function useLokiClient() {
24
+ export function useAmqpClient() {
25
25
  return instance.use();
26
26
  }
@@ -8,17 +8,22 @@
8
8
  import type { ObjectLiteral } from '@privateaim/kit';
9
9
  import { buildDomainEventFullName } from '@privateaim/kit';
10
10
  import { isLoggerUsable, useLogger } from '../logger';
11
- import type { DomainEventPublishOptions, IDomainEventPublisher } from './types';
11
+ import type {
12
+ DomainEventConsumeOptions, DomainEventDestination,
13
+ DomainEventPublishOptions,
14
+ IDomainEventConsumer,
15
+ IDomainEventPublisher,
16
+ } from './types';
12
17
 
13
18
  export class DomainEventPublisher implements IDomainEventPublisher {
14
- protected publishers : Set<IDomainEventPublisher>;
19
+ protected consumers : Set<IDomainEventConsumer>;
15
20
 
16
21
  constructor() {
17
- this.publishers = new Set<IDomainEventPublisher>();
22
+ this.consumers = new Set<IDomainEventConsumer>();
18
23
  }
19
24
 
20
- addPublisher(publisher: IDomainEventPublisher) {
21
- this.publishers.add(publisher);
25
+ addConsumer(consumer: IDomainEventConsumer) {
26
+ this.consumers.add(consumer);
22
27
  }
23
28
 
24
29
  async safePublish<T extends ObjectLiteral = ObjectLiteral>(
@@ -41,14 +46,26 @@ export class DomainEventPublisher implements IDomainEventPublisher {
41
46
  useLogger().info(`Publishing event ${buildDomainEventFullName(ctx.metadata.domain, ctx.metadata.event)}`);
42
47
  }
43
48
 
44
- const publishers = this.publishers.values();
49
+ let destinations : DomainEventDestination[] = [];
50
+ if (typeof ctx.destinations === 'function') {
51
+ destinations = ctx.destinations(ctx.data);
52
+ } else {
53
+ destinations = ctx.destinations;
54
+ }
55
+
56
+ const consumeContext : DomainEventConsumeOptions = {
57
+ ...ctx,
58
+ destinations,
59
+ };
60
+
61
+ const consumers = this.consumers.values();
45
62
  while (true) {
46
- const it = publishers.next();
63
+ const it = consumers.next();
47
64
  if (it.done) {
48
65
  return;
49
66
  }
50
67
 
51
- await it.value.publish(ctx);
68
+ await it.value.consume(consumeContext);
52
69
  }
53
70
  }
54
71
  }
@@ -0,0 +1,28 @@
1
+ /*
2
+ * Copyright (c) 2025.
3
+ * Author Peter Placzek (tada5hi)
4
+ * For the full copyright and license information,
5
+ * view the LICENSE file that was distributed with this source code.
6
+ */
7
+
8
+ function stringify(input: string | string[]) {
9
+ return typeof input === 'string' ? input : input.join('/');
10
+ }
11
+
12
+ export function buildDomainEventRedisChannel(
13
+ channel: string | string[],
14
+ namespace?: string | string[],
15
+ ) {
16
+ const channelNormalized = stringify(channel);
17
+
18
+ let namespaceNormalized : string | undefined;
19
+ if (namespace) {
20
+ namespaceNormalized = stringify(namespace);
21
+ }
22
+
23
+ if (typeof namespaceNormalized === 'undefined') {
24
+ return channelNormalized;
25
+ }
26
+
27
+ return `${namespaceNormalized}/${channelNormalized}`;
28
+ }
@@ -6,3 +6,4 @@
6
6
  */
7
7
 
8
8
  export * from './module';
9
+ export * from './helpers';
@@ -7,48 +7,36 @@
7
7
 
8
8
  import type { Client } from 'redis-extension';
9
9
  import type { DomainEventRecord } from '@privateaim/kit';
10
- import type { DomainEventPublishOptions, IDomainEventPublisher } from '../types';
11
- import { buildEventChannelName, transformEventData } from '../utils';
10
+ import type { DomainEventPublishOptions, IDomainEventConsumer } from '../types';
11
+ import { transformEventData } from '../utils';
12
+ import { buildDomainEventRedisChannel } from './helpers';
12
13
 
13
- export class DomainEventRedisPublisher implements IDomainEventPublisher {
14
+ export class DomainEventRedisPublisher implements IDomainEventConsumer {
14
15
  protected driver : Client;
15
16
 
16
17
  constructor(client: Client) {
17
18
  this.driver = client;
18
19
  }
19
20
 
20
- async publish(ctx: DomainEventPublishOptions) : Promise<void> {
21
+ async consume(ctx: DomainEventPublishOptions) : Promise<void> {
21
22
  const payload : DomainEventRecord = {
22
23
  type: ctx.metadata.domain,
23
24
  event: ctx.metadata.event,
24
25
  data: transformEventData(ctx.data),
25
26
  };
27
+
26
28
  const payloadSerialized = JSON.stringify(payload);
27
29
 
28
30
  const pipeline = this.driver.pipeline();
29
31
  for (let i = 0; i < ctx.destinations.length; i++) {
30
32
  const destination = ctx.destinations[i];
31
33
 
32
- let keyPrefix : string | undefined;
33
- if (destination.namespace) {
34
- keyPrefix = typeof destination.namespace === 'function' ?
35
- destination.namespace(ctx.data) :
36
- destination.namespace;
37
- }
38
-
39
- let key : string;
40
- if (keyPrefix) {
41
- key = keyPrefix + buildEventChannelName(destination.channel);
42
- } else {
43
- key = buildEventChannelName(destination.channel);
44
- }
34
+ const key = buildDomainEventRedisChannel(
35
+ destination.channel,
36
+ destination.namespace,
37
+ );
45
38
 
46
39
  pipeline.publish(key, payloadSerialized);
47
-
48
- if (typeof destination.channel === 'function') {
49
- key = keyPrefix + buildEventChannelName(destination.channel, ctx.data.id);
50
- pipeline.publish(key, payloadSerialized);
51
- }
52
40
  }
53
41
 
54
42
  await pipeline.exec();
@@ -9,7 +9,7 @@ import { singa } from 'singa';
9
9
  import { isRedisClientUsable, useRedisClient } from '../redis';
10
10
  import { DomainEventPublisher } from './module';
11
11
  import { DomainEventRedisPublisher } from './redis';
12
- import { DomainEventSocketPublisher } from './socket';
12
+ import { DomainEventSocketConsumer } from './socket';
13
13
 
14
14
  const singaInstance = singa<DomainEventPublisher>({
15
15
  name: 'domainEventPublisher',
@@ -19,8 +19,8 @@ const singaInstance = singa<DomainEventPublisher>({
19
19
  if (isRedisClientUsable()) {
20
20
  const client = useRedisClient();
21
21
 
22
- publisher.addPublisher(new DomainEventRedisPublisher(client));
23
- publisher.addPublisher(new DomainEventSocketPublisher(client));
22
+ publisher.addConsumer(new DomainEventRedisPublisher(client));
23
+ publisher.addConsumer(new DomainEventSocketConsumer(client));
24
24
  }
25
25
 
26
26
  return publisher;
@@ -0,0 +1,26 @@
1
+ /*
2
+ * Copyright (c) 2025.
3
+ * Author Peter Placzek (tada5hi)
4
+ * For the full copyright and license information,
5
+ * view the LICENSE file that was distributed with this source code.
6
+ */
7
+
8
+ export function buildDomainEventSocketNamespace(namespace?: string | string[]) {
9
+ if (typeof namespace === 'undefined') {
10
+ return '/';
11
+ }
12
+
13
+ if (typeof namespace === 'string') {
14
+ return namespace.startsWith('/') ? namespace : `/${namespace}`;
15
+ }
16
+
17
+ return `/${namespace.join('/')}`;
18
+ }
19
+
20
+ export function buildDomainEventSocketChannel(channel: string | string[]) {
21
+ if (typeof channel === 'string') {
22
+ return channel;
23
+ }
24
+
25
+ return channel.join('/');
26
+ }
@@ -6,3 +6,4 @@
6
6
  */
7
7
 
8
8
  export * from './module';
9
+ export * from './helpers';
@@ -8,61 +8,46 @@
8
8
  import { buildDomainEventFullName } from '@privateaim/kit';
9
9
  import { Emitter } from '@socket.io/redis-emitter';
10
10
  import type { Client } from 'redis-extension';
11
- import type { DomainEventPublishOptions, IDomainEventPublisher } from '../types';
12
- import { buildEventChannelName, transformEventData } from '../utils';
11
+ import type { DomainEventPublishOptions, IDomainEventConsumer } from '../types';
12
+ import { transformEventData } from '../utils';
13
+ import { buildDomainEventSocketChannel, buildDomainEventSocketNamespace } from './helpers';
13
14
 
14
- export class DomainEventSocketPublisher implements IDomainEventPublisher {
15
+ export class DomainEventSocketConsumer implements IDomainEventConsumer {
15
16
  protected client : Client;
16
17
 
17
18
  constructor(client: Client) {
18
19
  this.client = client;
19
20
  }
20
21
 
21
- async publish(ctx: DomainEventPublishOptions) : Promise<void> {
22
+ async consume(ctx: DomainEventPublishOptions) : Promise<void> {
22
23
  ctx.data = transformEventData(ctx.data);
23
24
 
24
25
  for (let i = 0; i < ctx.destinations.length; i++) {
25
26
  const destination = ctx.destinations[i];
26
27
 
27
- let namespace : string;
28
- if (destination.namespace) {
29
- namespace = typeof destination.namespace === 'function' ?
30
- destination.namespace(ctx.data) :
31
- destination.namespace;
32
- } else {
33
- namespace = '/';
34
- }
35
-
36
- const emitter = new Emitter(this.client, {}, namespace);
28
+ const namespace = buildDomainEventSocketNamespace(destination.namespace);
29
+ const roomName = buildDomainEventSocketChannel(destination.channel);
37
30
 
38
31
  const fullEventName = buildDomainEventFullName(
39
32
  ctx.metadata.domain,
40
33
  ctx.metadata.event,
41
34
  );
42
35
 
43
- const rooms : string[] = [
44
- buildEventChannelName(destination.channel),
45
- ];
46
-
47
- if (typeof destination.channel === 'function') {
48
- rooms.push(buildEventChannelName(destination.channel, ctx.data.id));
49
- }
36
+ const emitter = new Emitter(this.client, {}, namespace);
50
37
 
51
- for (let j = 0; j < rooms.length; j++) {
52
- emitter
53
- .in(rooms[j])
54
- .emit(fullEventName, {
55
- data: {
56
- data: ctx.data,
57
- type: ctx.metadata.domain,
58
- event: ctx.metadata.event,
59
- },
60
- meta: {
61
- namespace,
62
- roomName: rooms[j],
63
- },
64
- });
65
- }
38
+ emitter
39
+ .in(roomName)
40
+ .emit(fullEventName, {
41
+ data: {
42
+ data: ctx.data,
43
+ type: ctx.metadata.domain,
44
+ event: ctx.metadata.event,
45
+ },
46
+ meta: {
47
+ namespace,
48
+ roomName,
49
+ },
50
+ });
66
51
  }
67
52
  }
68
53
  }