REDWEBAPI reference
HTTP

HttpServer

Back to top

Wraps Express with sensible defaults (JSON body parsing, CORS, static asset folders) and starts listening immediately unless `listen: false` is supplied. You get the underlying Express instance back via `app`.

Options
  • port: number (default 80)
  • bind: string (default 0.0.0.0)
  • publicPaths: string[] (default ["./public"])
  • services: array of { serviceName, method, function }
  • listen: boolean (default true); set false to build app without binding a port
  • listenCallback: function invoked after listen
  • encoding: "json" | "urlencoded" (default json)
  • corsOptions: passed to cors
  • enableHtmxRendering: boolean to render .htmx files
js
const { HttpServer, METHODS } = require('redweb')

const server = new HttpServer({
  port: 4000,
  bind: '0.0.0.0',
  publicPaths: ['./static'],
  services: [
    { serviceName: '/ping', method: METHODS.GET, function: (req, res) => res.json({ pong: true }) },
  ],
  enableHtmxRendering: true,
})

// Express is still available:
server.app.get('/health', (req, res) => res.send('ok'))
Methods
constructor(options)

Merges defaults, wires body parsing, CORS, static serving, optional HTMX rendering, registers REST services, and starts listening unless listen is false.

app (Express instance)

Use the returned `app` to add middleware or routes exactly like a normal Express server.

HTTP

BaseHttpServer

Back to top

Public Express app builder used by HttpServer and HttpsServer. Use it for advanced composition when you want Redweb middleware, static files, services, and HTMX rendering without any listener behavior.

Options
  • All `HttpServer` app-building options
  • server: existing Express application to configure
  • listen is ignored because BaseHttpServer never binds a port
js
const { BaseHttpServer, METHODS } = require('redweb')

const base = new BaseHttpServer({
  publicPaths: ['./public'],
  services: [
    { serviceName: '/health', method: METHODS.GET, function: (req, res) => res.json({ ok: true }) },
  ],
})

base.app.get('/extra', (req, res) => res.send('ok'))
Methods
constructor(options)

Builds or configures an Express app with body parsing, CORS, static serving, optional HTMX rendering, and REST services.

app (Express instance)

The configured Express application. Pass it to http.createServer(app) for custom server ownership.

HTTP

HttpsServer

Back to top

TLS-enabled variant of `HttpServer`. Accepts `ssl.key` and `ssl.cert` file paths, wraps them in an https server, and bootstraps the same middleware pipeline.

Options
  • All `HttpServer` options
  • ssl.key: path to private key (required)
  • ssl.cert: path to certificate (required)
js
const { HttpsServer, METHODS } = require('redweb')

new HttpsServer({
  port: 4443,
  ssl: { key: './certs/dev.key', cert: './certs/dev.crt' },
  services: [
    { serviceName: '/secure', method: METHODS.GET, function: (req, res) => res.json({ ok: true }) },
  ],
})
Methods
constructor(options)

Loads the provided key/cert pair, builds the Express app with BaseHttpServer, then creates and starts the HTTPS listener unless listen is false.

WebSocket

SocketServer

Back to top

HTTP-upgrade WebSocket server on top of `ws`. Builds and listens on its own HTTP server by default; if you pass a Node `server`, it attaches upgrade handling and leaves `.listen()` to you unless `listen: true` is explicit.

Options
  • port: number (default 3000)
  • listen: boolean (default true for owned servers); supplied servers do not listen unless explicitly true
  • server: existing http.Server to attach to without double-listening (optional)
  • routes: array of SocketRoute subclasses (defaults to a single DefaultRoute at "/")
js
const http = require('http')
const { HttpServer, METHODS, SocketServer } = require('redweb')

const httpServer = new HttpServer({
  listen: false,
  publicPaths: ['./public'],
  services: [
    { serviceName: '/health', method: METHODS.GET, function: (req, res) => res.json({ ok: true }) },
  ],
})

const server = http.createServer(httpServer.app)

new SocketServer({
  server,
  routes: [ChatRoute],
})

server.listen(3030)
Methods
constructor(options)

Creates or reuses an HTTP server, instantiates supplied routes or a DefaultRoute, attaches upgrade handling, and starts listening only when Redweb owns the server or listen is explicitly true.

addRoute(RouteClass)

Instantiate and register another `SocketRoute` at runtime.

handleUpgrade(req, socket, head)

Internal: normalises the request path, picks a matching route (or "/"), and forwards the upgrade to that route's server.

shutdown()

Closes all registered routes and the underlying HTTP server.

WebSocket

SecureSocketServer

Back to top

HTTPS + WebSocket pairing. Mirrors `SocketServer` but wraps an HTTPS server built from the provided TLS files.

Options
  • port: number (default 3000)
  • listen: boolean (default true for owned servers); supplied servers do not listen unless explicitly true
  • server: existing https.Server to attach to without double-listening (optional)
  • ssl.key and ssl.cert: required file paths
  • routes: array of SocketRoute subclasses
js
const { SecureSocketServer } = require('redweb')
const { GameRoute } = require('./routes/GameRoute')

new SecureSocketServer({
  port: 3443,
  ssl: { key: './certs/dev.key', cert: './certs/dev.crt' },
  routes: [GameRoute],
})
Methods
constructor(options)

Loads TLS files or reuses a supplied HTTPS server, registers the provided routes, attaches upgrade handling, and starts listening only when Redweb owns the server or listen is explicitly true.

addRoute(RouteClass)

Same runtime route attachment as `SocketServer`.

shutdown()

Stops routes, services, and the HTTPS listener.

WebSocket

SocketRoute

Back to top

Defines a WebSocket endpoint and owns its handlers, services, clients, and opt-in multiplayer policies. Routes can add bounded admission, transport limits, ordered work, heartbeat, rooms, resumable sessions, distribution, draining, metrics, and protocol negotiation without changing legacy routes.

Options
  • path: WebSocket path (required)
  • handlers: array of handler classes (required)
  • services: array of SocketService subclasses (optional)
  • allowDuplicateConnections: allow multiple clients from the same IP
  • websocketOptions: options passed to ws WebSocketServer, such as maxPayload or perMessageDeflate
  • admission: authenticate, validate origins, and optionally place a client before upgrade
  • maxPendingUpgrades: finite concurrent admission/negotiation work (default 64)
  • limits: connection, message-rate, pending-message, and outbound-buffer ceilings
  • orderedMessages: serialize each connection through a bounded queue
  • heartbeat: one route-level half-open connection monitor
  • rooms and sessions: bounded grouping and expiring application-issued ownership
  • distribution: optional bounded broker adapter; no broker is bundled or required
  • drainHandlers: track handler work and expose a cooperative shutdown signal
  • protocol: version negotiation, stable envelopes/error codes, and optional binary codecs
js
const { SocketRoute } = require('redweb')
const { ChatHandler } = require('./handlers/ChatHandler')
const { ClockService } = require('./services/ClockService')

class ChatRoute extends SocketRoute {
  constructor() {
    super({
      path: '/chat',
      handlers: [ChatHandler],
      services: [ClockService],
      allowDuplicateConnections: true,
      websocketOptions: {
        maxPayload: 1024 * 1024,
        perMessageDeflate: false,
      },
    })
  }
}
Methods
constructor({ path, handlers, services, allowDuplicateConnections, websocketOptions })

Validates input, instantiates handlers/services, sets up a `ws` server for the path with any websocketOptions, and registers connection listeners.

addHandler(HandlerClass)

Adds another handler class unless a handler with the same name already exists.

handleConnection(socket, req)

Stores the client (deduping by IP unless allowed), decorates the socket with `sendJson`/`broadcast`, and wires close/error/message listeners.

handleMessage(socket, data)

Parses JSON text frames, finds the handler matching `data.type`; on success delegates to handler.handleMessage, otherwise replies with an error and closes the socket.

handleBinaryMessage(socket, buffer)

Handles binary frames separately from JSON text frames and delegates to a handler selected by acceptsBinary(socket, buffer).

handleClose(socket, ip)

Removes the client from the registry and triggers an optional `connectionCloseCallback`.

shutdown()

Marks the route draining, stops services, bounds handler/adapter cleanup, closes clients, and releases every route-owned resource.

beginDrain()

Flips readiness and rejects new upgrades before shutdown work begins.

isReady()

Reports whether the route is accepting upgrades and any required distribution adapter is healthy.

publish(type, payload)

Publishes through the optional bounded distribution adapter and resolves to a success boolean.

handleError(socket, error, ip)

Logs socket errors; override for custom reporting.

WebSocket

SocketService

Back to top

Route-scoped background worker. Used by `SocketRoute` to run ticks or lifecycle hooks tied to a specific route.

js
const { SocketService } = require('redweb')

class ClockService extends SocketService {
  constructor() { super('clock', 1000) }
  onTick() {
    this.route.clients.forEach((socket) => socket.sendJson({ type: 'time', now: Date.now() }))
  }
}
Methods
constructor(name, tickRateMs = null)

Stores a service id and optional tick interval; the interval is activated in onInit if onTick exists.

onInit(route)

Called once by SocketRoute, sets `this.route` and, if a tick interval was supplied, schedules recurring onTick execution.

onTick()

Optional; implement to run on the configured interval.

onShutdown()

Clears the tick interval; extend for cleanup hooks.

Multiplayer

FixedStepService

Back to top

Route-scoped simulation clock that compensates for drift, prevents overlapping async ticks, bounds catch-up work, and reports dropped retained lag instead of replaying forever.

js
const { FixedStepService } = require('redweb')

class Simulation extends FixedStepService {
  constructor() { super('simulation', 50, 3) }
  async onTick(stepMs, tick) {
    await game.update(stepMs, tick)
  }
}
Methods
constructor(name, tickRateMs, maxCatchUpTicks?, maxRetainedLagMs?)

Creates a fixed-step route service with finite catch-up and retained-lag limits.

onTick(stepMs, tick)

Implement one simulation step. Async work never overlaps the next pulse.

onLagDropped(milliseconds)

Optional observability hook called when retained lag is deliberately discarded.

Multiplayer

RoomRegistry

Back to top

Bounded route-local connection groups. Sockets normally use joinRoom, leaveRoom, and roomBroadcast; disconnect cleanup removes all memberships and reclaims empty rooms.

js
class MatchRoute extends SocketRoute {
  constructor() {
    super({
      path: '/match',
      handlers: [MatchHandler],
      rooms: { maxRooms: 1000, maxMembersPerRoom: 32 },
    })
  }
}
Methods
socket.joinRoom(roomId)

Idempotently joins a bounded room and returns whether membership is active.

socket.leaveRoom(roomId)

Idempotently leaves one room and reclaims it when empty.

socket.roomBroadcast(roomId, data, options?)

Serializes once and sends to selected connected members.

Multiplayer

SessionRegistry

Back to top

Bounded, expiring ownership records for application-issued opaque session IDs. Redweb handles takeover and expiry; the application owns credential issuance and payload validation.

js
class MatchRoute extends SocketRoute {
  constructor() {
    super({
      path: '/match',
      handlers: [MatchHandler],
      sessions: { ttlMs: 30000, maxSessions: 10000 },
    })
  }
}
Methods
socket.createSession(sessionId, data)

Creates a bounded application-issued session owned by the current connection.

socket.resumeSession(sessionId)

Atomically transfers ownership, closes the former owner, and returns stored data.

stop()

Stops the one route-level sweep timer and clears every retained record.

Client

ProtocolClient

Back to top

Dependency-free helper from redweb/client for opt-in versioned routes. It builds, sends, and validates stable envelopes from the same checked-in schema used by server constants and TypeScript declarations.

js
const { ProtocolClient, ERROR_CODES } = require('redweb/client')

const socket = new WebSocket('wss://game.example/match?redwebVersion=1')
const client = new ProtocolClient(socket, '1')
client.send('move', { x: 4, y: 2 }, { sequence: 17 })
Methods
constructor(socket, version)

Wraps any socket-like object with send(data) and selects the envelope version.

envelope(type, payload, metadata?)

Builds a stable versioned event with optional requestId and sequence.

send(type, payload, metadata?)

Serializes and sends one versioned event through the wrapped socket.

parse(value)

Parses and validates a protocol event or error envelope.

WebSocket

SocketRegistry

Back to top

Small EventEmitter-backed list for socket-scoped entities (players, rooms, etc.). Emits `added` and `removed` events.

js
const { SocketRegistry } = require('redweb')

class PlayerRegistry extends SocketRegistry {
  addPlayer(player) {
    this.add(player)
    this.emit('playerJoined', player)
  }
}
Methods
add(item)

Stores the item and emits an `added` event.

remove(itemOrId, by = "id")

Remove by object reference or by matching a property (defaults to "id"); returns true when removal occurred and emits `removed`.

all()

Returns a shallow copy of all stored items.

count()

Convenience getter for `all().length`.

WebSocket

BaseHandler

Back to top

Abstract message handler. Provide a name in the constructor; clients send `{ type: name, ... }` to target JSON messages, while binary frames can be accepted and handled as raw Buffer payloads.

js
const { BaseHandler } = require('redweb')

class UploadHandler extends BaseHandler {
  constructor() { super('upload') }

  onMessage(socket, message) {
    socket.sendJson({ type: 'upload:control', action: message.action })
  }

  acceptsBinary(socket, buffer) {
    return buffer.length > 0
  }

  onBinaryMessage(socket, buffer) {
    socket.sendJson({ type: 'upload:chunk', bytes: buffer.length })
  }
}
Methods
constructor(name)

Stores the handler name used by incoming messages.

handleMessage(socket, message)

Calls onMessage; override only if you need pre/post handling logic.

onMessage(socket, message)

Required; implement your message processing here. Throwing will close the socket with an error.

acceptsBinary(socket, buffer)

Optional selector used by SocketRoute to choose a handler for binary frames. Return true when this handler should receive the Buffer.

handleBinaryMessage(socket, buffer)

Calls onBinaryMessage. If onBinaryMessage is not implemented, Redweb sends a "Binary messages are not supported by this handler" error.

onBinaryMessage(socket, buffer)

Optional; override for normal binary-message handling. The second argument is the raw Buffer payload.

onInitialContact(socket)

Optional hook for first-touch logic (not used by default route).

Utility

sendJson

Back to top

Utility to JSON.stringify data and send it over a `ws` socket.

js
const { sendJson } = require('redweb')

sendJson(socket, { type: 'ping' })
Methods
sendJson(socket, data)

Serialises data and writes it to the socket.

Constants

ERROR_CODES

Back to top

Stable framework error codes shared by protocol-enabled servers and redweb/client.

js
const { ERROR_CODES } = require('redweb')

// INVALID_MESSAGE, UNKNOWN_HANDLER, HANDLER_FAILED,
// BINARY_UNSUPPORTED, RATE_LIMITED, QUEUE_FULL,
// CAPACITY_REACHED, INITIALIZATION_FAILED
Methods
Message errors

INVALID_MESSAGE, UNKNOWN_HANDLER, HANDLER_FAILED, and BINARY_UNSUPPORTED.

Capacity errors

RATE_LIMITED, QUEUE_FULL, and CAPACITY_REACHED.

Lifecycle errors

INITIALIZATION_FAILED.

Constants

SOCKET_OPTIONS

Back to top

Default WebSocket server options used by BaseSocketServer.

js
const { SOCKET_OPTIONS } = require('redweb')
// { port: 3000, ssl: null, listen: true, routes: [] }
Methods
port

Default WebSocket port (3000).

ssl

Default TLS config (null).

listen

Owned socket servers listen by default. Supplied servers remain caller-owned unless listen is explicitly true.

routes

Routes array default (empty; a DefaultRoute is created when none are provided).

Constants

HTTP_OPTIONS

Back to top

Frozen defaults used by the HTTP and HTTPS server constructors.

js
const { HTTP_OPTIONS } = require('redweb')
// port 80, bind 0.0.0.0, publicPaths ['./public'],
// listen true, encoding 'json', HTMX and error exposure disabled
Methods
Server defaults

port, bind, listen, ssl, logger, and static public paths.

Application defaults

services, encoding, HTMX rendering, and safe error exposure.

Constants

ENCODINGS

Back to top

Supported request-body parser names for HTTP server configuration.

js
const { ENCODINGS } = require('redweb')
// ENCODINGS.json, ENCODINGS.urlencoded
Methods
json

Use Express JSON body parsing.

urlencoded

Use Express URL-encoded body parsing.

Constants

METHODS

Back to top

Lowercase HTTP verb helpers passed straight to Express route registration.

js
const { METHODS } = require('redweb')
// METHODS.GET, METHODS.POST, METHODS.PUT, METHODS.DELETE
Methods
GET

Use with services array or Express: METHODS.GET

POST

Use with services array or Express: METHODS.POST

PUT

Use with services array or Express: METHODS.PUT

DELETE

Use with services array or Express: METHODS.DELETE