@riaskov/nevo-messaging 1.1.1 → 1.1.3
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 +268 -293
- package/dist/transports/http/index.d.ts +1 -0
- package/dist/transports/http/index.js +1 -0
- package/dist/transports/http/microservice.config.d.ts +3 -0
- package/dist/transports/http/microservice.config.js +16 -0
- package/dist/transports/index.d.ts +1 -0
- package/dist/transports/index.js +1 -0
- package/dist/transports/kafka/microservice.config.d.ts +2 -9
- package/dist/transports/microservice.options.d.ts +9 -0
- package/dist/transports/microservice.options.js +2 -0
- package/dist/transports/nats/index.d.ts +1 -0
- package/dist/transports/nats/index.js +1 -0
- package/dist/transports/nats/microservice.config.d.ts +3 -0
- package/dist/transports/nats/microservice.config.js +16 -0
- package/dist/transports/socket-io/index.d.ts +1 -0
- package/dist/transports/socket-io/index.js +1 -0
- package/dist/transports/socket-io/microservice.config.d.ts +3 -0
- package/dist/transports/socket-io/microservice.config.js +16 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
# Nevo Messaging
|
|
2
2
|
|
|
3
|
-
A powerful microservices messaging framework for NestJS 11+ with Kafka
|
|
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
|
-
- 🚀 **Type-safe messaging** - Full TypeScript support with auto-completion
|
|
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
|
|
11
|
-
- 🎯 **Signal-based routing** - Declarative method mapping with `@Signal` decorator
|
|
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** - Kafka,
|
|
16
|
-
- 🔧 **Auto-configuration** - Automatic topic creation and client setup
|
|
17
|
-
- 🛡️ **Error handling** - Comprehensive error propagation and timeout management
|
|
18
|
-
- 📊 **BigInt support** - Native handling of large integers across services
|
|
19
|
-
- 🪝 **Lifecycle hooks** - Before/after message processing hooks
|
|
20
|
-
- 🔍 **Debug mode** - Built-in logging for development and troubleshooting
|
|
7
|
+
- 🚀 **Type-safe messaging** - Full TypeScript support with auto-completion
|
|
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
|
|
11
|
+
- 🎯 **Signal-based routing** - Declarative method mapping with `@Signal` decorator
|
|
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)
|
|
16
|
+
- 🔧 **Auto-configuration** - Automatic topic creation and client setup
|
|
17
|
+
- 🛡️ **Error handling** - Comprehensive error propagation and timeout management
|
|
18
|
+
- 📊 **BigInt support** - Native handling of large integers across services
|
|
19
|
+
- 🪝 **Lifecycle hooks** - Before/after message processing hooks
|
|
20
|
+
- 🔍 **Debug mode** - Built-in logging for development and troubleshooting
|
|
21
21
|
|
|
22
22
|
## Installation
|
|
23
23
|
|
|
@@ -28,23 +28,23 @@ npm install @riaskov/nevo-messaging
|
|
|
28
28
|
### Peer Dependencies
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
|
-
npm install @nestjs/common @nestjs/core @nestjs/microservices @nestjs/config @nestjs/platform-fastify kafkajs nats socket.io socket.io-client 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
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
## Quick Start
|
|
35
35
|
|
|
36
|
-
### 1. Basic Service Setup
|
|
36
|
+
### 1. Basic Service Setup (NATS)
|
|
37
37
|
|
|
38
38
|
Create a simple microservice that responds to messages:
|
|
39
39
|
|
|
40
40
|
```typescript
|
|
41
41
|
// user.service.ts
|
|
42
42
|
import { Injectable, Inject } from "@nestjs/common"
|
|
43
|
-
import {
|
|
43
|
+
import { NatsClientBase, NevoNatsClient } from "@riaskov/nevo-messaging"
|
|
44
44
|
|
|
45
45
|
@Injectable()
|
|
46
|
-
export class UserService extends
|
|
47
|
-
constructor(@Inject("
|
|
46
|
+
export class UserService extends NatsClientBase {
|
|
47
|
+
constructor(@Inject("NEVO_NATS_CLIENT") nevoClient: NevoNatsClient) {
|
|
48
48
|
super(nevoClient)
|
|
49
49
|
}
|
|
50
50
|
|
|
@@ -66,11 +66,11 @@ Map service methods to external signals using the `@Signal` decorator:
|
|
|
66
66
|
```typescript
|
|
67
67
|
// user.controller.ts
|
|
68
68
|
import { Controller, Inject } from "@nestjs/common"
|
|
69
|
-
import {
|
|
69
|
+
import { NatsSignalRouter, Signal } from "@riaskov/nevo-messaging"
|
|
70
70
|
import { UserService } from "./user.service"
|
|
71
71
|
|
|
72
72
|
@Controller()
|
|
73
|
-
@
|
|
73
|
+
@NatsSignalRouter([UserService])
|
|
74
74
|
export class UserController {
|
|
75
75
|
constructor(@Inject(UserService) private readonly userService: UserService) {}
|
|
76
76
|
|
|
@@ -84,13 +84,13 @@ export class UserController {
|
|
|
84
84
|
|
|
85
85
|
### 3. Module Configuration
|
|
86
86
|
|
|
87
|
-
Configure the module with
|
|
87
|
+
Configure the module with the NATS client:
|
|
88
88
|
|
|
89
89
|
```typescript
|
|
90
90
|
// user.module.ts
|
|
91
91
|
import { Module } from "@nestjs/common"
|
|
92
92
|
import { ConfigModule } from "@nestjs/config"
|
|
93
|
-
import {
|
|
93
|
+
import { createNevoNatsClient } from "@riaskov/nevo-messaging"
|
|
94
94
|
import { UserController } from "./user.controller"
|
|
95
95
|
import { UserService } from "./user.service"
|
|
96
96
|
|
|
@@ -99,8 +99,9 @@ import { UserService } from "./user.service"
|
|
|
99
99
|
controllers: [UserController],
|
|
100
100
|
providers: [
|
|
101
101
|
UserService,
|
|
102
|
-
|
|
103
|
-
clientIdPrefix: "user"
|
|
102
|
+
createNevoNatsClient(["COORDINATOR"], {
|
|
103
|
+
clientIdPrefix: "user",
|
|
104
|
+
servers: ["nats://127.0.0.1:4222"]
|
|
104
105
|
})
|
|
105
106
|
]
|
|
106
107
|
})
|
|
@@ -109,20 +110,19 @@ export class UserModule {}
|
|
|
109
110
|
|
|
110
111
|
### 4. Application Bootstrap
|
|
111
112
|
|
|
112
|
-
Start your
|
|
113
|
+
Start your service:
|
|
113
114
|
|
|
114
115
|
```typescript
|
|
115
116
|
// main.ts
|
|
116
|
-
import {
|
|
117
|
+
import { createNatsMicroservice } from "@riaskov/nevo-messaging"
|
|
117
118
|
import { AppModule } from "./app.module"
|
|
118
119
|
|
|
119
|
-
|
|
120
|
+
createNatsMicroservice({
|
|
120
121
|
microserviceName: "user",
|
|
121
122
|
module: AppModule,
|
|
122
123
|
port: 8086
|
|
123
124
|
}).then()
|
|
124
125
|
```
|
|
125
|
-
|
|
126
126
|
## Core Concepts
|
|
127
127
|
|
|
128
128
|
### Signal Routing
|
|
@@ -142,44 +142,44 @@ Use for operations that need a response:
|
|
|
142
142
|
const user = await this.query("user", "user.getById", { id: 123n })
|
|
143
143
|
```
|
|
144
144
|
|
|
145
|
-
#### Emit Pattern (Fire-and-Forget)
|
|
146
|
-
Use for events and notifications:
|
|
147
|
-
|
|
148
|
-
```typescript
|
|
149
|
-
await this.emit("notifications", "user.created", { userId: 123n, email: "user@example.com" })
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
#### Subscription Pattern (Publish/Subscribe)
|
|
153
|
-
Use when you want to receive updates without requesting:
|
|
154
|
-
|
|
155
|
-
```typescript
|
|
156
|
-
const sub = await this.subscribe("user", "user.updated", { ack: true }, async (msg, ctx) => {
|
|
157
|
-
await ctx.ack()
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
await sub.unsubscribe()
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
Publish updates:
|
|
164
|
-
|
|
165
|
-
```typescript
|
|
166
|
-
await this.publish("user", "user.updated", { userId: 123n })
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
#### Broadcast Pattern (System-Wide)
|
|
170
|
-
Send to everyone connected to the broker:
|
|
171
|
-
|
|
172
|
-
```typescript
|
|
173
|
-
await this.broadcast("system.status", { ok: true })
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
Receive broadcast:
|
|
177
|
-
|
|
178
|
-
```typescript
|
|
179
|
-
await this.subscribe("__broadcast", "system.status", {}, (msg) => {
|
|
180
|
-
console.log("System status:", msg)
|
|
181
|
-
})
|
|
182
|
-
```
|
|
145
|
+
#### Emit Pattern (Fire-and-Forget)
|
|
146
|
+
Use for events and notifications:
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
await this.emit("notifications", "user.created", { userId: 123n, email: "user@example.com" })
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
#### Subscription Pattern (Publish/Subscribe)
|
|
153
|
+
Use when you want to receive updates without requesting:
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
const sub = await this.subscribe("user", "user.updated", { ack: true }, async (msg, ctx) => {
|
|
157
|
+
await ctx.ack()
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
await sub.unsubscribe()
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Publish updates:
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
await this.publish("user", "user.updated", { userId: 123n })
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
#### Broadcast Pattern (System-Wide)
|
|
170
|
+
Send to everyone connected to the broker:
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
await this.broadcast("system.status", { ok: true })
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Receive broadcast:
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
await this.subscribe("__broadcast", "system.status", {}, (msg) => {
|
|
180
|
+
console.log("System status:", msg)
|
|
181
|
+
})
|
|
182
|
+
```
|
|
183
183
|
|
|
184
184
|
## Advanced Usage
|
|
185
185
|
|
|
@@ -295,7 +295,7 @@ export class UserController {
|
|
|
295
295
|
}
|
|
296
296
|
```
|
|
297
297
|
|
|
298
|
-
### Error Handling
|
|
298
|
+
### Error Handling
|
|
299
299
|
|
|
300
300
|
The framework provides comprehensive error handling:
|
|
301
301
|
|
|
@@ -316,69 +316,69 @@ export class UserService extends KafkaClientBase {
|
|
|
316
316
|
|
|
317
317
|
return user
|
|
318
318
|
}
|
|
319
|
-
}
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
### Method Suggestions (Did You Mean)
|
|
323
|
-
|
|
324
|
-
If you call a method that doesn't exist, the framework returns a helpful error:
|
|
325
|
-
|
|
326
|
-
```
|
|
327
|
-
Invalid method name 'user.getByI', did you mean 'user.getById'?
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
This works for all transports.
|
|
331
|
-
|
|
332
|
-
### Exponential Backoff (Client-Side)
|
|
333
|
-
|
|
334
|
-
Clients apply a backoff for **in-flight requests** to avoid sending a duplicate query while the previous one is still being processed.
|
|
335
|
-
|
|
336
|
-
```typescript
|
|
337
|
-
createNevoKafkaClient(["USER"], {
|
|
338
|
-
clientIdPrefix: "frontend",
|
|
339
|
-
backoff: {
|
|
340
|
-
enabled: true,
|
|
341
|
-
baseMs: 100,
|
|
342
|
-
maxMs: 2000,
|
|
343
|
-
maxAttempts: 0, // 0 = wait until slot is free
|
|
344
|
-
jitter: true
|
|
345
|
-
}
|
|
346
|
-
})
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
This prevents repeated sending of the same request while the service is busy (e.g., stopped on a breakpoint).
|
|
350
|
-
|
|
351
|
-
### Access Control (ACL)
|
|
352
|
-
|
|
353
|
-
Restrict who can read messages by topic + method + service:
|
|
354
|
-
|
|
355
|
-
```typescript
|
|
356
|
-
@KafkaSignalRouter([UserService], {
|
|
357
|
-
accessControl: {
|
|
358
|
-
rules: [
|
|
359
|
-
{ topic: "user-events", method: "*", allow: ["frontend", "coordinator"] },
|
|
360
|
-
{ topic: "user-events", method: "user.delete", deny: ["frontend"] }
|
|
361
|
-
],
|
|
362
|
-
logDenied: true
|
|
363
|
-
}
|
|
364
|
-
})
|
|
365
|
-
export class UserController {}
|
|
366
|
-
```
|
|
367
|
-
|
|
368
|
-
By default, all services are allowed.
|
|
369
|
-
|
|
370
|
-
### Service Discovery (Registry Topic)
|
|
371
|
-
|
|
372
|
-
Each client sends heartbeats to `__nevo.discovery`. You can read the registry:
|
|
373
|
-
|
|
374
|
-
```typescript
|
|
375
|
-
const services = this.getDiscoveredServices()
|
|
376
|
-
const isUserAvailable = this.isServiceAvailable("user")
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
Discovery is enabled by default for Kafka/NATS. HTTP and Socket.IO discovery are
|
|
380
|
-
|
|
381
|
-
## Configuration
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Method Suggestions (Did You Mean)
|
|
323
|
+
|
|
324
|
+
If you call a method that doesn't exist, the framework returns a helpful error:
|
|
325
|
+
|
|
326
|
+
```
|
|
327
|
+
Invalid method name 'user.getByI', did you mean 'user.getById'?
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
This works for all transports.
|
|
331
|
+
|
|
332
|
+
### Exponential Backoff (Client-Side)
|
|
333
|
+
|
|
334
|
+
Clients apply a backoff for **in-flight requests** to avoid sending a duplicate query while the previous one is still being processed.
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
createNevoKafkaClient(["USER"], {
|
|
338
|
+
clientIdPrefix: "frontend",
|
|
339
|
+
backoff: {
|
|
340
|
+
enabled: true,
|
|
341
|
+
baseMs: 100,
|
|
342
|
+
maxMs: 2000,
|
|
343
|
+
maxAttempts: 0, // 0 = wait until slot is free
|
|
344
|
+
jitter: true
|
|
345
|
+
}
|
|
346
|
+
})
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
This prevents repeated sending of the same request while the service is busy (e.g., stopped on a breakpoint).
|
|
350
|
+
|
|
351
|
+
### Access Control (ACL)
|
|
352
|
+
|
|
353
|
+
Restrict who can read messages by topic + method + service:
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
@KafkaSignalRouter([UserService], {
|
|
357
|
+
accessControl: {
|
|
358
|
+
rules: [
|
|
359
|
+
{ topic: "user-events", method: "*", allow: ["frontend", "coordinator"] },
|
|
360
|
+
{ topic: "user-events", method: "user.delete", deny: ["frontend"] }
|
|
361
|
+
],
|
|
362
|
+
logDenied: true
|
|
363
|
+
}
|
|
364
|
+
})
|
|
365
|
+
export class UserController {}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
By default, all services are allowed.
|
|
369
|
+
|
|
370
|
+
### Service Discovery (Registry Topic)
|
|
371
|
+
|
|
372
|
+
Each client sends heartbeats to `__nevo.discovery`. You can read the registry:
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
const services = this.getDiscoveredServices()
|
|
376
|
+
const isUserAvailable = this.isServiceAvailable("user")
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
Discovery is enabled by default for Kafka/NATS. HTTP and Socket.IO discovery are available when enabled (HTTP requires `discoveryUrl`).
|
|
380
|
+
|
|
381
|
+
## Configuration
|
|
382
382
|
|
|
383
383
|
### Environment Variables
|
|
384
384
|
|
|
@@ -392,102 +392,134 @@ NODE_ENV=production
|
|
|
392
392
|
### Kafka Client Options
|
|
393
393
|
|
|
394
394
|
```typescript
|
|
395
|
-
createNevoKafkaClient(["USER", "INVENTORY", "NOTIFICATIONS"], {
|
|
396
|
-
clientIdPrefix: "order-service",
|
|
397
|
-
groupIdPrefix: "order-consumer",
|
|
398
|
-
sessionTimeout: 30000,
|
|
399
|
-
allowAutoTopicCreation: true,
|
|
400
|
-
retryAttempts: 5,
|
|
401
|
-
brokerRetryTimeout: 2000,
|
|
402
|
-
timeoutMs: 25000,
|
|
403
|
-
debug: false,
|
|
404
|
-
discovery: {
|
|
405
|
-
enabled: true,
|
|
406
|
-
heartbeatIntervalMs: 5000,
|
|
407
|
-
ttlMs: 15000
|
|
408
|
-
}
|
|
409
|
-
})
|
|
410
|
-
```
|
|
395
|
+
createNevoKafkaClient(["USER", "INVENTORY", "NOTIFICATIONS"], {
|
|
396
|
+
clientIdPrefix: "order-service",
|
|
397
|
+
groupIdPrefix: "order-consumer",
|
|
398
|
+
sessionTimeout: 30000,
|
|
399
|
+
allowAutoTopicCreation: true,
|
|
400
|
+
retryAttempts: 5,
|
|
401
|
+
brokerRetryTimeout: 2000,
|
|
402
|
+
timeoutMs: 25000,
|
|
403
|
+
debug: false,
|
|
404
|
+
discovery: {
|
|
405
|
+
enabled: true,
|
|
406
|
+
heartbeatIntervalMs: 5000,
|
|
407
|
+
ttlMs: 15000
|
|
408
|
+
}
|
|
409
|
+
})
|
|
410
|
+
```
|
|
411
411
|
|
|
412
412
|
### Microservice Startup Options
|
|
413
413
|
|
|
414
414
|
```typescript
|
|
415
|
-
createKafkaMicroservice({
|
|
416
|
-
microserviceName: "user",
|
|
417
|
-
module: AppModule,
|
|
418
|
-
port: 8086,
|
|
419
|
-
host: "0.0.0.0",
|
|
420
|
-
debug: true,
|
|
421
|
-
onInit: async (app) => {
|
|
422
|
-
// Custom initialization logic
|
|
423
|
-
await app.get(DatabaseService).runMigrations()
|
|
424
|
-
}
|
|
425
|
-
})
|
|
426
|
-
```
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
```
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
```
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
```
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
```
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
415
|
+
createKafkaMicroservice({
|
|
416
|
+
microserviceName: "user",
|
|
417
|
+
module: AppModule,
|
|
418
|
+
port: 8086,
|
|
419
|
+
host: "0.0.0.0",
|
|
420
|
+
debug: true,
|
|
421
|
+
onInit: async (app) => {
|
|
422
|
+
// Custom initialization logic
|
|
423
|
+
await app.get(DatabaseService).runMigrations()
|
|
424
|
+
}
|
|
425
|
+
})
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
Same options apply to:
|
|
429
|
+
|
|
430
|
+
```typescript
|
|
431
|
+
createNatsMicroservice({ microserviceName: "user", module: AppModule, port: 8087 }).then()
|
|
432
|
+
createSocketMicroservice({ microserviceName: "user", module: AppModule, port: 8088 }).then()
|
|
433
|
+
createHttpMicroservice({ microserviceName: "user", module: AppModule, port: 8089 }).then()
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
## Transports
|
|
437
|
+
|
|
438
|
+
| Transport | Patterns | Discovery | Infra | Notes |
|
|
439
|
+
| --- | --- | --- | --- | --- |
|
|
440
|
+
| NATS | query/emit/publish/subscribe/broadcast | on by default | NATS server | Lowest latency, simple ops |
|
|
441
|
+
| Kafka | query/emit/publish/subscribe/broadcast | on by default | Kafka broker | Durable log, topic setup |
|
|
442
|
+
| Socket.IO | query/emit/publish/subscribe/broadcast | optional | Socket.IO server | WebSocket-friendly apps |
|
|
443
|
+
| HTTP (SSE) | query/emit + SSE subscribe/broadcast | optional | HTTP server | Simple HTTP/SSE integration |
|
|
444
|
+
|
|
445
|
+
### NATS (priority)
|
|
446
|
+
Client factory:
|
|
447
|
+
|
|
448
|
+
```typescript
|
|
449
|
+
createNevoNatsClient(["USER", "COORDINATOR"], {
|
|
450
|
+
clientIdPrefix: "user",
|
|
451
|
+
servers: ["nats://127.0.0.1:4222"]
|
|
452
|
+
})
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
Quick bootstrap:
|
|
456
|
+
|
|
457
|
+
```typescript
|
|
458
|
+
createNatsMicroservice({ microserviceName: "user", module: AppModule, port: 8087 }).then()
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
Controller decorator:
|
|
462
|
+
|
|
463
|
+
```typescript
|
|
464
|
+
@NatsSignalRouter([UserService])
|
|
465
|
+
export class UserController {}
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### Kafka
|
|
469
|
+
Use `createKafkaMicroservice` + `KafkaSignalRouter` as before.
|
|
470
|
+
|
|
471
|
+
### Socket.IO
|
|
472
|
+
Socket.IO server is started inside the router decorator:
|
|
473
|
+
|
|
474
|
+
```typescript
|
|
475
|
+
@SocketSignalRouter([UserService], { serviceName: "user", port: 8093 })
|
|
476
|
+
export class UserController {}
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
Quick bootstrap:
|
|
480
|
+
|
|
481
|
+
```typescript
|
|
482
|
+
createSocketMicroservice({ microserviceName: "user", module: AppModule, port: 8092 }).then()
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
Client:
|
|
486
|
+
|
|
487
|
+
```typescript
|
|
488
|
+
createNevoSocketClient(
|
|
489
|
+
{ coordinator: "http://127.0.0.1:8094" },
|
|
490
|
+
{ clientIdPrefix: "user" }
|
|
491
|
+
)
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### HTTP (SSE)
|
|
495
|
+
HTTP uses plain POST for `query/emit` and SSE for `subscribe`.
|
|
496
|
+
|
|
497
|
+
```typescript
|
|
498
|
+
@HttpSignalRouter([UserService])
|
|
499
|
+
export class UserController {}
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
Include transport controller to enable SSE + publish endpoints:
|
|
503
|
+
|
|
504
|
+
```typescript
|
|
505
|
+
controllers: [UserController, HttpTransportController]
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
Quick bootstrap:
|
|
509
|
+
|
|
510
|
+
```typescript
|
|
511
|
+
createHttpMicroservice({ microserviceName: "user", module: AppModule, port: 8090 }).then()
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
Client:
|
|
515
|
+
|
|
516
|
+
```typescript
|
|
517
|
+
createNevoHttpClient(
|
|
518
|
+
{ coordinator: "http://127.0.0.1:8091" },
|
|
519
|
+
{ clientIdPrefix: "user" }
|
|
520
|
+
)
|
|
521
|
+
```
|
|
522
|
+
## BigInt Support
|
|
491
523
|
|
|
492
524
|
The framework automatically handles BigInt serialization across service boundaries:
|
|
493
525
|
|
|
@@ -860,79 +892,22 @@ createNevoKafkaClient(["HIGH_VOLUME_SERVICE"], {
|
|
|
860
892
|
|
|
861
893
|
## API Reference
|
|
862
894
|
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
#### `@Signal(signalName, methodName?, paramTransformer?, resultTransformer?)`
|
|
866
|
-
|
|
867
|
-
Maps external signals to service methods.
|
|
868
|
-
|
|
869
|
-
**Parameters:**
|
|
870
|
-
- `signalName` (string): External signal identifier
|
|
871
|
-
- `methodName` (string, optional): Service method name (defaults to signalName)
|
|
872
|
-
- `paramTransformer` (function, optional): Transform incoming parameters
|
|
873
|
-
- `resultTransformer` (function, optional): Transform outgoing results
|
|
874
|
-
|
|
875
|
-
#### `@KafkaSignalRouter(serviceTypes, options?)`
|
|
876
|
-
|
|
877
|
-
Class decorator for signal routing setup.
|
|
878
|
-
|
|
879
|
-
**Parameters:**
|
|
880
|
-
- `serviceTypes` (Type<any> | Type<any>[]): Service classes to route to
|
|
881
|
-
- `options` (object, optional): Configuration options
|
|
882
|
-
|
|
883
|
-
### Classes
|
|
884
|
-
|
|
885
|
-
#### `KafkaClientBase`
|
|
886
|
-
|
|
887
|
-
Base class for services that need to communicate with other microservices.
|
|
888
|
-
|
|
889
|
-
**Methods:**
|
|
890
|
-
- `query<T>(serviceName, method, params): Promise<T>` - Request-response communication
|
|
891
|
-
- `emit(serviceName, method, params): Promise<void>` - Fire-and-forget communication
|
|
892
|
-
- `publish(serviceName, method, params): Promise<void>` - Publish to subscriptions
|
|
893
|
-
- `subscribe(serviceName, method, options, handler): Promise<Subscription>` - Subscribe to updates
|
|
894
|
-
- `broadcast(method, params): Promise<void>` - System-wide broadcast
|
|
895
|
-
- `getAvailableServices(): string[]` - List registered services
|
|
896
|
-
- `getDiscoveredServices(): DiscoveryEntry[]` - Service registry snapshot
|
|
897
|
-
- `isServiceAvailable(serviceName): boolean` - Availability check
|
|
898
|
-
|
|
899
|
-
#### `NevoKafkaClient`
|
|
900
|
-
|
|
901
|
-
Universal Kafka client for multi-service communication.
|
|
902
|
-
|
|
903
|
-
**Methods:**
|
|
904
|
-
- `query<T>(serviceName, method, params): Promise<T>` - Send query to service
|
|
905
|
-
- `emit(serviceName, method, params): Promise<void>` - Emit event to service
|
|
906
|
-
- `publish(serviceName, method, params): Promise<void>` - Publish to subscriptions
|
|
907
|
-
- `subscribe(serviceName, method, options, handler): Promise<Subscription>` - Subscribe to updates
|
|
908
|
-
- `broadcast(method, params): Promise<void>` - System-wide broadcast
|
|
909
|
-
- `getAvailableServices(): string[]` - Get list of available services
|
|
910
|
-
|
|
911
|
-
### Functions
|
|
895
|
+
See `API.md`.
|
|
912
896
|
|
|
913
|
-
|
|
897
|
+
## Examples
|
|
914
898
|
|
|
915
|
-
|
|
899
|
+
### NATS
|
|
900
|
+
- `examples/nats-user` - NATS request/response + publish/subscribe + broadcast
|
|
916
901
|
|
|
917
|
-
|
|
902
|
+
### Kafka
|
|
903
|
+
- `examples/user` - standard Kafka microservice
|
|
918
904
|
|
|
919
|
-
|
|
905
|
+
### Socket.IO
|
|
906
|
+
- `examples/socket-user` - Socket.IO transport with subscribe/broadcast
|
|
920
907
|
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
- `examples/user` - standard Kafka microservice
|
|
925
|
-
|
|
926
|
-
### NATS
|
|
927
|
-
- `examples/nats-user` - NATS request/response + publish/subscribe + broadcast
|
|
928
|
-
|
|
929
|
-
### HTTP (SSE)
|
|
930
|
-
- `examples/http-user` - HTTP query/emit + SSE subscribe + broadcast + discovery
|
|
931
|
-
|
|
932
|
-
### Socket.IO
|
|
933
|
-
- `examples/socket-user` - Socket.IO transport with subscribe/broadcast
|
|
934
|
-
|
|
935
|
-
## Troubleshooting
|
|
908
|
+
### HTTP (SSE)
|
|
909
|
+
- `examples/http-user` - HTTP query/emit + SSE subscribe + broadcast + discovery
|
|
910
|
+
## Troubleshooting
|
|
936
911
|
|
|
937
912
|
### Common Issues
|
|
938
913
|
|
|
@@ -1013,4 +988,4 @@ MIT License - see [LICENSE](LICENSE) file for details.
|
|
|
1013
988
|
- Examples: Check the `examples/` directory for complete working examples
|
|
1014
989
|
|
|
1015
990
|
## Aux
|
|
1016
|
-
There are many anys in core code - the simple temporary solution for changeable Nest.js microservices API.
|
|
991
|
+
There are many anys in core code - the simple temporary solution for changeable Nest.js microservices API.
|
|
@@ -19,3 +19,4 @@ __exportStar(require("./http.client-base"), exports);
|
|
|
19
19
|
__exportStar(require("./http.signal-router.decorator"), exports);
|
|
20
20
|
__exportStar(require("./http.transport.controller"), exports);
|
|
21
21
|
__exportStar(require("./http.config"), exports);
|
|
22
|
+
__exportStar(require("./microservice.config"), exports);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createHttpMicroservice = createHttpMicroservice;
|
|
4
|
+
const core_1 = require("@nestjs/core");
|
|
5
|
+
const platform_fastify_1 = require("@nestjs/platform-fastify");
|
|
6
|
+
async function createHttpMicroservice(options) {
|
|
7
|
+
// @ts-ignore
|
|
8
|
+
const { microserviceName, module, port = 3000, host = "0.0.0.0", debug = process.env["NODE_ENV"] !== "production", onInit } = options;
|
|
9
|
+
const app = await core_1.NestFactory.create(module, new platform_fastify_1.FastifyAdapter());
|
|
10
|
+
if (onInit) {
|
|
11
|
+
await onInit(app);
|
|
12
|
+
}
|
|
13
|
+
await app.listen(port, host);
|
|
14
|
+
console.log(`Service started on http://${host === "0.0.0.0" ? "localhost" : host}:${port}`);
|
|
15
|
+
return app;
|
|
16
|
+
}
|
package/dist/transports/index.js
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
import { INestApplication
|
|
2
|
-
|
|
3
|
-
microserviceName: string;
|
|
4
|
-
module: Type<any>;
|
|
5
|
-
port?: number;
|
|
6
|
-
host?: string;
|
|
7
|
-
debug?: boolean;
|
|
8
|
-
onInit?: (app: INestApplication) => Promise<void>;
|
|
9
|
-
}
|
|
1
|
+
import { INestApplication } from "@nestjs/common";
|
|
2
|
+
import { NestApplicationOptions } from "../microservice.options";
|
|
10
3
|
export declare function createKafkaMicroservice(options: NestApplicationOptions): Promise<INestApplication>;
|
|
@@ -18,3 +18,4 @@ __exportStar(require("./nevo-nats.client"), exports);
|
|
|
18
18
|
__exportStar(require("./nats.client-base"), exports);
|
|
19
19
|
__exportStar(require("./nats.config"), exports);
|
|
20
20
|
__exportStar(require("./nats.signal-router.decorator"), exports);
|
|
21
|
+
__exportStar(require("./microservice.config"), exports);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createNatsMicroservice = createNatsMicroservice;
|
|
4
|
+
const core_1 = require("@nestjs/core");
|
|
5
|
+
const platform_fastify_1 = require("@nestjs/platform-fastify");
|
|
6
|
+
async function createNatsMicroservice(options) {
|
|
7
|
+
// @ts-ignore
|
|
8
|
+
const { microserviceName, module, port = 3000, host = "0.0.0.0", debug = process.env["NODE_ENV"] !== "production", onInit } = options;
|
|
9
|
+
const app = await core_1.NestFactory.create(module, new platform_fastify_1.FastifyAdapter());
|
|
10
|
+
if (onInit) {
|
|
11
|
+
await onInit(app);
|
|
12
|
+
}
|
|
13
|
+
await app.listen(port, host);
|
|
14
|
+
console.log(`Service started on http://${host === "0.0.0.0" ? "localhost" : host}:${port}`);
|
|
15
|
+
return app;
|
|
16
|
+
}
|
|
@@ -18,3 +18,4 @@ __exportStar(require("./nevo-socket.client"), exports);
|
|
|
18
18
|
__exportStar(require("./socket.client-base"), exports);
|
|
19
19
|
__exportStar(require("./socket.signal-router.decorator"), exports);
|
|
20
20
|
__exportStar(require("./socket.config"), exports);
|
|
21
|
+
__exportStar(require("./microservice.config"), exports);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSocketMicroservice = createSocketMicroservice;
|
|
4
|
+
const core_1 = require("@nestjs/core");
|
|
5
|
+
const platform_fastify_1 = require("@nestjs/platform-fastify");
|
|
6
|
+
async function createSocketMicroservice(options) {
|
|
7
|
+
// @ts-ignore
|
|
8
|
+
const { microserviceName, module, port = 3000, host = "0.0.0.0", debug = process.env["NODE_ENV"] !== "production", onInit } = options;
|
|
9
|
+
const app = await core_1.NestFactory.create(module, new platform_fastify_1.FastifyAdapter());
|
|
10
|
+
if (onInit) {
|
|
11
|
+
await onInit(app);
|
|
12
|
+
}
|
|
13
|
+
await app.listen(port, host);
|
|
14
|
+
console.log(`Service started on http://${host === "0.0.0.0" ? "localhost" : host}:${port}`);
|
|
15
|
+
return app;
|
|
16
|
+
}
|
package/package.json
CHANGED