@privateaim/server-kit 0.8.21 → 0.8.23

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 +45 -0
  2. package/dist/core/component/caller/compound/index.d.ts +2 -0
  3. package/dist/core/component/caller/compound/index.d.ts.map +1 -0
  4. package/dist/core/component/caller/compound/module.d.ts +9 -0
  5. package/dist/core/component/caller/compound/module.d.ts.map +1 -0
  6. package/dist/core/component/caller/direct/index.d.ts +3 -0
  7. package/dist/core/component/caller/direct/index.d.ts.map +1 -0
  8. package/dist/core/component/caller/direct/module.d.ts +23 -0
  9. package/dist/core/component/caller/direct/module.d.ts.map +1 -0
  10. package/dist/core/component/caller/direct/types.d.ts +5 -0
  11. package/dist/core/component/caller/direct/types.d.ts.map +1 -0
  12. package/dist/core/component/caller/index.d.ts +6 -0
  13. package/dist/core/component/caller/index.d.ts.map +1 -0
  14. package/dist/core/component/caller/queue-dispatch/index.d.ts +2 -0
  15. package/dist/core/component/caller/queue-dispatch/index.d.ts.map +1 -0
  16. package/dist/core/component/caller/queue-dispatch/module.d.ts +9 -0
  17. package/dist/core/component/caller/queue-dispatch/module.d.ts.map +1 -0
  18. package/dist/core/component/caller/queue-dispatch/types.d.ts +6 -0
  19. package/dist/core/component/caller/queue-dispatch/types.d.ts.map +1 -0
  20. package/dist/core/component/caller/queue-worker/index.d.ts +2 -0
  21. package/dist/core/component/caller/queue-worker/index.d.ts.map +1 -0
  22. package/dist/core/component/caller/queue-worker/module.d.ts +17 -0
  23. package/dist/core/component/caller/queue-worker/module.d.ts.map +1 -0
  24. package/dist/core/component/caller/queue-worker/types.d.ts +6 -0
  25. package/dist/core/component/caller/queue-worker/types.d.ts.map +1 -0
  26. package/dist/core/component/caller/types.d.ts +13 -0
  27. package/dist/core/component/caller/types.d.ts.map +1 -0
  28. package/dist/core/component/error.d.ts +1 -1
  29. package/dist/core/component/error.d.ts.map +1 -1
  30. package/dist/core/component/handler/index.d.ts +1 -1
  31. package/dist/core/component/handler/index.d.ts.map +1 -1
  32. package/dist/core/component/handler/types.d.ts +8 -7
  33. package/dist/core/component/handler/types.d.ts.map +1 -1
  34. package/dist/core/component/index.d.ts +2 -0
  35. package/dist/core/component/index.d.ts.map +1 -1
  36. package/dist/core/component/module.d.ts +23 -0
  37. package/dist/core/component/module.d.ts.map +1 -0
  38. package/dist/core/component/type.d.ts +26 -9
  39. package/dist/core/component/type.d.ts.map +1 -1
  40. package/dist/core/index.d.ts +0 -1
  41. package/dist/core/index.d.ts.map +1 -1
  42. package/dist/core/queue-router/types.d.ts +2 -1
  43. package/dist/core/queue-router/types.d.ts.map +1 -1
  44. package/dist/index.mjs +388 -290
  45. package/dist/index.mjs.map +1 -1
  46. package/dist/services/cache/adapters/memory.d.ts +3 -3
  47. package/dist/services/cache/adapters/memory.d.ts.map +1 -1
  48. package/dist/services/index.d.ts +1 -0
  49. package/dist/services/index.d.ts.map +1 -1
  50. package/dist/services/redis/module.d.ts +4 -2
  51. package/dist/services/redis/module.d.ts.map +1 -1
  52. package/dist/services/task-manager/helpers.d.ts +3 -0
  53. package/dist/services/task-manager/helpers.d.ts.map +1 -0
  54. package/dist/services/task-manager/index.d.ts +3 -0
  55. package/dist/services/task-manager/index.d.ts.map +1 -0
  56. package/dist/services/task-manager/module.d.ts +33 -0
  57. package/dist/services/task-manager/module.d.ts.map +1 -0
  58. package/dist/services/task-manager/types.d.ts +16 -0
  59. package/dist/services/task-manager/types.d.ts.map +1 -0
  60. package/package.json +16 -15
  61. package/src/core/{queue → component/caller/compound}/index.ts +2 -3
  62. package/src/core/component/caller/compound/module.ts +42 -0
  63. package/src/core/component/caller/direct/index.ts +9 -0
  64. package/src/core/component/caller/direct/module.ts +81 -0
  65. package/src/core/component/caller/direct/types.ts +13 -0
  66. package/src/core/component/caller/index.ts +13 -0
  67. package/src/core/component/caller/queue-dispatch/index.ts +8 -0
  68. package/src/core/component/caller/queue-dispatch/module.ts +49 -0
  69. package/src/core/component/caller/queue-dispatch/types.ts +13 -0
  70. package/src/core/component/caller/queue-worker/index.ts +8 -0
  71. package/src/core/component/caller/queue-worker/module.ts +93 -0
  72. package/src/core/component/caller/queue-worker/types.ts +13 -0
  73. package/src/core/component/caller/types.ts +33 -0
  74. package/src/core/component/error.ts +1 -1
  75. package/src/core/component/handler/index.ts +1 -1
  76. package/src/core/component/handler/types.ts +12 -10
  77. package/src/core/component/index.ts +2 -0
  78. package/src/core/component/module.ts +160 -0
  79. package/src/core/component/type.ts +45 -19
  80. package/src/core/index.ts +0 -1
  81. package/src/core/queue-router/types.ts +4 -2
  82. package/src/services/cache/adapters/memory.ts +7 -4
  83. package/src/services/index.ts +1 -0
  84. package/src/services/redis/module.ts +4 -1
  85. package/src/services/task-manager/helpers.ts +15 -0
  86. package/src/services/task-manager/index.ts +9 -0
  87. package/src/services/task-manager/module.ts +131 -0
  88. package/src/services/task-manager/types.ts +32 -0
  89. package/test/unit/logger.spec.ts +1 -0
  90. package/test/unit/memory-cache.spec.ts +1 -0
  91. package/test/vitest.config.ts +17 -0
  92. package/dist/core/component/handler/module.d.ts +0 -13
  93. package/dist/core/component/handler/module.d.ts.map +0 -1
  94. package/dist/core/queue/index.d.ts +0 -3
  95. package/dist/core/queue/index.d.ts.map +0 -1
  96. package/dist/core/queue/type.d.ts +0 -12
  97. package/dist/core/queue/type.d.ts.map +0 -1
  98. package/dist/core/queue/utils.d.ts +0 -3
  99. package/dist/core/queue/utils.d.ts.map +0 -1
  100. package/dist/index.cjs +0 -970
  101. package/dist/index.cjs.map +0 -1
  102. package/src/core/component/handler/module.ts +0 -74
  103. package/src/core/queue/type.ts +0 -23
  104. package/src/core/queue/utils.ts +0 -17
  105. package/test/jest.config.js +0 -33
@@ -0,0 +1,42 @@
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 type { ComponentEventMap } from '../../type';
10
+ import type { ComponentCaller, ComponentCallerPayload } from '../types';
11
+
12
+ export class CompoundComponentCaller<
13
+ EventMap extends ComponentEventMap = ComponentEventMap,
14
+ Metadata extends ObjectLiteral = ObjectLiteral,
15
+ > implements ComponentCaller<EventMap, Metadata> {
16
+ protected callers : ComponentCaller<EventMap, Metadata>[];
17
+
18
+ constructor(callers: ComponentCaller<EventMap, Metadata>[]) {
19
+ this.callers = callers;
20
+ }
21
+
22
+ async call<Key extends keyof ComponentEventMap>(
23
+ key: Key & string,
24
+ ...payload: ComponentCallerPayload<ComponentEventMap[Key], Metadata>
25
+ ): Promise<void> {
26
+ const [data, metadata] = payload;
27
+
28
+ for (let i = 0; i < this.callers.length; i++) {
29
+ const caller = this.callers[i];
30
+
31
+ try {
32
+ await caller.call(key, data, metadata);
33
+
34
+ return;
35
+ } catch (e) {
36
+ // continue;
37
+ }
38
+ }
39
+
40
+ throw new Error('No caller could call component.');
41
+ }
42
+ }
@@ -0,0 +1,9 @@
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 * from './module';
9
+ export * from './types';
@@ -0,0 +1,81 @@
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 { createNanoID } from '@privateaim/kit';
9
+ import type { ComponentCaller, ComponentCallerPayload } from '../types';
10
+ import type { Component, ComponentEventMap, ComponentHandleOptions } from '../../type';
11
+ import type { ComponentDirectCallerResponse } from './types';
12
+
13
+ export class DirectComponentCaller<
14
+ EventMap extends ComponentEventMap = ComponentEventMap,
15
+ > implements ComponentCaller<EventMap> {
16
+ protected component: Component<EventMap>;
17
+
18
+ constructor(component : Component<EventMap>) {
19
+ this.component = component;
20
+ }
21
+
22
+ /**
23
+ * Call a specific handler and collect all unhandled events.
24
+ *
25
+ * @param key
26
+ * @param payload
27
+ */
28
+ async call<Key extends keyof EventMap>(
29
+ key: Key & string,
30
+ ...payload: ComponentCallerPayload<EventMap[Key]>
31
+ ): Promise<void> {
32
+ const [data, metadata] = payload;
33
+
34
+ await this.callAndWait(key, data, metadata);
35
+ }
36
+
37
+ async callWith<Key extends keyof EventMap>(
38
+ key: Key & string,
39
+ data: ComponentCallerPayload<EventMap[Key]>[0],
40
+ metadata: ComponentCallerPayload<EventMap[Key]>[1],
41
+ options: ComponentHandleOptions<EventMap>,
42
+ ) {
43
+ if (!this.component.handle) {
44
+ throw new Error(`Component ${this.component.constructor.name} can not be called.`);
45
+ }
46
+
47
+ metadata.correlationId = metadata.correlationId || createNanoID();
48
+
49
+ await this.component.handle(
50
+ key,
51
+ data,
52
+ metadata,
53
+ options,
54
+ );
55
+ }
56
+
57
+ /**
58
+ * Call a specific handler and collect all unhandled events.
59
+ *
60
+ * @param key
61
+ * @param payload
62
+ */
63
+ async callAndWait<Key extends keyof EventMap>(
64
+ key: Key & string,
65
+ ...payload: ComponentCallerPayload<EventMap[Key]>
66
+ ): Promise<ComponentDirectCallerResponse<EventMap>> {
67
+ const [data, metadata] = payload;
68
+
69
+ const events : ComponentDirectCallerResponse<EventMap> = {};
70
+
71
+ const options : ComponentHandleOptions<EventMap> = {
72
+ handle: (childValue, childContext) => {
73
+ events[childContext.key] = childValue;
74
+ },
75
+ };
76
+
77
+ await this.callWith(key, data, metadata, options);
78
+
79
+ return events;
80
+ }
81
+ }
@@ -0,0 +1,13 @@
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
+ import type { ComponentEventMap } from '../../type';
8
+
9
+ export type ComponentDirectCallerResponse<
10
+ EventMap extends ComponentEventMap = ComponentEventMap,
11
+ > = {
12
+ [K in keyof EventMap]?: EventMap[K][0]
13
+ };
@@ -0,0 +1,13 @@
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 * from './compound';
9
+ export * from './direct';
10
+ export * from './queue-dispatch';
11
+ export * from './queue-worker';
12
+
13
+ export * from './types';
@@ -0,0 +1,8 @@
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 * from './module';
@@ -0,0 +1,49 @@
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 { ComponentEventMap } from '../../type';
9
+ import type { ComponentCaller, ComponentCallerPayload } from '../types';
10
+ import { buildQueueRouterPublishPayload, isQueueRouterUsable, useQueueRouter } from '../../../queue-router';
11
+ import { useLogger } from '../../../../services';
12
+ import type { QueueDispatchComponentCallerOptions } from './types';
13
+
14
+ export class QueueDispatchComponentCaller<
15
+ EventMap extends ComponentEventMap = ComponentEventMap,
16
+ > implements ComponentCaller<EventMap> {
17
+ protected options : QueueDispatchComponentCallerOptions;
18
+
19
+ constructor(options: QueueDispatchComponentCallerOptions) {
20
+ this.options = options;
21
+ }
22
+
23
+ async call<K extends keyof EventMap>(
24
+ type: K & string,
25
+ ...payload: ComponentCallerPayload<EventMap[K]>
26
+ ): Promise<void> {
27
+ const [data, metadata] = payload;
28
+
29
+ if (!isQueueRouterUsable()) {
30
+ useLogger().warn(`Can not publish ${type} event.`);
31
+ return;
32
+ }
33
+
34
+ const client = useQueueRouter();
35
+ await client.publish(
36
+ buildQueueRouterPublishPayload({
37
+ type,
38
+ data,
39
+ metadata: {
40
+ ...metadata,
41
+ routing: this.options.queue,
42
+ },
43
+ }),
44
+ {
45
+ logging: this.options.logging ?? true,
46
+ },
47
+ );
48
+ }
49
+ }
@@ -0,0 +1,13 @@
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 { QueueRouterRouting } from '../../../queue-router';
9
+
10
+ export type QueueDispatchComponentCallerOptions = {
11
+ queue: QueueRouterRouting,
12
+ logging?: boolean
13
+ };
@@ -0,0 +1,8 @@
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 * from './module';
@@ -0,0 +1,93 @@
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 { Component, ComponentEventMap, ComponentHandleOptions } from '../../type';
9
+ import { buildQueueRouterPublishPayload, isQueueRouterUsable, useQueueRouter } from '../../../queue-router';
10
+ import type { ComponentCaller, ComponentCallerPayload } from '../types';
11
+ import type { QueueSelfComponentCallerOptions } from './types';
12
+ import { useLogger } from '../../../../services';
13
+
14
+ export class QueueWorkerComponentCaller<
15
+ EventMap extends ComponentEventMap = ComponentEventMap,
16
+ > implements ComponentCaller<EventMap>, Component<EventMap> {
17
+ protected component: Component<EventMap>;
18
+
19
+ protected options: QueueSelfComponentCallerOptions;
20
+
21
+ constructor(component: Component<EventMap>, options: QueueSelfComponentCallerOptions) {
22
+ this.component = component;
23
+ this.options = options;
24
+ }
25
+
26
+ async start() {
27
+ await this.component.start();
28
+
29
+ if (!isQueueRouterUsable()) {
30
+ useLogger().warn(`Can not consume queue for component ${this.component.constructor.name}`);
31
+ return;
32
+ }
33
+
34
+ const client = useQueueRouter();
35
+ await client.consumeAny(
36
+ this.options.consumeQueue,
37
+ async (payload) => {
38
+ await this.call(payload.type, payload.data, payload.metadata);
39
+ },
40
+ );
41
+ }
42
+
43
+ /**
44
+ * Call a specific handler and collect all unhandled events.
45
+ *
46
+ * @param key
47
+ * @param payload
48
+ */
49
+ async call<Key extends keyof EventMap>(
50
+ key: Key & string,
51
+ ...payload: ComponentCallerPayload<EventMap[Key]>
52
+ ): Promise<void> {
53
+ const [data, metadata] = payload;
54
+ if (!this.component.handle) {
55
+ throw new Error(`Component ${this.component.constructor.name} can not be called.`);
56
+ }
57
+
58
+ const client = useQueueRouter();
59
+ const options : ComponentHandleOptions<EventMap> = {
60
+ handle: async (
61
+ childValue,
62
+ childContext,
63
+ ) => {
64
+ if (this.options.publishQueue) {
65
+ /**
66
+ *
67
+ * publish unhandled requests to publish queue.
68
+ */
69
+ await client.publish(buildQueueRouterPublishPayload({
70
+ type: childContext.key,
71
+ data: childValue,
72
+ metadata: {
73
+ ...(metadata || {}),
74
+ ...childContext.metadata,
75
+ routing: this.options.publishQueue,
76
+ },
77
+ }));
78
+ } else {
79
+ useLogger().warn(
80
+ `Component ${this.component.constructor.name} event ${childContext.key} could not be handled.`,
81
+ );
82
+ }
83
+ },
84
+ };
85
+
86
+ await this.component.handle(
87
+ key,
88
+ data,
89
+ metadata,
90
+ options,
91
+ );
92
+ }
93
+ }
@@ -0,0 +1,13 @@
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 { QueueRouterRouting } from '../../../queue-router';
9
+
10
+ export type QueueSelfComponentCallerOptions = {
11
+ publishQueue?: QueueRouterRouting,
12
+ consumeQueue: QueueRouterRouting,
13
+ };
@@ -0,0 +1,33 @@
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 type { ComponentEventMap, ComponentEventMapValue } from '../type';
10
+
11
+ export type ComponentCallerPayload<
12
+ EventMapValue extends ComponentEventMapValue = ComponentEventMapValue,
13
+ Metadata extends ObjectLiteral = ObjectLiteral,
14
+ > = [data: EventMapValue[0], metadata: EventMapValue[1] & Metadata];
15
+
16
+ export type ComponentCallerFnArgsForMap<
17
+ EventMap extends ComponentEventMap = ComponentEventMap,
18
+ Metadata extends ObjectLiteral = ObjectLiteral,
19
+ > = {
20
+ [K in keyof EventMap]: [
21
+ key: K,
22
+ ...ComponentCallerPayload<EventMap[K], Metadata>,
23
+ ]
24
+ }[keyof EventMap];
25
+
26
+ export interface ComponentCaller<
27
+ EventMap extends ComponentEventMap = ComponentEventMap,
28
+ Metadata extends ObjectLiteral = ObjectLiteral,
29
+ > {
30
+ call(
31
+ ...input: ComponentCallerFnArgsForMap<EventMap, Metadata>
32
+ ) : Promise<void>;
33
+ }
@@ -8,7 +8,7 @@
8
8
  import type { ComponentErrorOptions } from './type';
9
9
 
10
10
  export class ComponentError extends Error {
11
- public code?: string | null;
11
+ public readonly code?: string | null;
12
12
 
13
13
  constructor(input: ComponentErrorOptions) {
14
14
  super(input.message, { cause: input.cause });
@@ -5,5 +5,5 @@
5
5
  * view the LICENSE file that was distributed with this source code.
6
6
  */
7
7
 
8
- export * from './module';
8
+ export * from './check';
9
9
  export * from './types';
@@ -5,24 +5,26 @@
5
5
  * view the LICENSE file that was distributed with this source code.
6
6
  */
7
7
 
8
- import type { ObjectLiteral } from '../../../type';
8
+ import type { ComponentEventMap, ComponentHandlerCallFnForMap } from '../type';
9
9
 
10
10
  export type ComponentHandlerContext<
11
- KEY extends string = string,
11
+ EventMap extends ComponentEventMap = ComponentEventMap,
12
+ Key extends keyof EventMap = keyof EventMap,
12
13
  > = {
13
- key: KEY,
14
- metadata: ObjectLiteral
14
+ key: Key & string,
15
+ metadata: EventMap[Key][1],
16
+ handle: ComponentHandlerCallFnForMap<EventMap>
15
17
  };
16
18
 
17
19
  export type ComponentHandlerFn<
18
- KEY extends string = string,
19
- VALUE extends ObjectLiteral = ObjectLiteral,
20
- > = (value: VALUE, context: ComponentHandlerContext<KEY>) => Promise<void> | void;
20
+ EventMap extends ComponentEventMap = ComponentEventMap,
21
+ Key extends keyof EventMap = keyof EventMap,
22
+ > = (value: EventMap[Key][0], context: ComponentHandlerContext<EventMap, Key>) => Promise<void> | void;
21
23
 
22
24
  export type ComponentHandler<
23
- KEY extends string = string,
24
- VALUE extends ObjectLiteral = ObjectLiteral,
25
+ EventMap extends ComponentEventMap = ComponentEventMap,
26
+ Key extends keyof EventMap = keyof EventMap,
25
27
  > = {
26
28
  initialize?: () => Promise<void> | void;
27
- handle: ComponentHandlerFn<KEY, VALUE>
29
+ handle: ComponentHandlerFn<EventMap, Key>
28
30
  };
@@ -5,7 +5,9 @@
5
5
  * view the LICENSE file that was distributed with this source code.
6
6
  */
7
7
 
8
+ export * from './caller';
8
9
  export * from './error';
9
10
  export * from './handler';
11
+ export * from './module';
10
12
  export * from './helper';
11
13
  export * from './type';
@@ -0,0 +1,160 @@
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 {
9
+ Component, ComponentEventMap, ComponentHandleOptions, ComponentHandlers,
10
+ } from './type';
11
+ import type {
12
+ ComponentHandler, ComponentHandlerContext, ComponentHandlerFn,
13
+ } from './handler';
14
+
15
+ export abstract class BaseComponent<
16
+ EventMap extends ComponentEventMap = ComponentEventMap,
17
+ > implements Component<EventMap> {
18
+ private initializePromise : Promise<void> | undefined;
19
+
20
+ protected initialized : boolean;
21
+
22
+ protected handlers: ComponentHandlers<EventMap>;
23
+
24
+ protected constructor() {
25
+ this.initializePromise = undefined;
26
+ this.initialized = false;
27
+ this.handlers = new Map();
28
+ }
29
+
30
+ mount<Key extends keyof EventMap>(
31
+ key: Key,
32
+ fn: ComponentHandler<EventMap, Key> | ComponentHandlerFn<EventMap, Key>
33
+ ) : void;
34
+
35
+ mount(
36
+ key: '*',
37
+ fn: ComponentHandler<EventMap> | ComponentHandlerFn<EventMap>
38
+ ) : void;
39
+
40
+ mount(
41
+ key: PropertyKey,
42
+ fn: ComponentHandler<EventMap> | ComponentHandlerFn<EventMap>,
43
+ ) : void {
44
+ this.handlers.set(key as keyof EventMap, fn);
45
+ }
46
+
47
+ unmount<Key extends keyof EventMap>(key: Key) {
48
+ this.handlers.delete(key);
49
+ }
50
+
51
+ async initialize() : Promise<void> {
52
+ if (this.initialized) {
53
+ return Promise.resolve();
54
+ }
55
+
56
+ if (this.initializePromise) {
57
+ return this.initializePromise;
58
+ }
59
+
60
+ const promises: Promise<void>[] = [];
61
+ const keys = Array.from(this.handlers.keys());
62
+ for (let i = 0; i < keys.length; i++) {
63
+ const handler = this.handlers.get(keys[i]);
64
+
65
+ if (
66
+ typeof handler !== 'function' &&
67
+ handler.initialize
68
+ ) {
69
+ promises.push(Promise.resolve().then(() => handler.initialize()));
70
+ }
71
+ }
72
+
73
+ this.initializePromise = new Promise<void>((resolve, reject) => {
74
+ Promise.all(promises)
75
+ .then(() => resolve())
76
+ .catch((err) => reject(err));
77
+ });
78
+
79
+ this.initializePromise.finally(() => {
80
+ setTimeout(() => {
81
+ this.initialized = true;
82
+ this.initializePromise = undefined;
83
+ }, 0);
84
+ });
85
+
86
+ return this.initializePromise;
87
+ }
88
+
89
+ /**
90
+ * Handle specific component event.
91
+ *
92
+ * @param key
93
+ * @param data
94
+ * @param metadata
95
+ * @param options
96
+ */
97
+ async handle<Key extends keyof EventMap>(
98
+ key: Key & string,
99
+ data: EventMap[Key][0],
100
+ metadata: EventMap[Key][1] = {},
101
+ options: ComponentHandleOptions<EventMap> = {},
102
+ ) : Promise<void> {
103
+ await this.initialize();
104
+
105
+ const context : ComponentHandlerContext<EventMap, Key> = {
106
+ key,
107
+ metadata,
108
+ handle: (
109
+ childKey,
110
+ childData,
111
+ childMetadata,
112
+ ) => {
113
+ this.handle(
114
+ childKey as Key & string,
115
+ childData as EventMap[Key][0],
116
+ {
117
+ ...metadata,
118
+ ...(childMetadata || {}),
119
+ } as EventMap[Key][1],
120
+ {
121
+ ...options,
122
+ ...(options || {}),
123
+ },
124
+ );
125
+ },
126
+ };
127
+
128
+ let handler = this.handlers.get(key) as ComponentHandler<EventMap, Key> |
129
+ ComponentHandlerFn<EventMap, Key>;
130
+
131
+ if (handler) {
132
+ if (typeof handler === 'function') {
133
+ return handler(data, context);
134
+ }
135
+
136
+ return handler.handle(data, context);
137
+ }
138
+
139
+ handler = this.handlers.get('*') as ComponentHandler<EventMap, Key> |
140
+ ComponentHandlerFn<EventMap, Key>;
141
+
142
+ if (handler) {
143
+ if (typeof handler === 'function') {
144
+ return Promise.resolve()
145
+ .then(() => handler(data, context));
146
+ }
147
+
148
+ return Promise.resolve()
149
+ .then(() => handler.handle(data, context));
150
+ }
151
+
152
+ if (options.handle) {
153
+ return options.handle(data, context);
154
+ }
155
+
156
+ return Promise.resolve();
157
+ }
158
+
159
+ abstract start() : Promise<void> | void;
160
+ }