From 822d0bf730d977a29f3efd656421daccffe583a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=AC=EC=9A=B1?= Date: Thu, 19 Mar 2026 23:37:49 +0900 Subject: [PATCH 1/2] feat(sio): add ackTimeout option for broadcast emitWithAck --- packages/socket.io/lib/broadcast-operator.ts | 13 ++++++++++++- packages/socket.io/lib/index.ts | 4 ++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/socket.io/lib/broadcast-operator.ts b/packages/socket.io/lib/broadcast-operator.ts index ca7eccf2f..b2d9c127c 100644 --- a/packages/socket.io/lib/broadcast-operator.ts +++ b/packages/socket.io/lib/broadcast-operator.ts @@ -325,6 +325,14 @@ export class BroadcastOperator ev: Ev, ...args: AllButLast> ): Promise>>> { + const defaultTimeout = this.adapter.nsp.server?.opts?.ackTimeout; + const operator = + this.flags.timeout === undefined && defaultTimeout !== undefined + ? new BroadcastOperator(this.adapter, this.rooms, this.exceptRooms, { + ...this.flags, + timeout: defaultTimeout, + }) + : this; return new Promise((resolve, reject) => { args.push((err, responses) => { if (err) { @@ -334,7 +342,10 @@ export class BroadcastOperator return resolve(responses); } }); - this.emit(ev, ...(args as any[] as EventParams)); + (operator as this).emit( + ev, + ...(args as any[] as EventParams), + ); }); } diff --git a/packages/socket.io/lib/index.ts b/packages/socket.io/lib/index.ts index 0cebc9254..4855b83d2 100644 --- a/packages/socket.io/lib/index.ts +++ b/packages/socket.io/lib/index.ts @@ -94,6 +94,10 @@ interface ServerOptions extends EngineOptions, AttachOptions { * @default 45000 */ connectTimeout: number; + /** + * the default timeout in milliseconds used when waiting for an acknowledgement + */ + ackTimeout: number; /** * Whether to enable the recovery of connection state when a client temporarily disconnects. * From 6a83fc034e9031fed82fe846643012d741215f54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=AC=EC=9A=B1?= Date: Fri, 20 Mar 2026 08:06:16 +0900 Subject: [PATCH 2/2] feat(sio): add ackTimeout option and enable io/namespace emitWithAck --- packages/socket.io/lib/index.ts | 18 +++++++++++++++++- packages/socket.io/lib/namespace.ts | 18 ++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/packages/socket.io/lib/index.ts b/packages/socket.io/lib/index.ts index 4855b83d2..bfbf7a464 100644 --- a/packages/socket.io/lib/index.ts +++ b/packages/socket.io/lib/index.ts @@ -45,6 +45,7 @@ import { RemoveAcknowledgements, EventNamesWithAck, FirstNonErrorArg, + EventNamesWithError, } from "./typed-events"; import { patchAdapter, restoreAdapter, serveFile } from "./uws"; import corsMiddleware from "cors"; @@ -97,7 +98,7 @@ interface ServerOptions extends EngineOptions, AttachOptions { /** * the default timeout in milliseconds used when waiting for an acknowledgement */ - ackTimeout: number; + ackTimeout?: number; /** * Whether to enable the recovery of connection state when a client temporarily disconnects. * @@ -1090,6 +1091,21 @@ export class Server< return this.sockets.timeout(timeout); } + /** + * Emits an event and waits for an acknowledgement from all clients. + * + * @example + * const responses = await io.emitWithAck("some-event"); + * + * @return a Promise that will be fulfilled when all clients have acknowledged the event + */ + public emitWithAck>( + ev: Ev, + ...args: AllButLast> + ): Promise>>> { + return this.sockets.emitWithAck(ev, ...args); + } + /** * Returns the matching socket instances. * diff --git a/packages/socket.io/lib/namespace.ts b/packages/socket.io/lib/namespace.ts index 72df7301e..ae2ca0335 100644 --- a/packages/socket.io/lib/namespace.ts +++ b/packages/socket.io/lib/namespace.ts @@ -14,6 +14,7 @@ import { EventNamesWithAck, FirstNonErrorArg, EventNamesWithoutAck, + EventNamesWithError, } from "./typed-events"; import type { Client } from "./client"; import debugModule from "debug"; @@ -469,6 +470,23 @@ export class Namespace< ); } + /** + * Emits an event and waits for an acknowledgement from all clients. + * + * @example + * const responses = await myNamespace.emitWithAck("some-event"); + * + * @return a Promise that will be fulfilled when all clients have acknowledged the event + */ + public emitWithAck>( + ev: Ev, + ...args: AllButLast> + ): Promise>>> { + return new BroadcastOperator( + this.adapter, + ).emitWithAck(ev, ...args); + } + /** * Sends a `message` event to all clients. *