UNPKG

17.1 kBTypeScriptView Raw
1import { Packet } from "socket.io-parser";
2import { Manager } from "./manager.js";
3import { DefaultEventsMap, EventNames, EventParams, EventsMap, Emitter } from "@socket.io/component-emitter";
4type PrependTimeoutError<T extends any[]> = {
5 [K in keyof T]: T[K] extends (...args: infer Params) => infer Result ? (err: Error, ...args: Params) => Result : T[K];
6};
7/**
8 * Utility type to decorate the acknowledgement callbacks with a timeout error.
9 *
10 * This is needed because the timeout() flag breaks the symmetry between the sender and the receiver:
11 *
12 * @example
13 * interface Events {
14 * "my-event": (val: string) => void;
15 * }
16 *
17 * socket.on("my-event", (cb) => {
18 * cb("123"); // one single argument here
19 * });
20 *
21 * socket.timeout(1000).emit("my-event", (err, val) => {
22 * // two arguments there (the "err" argument is not properly typed)
23 * });
24 *
25 */
26export type DecorateAcknowledgements<E> = {
27 [K in keyof E]: E[K] extends (...args: infer Params) => infer Result ? (...args: PrependTimeoutError<Params>) => Result : E[K];
28};
29export type Last<T extends any[]> = T extends [...infer H, infer L] ? L : any;
30export type AllButLast<T extends any[]> = T extends [...infer H, infer L] ? H : any[];
31export type FirstArg<T> = T extends (arg: infer Param) => infer Result ? Param : any;
32export interface SocketOptions {
33 /**
34 * the authentication payload sent when connecting to the Namespace
35 */
36 auth?: {
37 [key: string]: any;
38 } | ((cb: (data: object) => void) => void);
39 /**
40 * The maximum number of retries. Above the limit, the packet will be discarded.
41 *
42 * Using `Infinity` means the delivery guarantee is "at-least-once" (instead of "at-most-once" by default), but a
43 * smaller value like 10 should be sufficient in practice.
44 */
45 retries?: number;
46 /**
47 * The default timeout in milliseconds used when waiting for an acknowledgement.
48 */
49 ackTimeout?: number;
50}
51export type DisconnectDescription = Error | {
52 description: string;
53 context?: unknown;
54};
55interface SocketReservedEvents {
56 connect: () => void;
57 connect_error: (err: Error) => void;
58 disconnect: (reason: Socket.DisconnectReason, description?: DisconnectDescription) => void;
59}
60/**
61 * A Socket is the fundamental class for interacting with the server.
62 *
63 * A Socket belongs to a certain Namespace (by default /) and uses an underlying {@link Manager} to communicate.
64 *
65 * @example
66 * const socket = io();
67 *
68 * socket.on("connect", () => {
69 * console.log("connected");
70 * });
71 *
72 * // send an event to the server
73 * socket.emit("foo", "bar");
74 *
75 * socket.on("foobar", () => {
76 * // an event was received from the server
77 * });
78 *
79 * // upon disconnection
80 * socket.on("disconnect", (reason) => {
81 * console.log(`disconnected due to ${reason}`);
82 * });
83 */
84export declare class Socket<ListenEvents extends EventsMap = DefaultEventsMap, EmitEvents extends EventsMap = ListenEvents> extends Emitter<ListenEvents, EmitEvents, SocketReservedEvents> {
85 readonly io: Manager<ListenEvents, EmitEvents>;
86 /**
87 * A unique identifier for the session. `undefined` when the socket is not connected.
88 *
89 * @example
90 * const socket = io();
91 *
92 * console.log(socket.id); // undefined
93 *
94 * socket.on("connect", () => {
95 * console.log(socket.id); // "G5p5..."
96 * });
97 */
98 id: string | undefined;
99 /**
100 * The session ID used for connection state recovery, which must not be shared (unlike {@link id}).
101 *
102 * @private
103 */
104 private _pid;
105 /**
106 * The offset of the last received packet, which will be sent upon reconnection to allow for the recovery of the connection state.
107 *
108 * @private
109 */
110 private _lastOffset;
111 /**
112 * Whether the socket is currently connected to the server.
113 *
114 * @example
115 * const socket = io();
116 *
117 * socket.on("connect", () => {
118 * console.log(socket.connected); // true
119 * });
120 *
121 * socket.on("disconnect", () => {
122 * console.log(socket.connected); // false
123 * });
124 */
125 connected: boolean;
126 /**
127 * Whether the connection state was recovered after a temporary disconnection. In that case, any missed packets will
128 * be transmitted by the server.
129 */
130 recovered: boolean;
131 /**
132 * Credentials that are sent when accessing a namespace.
133 *
134 * @example
135 * const socket = io({
136 * auth: {
137 * token: "abcd"
138 * }
139 * });
140 *
141 * // or with a function
142 * const socket = io({
143 * auth: (cb) => {
144 * cb({ token: localStorage.token })
145 * }
146 * });
147 */
148 auth: {
149 [key: string]: any;
150 } | ((cb: (data: object) => void) => void);
151 /**
152 * Buffer for packets received before the CONNECT packet
153 */
154 receiveBuffer: Array<ReadonlyArray<any>>;
155 /**
156 * Buffer for packets that will be sent once the socket is connected
157 */
158 sendBuffer: Array<Packet>;
159 /**
160 * The queue of packets to be sent with retry in case of failure.
161 *
162 * Packets are sent one by one, each waiting for the server acknowledgement, in order to guarantee the delivery order.
163 * @private
164 */
165 private _queue;
166 /**
167 * A sequence to generate the ID of the {@link QueuedPacket}.
168 * @private
169 */
170 private _queueSeq;
171 private readonly nsp;
172 private readonly _opts;
173 private ids;
174 /**
175 * A map containing acknowledgement handlers.
176 *
177 * The `withError` attribute is used to differentiate handlers that accept an error as first argument:
178 *
179 * - `socket.emit("test", (err, value) => { ... })` with `ackTimeout` option
180 * - `socket.timeout(5000).emit("test", (err, value) => { ... })`
181 * - `const value = await socket.emitWithAck("test")`
182 *
183 * From those that don't:
184 *
185 * - `socket.emit("test", (value) => { ... });`
186 *
187 * In the first case, the handlers will be called with an error when:
188 *
189 * - the timeout is reached
190 * - the socket gets disconnected
191 *
192 * In the second case, the handlers will be simply discarded upon disconnection, since the client will never receive
193 * an acknowledgement from the server.
194 *
195 * @private
196 */
197 private acks;
198 private flags;
199 private subs?;
200 private _anyListeners;
201 private _anyOutgoingListeners;
202 /**
203 * `Socket` constructor.
204 */
205 constructor(io: Manager, nsp: string, opts?: Partial<SocketOptions>);
206 /**
207 * Whether the socket is currently disconnected
208 *
209 * @example
210 * const socket = io();
211 *
212 * socket.on("connect", () => {
213 * console.log(socket.disconnected); // false
214 * });
215 *
216 * socket.on("disconnect", () => {
217 * console.log(socket.disconnected); // true
218 * });
219 */
220 get disconnected(): boolean;
221 /**
222 * Subscribe to open, close and packet events
223 *
224 * @private
225 */
226 private subEvents;
227 /**
228 * Whether the Socket will try to reconnect when its Manager connects or reconnects.
229 *
230 * @example
231 * const socket = io();
232 *
233 * console.log(socket.active); // true
234 *
235 * socket.on("disconnect", (reason) => {
236 * if (reason === "io server disconnect") {
237 * // the disconnection was initiated by the server, you need to manually reconnect
238 * console.log(socket.active); // false
239 * }
240 * // else the socket will automatically try to reconnect
241 * console.log(socket.active); // true
242 * });
243 */
244 get active(): boolean;
245 /**
246 * "Opens" the socket.
247 *
248 * @example
249 * const socket = io({
250 * autoConnect: false
251 * });
252 *
253 * socket.connect();
254 */
255 connect(): this;
256 /**
257 * Alias for {@link connect()}.
258 */
259 open(): this;
260 /**
261 * Sends a `message` event.
262 *
263 * This method mimics the WebSocket.send() method.
264 *
265 * @see https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send
266 *
267 * @example
268 * socket.send("hello");
269 *
270 * // this is equivalent to
271 * socket.emit("message", "hello");
272 *
273 * @return self
274 */
275 send(...args: any[]): this;
276 /**
277 * Override `emit`.
278 * If the event is in `events`, it's emitted normally.
279 *
280 * @example
281 * socket.emit("hello", "world");
282 *
283 * // all serializable datastructures are supported (no need to call JSON.stringify)
284 * socket.emit("hello", 1, "2", { 3: ["4"], 5: Uint8Array.from([6]) });
285 *
286 * // with an acknowledgement from the server
287 * socket.emit("hello", "world", (val) => {
288 * // ...
289 * });
290 *
291 * @return self
292 */
293 emit<Ev extends EventNames<EmitEvents>>(ev: Ev, ...args: EventParams<EmitEvents, Ev>): this;
294 /**
295 * @private
296 */
297 private _registerAckCallback;
298 /**
299 * Emits an event and waits for an acknowledgement
300 *
301 * @example
302 * // without timeout
303 * const response = await socket.emitWithAck("hello", "world");
304 *
305 * // with a specific timeout
306 * try {
307 * const response = await socket.timeout(1000).emitWithAck("hello", "world");
308 * } catch (err) {
309 * // the server did not acknowledge the event in the given delay
310 * }
311 *
312 * @return a Promise that will be fulfilled when the server acknowledges the event
313 */
314 emitWithAck<Ev extends EventNames<EmitEvents>>(ev: Ev, ...args: AllButLast<EventParams<EmitEvents, Ev>>): Promise<FirstArg<Last<EventParams<EmitEvents, Ev>>>>;
315 /**
316 * Add the packet to the queue.
317 * @param args
318 * @private
319 */
320 private _addToQueue;
321 /**
322 * Send the first packet of the queue, and wait for an acknowledgement from the server.
323 * @param force - whether to resend a packet that has not been acknowledged yet
324 *
325 * @private
326 */
327 private _drainQueue;
328 /**
329 * Sends a packet.
330 *
331 * @param packet
332 * @private
333 */
334 private packet;
335 /**
336 * Called upon engine `open`.
337 *
338 * @private
339 */
340 private onopen;
341 /**
342 * Sends a CONNECT packet to initiate the Socket.IO session.
343 *
344 * @param data
345 * @private
346 */
347 private _sendConnectPacket;
348 /**
349 * Called upon engine or manager `error`.
350 *
351 * @param err
352 * @private
353 */
354 private onerror;
355 /**
356 * Called upon engine `close`.
357 *
358 * @param reason
359 * @param description
360 * @private
361 */
362 private onclose;
363 /**
364 * Clears the acknowledgement handlers upon disconnection, since the client will never receive an acknowledgement from
365 * the server.
366 *
367 * @private
368 */
369 private _clearAcks;
370 /**
371 * Called with socket packet.
372 *
373 * @param packet
374 * @private
375 */
376 private onpacket;
377 /**
378 * Called upon a server event.
379 *
380 * @param packet
381 * @private
382 */
383 private onevent;
384 private emitEvent;
385 /**
386 * Produces an ack callback to emit with an event.
387 *
388 * @private
389 */
390 private ack;
391 /**
392 * Called upon a server acknowledgement.
393 *
394 * @param packet
395 * @private
396 */
397 private onack;
398 /**
399 * Called upon server connect.
400 *
401 * @private
402 */
403 private onconnect;
404 /**
405 * Emit buffered events (received and emitted).
406 *
407 * @private
408 */
409 private emitBuffered;
410 /**
411 * Called upon server disconnect.
412 *
413 * @private
414 */
415 private ondisconnect;
416 /**
417 * Called upon forced client/server side disconnections,
418 * this method ensures the manager stops tracking us and
419 * that reconnections don't get triggered for this.
420 *
421 * @private
422 */
423 private destroy;
424 /**
425 * Disconnects the socket manually. In that case, the socket will not try to reconnect.
426 *
427 * If this is the last active Socket instance of the {@link Manager}, the low-level connection will be closed.
428 *
429 * @example
430 * const socket = io();
431 *
432 * socket.on("disconnect", (reason) => {
433 * // console.log(reason); prints "io client disconnect"
434 * });
435 *
436 * socket.disconnect();
437 *
438 * @return self
439 */
440 disconnect(): this;
441 /**
442 * Alias for {@link disconnect()}.
443 *
444 * @return self
445 */
446 close(): this;
447 /**
448 * Sets the compress flag.
449 *
450 * @example
451 * socket.compress(false).emit("hello");
452 *
453 * @param compress - if `true`, compresses the sending data
454 * @return self
455 */
456 compress(compress: boolean): this;
457 /**
458 * Sets a modifier for a subsequent event emission that the event message will be dropped when this socket is not
459 * ready to send messages.
460 *
461 * @example
462 * socket.volatile.emit("hello"); // the server may or may not receive it
463 *
464 * @returns self
465 */
466 get volatile(): this;
467 /**
468 * Sets a modifier for a subsequent event emission that the callback will be called with an error when the
469 * given number of milliseconds have elapsed without an acknowledgement from the server:
470 *
471 * @example
472 * socket.timeout(5000).emit("my-event", (err) => {
473 * if (err) {
474 * // the server did not acknowledge the event in the given delay
475 * }
476 * });
477 *
478 * @returns self
479 */
480 timeout(timeout: number): Socket<ListenEvents, DecorateAcknowledgements<EmitEvents>>;
481 /**
482 * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
483 * callback.
484 *
485 * @example
486 * socket.onAny((event, ...args) => {
487 * console.log(`got ${event}`);
488 * });
489 *
490 * @param listener
491 */
492 onAny(listener: (...args: any[]) => void): this;
493 /**
494 * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
495 * callback. The listener is added to the beginning of the listeners array.
496 *
497 * @example
498 * socket.prependAny((event, ...args) => {
499 * console.log(`got event ${event}`);
500 * });
501 *
502 * @param listener
503 */
504 prependAny(listener: (...args: any[]) => void): this;
505 /**
506 * Removes the listener that will be fired when any event is emitted.
507 *
508 * @example
509 * const catchAllListener = (event, ...args) => {
510 * console.log(`got event ${event}`);
511 * }
512 *
513 * socket.onAny(catchAllListener);
514 *
515 * // remove a specific listener
516 * socket.offAny(catchAllListener);
517 *
518 * // or remove all listeners
519 * socket.offAny();
520 *
521 * @param listener
522 */
523 offAny(listener?: (...args: any[]) => void): this;
524 /**
525 * Returns an array of listeners that are listening for any event that is specified. This array can be manipulated,
526 * e.g. to remove listeners.
527 */
528 listenersAny(): ((...args: any[]) => void)[];
529 /**
530 * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
531 * callback.
532 *
533 * Note: acknowledgements sent to the server are not included.
534 *
535 * @example
536 * socket.onAnyOutgoing((event, ...args) => {
537 * console.log(`sent event ${event}`);
538 * });
539 *
540 * @param listener
541 */
542 onAnyOutgoing(listener: (...args: any[]) => void): this;
543 /**
544 * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
545 * callback. The listener is added to the beginning of the listeners array.
546 *
547 * Note: acknowledgements sent to the server are not included.
548 *
549 * @example
550 * socket.prependAnyOutgoing((event, ...args) => {
551 * console.log(`sent event ${event}`);
552 * });
553 *
554 * @param listener
555 */
556 prependAnyOutgoing(listener: (...args: any[]) => void): this;
557 /**
558 * Removes the listener that will be fired when any event is emitted.
559 *
560 * @example
561 * const catchAllListener = (event, ...args) => {
562 * console.log(`sent event ${event}`);
563 * }
564 *
565 * socket.onAnyOutgoing(catchAllListener);
566 *
567 * // remove a specific listener
568 * socket.offAnyOutgoing(catchAllListener);
569 *
570 * // or remove all listeners
571 * socket.offAnyOutgoing();
572 *
573 * @param [listener] - the catch-all listener (optional)
574 */
575 offAnyOutgoing(listener?: (...args: any[]) => void): this;
576 /**
577 * Returns an array of listeners that are listening for any event that is specified. This array can be manipulated,
578 * e.g. to remove listeners.
579 */
580 listenersAnyOutgoing(): ((...args: any[]) => void)[];
581 /**
582 * Notify the listeners for each packet sent
583 *
584 * @param packet
585 *
586 * @private
587 */
588 private notifyOutgoingListeners;
589}
590export declare namespace Socket {
591 type DisconnectReason = "io server disconnect" | "io client disconnect" | "ping timeout" | "transport close" | "transport error" | "parse error";
592}
593export {};
594
\No newline at end of file