From 8d5c17e3f94c2660db0ac78b1ff5da1b3de9e561 Mon Sep 17 00:00:00 2001 From: Samuel Tinnerholm Date: Mon, 22 Jun 2026 06:35:24 +0000 Subject: [PATCH] fix(core): accept address websocket subscriptions Add watchAddress/unwatchAddress to the sidecar WebSocket method registry so methods declared as ws in method-verbs.json are not rejected before dispatch. Fixes #1177 --- core/src/server/ws-handler.ts | 2 ++ .../ws-handler-streaming-methods.test.ts | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 core/test/pipeline/ws-handler-streaming-methods.test.ts diff --git a/core/src/server/ws-handler.ts b/core/src/server/ws-handler.ts index bef1d94c..96d8638d 100644 --- a/core/src/server/ws-handler.ts +++ b/core/src/server/ws-handler.ts @@ -103,6 +103,7 @@ const WATCH_METHODS = new Set([ "watchOrderBook", "watchOrderBooks", "watchTrades", + "watchAddress", ]); /** Data-feed methods that produce streaming data. */ @@ -113,6 +114,7 @@ const FEED_WATCH_METHODS = new Set([ /** Methods for unsubscribing. */ const UNWATCH_METHODS: Record = { unwatchOrderBook: "watchOrderBook", + unwatchAddress: "watchAddress", }; function send(ws: WebSocket, msg: ServerEvent): void { diff --git a/core/test/pipeline/ws-handler-streaming-methods.test.ts b/core/test/pipeline/ws-handler-streaming-methods.test.ts new file mode 100644 index 00000000..0c2b7586 --- /dev/null +++ b/core/test/pipeline/ws-handler-streaming-methods.test.ts @@ -0,0 +1,26 @@ +import fs from 'fs'; +import path from 'path'; + +const repoRoot = path.resolve(__dirname, '../../..'); + +function read(relativePath: string): string { + return fs.readFileSync(path.join(repoRoot, relativePath), 'utf8'); +} + +describe('WebSocket streaming method registry', () => { + it('accepts every exchange method declared with the ws verb', () => { + const methodVerbConfig = JSON.parse(read('core/src/server/method-verbs.json')) as Record; + const wsHandler = read('core/src/server/ws-handler.ts'); + + const registeredMethodNames = new Set( + Array.from(wsHandler.matchAll(/(?:["'])(watch[A-Za-z]+|unwatch[A-Za-z]+)(?:["'])|\b(unwatch[A-Za-z]+)\s*:/g)) + .map((match) => match[1] || match[2]) + .filter(Boolean), + ); + const wsMethods = Object.entries(methodVerbConfig) + .filter(([, config]) => config.verb === 'ws') + .map(([method]) => method); + + expect(wsMethods.filter((method) => !registeredMethodNames.has(method))).toEqual([]); + }); +});