From ae6e1fa4d2d527a362b142bed30a36093100af11 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Fri, 19 Jun 2026 05:27:52 +0200 Subject: [PATCH] fix(sdk): settle connect after observer errors --- packages/sdk/src/transport.test.ts | 36 ++++++++++++++++++++++++++++++ packages/sdk/src/transport.ts | 30 +++++++++++++++---------- 2 files changed, 54 insertions(+), 12 deletions(-) diff --git a/packages/sdk/src/transport.test.ts b/packages/sdk/src/transport.test.ts index 55f98c333028..48bacfd83014 100644 --- a/packages/sdk/src/transport.test.ts +++ b/packages/sdk/src/transport.test.ts @@ -59,4 +59,40 @@ describe("GatewayClientTransport", () => { await expect(transport.connect()).rejects.toThrow("gateway transport is closed"); expect(gatewayClientMocks.instances).toHaveLength(0); }); + + it("resolves connect when a hello observer throws", async () => { + const onHelloOk = vi.fn(() => { + throw new Error("hello observer failed"); + }); + const transport = new GatewayClientTransport({ onHelloOk }); + + const connect = transport.connect(); + const client = gatewayClientMocks.instances[0]; + + expect(() => client?.opts.onHelloOk?.({ sessionId: "session-1" })).toThrow( + "hello observer failed", + ); + + await expect(connect).resolves.toBeUndefined(); + expect(onHelloOk).toHaveBeenCalledWith({ sessionId: "session-1" }); + }); + + it("rejects connect when a connect-error observer throws", async () => { + const onConnectError = vi.fn(() => { + throw new Error("connect observer failed"); + }); + const transport = new GatewayClientTransport({ onConnectError }); + + const connect = transport.connect(); + const connectExpectation = expect(connect).rejects.toThrow("gateway rejected"); + const client = gatewayClientMocks.instances[0]; + + expect(() => client?.opts.onConnectError?.(new Error("gateway rejected"))).toThrow( + "connect observer failed", + ); + + await connectExpectation; + expect(onConnectError).toHaveBeenCalledOnce(); + expect(client?.stopAndWait).toHaveBeenCalledTimes(1); + }); }); diff --git a/packages/sdk/src/transport.ts b/packages/sdk/src/transport.ts index a92c40d24e90..4e1a5acb68b3 100644 --- a/packages/sdk/src/transport.ts +++ b/packages/sdk/src/transport.ts @@ -103,21 +103,27 @@ export class GatewayClientTransport implements ConnectableOpenClawTransport { this.options.onEvent?.(normalized); }, onHelloOk: (_hello: unknown) => { - this.options.onHelloOk?.(_hello); - this.rejectPendingConnect = null; - resolve(); + try { + this.options.onHelloOk?.(_hello); + } finally { + this.rejectPendingConnect = null; + resolve(); + } }, onConnectError: (error: Error) => { - this.options.onConnectError?.(error); - if (this.client === client) { - this.client = null; + try { + this.options.onConnectError?.(error); + } finally { + if (this.client === client) { + this.client = null; + } + if (this.connectPromise) { + this.connectPromise = null; + } + void client.stopAndWait().catch(() => {}); + this.rejectPendingConnect = null; + reject(error); } - if (this.connectPromise) { - this.connectPromise = null; - } - void client.stopAndWait().catch(() => {}); - this.rejectPendingConnect = null; - reject(error); }, onReconnectPaused: this.options.onReconnectPaused, onClose: this.options.onClose,