{ } qjs-lws

qjs-lws — JS API documentation

QuickJS bindings to libwebsockets. This documentation is derived from the C sources (lws.c, lws-context.c, lws-socket.c, lws-vhost.c, lws-spa.c, lws-sockaddr46.c, js-utils.c) and the helper JS modules under lib/.

The native module is loaded as:

import { LWSContext /* … */ } from 'lws';

Contents

FileTopic
native/module.mdModule exports: top-level functions and constants
native/LWSContext.mdThe libwebsockets context wrapper
native/LWSVhost.mdVirtual host objects
native/LWSSocket.mdPer-connection wsi object passed to callbacks
native/LWSSPA.mdServer-side multipart/POST form parser
native/LWSSockAddr46.mdIPv4/IPv6 socket address helper
native/protocols.mdProtocol handler objects and callback reasons
native/callbacks.mdPer-reason callback signatures and meaning
native/mounts.mdHTTP mount points (static files, redirects, callbacks)
native/tls.mdTLS / SSL configuration
native/event-loop.mdIntegration with os.setReadHandler / os.setWriteHandler
native/ws-server.mdWebSocket server example
native/ws-client.mdWebSocket client example
native/http-server.mdHTTP server example
native/http-client.mdHTTP client (fetch-like) example
native/raw-tcp.mdRaw TCP server / client
native/constants.mdEnumerated constants exported by the module
js/helpers.mdJS helpers shipped under lib/ (fetch, serve, WebSocket, TCPSocket)
js/bun.mdserve()'s Bun-compatible API surface in detail: server.upgrade(), WS pub/sub, chunked streaming, and their real constraints
native/examples.mdTwelve copy-paste examples covering every role
building.mdBuild instructions and CMake options

Architecture overview

   ┌──────────────────────────────────────────────────┐
   │  JavaScript                                       │
   │                                                   │
   │  import { LWSContext } from 'lws'                 │
   │  ┌──────────────┐    new LWSContext({…})          │
   │  │ user code    │──────────────────┐              │
   │  └──────┬───────┘                  ▼              │
   │         │            ┌────────────────────────┐   │
   │         │            │ LWSContext / LWSVhost   │  │
   │         │            │  LWSSocket / LWSSPA     │  │
   │         │            │  LWSSockAddr46          │  │
   │         │            └─────────────┬──────────┘   │
   │         │                          │              │
   └─────────┼──────────────────────────┼──────────────┘
             │ protocol callbacks       │ ffi
             ▼                          ▼
   ┌──────────────────────────────────────────────────┐
   │  libwebsockets (C)                                │
   │   - vhost listener / mounts                       │
   │   - HTTP/1.1, HTTP/2, WebSocket, raw TCP, MQTT    │
   │   - TLS / SSL                                     │
   └──────────────────────────────────────────────────┘
                       ▲
                       │ POLLIN / POLLOUT events
                       │
   ┌──────────────────────────────────────────────────┐
   │  QuickJS `os` module                              │
   │     os.setReadHandler(fd, fn)                     │
   │     os.setWriteHandler(fd, fn)                    │
   └──────────────────────────────────────────────────┘

qjs-lws does not call lws_service() in a loop. It hooks the LWS_CALLBACK_ADD_POLL_FD / LWS_CALLBACK_DEL_POLL_FD / LWS_CALLBACK_CHANGE_MODE_POLL_FD events and installs the file descriptors via QuickJS's own os.setReadHandler / os.setWriteHandler. The script's normal event loop drives libwebsockets; no manual polling is needed. See native/event-loop.md.

Quick example

import { createServer } from 'lws';

const ctx = createServer({
  port: 8080,
  vhostName: 'localhost',
  protocols: [{
    name: 'echo',
    onEstablished(wsi)         { console.log('open', wsi.peer?.host); },
    onReceive(wsi, data)       { wsi.write(data); },
    onClosed(wsi)              { console.log('close'); },
  }],
});