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

@webprotocol/nwep

v0.2.5

Published

@webprotocol/nwep ==================

Readme

@webprotocol/nwep

Node.js bindings for quiche-nwep, providing QUIC transport and NWEP (New Web Exchange Protocol) support.

Installation

npm install @webprotocol/nwep

Official High-Level Packages

For most use cases, we recommend using one of the official high-level packages built on top of @webprotocol/nwep:

webfetch - NWEP Client Library

A fetch-like API for making NWEP requests:

import { read, write, modify, del } from 'webfetch';

// READ request
const res = await read('web://[::1]:4433/users/123');
console.log(res.json());

// WRITE request
await write('web://[::1]:4433/users', {
  name: 'alice',
  email: '[email protected]'
});

// MODIFY request
await modify('web://[::1]:4433/users/123', { name: 'Alice Cooper' });

// DELETE request
await del('web://[::1]:4433/users/123');

Repository: webfetch

server - NWEP Server Framework

An Express-like framework for building NWEP servers:

import { Server } from 'server';

const server = new Server();

server.read('/', ctx => {
  ctx.send({ message: 'hello world' });
});

server.write('/users', ctx => {
  const data = ctx.parse();
  ctx.status('created');
  ctx.send({ id: 123, ...data });
});

server.read('/users/:id', ctx => {
  ctx.send({ id: ctx.id, name: 'alice' });
});

server.listen(4433);

Repository: server


Low-Level API

The following documentation covers the low-level QUIC and NWEP APIs. Most developers should use webfetch or server instead, which handle connection management, error handling, and provide idiomatic JavaScript APIs.

Use the low-level API only if you need:

  • Custom QUIC connection configuration
  • Direct control over packet handling
  • Integration with existing QUIC applications
  • Protocol-level debugging or experimentation

Error Handling

N-API functions in this package can return either a successful result or an Error object. You must check the result before using it:

// Helper function to check for errors
function isNapiError(value) {
  return value instanceof Error;
}

// Example: Creating a connection
const conn = Connection.connect(scid, local, peer, config);
if (isNapiError(conn)) {
  console.error('Failed to connect:', conn.message);
  return;
}

// Now safe to use conn
conn.send(buffer);

Common pattern for all N-API calls:

const result = someFunctionCall();
if (isNapiError(result)) {
  // Handle error - result.message contains the error description
  return;
}
// Use result safely

Note: Some operations like conn.recv() may return a "Done" error, which is not a failure but indicates no more data is available:

const recvResult = conn.recv(msg, peer);
if (isNapiError(recvResult) && recvResult.message !== 'Done') {
  console.error('Error receiving:', recvResult.message);
  return;
}
// Continue processing

This pattern is used throughout the low-level API. The high-level packages (webfetch and server) handle this automatically.

Requirements

  • Node.js 12.22+ / 14.17+ / 15.12+ / 16.0+
  • Rust 1.85+ (install from rustup.rs)
  • CMake 3.18+
  • C++ compiler (GCC, Clang, or MSVC)

On Ubuntu/Debian:

sudo apt-get install build-essential cmake

On macOS:

brew install cmake

Low-Level Quick Start

The examples below demonstrate direct usage of the QUIC and NWEP APIs. For production applications, consider using webfetch or server instead.

NWEP Client (Low-Level)

const dgram = require('dgram');
const { Config, Connection, H3Connection } = require('@webprotocol/nwep');

// Create UDP socket
const socket = dgram.createSocket('udp4');

// Create config
const config = new Config();
config.setApplicationProtos(['nwep/1']);
config.setMaxIdleTimeout(30000);
config.setInitialMaxData(10_000_000);
config.setInitialMaxStreamDataBidiLocal(1_000_000);
config.setInitialMaxStreamDataBidiRemote(1_000_000);
config.setInitialMaxStreamsBidi(100);

// Create QUIC connection
const connId = 0n;
const local = { address: '0.0.0.0', family: 'IPv4', port: 0 };
const peer = { address: '127.0.0.1', family: 'IPv4', port: 4433 };

const conn = Connection.connect('example.com', connId, local, peer, config);

// Create NWEP connection
const h3 = new H3Connection(conn);

// Send NWEP READ request
const headers = [
    [':method', 'READ'],
    [':scheme', 'web'],
    [':authority', 'example.com'],
    [':path', '/api/data'],
];
const streamId = h3.sendRequest(headers, true);

// Handle socket events
socket.on('message', (msg, rinfo) => {
    const recvInfo = {
        from: { address: rinfo.address, family: rinfo.family, port: rinfo.port },
        to: local,
    };

    conn.recv(msg, recvInfo);

    // Poll for NWEP events
    for (const event of h3.poll(conn)) {
        if (event.type === 'headers') {
            console.log('Response:', event.headers);
        } else if (event.type === 'data') {
            console.log('Body:', event.data);
        }
    }

    // Send outgoing packets
    const buf = Buffer.allocUnsafe(1200);
    while (true) {
        const [written, sendInfo] = conn.send(buf);
        if (written === 0) break;

        socket.send(buf.slice(0, written), sendInfo.to.port, sendInfo.to.address);
    }
});

socket.bind(local.port);

NWEP Server (Low-Level)

const dgram = require('dgram');
const { Config, Connection, H3Connection } = require('@webprotocol/nwep');

const socket = dgram.createSocket('udp4');
const connections = new Map();

// Create server config
const config = new Config();
config.setApplicationProtos(['nwep/1']);
config.loadCertChainFromPemFile('cert.crt');
config.loadPrivKeyFromPemFile('cert.key');
config.setMaxIdleTimeout(30000);
config.setInitialMaxData(10_000_000);
config.setInitialMaxStreamDataBidiLocal(1_000_000);
config.setInitialMaxStreamDataBidiRemote(1_000_000);
config.setInitialMaxStreamsBidi(100);

socket.on('message', (msg, rinfo) => {
    const connId = getConnectionId(msg); // Your connection ID logic

    let conn = connections.get(connId);
    if (!conn) {
        const local = { address: '127.0.0.1', family: 'IPv4', port: 4433 };
        const peer = { address: rinfo.address, family: rinfo.family, port: rinfo.port };

        conn = Connection.accept(connId, local, peer, config);
        connections.set(connId, conn);
    }

    const recvInfo = {
        from: { address: rinfo.address, family: rinfo.family, port: rinfo.port },
        to: { address: '127.0.0.1', family: 'IPv4', port: 4433 },
    };

    conn.recv(msg, recvInfo);

    if (conn.isEstablished() && !conn.h3) {
        conn.h3 = new H3Connection(conn);
    }

    if (conn.h3) {
        // Poll for NWEP requests
        for (const event of conn.h3.poll(conn)) {
            if (event.type === 'headers') {
                // Send NWEP response
                const responseHeaders = [
                    [':status', 'ok'],
                    ['content-type', 'text/plain'],
                ];
                conn.h3.sendResponse(event.streamId, responseHeaders, false);
                conn.h3.sendBody(event.streamId, Buffer.from('Hello NWEP!'), true);
            }
        }
    }

    // Send outgoing packets
    const buf = Buffer.allocUnsafe(1200);
    while (true) {
        const [written, sendInfo] = conn.send(buf);
        if (written === 0) break;

        socket.send(buf.slice(0, written), sendInfo.to.port, sendInfo.to.address);
    }
});

socket.bind(4433);

API Reference

Config

Create and configure a QUIC connection:

const config = new Config();

Methods:

  • setApplicationProtos(protos: string[]) - Set ALPN protocols (e.g., ['nwep/1'])
  • loadCertChainFromPemFile(path: string) - Load certificate chain (server)
  • loadPrivKeyFromPemFile(path: string) - Load private key (server)
  • setMaxIdleTimeout(ms: number) - Set idle timeout in milliseconds
  • setInitialMaxData(bytes: number) - Set connection-level flow control
  • setInitialMaxStreamDataBidiLocal(bytes: number) - Set stream flow control
  • setInitialMaxStreamDataBidiRemote(bytes: number) - Set stream flow control
  • setInitialMaxStreamsBidi(streams: number) - Set maximum bidirectional streams
  • setCongestionControl(algo: string) - Set congestion control ('cubic', 'reno', 'bbr')

Connection

Create a QUIC connection:

// Client
const conn = Connection.connect(serverName, connId, local, peer, config);

// Server
const conn = Connection.accept(connId, local, peer, config);

Methods:

  • recv(buf: Buffer, info: RecvInfo) - Process incoming packet
  • send(buf: Buffer): [number, SendInfo] - Generate outgoing packet
  • streamSend(id: bigint, data: Buffer, fin: boolean) - Send data on stream
  • streamRecv(id: bigint, buf: Buffer) - Receive data from stream
  • close(app: boolean, err: number, reason: string) - Close connection
  • timeout(): number - Get next timeout in milliseconds
  • onTimeout() - Handle timeout event
  • isEstablished(): boolean - Check if handshake complete
  • isClosed(): boolean - Check if connection closed

H3Connection

Create an NWEP/HTTP/3 connection:

const h3 = new H3Connection(conn);

Methods:

  • sendRequest(headers: [string, string][], fin: boolean): bigint - Send NWEP request
  • sendResponse(streamId: bigint, headers: [string, string][], fin: boolean) - Send NWEP response
  • sendBody(streamId: bigint, data: Buffer, fin: boolean) - Send body data
  • poll(conn: Connection): Event[] - Poll for events
  • isNwep(conn: Connection): boolean - Check if using NWEP protocol

Events:

  • { type: 'headers', streamId: bigint, headers: [string, string][] }
  • { type: 'data', streamId: bigint, data: Buffer }
  • { type: 'finished', streamId: bigint }
  • { type: 'datagram', data: Buffer }

NWEP Headers

Request:

const headers = [
    [':method', 'READ'],      // READ, WRITE, MODIFY, DELETE, PROBE
    [':scheme', 'web'],       // web:// scheme
    [':authority', 'example.com'],
    [':path', '/api/resource'],
    ['accept', 'application/json'],
];

Response:

const headers = [
    [':status', 'ok'],        // ok, created, not_found, internal_error, etc.
    ['content-type', 'application/json'],
];

Examples

High-Level Examples

Recommended for most users:

  • webfetch - Fetch-like NWEP client library with convenience methods
  • server - Express-like NWEP server framework

Low-Level Examples

Complete low-level examples are available in the examples/ directory:

Run a low-level example:

# NWEP server
node examples/nwep-server.js

# NWEP client
node examples/nwep-client.js web://127.0.0.1:4433/

Building from Source

The package uses napi-rs to build native Node.js addons from Rust:

# Development build
npm run build

# Release build
npm run build:release

# Debug build with symbols
npm run build:debug

The build process:

  1. Checks for Rust installation
  2. Compiles Rust code to native addon
  3. Places .node file in package directory
  4. Generates TypeScript definitions

Testing

npm test

Tests cover:

  • QUIC connection establishment
  • NWEP request/response handling
  • Stream management
  • Connection migration
  • Error handling

TypeScript

TypeScript definitions are included in index.d.ts:

import { Config, Connection, H3Connection } from '@webprotocol/nwep';

const config: Config = new Config();
const conn: Connection = Connection.connect('example.com', 0n, local, peer, config);
const h3: H3Connection = new H3Connection(conn);

Architecture

The NWEP ecosystem consists of multiple layers:

High-Level Libraries
  webfetch (client) / server (framework)
        ↓
   @webprotocol/nwep
  (Low-Level QUIC/NWEP API)
        ↓
   N-API Bindings (napi-rs)
        ↓
   Rust quiche Library
        ↓
   QUIC/NWEP Protocol
        ↓
      UDP Socket

Layer Responsibilities:

  • webfetch / server - High-level, application-friendly APIs (recommended)
  • @webprotocol/nwep - Low-level QUIC/NWEP primitives (advanced usage)
  • napi-rs bindings - Native performance bridge to Rust
  • quiche - Core protocol implementation

This architecture provides:

  • Multiple abstraction levels for different use cases
  • Native performance for QUIC packet processing
  • Zero-copy operations where possible
  • Cross-platform compatibility

License

MIT

The underlying quiche library is licensed under BSD-2-Clause. See COPYING for details.