@privateaim/server-kit 0.8.20 → 0.8.22
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/CHANGELOG.md +38 -0
- package/dist/core/component/caller/compound/index.d.ts +2 -0
- package/dist/core/component/caller/compound/index.d.ts.map +1 -0
- package/dist/core/component/caller/compound/module.d.ts +9 -0
- package/dist/core/component/caller/compound/module.d.ts.map +1 -0
- package/dist/core/component/caller/direct/index.d.ts +3 -0
- package/dist/core/component/caller/direct/index.d.ts.map +1 -0
- package/dist/core/component/caller/direct/module.d.ts +23 -0
- package/dist/core/component/caller/direct/module.d.ts.map +1 -0
- package/dist/core/component/caller/direct/types.d.ts +5 -0
- package/dist/core/component/caller/direct/types.d.ts.map +1 -0
- package/dist/core/component/caller/index.d.ts +6 -0
- package/dist/core/component/caller/index.d.ts.map +1 -0
- package/dist/core/component/caller/queue-dispatch/index.d.ts +2 -0
- package/dist/core/component/caller/queue-dispatch/index.d.ts.map +1 -0
- package/dist/core/component/caller/queue-dispatch/module.d.ts +9 -0
- package/dist/core/component/caller/queue-dispatch/module.d.ts.map +1 -0
- package/dist/core/component/caller/queue-dispatch/types.d.ts +6 -0
- package/dist/core/component/caller/queue-dispatch/types.d.ts.map +1 -0
- package/dist/core/component/caller/queue-worker/index.d.ts +2 -0
- package/dist/core/component/caller/queue-worker/index.d.ts.map +1 -0
- package/dist/core/component/caller/queue-worker/module.d.ts +17 -0
- package/dist/core/component/caller/queue-worker/module.d.ts.map +1 -0
- package/dist/core/component/caller/queue-worker/types.d.ts +6 -0
- package/dist/core/component/caller/queue-worker/types.d.ts.map +1 -0
- package/dist/core/component/caller/types.d.ts +13 -0
- package/dist/core/component/caller/types.d.ts.map +1 -0
- package/dist/core/component/error.d.ts +1 -1
- package/dist/core/component/error.d.ts.map +1 -1
- package/dist/core/component/handler/index.d.ts +1 -1
- package/dist/core/component/handler/index.d.ts.map +1 -1
- package/dist/core/component/handler/types.d.ts +8 -7
- package/dist/core/component/handler/types.d.ts.map +1 -1
- package/dist/core/component/index.d.ts +2 -0
- package/dist/core/component/index.d.ts.map +1 -1
- package/dist/core/component/module.d.ts +23 -0
- package/dist/core/component/module.d.ts.map +1 -0
- package/dist/core/component/type.d.ts +26 -9
- package/dist/core/component/type.d.ts.map +1 -1
- package/dist/core/index.d.ts +0 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/queue-router/types.d.ts +2 -1
- package/dist/core/queue-router/types.d.ts.map +1 -1
- package/dist/index.mjs +390 -290
- package/dist/index.mjs.map +1 -1
- package/dist/services/cache/adapters/memory.d.ts +3 -3
- package/dist/services/cache/adapters/memory.d.ts.map +1 -1
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/redis/module.d.ts +4 -2
- package/dist/services/redis/module.d.ts.map +1 -1
- package/dist/services/task-manager/helpers.d.ts +3 -0
- package/dist/services/task-manager/helpers.d.ts.map +1 -0
- package/dist/services/task-manager/index.d.ts +3 -0
- package/dist/services/task-manager/index.d.ts.map +1 -0
- package/dist/services/task-manager/module.d.ts +33 -0
- package/dist/services/task-manager/module.d.ts.map +1 -0
- package/dist/services/task-manager/types.d.ts +16 -0
- package/dist/services/task-manager/types.d.ts.map +1 -0
- package/package.json +16 -15
- package/src/core/{queue → component/caller/compound}/index.ts +2 -3
- package/src/core/component/caller/compound/module.ts +42 -0
- package/src/core/component/caller/direct/index.ts +9 -0
- package/src/core/component/caller/direct/module.ts +84 -0
- package/src/core/component/caller/direct/types.ts +13 -0
- package/src/core/component/caller/index.ts +13 -0
- package/src/core/component/caller/queue-dispatch/index.ts +8 -0
- package/src/core/component/caller/queue-dispatch/module.ts +49 -0
- package/src/core/component/caller/queue-dispatch/types.ts +13 -0
- package/src/core/component/caller/queue-worker/index.ts +8 -0
- package/src/core/component/caller/queue-worker/module.ts +91 -0
- package/src/core/component/caller/queue-worker/types.ts +13 -0
- package/src/core/component/caller/types.ts +33 -0
- package/src/core/component/error.ts +1 -1
- package/src/core/component/handler/index.ts +1 -1
- package/src/core/component/handler/types.ts +12 -10
- package/src/core/component/index.ts +2 -0
- package/src/core/component/module.ts +158 -0
- package/src/core/component/type.ts +45 -19
- package/src/core/index.ts +0 -1
- package/src/core/queue-router/types.ts +4 -2
- package/src/services/cache/adapters/memory.ts +7 -4
- package/src/services/index.ts +1 -0
- package/src/services/redis/module.ts +4 -1
- package/src/services/task-manager/helpers.ts +15 -0
- package/src/services/task-manager/index.ts +9 -0
- package/src/services/task-manager/module.ts +131 -0
- package/src/services/task-manager/types.ts +32 -0
- package/test/unit/logger.spec.ts +1 -0
- package/test/unit/memory-cache.spec.ts +1 -0
- package/test/vitest.config.ts +17 -0
- package/dist/core/component/handler/module.d.ts +0 -13
- package/dist/core/component/handler/module.d.ts.map +0 -1
- package/dist/core/queue/index.d.ts +0 -3
- package/dist/core/queue/index.d.ts.map +0 -1
- package/dist/core/queue/type.d.ts +0 -12
- package/dist/core/queue/type.d.ts.map +0 -1
- package/dist/core/queue/utils.d.ts +0 -3
- package/dist/core/queue/utils.d.ts.map +0 -1
- package/dist/index.cjs +0 -970
- package/dist/index.cjs.map +0 -1
- package/src/core/component/handler/module.ts +0 -74
- package/src/core/queue/type.ts +0 -23
- package/src/core/queue/utils.ts +0 -17
- 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,84 @@
|
|
|
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
|
+
if (!this.component.handle) {
|
|
69
|
+
throw new Error(`Component ${this.component.constructor.name} can not be called.`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const events : ComponentDirectCallerResponse<EventMap> = {};
|
|
73
|
+
|
|
74
|
+
const options : ComponentHandleOptions<EventMap> = {
|
|
75
|
+
handle: (childValue, childContext) => {
|
|
76
|
+
events[childContext.key] = childValue;
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
await this.callWith(key, data, metadata, options);
|
|
81
|
+
|
|
82
|
+
return events;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -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,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,91 @@
|
|
|
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
|
+
if (!isQueueRouterUsable()) {
|
|
28
|
+
useLogger().warn(`Can not consume queue for component ${this.component.constructor.name}`);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const client = useQueueRouter();
|
|
33
|
+
await client.consumeAny(
|
|
34
|
+
this.options.consumeQueue,
|
|
35
|
+
async (payload) => {
|
|
36
|
+
await this.call(payload.type, payload.data, payload.metadata);
|
|
37
|
+
},
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Call a specific handler and collect all unhandled events.
|
|
43
|
+
*
|
|
44
|
+
* @param key
|
|
45
|
+
* @param payload
|
|
46
|
+
*/
|
|
47
|
+
async call<Key extends keyof EventMap>(
|
|
48
|
+
key: Key & string,
|
|
49
|
+
...payload: ComponentCallerPayload<EventMap[Key]>
|
|
50
|
+
): Promise<void> {
|
|
51
|
+
const [data, metadata] = payload;
|
|
52
|
+
if (!this.component.handle) {
|
|
53
|
+
throw new Error(`Component ${this.component.constructor.name} can not be called.`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const client = useQueueRouter();
|
|
57
|
+
const options : ComponentHandleOptions<EventMap> = {
|
|
58
|
+
handle: async (
|
|
59
|
+
childValue,
|
|
60
|
+
childContext,
|
|
61
|
+
) => {
|
|
62
|
+
if (this.options.publishQueue) {
|
|
63
|
+
/**
|
|
64
|
+
*
|
|
65
|
+
* publish unhandled requests to publish queue.
|
|
66
|
+
*/
|
|
67
|
+
await client.publish(buildQueueRouterPublishPayload({
|
|
68
|
+
type: childContext.key,
|
|
69
|
+
data: childValue,
|
|
70
|
+
metadata: {
|
|
71
|
+
...(metadata || {}),
|
|
72
|
+
...childContext.metadata,
|
|
73
|
+
routing: this.options.publishQueue,
|
|
74
|
+
},
|
|
75
|
+
}));
|
|
76
|
+
} else {
|
|
77
|
+
useLogger().warn(
|
|
78
|
+
`Component ${this.component.constructor.name} event ${childContext.key} could not be handled.`,
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
await this.component.handle(
|
|
85
|
+
key,
|
|
86
|
+
data,
|
|
87
|
+
metadata,
|
|
88
|
+
options,
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -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,24 +5,26 @@
|
|
|
5
5
|
* view the LICENSE file that was distributed with this source code.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type {
|
|
8
|
+
import type { ComponentEventMap, ComponentHandlerCallFnForMap } from '../type';
|
|
9
9
|
|
|
10
10
|
export type ComponentHandlerContext<
|
|
11
|
-
|
|
11
|
+
EventMap extends ComponentEventMap = ComponentEventMap,
|
|
12
|
+
Key extends keyof EventMap = keyof EventMap,
|
|
12
13
|
> = {
|
|
13
|
-
key:
|
|
14
|
-
metadata:
|
|
14
|
+
key: Key & string,
|
|
15
|
+
metadata: EventMap[Key][1],
|
|
16
|
+
handle: ComponentHandlerCallFnForMap<EventMap>
|
|
15
17
|
};
|
|
16
18
|
|
|
17
19
|
export type ComponentHandlerFn<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
> = (value:
|
|
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
|
-
|
|
24
|
-
|
|
25
|
+
EventMap extends ComponentEventMap = ComponentEventMap,
|
|
26
|
+
Key extends keyof EventMap = keyof EventMap,
|
|
25
27
|
> = {
|
|
26
28
|
initialize?: () => Promise<void> | void;
|
|
27
|
-
handle: ComponentHandlerFn<
|
|
29
|
+
handle: ComponentHandlerFn<EventMap, Key>
|
|
28
30
|
};
|
|
@@ -0,0 +1,158 @@
|
|
|
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 handler(data, context);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return handler.handle(data, context);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (options.handle) {
|
|
151
|
+
return options.handle(data, context);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return Promise.resolve();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
abstract start() : Promise<void> | void;
|
|
158
|
+
}
|