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

@tty-pt/ndc

v1.0.0

Published

ndc example project

Readme

ndc

HTTP(S) + WS(S) + Terminal MUX

A cross-platform C library for building network daemons - HTTP servers, WebSocket servers, telnet-like services, terminal multiplexers, or custom network applications.

From NeverDark • Powers tty.pt

What is ndc?

libndc - C library for building network daemons
ndc - Standalone server binary with HTTP/WS/terminal mux

Build telnet-like servers, custom protocol handlers, HTTP APIs, WebSocket apps, or anything that needs persistent network connections with an event loop.

Platform Support

| Platform | Status | |----------|--------| | Linux, macOS, BSD | ✅ Full support | | Windows | ⚠️ HTTP/WS only (no PTY/CGI/privilege dropping) |

Quick Start

# Run simple HTTP server
ndc -d -p 8888

# With SSL (POSIX)
sudo ndc -C . -K certs.txt -d

Command Line Options

| Option | Description | |--------|-------------| | -p PORT | Specify HTTP server port | | -s PORT | Specify HTTPS server port (POSIX) | | -C PATH | Change directory to PATH before starting | | -K PATH | Load SSL certificate mappings from file (POSIX) | | -k CERT | Add single SSL certificate mapping (POSIX) | | -d | Don't detach (run in foreground) | | -r | Root multiplex mode | | -? | Display help message |

certs.txt Format (POSIX)

example.com:cert.pem:key.pem

Building Custom Daemons

Minimal Example

#include <ttypt/ndc.h>

int main(void) {
    ndc_config.port = 8080;
    ndc_register("GET", do_GET, CF_NOAUTH);
    return ndc_main();  // Blocks, runs event loop
}

Telnet-Style Server

void cmd_echo(socket_t fd, int argc, char *argv[]) {
    for (int i = 0; i < argc; i++)
        ndc_writef(fd, "%s ", argv[i]);
    ndc_writef(fd, "\n");
}

int ndc_connect(socket_t fd) {
    ndc_writef(fd, "Welcome! Type 'echo hello'\n");
    return 1;  // Accept connection
}

int main(void) {
    ndc_config.port = 2323;
    ndc_register("echo", cmd_echo, CF_NOAUTH);
    return ndc_main();
}

Custom Protocol Handler

void my_handler(socket_t fd, char *body) {
    // Handle raw data from client
    ndc_write(fd, "RESPONSE", 8);
}

void ndc_command(socket_t fd, int argc, char *argv[]) {
    // Called on every command
    log_command(argv[0]);
}

void ndc_update(unsigned long long dt) {
    // Periodic tick (game loops, etc)
}

Library API

Core Functions

| Function | Description | Return Value | |----------|-------------|--------------| | ndc_main() | Start event loop (blocking) | Exit code | | ndc_register(name, cb, flags) | Register command handler | - | | ndc_register_handler(path, handler) | Register HTTP handler for exact path | - | | ndc_write(fd, data, len) | Write raw bytes | Bytes written or -1 | | ndc_writef(fd, fmt, ...) | Write formatted data | Bytes written or -1 | | ndc_dwritef(fd, fmt, va) | Write formatted data with va_list | Bytes written or -1 | | ndc_close(fd) | Close connection | - | | ndc_wall(msg) | Broadcast message to all descriptors | - |

HTTP Functions

| Function | Description | Return Value | |----------|-------------|--------------| | ndc_header(fd, key, val) | Add response header (call before ndc_head) | - | | ndc_head(fd, code) | Send HTTP status and headers | - | | ndc_body(fd, body) | Send body and close connection | - | | ndc_sendfile(fd, path) | Serve static file with auto MIME type | - | | ndc_status_text(code) | Get HTTP status text for code | Status string |

Descriptor Functions

| Function | Description | Return Value | |----------|-------------|--------------| | ndc_flags(fd) | Get descriptor flags | Flags bitmask | | ndc_set_flags(fd, flags) | Set descriptor flags | - |

Request Environment Functions

| Function | Description | Return Value | |----------|-------------|--------------| | ndc_env_get(fd, target, key) | Get request environment value | 0 on success | | ndc_env_put(fd, key, value) | Set environment key/value | 0 on success | | ndc_env_clear(fd) | Clear request environment | - | | ndc_env(fd) | Get internal env handle (advanced) | Env handle |

POSIX-Only Functions

| Function | Description | Return Value | |----------|-------------|--------------| | ndc_pty(fd, args[]) | Spawn PTY-backed command | - | | ndc_exec(fd, args[], cb, input, len) | Execute command with callback | - | | ndc_auth(fd, username) | Mark user as authenticated, drop privileges (POSIX) | 0 on success, 1 on failure | | ndc_cert_add(str) | Add cert mapping: domain:cert.pem:key.pem | - | | ndc_certs_add(fname) | Load certificate mappings from file | - | | ndc_mmap(mapped, file) | Map file into memory | File size or -1 | | ndc_mmap_iter(start, pos) | Iterate mapped lines separated by \n | Next line or NULL | | ndc_sendfile(fd, path) | Serve static file (POSIX uses sendfile syscall) | - |

Built-in Command Handlers

| Handler | Description | |---------|-------------| | do_GET | HTTP GET request handler | | do_POST | HTTP POST request handler | | do_sh | Shell PTY handler (POSIX-only) |

Hook Functions (Optional)

Define these weak symbol hooks to customize behavior:

| Hook | Description | Return Value | |------|-------------|--------------| | ndc_connect(socket_t fd) | Accept/reject WebSocket connections | Non-zero to accept | | ndc_disconnect(socket_t fd) | Cleanup on disconnect | - | | ndc_accept(socket_t fd) | Called on socket accept | Ignored | | ndc_command(socket_t fd, int argc, char *argv[]) | Before command execution | - | | ndc_flush(socket_t fd, int argc, char *argv[]) | After command execution | - | | ndc_vim(socket_t fd, int argc, char *argv[]) | Called when command not found | - | | ndc_update(unsigned long long dt) | Periodic updates (dt in milliseconds) | - | | ndc_auth_check(socket_t fd) | Custom auth hook: validate credentials, return username. Default: session file lookup in ./sessions/ | Username string or NULL |

Example:

int ndc_connect(socket_t fd) {
    ndc_writef(fd, "Welcome!\n");
    return 1;  // Accept connection
}

void ndc_disconnect(socket_t fd) {
    // Cleanup resources
}

void ndc_command(socket_t fd, int argc, char *argv[]) {
    // Log or validate commands
}

void ndc_flush(socket_t fd, int argc, char *argv[]) {
    // Post-command processing
}

void ndc_vim(socket_t fd, int argc, char *argv[]) {
    ndc_writef(fd, "Unknown command: %s\n", argv[0]);
}

void ndc_update(unsigned long long dt) {
    // Game loop, periodic tasks, etc.
}

char *ndc_auth_check(socket_t fd) {
    // Check cookies, tokens, etc.
    // Return username or NULL
    return authenticated_user;
}

Configuration

struct ndc_config {
    char *chroot;                    // chroot directory (POSIX)
    unsigned flags;                  // Server flags (see below)
    unsigned port;                   // HTTP listen port
    unsigned ssl_port;               // HTTPS listen port (POSIX)
    ndc_handler_t *default_handler;  // Fallback HTTP handler
};

// Example usage
ndc_config.port = 8080;              // HTTP on port 8080
ndc_config.ssl_port = 8443;          // HTTPS on port 8443 (POSIX)
ndc_config.flags = NDC_SSL;          // Enable TLS
ndc_config.chroot = "/var/www";      // chroot directory (POSIX)
ndc_config.default_handler = my_404; // Custom 404 handler

Server Flags

| Flag | Description | |------|-------------| | NDC_WAKE | Wake on activity | | NDC_SSL | Enable TLS/SSL | | NDC_ROOT | Root multiplex mode | | NDC_SSL_ONLY | Redirect HTTP to HTTPS when SSL enabled | | NDC_DETACH | Detach into background (daemon mode) |

Command Flags

Use with ndc_register():

| Flag | Description | |------|-------------| | CF_NOAUTH | Allow command without authentication | | CF_NOTRIM | Do not trim trailing CR from input |

Descriptor Flags

Access with ndc_flags() and ndc_set_flags():

| Flag | Description | |------|-------------| | DF_CONNECTED | Connection established and accepted | | DF_WEBSOCKET | WebSocket mode enabled | | DF_TO_CLOSE | Marked to close after remaining output | | DF_ACCEPTED | Accepted socket (pre-WebSocket) | | DF_AUTHENTICATED | User authenticated |

POSIX vs Windows

| Feature | POSIX | Windows | |---------|-------|---------| | HTTP/WebSocket | ✅ | ✅ | | Custom commands | ✅ | ✅ | | PTY/Terminal | ✅ | ❌ | | CGI execution | ✅ | ❌ | | Authentication (privilege dropping) | ✅ | ❌ | | SSL certs | ✅ | ❌ |

Windows build provides core networking only.

CGI & Static Files (POSIX)

Create index.sh for dynamic pages:

#!/bin/sh
# CGI scripts output status line without "HTTP/1.1" prefix
printf "200 OK\r\n"
printf "Content-Type: text/plain\r\n"
printf "\r\n"
printf "Hello world\n"
printf "REQUEST_METHOD=%s\n" "$REQUEST_METHOD"
printf "QUERY_STRING=%s\n" "$QUERY_STRING"

Control access with serve.allow and serve.autoindex files.

NPM for Web Terminal

Install the package:

npm install @tty-pt/ndc

JavaScript/TypeScript API:

import { create } from "@tty-pt/ndc";

// Create terminal instance
const term = create(document.getElementById("terminal"), {
  proto: "ws",        // or "wss" for secure
  port: 4201,
  sub: {
    onOpen: (term, ws) => {
      console.log("Connected to server");
    },
    onClose: (ws) => {
      console.log("Disconnected, reconnecting...");
    },
    onMessage: (ev, arr) => {
      // Return true to continue default processing
      return true;
    },
    cols: 80,
    rows: 25,
  },
  debug: false,
});

See types/ndc.d.ts for full TypeScript definitions.

Documentation

  • Man pages: man ndc and man ndc.3
  • Full API: include/ttypt/ndc.h
  • Examples: src/test-*.c

Plugin System

Load dynamic modules with dependency resolution via libndx:

// In your plugin module
const char *ndx_deps[] = { "dependency.so", NULL };

// In main application
ndx_load("plugin.so");  // Automatically loads dependencies

The binary automatically loads core.so at startup. Plugins can hook into lifecycle events (ndc_update, ndc_connect, etc.) to extend functionality.


Installation: See install docs
Entry points: src/ndc.c (native), ndc-cli.js (npm)