UNPKG

20.3 kBTypeScriptView Raw
1import http = require("http");
2import type { Server as HTTPSServer } from "https";
3import type { Http2SecureServer, Http2Server } from "http2";
4import { Server as Engine } from "engine.io";
5import type { ServerOptions as EngineOptions, AttachOptions } from "engine.io";
6import { ExtendedError, Namespace, ServerReservedEventsMap } from "./namespace";
7import { Adapter, Room, SocketId } from "socket.io-adapter";
8import * as parser from "socket.io-parser";
9import type { Encoder } from "socket.io-parser";
10import { Socket } from "./socket";
11import { DisconnectReason } from "./socket-types";
12import type { BroadcastOperator, RemoteSocket } from "./broadcast-operator";
13import { EventsMap, DefaultEventsMap, EventParams, StrictEventEmitter, EventNames, DecorateAcknowledgementsWithTimeoutAndMultipleResponses, AllButLast, Last, RemoveAcknowledgements, EventNamesWithAck, FirstNonErrorArg } from "./typed-events";
14type ParentNspNameMatchFn = (name: string, auth: {
15 [key: string]: any;
16}, fn: (err: Error | null, success: boolean) => void) => void;
17type AdapterConstructor = typeof Adapter | ((nsp: Namespace) => Adapter);
18type TServerInstance = http.Server | HTTPSServer | Http2SecureServer | Http2Server;
19interface ServerOptions extends EngineOptions, AttachOptions {
20 /**
21 * name of the path to capture
22 * @default "/socket.io"
23 */
24 path: string;
25 /**
26 * whether to serve the client files
27 * @default true
28 */
29 serveClient: boolean;
30 /**
31 * the adapter to use
32 * @default the in-memory adapter (https://github.com/socketio/socket.io-adapter)
33 */
34 adapter: AdapterConstructor;
35 /**
36 * the parser to use
37 * @default the default parser (https://github.com/socketio/socket.io-parser)
38 */
39 parser: any;
40 /**
41 * how many ms before a client without namespace is closed
42 * @default 45000
43 */
44 connectTimeout: number;
45 /**
46 * Whether to enable the recovery of connection state when a client temporarily disconnects.
47 *
48 * The connection state includes the missed packets, the rooms the socket was in and the `data` attribute.
49 */
50 connectionStateRecovery: {
51 /**
52 * The backup duration of the sessions and the packets.
53 *
54 * @default 120000 (2 minutes)
55 */
56 maxDisconnectionDuration?: number;
57 /**
58 * Whether to skip middlewares upon successful connection state recovery.
59 *
60 * @default true
61 */
62 skipMiddlewares?: boolean;
63 };
64 /**
65 * Whether to remove child namespaces that have no sockets connected to them
66 * @default false
67 */
68 cleanupEmptyChildNamespaces: boolean;
69}
70/**
71 * Represents a Socket.IO server.
72 *
73 * @example
74 * import { Server } from "socket.io";
75 *
76 * const io = new Server();
77 *
78 * io.on("connection", (socket) => {
79 * console.log(`socket ${socket.id} connected`);
80 *
81 * // send an event to the client
82 * socket.emit("foo", "bar");
83 *
84 * socket.on("foobar", () => {
85 * // an event was received from the client
86 * });
87 *
88 * // upon disconnection
89 * socket.on("disconnect", (reason) => {
90 * console.log(`socket ${socket.id} disconnected due to ${reason}`);
91 * });
92 * });
93 *
94 * io.listen(3000);
95 */
96export declare class Server<
97/**
98 * Types for the events received from the clients.
99 *
100 * @example
101 * interface ClientToServerEvents {
102 * hello: (arg: string) => void;
103 * }
104 *
105 * const io = new Server<ClientToServerEvents>();
106 *
107 * io.on("connection", (socket) => {
108 * socket.on("hello", (arg) => {
109 * // `arg` is inferred as string
110 * });
111 * });
112 */
113ListenEvents extends EventsMap = DefaultEventsMap,
114/**
115 * Types for the events sent to the clients.
116 *
117 * @example
118 * interface ServerToClientEvents {
119 * hello: (arg: string) => void;
120 * }
121 *
122 * const io = new Server<DefaultEventMap, ServerToClientEvents>();
123 *
124 * io.emit("hello", "world");
125 */
126EmitEvents extends EventsMap = ListenEvents,
127/**
128 * Types for the events received from and sent to the other servers.
129 *
130 * @example
131 * interface InterServerEvents {
132 * ping: (arg: number) => void;
133 * }
134 *
135 * const io = new Server<DefaultEventMap, DefaultEventMap, ServerToClientEvents>();
136 *
137 * io.serverSideEmit("ping", 123);
138 *
139 * io.on("ping", (arg) => {
140 * // `arg` is inferred as number
141 * });
142 */
143ServerSideEvents extends EventsMap = DefaultEventsMap,
144/**
145 * Additional properties that can be attached to the socket instance.
146 *
147 * Note: any property can be attached directly to the socket instance (`socket.foo = "bar"`), but the `data` object
148 * will be included when calling {@link Server#fetchSockets}.
149 *
150 * @example
151 * io.on("connection", (socket) => {
152 * socket.data.eventsCount = 0;
153 *
154 * socket.onAny(() => {
155 * socket.data.eventsCount++;
156 * });
157 * });
158 */
159SocketData = any> extends StrictEventEmitter<ServerSideEvents, RemoveAcknowledgements<EmitEvents>, ServerReservedEventsMap<ListenEvents, EmitEvents, ServerSideEvents, SocketData>> {
160 readonly sockets: Namespace<ListenEvents, EmitEvents, ServerSideEvents, SocketData>;
161 /**
162 * A reference to the underlying Engine.IO server.
163 *
164 * @example
165 * const clientsCount = io.engine.clientsCount;
166 *
167 */
168 engine: Engine;
169 /**
170 * The underlying Node.js HTTP server.
171 *
172 * @see https://nodejs.org/api/http.html
173 */
174 httpServer: TServerInstance;
175 /** @private */
176 readonly _parser: typeof parser;
177 /** @private */
178 readonly encoder: Encoder;
179 /**
180 * @private
181 */
182 _nsps: Map<string, Namespace<ListenEvents, EmitEvents, ServerSideEvents, SocketData>>;
183 private parentNsps;
184 /**
185 * A subset of the {@link parentNsps} map, only containing {@link ParentNamespace} which are based on a regular
186 * expression.
187 *
188 * @private
189 */
190 private parentNamespacesFromRegExp;
191 private _adapter?;
192 private _serveClient;
193 private readonly opts;
194 private eio;
195 private _path;
196 private clientPathRegex;
197 /**
198 * @private
199 */
200 _connectTimeout: number;
201 private _corsMiddleware;
202 /**
203 * Server constructor.
204 *
205 * @param srv http server, port, or options
206 * @param [opts]
207 */
208 constructor(opts?: Partial<ServerOptions>);
209 constructor(srv?: TServerInstance | number, opts?: Partial<ServerOptions>);
210 constructor(srv: undefined | Partial<ServerOptions> | TServerInstance | number, opts?: Partial<ServerOptions>);
211 get _opts(): Partial<ServerOptions>;
212 /**
213 * Sets/gets whether client code is being served.
214 *
215 * @param v - whether to serve client code
216 * @return self when setting or value when getting
217 */
218 serveClient(v: boolean): this;
219 serveClient(): boolean;
220 serveClient(v?: boolean): this | boolean;
221 /**
222 * Executes the middleware for an incoming namespace not already created on the server.
223 *
224 * @param name - name of incoming namespace
225 * @param auth - the auth parameters
226 * @param fn - callback
227 *
228 * @private
229 */
230 _checkNamespace(name: string, auth: {
231 [key: string]: any;
232 }, fn: (nsp: Namespace<ListenEvents, EmitEvents, ServerSideEvents, SocketData> | false) => void): void;
233 /**
234 * Sets the client serving path.
235 *
236 * @param {String} v pathname
237 * @return {Server|String} self when setting or value when getting
238 */
239 path(v: string): this;
240 path(): string;
241 path(v?: string): this | string;
242 /**
243 * Set the delay after which a client without namespace is closed
244 * @param v
245 */
246 connectTimeout(v: number): this;
247 connectTimeout(): number;
248 connectTimeout(v?: number): this | number;
249 /**
250 * Sets the adapter for rooms.
251 *
252 * @param v pathname
253 * @return self when setting or value when getting
254 */
255 adapter(): AdapterConstructor | undefined;
256 adapter(v: AdapterConstructor): this;
257 /**
258 * Attaches socket.io to a server or port.
259 *
260 * @param srv - server or port
261 * @param opts - options passed to engine.io
262 * @return self
263 */
264 listen(srv: TServerInstance | number, opts?: Partial<ServerOptions>): this;
265 /**
266 * Attaches socket.io to a server or port.
267 *
268 * @param srv - server or port
269 * @param opts - options passed to engine.io
270 * @return self
271 */
272 attach(srv: TServerInstance | number, opts?: Partial<ServerOptions>): this;
273 attachApp(app: any, opts?: Partial<ServerOptions>): void;
274 /**
275 * Initialize engine
276 *
277 * @param srv - the server to attach to
278 * @param opts - options passed to engine.io
279 * @private
280 */
281 private initEngine;
282 /**
283 * Attaches the static file serving.
284 *
285 * @param srv http server
286 * @private
287 */
288 private attachServe;
289 /**
290 * Handles a request serving of client source and map
291 *
292 * @param req
293 * @param res
294 * @private
295 */
296 private serve;
297 /**
298 * @param filename
299 * @param req
300 * @param res
301 * @private
302 */
303 private static sendFile;
304 /**
305 * Binds socket.io to an engine.io instance.
306 *
307 * @param engine engine.io (or compatible) server
308 * @return self
309 */
310 bind(engine: any): this;
311 /**
312 * Called with each incoming transport connection.
313 *
314 * @param {engine.Socket} conn
315 * @return self
316 * @private
317 */
318 private onconnection;
319 /**
320 * Looks up a namespace.
321 *
322 * @example
323 * // with a simple string
324 * const myNamespace = io.of("/my-namespace");
325 *
326 * // with a regex
327 * const dynamicNsp = io.of(/^\/dynamic-\d+$/).on("connection", (socket) => {
328 * const namespace = socket.nsp; // newNamespace.name === "/dynamic-101"
329 *
330 * // broadcast to all clients in the given sub-namespace
331 * namespace.emit("hello");
332 * });
333 *
334 * @param name - nsp name
335 * @param fn optional, nsp `connection` ev handler
336 */
337 of(name: string | RegExp | ParentNspNameMatchFn, fn?: (socket: Socket<ListenEvents, EmitEvents, ServerSideEvents, SocketData>) => void): Namespace<ListenEvents, EmitEvents, ServerSideEvents, SocketData>;
338 /**
339 * Closes server connection
340 *
341 * @param [fn] optional, called as `fn([err])` on error OR all conns closed
342 */
343 close(fn?: (err?: Error) => void): Promise<void>;
344 /**
345 * Registers a middleware, which is a function that gets executed for every incoming {@link Socket}.
346 *
347 * @example
348 * io.use((socket, next) => {
349 * // ...
350 * next();
351 * });
352 *
353 * @param fn - the middleware function
354 */
355 use(fn: (socket: Socket<ListenEvents, EmitEvents, ServerSideEvents, SocketData>, next: (err?: ExtendedError) => void) => void): this;
356 /**
357 * Targets a room when emitting.
358 *
359 * @example
360 * // the “foo” event will be broadcast to all connected clients in the “room-101” room
361 * io.to("room-101").emit("foo", "bar");
362 *
363 * // with an array of rooms (a client will be notified at most once)
364 * io.to(["room-101", "room-102"]).emit("foo", "bar");
365 *
366 * // with multiple chained calls
367 * io.to("room-101").to("room-102").emit("foo", "bar");
368 *
369 * @param room - a room, or an array of rooms
370 * @return a new {@link BroadcastOperator} instance for chaining
371 */
372 to(room: Room | Room[]): BroadcastOperator<import("./typed-events").DecorateAcknowledgementsWithMultipleResponses<EmitEvents>, SocketData>;
373 /**
374 * Targets a room when emitting. Similar to `to()`, but might feel clearer in some cases:
375 *
376 * @example
377 * // disconnect all clients in the "room-101" room
378 * io.in("room-101").disconnectSockets();
379 *
380 * @param room - a room, or an array of rooms
381 * @return a new {@link BroadcastOperator} instance for chaining
382 */
383 in(room: Room | Room[]): BroadcastOperator<import("./typed-events").DecorateAcknowledgementsWithMultipleResponses<EmitEvents>, SocketData>;
384 /**
385 * Excludes a room when emitting.
386 *
387 * @example
388 * // the "foo" event will be broadcast to all connected clients, except the ones that are in the "room-101" room
389 * io.except("room-101").emit("foo", "bar");
390 *
391 * // with an array of rooms
392 * io.except(["room-101", "room-102"]).emit("foo", "bar");
393 *
394 * // with multiple chained calls
395 * io.except("room-101").except("room-102").emit("foo", "bar");
396 *
397 * @param room - a room, or an array of rooms
398 * @return a new {@link BroadcastOperator} instance for chaining
399 */
400 except(room: Room | Room[]): BroadcastOperator<import("./typed-events").DecorateAcknowledgementsWithMultipleResponses<EmitEvents>, SocketData>;
401 /**
402 * Sends a `message` event to all clients.
403 *
404 * This method mimics the WebSocket.send() method.
405 *
406 * @see https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send
407 *
408 * @example
409 * io.send("hello");
410 *
411 * // this is equivalent to
412 * io.emit("message", "hello");
413 *
414 * @return self
415 */
416 send(...args: EventParams<EmitEvents, "message">): this;
417 /**
418 * Sends a `message` event to all clients. Alias of {@link send}.
419 *
420 * @return self
421 */
422 write(...args: EventParams<EmitEvents, "message">): this;
423 /**
424 * Sends a message to the other Socket.IO servers of the cluster.
425 *
426 * @example
427 * io.serverSideEmit("hello", "world");
428 *
429 * io.on("hello", (arg1) => {
430 * console.log(arg1); // prints "world"
431 * });
432 *
433 * // acknowledgements (without binary content) are supported too:
434 * io.serverSideEmit("ping", (err, responses) => {
435 * if (err) {
436 * // some servers did not acknowledge the event in the given delay
437 * } else {
438 * console.log(responses); // one response per server (except the current one)
439 * }
440 * });
441 *
442 * io.on("ping", (cb) => {
443 * cb("pong");
444 * });
445 *
446 * @param ev - the event name
447 * @param args - an array of arguments, which may include an acknowledgement callback at the end
448 */
449 serverSideEmit<Ev extends EventNames<ServerSideEvents>>(ev: Ev, ...args: EventParams<DecorateAcknowledgementsWithTimeoutAndMultipleResponses<ServerSideEvents>, Ev>): boolean;
450 /**
451 * Sends a message and expect an acknowledgement from the other Socket.IO servers of the cluster.
452 *
453 * @example
454 * try {
455 * const responses = await io.serverSideEmitWithAck("ping");
456 * console.log(responses); // one response per server (except the current one)
457 * } catch (e) {
458 * // some servers did not acknowledge the event in the given delay
459 * }
460 *
461 * @param ev - the event name
462 * @param args - an array of arguments
463 *
464 * @return a Promise that will be fulfilled when all servers have acknowledged the event
465 */
466 serverSideEmitWithAck<Ev extends EventNamesWithAck<ServerSideEvents>>(ev: Ev, ...args: AllButLast<EventParams<ServerSideEvents, Ev>>): Promise<FirstNonErrorArg<Last<EventParams<ServerSideEvents, Ev>>>[]>;
467 /**
468 * Gets a list of socket ids.
469 *
470 * @deprecated this method will be removed in the next major release, please use {@link Server#serverSideEmit} or
471 * {@link Server#fetchSockets} instead.
472 */
473 allSockets(): Promise<Set<SocketId>>;
474 /**
475 * Sets the compress flag.
476 *
477 * @example
478 * io.compress(false).emit("hello");
479 *
480 * @param compress - if `true`, compresses the sending data
481 * @return a new {@link BroadcastOperator} instance for chaining
482 */
483 compress(compress: boolean): BroadcastOperator<import("./typed-events").DecorateAcknowledgementsWithMultipleResponses<EmitEvents>, SocketData>;
484 /**
485 * Sets a modifier for a subsequent event emission that the event data may be lost if the client is not ready to
486 * receive messages (because of network slowness or other issues, or because they’re connected through long polling
487 * and is in the middle of a request-response cycle).
488 *
489 * @example
490 * io.volatile.emit("hello"); // the clients may or may not receive it
491 *
492 * @return a new {@link BroadcastOperator} instance for chaining
493 */
494 get volatile(): BroadcastOperator<import("./typed-events").DecorateAcknowledgementsWithMultipleResponses<EmitEvents>, SocketData>;
495 /**
496 * Sets a modifier for a subsequent event emission that the event data will only be broadcast to the current node.
497 *
498 * @example
499 * // the “foo” event will be broadcast to all connected clients on this node
500 * io.local.emit("foo", "bar");
501 *
502 * @return a new {@link BroadcastOperator} instance for chaining
503 */
504 get local(): BroadcastOperator<import("./typed-events").DecorateAcknowledgementsWithMultipleResponses<EmitEvents>, SocketData>;
505 /**
506 * Adds a timeout in milliseconds for the next operation.
507 *
508 * @example
509 * io.timeout(1000).emit("some-event", (err, responses) => {
510 * if (err) {
511 * // some clients did not acknowledge the event in the given delay
512 * } else {
513 * console.log(responses); // one response per client
514 * }
515 * });
516 *
517 * @param timeout
518 */
519 timeout(timeout: number): BroadcastOperator<import("./typed-events").DecorateAcknowledgements<import("./typed-events").DecorateAcknowledgementsWithMultipleResponses<EmitEvents>>, SocketData>;
520 /**
521 * Returns the matching socket instances.
522 *
523 * Note: this method also works within a cluster of multiple Socket.IO servers, with a compatible {@link Adapter}.
524 *
525 * @example
526 * // return all Socket instances
527 * const sockets = await io.fetchSockets();
528 *
529 * // return all Socket instances in the "room1" room
530 * const sockets = await io.in("room1").fetchSockets();
531 *
532 * for (const socket of sockets) {
533 * console.log(socket.id);
534 * console.log(socket.handshake);
535 * console.log(socket.rooms);
536 * console.log(socket.data);
537 *
538 * socket.emit("hello");
539 * socket.join("room1");
540 * socket.leave("room2");
541 * socket.disconnect();
542 * }
543 */
544 fetchSockets(): Promise<RemoteSocket<EmitEvents, SocketData>[]>;
545 /**
546 * Makes the matching socket instances join the specified rooms.
547 *
548 * Note: this method also works within a cluster of multiple Socket.IO servers, with a compatible {@link Adapter}.
549 *
550 * @example
551 *
552 * // make all socket instances join the "room1" room
553 * io.socketsJoin("room1");
554 *
555 * // make all socket instances in the "room1" room join the "room2" and "room3" rooms
556 * io.in("room1").socketsJoin(["room2", "room3"]);
557 *
558 * @param room - a room, or an array of rooms
559 */
560 socketsJoin(room: Room | Room[]): void;
561 /**
562 * Makes the matching socket instances leave the specified rooms.
563 *
564 * Note: this method also works within a cluster of multiple Socket.IO servers, with a compatible {@link Adapter}.
565 *
566 * @example
567 * // make all socket instances leave the "room1" room
568 * io.socketsLeave("room1");
569 *
570 * // make all socket instances in the "room1" room leave the "room2" and "room3" rooms
571 * io.in("room1").socketsLeave(["room2", "room3"]);
572 *
573 * @param room - a room, or an array of rooms
574 */
575 socketsLeave(room: Room | Room[]): void;
576 /**
577 * Makes the matching socket instances disconnect.
578 *
579 * Note: this method also works within a cluster of multiple Socket.IO servers, with a compatible {@link Adapter}.
580 *
581 * @example
582 * // make all socket instances disconnect (the connections might be kept alive for other namespaces)
583 * io.disconnectSockets();
584 *
585 * // make all socket instances in the "room1" room disconnect and close the underlying connections
586 * io.in("room1").disconnectSockets(true);
587 *
588 * @param close - whether to close the underlying connection
589 */
590 disconnectSockets(close?: boolean): void;
591}
592export { Socket, DisconnectReason, ServerOptions, Namespace, BroadcastOperator, RemoteSocket, DefaultEventsMap, ExtendedError, };
593export { Event } from "./socket";
594
\No newline at end of file