# nes

> WebSocket adapter plugin for hapi routes

Latest version **10.0.2** (published 2019-03-05) · BSD-3-Clause license · 0 weekly downloads

> **Deprecated.** This package is deprecated.

## Install

```sh
npm install nes
pnpm add nes
yarn add nes
bun add nes
```

## Health

**Score 10/100 (F)** — status: deprecated.

Negative: deprecated.

## Facts

| | |
|---|---|
| Version | 10.0.2 |
| Published | 2019-03-05 |
| First published | 2015-09-01 |
| Weekly downloads | 0 |
| License | BSD-3-Clause |
| TypeScript types | separate (@types/nes) |
| Module format | CommonJS |
| Dependencies | 9 |
| Unpacked size | 76.6 KB |
| Known vulnerabilities | 0 (+2 in 2 direct dependencies) |
| Install scripts | no |
| GitHub stars | 502 |
| Maintainers | hueniverse, marsup, mtharrison, nlf, wyatt |
| Keywords | hapi, plugin, websocket |

## Links

- npm: https://www.npmjs.com/package/nes
- Repository: https://github.com/hapijs/nes
- Homepage: https://github.com/hapijs/nes#readme
- Issues: https://github.com/hapijs/nes/issues
- npm.io page: https://npm.io/package/nes

## Dependencies (9)

- [ws](https://npm.io/package/ws.md) 6.x.x
- [joi](https://npm.io/package/joi.md) 14.x.x
- [boom](https://npm.io/package/boom.md) 7.x.x
- [call](https://npm.io/package/call.md) 5.x.x
- [hoek](https://npm.io/package/hoek.md) 6.x.x
- [iron](https://npm.io/package/iron.md) 5.x.x
- [bounce](https://npm.io/package/bounce.md) 1.x.x
- [teamwork](https://npm.io/package/teamwork.md) 3.x.x
- [cryptiles](https://npm.io/package/cryptiles.md) 4.x.x

## Alternatives

- [@opentelemetry/exporter-zipkin](https://npm.io/package/@opentelemetry/exporter-zipkin.md) — 14.8M weekly downloads
- [pusher-js](https://npm.io/package/pusher-js.md) — 2.0M weekly downloads
- [browserify](https://npm.io/package/browserify.md) — 1.7M weekly downloads
- [sqs-consumer](https://npm.io/package/sqs-consumer.md) — 1.7M weekly downloads
- [@sanity/eventsource](https://npm.io/package/@sanity/eventsource.md) — 930.8K weekly downloads

## Recent versions

- 10.0.2 (latest) — 2019-03-05
- 6.5.2 (lts) — 2017-12-18
- 6.5.1 (legacy) — 2017-11-13
- 10.0.1 — 2019-03-04
- 10.0.0 — 2019-01-18
- 9.1.0 — 2018-11-24
- 9.0.2 — 2018-11-11
- 9.0.1 — 2018-07-02
- 9.0.0 — 2018-06-11
- 8.1.0 — 2018-05-03
- 8.0.1 — 2018-04-12
- 8.0.0 — 2018-03-20
- 7.2.0 — 2018-03-15
- 7.1.0 — 2018-03-12
- 7.0.4 — 2018-03-08
- … 58 more at https://npm.io/package/nes/versions

## README

<img src="https://raw.github.com/hapijs/nes/master/images/nes.png" />

**nes** adds native WebSocket support to [**hapi**](https://github.com/hapijs/hapi)-based application
servers. Instead of treating the WebSocket connections as a separate platform with its own security
and application context, **nes** builds on top of the existing **hapi** architecture to provide a
flexible and organic extension.

Protocol version: 2.4.x (different from module version)

[![Build Status](https://secure.travis-ci.org/hapijs/nes.svg)](http://travis-ci.org/hapijs/nes)

Lead Maintainer - [Matt Harrison](https://github.com/mtharrison)

- [API](#api)
- [Protocol](#protocol)
- [Examples](#examples)
    - [Route invocation](#route-invocation)
    - [Subscriptions](#subscriptions)
    - [Broadcast](#broadcast)
    - [Route authentication](#route-authentication)
    - [Subscription filter](#subscription-filter)
- [Browser Client](#browser-client)

## API

The full client and server API is available in the [API documentation](https://github.com/hapijs/nes/blob/master/API.md).

## Protocol

The **nes** protocol is described in the [Protocol documentation](https://github.com/hapijs/nes/blob/master/PROTOCOL.md).

## Examples

### Route invocation

#### Server

```js
const Hapi = require('hapi');
const Nes = require('nes');

const server = new Hapi.Server();

const start = async () => {

    await server.register(Nes);
    server.route({
        method: 'GET',
        path: '/h',
        config: {
            id: 'hello',
            handler: (request, h) => {

                return 'world!';
            }
        }
    });

    await server.start();
};

start();
```

#### Client

```js
const Nes = require('nes');

var client = new Nes.Client('ws://localhost');

const start = async () => {

    await client.connect();
    const payload = await client.request('hello');  // Can also request '/h'
    // payload -> 'world!'
};

start();
```

### Subscriptions

#### Server

```js
const Hapi = require('hapi');
const Nes = require('nes');

const server = new Hapi.Server();

const start = async () => {

    await server.register(Nes);
    server.subscription('/item/{id}');
    await server.start();
    server.publish('/item/5', { id: 5, status: 'complete' });
    server.publish('/item/6', { id: 6, status: 'initial' });
};

start();
```

#### Client

```js
const Nes = require('nes');

const client = new Nes.Client('ws://localhost');
const start = async () => {

    await client.connect();
    const handler = (update, flags) => {

        // update -> { id: 5, status: 'complete' }
        // Second publish is not received (doesn't match)
    };

    client.subscribe('/item/5', handler);
};

start();
```

### Broadcast

#### Server

```js
const Hapi = require('hapi');
const Nes = require('nes');

const server = new Hapi.Server();

const start = async () => {

    await server.register(Nes);
    await server.start();
    server.broadcast('welcome!');
};

start();
```

#### Client

```js
const Nes = require('nes');

const client = new Nes.Client('ws://localhost');
const start = async () => {

    await client.connect();
    client.onUpdate = (update) => {

        // update -> 'welcome!'
    };
};

start();
```

### Route authentication

#### Server

```js
const Hapi = require('hapi');
const Basic = require('hapi-auth-basic');
const Bcrypt = require('bcrypt');
const Nes = require('nes');

const server = new Hapi.Server();

const start = async () => {

    await server.register([Basic, Nes]);

    // Set up HTTP Basic authentication

    const users = {
        john: {
            username: 'john',
            password: '$2a$10$iqJSHD.BGr0E2IxQwYgJmeP3NvhPrXAeLSaGCj6IR/XU5QtjVu5Tm',   // 'secret'
            name: 'John Doe',
            id: '2133d32a'
        }
    };

    const validate = async (request, username, password) => {

        const user = users[username];
        if (!user) {
            return { isValid: false };
        }

        const isValid = await Bcrypt.compare(password, user.password);
        const  credentials = { id: user.id, name: user.name };
        return { isValid, credentials };
    };

    server.auth.strategy('simple', 'basic', { validate });

    // Configure route with authentication

    server.route({
        method: 'GET',
        path: '/h',
        config: {
            id: 'hello',
            handler: (request, h) => {

                return `Hello ${request.auth.credentials.name}`;
            }
        }
    });

    await server.start();
};

start();
```

#### Client

```js
const Nes = require('nes');

const client = new Nes.Client('ws://localhost');
const start = async () => {

    await client.connect({ auth: { headers: { authorization: 'Basic am9objpzZWNyZXQ=' } } });
    const payload = await client.request('hello')  // Can also request '/h'
    // payload -> 'Hello John Doe'
};

start();
```

### Subscription filter

#### Server

```js
const Hapi = require('hapi');
const Basic = require('hapi-auth-basic');
const Bcrypt = require('bcrypt');
const Nes = require('nes');

const server = new Hapi.Server();

const start = async () => {

    await server.register([Basic, Nes]);

    // Set up HTTP Basic authentication

    const users = {
        john: {
            username: 'john',
            password: '$2a$10$iqJSHD.BGr0E2IxQwYgJmeP3NvhPrXAeLSaGCj6IR/XU5QtjVu5Tm',   // 'secret'
            name: 'John Doe',
            id: '2133d32a'
        }
    };

    const validate = async (request, username, password) => {

        const user = users[username];
        if (!user) {
            return { isValid: false };
        }

        const isValid = await Bcrypt.compare(password, user.password);
        const  credentials = { id: user.id, name: user.name };
        return { isValid, credentials };
    };

    server.auth.strategy('simple', 'basic', 'required', { validate });

    // Set up subscription

    server.subscription('/items', {
        filter: (path, message, options) => {

            return (message.updater !== options.credentials.username);
        }
    });

    await server.start();
    server.publish('/items', { id: 5, status: 'complete', updater: 'john' });
    server.publish('/items', { id: 6, status: 'initial', updater: 'steve' });
};

start();
```

#### Client

```js
const Nes = require('nes');

const client = new Nes.Client('ws://localhost');

// Authenticate as 'john'

const start = async () => {

    await client.connect({ auth: { headers: { authorization: 'Basic am9objpzZWNyZXQ=' } } });
    const handler = (err, update) => {

        // First publish is not received (filtered due to updater key)
        // update -> { id: 6, status: 'initial', updater: 'steve' }
    };

    client.subscribe('/items', handler);
};

start();
```

### Browser Client

When you `require('nes')` it loads the full module and adds a lot of extra code that is not needed
for the browser. The browser will only need the **nes** client. If you are using CommonJS you can
load the client with `require('nes/client')`.

---
_Source: https://npm.io/package/nes · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
