From 0eac2b2a23860a77ce7792d510efa36f51c2537d Mon Sep 17 00:00:00 2001 From: yushen Date: Wed, 4 Feb 2026 13:27:23 +0800 Subject: [PATCH] feat(sdk): add auto-verify handshake after gateway registration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Embed transparent verification logic in GatewayClient that automatically sends an RPC "verify" request to the Hub after REGISTERED event. Adds hubId, token, and verifyTimeout options. Upper-layer callers see no change — "registered" state means both gateway registration and Hub verification are complete. Failures surface via onError callback. Co-Authored-By: Claude Opus 4.5 --- packages/sdk/src/actions/index.ts | 2 ++ packages/sdk/src/actions/rpc.ts | 11 ++++++++ packages/sdk/src/client.ts | 43 ++++++++++++++++++++++++++++--- packages/sdk/src/types.ts | 7 +++++ 4 files changed, 60 insertions(+), 3 deletions(-) diff --git a/packages/sdk/src/actions/index.ts b/packages/sdk/src/actions/index.ts index d9fb2b1b..6e010e37 100644 --- a/packages/sdk/src/actions/index.ts +++ b/packages/sdk/src/actions/index.ts @@ -25,6 +25,8 @@ export { type DeleteAgentResult, type UpdateGatewayParams, type UpdateGatewayResult, + type VerifyParams, + type VerifyResult, } from "./rpc"; export { diff --git a/packages/sdk/src/actions/rpc.ts b/packages/sdk/src/actions/rpc.ts index a81a15b1..7837644c 100644 --- a/packages/sdk/src/actions/rpc.ts +++ b/packages/sdk/src/actions/rpc.ts @@ -145,3 +145,14 @@ export interface UpdateGatewayResult { url: string; connectionState: string; } + +/** verify - request params */ +export interface VerifyParams { + token?: string; +} + +/** verify - response payload */ +export interface VerifyResult { + hubId: string; + agentId: string; +} diff --git a/packages/sdk/src/client.ts b/packages/sdk/src/client.ts index 836708eb..d87caffd 100644 --- a/packages/sdk/src/client.ts +++ b/packages/sdk/src/client.ts @@ -34,6 +34,9 @@ interface ResolvedOptions { deviceType: DeviceType; autoReconnect: boolean; reconnectDelay: number; + hubId: string | undefined; + token: string | undefined; + verifyTimeout: number; } export class GatewayClient { @@ -55,6 +58,9 @@ export class GatewayClient { deviceType: options.deviceType, autoReconnect: options.autoReconnect ?? true, reconnectDelay: options.reconnectDelay ?? 1000, + hubId: options.hubId, + token: options.token, + verifyTimeout: options.verifyTimeout ?? 30_000, }; } @@ -227,6 +233,12 @@ export class GatewayClient { return this; } + /** Hub 验证成功回调 */ + onVerified(callback: (result: { hubId: string; agentId: string }) => void): this { + this.callbacks.onVerified = callback; + return this; + } + /** 注册消息回调 */ onMessage(callback: (message: RoutedMessage) => void): this { this.callbacks.onMessage = callback; @@ -291,11 +303,36 @@ export class GatewayClient { this.socket.on( GatewayEvents.REGISTERED, (response: RegisteredResponse) => { - if (response.success) { + if (!response.success) { + this.callbacks.onError?.(new Error(response.error ?? "Registration failed")); + return; + } + + // If hubId is configured, auto-verify before exposing "registered" to upper layer + if (this.options.hubId) { + // Set internal state to allow send/request during verify + this._state = "registered"; + this.request<{ hubId: string; agentId: string }>( + this.options.hubId, + "verify", + { token: this.options.token }, + this.options.verifyTimeout, + ) + .then((result) => { + // Verify succeeded — now expose "registered" to upper layer + this.callbacks.onVerified?.(result); + this.callbacks.onRegistered?.(response.deviceId); + this.callbacks.onStateChange?.("registered"); + }) + .catch((err) => { + // Verify failed (UNAUTHORIZED, REJECTED, or timeout) + this.callbacks.onError?.(err instanceof Error ? err : new Error(String(err))); + this.disconnect(); + }); + } else { + // No hubId — original behavior this.setState("registered"); this.callbacks.onRegistered?.(response.deviceId); - } else { - this.callbacks.onError?.(new Error(response.error ?? "Registration failed")); } } ); diff --git a/packages/sdk/src/types.ts b/packages/sdk/src/types.ts index d0067591..88118021 100644 --- a/packages/sdk/src/types.ts +++ b/packages/sdk/src/types.ts @@ -89,6 +89,12 @@ export interface GatewayClientOptions { autoReconnect?: boolean | undefined; /** Reconnect delay (milliseconds), defaults to 1000 */ reconnectDelay?: number | undefined; + /** Hub device ID for verification (optional, enables auto-verify after gateway registration) */ + hubId?: string | undefined; + /** Token for first-time verification (optional, omit for reconnection via device whitelist) */ + token?: string | undefined; + /** Verify timeout in ms (default: 30_000, longer because user confirmation may be needed) */ + verifyTimeout?: number | undefined; } /** Connection state */ @@ -103,6 +109,7 @@ export interface GatewayClientCallbacks { onConnect?: (socketId: string) => void; onDisconnect?: (reason: string) => void; onRegistered?: (deviceId: string) => void; + onVerified?: (result: { hubId: string; agentId: string }) => void; onMessage?: (message: RoutedMessage) => void; onSendError?: (error: SendErrorResponse) => void; onPong?: (data: string) => void;