UNPKG

39.3 kBMarkdownView Raw
1# NATS.js - A [NATS](http://nats.io) client for [Node.Js](https://nodejs.org/en/)
2
3A Node.js client for the [NATS messaging system](https://nats.io).
4
5[![License](https://img.shields.io/badge/Licence-Apache%202.0-blue.svg)](./LICENSE)
6![NATS.js CI](https://github.com/nats-io/nats.js/workflows/NATS.js%20CI/badge.svg)
7[![npm](https://img.shields.io/npm/v/nats.svg)](https://www.npmjs.com/package/nats)
8[![npm](https://img.shields.io/npm/dt/nats.svg)](https://www.npmjs.com/package/nats)
9[![npm](https://img.shields.io/npm/dm/nats.svg)](https://www.npmjs.com/package/nats)
10
11# Installation
12
13```bash
14npm install nats@latest
15```
16
17The nats.js@2.0.0 **is not API compatible** with previous versions of
18nats.js. For a migration guide, please see [the migration guide](migration.md).
19
20## Basics
21
22### Connecting to a nats-server
23
24To connect to a server you use the `connect()` function. It returns a connection
25that you can use to interact with the server. You can customize the behavior of
26the client by specifying many [`ConnectionOptions`](#Connection-Options).
27
28By default, a connection will attempt a connection on`127.0.0.1:4222`. If the
29connection is dropped, the client will attempt to reconnect. You can customize
30the server you want to connect to by specifying `port` (for local connections),
31or full host port on the `servers` option. Note that the `servers` option can be
32a single hostport (a string) or an array of hostports.
33
34The example below will attempt to connect to different servers by specifying
35different `ConnectionOptions`. At least two of them should work if your internet
36is working.
37
38```javascript
39const { connect } = require("nats");
40const servers = [
41 {},
42 { servers: ["demo.nats.io:4442", "demo.nats.io:4222"] },
43 { servers: "demo.nats.io:4443" },
44 { port: 4222 },
45 { servers: "localhost" },
46];
47await servers.forEach(async (v) => {
48 try {
49 const nc = await connect(v);
50 console.log(`connected to ${nc.getServer()}`);
51 // this promise indicates the client closed
52 const done = nc.closed();
53 // do something with the connection
54
55 // close the connection
56 await nc.close();
57 // check if the close was OK
58 const err = await done;
59 if (err) {
60 console.log(`error closing:`, err);
61 }
62 } catch (err) {
63 console.log(`error connecting to ${JSON.stringify(v)}`);
64 }
65});
66```
67
68To disconnect from the nats-server, call `close()` on the connection. A
69connection can also be terminated when an unexpected error happens. For example,
70the server returns a run-time error. In those cases, the client will re-initiate
71a connection.
72
73By default, the client will always attempt to reconnect if the connection is
74closed for a reason other than calling `close()`. To get notified when the
75connection is closed for some reason, await the resolution of the Promise
76returned by `closed()`. If closed resolves to a value, the value is a
77`NatsError` indicating why the connection closed.
78
79### Publish and Subscribe
80
81The basic client operations are `publish` to send messages and `subscribe` to
82receive messages.
83
84Messages are published to a subject. A subject is like a URL with the exception
85that it doesn't specify an actual endpoint. All recipients that have expressed
86interest in a subject will receive messages addressed to that subject (provided
87they have access and permissions to get it). To express interest in a subject,
88you create a `subscription`.
89
90In JavaScript clients (websocket, Deno, or Node) subscriptions work as an async
91iterator - clients simply loop to process messages as they become available.
92
93NATS messages are payload agnostic. Payloads are `Uint8Arrays`. You can easily
94convert to and from JSON or strings by using `JSONCodec` or `StringCodec`, or a
95custom `Codec`.
96
97To cancel a subscription and terminate your interest, you call `unsubscribe()`
98or `drain()` on a subscription. Unsubscribe will typically terminate regardless
99of whether there are messages in flight for the client. Drain ensures that all
100messages that are inflight are processed before canceling the subscription.
101Connections can also be drained as well. Draining a connection closes it, after
102all subscriptions have been drained and all outbound messages have been sent to
103the server.
104
105```javascript
106const { connect, StringCodec } = require("nats");
107
108// to create a connection to a nats-server:
109const nc = await connect({ servers: "demo.nats.io:4222" });
110
111// create a codec
112const sc = StringCodec();
113// create a simple subscriber and iterate over messages
114// matching the subscription
115const sub = nc.subscribe("hello");
116(async () => {
117 for await (const m of sub) {
118 console.log(`[${sub.getProcessed()}]: ${sc.decode(m.data)}`);
119 }
120 console.log("subscription closed");
121})();
122
123nc.publish("hello", sc.encode("world"));
124nc.publish("hello", sc.encode("again"));
125
126// we want to insure that messages that are in flight
127// get processed, so we are going to drain the
128// connection. Drain is the same as close, but makes
129// sure that all messages in flight get seen
130// by the iterator. After calling drain on the connection
131// the connection closes.
132await nc.drain();
133```
134
135### Wildcard Subscriptions
136
137Subjects can be used to organize messages into hierarchies. For example, a
138subject may contain additional information that can be useful in providing a
139context to the message, such as the ID of the client that sent the message, or
140the region where a message originated.
141
142Instead of subscribing to each specific subject, you can create subscriptions
143that have subjects with wildcards. Wildcards match one or more tokens in a
144subject. A token is a string following a period.
145
146All subscriptions are independent. If two different subscriptions match a
147subject, both will get to process the message:
148
149```javascript
150const { connect, StringCodec } = require("nats");
151
152const nc = await connect({ servers: "demo.nats.io:4222" });
153const sc = StringCodec();
154
155// subscriptions can have wildcard subjects
156// the '*' matches any string in the specified token position
157const s1 = nc.subscribe("help.*.system");
158const s2 = nc.subscribe("help.me.*");
159// the '>' matches any tokens in that position or following
160// '>' can only be specified at the end of the subject
161const s3 = nc.subscribe("help.>");
162
163async function printMsgs(s) {
164 let subj = s.getSubject();
165 console.log(`listening for ${subj}`);
166 const c = (13 - subj.length);
167 const pad = "".padEnd(c);
168 for await (const m of s) {
169 console.log(
170 `[${subj}]${pad} #${s.getProcessed()} - ${m.subject} ${
171 m.data ? " " + sc.decode(m.data) : ""
172 }`,
173 );
174 }
175}
176
177printMsgs(s1);
178printMsgs(s2);
179printMsgs(s3);
180
181// don't exit until the client closes
182await nc.closed();
183```
184
185### Services: Request/Reply
186
187Request/Reply is NATS equivalent to an HTTP request. To make requests you
188publish messages as you did before, but also specify a `reply` subject. The
189`reply` subject is where a service will publish your response.
190
191NATS provides syntactic sugar, for publishing requests. The `request()` API will
192generate a reply subject and manage the creation of a subscription under the
193covers. It will also start a timer to ensure that if a response is not received
194within your allotted time, the request fails. The example also illustrates a
195graceful shutdown.
196
197#### Services
198
199Here's an example of a service. It is a bit more complicated than expected
200simply to illustrate not only how to create responses, but how the subject
201itself is used to dispatch different behaviors.
202
203```javascript
204const { connect, StringCodec, Subscription } = require("nats");
205
206// create a connection
207const nc = await connect({ servers: "demo.nats.io" });
208
209// create a codec
210const sc = StringCodec();
211
212// this subscription listens for `time` requests and returns the current time
213const sub = nc.subscribe("time");
214(async (sub: Subscription) => {
215 console.log(`listening for ${sub.getSubject()} requests...`);
216 for await (const m of sub) {
217 if (m.respond(sc.encode(new Date().toISOString()))) {
218 console.info(`[time] handled #${sub.getProcessed()}`);
219 } else {
220 console.log(`[time] #${sub.getProcessed()} ignored - no reply subject`);
221 }
222 }
223 console.log(`subscription ${sub.getSubject()} drained.`);
224})(sub);
225
226// this subscription listens for admin.uptime and admin.stop
227// requests to admin.uptime returns how long the service has been running
228// requests to admin.stop gracefully stop the client by draining
229// the connection
230const started = Date.now();
231const msub = nc.subscribe("admin.*");
232(async (sub) => {
233 console.log(`listening for ${sub.getSubject()} requests [uptime | stop]`);
234 // it would be very good to verify the origin of the request
235 // before implementing something that allows your service to be managed.
236 // NATS can limit which client can send or receive on what subjects.
237 for await (const m of sub) {
238 const chunks = m.subject.split(".");
239 console.info(`[admin] #${sub.getProcessed()} handling ${chunks[1]}`);
240 switch (chunks[1]) {
241 case "uptime":
242 // send the number of millis since up
243 m.respond(sc.encode(`${Date.now() - started}`));
244 break;
245 case "stop": {
246 m.respond(sc.encode(`[admin] #${sub.getProcessed()} stopping....`));
247 // gracefully shutdown
248 nc.drain()
249 .catch((err) => {
250 console.log("error draining", err);
251 });
252 break;
253 }
254 default:
255 console.log(
256 `[admin] #${sub.getProcessed()} ignoring request for ${m.subject}`,
257 );
258 }
259 }
260 console.log(`subscription ${sub.getSubject()} drained.`);
261})(msub);
262
263// wait for the client to close here.
264await nc.closed().then((err) => {
265 let m = `connection to ${nc.getServer()} closed`;
266 if (err) {
267 m = `${m} with an error: ${err.message}`;
268 }
269 console.log(m);
270});
271```
272
273#### Making Requests
274
275Here's a simple example of a client making a simple request from the service
276above:
277
278```javascript
279const { connect, StringCodec } = require("nats");
280
281// create a connection
282const nc = await connect({ servers: "demo.nats.io:4222" });
283
284// create an encoder
285const sc = StringCodec();
286
287// the client makes a request and receives a promise for a message
288// by default the request times out after 1s (1000 millis) and has
289// no payload.
290await nc.request("time", Empty, { timeout: 1000 })
291 .then((m) => {
292 console.log(`got response: ${sc.decode(m.data)}`);
293 })
294 .catch((err) => {
295 console.log(`problem with request: ${err.message}`);
296 });
297
298await nc.close();
299```
300
301### Queue Groups
302
303Queue groups allow scaling of services horizontally. Subscriptions for members
304of a queue group are treated as a single service. When you send a message to a
305queue group subscription, only a single client in a queue group will receive it.
306
307There can be any number of queue groups. Each group is treated as its own
308independent unit. Note that non-queue subscriptions are also independent of
309subscriptions in a queue group.
310
311```javascript
312const {
313 connect,
314 NatsConnection,
315 StringCodec,
316} = require("nats");
317
318async function createService(
319 name,
320 count = 1,
321 queue = ""
322): Promise {
323 const conns = [];
324 for (let i = 1; i <= count; i++) {
325 const n = queue ? `${name}-${i}` : name;
326 const nc = await connect(
327 { servers: "demo.nats.io:4222", name: `${n}` },
328 );
329 nc.closed()
330 .then((err) => {
331 if (err) {
332 console.error(
333 `service ${n} exited because of error: ${err.message}`,
334 );
335 }
336 });
337 // create a subscription - note the option for a queue, if set
338 // any client with the same queue will be a member of the group.
339 const sub = nc.subscribe("echo", { queue: queue });
340 const _ = handleRequest(n, sub);
341 console.log(`${nc.options.name} is listening for 'echo' requests...`);
342 conns.push(nc);
343 }
344 return conns;
345}
346
347const sc = StringCodec();
348
349// simple handler for service requests
350async function handleRequest(name, s) {
351 const p = 12 - name.length;
352 const pad = "".padEnd(p);
353 for await (const m of s) {
354 // respond returns true if the message had a reply subject, thus it could respond
355 if (m.respond(m.data)) {
356 console.log(
357 `[${name}]:${pad} #${s.getProcessed()} echoed ${sc.decode(m.data)}`,
358 );
359 } else {
360 console.log(
361 `[${name}]:${pad} #${s.getProcessed()} ignoring request - no reply subject`,
362 );
363 }
364 }
365}
366
367// let's create two queue groups and a standalone subscriber
368const conns = [];
369conns.push(...await createService("echo", 3, "echo"));
370conns.push(...await createService("other-echo", 2, "other-echo"));
371conns.push(...await createService("standalone"));
372
373const a: Promise<void | Error>[] = [];
374conns.forEach((c) => {
375 a.push(c.closed());
376});
377await Promise.all(a);
378```
379
380Run it and publish a request to the subject `echo` to see what happens.
381
382## Advanced Usage
383
384### Headers
385
386NATS headers are similar to HTTP headers. Headers are enabled automatically if
387the server supports them. Note that if you publish a message using headers, and
388the server doesn't support them, an Error is thrown. Also note that even if you
389are publishing a message with a header, it is possible for the recipient to not
390support them.
391
392```javascript
393const { connect, createInbox, Empty, headers } = require("nats");
394
395const nc = await connect(
396 {
397 servers: `demo.nats.io`,
398 },
399);
400
401const subj = createInbox();
402const sub = nc.subscribe(subj);
403(async () => {
404 for await (const m of sub) {
405 if (m.headers) {
406 for (const [key, value] of m.headers) {
407 console.log(`${key}=${value}`);
408 }
409 // reading/setting a header is not case sensitive
410 console.log("id", m.headers.get("id"));
411 }
412 }
413})().then();
414
415// headers always have their names turned into a canonical mime header key
416// header names can be any printable ASCII character with the exception of `:`.
417// header values can be any ASCII character except `\r` or `\n`.
418// see https://www.ietf.org/rfc/rfc822.txt
419const h = headers();
420h.append("id", "123456");
421h.append("unix_time", Date.now().toString());
422nc.publish(subj, Empty, { headers: h });
423
424await nc.flush();
425await nc.close();
426```
427
428### No Responders
429
430Requests can fail for many reasons. A common reason for a failure is the lack of
431interest in the subject. Typically, these surface as a timeout error. If the
432server is enabled to use headers, it will also enable a `no responders` feature.
433If you send a request for which there's no interest, the request will be
434immediately rejected:
435
436```javascript
437const nc = await connect({
438 servers: `demo.nats.io`,
439});
440
441try {
442 const m = await nc.request("hello.world");
443 console.log(m.data);
444} catch (err) {
445 switch (err.code) {
446 case ErrorCode.NoResponders:
447 console.log("no one is listening to 'hello.world'");
448 break;
449 case ErrorCode.Timeout:
450 console.log("someone is listening but didn't respond");
451 break;
452 default:
453 console.log("request failed", err);
454 }
455}
456
457await nc.close();
458```
459
460### Authentication
461
462NATS supports many different forms of authentication:
463
464- username/password
465- token
466- NKEYS
467- client certificates
468- JWTs
469
470For user/password and token authentication, you can simply provide them as
471`ConnectionOptions` - see `user`, `pass`, `token`. Internally these mechanisms
472are implemented as an `Authenticator`. An `Authenticator` is simply a function
473that handles the type of authentication specified.
474
475Setting the `user`/`pass` or `token` options, simply initializes an
476`Authenticator` and sets the username/password.
477
478```typescript
479// if the connection requires authentication, provide `user` and `pass` or
480// `token` options in the NatsConnectionOptions
481const { connect } = require("nats");
482
483const nc1 = await connect({
484 servers: "127.0.0.1:4222",
485 user: "jenny",
486 pass: "867-5309",
487});
488const nc2 = await connect({ port: 4222, token: "t0pS3cret!" });
489```
490
491#### Authenticators
492
493NKEYs and JWT authentication are more complex, as they cryptographically respond
494to a server challenge.
495
496Because NKEY and JWT authentication may require reading data from a file or an
497HTTP cookie, these forms of authentication will require a bit more from the
498developer to activate them. However, the work is related to accessing these
499resources varies depending on the platform.
500
501After the credential artifacts are read, you can use one of these functions to
502create the authenticator. You then simply assign it to the `authenticator`
503property of the `ConnectionOptions`:
504
505- `nkeyAuthenticator(seed?: Uint8Array | (() => Uint8Array)): Authenticator`
506- `jwtAuthenticator(jwt: string | (() => string), seed?: Uint8Array | (()=> Uint8Array)): Authenticator`
507- `credsAuthenticator(creds: Uint8Array): Authenticator`
508
509The first two options provide the ability to specify functions that return the
510desired value. This enables dynamic environments such as a browser where values
511accessed by fetching a value from a cookie.
512
513Here's an example:
514
515```javascript
516// read the creds file as necessary, in the case it
517// is part of the code for illustration purposes
518const creds = `-----BEGIN NATS USER JWT-----
519 eyJ0eXAiOiJqdSDJB....
520 ------END NATS USER JWT------
521
522************************* IMPORTANT *************************
523 NKEY Seed printed below can be used sign and prove identity.
524 NKEYs are sensitive and should be treated as secrets.
525
526 -----BEGIN USER NKEY SEED-----
527 SUAIBDPBAUTW....
528 ------END USER NKEY SEED------
529`;
530
531const nc = await connect(
532 {
533 port: 4222,
534 authenticator: credsAuthenticator(new TextEncoder().encode(creds)),
535 },
536);
537```
538
539The node client supports the ability to verify the tls connection if client
540certificates are specified as ConnectionOptions:
541
542```javascript
543tlsOptions = {
544 keyFile: "./test/certs/client-key.pem",
545 certFile: "./test/certs/client-cert.pem",
546 caFile: "./test/certs/ca.pem"
547};
548nc = await connect({ tls: tlsOptions });
549```
550
551### Flush
552
553Flush sends a PING to the server. When the server responds with PONG you are
554guaranteed that all pending data was sent and received by the server. Note
555`ping()` effectively adds a server round-trip. All NATS clients handle their
556buffering optimally, so `ping(): Promise<void>` shouldn't be used except in
557cases where you are writing some sort of test.
558
559```javascript
560nc.publish("foo");
561nc.publish("bar");
562await nc.flush();
563```
564
565### `PublishOptions`
566
567When you publish a message you can specify some options:
568
569- `reply` - this is a subject to receive a reply (you must set up a subscription)
570 before you publish.
571- `headers` - a set of headers to decorate the message.
572
573### `SubscriptionOptions`
574
575You can specify several options when creating a subscription:
576
577- `max`: maximum number of messages to receive - auto unsubscribe
578- `timeout`: how long to wait for the first message
579- `queue`: the [queue group](#Queue-Groups) name the subscriber belongs to
580- `callback`: a function with the signature
581 `(err: NatsError|null, msg: Msg) => void;` that should be used for handling
582 the message. Subscriptions with callbacks are NOT iterators.
583
584#### Auto Unsubscribe
585
586```javascript
587// subscriptions can auto unsubscribe after a certain number of messages
588nc.subscribe("foo", { max: 10 });
589```
590
591#### Timeout Subscriptions
592
593```javascript
594// create subscription with a timeout, if no message arrives
595// within the timeout, the function running the iterator with
596// reject - depending on how you code it, you may need a
597// try/catch block.
598const sub = nc.subscribe("hello", { timeout: 1000 });
599(async () => {
600 for await (const m of sub) {
601 }
602})().catch((err) => {
603 if (err.code === ErrorCode.Timeout) {
604 console.log(`sub timed out!`);
605 } else {
606 console.log(`sub iterator got an error!`);
607 }
608});
609```
610
611### `RequestOptions`
612
613When making a request, there are several options you can pass:
614
615- `timeout`: how long to wait for the response
616- `headers`: optional headers to include with the message
617- `noMux`: create a new subscription to handle the request. Normally a shared
618 subscription is used to receive response messages.
619- `reply`: optional subject where the reply should be sent.
620
621#### `noMux` and `reply`
622
623Under the hood, the request API simply uses a wildcard subscription to handle
624all requests you send.
625
626In some cases, the default subscription strategy doesn't work correctly. For
627example, a client may be constrained by the subjects where it can receive
628replies.
629
630When `noMux` is set to `true`, the client will create a normal subscription for
631receiving the response to a generated inbox subject before the request is
632published. The `reply` option can be used to override the generated inbox
633subject with an application provided one. Note that setting `reply` requires
634`noMux` to be `true`:
635
636```typescript
637const m = await nc.request(
638 "q",
639 Empty,
640 { reply: "bar", noMux: true, timeout: 1000 },
641);
642```
643
644### Draining Connections and Subscriptions
645
646Draining provides for a graceful way to unsubscribe or close a connection
647without losing messages that have already been dispatched to the client.
648
649You can drain a subscription or all subscriptions in a connection.
650
651When you drain a subscription, the client sends an `unsubscribe` protocol
652message to the server followed by a `flush`. The subscription handler is only
653removed after the server responds. Thus, all pending messages for the
654subscription have been processed.
655
656Draining a connection, drains all subscriptions. However, when you drain the
657connection it becomes impossible to make new subscriptions or send new requests.
658After the last subscription is drained, it also becomes impossible to publish a
659message. These restrictions do not exist when just draining a subscription.
660
661### Lifecycle/Informational Events
662
663Clients can get notification on various event types:
664
665- `Events.Disconnect`
666- `Events.Reconnect`
667- `Events.Update`
668- `Events.LDM`
669- `Events.Error`
670
671The first two fire when a client disconnects and reconnects respectively. The
672payload will be the server where the event took place.
673
674The `UPDATE` event notifies whenever the client receives a cluster configuration
675update. The `ServersChanged` interface provides two arrays: `added` and
676`deleted` listing the servers that were added or removed.
677
678The `LDM` event notifies that the current server has signaled that it is running
679in _Lame Duck Mode_ and will evict clients. Depending on the server
680configuration policy, the client may want to initiate an ordered shutdown, and
681initiate a new connection to a different server in the cluster.
682
683The `ERROR` event notifies you of async errors that couldn't be routed in a more
684precise way to your client. For example, permission errors for a subscription or
685request, will properly be reported by the subscription or request. However,
686permission errors on publish will be reported via the status mechanism.
687
688```javascript
689const nc = await connect();
690(async () => {
691 console.info(`connected ${nc.getServer()}`);
692 for await (const s of nc.status()) {
693 console.info(`${s.type}: ${s.data}`);
694 }
695})().then();
696
697nc.closed()
698 .then((err) => {
699 console.log(
700 `connection closed ${err ? " with error: " + err.message : ""}`,
701 );
702 });
703```
704
705Be aware that when a client closes, you will need to wait for the `closed()`
706promise to resolve. When it resolves, the client is done and will not reconnect.
707
708### Async vs. Callbacks
709
710Previous versions of the JavaScript NATS clients specified callbacks for message
711processing. This required complex handling logic when a service required
712coordination of operations. Callbacks are an inversion of control anti-pattern.
713
714The async APIs trivialize complex coordination and makes your code easier to
715maintain. With that said, there are some implications:
716
717- Async subscriptions buffer inbound messages.
718- Subscription processing delays until the runtime executes the promise related
719 microtasks at the end of an event loop.
720
721In a traditional callback-based library, I/O happens after all data yielded by a
722read in the current event loop completes processing. This means that callbacks
723are invoked as part of processing. With async, the processing is queued in a
724microtask queue. At the end of the event loop, the runtime processes the
725microtasks, which in turn resumes your functions. As expected, this increases
726latency, but also provides additional liveliness.
727
728To reduce async latency, the NATS client allows processing a subscription in the
729same event loop that dispatched the message. Simply specify a `callback` in the
730subscription options. The signature for a callback is
731`(err: (NatsError|null), msg: Msg) => void`. When specified, the subscription
732iterator will never yield a message, as the callback will intercept all
733messages.
734
735Note that `callback` likely shouldn't even be documented, as likely it is a
736workaround to an underlying application problem where you should be considering
737a different strategy to horizontally scale your application, or reduce pressure
738on the clients, such as using queue workers, or more explicitly targeting
739messages. With that said, there are many situations where using callbacks can be
740more performant or appropriate.
741
742## Connection Options
743
744The following is the list of connection options and default values.
745
746| Option | Default | Description |
747| ----------------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
748| `authenticator` | none | Specifies the authenticator function that sets the client credentials. |
749| `debug` | `false` | If `true`, the client prints protocol interactions to the console. Useful for debugging. |
750| `ignoreClusterUpdates` | `false` | If `true` the client will ignore any cluster updates provided by the server. |
751| `inboxPrefix` | `"_INBOX"` | Sets de prefix for automatically created inboxes - `createInbox(prefix)` |
752| `maxPingOut` | `2` | Max number of pings the client will allow unanswered before raising a stale connection error. |
753| `maxReconnectAttempts` | `10` | Sets the maximum number of reconnect attempts. The value of `-1` specifies no limit. |
754| `name` | | Optional client name - recommended to be set to a unique client name. |
755| `noEcho` | `false` | Subscriptions receive messages published by the client. Requires server support (1.2.0). If set to true, and the server does not support the feature, an error with code `NO_ECHO_NOT_SUPPORTED` is emitted, and the connection is aborted. Note that it is possible for this error to be emitted on reconnect when the server reconnects to a server that does not support the feature. |
756| `noRandomize` | `false` | If set, the order of user-specified servers is randomized. |
757| `pass` | | Sets the password for a connection. |
758| `pedantic` | `false` | Turns on strict subject format checks. |
759| `pingInterval` | `120000` | Number of milliseconds between client-sent pings. |
760| `port` | `4222` | Port to connect to (only used if `servers` is not specified). |
761| `reconnect` | `true` | If false, client will not attempt reconnecting. |
762| `reconnectDelayHandler` | Generated function | A function that returns the number of millis to wait before the next connection to a server it connected to `()=>number`. |
763| `reconnectJitter` | `100` | Number of millis to randomize after `reconnectTimeWait`. |
764| `reconnectJitterTLS` | `1000` | Number of millis to randomize after `reconnectTimeWait` when TLS options are specified. |
765| `reconnectTimeWait` | `2000` | If disconnected, the client will wait the specified number of milliseconds between reconnect attempts. |
766| `servers` | `"localhost:4222"` | String or Array of hostport for servers. |
767| `timeout` | 20000 | Number of milliseconds the client will wait for a connection to be established. If it fails it will emit a `connection_timeout` event with a NatsError that provides the hostport of the server where the connection was attempted. |
768| `tls` | TlsOptions | A configuration object for requiring a TLS connection (not applicable to nats.ws). |
769| `token` | | Sets a authorization token for a connection. |
770| `user` | | Sets the username for a connection. |
771| `verbose` | `false` | Turns on `+OK` protocol acknowledgements. |
772| `waitOnFirstConnect` | `false` | If `true` the client will fall back to a reconnect mode if it fails its first connection attempt. |
773
774### TlsOptions
775
776| Option | Default | Description |
777| ---------- | ------- | ---------------------------- |
778| `caFile` | | CA certificate filepath |
779| `ca` | | CA certificate |
780| `certFile` | | Client certificate file path |
781| `cert` | | Client certificate |
782| `keyFile` | | Client key file path |
783| `key` | | Client key |
784
785In some Node and Deno clients, having the option set to an empty option,
786requires the client have a secured connection.
787
788### Jitter
789
790The settings `reconnectTimeWait`, `reconnectJitter`, `reconnectJitterTLS`,
791`reconnectDelayHandler` are all related. They control how long before the NATS
792client attempts to reconnect to a server it has previously connected.
793
794The intention of the settings is to spread out the number of clients attempting
795to reconnect to a server over a period of time, and thus preventing a
796["Thundering Herd"](https://docs.nats.io/developing-with-nats/reconnect/random).
797
798The relationship between these are:
799
800- If `reconnectDelayHandler` is specified, the client will wait the value
801 returned by this function. No other value will be taken into account.
802- If the client specified TLS options, the client will generate a number between
803 0 and `reconnectJitterTLS` and add it to `reconnectTimeWait`.
804- If the client didn't specify TLS options, the client will generate a number
805 between 0 and `reconnectJitter` and add it to `reconnectTimeWait`.
806
807## JetStream
808
809[Support for JetStream is built-in](https://github.com/nats-io/nats.deno/blob/main/jetstream.md).
810However, the JetStream API extensions are still in beta. Feel free to use them.
811The client will emit a console message when either `nc.jetstream()` or
812`nc.jetstreamManager()` apis are used to remind you they are in beta.
813
814## Contributing
815
816The library shares client functionality with
817[NATS.deno](https://github.com/nats-io/nats.deno). This means that both the
818NATS.deno and NATS.js use the same exact code base, only differing on the
819implementation of the `Transport`. This strategy greatly reduces the amount of
820work required to develop and maintain the clients, as well as provide a
821completely compatible API across all clients.
822
823Currently, the base client implementation is the deno implementation. You can
824take a look at it
825[here](https://github.com/nats-io/nats.deno/tree/main/nats-base-client).
826
827## Supported Node Versions
828
829Our support policy for Nodejs versions follows
830[Nodejs release support](https://github.com/nodejs/Release). We will support and
831build node-nats on even-numbered Nodejs versions that are current or in LTS.