@asenajs/asena 0.7.0 → 0.8.0
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 +2 -2
- package/dist/lib/adapter/AsenaAdapter.d.ts +5 -3
- package/dist/lib/adapter/AsenaAdapter.js.map +1 -1
- package/dist/lib/adapter/AsenaContext.d.ts +6 -0
- package/dist/lib/adapter/types/ServeOptions.d.ts +16 -0
- package/dist/lib/ioc/Container.d.ts +25 -0
- package/dist/lib/ioc/Container.js +47 -0
- package/dist/lib/ioc/Container.js.map +1 -1
- package/dist/lib/ioc/CoreContainer.d.ts +5 -3
- package/dist/lib/ioc/CoreContainer.js +9 -3
- package/dist/lib/ioc/CoreContainer.js.map +1 -1
- package/dist/lib/ioc/IocEngine.js +4 -5
- package/dist/lib/ioc/IocEngine.js.map +1 -1
- package/dist/lib/ioc/component/decorators/Inject.js +16 -0
- package/dist/lib/ioc/component/decorators/Inject.js.map +1 -1
- package/dist/lib/ioc/constants/ComponentConstants.d.ts +4 -0
- package/dist/lib/ioc/constants/ComponentConstants.js +5 -0
- package/dist/lib/ioc/constants/ComponentConstants.js.map +1 -1
- package/dist/lib/ioc/types/ICoreServiceNamesType.d.ts +1 -0
- package/dist/lib/ioc/types/ICoreServiceNamesType.js +1 -0
- package/dist/lib/ioc/types/ICoreServiceNamesType.js.map +1 -1
- package/dist/lib/ioc/types/InjectableComponent.d.ts +10 -0
- package/dist/lib/ioc/types/decorators/ComponentType.d.ts +2 -1
- package/dist/lib/ioc/types/decorators/ComponentType.js +1 -0
- package/dist/lib/ioc/types/decorators/ComponentType.js.map +1 -1
- package/dist/lib/server/AsenaServer.d.ts +46 -3
- package/dist/lib/server/AsenaServer.js +159 -29
- package/dist/lib/server/AsenaServer.js.map +1 -1
- package/dist/lib/server/AsenaServerFactory.d.ts +38 -3
- package/dist/lib/server/AsenaServerFactory.js +21 -2
- package/dist/lib/server/AsenaServerFactory.js.map +1 -1
- package/dist/lib/server/config/AsenaConfig.d.ts +82 -4
- package/dist/lib/server/config/AsenaConfig.js +39 -1
- package/dist/lib/server/config/AsenaConfig.js.map +1 -1
- package/dist/lib/server/decorators/components/FrontendController.js.map +1 -1
- package/dist/lib/server/decorators/components/MessageController.d.ts +49 -0
- package/dist/lib/server/decorators/components/MessageController.js +62 -0
- package/dist/lib/server/decorators/components/MessageController.js.map +1 -0
- package/dist/lib/server/decorators/components/index.d.ts +1 -0
- package/dist/lib/server/decorators/components/index.js +1 -0
- package/dist/lib/server/decorators/components/index.js.map +1 -1
- package/dist/lib/server/event/EventDispatchService.d.ts +3 -7
- package/dist/lib/server/event/EventDispatchService.js +9 -40
- package/dist/lib/server/event/EventDispatchService.js.map +1 -1
- package/dist/lib/server/event/PatternHandlerIndex.d.ts +53 -0
- package/dist/lib/server/event/PatternHandlerIndex.js +100 -0
- package/dist/lib/server/event/PatternHandlerIndex.js.map +1 -0
- package/dist/lib/server/event/decorators/On.d.ts +4 -0
- package/dist/lib/server/event/decorators/On.js +6 -0
- package/dist/lib/server/event/decorators/On.js.map +1 -1
- package/dist/lib/server/event/index.d.ts +1 -0
- package/dist/lib/server/event/index.js +2 -0
- package/dist/lib/server/event/index.js.map +1 -1
- package/dist/lib/server/event/types.d.ts +12 -0
- package/dist/lib/server/health/HealthServer.d.ts +26 -0
- package/dist/lib/server/health/HealthServer.js +63 -0
- package/dist/lib/server/health/HealthServer.js.map +1 -0
- package/dist/lib/server/health/index.d.ts +1 -0
- package/dist/lib/server/health/index.js +2 -0
- package/dist/lib/server/health/index.js.map +1 -0
- package/dist/lib/server/messaging/Ulak.d.ts +156 -0
- package/dist/lib/server/messaging/Ulak.js +174 -0
- package/dist/lib/server/messaging/Ulak.js.map +1 -1
- package/dist/lib/server/messaging/types.d.ts +5 -1
- package/dist/lib/server/messaging/types.js +5 -0
- package/dist/lib/server/messaging/types.js.map +1 -1
- package/dist/lib/server/microservice/InMemoryTransport.d.ts +45 -0
- package/dist/lib/server/microservice/InMemoryTransport.js +124 -0
- package/dist/lib/server/microservice/InMemoryTransport.js.map +1 -0
- package/dist/lib/server/microservice/MicroserviceTransport.d.ts +132 -0
- package/dist/lib/server/microservice/MicroserviceTransport.js +2 -0
- package/dist/lib/server/microservice/MicroserviceTransport.js.map +1 -0
- package/dist/lib/server/microservice/decorators/EventPattern.d.ts +38 -0
- package/dist/lib/server/microservice/decorators/EventPattern.js +59 -0
- package/dist/lib/server/microservice/decorators/EventPattern.js.map +1 -0
- package/dist/lib/server/microservice/decorators/MessagePattern.d.ts +31 -0
- package/dist/lib/server/microservice/decorators/MessagePattern.js +55 -0
- package/dist/lib/server/microservice/decorators/MessagePattern.js.map +1 -0
- package/dist/lib/server/microservice/decorators/index.d.ts +2 -0
- package/dist/lib/server/microservice/decorators/index.js +3 -0
- package/dist/lib/server/microservice/decorators/index.js.map +1 -0
- package/dist/lib/server/microservice/index.d.ts +5 -0
- package/dist/lib/server/microservice/index.js +11 -0
- package/dist/lib/server/microservice/index.js.map +1 -0
- package/dist/lib/server/microservice/interceptorChain.d.ts +20 -0
- package/dist/lib/server/microservice/interceptorChain.js +39 -0
- package/dist/lib/server/microservice/interceptorChain.js.map +1 -0
- package/dist/lib/server/microservice/types.d.ts +142 -0
- package/dist/lib/server/microservice/types.js +5 -0
- package/dist/lib/server/microservice/types.js.map +1 -0
- package/dist/lib/server/src/services/PrepareEventService.d.ts +4 -1
- package/dist/lib/server/src/services/PrepareEventService.js +10 -3
- package/dist/lib/server/src/services/PrepareEventService.js.map +1 -1
- package/dist/lib/server/src/services/PrepareFrontendControllerService.d.ts +1 -0
- package/dist/lib/server/src/services/PrepareFrontendControllerService.js +1 -1
- package/dist/lib/server/src/services/PrepareFrontendControllerService.js.map +1 -1
- package/dist/lib/server/src/services/PrepareMicroserviceService.d.ts +66 -0
- package/dist/lib/server/src/services/PrepareMicroserviceService.js +193 -0
- package/dist/lib/server/src/services/PrepareMicroserviceService.js.map +1 -0
- package/dist/lib/server/src/services/PrepareScheduleService.js.map +1 -1
- package/dist/lib/server/web/decorators/methods/Connect.js +9 -1
- package/dist/lib/server/web/decorators/methods/Connect.js.map +1 -1
- package/dist/lib/server/web/decorators/methods/Options.js +9 -1
- package/dist/lib/server/web/decorators/methods/Options.js.map +1 -1
- package/dist/lib/server/web/websocket/AsenaSocket.js.map +1 -1
- package/dist/lib/test/factory/deepMock.d.ts +25 -0
- package/dist/lib/test/factory/deepMock.js +105 -0
- package/dist/lib/test/factory/deepMock.js.map +1 -0
- package/dist/lib/test/factory/ulakStub.d.ts +44 -0
- package/dist/lib/test/factory/ulakStub.js +40 -0
- package/dist/lib/test/factory/ulakStub.js.map +1 -0
- package/dist/lib/test/harness/createTestApp.d.ts +33 -0
- package/dist/lib/test/harness/createTestApp.js +105 -0
- package/dist/lib/test/harness/createTestApp.js.map +1 -0
- package/dist/lib/test/harness/createWebTest.d.ts +28 -0
- package/dist/lib/test/harness/createWebTest.js +127 -0
- package/dist/lib/test/harness/createWebTest.js.map +1 -0
- package/dist/lib/test/harness/silentLogger.d.ts +27 -0
- package/dist/lib/test/harness/silentLogger.js +54 -0
- package/dist/lib/test/harness/silentLogger.js.map +1 -0
- package/dist/lib/test/harness/types.d.ts +147 -0
- package/dist/lib/test/harness/types.js +2 -0
- package/dist/lib/test/harness/types.js.map +1 -0
- package/dist/lib/test/http/TestHttpCall.d.ts +78 -0
- package/dist/lib/test/http/TestHttpCall.js +149 -0
- package/dist/lib/test/http/TestHttpCall.js.map +1 -0
- package/dist/lib/test/http/TestHttpResponse.d.ts +46 -0
- package/dist/lib/test/http/TestHttpResponse.js +70 -0
- package/dist/lib/test/http/TestHttpResponse.js.map +1 -0
- package/dist/lib/test/index.d.ts +9 -0
- package/dist/lib/test/index.js +8 -0
- package/dist/lib/test/index.js.map +1 -1
- package/dist/lib/test/metadata/discovery.d.ts +21 -0
- package/dist/lib/test/metadata/discovery.js +37 -8
- package/dist/lib/test/metadata/discovery.js.map +1 -1
- package/dist/lib/test/mockComponent.d.ts +25 -0
- package/dist/lib/test/mockComponent.js +39 -6
- package/dist/lib/test/mockComponent.js.map +1 -1
- package/dist/lib/test/types.d.ts +13 -0
- package/package.json +11 -7
|
@@ -1,6 +1,57 @@
|
|
|
1
1
|
import type { AsenaContext, AsenaServeOptions } from '../../adapter';
|
|
2
2
|
import type { WebSocketTransport } from '../web/websocket';
|
|
3
3
|
import type { MiddlewareClass } from '../web/middleware';
|
|
4
|
+
import type { MessagingInterceptor } from '../microservice/types';
|
|
5
|
+
import type { MicroserviceTransport } from '../microservice/MicroserviceTransport';
|
|
6
|
+
/**
|
|
7
|
+
* Object form of the transport() hook - configures WebSocket and microservice
|
|
8
|
+
* transports separately (all fields optional)
|
|
9
|
+
*/
|
|
10
|
+
export interface AsenaTransportConfig {
|
|
11
|
+
/**
|
|
12
|
+
* WebSocket transport for cross-pod messaging (same as the bare return form)
|
|
13
|
+
*/
|
|
14
|
+
websocket?: WebSocketTransport | Promise<WebSocketTransport>;
|
|
15
|
+
/**
|
|
16
|
+
* Microservice transport(s). A single transport is registered under the
|
|
17
|
+
* name 'default'; a named map allows multiple brokers in one project
|
|
18
|
+
* (e.g. part on Redis, part on NATS).
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* microservice: new RedisMicroserviceTransport({ ... })
|
|
22
|
+
* @example
|
|
23
|
+
* microservice: { default: redisTransport, analytics: natsTransport }
|
|
24
|
+
*/
|
|
25
|
+
microservice?: MicroserviceTransport | Record<string, MicroserviceTransport> | Promise<MicroserviceTransport | Record<string, MicroserviceTransport>>;
|
|
26
|
+
/**
|
|
27
|
+
* Messaging interceptors applied to all microservice transports
|
|
28
|
+
* (e.g. OpenTelemetry trace propagation)
|
|
29
|
+
*/
|
|
30
|
+
interceptors?: MessagingInterceptor[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Normalized result of the transport() hook
|
|
34
|
+
*/
|
|
35
|
+
export interface NormalizedTransportConfig {
|
|
36
|
+
websocket?: WebSocketTransport;
|
|
37
|
+
microservices: Map<string, MicroserviceTransport>;
|
|
38
|
+
interceptors: MessagingInterceptor[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Normalize the transport() hook result into a single shape.
|
|
42
|
+
*
|
|
43
|
+
* - A bare WebSocketTransport (has a publish function) is the legacy form → { websocket }
|
|
44
|
+
* - An object form is discriminated per field; a single MicroserviceTransport
|
|
45
|
+
* (has a send function) becomes the 'default' named transport
|
|
46
|
+
* - An object with none of the known fields throws (catches accidentally
|
|
47
|
+
* returning a bare MicroserviceTransport, which would otherwise be a silent no-op)
|
|
48
|
+
*
|
|
49
|
+
* CAVEAT: the legacy detection is duck-typed on `publish`. A custom
|
|
50
|
+
* MicroserviceTransport that also defines a `publish` method would be
|
|
51
|
+
* mistaken for a bare WebSocketTransport when returned bare - such
|
|
52
|
+
* transports must use the explicit `{ microservice: ... }` object form.
|
|
53
|
+
*/
|
|
54
|
+
export declare function normalizeTransportConfig(result: WebSocketTransport | AsenaTransportConfig): Promise<NormalizedTransportConfig>;
|
|
4
55
|
/**
|
|
5
56
|
* Route configuration for global middleware
|
|
6
57
|
*/
|
|
@@ -114,18 +165,45 @@ export interface AsenaConfig<C extends AsenaContext<any, any> = AsenaContext<any
|
|
|
114
165
|
*/
|
|
115
166
|
globalMiddlewares?(): Promise<GlobalMiddlewareEntry[]> | GlobalMiddlewareEntry[];
|
|
116
167
|
/**
|
|
117
|
-
*
|
|
168
|
+
* Transport configuration for cross-pod WebSocket messaging and
|
|
169
|
+
* microservice messaging.
|
|
118
170
|
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
171
|
+
* Two return forms are supported:
|
|
172
|
+
* 1. Bare WebSocketTransport (legacy, backward compatible) - configures
|
|
173
|
+
* only the WebSocket transport. When not specified, BunLocalTransport
|
|
174
|
+
* is used (single-pod, zero overhead).
|
|
175
|
+
* 2. AsenaTransportConfig object - configures WebSocket and microservice
|
|
176
|
+
* transports separately, plus messaging interceptors.
|
|
121
177
|
*
|
|
122
178
|
* @example
|
|
123
179
|
* ```typescript
|
|
180
|
+
* // Legacy form - WebSocket only
|
|
124
181
|
* transport() {
|
|
125
182
|
* return new RedisTransport(this.redis);
|
|
126
183
|
* }
|
|
184
|
+
*
|
|
185
|
+
* // Object form - WebSocket + microservice
|
|
186
|
+
* transport() {
|
|
187
|
+
* return {
|
|
188
|
+
* websocket: new RedisTransport(this.redis),
|
|
189
|
+
* microservice: new RedisMicroserviceTransport({
|
|
190
|
+
* url: 'redis://localhost:6379',
|
|
191
|
+
* serviceName: 'order-service',
|
|
192
|
+
* }),
|
|
193
|
+
* };
|
|
194
|
+
* }
|
|
195
|
+
*
|
|
196
|
+
* // Multiple named microservice transports (multi-broker projects)
|
|
197
|
+
* transport() {
|
|
198
|
+
* return {
|
|
199
|
+
* microservice: {
|
|
200
|
+
* default: new RedisMicroserviceTransport({ ... }),
|
|
201
|
+
* analytics: new NatsMicroserviceTransport({ ... }),
|
|
202
|
+
* },
|
|
203
|
+
* };
|
|
204
|
+
* }
|
|
127
205
|
* ```
|
|
128
206
|
*/
|
|
129
|
-
transport?(): WebSocketTransport | Promise<WebSocketTransport>;
|
|
207
|
+
transport?(): WebSocketTransport | AsenaTransportConfig | Promise<WebSocketTransport | AsenaTransportConfig>;
|
|
130
208
|
}
|
|
131
209
|
export type AsenaConfigFunctions = 'onError' | 'serveOptions' | 'globalMiddlewares' | 'transport';
|
|
@@ -1,2 +1,40 @@
|
|
|
1
|
-
|
|
1
|
+
import { DEFAULT_TRANSPORT_NAME } from '../microservice/types';
|
|
2
|
+
/**
|
|
3
|
+
* Normalize the transport() hook result into a single shape.
|
|
4
|
+
*
|
|
5
|
+
* - A bare WebSocketTransport (has a publish function) is the legacy form → { websocket }
|
|
6
|
+
* - An object form is discriminated per field; a single MicroserviceTransport
|
|
7
|
+
* (has a send function) becomes the 'default' named transport
|
|
8
|
+
* - An object with none of the known fields throws (catches accidentally
|
|
9
|
+
* returning a bare MicroserviceTransport, which would otherwise be a silent no-op)
|
|
10
|
+
*
|
|
11
|
+
* CAVEAT: the legacy detection is duck-typed on `publish`. A custom
|
|
12
|
+
* MicroserviceTransport that also defines a `publish` method would be
|
|
13
|
+
* mistaken for a bare WebSocketTransport when returned bare - such
|
|
14
|
+
* transports must use the explicit `{ microservice: ... }` object form.
|
|
15
|
+
*/
|
|
16
|
+
export async function normalizeTransportConfig(result) {
|
|
17
|
+
// Legacy form: bare WebSocketTransport (publish is its only required member)
|
|
18
|
+
if (typeof result.publish === 'function') {
|
|
19
|
+
return { websocket: result, microservices: new Map(), interceptors: [] };
|
|
20
|
+
}
|
|
21
|
+
const config = result;
|
|
22
|
+
if (config.websocket === undefined && config.microservice === undefined && config.interceptors === undefined) {
|
|
23
|
+
throw new Error('transport() returned an object without websocket/microservice/interceptors fields - return a WebSocketTransport or an AsenaTransportConfig object');
|
|
24
|
+
}
|
|
25
|
+
const websocket = config.websocket ? await config.websocket : undefined;
|
|
26
|
+
const microservices = new Map();
|
|
27
|
+
if (config.microservice) {
|
|
28
|
+
const resolved = await config.microservice;
|
|
29
|
+
if (typeof resolved.send === 'function') {
|
|
30
|
+
microservices.set(DEFAULT_TRANSPORT_NAME, resolved);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
for (const [name, transport] of Object.entries(resolved)) {
|
|
34
|
+
microservices.set(name, transport);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return { websocket, microservices, interceptors: config.interceptors || [] };
|
|
39
|
+
}
|
|
2
40
|
//# sourceMappingURL=AsenaConfig.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AsenaConfig.js","sourceRoot":"","sources":["../../../../lib/server/config/AsenaConfig.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"AsenaConfig.js","sourceRoot":"","sources":["../../../../lib/server/config/AsenaConfig.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AA2C/D;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,MAAiD;IAEjD,6EAA6E;IAC7E,IAAI,OAAQ,MAA6B,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;QACjE,OAAO,EAAE,SAAS,EAAE,MAA4B,EAAE,aAAa,EAAE,IAAI,GAAG,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;IACjG,CAAC;IAED,MAAM,MAAM,GAAG,MAA8B,CAAC;IAE9C,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS,IAAI,MAAM,CAAC,YAAY,KAAK,SAAS,IAAI,MAAM,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;QAC7G,MAAM,IAAI,KAAK,CACb,mJAAmJ,CACpJ,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAExE,MAAM,aAAa,GAAG,IAAI,GAAG,EAAiC,CAAC;IAE/D,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QACxB,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC;QAE3C,IAAI,OAAQ,QAAkC,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YACnE,aAAa,CAAC,GAAG,CAAC,sBAAsB,EAAE,QAAiC,CAAC,CAAC;QAC/E,CAAC;aAAM,CAAC;YACN,KAAK,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAiD,CAAC,EAAE,CAAC;gBAClG,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YACrC,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,EAAE,EAAE,CAAC;AAC/E,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FrontendController.js","sourceRoot":"","sources":["../../../../../lib/server/decorators/components/FrontendController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAOnE;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,MAAyC,EAAkB,EAAE;IAC9F,MAAM,OAAO,GACX,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAE3G,OAAO,eAAe,CAAC,aAAa,CAAC,mBAAmB,EAAE,OAAO,EAAE,CAAC,MAAM,EAAE,EAAE;QAC5E,mBAAmB,
|
|
1
|
+
{"version":3,"file":"FrontendController.js","sourceRoot":"","sources":["../../../../../lib/server/decorators/components/FrontendController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAOnE;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,MAAyC,EAAkB,EAAE;IAC9F,MAAM,OAAO,GACX,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAE3G,OAAO,eAAe,CAAC,aAAa,CAAC,mBAAmB,EAAE,OAAO,EAAE,CAAC,MAAM,EAAE,EAAE;QAC5E,mBAAmB,CAAS,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,GAAG,EAAE,MAAM,CAAC,CAAC;IAC5G,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { MessageControllerParams } from '../../microservice';
|
|
2
|
+
/**
|
|
3
|
+
* @description MessageController decorator - Marks a class as a microservice message controller
|
|
4
|
+
*
|
|
5
|
+
* Message controllers contain @MessagePattern (request/response) and
|
|
6
|
+
* @EventPattern (fire-and-forget) decorated methods. They are registered into the
|
|
7
|
+
* microservice transport configured via the @Config transport() hook.
|
|
8
|
+
*
|
|
9
|
+
* The prefix is joined (with a dot) onto every @MessagePattern AND @EventPattern
|
|
10
|
+
* in the class. A single handler opts out with `prefix: false`.
|
|
11
|
+
*
|
|
12
|
+
* @param params - Optional configuration or prefix string
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* // With prefix
|
|
16
|
+
* @MessageController('order')
|
|
17
|
+
* export class OrderHandler {
|
|
18
|
+
* @MessagePattern('create') // Handles 'order.create'
|
|
19
|
+
* async create(data: CreateOrderDto, context: MessageContext) {
|
|
20
|
+
* return this.orderService.create(data);
|
|
21
|
+
* }
|
|
22
|
+
*
|
|
23
|
+
* @EventPattern('created') // Handles 'order.created'
|
|
24
|
+
* async onCreated(event: OrderEvent) { }
|
|
25
|
+
*
|
|
26
|
+
* // Absolute - another service's event vocabulary
|
|
27
|
+
* @EventPattern({ pattern: 'payment.completed', prefix: false })
|
|
28
|
+
* async onPaymentCompleted(event: PaymentEvent) { }
|
|
29
|
+
* }
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* // Without prefix
|
|
33
|
+
* @MessageController()
|
|
34
|
+
* export class GlobalHandler {
|
|
35
|
+
* @MessagePattern('ping') // Handles 'ping'
|
|
36
|
+
* async ping() {
|
|
37
|
+
* return 'pong';
|
|
38
|
+
* }
|
|
39
|
+
* }
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* // Bound to a named transport (multi-broker projects)
|
|
43
|
+
* @MessageController({ prefix: 'metrics', transport: 'analytics' })
|
|
44
|
+
* export class AnalyticsHandler {
|
|
45
|
+
* @EventPattern('page.viewed') // Handles 'metrics.page.viewed'
|
|
46
|
+
* async onPageViewed(event: PageViewedEvent) { }
|
|
47
|
+
* }
|
|
48
|
+
*/
|
|
49
|
+
export declare const MessageController: (params?: MessageControllerParams | string) => ClassDecorator;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { ComponentConstants, ComponentType } from '../../../ioc';
|
|
2
|
+
import { defineComponent } from '../../../ioc/component';
|
|
3
|
+
import { defineTypedMetadata } from '../../../utils';
|
|
4
|
+
import { DEFAULT_TRANSPORT_NAME } from '../../microservice';
|
|
5
|
+
/**
|
|
6
|
+
* @description MessageController decorator - Marks a class as a microservice message controller
|
|
7
|
+
*
|
|
8
|
+
* Message controllers contain @MessagePattern (request/response) and
|
|
9
|
+
* @EventPattern (fire-and-forget) decorated methods. They are registered into the
|
|
10
|
+
* microservice transport configured via the @Config transport() hook.
|
|
11
|
+
*
|
|
12
|
+
* The prefix is joined (with a dot) onto every @MessagePattern AND @EventPattern
|
|
13
|
+
* in the class. A single handler opts out with `prefix: false`.
|
|
14
|
+
*
|
|
15
|
+
* @param params - Optional configuration or prefix string
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* // With prefix
|
|
19
|
+
* @MessageController('order')
|
|
20
|
+
* export class OrderHandler {
|
|
21
|
+
* @MessagePattern('create') // Handles 'order.create'
|
|
22
|
+
* async create(data: CreateOrderDto, context: MessageContext) {
|
|
23
|
+
* return this.orderService.create(data);
|
|
24
|
+
* }
|
|
25
|
+
*
|
|
26
|
+
* @EventPattern('created') // Handles 'order.created'
|
|
27
|
+
* async onCreated(event: OrderEvent) { }
|
|
28
|
+
*
|
|
29
|
+
* // Absolute - another service's event vocabulary
|
|
30
|
+
* @EventPattern({ pattern: 'payment.completed', prefix: false })
|
|
31
|
+
* async onPaymentCompleted(event: PaymentEvent) { }
|
|
32
|
+
* }
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* // Without prefix
|
|
36
|
+
* @MessageController()
|
|
37
|
+
* export class GlobalHandler {
|
|
38
|
+
* @MessagePattern('ping') // Handles 'ping'
|
|
39
|
+
* async ping() {
|
|
40
|
+
* return 'pong';
|
|
41
|
+
* }
|
|
42
|
+
* }
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* // Bound to a named transport (multi-broker projects)
|
|
46
|
+
* @MessageController({ prefix: 'metrics', transport: 'analytics' })
|
|
47
|
+
* export class AnalyticsHandler {
|
|
48
|
+
* @EventPattern('page.viewed') // Handles 'metrics.page.viewed'
|
|
49
|
+
* async onPageViewed(event: PageViewedEvent) { }
|
|
50
|
+
* }
|
|
51
|
+
*/
|
|
52
|
+
export const MessageController = (params) => {
|
|
53
|
+
// Normalize params BEFORE defineComponent - a bare string must become a prefix,
|
|
54
|
+
// otherwise paramsGenerator would treat it as the component name
|
|
55
|
+
const _params = typeof params === 'string' ? { prefix: params, name: undefined } : params || { prefix: undefined, name: undefined };
|
|
56
|
+
return defineComponent(ComponentType.MESSAGE_CONTROLLER, _params, (target) => {
|
|
57
|
+
// Store prefix + transport binding metadata for PrepareMicroserviceService
|
|
58
|
+
defineTypedMetadata(ComponentConstants.MessagePrefixKey, _params.prefix || '', target);
|
|
59
|
+
defineTypedMetadata(ComponentConstants.MessageTransportKey, _params.transport || DEFAULT_TRANSPORT_NAME, target);
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=MessageController.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageController.js","sourceRoot":"","sources":["../../../../../lib/server/decorators/components/MessageController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAG5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,MAAyC,EAAkB,EAAE;IAC7F,gFAAgF;IAChF,iEAAiE;IACjE,MAAM,OAAO,GACX,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAEtH,OAAO,eAAe,CAAC,aAAa,CAAC,kBAAkB,EAAE,OAAO,EAAE,CAAC,MAAM,EAAE,EAAE;QAC3E,2EAA2E;QAC3E,mBAAmB,CAAS,kBAAkB,CAAC,gBAAgB,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE,EAAE,MAAM,CAAC,CAAC;QAE/F,mBAAmB,CACjB,kBAAkB,CAAC,mBAAmB,EACtC,OAAO,CAAC,SAAS,IAAI,sBAAsB,EAC3C,MAAM,CACP,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../lib/server/decorators/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,6CAA6C,CAAC;AAC5D,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../lib/server/decorators/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,6CAA6C,CAAC;AAC5D,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC"}
|
|
@@ -26,14 +26,10 @@ export declare class EventDispatchService implements ICoreService {
|
|
|
26
26
|
*/
|
|
27
27
|
private warmedUp;
|
|
28
28
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
29
|
+
* Hybrid lookup index (exact Map + wildcard array), shared implementation
|
|
30
|
+
* with the microservice transports
|
|
31
31
|
*/
|
|
32
|
-
private
|
|
33
|
-
/**
|
|
34
|
-
* Wildcard patterns that need O(n) matching
|
|
35
|
-
*/
|
|
36
|
-
private wildcardPatterns;
|
|
32
|
+
private index;
|
|
37
33
|
/**
|
|
38
34
|
* Register a handler for an event pattern
|
|
39
35
|
*
|
|
@@ -6,7 +6,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
6
6
|
};
|
|
7
7
|
import { CoreService } from '../../ioc';
|
|
8
8
|
import { ICoreServiceNames } from '../../ioc';
|
|
9
|
-
import {
|
|
9
|
+
import { PatternHandlerIndex } from './PatternHandlerIndex';
|
|
10
10
|
/**
|
|
11
11
|
* @description Internal event dispatch service
|
|
12
12
|
* Handles pattern matching, storage, and dispatching of events
|
|
@@ -33,14 +33,10 @@ let EventDispatchService = class EventDispatchService {
|
|
|
33
33
|
*/
|
|
34
34
|
warmedUp = false;
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
36
|
+
* Hybrid lookup index (exact Map + wildcard array), shared implementation
|
|
37
|
+
* with the microservice transports
|
|
38
38
|
*/
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Wildcard patterns that need O(n) matching
|
|
42
|
-
*/
|
|
43
|
-
wildcardPatterns = [];
|
|
39
|
+
index = new PatternHandlerIndex();
|
|
44
40
|
/**
|
|
45
41
|
* Register a handler for an event pattern
|
|
46
42
|
*
|
|
@@ -94,24 +90,8 @@ let EventDispatchService = class EventDispatchService {
|
|
|
94
90
|
if (!this.warmedUp) {
|
|
95
91
|
this.warmup();
|
|
96
92
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const exactHandlers = this.exactMatches.get(eventName);
|
|
100
|
-
if (exactHandlers) {
|
|
101
|
-
for (const handler of exactHandlers) {
|
|
102
|
-
// Find full subscription info (for 'once' support)
|
|
103
|
-
const sub = this.handlers.find((s) => s.handler === handler && s.pattern === eventName);
|
|
104
|
-
if (sub) {
|
|
105
|
-
handlersToCall.push(sub);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
// 2. Check wildcard patterns - O(n) but smaller n
|
|
110
|
-
for (const sub of this.wildcardPatterns) {
|
|
111
|
-
if (matchesEventPattern(eventName, sub.pattern)) {
|
|
112
|
-
handlersToCall.push(sub);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
93
|
+
// 1-2. Collect matching subscriptions: exact matches O(1), then wildcards O(n)
|
|
94
|
+
const handlersToCall = this.index.collect(eventName);
|
|
115
95
|
// 3. No handlers matched
|
|
116
96
|
if (handlersToCall.length === 0) {
|
|
117
97
|
return false;
|
|
@@ -159,19 +139,9 @@ let EventDispatchService = class EventDispatchService {
|
|
|
159
139
|
* @private
|
|
160
140
|
*/
|
|
161
141
|
warmup() {
|
|
162
|
-
this.
|
|
163
|
-
this.wildcardPatterns = [];
|
|
142
|
+
this.index.clear();
|
|
164
143
|
for (const sub of this.handlers) {
|
|
165
|
-
|
|
166
|
-
// Wildcard pattern - needs O(n) matching on dispatch
|
|
167
|
-
this.wildcardPatterns.push(sub);
|
|
168
|
-
}
|
|
169
|
-
else {
|
|
170
|
-
// Exact pattern - O(1) lookup on dispatch
|
|
171
|
-
const handlers = this.exactMatches.get(sub.pattern) || [];
|
|
172
|
-
handlers.push(sub.handler);
|
|
173
|
-
this.exactMatches.set(sub.pattern, handlers);
|
|
174
|
-
}
|
|
144
|
+
this.index.add(sub.pattern, sub);
|
|
175
145
|
}
|
|
176
146
|
this.warmedUp = true;
|
|
177
147
|
}
|
|
@@ -191,8 +161,7 @@ let EventDispatchService = class EventDispatchService {
|
|
|
191
161
|
*/
|
|
192
162
|
clearHandlers() {
|
|
193
163
|
this.handlers = [];
|
|
194
|
-
this.
|
|
195
|
-
this.wildcardPatterns = [];
|
|
164
|
+
this.index.clear();
|
|
196
165
|
this.warmedUp = false;
|
|
197
166
|
}
|
|
198
167
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EventDispatchService.js","sourceRoot":"","sources":["../../../../lib/server/event/EventDispatchService.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAE9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAG5D;;;;;;;;;;;;;;GAcG;AAEI,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IACf,WAAW,GAAG,sBAAsB,CAAC;IAErD;;OAEG;IACK,QAAQ,GAAwB,EAAE,CAAC;IAE3C;;OAEG;IACK,QAAQ,GAAG,KAAK,CAAC;IAEzB;;;OAGG;IACK,
|
|
1
|
+
{"version":3,"file":"EventDispatchService.js","sourceRoot":"","sources":["../../../../lib/server/event/EventDispatchService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description Shared pattern → handler index with the hybrid lookup strategy
|
|
3
|
+
* used across Asena's event and messaging systems:
|
|
4
|
+
*
|
|
5
|
+
* - Exact patterns → Map (O(1) lookup on collect)
|
|
6
|
+
* - Wildcard patterns → Array (O(n) matchesEventPattern check, smaller n)
|
|
7
|
+
*
|
|
8
|
+
* Consumers: EventDispatchService (in-process events), InMemoryTransport and
|
|
9
|
+
* RedisMicroserviceTransport (microservice event handlers). The generic type T
|
|
10
|
+
* lets each consumer store what it needs (a bare handler or a subscription object).
|
|
11
|
+
*
|
|
12
|
+
* Collection order: exact matches first (registration order), then wildcard
|
|
13
|
+
* matches (registration order).
|
|
14
|
+
*/
|
|
15
|
+
export declare class PatternHandlerIndex<T> {
|
|
16
|
+
/**
|
|
17
|
+
* Exact pattern → entries (O(1) fast path)
|
|
18
|
+
*/
|
|
19
|
+
private exact;
|
|
20
|
+
/**
|
|
21
|
+
* Wildcard patterns, matched with matchesEventPattern on collect
|
|
22
|
+
*/
|
|
23
|
+
private wildcard;
|
|
24
|
+
/**
|
|
25
|
+
* Register an entry under a pattern
|
|
26
|
+
*/
|
|
27
|
+
add(pattern: string, entry: T): void;
|
|
28
|
+
/**
|
|
29
|
+
* Remove a specific entry registered under a pattern (identity comparison)
|
|
30
|
+
*
|
|
31
|
+
* @returns true if the entry was found and removed
|
|
32
|
+
*/
|
|
33
|
+
remove(pattern: string, entry: T): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Collect all entries whose pattern matches the given event name
|
|
36
|
+
*/
|
|
37
|
+
collect(eventName: string): T[];
|
|
38
|
+
/**
|
|
39
|
+
* All registered patterns - exact first (registration order), then wildcard
|
|
40
|
+
*
|
|
41
|
+
* Diagnostics only: consumers use it to explain why an expected source
|
|
42
|
+
* matched no handler (e.g. the Kafka transport's external-topic hint).
|
|
43
|
+
*/
|
|
44
|
+
patterns(): string[];
|
|
45
|
+
/**
|
|
46
|
+
* Whether the index holds no entries at all
|
|
47
|
+
*/
|
|
48
|
+
get isEmpty(): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Remove all entries
|
|
51
|
+
*/
|
|
52
|
+
clear(): void;
|
|
53
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { matchesEventPattern } from './eventPatternMatcher';
|
|
2
|
+
/**
|
|
3
|
+
* @description Shared pattern → handler index with the hybrid lookup strategy
|
|
4
|
+
* used across Asena's event and messaging systems:
|
|
5
|
+
*
|
|
6
|
+
* - Exact patterns → Map (O(1) lookup on collect)
|
|
7
|
+
* - Wildcard patterns → Array (O(n) matchesEventPattern check, smaller n)
|
|
8
|
+
*
|
|
9
|
+
* Consumers: EventDispatchService (in-process events), InMemoryTransport and
|
|
10
|
+
* RedisMicroserviceTransport (microservice event handlers). The generic type T
|
|
11
|
+
* lets each consumer store what it needs (a bare handler or a subscription object).
|
|
12
|
+
*
|
|
13
|
+
* Collection order: exact matches first (registration order), then wildcard
|
|
14
|
+
* matches (registration order).
|
|
15
|
+
*/
|
|
16
|
+
export class PatternHandlerIndex {
|
|
17
|
+
/**
|
|
18
|
+
* Exact pattern → entries (O(1) fast path)
|
|
19
|
+
*/
|
|
20
|
+
exact = new Map();
|
|
21
|
+
/**
|
|
22
|
+
* Wildcard patterns, matched with matchesEventPattern on collect
|
|
23
|
+
*/
|
|
24
|
+
wildcard = [];
|
|
25
|
+
/**
|
|
26
|
+
* Register an entry under a pattern
|
|
27
|
+
*/
|
|
28
|
+
add(pattern, entry) {
|
|
29
|
+
if (pattern.includes('*')) {
|
|
30
|
+
this.wildcard.push({ pattern, entry });
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const entries = this.exact.get(pattern) || [];
|
|
34
|
+
entries.push(entry);
|
|
35
|
+
this.exact.set(pattern, entries);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Remove a specific entry registered under a pattern (identity comparison)
|
|
39
|
+
*
|
|
40
|
+
* @returns true if the entry was found and removed
|
|
41
|
+
*/
|
|
42
|
+
remove(pattern, entry) {
|
|
43
|
+
if (pattern.includes('*')) {
|
|
44
|
+
const index = this.wildcard.findIndex((item) => item.pattern === pattern && item.entry === entry);
|
|
45
|
+
if (index !== -1) {
|
|
46
|
+
this.wildcard.splice(index, 1);
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
const entries = this.exact.get(pattern);
|
|
52
|
+
if (!entries) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
const index = entries.indexOf(entry);
|
|
56
|
+
if (index === -1) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
entries.splice(index, 1);
|
|
60
|
+
if (!entries.length) {
|
|
61
|
+
this.exact.delete(pattern);
|
|
62
|
+
}
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Collect all entries whose pattern matches the given event name
|
|
67
|
+
*/
|
|
68
|
+
collect(eventName) {
|
|
69
|
+
const result = [...(this.exact.get(eventName) || [])];
|
|
70
|
+
for (const item of this.wildcard) {
|
|
71
|
+
if (matchesEventPattern(eventName, item.pattern)) {
|
|
72
|
+
result.push(item.entry);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* All registered patterns - exact first (registration order), then wildcard
|
|
79
|
+
*
|
|
80
|
+
* Diagnostics only: consumers use it to explain why an expected source
|
|
81
|
+
* matched no handler (e.g. the Kafka transport's external-topic hint).
|
|
82
|
+
*/
|
|
83
|
+
patterns() {
|
|
84
|
+
return [...this.exact.keys(), ...this.wildcard.map((item) => item.pattern)];
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Whether the index holds no entries at all
|
|
88
|
+
*/
|
|
89
|
+
get isEmpty() {
|
|
90
|
+
return this.exact.size === 0 && this.wildcard.length === 0;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Remove all entries
|
|
94
|
+
*/
|
|
95
|
+
clear() {
|
|
96
|
+
this.exact.clear();
|
|
97
|
+
this.wildcard = [];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=PatternHandlerIndex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PatternHandlerIndex.js","sourceRoot":"","sources":["../../../../lib/server/event/PatternHandlerIndex.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,mBAAmB;IAC9B;;OAEG;IACK,KAAK,GAAG,IAAI,GAAG,EAAe,CAAC;IAEvC;;OAEG;IACK,QAAQ,GAAoC,EAAE,CAAC;IAEvD;;OAEG;IACI,GAAG,CAAC,OAAe,EAAE,KAAQ;QAClC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;YACvC,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAE9C,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACnC,CAAC;IAED;;;;OAIG;IACI,MAAM,CAAC,OAAe,EAAE,KAAQ;QACrC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,KAAK,OAAO,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;YAElG,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;gBACjB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;gBAC/B,OAAO,IAAI,CAAC;YACd,CAAC;YAED,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAExC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAErC,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;YACjB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAEzB,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACpB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC7B,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACI,OAAO,CAAC,SAAiB;QAC9B,MAAM,MAAM,GAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAE3D,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACjC,IAAI,mBAAmB,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBACjD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;;;OAKG;IACI,QAAQ;QACb,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IAC9E,CAAC;IAED;;OAEG;IACH,IAAW,OAAO;QAChB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC;IAC7D,CAAC;IAED;;OAEG;IACI,KAAK;QACV,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;IACrB,CAAC;CACF"}
|
|
@@ -20,6 +20,10 @@ import type { OnParams } from '../types';
|
|
|
20
20
|
*
|
|
21
21
|
* @On({ event: 'deleted', skip: true }) // Temporarily disabled
|
|
22
22
|
* handleDeleted(eventName: string, data: any) { }
|
|
23
|
+
*
|
|
24
|
+
* // Absolute - opts out of the 'user' prefix
|
|
25
|
+
* @On({ event: 'payment.completed', prefix: false })
|
|
26
|
+
* handlePayment(eventName: string, data: any) { }
|
|
23
27
|
* }
|
|
24
28
|
*
|
|
25
29
|
* @example
|
|
@@ -21,6 +21,10 @@ import { defineTypedMetadata, getOwnTypedMetadata } from '../../../utils';
|
|
|
21
21
|
*
|
|
22
22
|
* @On({ event: 'deleted', skip: true }) // Temporarily disabled
|
|
23
23
|
* handleDeleted(eventName: string, data: any) { }
|
|
24
|
+
*
|
|
25
|
+
* // Absolute - opts out of the 'user' prefix
|
|
26
|
+
* @On({ event: 'payment.completed', prefix: false })
|
|
27
|
+
* handlePayment(eventName: string, data: any) { }
|
|
24
28
|
* }
|
|
25
29
|
*
|
|
26
30
|
* @example
|
|
@@ -46,6 +50,8 @@ export function On(params) {
|
|
|
46
50
|
handlers[propertyKey.toString()] = {
|
|
47
51
|
pattern: _params.event,
|
|
48
52
|
methodName: propertyKey.toString(),
|
|
53
|
+
// `!== false` covers the string shorthand and objects that omit the flag
|
|
54
|
+
prefix: _params.prefix !== false,
|
|
49
55
|
skip: _params.skip || false,
|
|
50
56
|
};
|
|
51
57
|
// Store updated metadata
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"On.js","sourceRoot":"","sources":["../../../../../lib/server/event/decorators/On.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAG1E
|
|
1
|
+
{"version":3,"file":"On.js","sourceRoot":"","sources":["../../../../../lib/server/event/decorators/On.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAG1E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,UAAU,EAAE,CAAC,MAAyB;IAC1C,oDAAoD;IACpD,MAAM,OAAO,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IAErF,OAAO,UAAU,MAAc,EAAE,WAA4B,EAAE,UAA8B;QAC3F,qDAAqD;QACrD,MAAM,QAAQ,GACZ,mBAAmB,CACjB,kBAAkB,CAAC,gBAAgB,EACnC,MAAM,CAAC,WAAW,CACnB,IAAI,EAAE,CAAC;QAEV,8BAA8B;QAC9B,QAAQ,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC,GAAG;YACjC,OAAO,EAAE,OAAO,CAAC,KAAK;YACtB,UAAU,EAAE,WAAW,CAAC,QAAQ,EAAE;YAClC,yEAAyE;YACzE,MAAM,EAAE,OAAO,CAAC,MAAM,KAAK,KAAK;YAChC,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,KAAK;SAC5B,CAAC;QAEF,yBAAyB;QACzB,mBAAmB,CAAC,kBAAkB,CAAC,gBAAgB,EAAE,QAAQ,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC;QAEvF,OAAO,UAAU,CAAC;IACpB,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { EventEmitter } from './EventEmitter';
|
|
2
2
|
export { EventDispatchService } from './EventDispatchService';
|
|
3
3
|
export { matchesEventPattern } from './eventPatternMatcher';
|
|
4
|
+
export { PatternHandlerIndex } from './PatternHandlerIndex';
|
|
4
5
|
export { emitter } from './emitter';
|
|
5
6
|
export * from './types';
|
|
6
7
|
export * from './decorators';
|
|
@@ -3,6 +3,8 @@ export { EventEmitter } from './EventEmitter';
|
|
|
3
3
|
export { EventDispatchService } from './EventDispatchService';
|
|
4
4
|
// Pattern matcher (utility)
|
|
5
5
|
export { matchesEventPattern } from './eventPatternMatcher';
|
|
6
|
+
// Shared pattern → handler index (hybrid exact/wildcard lookup)
|
|
7
|
+
export { PatternHandlerIndex } from './PatternHandlerIndex';
|
|
6
8
|
// Injection utility
|
|
7
9
|
export { emitter } from './emitter';
|
|
8
10
|
// Types
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../lib/server/event/index.ts"],"names":[],"mappings":"AAAA,oBAAoB;AACpB,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,4BAA4B;AAC5B,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,oBAAoB;AACpB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,QAAQ;AACR,cAAc,SAAS,CAAC;AAExB,aAAa;AACb,cAAc,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../lib/server/event/index.ts"],"names":[],"mappings":"AAAA,oBAAoB;AACpB,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,4BAA4B;AAC5B,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,gEAAgE;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,oBAAoB;AACpB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,QAAQ;AACR,cAAc,SAAS,CAAC;AAExB,aAAa;AACb,cAAc,cAAc,CAAC"}
|