IOServer Class
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:
- Waits for Fastify and Socket.IO to be ready
- Creates Socket.IO namespaces and registers event handlers for all services
- Calls
watch()on all watchers (non-blocking) - Calls
webapp.listen()
await server.start();
Throws IOServerError (500) on startup failure.
stop(): Promise<void>
Stops the server:
- Calls
stop()on all watchers - 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:
| Field | Type | Required | Description |
|---|---|---|---|
event | string | Yes | Socket.IO event name |
data | any | Yes | Payload to send |
namespace | string | No | Namespace name (default "/") |
room | string | No | Target a specific room |
sid | string | No | Target 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