npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@provide/nats.ws

v1.0.6

Published

NATS websocket client

Readme

NATS - Websocket Javascript Client

A websocket client for the NATS messaging system.

license Travis branch Coveralls github branch npm npm

Installation

npm install nats.ws

Ws-nats requires a websocket proxy, if the NATS server requires LTS, the websocket must be a secure websocket.

Basic Usage

nats.ws supports Promises, depending on the browser/runtime environment you can also use async-await constructs.

Load the library:

<script src='./nats.js'></script>

In another script block, reference the 'nats' global:

// create a connection
const nc = await nats.connect({ url: 'ws://localhost:8080', payload: nats.Payload.STRING })

// simple publisher
nc.publish('hello', 'nats')

// simple subscriber, if the message has a reply subject
// send a reply
const sub = await nc.subscribe('help', (msg) => {
  if (msg.reply) {
    nc.publish(msg.reply, `I can help ${msg.data}`)
  }
})

// unsubscribe
sub.unsubscribe()

// request data - requests only receive one message
// to receive multiple messages, create a subscription
const msg = await nc.request('help', 1000, 'nats request')
console.log(msg.data)

// publishing a request, is similar to publishing. You must have
// a subscription ready to handle the reply subject. Requests
// sent this way can get multiple replies
nc.publish('help', '', 'replysubject')


// close the connection
nc.close()

Wildcard Subscriptions

// the `*` matches any string in the subject token
const sub = await nc.subscribe('help.*.system', (msg) => {
    if (msg.reply) {
        nc.publish(msg.reply, `I can help ${msg.data}`)
    }
})
sub.unsubscribe()

const sub2 = await nc.subscribe('help.me.*', (msg) => {
  if (msg.reply) {
    nc.publish(msg.reply, `I can help ${msg.data}`)
  }
})

// the `>` matches any tokens, can only be at the last token
const sub3 = await nc.subscribe('help.>', (msg) => {
  if (msg.reply) {
    nc.publish(msg.reply, `I can help ${msg.data}`)
  }
})

Queue Groups

// All subscriptions with the same queue name form a queue group.
// The server will select a single subscriber in each queue group
// matching the subscription to receive the message.
const qsub = await nc.subscribe('urgent.help', (msg) => {
  if (msg.reply) {
     nc.publish(msg.reply, `I can help ${msg.data}`)
  }
}, {queue: "urgent"})

Authentication

// if the websocket server requires authentication, 
// provide it in the URL. NATS credentials are specified
// in the `user`, `pass` or `token` options in the ConnectionOptions

let nc = nats.connect({url: "ws://wsuser:wsuserpass@localhost:8080", user: "me", pass: "secret"})
let nc1 = nats.connect({url: "ws://localhost:8080", user: "jenny", token: "867-5309"})
let nc3 = nats.connect({url: "ws://localhost:8080", token: "t0pS3cret!"})

Advanced Usage

Flush

// flush does a round trip to the server. When it
// returns the the server saw it
await nc.flush()

// or with a custom callback
nc.flush(()=>{
  console.log('sent!')
});

// or publish a few things, and wait for the flush
await nc.publish('foo').publish('bar').flush()

Auto unsubscribe

// subscriptions can auto unsubscribe after a certain number of messages
const sub = await nc.subscribe('foo', ()=> {}, {max:10})

// the number can be changed or set afterwards
// if the number is less than the number of received
// messages it cancels immediately
let next = sub.getReceived() + 1
sub.unsubscribe(next)

Timeout Subscriptions

// subscriptions can specify attach a timeout
// timeout will clear with first message
const sub = await nc.subscribe('foo', ()=> {})
sub.setTimeout(300, ()=> {
  console.log('no messages received')
})

// if 10 messages are not received, timeout fires
const sub = await nc.subscribe('foo', ()=> {}, {max:10})
sub.setTimeout(300, ()=> {
    console.log(`got ${sub.getReceived()} messages. Was expecting 10`)
})

// timeout can be cancelled
sub.clearTimeout()

Error Handling

// when server returns an error, you are notified asynchronously
nc.addEventListener('error', (ex)=> {
  console.log('server sent error: ', ex)
});

// when disconnected from the server, the 'close' event is sent
nc.addEventListener('close', ()=> {
  console.log('the connection closed')
})

NATS in the Browser

Here's an example (check examples/chat.html for the latest version) of a chat application using ws-nats.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ws-nats chat</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
          crossorigin="anonymous">
</head>
<!-- when the browser exits, we publish a message -->
<body onunload="exiting()">

<!-- a form for entering messages -->
<div class="container">
    <h1>ws-nats chat</h1>
    <input type="text" class="form-control" id="data" placeholder="Message" autocomplete="off"><br/>
    <button id="send" onclick="send()" class="btn btn-primary">Send</button>
</div>
<br/>

<!-- a place to record messages -->
<div id="chats" class="container"></div>

<!-- load the nats library -->
<script src="../nats.js"></script>

<script>
const Payload = nats.Payload
const me = Date.now()

// create a connection, and register listeners
const init = async function () {
  // if the connection doesn't resolve, an exception is thrown
  // a real app would allow configuring the URL
  const conn = await nats.connect({ url: '{{WSURL}}', payload: Payload.JSON })

  // handle errors sent by the gnatsd - permissions errors, etc.
  conn.addEventListener('error', (ex) => {
    addEntry(`Received error from NATS: ${ex}`)
  })

  // handle connection to the server is closed - should disable the ui
  conn.addEventListener('close', () => {
    addEntry('NATS connection closed')
  })

  // the chat application listens for messages sent under the subject 'chat'
  conn.subscribe('chat', (msg) => {
    addEntry(msg.data.id === me ? `(me): ${msg.data.m}` : `(${msg.data.id}): ${msg.data.m}`)
  })

  // when a new browser joins, the joining browser publishes an 'enter' message
  conn.subscribe('enter', (msg) => {
    if (msg.data.id !== me) {
      addEntry(`${msg.data.id} entered.`)
    }
  })

  // when a browser closes, the leaving browser publishes an 'exit' message
  conn.subscribe('exit', (msg) => {
    if (msg.data.id !== me) {
      addEntry(`${msg.data.id} exited.`)
    }
  })

  // we connected, and we publish our enter message
  conn.publish('enter', { id: me })
  return conn
}

init().then(conn => {
  window.nc = conn
}).catch(ex => {
  addEntry(`Error connecting to NATS: ${ex}`)
})

// this is the input field
let input = document.getElementById('data')

// add a listener to detect edits. If they hit Enter, we publish it
input.addEventListener('keyup', (e) => {
  if (e.key === 'Enter') {
    document.getElementById('send').click()
  } else {
    e.preventDefault()
  }
})

// send a message if user typed one
function send () {
  input = document.getElementById('data')
  const m = input.value
  if (m !== '' && window.nc) {
    window.nc.publish('chat', { id: me, m: m })
    input.value = ''
  }
  return false
}

// send the exit message
function exiting () {
  if (window.nc) {
    window.nc.publish('exit', { id: me })
  }
}

// add an entry to the document
function addEntry (s) {
  const p = document.createElement('pre')
  p.appendChild(document.createTextNode(s))
  document.getElementById('chats').appendChild(p)
}
</script>
</body>
</html>