@horizon-republic/nestjs-jetstream 1.0.6 → 2.0.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 +711 -107
- package/dist/client/index.d.ts +2 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +6 -15
- package/dist/client/index.js.map +1 -1
- package/dist/client/jetstream.client.d.ts +72 -0
- package/dist/client/jetstream.client.d.ts.map +1 -0
- package/dist/client/jetstream.client.js +280 -0
- package/dist/client/jetstream.client.js.map +1 -0
- package/dist/client/jetstream.record.d.ts +55 -0
- package/dist/client/jetstream.record.d.ts.map +1 -0
- package/dist/client/jetstream.record.js +84 -0
- package/dist/client/jetstream.record.js.map +1 -0
- package/dist/codec/index.d.ts +2 -0
- package/dist/codec/index.d.ts.map +1 -0
- package/dist/codec/index.js +6 -0
- package/dist/codec/index.js.map +1 -0
- package/dist/codec/json.codec.d.ts +20 -0
- package/dist/codec/json.codec.d.ts.map +1 -0
- package/dist/codec/json.codec.js +30 -0
- package/dist/codec/json.codec.js.map +1 -0
- package/dist/connection/connection.provider.d.ts +50 -0
- package/dist/connection/connection.provider.d.ts.map +1 -0
- package/dist/connection/connection.provider.js +141 -0
- package/dist/connection/connection.provider.js.map +1 -0
- package/dist/connection/index.d.ts +2 -0
- package/dist/connection/index.d.ts.map +1 -0
- package/dist/connection/index.js +6 -0
- package/dist/connection/index.js.map +1 -0
- package/dist/context/index.d.ts +2 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +6 -0
- package/dist/context/index.js.map +1 -0
- package/dist/context/rpc.context.d.ts +27 -0
- package/dist/context/rpc.context.d.ts.map +1 -0
- package/dist/context/rpc.context.js +32 -0
- package/dist/context/rpc.context.js.map +1 -0
- package/dist/hooks/event-bus.d.ts +31 -0
- package/dist/hooks/event-bus.d.ts.map +1 -0
- package/dist/hooks/event-bus.js +77 -0
- package/dist/hooks/event-bus.js.map +1 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +6 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/index.d.ts +10 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +34 -17
- package/dist/index.js.map +1 -1
- package/dist/interfaces/client.interface.d.ts +14 -0
- package/dist/interfaces/client.interface.d.ts.map +1 -0
- package/dist/{server/types/index.js → interfaces/client.interface.js} +1 -1
- package/dist/interfaces/client.interface.js.map +1 -0
- package/dist/interfaces/codec.interface.d.ts +28 -0
- package/dist/interfaces/codec.interface.d.ts.map +1 -0
- package/dist/{client/types/index.js → interfaces/codec.interface.js} +1 -1
- package/dist/interfaces/codec.interface.js.map +1 -0
- package/dist/interfaces/hooks.interface.d.ts +49 -0
- package/dist/interfaces/hooks.interface.d.ts.map +1 -0
- package/dist/interfaces/hooks.interface.js +16 -0
- package/dist/interfaces/hooks.interface.js.map +1 -0
- package/dist/interfaces/index.d.ts +8 -0
- package/dist/interfaces/index.d.ts.map +1 -0
- package/dist/interfaces/index.js +6 -0
- package/dist/interfaces/index.js.map +1 -0
- package/dist/interfaces/options.interface.d.ts +118 -0
- package/dist/interfaces/options.interface.d.ts.map +1 -0
- package/dist/{common/types/jetstream-transport.options.js → interfaces/options.interface.js} +1 -1
- package/dist/interfaces/options.interface.js.map +1 -0
- package/dist/interfaces/routing.interface.d.ts +15 -0
- package/dist/interfaces/routing.interface.d.ts.map +1 -0
- package/dist/{server/types/nats.events-map.js → interfaces/routing.interface.js} +1 -2
- package/dist/interfaces/routing.interface.js.map +1 -0
- package/dist/interfaces/stream.interface.d.ts +5 -0
- package/dist/interfaces/stream.interface.d.ts.map +1 -0
- package/dist/interfaces/stream.interface.js +3 -0
- package/dist/interfaces/stream.interface.js.map +1 -0
- package/dist/jetstream.constants.d.ts +56 -0
- package/dist/jetstream.constants.d.ts.map +1 -0
- package/dist/jetstream.constants.js +165 -0
- package/dist/jetstream.constants.js.map +1 -0
- package/dist/jetstream.module.d.ts +83 -0
- package/dist/jetstream.module.d.ts.map +1 -0
- package/dist/jetstream.module.js +380 -0
- package/dist/jetstream.module.js.map +1 -0
- package/dist/server/core-rpc.server.d.ts +31 -0
- package/dist/server/core-rpc.server.d.ts.map +1 -0
- package/dist/server/core-rpc.server.js +93 -0
- package/dist/server/core-rpc.server.js.map +1 -0
- package/dist/server/index.d.ts +4 -2
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +13 -16
- package/dist/server/index.js.map +1 -1
- package/dist/server/infrastructure/consumer.provider.d.ts +36 -0
- package/dist/server/infrastructure/consumer.provider.d.ts.map +1 -0
- package/dist/server/infrastructure/consumer.provider.js +123 -0
- package/dist/server/infrastructure/consumer.provider.js.map +1 -0
- package/dist/server/infrastructure/index.d.ts +4 -0
- package/dist/server/infrastructure/index.d.ts.map +1 -0
- package/dist/server/infrastructure/index.js +10 -0
- package/dist/server/infrastructure/index.js.map +1 -0
- package/dist/server/infrastructure/message.provider.d.ts +46 -0
- package/dist/server/infrastructure/message.provider.d.ts.map +1 -0
- package/dist/server/infrastructure/message.provider.js +100 -0
- package/dist/server/infrastructure/message.provider.js.map +1 -0
- package/dist/server/infrastructure/stream.provider.d.ts +38 -0
- package/dist/server/infrastructure/stream.provider.d.ts.map +1 -0
- package/dist/server/infrastructure/stream.provider.js +109 -0
- package/dist/server/infrastructure/stream.provider.js.map +1 -0
- package/dist/server/routing/event.router.d.ts +37 -0
- package/dist/server/routing/event.router.d.ts.map +1 -0
- package/dist/server/routing/event.router.js +89 -0
- package/dist/server/routing/event.router.js.map +1 -0
- package/dist/server/routing/index.d.ts +4 -0
- package/dist/server/routing/index.d.ts.map +1 -0
- package/dist/server/routing/index.js +10 -0
- package/dist/server/routing/index.js.map +1 -0
- package/dist/server/routing/pattern-registry.d.ts +39 -0
- package/dist/server/routing/pattern-registry.d.ts.map +1 -0
- package/dist/server/routing/pattern-registry.js +116 -0
- package/dist/server/routing/pattern-registry.js.map +1 -0
- package/dist/server/routing/rpc.router.d.ts +37 -0
- package/dist/server/routing/rpc.router.d.ts.map +1 -0
- package/dist/server/routing/rpc.router.js +121 -0
- package/dist/server/routing/rpc.router.js.map +1 -0
- package/dist/server/strategy.d.ts +55 -0
- package/dist/server/strategy.d.ts.map +1 -0
- package/dist/server/strategy.js +113 -0
- package/dist/server/strategy.js.map +1 -0
- package/dist/shutdown/index.d.ts +2 -0
- package/dist/shutdown/index.d.ts.map +1 -0
- package/dist/shutdown/index.js +6 -0
- package/dist/shutdown/index.js.map +1 -0
- package/dist/shutdown/shutdown.manager.d.ts +27 -0
- package/dist/shutdown/shutdown.manager.d.ts.map +1 -0
- package/dist/shutdown/shutdown.manager.js +45 -0
- package/dist/shutdown/shutdown.manager.js.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/unwrap-result.d.ts +11 -0
- package/dist/utils/unwrap-result.d.ts.map +1 -0
- package/dist/utils/unwrap-result.js +37 -0
- package/dist/utils/unwrap-result.js.map +1 -0
- package/package.json +14 -25
- package/dist/client/jetstream-client.module.d.ts +0 -6
- package/dist/client/jetstream-client.module.d.ts.map +0 -1
- package/dist/client/jetstream-client.module.js +0 -68
- package/dist/client/jetstream-client.module.js.map +0 -1
- package/dist/client/jetstream.client-proxy.d.ts +0 -179
- package/dist/client/jetstream.client-proxy.d.ts.map +0 -1
- package/dist/client/jetstream.client-proxy.js +0 -300
- package/dist/client/jetstream.client-proxy.js.map +0 -1
- package/dist/client/types/index.d.ts +0 -7
- package/dist/client/types/index.d.ts.map +0 -1
- package/dist/client/types/index.js.map +0 -1
- package/dist/common/connection.provider.d.ts +0 -309
- package/dist/common/connection.provider.d.ts.map +0 -1
- package/dist/common/connection.provider.js +0 -326
- package/dist/common/connection.provider.js.map +0 -1
- package/dist/common/enum/service-type.enum.d.ts +0 -5
- package/dist/common/enum/service-type.enum.d.ts.map +0 -1
- package/dist/common/enum/service-type.enum.js +0 -9
- package/dist/common/enum/service-type.enum.js.map +0 -1
- package/dist/common/helpers.d.ts +0 -14
- package/dist/common/helpers.d.ts.map +0 -1
- package/dist/common/helpers.js +0 -21
- package/dist/common/helpers.js.map +0 -1
- package/dist/common/index.d.ts +0 -2
- package/dist/common/index.d.ts.map +0 -1
- package/dist/common/index.js +0 -7
- package/dist/common/index.js.map +0 -1
- package/dist/common/pattern-registry.d.ts +0 -51
- package/dist/common/pattern-registry.d.ts.map +0 -1
- package/dist/common/pattern-registry.js +0 -86
- package/dist/common/pattern-registry.js.map +0 -1
- package/dist/common/rpc.context.d.ts +0 -8
- package/dist/common/rpc.context.d.ts.map +0 -1
- package/dist/common/rpc.context.js +0 -14
- package/dist/common/rpc.context.js.map +0 -1
- package/dist/common/types/index.d.ts +0 -2
- package/dist/common/types/index.d.ts.map +0 -1
- package/dist/common/types/index.js +0 -18
- package/dist/common/types/index.js.map +0 -1
- package/dist/common/types/jetstream-transport.options.d.ts +0 -60
- package/dist/common/types/jetstream-transport.options.d.ts.map +0 -1
- package/dist/common/types/jetstream-transport.options.js.map +0 -1
- package/dist/enum/index.d.ts +0 -16
- package/dist/enum/index.d.ts.map +0 -1
- package/dist/enum/index.js +0 -21
- package/dist/enum/index.js.map +0 -1
- package/dist/server/const/index.d.ts +0 -4
- package/dist/server/const/index.d.ts.map +0 -1
- package/dist/server/const/index.js +0 -96
- package/dist/server/const/index.js.map +0 -1
- package/dist/server/enum/index.d.ts +0 -5
- package/dist/server/enum/index.d.ts.map +0 -1
- package/dist/server/enum/index.js +0 -9
- package/dist/server/enum/index.js.map +0 -1
- package/dist/server/jetstream-server.module.d.ts +0 -157
- package/dist/server/jetstream-server.module.d.ts.map +0 -1
- package/dist/server/jetstream-server.module.js +0 -375
- package/dist/server/jetstream-server.module.js.map +0 -1
- package/dist/server/jetstream.strategy.d.ts +0 -150
- package/dist/server/jetstream.strategy.d.ts.map +0 -1
- package/dist/server/jetstream.strategy.js +0 -192
- package/dist/server/jetstream.strategy.js.map +0 -1
- package/dist/server/jetstream.transport.d.ts +0 -9
- package/dist/server/jetstream.transport.d.ts.map +0 -1
- package/dist/server/jetstream.transport.js +0 -26
- package/dist/server/jetstream.transport.js.map +0 -1
- package/dist/server/providers/consumer.provider.d.ts +0 -226
- package/dist/server/providers/consumer.provider.d.ts.map +0 -1
- package/dist/server/providers/consumer.provider.js +0 -272
- package/dist/server/providers/consumer.provider.js.map +0 -1
- package/dist/server/providers/message-routing.provider.d.ts +0 -295
- package/dist/server/providers/message-routing.provider.d.ts.map +0 -1
- package/dist/server/providers/message-routing.provider.js +0 -420
- package/dist/server/providers/message-routing.provider.js.map +0 -1
- package/dist/server/providers/message.provider.d.ts +0 -142
- package/dist/server/providers/message.provider.d.ts.map +0 -1
- package/dist/server/providers/message.provider.js +0 -209
- package/dist/server/providers/message.provider.js.map +0 -1
- package/dist/server/providers/stream.provider.d.ts +0 -320
- package/dist/server/providers/stream.provider.d.ts.map +0 -1
- package/dist/server/providers/stream.provider.js +0 -376
- package/dist/server/providers/stream.provider.js.map +0 -1
- package/dist/server/types/index.d.ts +0 -7
- package/dist/server/types/index.d.ts.map +0 -1
- package/dist/server/types/index.js.map +0 -1
- package/dist/server/types/nats.events-map.d.ts +0 -22
- package/dist/server/types/nats.events-map.d.ts.map +0 -1
- package/dist/server/types/nats.events-map.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,162 +1,770 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @horizon-republic/nestjs-jetstream
|
|
2
2
|
|
|
3
|
-
A NestJS transport for NATS JetStream with built-in support for **Events**
|
|
4
|
-
messaging patterns.
|
|
3
|
+
A production-grade NestJS transport for NATS JetStream with built-in support for **Events**, **Broadcast**, and **RPC** messaging patterns.
|
|
5
4
|
|
|
6
5
|
[](https://www.npmjs.com/package/@horizon-republic/nestjs-jetstream)
|
|
7
6
|
[](https://codecov.io/github/HorizonRepublic/nestjs-jetstream)
|
|
8
7
|
[](https://opensource.org/licenses/MIT)
|
|
9
8
|
|
|
10
|
-
##
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
- [Features](#features)
|
|
12
|
+
- [Installation](#installation)
|
|
13
|
+
- [Quick Start](#quick-start)
|
|
14
|
+
- [Module Configuration](#module-configuration)
|
|
15
|
+
- [forRoot / forRootAsync](#forroot--forrootasync)
|
|
16
|
+
- [forFeature](#forfeature)
|
|
17
|
+
- [Full Options Reference](#full-options-reference)
|
|
18
|
+
- [RPC (Request/Reply)](#rpc-requestreply)
|
|
19
|
+
- [Core Mode (Default)](#core-mode-default)
|
|
20
|
+
- [JetStream Mode](#jetstream-mode)
|
|
21
|
+
- [Events](#events)
|
|
22
|
+
- [Workqueue Events](#workqueue-events)
|
|
23
|
+
- [Broadcast Events](#broadcast-events)
|
|
24
|
+
- [JetstreamRecord Builder](#jetstreamrecord-builder)
|
|
25
|
+
- [Custom Codec](#custom-codec)
|
|
26
|
+
- [RpcContext](#rpccontext)
|
|
27
|
+
- [Lifecycle Hooks](#lifecycle-hooks)
|
|
28
|
+
- [Graceful Shutdown](#graceful-shutdown)
|
|
29
|
+
- [Edge Cases & Important Notes](#edge-cases--important-notes)
|
|
30
|
+
- [NATS Naming Conventions](#nats-naming-conventions)
|
|
31
|
+
- [Default Stream & Consumer Configs](#default-stream--consumer-configs)
|
|
32
|
+
- [API Reference](#api-reference)
|
|
33
|
+
- [Contributing](#contributing)
|
|
34
|
+
- [License](#license)
|
|
35
|
+
- [Links](#links)
|
|
18
36
|
|
|
19
|
-
|
|
37
|
+
## Features
|
|
20
38
|
|
|
21
|
-
-
|
|
39
|
+
- **Two RPC modes** — NATS Core request/reply (lowest latency) or JetStream-persisted commands
|
|
40
|
+
- **At-least-once event delivery** — messages acked after handler success, redelivered on failure
|
|
41
|
+
- **Broadcast events** — fan-out to all subscribing services with per-service durable consumers
|
|
42
|
+
- **Pluggable codec** — JSON by default, swap in MessagePack, Protobuf, or any custom format
|
|
43
|
+
- **Progressive configuration** — two lines to start, full NATS overrides for power users
|
|
44
|
+
- **Lifecycle hooks** — observable events for connect, disconnect, errors, timeouts, shutdown
|
|
45
|
+
- **Graceful shutdown** — drain in-flight messages before closing the connection
|
|
46
|
+
- **Publisher-only mode** — set `consumer: false` for API gateways that only send messages
|
|
47
|
+
- **Per-feature codec override** — different serialization per target service
|
|
22
48
|
|
|
23
49
|
## Installation
|
|
24
50
|
|
|
25
51
|
```bash
|
|
26
52
|
npm install @horizon-republic/nestjs-jetstream
|
|
53
|
+
# or
|
|
54
|
+
pnpm add @horizon-republic/nestjs-jetstream
|
|
55
|
+
# or
|
|
56
|
+
yarn add @horizon-republic/nestjs-jetstream
|
|
27
57
|
```
|
|
28
58
|
|
|
29
|
-
|
|
59
|
+
**Peer dependencies:**
|
|
30
60
|
|
|
31
|
-
|
|
61
|
+
```
|
|
62
|
+
@nestjs/common ^11.0.0
|
|
63
|
+
@nestjs/core ^11.0.0
|
|
64
|
+
@nestjs/microservices ^11.0.0
|
|
65
|
+
nats ^2.0.0
|
|
66
|
+
reflect-metadata ^0.2.0
|
|
67
|
+
rxjs ^7.8.0
|
|
68
|
+
```
|
|
32
69
|
|
|
33
|
-
|
|
70
|
+
## Quick Start
|
|
34
71
|
|
|
35
|
-
|
|
36
|
-
import {JetstreamServerModule} from '@horizon-republic/nestjs-jetstream'
|
|
72
|
+
### 1. Register the module
|
|
37
73
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
74
|
+
```typescript
|
|
75
|
+
// app.module.ts
|
|
76
|
+
import { Module } from '@nestjs/common';
|
|
77
|
+
import { JetstreamModule } from '@horizon-republic/nestjs-jetstream';
|
|
78
|
+
|
|
79
|
+
@Module({
|
|
80
|
+
imports: [
|
|
81
|
+
// Global setup — once per application
|
|
82
|
+
JetstreamModule.forRoot({
|
|
83
|
+
name: 'orders',
|
|
84
|
+
servers: ['nats://localhost:4222'],
|
|
42
85
|
}),
|
|
43
|
-
|
|
86
|
+
|
|
87
|
+
// Client for sending messages to the "orders" service
|
|
88
|
+
JetstreamModule.forFeature({ name: 'orders' }),
|
|
89
|
+
],
|
|
90
|
+
})
|
|
91
|
+
export class AppModule {}
|
|
44
92
|
```
|
|
45
93
|
|
|
46
|
-
|
|
94
|
+
### 2. Connect the transport
|
|
47
95
|
|
|
48
96
|
```typescript
|
|
49
|
-
|
|
97
|
+
// main.ts
|
|
98
|
+
import { NestFactory } from '@nestjs/core';
|
|
99
|
+
import { JetstreamStrategy } from '@horizon-republic/nestjs-jetstream';
|
|
100
|
+
import { AppModule } from './app.module';
|
|
50
101
|
|
|
51
102
|
const bootstrap = async () => {
|
|
52
|
-
|
|
103
|
+
const app = await NestFactory.create(AppModule);
|
|
104
|
+
|
|
105
|
+
app.connectMicroservice(
|
|
106
|
+
{ strategy: app.get(JetstreamStrategy) },
|
|
107
|
+
{ inheritAppConfig: true },
|
|
108
|
+
);
|
|
53
109
|
|
|
54
|
-
|
|
110
|
+
await app.startAllMicroservices();
|
|
111
|
+
await app.listen(3000);
|
|
112
|
+
};
|
|
55
113
|
|
|
56
|
-
|
|
114
|
+
void bootstrap();
|
|
115
|
+
```
|
|
57
116
|
|
|
58
|
-
|
|
117
|
+
### 3. Define handlers
|
|
59
118
|
|
|
60
|
-
|
|
61
|
-
};
|
|
119
|
+
```typescript
|
|
120
|
+
import { Controller } from '@nestjs/common';
|
|
121
|
+
import { EventPattern, MessagePattern, Payload } from '@nestjs/microservices';
|
|
122
|
+
|
|
123
|
+
@Controller()
|
|
124
|
+
export class OrdersController {
|
|
125
|
+
@EventPattern('order.created')
|
|
126
|
+
handleOrderCreated(@Payload() data: { orderId: number }) {
|
|
127
|
+
console.log('Order created:', data.orderId);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
@MessagePattern('order.get')
|
|
131
|
+
getOrder(@Payload() data: { id: number }) {
|
|
132
|
+
return { id: data.id, status: 'shipped' };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
62
135
|
```
|
|
63
136
|
|
|
64
|
-
|
|
137
|
+
### 4. Send messages
|
|
65
138
|
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
139
|
+
```typescript
|
|
140
|
+
import { Controller, Get, Inject } from '@nestjs/common';
|
|
141
|
+
import { ClientProxy } from '@nestjs/microservices';
|
|
142
|
+
|
|
143
|
+
@Controller()
|
|
144
|
+
export class AppController {
|
|
145
|
+
constructor(@Inject('orders') private client: ClientProxy) {}
|
|
146
|
+
|
|
147
|
+
@Get('create')
|
|
148
|
+
createOrder() {
|
|
149
|
+
return this.client.emit('order.created', { orderId: 42 });
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
@Get('get')
|
|
153
|
+
getOrder() {
|
|
154
|
+
return this.client.send('order.get', { id: 42 });
|
|
155
|
+
}
|
|
156
|
+
}
|
|
77
157
|
```
|
|
78
158
|
|
|
79
|
-
|
|
159
|
+
## Module Configuration
|
|
160
|
+
|
|
161
|
+
### forRoot / forRootAsync
|
|
80
162
|
|
|
81
|
-
|
|
82
|
-
- `my_service__microservice_cmd-stream` - for commands
|
|
163
|
+
`forRoot()` registers the transport globally. Call it once in your root `AppModule`.
|
|
83
164
|
|
|
84
|
-
|
|
165
|
+
```typescript
|
|
166
|
+
JetstreamModule.forRoot({
|
|
167
|
+
name: 'orders',
|
|
168
|
+
servers: ['nats://localhost:4222'],
|
|
169
|
+
rpc: { mode: 'core', timeout: 10_000 },
|
|
170
|
+
shutdownTimeout: 15_000,
|
|
171
|
+
hooks: {
|
|
172
|
+
[TransportEvent.Error]: (err, ctx) => sentry.captureException(err),
|
|
173
|
+
},
|
|
174
|
+
})
|
|
175
|
+
```
|
|
85
176
|
|
|
86
|
-
|
|
87
|
-
microservice.
|
|
88
|
-
You can use the `@EventPattern` and `@MessagePattern` decorators not only in controllers, but also in other classes as
|
|
89
|
-
well.
|
|
177
|
+
For async configuration (e.g., loading from `ConfigService`):
|
|
90
178
|
|
|
91
179
|
```typescript
|
|
92
|
-
|
|
93
|
-
|
|
180
|
+
JetstreamModule.forRootAsync({
|
|
181
|
+
name: 'orders',
|
|
182
|
+
imports: [ConfigModule],
|
|
183
|
+
inject: [ConfigService],
|
|
184
|
+
useFactory: (config: ConfigService) => ({
|
|
185
|
+
servers: [config.get('NATS_URL')],
|
|
186
|
+
rpc: { mode: config.get('RPC_MODE') as 'core' | 'jetstream' },
|
|
187
|
+
}),
|
|
188
|
+
})
|
|
189
|
+
```
|
|
94
190
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
191
|
+
Also supports `useExisting` and `useClass` patterns.
|
|
192
|
+
|
|
193
|
+
### forFeature
|
|
194
|
+
|
|
195
|
+
`forFeature()` creates a lightweight client for a target service. Import in each feature module.
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
// The client reuses the NATS connection from forRoot().
|
|
199
|
+
// No separate connection is created.
|
|
200
|
+
JetstreamModule.forFeature({ name: 'users' })
|
|
201
|
+
JetstreamModule.forFeature({ name: 'payments' })
|
|
202
|
+
|
|
203
|
+
// Optionally override the codec for a specific client
|
|
204
|
+
JetstreamModule.forFeature({ name: 'legacy-service', codec: new MsgPackCodec() })
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Inject clients by the service name:
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
constructor(
|
|
211
|
+
@Inject('users') private usersClient: ClientProxy,
|
|
212
|
+
@Inject('payments') private paymentsClient: ClientProxy,
|
|
213
|
+
) {}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Full Options Reference
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
interface JetstreamModuleOptions {
|
|
220
|
+
/** Service name. Used for stream/consumer/subject naming. */
|
|
221
|
+
name: string;
|
|
222
|
+
|
|
223
|
+
/** NATS server URLs. */
|
|
224
|
+
servers: string[];
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Global message codec.
|
|
228
|
+
* @default JsonCodec
|
|
229
|
+
*/
|
|
230
|
+
codec?: Codec;
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* RPC transport mode.
|
|
234
|
+
* @default { mode: 'core' }
|
|
235
|
+
*/
|
|
236
|
+
rpc?: RpcConfig;
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Enable consumer infrastructure (streams, consumers, message routing).
|
|
240
|
+
* Set to false for publisher-only services (e.g., API gateways).
|
|
241
|
+
* @default true
|
|
242
|
+
*/
|
|
243
|
+
consumer?: boolean;
|
|
244
|
+
|
|
245
|
+
/** Workqueue event stream/consumer overrides. */
|
|
246
|
+
events?: { stream?: Partial<StreamConfig>; consumer?: Partial<ConsumerConfig> };
|
|
247
|
+
|
|
248
|
+
/** Broadcast event stream/consumer overrides. */
|
|
249
|
+
broadcast?: { stream?: Partial<StreamConfig>; consumer?: Partial<ConsumerConfig> };
|
|
250
|
+
|
|
251
|
+
/** Transport lifecycle hook handlers. Unset hooks fall back to NestJS Logger. */
|
|
252
|
+
hooks?: Partial<TransportHooks>;
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Graceful shutdown timeout in ms.
|
|
256
|
+
* @default 10_000
|
|
257
|
+
*/
|
|
258
|
+
shutdownTimeout?: number;
|
|
259
|
+
|
|
260
|
+
/** Raw NATS ConnectionOptions pass-through (tls, auth, reconnect, etc.). */
|
|
261
|
+
connectionOptions?: Partial<ConnectionOptions>;
|
|
111
262
|
}
|
|
263
|
+
```
|
|
112
264
|
|
|
265
|
+
#### RpcConfig
|
|
266
|
+
|
|
267
|
+
Discriminated union on `mode`:
|
|
268
|
+
|
|
269
|
+
| Mode | Timeout Default | Persistence | Use Case |
|
|
270
|
+
|------|----------------|-------------|----------|
|
|
271
|
+
| `'core'` | 30s | None | Low-latency, simple RPC |
|
|
272
|
+
| `'jetstream'` | 3 min | JetStream stream | Commands must survive handler downtime |
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
// Core mode (default)
|
|
276
|
+
rpc: { mode: 'core', timeout: 10_000 }
|
|
277
|
+
|
|
278
|
+
// JetStream mode with custom stream/consumer config
|
|
279
|
+
rpc: {
|
|
280
|
+
mode: 'jetstream',
|
|
281
|
+
timeout: 60_000,
|
|
282
|
+
stream: { max_age: nanos(60_000) },
|
|
283
|
+
consumer: { max_deliver: 3 },
|
|
284
|
+
}
|
|
113
285
|
```
|
|
114
286
|
|
|
115
|
-
##
|
|
287
|
+
## RPC (Request/Reply)
|
|
288
|
+
|
|
289
|
+
### Core Mode (Default)
|
|
116
290
|
|
|
117
|
-
|
|
291
|
+
Uses NATS native `request/reply` for the lowest possible latency.
|
|
118
292
|
|
|
119
293
|
```typescript
|
|
120
|
-
|
|
294
|
+
// Configuration
|
|
295
|
+
JetstreamModule.forRoot({
|
|
296
|
+
name: 'orders',
|
|
297
|
+
servers: ['nats://localhost:4222'],
|
|
298
|
+
// rpc: { mode: 'core' } ← default, can be omitted
|
|
299
|
+
})
|
|
300
|
+
```
|
|
121
301
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
302
|
+
**How it works:**
|
|
303
|
+
|
|
304
|
+
1. Client calls `nc.request()` with a timeout
|
|
305
|
+
2. Server receives on a queue-group subscription (load-balanced across instances)
|
|
306
|
+
3. Handler executes and responds via `msg.respond()`
|
|
307
|
+
4. Client receives the response
|
|
308
|
+
|
|
309
|
+
**Error behavior:**
|
|
310
|
+
|
|
311
|
+
| Scenario | Result |
|
|
312
|
+
|----------|--------|
|
|
313
|
+
| Handler success | Response returned to caller |
|
|
314
|
+
| Handler throws | Error response returned to caller |
|
|
315
|
+
| No handler running | Client times out |
|
|
316
|
+
| Decode error | Error response returned to caller |
|
|
317
|
+
|
|
318
|
+
### JetStream Mode
|
|
319
|
+
|
|
320
|
+
Commands are persisted in a JetStream stream. Responses flow back via NATS Core inbox.
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
JetstreamModule.forRoot({
|
|
324
|
+
name: 'orders',
|
|
325
|
+
servers: ['nats://localhost:4222'],
|
|
326
|
+
rpc: { mode: 'jetstream', timeout: 120_000 },
|
|
327
|
+
})
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
**How it works:**
|
|
331
|
+
|
|
332
|
+
1. Client publishes command to JetStream with `replyTo` and `correlationId` headers
|
|
333
|
+
2. Server pulls from consumer, executes handler
|
|
334
|
+
3. Server publishes response to the client's inbox via Core NATS
|
|
335
|
+
4. Server acks/terms the JetStream message
|
|
336
|
+
|
|
337
|
+
**Error behavior:**
|
|
338
|
+
|
|
339
|
+
| Scenario | JetStream Action | Client Result |
|
|
340
|
+
|----------|-----------------|---------------|
|
|
341
|
+
| Handler success | `ack` | Response returned |
|
|
342
|
+
| Handler throws | `term` (no redelivery) | Error response |
|
|
343
|
+
| Handler timeout | `term` | Client times out |
|
|
344
|
+
| Decode error | `term` | No response |
|
|
345
|
+
| No handler | `term` | No response |
|
|
346
|
+
|
|
347
|
+
> **Why `term` instead of `nak` for RPC errors?** Redelivering a failed command could cause duplicate side effects. The caller is responsible for retrying.
|
|
348
|
+
|
|
349
|
+
## Events
|
|
350
|
+
|
|
351
|
+
### Workqueue Events
|
|
352
|
+
|
|
353
|
+
Each event is delivered to **one** handler instance (load-balanced). Messages are acked **after** the handler completes successfully.
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
// Sending
|
|
357
|
+
this.client.emit('order.created', { orderId: 42 });
|
|
358
|
+
|
|
359
|
+
// Handling
|
|
360
|
+
@EventPattern('order.created')
|
|
361
|
+
handleOrderCreated(@Payload() data: OrderCreatedDto) {
|
|
362
|
+
// If this throws, the message is nak'd and redelivered (up to max_deliver times)
|
|
363
|
+
await this.ordersService.process(data);
|
|
364
|
+
}
|
|
128
365
|
```
|
|
129
366
|
|
|
130
|
-
**
|
|
367
|
+
**Delivery semantics (at-least-once):**
|
|
368
|
+
|
|
369
|
+
| Scenario | Action | Redelivery? |
|
|
370
|
+
|----------|--------|-------------|
|
|
371
|
+
| Handler success | `ack` | No |
|
|
372
|
+
| Handler throws | `nak` | Yes, up to `max_deliver` (default: 3) |
|
|
373
|
+
| Decode error | `term` | No (malformed payload) |
|
|
374
|
+
| No handler found | `term` | No (configuration error) |
|
|
375
|
+
|
|
376
|
+
> Handlers **must be idempotent** — NATS may redeliver on failure or timeout.
|
|
377
|
+
|
|
378
|
+
### Broadcast Events
|
|
379
|
+
|
|
380
|
+
Broadcast events are delivered to **all** subscribing services. Each service gets its own durable consumer on a shared `broadcast-stream`.
|
|
131
381
|
|
|
132
382
|
```typescript
|
|
133
|
-
|
|
134
|
-
|
|
383
|
+
// Sending — use the 'broadcast:' prefix
|
|
384
|
+
this.client.emit('broadcast:config.updated', { key: 'theme', value: 'dark' });
|
|
135
385
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
386
|
+
// Handling — use { broadcast: true } in extras
|
|
387
|
+
@EventPattern('config.updated', { broadcast: true })
|
|
388
|
+
handleConfigUpdated(@Payload() data: ConfigDto) {
|
|
389
|
+
this.configCache.invalidate(data.key);
|
|
390
|
+
}
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
Every service with this handler receives the message independently.
|
|
394
|
+
|
|
395
|
+
## JetstreamRecord Builder
|
|
396
|
+
|
|
397
|
+
Attach custom headers and per-request timeouts using the builder pattern:
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
import { JetstreamRecordBuilder } from '@horizon-republic/nestjs-jetstream';
|
|
401
|
+
|
|
402
|
+
const record = new JetstreamRecordBuilder({ id: 1 })
|
|
403
|
+
.setHeader('x-trace-id', 'abc-123')
|
|
404
|
+
.setHeader('x-tenant', 'acme')
|
|
405
|
+
.setTimeout(5000)
|
|
406
|
+
.build();
|
|
407
|
+
|
|
408
|
+
// Works with both send() and emit()
|
|
409
|
+
this.client.send('user.get', record);
|
|
410
|
+
this.client.emit('user.created', record);
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
**Reserved headers** (set automatically by the transport, cannot be overridden):
|
|
414
|
+
|
|
415
|
+
| Header | Purpose |
|
|
416
|
+
|--------|---------|
|
|
417
|
+
| `x-correlation-id` | RPC request/response matching |
|
|
418
|
+
| `x-reply-to` | JetStream RPC response inbox |
|
|
419
|
+
| `x-message-id` | Deduplication |
|
|
420
|
+
|
|
421
|
+
Attempting to set a reserved header throws an error at build time.
|
|
422
|
+
|
|
423
|
+
**Additional transport headers** (set automatically, available in handlers):
|
|
424
|
+
|
|
425
|
+
| Header | Purpose |
|
|
426
|
+
|--------|---------|
|
|
427
|
+
| `x-subject` | Original NATS subject |
|
|
428
|
+
| `x-caller-name` | Sending service name |
|
|
429
|
+
| `x-request-id` | Available for user-defined request tracking |
|
|
430
|
+
| `x-trace-id` | Available for distributed tracing |
|
|
431
|
+
| `x-span-id` | Available for distributed tracing |
|
|
432
|
+
|
|
433
|
+
## Custom Codec
|
|
434
|
+
|
|
435
|
+
The library uses JSON by default. Implement the `Codec` interface for any serialization format:
|
|
436
|
+
|
|
437
|
+
```typescript
|
|
438
|
+
import { Codec } from '@horizon-republic/nestjs-jetstream';
|
|
439
|
+
import { encode, decode } from '@msgpack/msgpack';
|
|
440
|
+
|
|
441
|
+
class MsgPackCodec implements Codec {
|
|
442
|
+
encode(data: unknown): Uint8Array {
|
|
443
|
+
return encode(data);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
decode(data: Uint8Array): unknown {
|
|
447
|
+
return decode(data);
|
|
448
|
+
}
|
|
152
449
|
}
|
|
450
|
+
```
|
|
153
451
|
|
|
452
|
+
```typescript
|
|
453
|
+
// Global codec
|
|
454
|
+
JetstreamModule.forRoot({
|
|
455
|
+
name: 'orders',
|
|
456
|
+
servers: ['nats://localhost:4222'],
|
|
457
|
+
codec: new MsgPackCodec(),
|
|
458
|
+
})
|
|
459
|
+
|
|
460
|
+
// Per-client override (falls back to global codec when omitted)
|
|
461
|
+
JetstreamModule.forFeature({
|
|
462
|
+
name: 'legacy-service',
|
|
463
|
+
codec: new JsonCodec(),
|
|
464
|
+
})
|
|
154
465
|
```
|
|
155
466
|
|
|
156
|
-
|
|
467
|
+
> All services communicating with each other **must use the same codec**. A codec mismatch results in decode errors (`term`, no redelivery).
|
|
468
|
+
|
|
469
|
+
## RpcContext
|
|
470
|
+
|
|
471
|
+
Access the raw NATS message in handlers for advanced use cases:
|
|
472
|
+
|
|
473
|
+
```typescript
|
|
474
|
+
import { Ctx, Payload, MessagePattern } from '@nestjs/microservices';
|
|
475
|
+
import { RpcContext } from '@horizon-republic/nestjs-jetstream';
|
|
476
|
+
|
|
477
|
+
@MessagePattern('user.get')
|
|
478
|
+
getUser(@Payload() data: GetUserDto, @Ctx() ctx: RpcContext) {
|
|
479
|
+
const msg = ctx.getMessage(); // JsMsg | Msg
|
|
480
|
+
const subject = ctx.getSubject(); // Full NATS subject
|
|
157
481
|
|
|
158
|
-
|
|
159
|
-
|
|
482
|
+
const traceId = msg.headers?.get('x-trace-id');
|
|
483
|
+
|
|
484
|
+
return this.userService.findOne(data.id);
|
|
485
|
+
}
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
Available on both `@EventPattern` and `@MessagePattern` handlers.
|
|
489
|
+
|
|
490
|
+
## Lifecycle Hooks
|
|
491
|
+
|
|
492
|
+
Subscribe to transport events for monitoring, alerting, or custom logic:
|
|
493
|
+
|
|
494
|
+
```typescript
|
|
495
|
+
import { JetstreamModule, TransportEvent } from '@horizon-republic/nestjs-jetstream';
|
|
496
|
+
|
|
497
|
+
JetstreamModule.forRoot({
|
|
498
|
+
name: 'orders',
|
|
499
|
+
servers: ['nats://localhost:4222'],
|
|
500
|
+
hooks: {
|
|
501
|
+
[TransportEvent.Connect]: (server) => {
|
|
502
|
+
console.log(`Connected to ${server}`);
|
|
503
|
+
},
|
|
504
|
+
[TransportEvent.Disconnect]: () => {
|
|
505
|
+
metrics.increment('nats.disconnect');
|
|
506
|
+
},
|
|
507
|
+
[TransportEvent.Error]: (error, context) => {
|
|
508
|
+
sentry.captureException(error, { extra: { context } });
|
|
509
|
+
},
|
|
510
|
+
[TransportEvent.RpcTimeout]: (subject, correlationId) => {
|
|
511
|
+
metrics.increment('rpc.timeout', { subject });
|
|
512
|
+
},
|
|
513
|
+
},
|
|
514
|
+
})
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
**Available events:**
|
|
518
|
+
|
|
519
|
+
| Event | Arguments | Default (no hook) |
|
|
520
|
+
|-------|-----------|-------------------|
|
|
521
|
+
| `connect` | `(server: string)` | `Logger.log` |
|
|
522
|
+
| `disconnect` | `()` | `Logger.warn` |
|
|
523
|
+
| `reconnect` | `(server: string)` | `Logger.log` |
|
|
524
|
+
| `error` | `(error: Error, context?: string)` | `Logger.error` |
|
|
525
|
+
| `rpcTimeout` | `(subject: string, correlationId: string)` | `Logger.warn` |
|
|
526
|
+
| `consumerLag` | `(consumer: string, pending: number)` | `Logger.warn` |
|
|
527
|
+
| `messageRouted` | `(subject: string, kind: 'rpc' \| 'event')` | `Logger.debug` |
|
|
528
|
+
| `shutdownStart` | `()` | `Logger.log` |
|
|
529
|
+
| `shutdownComplete` | `()` | `Logger.log` |
|
|
530
|
+
|
|
531
|
+
## Graceful Shutdown
|
|
532
|
+
|
|
533
|
+
The transport shuts down automatically via NestJS `onApplicationShutdown()`:
|
|
534
|
+
|
|
535
|
+
1. Stop accepting new messages (close subscriptions, stop consumers)
|
|
536
|
+
2. Drain and close NATS connection (waits for in-flight messages)
|
|
537
|
+
3. Safety timeout if drain takes too long
|
|
538
|
+
|
|
539
|
+
```typescript
|
|
540
|
+
JetstreamModule.forRoot({
|
|
541
|
+
name: 'orders',
|
|
542
|
+
servers: ['nats://localhost:4222'],
|
|
543
|
+
shutdownTimeout: 15_000, // default: 10_000 ms
|
|
544
|
+
})
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
No manual shutdown code needed.
|
|
548
|
+
|
|
549
|
+
## Edge Cases & Important Notes
|
|
550
|
+
|
|
551
|
+
### Event handlers must be idempotent
|
|
552
|
+
|
|
553
|
+
Events use at-least-once delivery. If your handler throws, the message is `nak`'d and NATS redelivers it (up to `max_deliver` times, default 3). Design handlers to be safe for repeated execution.
|
|
554
|
+
|
|
555
|
+
### RPC errors are not retried (JetStream mode)
|
|
556
|
+
|
|
557
|
+
When a JetStream RPC handler fails, the message is `term`'d (not `nak`'d). This prevents duplicate side effects. The caller is responsible for implementing retry logic.
|
|
558
|
+
|
|
559
|
+
### Fire-and-forget events
|
|
560
|
+
|
|
561
|
+
This library focuses on **reliable, persistent** event delivery via JetStream. If you need fire-and-forget (no persistence, no ack) for high-throughput scenarios, use the standard [NestJS NATS transport](https://docs.nestjs.com/microservices/nats) — it works perfectly alongside this library on the same NATS server.
|
|
562
|
+
|
|
563
|
+
### Publisher-only mode
|
|
564
|
+
|
|
565
|
+
For services that only send messages (e.g., API gateways), disable consumer infrastructure:
|
|
566
|
+
|
|
567
|
+
```typescript
|
|
568
|
+
JetstreamModule.forRoot({
|
|
569
|
+
name: 'api-gateway',
|
|
570
|
+
servers: ['nats://localhost:4222'],
|
|
571
|
+
consumer: false, // no streams, consumers, or routers created
|
|
572
|
+
})
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
### Broadcast stream is shared
|
|
576
|
+
|
|
577
|
+
All services share a single `broadcast-stream`. Each service creates its own durable consumer with `filter_subjects` matching only its registered broadcast patterns. Stream-level configuration (`broadcast.stream`) affects all services.
|
|
578
|
+
|
|
579
|
+
### Connection failure behavior
|
|
580
|
+
|
|
581
|
+
If the initial NATS connection is refused, the module throws a `RuntimeException` immediately (fail fast). For transient disconnects after startup, NATS handles reconnection automatically and the `reconnect` hook fires.
|
|
582
|
+
|
|
583
|
+
### Observable return values
|
|
584
|
+
|
|
585
|
+
Handlers can return Observables. The transport takes the **first emitted value** for RPC responses and awaits completion for events:
|
|
586
|
+
|
|
587
|
+
```typescript
|
|
588
|
+
@MessagePattern('user.get')
|
|
589
|
+
getUser(@Payload() data: { id: number }): Observable<UserDto> {
|
|
590
|
+
return this.userService.findById(data.id); // first value used as response
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
@EventPattern('order.created')
|
|
594
|
+
handleOrder(@Payload() data: OrderDto): Observable<void> {
|
|
595
|
+
return this.pipeline.process(data); // awaits completion before ack
|
|
596
|
+
}
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
### Consumer self-healing
|
|
600
|
+
|
|
601
|
+
If a JetStream consumer's message iterator ends unexpectedly (e.g., NATS restart), the transport automatically re-establishes consumption after a 100ms delay. This is logged as a warning.
|
|
602
|
+
|
|
603
|
+
### NATS header size
|
|
604
|
+
|
|
605
|
+
Custom headers are transmitted as NATS message headers. NATS has a default header size limit. If you're attaching large metadata, consider putting it in the message body instead.
|
|
606
|
+
|
|
607
|
+
## NATS Naming Conventions
|
|
608
|
+
|
|
609
|
+
The transport generates NATS subjects, streams, and consumers based on the service `name`:
|
|
610
|
+
|
|
611
|
+
| Resource | Format | Example (`name: 'orders'`) |
|
|
612
|
+
|----------|--------|----------------------------|
|
|
613
|
+
| Internal name | `{name}__microservice` | `orders__microservice` |
|
|
614
|
+
| RPC subject | `{internal}.cmd.{pattern}` | `orders__microservice.cmd.get.order` |
|
|
615
|
+
| Event subject | `{internal}.ev.{pattern}` | `orders__microservice.ev.order.created` |
|
|
616
|
+
| Broadcast subject | `broadcast.{pattern}` | `broadcast.config.updated` |
|
|
617
|
+
| Event stream | `{internal}_ev-stream` | `orders__microservice_ev-stream` |
|
|
618
|
+
| Command stream | `{internal}_cmd-stream` | `orders__microservice_cmd-stream` |
|
|
619
|
+
| Broadcast stream | `broadcast-stream` | `broadcast-stream` |
|
|
620
|
+
| Event consumer | `{internal}_ev-consumer` | `orders__microservice_ev-consumer` |
|
|
621
|
+
| Command consumer | `{internal}_cmd-consumer` | `orders__microservice_cmd-consumer` |
|
|
622
|
+
| Broadcast consumer | `{internal}_broadcast-consumer` | `orders__microservice_broadcast-consumer` |
|
|
623
|
+
|
|
624
|
+
## Default Stream & Consumer Configs
|
|
625
|
+
|
|
626
|
+
All defaults can be overridden via `events`, `broadcast`, or `rpc` options.
|
|
627
|
+
|
|
628
|
+
<details>
|
|
629
|
+
<summary><strong>Event Stream</strong></summary>
|
|
630
|
+
|
|
631
|
+
| Property | Value |
|
|
632
|
+
|----------|-------|
|
|
633
|
+
| Retention | Workqueue |
|
|
634
|
+
| Storage | File |
|
|
635
|
+
| Replicas | 1 |
|
|
636
|
+
| Max consumers | 100 |
|
|
637
|
+
| Max message size | 10 MB |
|
|
638
|
+
| Max messages/subject | 5,000,000 |
|
|
639
|
+
| Max messages | 50,000,000 |
|
|
640
|
+
| Max bytes | 5 GB |
|
|
641
|
+
| Max age | 7 days |
|
|
642
|
+
| Duplicate window | 2 minutes |
|
|
643
|
+
|
|
644
|
+
</details>
|
|
645
|
+
|
|
646
|
+
<details>
|
|
647
|
+
<summary><strong>Command Stream (JetStream RPC only)</strong></summary>
|
|
648
|
+
|
|
649
|
+
| Property | Value |
|
|
650
|
+
|----------|-------|
|
|
651
|
+
| Retention | Workqueue |
|
|
652
|
+
| Storage | File |
|
|
653
|
+
| Replicas | 1 |
|
|
654
|
+
| Max consumers | 50 |
|
|
655
|
+
| Max message size | 5 MB |
|
|
656
|
+
| Max messages/subject | 100,000 |
|
|
657
|
+
| Max messages | 1,000,000 |
|
|
658
|
+
| Max bytes | 100 MB |
|
|
659
|
+
| Max age | 3 minutes |
|
|
660
|
+
| Duplicate window | 30 seconds |
|
|
661
|
+
|
|
662
|
+
</details>
|
|
663
|
+
|
|
664
|
+
<details>
|
|
665
|
+
<summary><strong>Broadcast Stream</strong></summary>
|
|
666
|
+
|
|
667
|
+
| Property | Value |
|
|
668
|
+
|----------|-------|
|
|
669
|
+
| Retention | Limits |
|
|
670
|
+
| Storage | File |
|
|
671
|
+
| Replicas | 1 |
|
|
672
|
+
| Max consumers | 200 |
|
|
673
|
+
| Max message size | 10 MB |
|
|
674
|
+
| Max messages/subject | 1,000,000 |
|
|
675
|
+
| Max messages | 10,000,000 |
|
|
676
|
+
| Max bytes | 2 GB |
|
|
677
|
+
| Max age | 1 day |
|
|
678
|
+
| Duplicate window | 2 minutes |
|
|
679
|
+
|
|
680
|
+
</details>
|
|
681
|
+
|
|
682
|
+
<details>
|
|
683
|
+
<summary><strong>Consumer Configs</strong></summary>
|
|
684
|
+
|
|
685
|
+
**Event consumer:**
|
|
686
|
+
|
|
687
|
+
| Property | Value |
|
|
688
|
+
|----------|-------|
|
|
689
|
+
| Ack wait | 10 seconds |
|
|
690
|
+
| Max deliver | 3 |
|
|
691
|
+
| Max ack pending | 100 |
|
|
692
|
+
|
|
693
|
+
**Command consumer (JetStream RPC):**
|
|
694
|
+
|
|
695
|
+
| Property | Value |
|
|
696
|
+
|----------|-------|
|
|
697
|
+
| Ack wait | 5 minutes |
|
|
698
|
+
| Max deliver | 1 |
|
|
699
|
+
| Max ack pending | 100 |
|
|
700
|
+
|
|
701
|
+
**Broadcast consumer:**
|
|
702
|
+
|
|
703
|
+
| Property | Value |
|
|
704
|
+
|----------|-------|
|
|
705
|
+
| Ack wait | 10 seconds |
|
|
706
|
+
| Max deliver | 3 |
|
|
707
|
+
| Max ack pending | 100 |
|
|
708
|
+
|
|
709
|
+
</details>
|
|
710
|
+
|
|
711
|
+
## API Reference
|
|
712
|
+
|
|
713
|
+
### Exports
|
|
714
|
+
|
|
715
|
+
```typescript
|
|
716
|
+
// Module
|
|
717
|
+
JetstreamModule
|
|
718
|
+
|
|
719
|
+
// Client
|
|
720
|
+
JetstreamClient
|
|
721
|
+
JetstreamRecord
|
|
722
|
+
JetstreamRecordBuilder
|
|
723
|
+
|
|
724
|
+
// Server
|
|
725
|
+
JetstreamStrategy
|
|
726
|
+
|
|
727
|
+
// Codec
|
|
728
|
+
JsonCodec
|
|
729
|
+
|
|
730
|
+
// Context
|
|
731
|
+
RpcContext
|
|
732
|
+
|
|
733
|
+
// Hooks
|
|
734
|
+
EventBus
|
|
735
|
+
TransportEvent
|
|
736
|
+
|
|
737
|
+
// Constants
|
|
738
|
+
JETSTREAM_OPTIONS
|
|
739
|
+
JETSTREAM_CONNECTION
|
|
740
|
+
JETSTREAM_CODEC
|
|
741
|
+
JETSTREAM_EVENT_BUS
|
|
742
|
+
JetstreamHeader
|
|
743
|
+
getClientToken
|
|
744
|
+
nanos
|
|
745
|
+
|
|
746
|
+
// Types
|
|
747
|
+
Codec
|
|
748
|
+
JetstreamModuleOptions
|
|
749
|
+
JetstreamModuleAsyncOptions
|
|
750
|
+
JetstreamFeatureOptions
|
|
751
|
+
RpcConfig
|
|
752
|
+
StreamConsumerOverrides
|
|
753
|
+
TransportHooks
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
### Helper: `nanos(ms)`
|
|
757
|
+
|
|
758
|
+
Convert milliseconds to nanoseconds (required by NATS JetStream config):
|
|
759
|
+
|
|
760
|
+
```typescript
|
|
761
|
+
import { nanos } from '@horizon-republic/nestjs-jetstream';
|
|
762
|
+
|
|
763
|
+
// Use in stream/consumer overrides
|
|
764
|
+
events: {
|
|
765
|
+
stream: { max_age: nanos(3 * 24 * 60 * 60 * 1000) }, // 3 days
|
|
766
|
+
consumer: { ack_wait: nanos(30_000) }, // 30s
|
|
767
|
+
}
|
|
160
768
|
```
|
|
161
769
|
|
|
162
770
|
## Contributing
|
|
@@ -165,7 +773,7 @@ Contributions are welcome! Please read [CONTRIBUTING.md](./CONTRIBUTING.md) for
|
|
|
165
773
|
|
|
166
774
|
## License
|
|
167
775
|
|
|
168
|
-
MIT
|
|
776
|
+
[MIT](./LICENSE)
|
|
169
777
|
|
|
170
778
|
## Links
|
|
171
779
|
|
|
@@ -173,9 +781,5 @@ MIT © [Your Name]
|
|
|
173
781
|
- [NestJS Microservices](https://docs.nestjs.com/microservices/basics)
|
|
174
782
|
- [GitHub Repository](https://github.com/HorizonRepublic/nestjs-jetstream)
|
|
175
783
|
- [npm Package](https://www.npmjs.com/package/@horizon-republic/nestjs-jetstream)
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
- 🐛 [Report bugs](https://github.com/HorizonRepublic/nestjs-jetstream/issues)
|
|
180
|
-
- 💬 [Discussions](https://github.com/HorizonRepublic/nestjs-jetstream/discussions)
|
|
181
|
-
- 📧 Email: [themaiby0@gmail.com](mailto:themaiby0@gmail.com)
|
|
784
|
+
- [Report bugs](https://github.com/HorizonRepublic/nestjs-jetstream/issues)
|
|
785
|
+
- [Discussions](https://github.com/HorizonRepublic/nestjs-jetstream/discussions)
|