Api

IOServer Class

Complete API reference for the IOServer class — constructor, registration, lifecycle, and messaging.

IOServer Class

Import

import { IOServer } from "ioserver";
// or
import IOServer from "ioserver";

Constructor

new IOServer(options?: IOServerOptions): IOServer

Creates and configures the server. Does not start listening. Route files for controllers are read at addController() time, not at construction.

See the Configuration guide for the full IOServerOptions reference.

const server = new IOServer({
  host: "0.0.0.0",
  port: 3000,
  verbose: "INFORMATION",
  routes: "./routes",
  cors: {
    origin: ["https://app.example.com"],
    methods: ["GET", "POST"],
  },
});

Throws IOServerError (400) if port is out of range (1–65535).


Registration methods

addManager(options: ManagerOptions): void

Registers a manager. Synchronous — the manager is instantiated immediately and added to appHandle before the call returns. If the manager defines async start(), it is called asynchronously (non-blocking, errors logged).

server.addManager({ name: "db", manager: DatabaseManager });
// appHandle.db is now available

Throws IOServerError (400) if name is missing, too short, or reserved. (409) if already registered.


addService(options: ServiceOptions): void

Registers a service. Instantiated immediately; Socket.IO namespace and event handlers are set up at start().

server.addService({ service: ChatService });                    // namespace "/"
server.addService({ name: "chat", service: ChatService });      // namespace "/chat"
server.addService({ name: "chat", service: ChatService, middlewares: [AuthMiddleware] });

addController(options: ControllerOptions): void

Registers a controller and immediately registers its routes in Fastify. Reads the route file at {routes}/{name}.json.

server.addController({ name: "api", controller: ApiController });
server.addController({ name: "api", controller: ApiController, prefix: "/v1" });
server.addController({ name: "api", controller: ApiController, prefix: "" });
server.addController({ name: "api", controller: ApiController, middlewares: [AuthMiddleware] });

Throws IOServerError (404) if the route file does not exist.


addWatcher(options: WatcherOptions): void

Registers a watcher. Instantiated immediately; watch() is called at start().

server.addWatcher({ name: "health", watcher: HealthWatcher });

Lifecycle methods

start(): Promise<void>

Starts the server:

  1. Waits for Fastify and Socket.IO to be ready
  2. Creates Socket.IO namespaces and registers event handlers for all services
  3. Calls watch() on all watchers (non-blocking)
  4. Calls webapp.listen()
await server.start();

Throws IOServerError (500) on startup failure.


stop(): Promise<void>

Stops the server:

  1. Calls stop() on all watchers
  2. Closes the Fastify server (and its Socket.IO server)
await server.stop();

Messaging

sendTo(options: SendToOptions): boolean

Sends a Socket.IO event from anywhere — including managers, watchers, and controllers. Returns false if Socket.IO is not yet initialized.

// Broadcast to all clients in a namespace
server.sendTo({ namespace: "chat", event: "announcement", data: { text: "Hello" } });

// Broadcast to a specific room
server.sendTo({ namespace: "chat", event: "new_message", room: "general", data: msg });

// Send to a specific socket
server.sendTo({ namespace: "chat", event: "private", sid: socket.id, data: msg });

SendToOptions fields:

FieldTypeRequiredDescription
eventstringYesSocket.IO event name
dataanyYesPayload to send
namespacestringNoNamespace name (default "/")
roomstringNoTarget a specific room
sidstringNoTarget a specific socket ID

Introspection

getHost(): string

Returns the configured hostname.

getPort(): number

Returns the configured port.

getApp(): FastifyInstance

Returns the underlying Fastify instance. Use this to add plugins or routes directly:

const app = server.getApp();
app.register(somePlugin, { option: "value" });

getService(name: string): any

Returns a service instance by name, or undefined if not found.

const chatService = server.getService("chat");

isRegistered(type: string, name: string): boolean

Checks whether a component with the given type and name has been registered.

server.isRegistered("service", "chat");     // true / false
server.isRegistered("manager", "db");       // true / false
server.isRegistered("controller", "api");   // true / false
server.isRegistered("watcher", "health");   // true / false

Valid type values: "service", "controller", "manager", "watcher".

log(level: number, text: string): void

Logs a message at the given level. Respects the configured verbose threshold.

server.log(3, "Something went wrong");   // ERROR
server.log(6, "Request processed");      // INFORMATION
server.log(7, "Raw payload: ...");       // DEBUG
Copyright © 2026