@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.
Files changed (234) hide show
  1. package/README.md +711 -107
  2. package/dist/client/index.d.ts +2 -1
  3. package/dist/client/index.d.ts.map +1 -1
  4. package/dist/client/index.js +6 -15
  5. package/dist/client/index.js.map +1 -1
  6. package/dist/client/jetstream.client.d.ts +72 -0
  7. package/dist/client/jetstream.client.d.ts.map +1 -0
  8. package/dist/client/jetstream.client.js +280 -0
  9. package/dist/client/jetstream.client.js.map +1 -0
  10. package/dist/client/jetstream.record.d.ts +55 -0
  11. package/dist/client/jetstream.record.d.ts.map +1 -0
  12. package/dist/client/jetstream.record.js +84 -0
  13. package/dist/client/jetstream.record.js.map +1 -0
  14. package/dist/codec/index.d.ts +2 -0
  15. package/dist/codec/index.d.ts.map +1 -0
  16. package/dist/codec/index.js +6 -0
  17. package/dist/codec/index.js.map +1 -0
  18. package/dist/codec/json.codec.d.ts +20 -0
  19. package/dist/codec/json.codec.d.ts.map +1 -0
  20. package/dist/codec/json.codec.js +30 -0
  21. package/dist/codec/json.codec.js.map +1 -0
  22. package/dist/connection/connection.provider.d.ts +50 -0
  23. package/dist/connection/connection.provider.d.ts.map +1 -0
  24. package/dist/connection/connection.provider.js +141 -0
  25. package/dist/connection/connection.provider.js.map +1 -0
  26. package/dist/connection/index.d.ts +2 -0
  27. package/dist/connection/index.d.ts.map +1 -0
  28. package/dist/connection/index.js +6 -0
  29. package/dist/connection/index.js.map +1 -0
  30. package/dist/context/index.d.ts +2 -0
  31. package/dist/context/index.d.ts.map +1 -0
  32. package/dist/context/index.js +6 -0
  33. package/dist/context/index.js.map +1 -0
  34. package/dist/context/rpc.context.d.ts +27 -0
  35. package/dist/context/rpc.context.d.ts.map +1 -0
  36. package/dist/context/rpc.context.js +32 -0
  37. package/dist/context/rpc.context.js.map +1 -0
  38. package/dist/hooks/event-bus.d.ts +31 -0
  39. package/dist/hooks/event-bus.d.ts.map +1 -0
  40. package/dist/hooks/event-bus.js +77 -0
  41. package/dist/hooks/event-bus.js.map +1 -0
  42. package/dist/hooks/index.d.ts +2 -0
  43. package/dist/hooks/index.d.ts.map +1 -0
  44. package/dist/hooks/index.js +6 -0
  45. package/dist/hooks/index.js.map +1 -0
  46. package/dist/index.d.ts +10 -3
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +34 -17
  49. package/dist/index.js.map +1 -1
  50. package/dist/interfaces/client.interface.d.ts +14 -0
  51. package/dist/interfaces/client.interface.d.ts.map +1 -0
  52. package/dist/{server/types/index.js → interfaces/client.interface.js} +1 -1
  53. package/dist/interfaces/client.interface.js.map +1 -0
  54. package/dist/interfaces/codec.interface.d.ts +28 -0
  55. package/dist/interfaces/codec.interface.d.ts.map +1 -0
  56. package/dist/{client/types/index.js → interfaces/codec.interface.js} +1 -1
  57. package/dist/interfaces/codec.interface.js.map +1 -0
  58. package/dist/interfaces/hooks.interface.d.ts +49 -0
  59. package/dist/interfaces/hooks.interface.d.ts.map +1 -0
  60. package/dist/interfaces/hooks.interface.js +16 -0
  61. package/dist/interfaces/hooks.interface.js.map +1 -0
  62. package/dist/interfaces/index.d.ts +8 -0
  63. package/dist/interfaces/index.d.ts.map +1 -0
  64. package/dist/interfaces/index.js +6 -0
  65. package/dist/interfaces/index.js.map +1 -0
  66. package/dist/interfaces/options.interface.d.ts +118 -0
  67. package/dist/interfaces/options.interface.d.ts.map +1 -0
  68. package/dist/{common/types/jetstream-transport.options.js → interfaces/options.interface.js} +1 -1
  69. package/dist/interfaces/options.interface.js.map +1 -0
  70. package/dist/interfaces/routing.interface.d.ts +15 -0
  71. package/dist/interfaces/routing.interface.d.ts.map +1 -0
  72. package/dist/{server/types/nats.events-map.js → interfaces/routing.interface.js} +1 -2
  73. package/dist/interfaces/routing.interface.js.map +1 -0
  74. package/dist/interfaces/stream.interface.d.ts +5 -0
  75. package/dist/interfaces/stream.interface.d.ts.map +1 -0
  76. package/dist/interfaces/stream.interface.js +3 -0
  77. package/dist/interfaces/stream.interface.js.map +1 -0
  78. package/dist/jetstream.constants.d.ts +56 -0
  79. package/dist/jetstream.constants.d.ts.map +1 -0
  80. package/dist/jetstream.constants.js +165 -0
  81. package/dist/jetstream.constants.js.map +1 -0
  82. package/dist/jetstream.module.d.ts +83 -0
  83. package/dist/jetstream.module.d.ts.map +1 -0
  84. package/dist/jetstream.module.js +380 -0
  85. package/dist/jetstream.module.js.map +1 -0
  86. package/dist/server/core-rpc.server.d.ts +31 -0
  87. package/dist/server/core-rpc.server.d.ts.map +1 -0
  88. package/dist/server/core-rpc.server.js +93 -0
  89. package/dist/server/core-rpc.server.js.map +1 -0
  90. package/dist/server/index.d.ts +4 -2
  91. package/dist/server/index.d.ts.map +1 -1
  92. package/dist/server/index.js +13 -16
  93. package/dist/server/index.js.map +1 -1
  94. package/dist/server/infrastructure/consumer.provider.d.ts +36 -0
  95. package/dist/server/infrastructure/consumer.provider.d.ts.map +1 -0
  96. package/dist/server/infrastructure/consumer.provider.js +123 -0
  97. package/dist/server/infrastructure/consumer.provider.js.map +1 -0
  98. package/dist/server/infrastructure/index.d.ts +4 -0
  99. package/dist/server/infrastructure/index.d.ts.map +1 -0
  100. package/dist/server/infrastructure/index.js +10 -0
  101. package/dist/server/infrastructure/index.js.map +1 -0
  102. package/dist/server/infrastructure/message.provider.d.ts +46 -0
  103. package/dist/server/infrastructure/message.provider.d.ts.map +1 -0
  104. package/dist/server/infrastructure/message.provider.js +100 -0
  105. package/dist/server/infrastructure/message.provider.js.map +1 -0
  106. package/dist/server/infrastructure/stream.provider.d.ts +38 -0
  107. package/dist/server/infrastructure/stream.provider.d.ts.map +1 -0
  108. package/dist/server/infrastructure/stream.provider.js +109 -0
  109. package/dist/server/infrastructure/stream.provider.js.map +1 -0
  110. package/dist/server/routing/event.router.d.ts +37 -0
  111. package/dist/server/routing/event.router.d.ts.map +1 -0
  112. package/dist/server/routing/event.router.js +89 -0
  113. package/dist/server/routing/event.router.js.map +1 -0
  114. package/dist/server/routing/index.d.ts +4 -0
  115. package/dist/server/routing/index.d.ts.map +1 -0
  116. package/dist/server/routing/index.js +10 -0
  117. package/dist/server/routing/index.js.map +1 -0
  118. package/dist/server/routing/pattern-registry.d.ts +39 -0
  119. package/dist/server/routing/pattern-registry.d.ts.map +1 -0
  120. package/dist/server/routing/pattern-registry.js +116 -0
  121. package/dist/server/routing/pattern-registry.js.map +1 -0
  122. package/dist/server/routing/rpc.router.d.ts +37 -0
  123. package/dist/server/routing/rpc.router.d.ts.map +1 -0
  124. package/dist/server/routing/rpc.router.js +121 -0
  125. package/dist/server/routing/rpc.router.js.map +1 -0
  126. package/dist/server/strategy.d.ts +55 -0
  127. package/dist/server/strategy.d.ts.map +1 -0
  128. package/dist/server/strategy.js +113 -0
  129. package/dist/server/strategy.js.map +1 -0
  130. package/dist/shutdown/index.d.ts +2 -0
  131. package/dist/shutdown/index.d.ts.map +1 -0
  132. package/dist/shutdown/index.js +6 -0
  133. package/dist/shutdown/index.js.map +1 -0
  134. package/dist/shutdown/shutdown.manager.d.ts +27 -0
  135. package/dist/shutdown/shutdown.manager.d.ts.map +1 -0
  136. package/dist/shutdown/shutdown.manager.js +45 -0
  137. package/dist/shutdown/shutdown.manager.js.map +1 -0
  138. package/dist/utils/index.d.ts +2 -0
  139. package/dist/utils/index.d.ts.map +1 -0
  140. package/dist/utils/index.js +6 -0
  141. package/dist/utils/index.js.map +1 -0
  142. package/dist/utils/unwrap-result.d.ts +11 -0
  143. package/dist/utils/unwrap-result.d.ts.map +1 -0
  144. package/dist/utils/unwrap-result.js +37 -0
  145. package/dist/utils/unwrap-result.js.map +1 -0
  146. package/package.json +14 -25
  147. package/dist/client/jetstream-client.module.d.ts +0 -6
  148. package/dist/client/jetstream-client.module.d.ts.map +0 -1
  149. package/dist/client/jetstream-client.module.js +0 -68
  150. package/dist/client/jetstream-client.module.js.map +0 -1
  151. package/dist/client/jetstream.client-proxy.d.ts +0 -179
  152. package/dist/client/jetstream.client-proxy.d.ts.map +0 -1
  153. package/dist/client/jetstream.client-proxy.js +0 -300
  154. package/dist/client/jetstream.client-proxy.js.map +0 -1
  155. package/dist/client/types/index.d.ts +0 -7
  156. package/dist/client/types/index.d.ts.map +0 -1
  157. package/dist/client/types/index.js.map +0 -1
  158. package/dist/common/connection.provider.d.ts +0 -309
  159. package/dist/common/connection.provider.d.ts.map +0 -1
  160. package/dist/common/connection.provider.js +0 -326
  161. package/dist/common/connection.provider.js.map +0 -1
  162. package/dist/common/enum/service-type.enum.d.ts +0 -5
  163. package/dist/common/enum/service-type.enum.d.ts.map +0 -1
  164. package/dist/common/enum/service-type.enum.js +0 -9
  165. package/dist/common/enum/service-type.enum.js.map +0 -1
  166. package/dist/common/helpers.d.ts +0 -14
  167. package/dist/common/helpers.d.ts.map +0 -1
  168. package/dist/common/helpers.js +0 -21
  169. package/dist/common/helpers.js.map +0 -1
  170. package/dist/common/index.d.ts +0 -2
  171. package/dist/common/index.d.ts.map +0 -1
  172. package/dist/common/index.js +0 -7
  173. package/dist/common/index.js.map +0 -1
  174. package/dist/common/pattern-registry.d.ts +0 -51
  175. package/dist/common/pattern-registry.d.ts.map +0 -1
  176. package/dist/common/pattern-registry.js +0 -86
  177. package/dist/common/pattern-registry.js.map +0 -1
  178. package/dist/common/rpc.context.d.ts +0 -8
  179. package/dist/common/rpc.context.d.ts.map +0 -1
  180. package/dist/common/rpc.context.js +0 -14
  181. package/dist/common/rpc.context.js.map +0 -1
  182. package/dist/common/types/index.d.ts +0 -2
  183. package/dist/common/types/index.d.ts.map +0 -1
  184. package/dist/common/types/index.js +0 -18
  185. package/dist/common/types/index.js.map +0 -1
  186. package/dist/common/types/jetstream-transport.options.d.ts +0 -60
  187. package/dist/common/types/jetstream-transport.options.d.ts.map +0 -1
  188. package/dist/common/types/jetstream-transport.options.js.map +0 -1
  189. package/dist/enum/index.d.ts +0 -16
  190. package/dist/enum/index.d.ts.map +0 -1
  191. package/dist/enum/index.js +0 -21
  192. package/dist/enum/index.js.map +0 -1
  193. package/dist/server/const/index.d.ts +0 -4
  194. package/dist/server/const/index.d.ts.map +0 -1
  195. package/dist/server/const/index.js +0 -96
  196. package/dist/server/const/index.js.map +0 -1
  197. package/dist/server/enum/index.d.ts +0 -5
  198. package/dist/server/enum/index.d.ts.map +0 -1
  199. package/dist/server/enum/index.js +0 -9
  200. package/dist/server/enum/index.js.map +0 -1
  201. package/dist/server/jetstream-server.module.d.ts +0 -157
  202. package/dist/server/jetstream-server.module.d.ts.map +0 -1
  203. package/dist/server/jetstream-server.module.js +0 -375
  204. package/dist/server/jetstream-server.module.js.map +0 -1
  205. package/dist/server/jetstream.strategy.d.ts +0 -150
  206. package/dist/server/jetstream.strategy.d.ts.map +0 -1
  207. package/dist/server/jetstream.strategy.js +0 -192
  208. package/dist/server/jetstream.strategy.js.map +0 -1
  209. package/dist/server/jetstream.transport.d.ts +0 -9
  210. package/dist/server/jetstream.transport.d.ts.map +0 -1
  211. package/dist/server/jetstream.transport.js +0 -26
  212. package/dist/server/jetstream.transport.js.map +0 -1
  213. package/dist/server/providers/consumer.provider.d.ts +0 -226
  214. package/dist/server/providers/consumer.provider.d.ts.map +0 -1
  215. package/dist/server/providers/consumer.provider.js +0 -272
  216. package/dist/server/providers/consumer.provider.js.map +0 -1
  217. package/dist/server/providers/message-routing.provider.d.ts +0 -295
  218. package/dist/server/providers/message-routing.provider.d.ts.map +0 -1
  219. package/dist/server/providers/message-routing.provider.js +0 -420
  220. package/dist/server/providers/message-routing.provider.js.map +0 -1
  221. package/dist/server/providers/message.provider.d.ts +0 -142
  222. package/dist/server/providers/message.provider.d.ts.map +0 -1
  223. package/dist/server/providers/message.provider.js +0 -209
  224. package/dist/server/providers/message.provider.js.map +0 -1
  225. package/dist/server/providers/stream.provider.d.ts +0 -320
  226. package/dist/server/providers/stream.provider.d.ts.map +0 -1
  227. package/dist/server/providers/stream.provider.js +0 -376
  228. package/dist/server/providers/stream.provider.js.map +0 -1
  229. package/dist/server/types/index.d.ts +0 -7
  230. package/dist/server/types/index.d.ts.map +0 -1
  231. package/dist/server/types/index.js.map +0 -1
  232. package/dist/server/types/nats.events-map.d.ts +0 -22
  233. package/dist/server/types/nats.events-map.d.ts.map +0 -1
  234. package/dist/server/types/nats.events-map.js.map +0 -1
package/README.md CHANGED
@@ -1,162 +1,770 @@
1
- # NestJs JetStream Transport
1
+ # @horizon-republic/nestjs-jetstream
2
2
 
3
- A NestJS transport for NATS JetStream with built-in support for **Events** (fire-and-forget) and **Commands** (RPC)
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
  [![npm version](https://img.shields.io/npm/v/@horizon-republic/nestjs-jetstream.svg)](https://www.npmjs.com/package/@horizon-republic/nestjs-jetstream)
7
6
  [![codecov](https://codecov.io/github/HorizonRepublic/nestjs-jetstream/graph/badge.svg?token=40IPSWFMT4)](https://codecov.io/github/HorizonRepublic/nestjs-jetstream)
8
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
8
 
10
- ## Features
11
-
12
- - 🔄 **Full JetStream support**: JetStream used for persistence + Core NATS for low-latency replies in RPC
13
- - 🚀 **Dual messaging patterns**: Events (pub/sub) and Commands (RPC)
14
- - 🎯 **Type-safe**: Full TypeScript support with strict types
15
- - 📦 **Multiple instances**: Run multiple services in a single application
16
- - **High performance**: Optimized for throughput and low latency
17
- - 🛡️ **Reliable**: At-least-once delivery with configurable acknowledgment strategies
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
- # ToDo
37
+ ## Features
20
38
 
21
- - 🔧 **Configurable**: Extensive stream and consumer configuration options
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
- # Quick Start
59
+ **Peer dependencies:**
30
60
 
31
- ## Server (Consumer)
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
- Register the module in your app.module.ts:
70
+ ## Quick Start
34
71
 
35
- ```typescript
36
- import {JetstreamServerModule} from '@horizon-republic/nestjs-jetstream'
72
+ ### 1. Register the module
37
73
 
38
- imports: [
39
- JetstreamServerModule.forRoot({
40
- name: 'my_service', // Unique name for the JetStream service. Will be registered as `my_service__microservice``
41
- servers: ['localhost:4222'], // List of NATS servers to connect to.
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
- Get transport instance in your main.ts:
94
+ ### 2. Connect the transport
47
95
 
48
96
  ```typescript
49
- import {getJetStreamTransportToken, JetstreamTransport} from '@horizon-republic/nestjs-jetstream';
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
- // ... your code here
103
+ const app = await NestFactory.create(AppModule);
104
+
105
+ app.connectMicroservice(
106
+ { strategy: app.get(JetstreamStrategy) },
107
+ { inheritAppConfig: true },
108
+ );
53
109
 
54
- const transport: JetstreamTransport = app.get(getJetStreamTransportToken('my_service'));
110
+ await app.startAllMicroservices();
111
+ await app.listen(3000);
112
+ };
55
113
 
56
- app.connectMicroservice(transport, {inheritAppConfig: true});
114
+ void bootstrap();
115
+ ```
57
116
 
58
- await app.startAllMicroservices();
117
+ ### 3. Define handlers
59
118
 
60
- // ... app.listen() and etc
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
- If everything is set up correctly, you should see the following logs in your console:
137
+ ### 4. Send messages
65
138
 
66
- ```shell
67
- [Nest] 98936 - 11/04/2025, 10:25:59 PM LOG [StreamProvider] Ensure stream requested: my_service__microservice_ev-stream
68
- [Nest] 98936 - 11/04/2025, 10:25:59 PM LOG [StreamProvider] Ensure stream requested: my_service__microservice_cmd-stream
69
- [Nest] 98936 - 11/04/2025, 10:25:59 PM LOG [ConnectionProvider] NATS connection established: localhost:4222
70
- [Nest] 98936 - 11/04/2025, 10:25:59 PM LOG [ConnectionProvider] NATS JetStream manager initialized
71
- [Nest] 98936 - 11/04/2025, 10:25:59 PM DEBUG [StreamProvider] Checking stream existence: my_service__microservice_ev-stream
72
- [Nest] 98936 - 11/04/2025, 10:25:59 PM DEBUG [StreamProvider] Checking stream existence: my_service__microservice_cmd-stream
73
- [Nest] 98936 - 11/04/2025, 10:25:59 PM LOG [StreamProvider] Stream exists, updating: my_service__microservice_ev-stream (subjects: 1)
74
- [Nest] 98936 - 11/04/2025, 10:25:59 PM LOG [StreamProvider] Stream exists, updating: my_service__microservice_cmd-stream (subjects: 1)
75
- [Nest] 98936 - 11/04/2025, 10:25:59 PM DEBUG [ConsumerProvider] Consumer exists: my_service__microservice_cmd-consumer
76
- [Nest] 98936 - 11/04/2025, 10:25:59 PM DEBUG [ConsumerProvider] Consumer exists: my_service__microservice_ev-consumer
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
- Consumer register 2 message handlers and process them independently:
159
+ ## Module Configuration
160
+
161
+ ### forRoot / forRootAsync
80
162
 
81
- - `my_service__microservice_ev-stream` - for events
82
- - `my_service__microservice_cmd-stream` - for commands
163
+ `forRoot()` registers the transport globally. Call it once in your root `AppModule`.
83
164
 
84
- **Message Handlers:**
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
- You can register message handlers for events and commands in the same way as you would do for any other NestJS
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
- import { EventPattern, MessagePattern, Payload } from '@nestjs/microservices';
93
- import { Controller } from '@nestjs/common';
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
- @Controller()
96
- export class AppMicroserviceController {
97
- @EventPattern('user.created')
98
- public handleEvent(@Payload() payload: any) {
99
- console.log('Received event:', payload);
100
- }
101
-
102
- @MessagePattern('user.get')
103
- public handleCommand(@Payload() payload: any) {
104
- console.log('Received command:', payload);
105
-
106
- return {
107
- id: 1,
108
- name: 'John Doe',
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
- ## Client (Publisher)
287
+ ## RPC (Request/Reply)
288
+
289
+ ### Core Mode (Default)
116
290
 
117
- Register the module in your module:
291
+ Uses NATS native `request/reply` for the lowest possible latency.
118
292
 
119
293
  ```typescript
120
- import { JetstreamClientModule } from '@horizon-republic/nestjs-jetstream';
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
- imports: [
123
- JetstreamClientModule.forFeature({
124
- name: 'my_service', // Should match the name of the server module because routing is based on the name
125
- servers: ['localhost:4222'],
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
- **Using the Client:**
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
- import { ClientProxy } from '@nestjs/microservices';
134
- import { Controller, Get, Inject } from '@nestjs/common';
383
+ // Sending use the 'broadcast:' prefix
384
+ this.client.emit('broadcast:config.updated', { key: 'theme', value: 'dark' });
135
385
 
136
- @Controller()
137
- export class AppMicroserviceController {
138
- public constructor(
139
- @Inject('my_service')
140
- private readonly myServiceProxy: ClientProxy,
141
- ) {}
142
-
143
- @Get('send-event')
144
- public sendEvent() {
145
- return this.myServiceProxy.emit('user.created', { someData: 'someData' });
146
- }
147
-
148
- @Get('send-command')
149
- public sendCommand() {
150
- return this.myServiceProxy.send('user.get', { id: 1 });
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
- Success connection will trigger the following log:
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
- ```shell
159
- [Nest] 843 - 11/04/2025, 10:37:37 PM LOG [JetstreamClientProxy] Inbox subscription established: my_service__microservice.PWL9AF1Y7EQKTZ8RSA0V0Y
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 © [Your Name]
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
- ## Support
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)