@riaskov/nevo-messaging 1.0.1 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +202 -67
  3. package/dist/common/access-control.d.ts +15 -0
  4. package/dist/common/access-control.js +94 -0
  5. package/dist/common/base.client.d.ts +7 -2
  6. package/dist/common/base.client.js +16 -2
  7. package/dist/common/base.controller.d.ts +6 -1
  8. package/dist/common/base.controller.js +68 -4
  9. package/dist/common/constants.d.ts +4 -0
  10. package/dist/common/constants.js +7 -0
  11. package/dist/common/discovery.d.ts +8 -0
  12. package/dist/common/discovery.js +35 -0
  13. package/dist/common/error-code.d.ts +2 -1
  14. package/dist/common/error-code.js +1 -0
  15. package/dist/common/error-messages.js +2 -1
  16. package/dist/common/index.d.ts +3 -0
  17. package/dist/common/index.js +3 -0
  18. package/dist/common/service-utils.d.ts +2 -0
  19. package/dist/common/service-utils.js +8 -0
  20. package/dist/common/types.d.ts +62 -0
  21. package/dist/signal-router.utils.d.ts +3 -1
  22. package/dist/signal-router.utils.js +70 -6
  23. package/dist/transports/http/http.client-base.d.ts +13 -0
  24. package/dist/transports/http/http.client-base.js +33 -0
  25. package/dist/transports/http/http.config.d.ts +8 -0
  26. package/dist/transports/http/http.config.js +16 -0
  27. package/dist/transports/http/http.signal-router.decorator.d.ts +3 -0
  28. package/dist/transports/http/http.signal-router.decorator.js +18 -0
  29. package/dist/transports/http/http.transport.controller.d.ts +21 -0
  30. package/dist/transports/http/http.transport.controller.js +114 -0
  31. package/dist/transports/http/index.d.ts +5 -0
  32. package/dist/transports/http/index.js +21 -0
  33. package/dist/transports/http/nevo-http.client.d.ts +54 -0
  34. package/dist/transports/http/nevo-http.client.js +280 -0
  35. package/dist/transports/index.d.ts +3 -0
  36. package/dist/transports/index.js +3 -0
  37. package/dist/transports/kafka/kafka.client-base.d.ts +5 -0
  38. package/dist/transports/kafka/kafka.client-base.js +15 -0
  39. package/dist/transports/kafka/kafka.config.d.ts +7 -0
  40. package/dist/transports/kafka/kafka.config.js +48 -2
  41. package/dist/transports/kafka/kafka.signal-router.decorator.js +2 -1
  42. package/dist/transports/kafka/nevo-kafka.client.d.ts +42 -0
  43. package/dist/transports/kafka/nevo-kafka.client.js +210 -4
  44. package/dist/transports/nats/index.d.ts +4 -0
  45. package/dist/transports/nats/index.js +20 -0
  46. package/dist/transports/nats/nats.client-base.d.ts +13 -0
  47. package/dist/transports/nats/nats.client-base.js +33 -0
  48. package/dist/transports/nats/nats.config.d.ts +8 -0
  49. package/dist/transports/nats/nats.config.js +16 -0
  50. package/dist/transports/nats/nats.signal-router.decorator.d.ts +6 -0
  51. package/dist/transports/nats/nats.signal-router.decorator.js +49 -0
  52. package/dist/transports/nats/nevo-nats.client.d.ts +55 -0
  53. package/dist/transports/nats/nevo-nats.client.js +210 -0
  54. package/dist/transports/socket-io/index.d.ts +4 -0
  55. package/dist/transports/socket-io/index.js +20 -0
  56. package/dist/transports/socket-io/nevo-socket.client.d.ts +50 -0
  57. package/dist/transports/socket-io/nevo-socket.client.js +202 -0
  58. package/dist/transports/socket-io/socket.client-base.d.ts +13 -0
  59. package/dist/transports/socket-io/socket.client-base.js +33 -0
  60. package/dist/transports/socket-io/socket.config.d.ts +8 -0
  61. package/dist/transports/socket-io/socket.config.js +16 -0
  62. package/dist/transports/socket-io/socket.signal-router.decorator.d.ts +13 -0
  63. package/dist/transports/socket-io/socket.signal-router.decorator.js +109 -0
  64. package/package.json +11 -5
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Andrei Riaskóv
3
+ Copyright (c) 2026 Andrei Riaskóv <code@riaskov.com>
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,13 +1,18 @@
1
1
  # Nevo Messaging
2
2
 
3
- A powerful microservices messaging framework for NestJS 11+ with Kafka 4+ transport, designed for building scalable distributed systems with type-safe inter-service communication.
3
+ A powerful microservices messaging framework for NestJS 11+ with multi-transport support (NATS, Kafka, Socket.IO, HTTP/SSE), designed for building scalable distributed systems with type-safe inter-service communication.
4
4
 
5
5
  ## Features
6
6
 
7
7
  - 🚀 **Type-safe messaging** - Full TypeScript support with auto-completion
8
8
  - 🔄 **Dual communication patterns** - Both request-response (query) and fire-and-forget (emit)
9
+ - 📡 **Subscriptions** - Publish/subscribe updates without direct requests
10
+ - 📢 **Broadcast** - System-wide messages for all connected consumers
9
11
  - 🎯 **Signal-based routing** - Declarative method mapping with `@Signal` decorator
10
12
  - 📡 **Kafka transport** - Production-ready Apache Kafka integration
13
+ - 🧭 **Service discovery** - Heartbeat-based registry topic
14
+ - 🔐 **Access control** - Topic + method + service-level ACLs
15
+ - 🔌 **Multiple transports** - NATS, Kafka, Socket.IO, HTTP (SSE)
11
16
  - 🔧 **Auto-configuration** - Automatic topic creation and client setup
12
17
  - 🛡️ **Error handling** - Comprehensive error propagation and timeout management
13
18
  - 📊 **BigInt support** - Native handling of large integers across services
@@ -23,23 +28,23 @@ npm install @riaskov/nevo-messaging
23
28
  ### Peer Dependencies
24
29
 
25
30
  ```bash
26
- npm install @nestjs/common @nestjs/core @nestjs/microservices @nestjs/config @nestjs/platform-fastify kafkajs rxjs reflect-metadata
31
+ npm install @nestjs/common @nestjs/core @nestjs/microservices @nestjs/config @nestjs/platform-fastify kafkajs nats socket.io socket.io-client rxjs reflect-metadata
27
32
  ```
28
33
 
29
34
  ## Quick Start
30
35
 
31
- ### 1. Basic Service Setup
36
+ ### 1. Basic Service Setup (NATS)
32
37
 
33
38
  Create a simple microservice that responds to messages:
34
39
 
35
40
  ```typescript
36
41
  // user.service.ts
37
42
  import { Injectable, Inject } from "@nestjs/common"
38
- import { KafkaClientBase, NevoKafkaClient } from "@riaskov/nevo-messaging"
43
+ import { NatsClientBase, NevoNatsClient } from "@riaskov/nevo-messaging"
39
44
 
40
45
  @Injectable()
41
- export class UserService extends KafkaClientBase {
42
- constructor(@Inject("NEVO_KAFKA_CLIENT") nevoClient: NevoKafkaClient) {
46
+ export class UserService extends NatsClientBase {
47
+ constructor(@Inject("NEVO_NATS_CLIENT") nevoClient: NevoNatsClient) {
43
48
  super(nevoClient)
44
49
  }
45
50
 
@@ -61,11 +66,11 @@ Map service methods to external signals using the `@Signal` decorator:
61
66
  ```typescript
62
67
  // user.controller.ts
63
68
  import { Controller, Inject } from "@nestjs/common"
64
- import { KafkaSignalRouter, Signal } from "@riaskov/nevo-messaging"
69
+ import { NatsSignalRouter, Signal } from "@riaskov/nevo-messaging"
65
70
  import { UserService } from "./user.service"
66
71
 
67
72
  @Controller()
68
- @KafkaSignalRouter([UserService])
73
+ @NatsSignalRouter([UserService])
69
74
  export class UserController {
70
75
  constructor(@Inject(UserService) private readonly userService: UserService) {}
71
76
 
@@ -79,13 +84,13 @@ export class UserController {
79
84
 
80
85
  ### 3. Module Configuration
81
86
 
82
- Configure the module with Kafka client:
87
+ Configure the module with the NATS client:
83
88
 
84
89
  ```typescript
85
90
  // user.module.ts
86
91
  import { Module } from "@nestjs/common"
87
92
  import { ConfigModule } from "@nestjs/config"
88
- import { createNevoKafkaClient } from "@riaskov/nevo-messaging"
93
+ import { createNevoNatsClient } from "@riaskov/nevo-messaging"
89
94
  import { UserController } from "./user.controller"
90
95
  import { UserService } from "./user.service"
91
96
 
@@ -94,8 +99,9 @@ import { UserService } from "./user.service"
94
99
  controllers: [UserController],
95
100
  providers: [
96
101
  UserService,
97
- createNevoKafkaClient(["COORDINATOR"], {
98
- clientIdPrefix: "user"
102
+ createNevoNatsClient(["COORDINATOR"], {
103
+ clientIdPrefix: "user",
104
+ servers: ["nats://127.0.0.1:4222"]
99
105
  })
100
106
  ]
101
107
  })
@@ -104,20 +110,20 @@ export class UserModule {}
104
110
 
105
111
  ### 4. Application Bootstrap
106
112
 
107
- Start your microservice:
113
+ Start your service:
108
114
 
109
115
  ```typescript
110
116
  // main.ts
111
- import { createKafkaMicroservice } from "@riaskov/nevo-messaging"
117
+ import { NestFactory } from "@nestjs/core"
112
118
  import { AppModule } from "./app.module"
113
119
 
114
- createKafkaMicroservice({
115
- microserviceName: "user",
116
- module: AppModule,
117
- port: 8086
118
- }).then()
119
- ```
120
+ async function bootstrap() {
121
+ const app = await NestFactory.create(AppModule)
122
+ await app.listen(8086)
123
+ }
120
124
 
125
+ bootstrap()
126
+ ```
121
127
  ## Core Concepts
122
128
 
123
129
  ### Signal Routing
@@ -144,6 +150,38 @@ Use for events and notifications:
144
150
  await this.emit("notifications", "user.created", { userId: 123n, email: "user@example.com" })
145
151
  ```
146
152
 
153
+ #### Subscription Pattern (Publish/Subscribe)
154
+ Use when you want to receive updates without requesting:
155
+
156
+ ```typescript
157
+ const sub = await this.subscribe("user", "user.updated", { ack: true }, async (msg, ctx) => {
158
+ await ctx.ack()
159
+ })
160
+
161
+ await sub.unsubscribe()
162
+ ```
163
+
164
+ Publish updates:
165
+
166
+ ```typescript
167
+ await this.publish("user", "user.updated", { userId: 123n })
168
+ ```
169
+
170
+ #### Broadcast Pattern (System-Wide)
171
+ Send to everyone connected to the broker:
172
+
173
+ ```typescript
174
+ await this.broadcast("system.status", { ok: true })
175
+ ```
176
+
177
+ Receive broadcast:
178
+
179
+ ```typescript
180
+ await this.subscribe("__broadcast", "system.status", {}, (msg) => {
181
+ console.log("System status:", msg)
182
+ })
183
+ ```
184
+
147
185
  ## Advanced Usage
148
186
 
149
187
  ### Parameter Transformation
@@ -282,6 +320,65 @@ export class UserService extends KafkaClientBase {
282
320
  }
283
321
  ```
284
322
 
323
+ ### Method Suggestions (Did You Mean)
324
+
325
+ If you call a method that doesn't exist, the framework returns a helpful error:
326
+
327
+ ```
328
+ Invalid method name 'user.getByI', did you mean 'user.getById'?
329
+ ```
330
+
331
+ This works for all transports.
332
+
333
+ ### Exponential Backoff (Client-Side)
334
+
335
+ Clients apply a backoff for **in-flight requests** to avoid sending a duplicate query while the previous one is still being processed.
336
+
337
+ ```typescript
338
+ createNevoKafkaClient(["USER"], {
339
+ clientIdPrefix: "frontend",
340
+ backoff: {
341
+ enabled: true,
342
+ baseMs: 100,
343
+ maxMs: 2000,
344
+ maxAttempts: 0, // 0 = wait until slot is free
345
+ jitter: true
346
+ }
347
+ })
348
+ ```
349
+
350
+ This prevents repeated sending of the same request while the service is busy (e.g., stopped on a breakpoint).
351
+
352
+ ### Access Control (ACL)
353
+
354
+ Restrict who can read messages by topic + method + service:
355
+
356
+ ```typescript
357
+ @KafkaSignalRouter([UserService], {
358
+ accessControl: {
359
+ rules: [
360
+ { topic: "user-events", method: "*", allow: ["frontend", "coordinator"] },
361
+ { topic: "user-events", method: "user.delete", deny: ["frontend"] }
362
+ ],
363
+ logDenied: true
364
+ }
365
+ })
366
+ export class UserController {}
367
+ ```
368
+
369
+ By default, all services are allowed.
370
+
371
+ ### Service Discovery (Registry Topic)
372
+
373
+ Each client sends heartbeats to `__nevo.discovery`. You can read the registry:
374
+
375
+ ```typescript
376
+ const services = this.getDiscoveredServices()
377
+ const isUserAvailable = this.isServiceAvailable("user")
378
+ ```
379
+
380
+ Discovery is enabled by default for Kafka/NATS. HTTP and Socket.IO discovery are available when enabled (HTTP requires `discoveryUrl`).
381
+
285
382
  ## Configuration
286
383
 
287
384
  ### Environment Variables
@@ -304,7 +401,12 @@ createNevoKafkaClient(["USER", "INVENTORY", "NOTIFICATIONS"], {
304
401
  retryAttempts: 5,
305
402
  brokerRetryTimeout: 2000,
306
403
  timeoutMs: 25000,
307
- debug: false
404
+ debug: false,
405
+ discovery: {
406
+ enabled: true,
407
+ heartbeatIntervalMs: 5000,
408
+ ttlMs: 15000
409
+ }
308
410
  })
309
411
  ```
310
412
 
@@ -324,6 +426,74 @@ createKafkaMicroservice({
324
426
  })
325
427
  ```
326
428
 
429
+ ## Transports
430
+
431
+ | Transport | Patterns | Discovery | Infra | Notes |
432
+ | --- | --- | --- | --- | --- |
433
+ | NATS | query/emit/publish/subscribe/broadcast | on by default | NATS server | Lowest latency, simple ops |
434
+ | Kafka | query/emit/publish/subscribe/broadcast | on by default | Kafka broker | Durable log, topic setup |
435
+ | Socket.IO | query/emit/publish/subscribe/broadcast | optional | Socket.IO server | WebSocket-friendly apps |
436
+ | HTTP (SSE) | query/emit + SSE subscribe/broadcast | optional | HTTP server | Simple HTTP/SSE integration |
437
+
438
+ ### NATS (priority)
439
+ Client factory:
440
+
441
+ ```typescript
442
+ createNevoNatsClient(["USER", "COORDINATOR"], {
443
+ clientIdPrefix: "user",
444
+ servers: ["nats://127.0.0.1:4222"]
445
+ })
446
+ ```
447
+
448
+ Controller decorator:
449
+
450
+ ```typescript
451
+ @NatsSignalRouter([UserService])
452
+ export class UserController {}
453
+ ```
454
+
455
+ ### Kafka
456
+ Use `createKafkaMicroservice` + `KafkaSignalRouter` as before.
457
+
458
+ ### Socket.IO
459
+ Socket.IO server is started inside the router decorator:
460
+
461
+ ```typescript
462
+ @SocketSignalRouter([UserService], { serviceName: "user", port: 8093 })
463
+ export class UserController {}
464
+ ```
465
+
466
+ Client:
467
+
468
+ ```typescript
469
+ createNevoSocketClient(
470
+ { coordinator: "http://127.0.0.1:8094" },
471
+ { clientIdPrefix: "user" }
472
+ )
473
+ ```
474
+
475
+ ### HTTP (SSE)
476
+ HTTP uses plain POST for `query/emit` and SSE for `subscribe`.
477
+
478
+ ```typescript
479
+ @HttpSignalRouter([UserService])
480
+ export class UserController {}
481
+ ```
482
+
483
+ Include transport controller to enable SSE + publish endpoints:
484
+
485
+ ```typescript
486
+ controllers: [UserController, HttpTransportController]
487
+ ```
488
+
489
+ Client:
490
+
491
+ ```typescript
492
+ createNevoHttpClient(
493
+ { coordinator: "http://127.0.0.1:8091" },
494
+ { clientIdPrefix: "user" }
495
+ )
496
+ ```
327
497
  ## BigInt Support
328
498
 
329
499
  The framework automatically handles BigInt serialization across service boundaries:
@@ -697,56 +867,21 @@ createNevoKafkaClient(["HIGH_VOLUME_SERVICE"], {
697
867
 
698
868
  ## API Reference
699
869
 
700
- ### Decorators
701
-
702
- #### `@Signal(signalName, methodName?, paramTransformer?, resultTransformer?)`
703
-
704
- Maps external signals to service methods.
705
-
706
- **Parameters:**
707
- - `signalName` (string): External signal identifier
708
- - `methodName` (string, optional): Service method name (defaults to signalName)
709
- - `paramTransformer` (function, optional): Transform incoming parameters
710
- - `resultTransformer` (function, optional): Transform outgoing results
711
-
712
- #### `@KafkaSignalRouter(serviceTypes, options?)`
713
-
714
- Class decorator for signal routing setup.
715
-
716
- **Parameters:**
717
- - `serviceTypes` (Type<any> | Type<any>[]): Service classes to route to
718
- - `options` (object, optional): Configuration options
719
-
720
- ### Classes
721
-
722
- #### `KafkaClientBase`
723
-
724
- Base class for services that need to communicate with other microservices.
725
-
726
- **Methods:**
727
- - `query<T>(serviceName, method, params): Promise<T>` - Request-response communication
728
- - `emit(serviceName, method, params): Promise<void>` - Fire-and-forget communication
729
- - `getAvailableServices(): string[]` - List registered services
730
-
731
- #### `NevoKafkaClient`
732
-
733
- Universal Kafka client for multi-service communication.
734
-
735
- **Methods:**
736
- - `query<T>(serviceName, method, params): Promise<T>` - Send query to service
737
- - `emit(serviceName, method, params): Promise<void>` - Emit event to service
738
- - `getAvailableServices(): string[]` - Get list of available services
739
-
740
- ### Functions
870
+ See `API.md`.
741
871
 
742
- #### `createNevoKafkaClient(serviceNames, options)`
872
+ ## Examples
743
873
 
744
- Factory function for creating Kafka client providers.
874
+ ### NATS
875
+ - `examples/nats-user` - NATS request/response + publish/subscribe + broadcast
745
876
 
746
- #### `createKafkaMicroservice(options)`
877
+ ### Kafka
878
+ - `examples/user` - standard Kafka microservice
747
879
 
748
- Bootstrap function for starting NestJS microservices with Kafka transport.
880
+ ### Socket.IO
881
+ - `examples/socket-user` - Socket.IO transport with subscribe/broadcast
749
882
 
883
+ ### HTTP (SSE)
884
+ - `examples/http-user` - HTTP query/emit + SSE subscribe + broadcast + discovery
750
885
  ## Troubleshooting
751
886
 
752
887
  ### Common Issues
@@ -828,4 +963,4 @@ MIT License - see [LICENSE](LICENSE) file for details.
828
963
  - Examples: Check the `examples/` directory for complete working examples
829
964
 
830
965
  ## Aux
831
- There are many anys in core code - the simple temporary solution for changeable Nest.js microservices API.
966
+ There are many anys in core code - the simple temporary solution for changeable Nest.js microservices API.
@@ -0,0 +1,15 @@
1
+ import { AccessControlConfig, MessageMeta } from "./types";
2
+ import { ErrorCode } from "./error-code";
3
+ export declare function extractCallerService(meta?: MessageMeta): string | undefined;
4
+ export declare function isAccessAllowed(config: AccessControlConfig | undefined, topic: string, method: string, callerService: string | undefined): boolean;
5
+ export declare function logAccessDenied(config: AccessControlConfig | undefined, details: Record<string, unknown>): void;
6
+ export declare function createAccessDeniedError(method: string, serviceName: string, callerService?: string): {
7
+ code: ErrorCode;
8
+ message: string;
9
+ details: {
10
+ method: string;
11
+ serviceName: string;
12
+ callerService: string | undefined;
13
+ };
14
+ service: string;
15
+ };
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractCallerService = extractCallerService;
4
+ exports.isAccessAllowed = isAccessAllowed;
5
+ exports.logAccessDenied = logAccessDenied;
6
+ exports.createAccessDeniedError = createAccessDeniedError;
7
+ const error_code_1 = require("./error-code");
8
+ function decodeJwtPayload(token) {
9
+ const parts = token.split(".");
10
+ if (parts.length < 2) {
11
+ return null;
12
+ }
13
+ try {
14
+ const payload = parts[1].replace(/-/g, "+").replace(/_/g, "/");
15
+ const padded = payload.padEnd(payload.length + ((4 - (payload.length % 4)) % 4), "=");
16
+ const json = Buffer.from(padded, "base64").toString("utf8");
17
+ return JSON.parse(json);
18
+ }
19
+ catch {
20
+ return null;
21
+ }
22
+ }
23
+ function extractCallerService(meta) {
24
+ if (meta?.service) {
25
+ return meta.service;
26
+ }
27
+ const token = meta?.auth?.token;
28
+ if (!token) {
29
+ return undefined;
30
+ }
31
+ const payload = decodeJwtPayload(token);
32
+ if (!payload) {
33
+ return undefined;
34
+ }
35
+ const serviceName = (payload["serviceName"] || payload["service"] || payload["svc"] || payload["sub"]);
36
+ return serviceName;
37
+ }
38
+ function matchPattern(pattern, value) {
39
+ if (!pattern || pattern === "*") {
40
+ return true;
41
+ }
42
+ return pattern === value;
43
+ }
44
+ function listHasValue(list, value) {
45
+ if (!list || list.length === 0) {
46
+ return false;
47
+ }
48
+ if (list.includes("*")) {
49
+ return true;
50
+ }
51
+ if (!value) {
52
+ return false;
53
+ }
54
+ return list.includes(value);
55
+ }
56
+ function isAccessAllowed(config, topic, method, callerService) {
57
+ if (!config) {
58
+ return true;
59
+ }
60
+ const allowAllByDefault = config.allowAllByDefault !== false;
61
+ const rules = config.rules || [];
62
+ let matched = false;
63
+ for (const rule of rules) {
64
+ if (!matchPattern(rule.topic, topic) || !matchPattern(rule.method, method)) {
65
+ continue;
66
+ }
67
+ matched = true;
68
+ if (listHasValue(rule.deny, callerService)) {
69
+ return false;
70
+ }
71
+ if (rule.allow && rule.allow.length > 0) {
72
+ return listHasValue(rule.allow, callerService);
73
+ }
74
+ }
75
+ return matched ? allowAllByDefault : allowAllByDefault;
76
+ }
77
+ function logAccessDenied(config, details) {
78
+ if (config?.logDenied === false) {
79
+ return;
80
+ }
81
+ console.warn("[NevoMessaging][ACL] Access denied:", details);
82
+ }
83
+ function createAccessDeniedError(method, serviceName, callerService) {
84
+ return {
85
+ code: error_code_1.ErrorCode.UNAUTHORIZED,
86
+ message: "Access denied",
87
+ details: {
88
+ method,
89
+ serviceName,
90
+ callerService
91
+ },
92
+ service: serviceName
93
+ };
94
+ }
@@ -1,12 +1,17 @@
1
- import { MessagePayload, MicroserviceConfig, TransportClientOptions } from "./types";
1
+ import { MessagePayload, MicroserviceConfig, TransportClientOptions, MessageType, Subscription, SubscriptionOptions, SubscriptionContext } from "./types";
2
2
  export declare abstract class BaseMessagingClient {
3
3
  protected readonly options: TransportClientOptions;
4
4
  protected readonly microservices: Map<string, string>;
5
+ protected readonly serviceName?: string;
6
+ protected readonly authToken?: string;
5
7
  protected constructor(options?: TransportClientOptions);
6
8
  protected registerMicroservices(configs: MicroserviceConfig[]): void;
7
9
  protected query<T = any>(serviceName: string, method: string, params: any): Promise<T>;
8
10
  protected emit(serviceName: string, method: string, params: any): Promise<void>;
9
- protected createMessagePayload(method: string, params: any): MessagePayload;
11
+ protected createMessagePayload(method: string, params: any, type?: MessageType): MessagePayload;
10
12
  protected abstract _queryMicroservice<T>(clientName: string, method: string, params: any): Promise<T>;
11
13
  protected abstract _emitToMicroservice(clientName: string, method: string, params: any): Promise<void>;
14
+ protected abstract _publishToMicroservice(clientName: string, method: string, params: any): Promise<void>;
15
+ protected abstract _broadcast(method: string, params: any): Promise<void>;
16
+ protected abstract _subscribeToMicroservice<T>(clientName: string, method: string, options: SubscriptionOptions | undefined, handler: (data: T, context: SubscriptionContext) => Promise<void> | void): Promise<Subscription>;
12
17
  }
@@ -12,6 +12,8 @@ class BaseMessagingClient {
12
12
  debug: false,
13
13
  ...options
14
14
  };
15
+ this.serviceName = this.options.serviceName || this.options.clientId;
16
+ this.authToken = this.options.authToken;
15
17
  }
16
18
  registerMicroservices(configs) {
17
19
  for (const config of configs) {
@@ -38,9 +40,21 @@ class BaseMessagingClient {
38
40
  }
39
41
  return this._emitToMicroservice(clientName, method, params);
40
42
  }
41
- createMessagePayload(method, params) {
43
+ createMessagePayload(method, params, type = "emit") {
42
44
  const uuid = (0, node_crypto_1.randomUUID)();
43
- const request = { uuid, method, params };
45
+ const request = {
46
+ uuid,
47
+ method,
48
+ params,
49
+ meta: {
50
+ type,
51
+ service: this.serviceName,
52
+ ts: Date.now(),
53
+ auth: {
54
+ token: this.authToken
55
+ }
56
+ }
57
+ };
44
58
  return {
45
59
  key: uuid,
46
60
  value: JSON.stringify(request)
@@ -1,4 +1,4 @@
1
- import { AfterHook, BeforeHook, ServiceMethodHandler, ServiceMethodMapping, SystemAfterHook, SystemBeforeHook, MessageResponse } from "./types";
1
+ import { AfterHook, BeforeHook, ServiceMethodHandler, ServiceMethodMapping, SystemAfterHook, SystemBeforeHook, MessageResponse, AccessControlConfig, MessageMeta } from "./types";
2
2
  export declare abstract class BaseMessageController {
3
3
  protected readonly methodRegistry: ServiceMethodMapping;
4
4
  serviceInstances: any[];
@@ -8,14 +8,18 @@ export declare abstract class BaseMessageController {
8
8
  protected readonly systemBeforeHook: SystemBeforeHook;
9
9
  protected readonly systemAfterHook: SystemAfterHook;
10
10
  protected readonly debug: boolean;
11
+ protected readonly accessControl?: AccessControlConfig;
11
12
  protected constructor(serviceName: string, serviceInstances: any[], methodHandlers: ServiceMethodMapping, options?: {
12
13
  onBefore?: BeforeHook;
13
14
  onAfter?: AfterHook;
14
15
  debug?: boolean;
16
+ accessControl?: AccessControlConfig;
15
17
  });
16
18
  protected registerMethodHandlers(handlers: ServiceMethodMapping): void;
17
19
  protected findServiceInstance(methodName: string): any;
18
20
  protected executeHandler(handler: ServiceMethodHandler, params: unknown): Promise<unknown>;
21
+ private suggestClosestMethod;
22
+ private levenshteinDistance;
19
23
  protected formatResult(result: unknown): Promise<unknown>;
20
24
  protected createErrorResponse(uuid: string, method: string, error: any): MessageResponse;
21
25
  processMessage(data: any): Promise<MessageResponse>;
@@ -23,6 +27,7 @@ export declare abstract class BaseMessageController {
23
27
  method: string;
24
28
  uuid: string;
25
29
  params: any;
30
+ meta?: MessageMeta;
26
31
  };
27
32
  abstract handleMessage(data: any): Promise<MessageResponse>;
28
33
  }