From 9b013b00c90e1e66f45e9385c68432041b943d87 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 16 Aug 2026 07:00:39 +0000 Subject: [PATCH 1/2] feat(providers): support custom request headers for WsProvider Add a `headers` option to `WsProviderOptions` so custom HTTP headers (e.g: an auth token for a private RPC endpoint or proxy) can be sent along with the websocket opening handshake. Headers can be provided either as a static map or as a function that is resolved on every connection attempt (including reconnects), which is helpful to refresh short-lived tokens or to use different credentials per endpoint. The headers are passed as an options object in the second constructor argument, which is supported by both the `ws` package (used by `@polkadot/x-ws` on Node.js < 22) and the native WebSocket implementation (Node.js >= 22, Bun). Browsers and Deno follow the WHATWG spec where the second argument is a list of subprotocols, so headers are ignored there with a warning. Closes #751 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Cpx2P4VETQHZ3hXGphLUAy --- packages/providers/README.md | 34 ++++- packages/providers/package.json | 4 +- .../providers/src/__tests__/utils.spec.ts | 30 +++- packages/providers/src/utils.ts | 21 +++ packages/providers/src/ws/WsProvider.ts | 95 ++++++++++++- .../src/ws/__tests__/WsProvider.spec.ts | 132 +++++++++++++++++- .../ws/__tests__/WsProviderHeaders.spec.ts | 79 +++++++++++ yarn.lock | 11 ++ 8 files changed, 398 insertions(+), 8 deletions(-) create mode 100644 packages/providers/src/ws/__tests__/WsProviderHeaders.spec.ts diff --git a/packages/providers/README.md b/packages/providers/README.md index f86adf640..7946598c7 100644 --- a/packages/providers/README.md +++ b/packages/providers/README.md @@ -2,4 +2,36 @@ JSON-RPC Providers - +## Custom request headers (`WsProvider`) + +Custom HTTP headers can be sent along with the websocket opening handshake, +e.g: to authenticate with a private RPC endpoint or proxy. + +```ts +import { WsProvider } from '@dedot/providers'; + +const provider = new WsProvider({ + endpoint: 'wss://private.rpc', + headers: { + Authorization: `Bearer ${process.env.API_TOKEN}`, + 'X-Client-ID': 'example-client', + }, +}); +``` + +Headers can also be resolved on each connection attempt (including reconnects), +which is helpful to refresh short-lived tokens or to use different credentials per endpoint: + +```ts +const provider = new WsProvider({ + endpoint: ['wss://private.rpc', 'wss://private-backup.rpc'], + headers: async ({ attempt, currentEndpoint }) => ({ + Authorization: `Bearer ${await fetchToken(currentEndpoint)}`, + }), +}); +``` + +> [!NOTE] +> Custom headers are only supported in non-browser environments (Node.js, Bun). +> Browsers do not allow setting headers for the websocket opening handshake, +> the headers are ignored and a warning is logged in that case. diff --git a/packages/providers/package.json b/packages/providers/package.json index 20301292d..6bc2e12d8 100644 --- a/packages/providers/package.json +++ b/packages/providers/package.json @@ -26,8 +26,10 @@ "directory": "dist" }, "devDependencies": { + "@types/ws": "^8.5.12", "mock-socket": "^9.3.1", - "smoldot": "^2.0.40" + "smoldot": "^2.0.40", + "ws": "^8.18.0" }, "engines": { "node": ">=18" diff --git a/packages/providers/src/__tests__/utils.spec.ts b/packages/providers/src/__tests__/utils.spec.ts index f042254cc..b82061f4a 100644 --- a/packages/providers/src/__tests__/utils.spec.ts +++ b/packages/providers/src/__tests__/utils.spec.ts @@ -1,6 +1,6 @@ import { DedotError } from '@dedot/utils'; -import { describe, expect, it } from 'vitest'; -import { pickRandomItem, validateEndpoint } from '../utils.js'; +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { canSendRequestHeaders, pickRandomItem, validateEndpoint } from '../utils.js'; describe('utils', () => { describe('validateEndpoint', () => { @@ -157,4 +157,30 @@ describe('utils', () => { }); }); }); + + describe('canSendRequestHeaders', () => { + afterEach(() => { + vi.unstubAllGlobals(); + }); + + it('returns true on Node.js', () => { + // Tests are running on Node.js, `process.versions.node` is available + expect(canSendRequestHeaders()).toBe(true); + }); + + it('returns true on Bun', () => { + vi.stubGlobal('process', { versions: { bun: '1.2.0' } }); + expect(canSendRequestHeaders()).toBe(true); + }); + + it('returns false on Deno', () => { + vi.stubGlobal('Deno', {}); + expect(canSendRequestHeaders()).toBe(false); + }); + + it('returns false in browsers', () => { + vi.stubGlobal('process', undefined); + expect(canSendRequestHeaders()).toBe(false); + }); + }); }); diff --git a/packages/providers/src/utils.ts b/packages/providers/src/utils.ts index d734a11d9..ef4d0df2f 100644 --- a/packages/providers/src/utils.ts +++ b/packages/providers/src/utils.ts @@ -21,6 +21,27 @@ export function pickRandomItem(items: T[], excludeItem?: T): T { return finalItems[Math.floor(Math.random() * finalItems.length)]; } +/** + * Check whether the current runtime is able to send custom headers + * along with the websocket opening handshake. + * + * Both the `ws` package (used on Node.js < 22) and the native `WebSocket` + * implementation (Node.js >= 22, Bun) accept an options object as the second + * constructor argument. Browsers (and Deno) follow the WHATWG spec where the + * second argument is a list of subprotocols, so custom headers cannot be set there. + */ +export function canSendRequestHeaders(): boolean { + const global = globalThis as any; + + // Deno exposes `process.versions.node` for compatibility reasons, + // but its WebSocket implementation follows the WHATWG spec + if (global.Deno) return false; + + const versions = global.process?.versions; + + return !!(versions?.node || versions?.bun); +} + /** * Validate that an endpoint is properly formatted */ diff --git a/packages/providers/src/ws/WsProvider.ts b/packages/providers/src/ws/WsProvider.ts index a34ccab3b..bad6bcd45 100644 --- a/packages/providers/src/ws/WsProvider.ts +++ b/packages/providers/src/ws/WsProvider.ts @@ -3,7 +3,7 @@ import { assert, DedotError, deferred, Deferred } from '@dedot/utils'; import { SubscriptionProvider } from '../base/index.js'; import { MaxRetryAttemptedError, NetworkDisconnectedError } from '../error.js'; import { JsonRpcRequest } from '../types.js'; -import { pickRandomItem, validateEndpoint } from '../utils.js'; +import { canSendRequestHeaders, pickRandomItem, validateEndpoint } from '../utils.js'; export interface WsConnectionState { /** @@ -25,6 +25,18 @@ export interface WsConnectionState { */ export type WsEndpointSelector = (info: WsConnectionState) => string | Promise; +/** + * A map of custom HTTP headers to send along with the websocket opening handshake + */ +export type WsRequestHeaders = Record; + +/** + * Function that returns the request headers to use for a connection attempt + * @param info Connection attempt information + * @returns The headers to send along with the websocket opening handshake + */ +export type WsHeadersSelector = (info: WsConnectionState) => WsRequestHeaders | Promise; + export interface WsProviderOptions { /** * The websocket endpoint to connect to. Can be: @@ -62,8 +74,30 @@ export interface WsProviderOptions { * @default 30000 */ timeout?: number; + /** + * Custom HTTP headers to send along with the websocket opening handshake, + * e.g: an auth token for a private RPC endpoint or proxy. + * + * Can be either a static map of headers or a function returning the headers, + * the function is called on every connection attempt (including reconnects), + * which is helpful to refresh short-lived tokens or to use different + * credentials per endpoint. + * + * Note: Custom headers are only supported in non-browser environments (Node.js, Bun), + * browsers do not allow setting headers for the websocket opening handshake. + * A warning will be logged and the headers ignored if the environment does not support this. + * + * @default undefined + */ + headers?: WsRequestHeaders | WsHeadersSelector; } +/** + * Constructor signature of websocket implementations accepting connection options, + * e.g: the `ws` package (Node.js < 22) or the native WebSocket implementation (Node.js >= 22, Bun) + */ +type WebSocketWithOptions = new (url: string, options: { headers: WsRequestHeaders }) => WebSocket; + const DEFAULT_OPTIONS: Partial = { retryDelayMs: 2500, timeout: 30_000, @@ -102,6 +136,21 @@ const NO_RESUBSCRIBE_PREFIXES = ['author_', 'chainHead_', 'transactionWatch_']; * return info.attempt >= 3 ? 'wss://backup.rpc' : 'wss://primary.rpc'; * }); * + * // With custom request headers (Node.js/Bun only), e.g: to authenticate with a private RPC + * const provider = new WsProvider({ + * endpoint: 'wss://private.rpc', + * headers: { + * Authorization: `Bearer ${process.env.API_TOKEN}`, + * 'X-Client-ID': 'example-client', + * }, + * }); + * + * // Headers can also be resolved on each connection attempt (e.g: to refresh short-lived tokens) + * const provider = new WsProvider({ + * endpoint: 'wss://private.rpc', + * headers: async () => ({ Authorization: `Bearer ${await fetchToken()}` }), + * }); + * * await provider.connect(); * * // Fetch the genesis hash @@ -137,6 +186,9 @@ export class WsProvider extends SubscriptionProvider { // Recovering promise for request queueing during reconnection #recovering?: Deferred; + // Only warn once per provider instance if custom headers are not supported by the environment + #headersUnsupportedWarned: boolean = false; + constructor(options: WsProviderOptions | string | string[] | WsEndpointSelector) { super(); @@ -221,13 +273,52 @@ export class WsProvider extends SubscriptionProvider { return endpoint; } + /** + * Get the custom request headers for the current connection attempt, + * either directly or by calling the headers selector function + * + * @returns The headers to use, or `undefined` if no headers should be sent + */ + async #getHeaders(): Promise { + const { headers } = this.#options; + if (!headers) return undefined; + + if (!canSendRequestHeaders()) { + if (!this.#headersUnsupportedWarned) { + this.#headersUnsupportedWarned = true; + console.warn( + 'Custom websocket request headers are not supported in this environment (e.g: browsers), headers will be ignored', + ); + } + + return undefined; + } + + const info: WsConnectionState = { + attempt: this.#attempt, + currentEndpoint: this.#currentEndpoint, + }; + + const resolved = typeof headers === 'function' ? await headers(info) : headers; + if (!resolved || Object.keys(resolved).length === 0) return undefined; + + return resolved; + } + async #doConnect() { assert(!this.#ws, 'Websocket connection already exists'); try { this.#currentEndpoint = await this.#getEndpoint(); - this.#ws = new WebSocket(this.#currentEndpoint); + const headers = await this.#getHeaders(); + + // Both the `ws` package and the native WebSocket implementation (Node.js >= 22, Bun) + // accept an options object as the second constructor argument, + // the type definitions from `@polkadot/x-ws` only expose the WHATWG (browser) signature + this.#ws = headers + ? new (WebSocket as unknown as WebSocketWithOptions)(this.#currentEndpoint, { headers }) + : new WebSocket(this.#currentEndpoint); this.#ws.onopen = this.#onSocketOpen; this.#ws.onclose = this.#onSocketClose; this.#ws.onmessage = this.#onSocketMessage; diff --git a/packages/providers/src/ws/__tests__/WsProvider.spec.ts b/packages/providers/src/ws/__tests__/WsProvider.spec.ts index d4bcaced4..783d3e7bf 100644 --- a/packages/providers/src/ws/__tests__/WsProvider.spec.ts +++ b/packages/providers/src/ws/__tests__/WsProvider.spec.ts @@ -11,15 +11,32 @@ process.on('unhandledRejection', (reason) => { const FAKE_WS_URL = 'ws://127.0.0.1:9944'; +// Records the arguments each websocket is constructed with, so we can verify +// what is being passed down to the underlying websocket implementation +const { capturedWsArgs } = vi.hoisted(() => ({ capturedWsArgs: [] as any[][] })); + vi.mock('@polkadot/x-ws', async (importOriginal) => { - const { WebSocket } = await import('mock-socket'); + const { WebSocket: MockWebSocket } = await import('mock-socket'); const mod = await importOriginal(); + + class CapturingWebSocket extends MockWebSocket { + constructor(url: string, ...rest: any[]) { + capturedWsArgs.push([url, ...rest]); + + // mock-socket only understands the (url, protocols) signature, + // so extra arguments are dropped before handing over to it + super(url); + } + } + return { ...mod, - WebSocket, + WebSocket: CapturingWebSocket, }; }); +const lastWsArgs = () => capturedWsArgs[capturedWsArgs.length - 1]; + describe('WsProvider', () => { let mockServer: Server; const FAKE_WS_URL_2 = 'ws://127.0.0.1:9945'; @@ -707,4 +724,115 @@ describe('WsProvider', () => { }); }); }); + + describe('Request Headers', () => { + beforeEach(() => { + capturedWsArgs.length = 0; + }); + + it('does not pass any options when no headers are provided', async () => { + const provider = new WsProvider(FAKE_WS_URL); + + try { + await provider.connect(); + + expect(lastWsArgs()).toEqual([FAKE_WS_URL]); + } finally { + await provider.disconnect().catch(() => {}); + } + }); + + it('passes static headers to the websocket implementation', async () => { + const headers = { Authorization: 'Bearer token', 'X-Client-ID': 'example-client' }; + const provider = new WsProvider({ endpoint: FAKE_WS_URL, headers }); + + try { + await provider.connect(); + + expect(lastWsArgs()).toEqual([FAKE_WS_URL, { headers }]); + } finally { + await provider.disconnect().catch(() => {}); + } + }); + + it('resolves headers via a selector function receiving the connection state', async () => { + const selector = vi.fn().mockResolvedValue({ Authorization: 'Bearer resolved-token' }); + const provider = new WsProvider({ endpoint: FAKE_WS_URL, headers: selector }); + + try { + await provider.connect(); + + expect(selector).toHaveBeenCalledTimes(1); + expect(selector).toHaveBeenCalledWith({ attempt: 1, currentEndpoint: FAKE_WS_URL }); + expect(lastWsArgs()).toEqual([FAKE_WS_URL, { headers: { Authorization: 'Bearer resolved-token' } }]); + } finally { + await provider.disconnect().catch(() => {}); + } + }); + + it('resolves headers again on each reconnection', async () => { + let token = 0; + const selector = vi.fn().mockImplementation(() => ({ Authorization: `Bearer token-${++token}` })); + + const provider = new WsProvider({ + endpoint: FAKE_WS_URL, + headers: selector, + retryDelayMs: 100, + }); + + provider.on('error', () => { + // Intentionally empty + }); + + try { + await provider.connect(); + expect(lastWsArgs()).toEqual([FAKE_WS_URL, { headers: { Authorization: 'Bearer token-1' } }]); + + // Simulate an abnormal disconnection to trigger a reconnect + (provider as any).__unsafeWs().close(3000); + await new Promise((resolve) => setTimeout(resolve, 200)); + + expect(provider.status).toBe('connected'); + expect(selector).toHaveBeenCalledTimes(2); + expect(lastWsArgs()).toEqual([FAKE_WS_URL, { headers: { Authorization: 'Bearer token-2' } }]); + } finally { + await provider.disconnect().catch(() => {}); + } + }); + + it('ignores an empty headers map', async () => { + const provider = new WsProvider({ endpoint: FAKE_WS_URL, headers: {} }); + + try { + await provider.connect(); + + expect(lastWsArgs()).toEqual([FAKE_WS_URL]); + } finally { + await provider.disconnect().catch(() => {}); + } + }); + + it('ignores headers & warns if the environment does not support them', async () => { + const consoleWarn = vi.spyOn(console, 'warn').mockImplementation(() => {}); + + // Deno follows the WHATWG spec where custom headers cannot be set + vi.stubGlobal('Deno', {}); + + const provider = new WsProvider({ + endpoint: FAKE_WS_URL, + headers: { Authorization: 'Bearer token' }, + }); + + try { + await provider.connect(); + + expect(lastWsArgs()).toEqual([FAKE_WS_URL]); + expect(consoleWarn).toHaveBeenCalledWith(expect.stringContaining('not supported in this environment')); + } finally { + vi.unstubAllGlobals(); + consoleWarn.mockRestore(); + await provider.disconnect().catch(() => {}); + } + }); + }); }); diff --git a/packages/providers/src/ws/__tests__/WsProviderHeaders.spec.ts b/packages/providers/src/ws/__tests__/WsProviderHeaders.spec.ts new file mode 100644 index 000000000..4e164277b --- /dev/null +++ b/packages/providers/src/ws/__tests__/WsProviderHeaders.spec.ts @@ -0,0 +1,79 @@ +// @vitest-environment node +import { IncomingHttpHeaders } from 'node:http'; +import { afterAll, beforeAll, describe, expect, it } from 'vitest'; +import { WebSocketServer } from 'ws'; +import { WsProvider } from '../WsProvider.js'; + +/** + * Unlike WsProvider.spec.ts, this suite does not mock the underlying websocket implementation, + * it verifies that custom headers are actually sent over the wire with the opening handshake, + * regardless of whether `@polkadot/x-ws` resolves to the `ws` package (Node.js < 22) + * or the native WebSocket implementation (Node.js >= 22). + * + * A `node` environment is required here, the default `happy-dom` environment + * provides its own global WebSocket which does not support custom headers. + */ +describe('WsProvider request headers (real websocket server)', () => { + let server: WebSocketServer; + let endpoint: string; + let receivedHeaders: IncomingHttpHeaders; + + beforeAll(async () => { + server = new WebSocketServer({ port: 0 }); + + server.on('connection', (socket, request) => { + receivedHeaders = request.headers; + + socket.on('message', (data) => { + const { id } = JSON.parse(data.toString()); + socket.send(JSON.stringify({ id, jsonrpc: '2.0', result: 'ok' })); + }); + }); + + await new Promise((resolve) => server.once('listening', resolve)); + + const { port } = server.address() as { port: number }; + endpoint = `ws://127.0.0.1:${port}`; + }); + + afterAll(async () => { + await new Promise((resolve) => server.close(() => resolve())); + }); + + it('sends custom headers with the opening handshake', async () => { + const provider = new WsProvider({ + endpoint, + headers: { + Authorization: 'Bearer secret-token', + 'X-Client-ID': 'example-client', + }, + }); + + try { + await provider.connect(); + + expect(receivedHeaders['authorization']).toBe('Bearer secret-token'); + expect(receivedHeaders['x-client-id']).toBe('example-client'); + + // Make sure the connection is fully functional with headers attached + await expect(provider.send('test_method', [])).resolves.toBe('ok'); + } finally { + await provider.disconnect().catch(() => {}); + } + }); + + it('sends no custom headers & no bogus subprotocol when headers are not provided', async () => { + const provider = new WsProvider(endpoint); + + try { + await provider.connect(); + + expect(receivedHeaders['authorization']).toBeUndefined(); + expect(receivedHeaders['sec-websocket-protocol']).toBeUndefined(); + + await expect(provider.send('test_method', [])).resolves.toBe('ok'); + } finally { + await provider.disconnect().catch(() => {}); + } + }); +}); diff --git a/yarn.lock b/yarn.lock index 5d249c744..8e5858be9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -394,8 +394,10 @@ __metadata: dependencies: "@dedot/utils": "npm:^1.3.0" "@polkadot/x-ws": "npm:^14.0.1" + "@types/ws": "npm:^8.5.12" mock-socket: "npm:^9.3.1" smoldot: "npm:^2.0.40" + ws: "npm:^8.18.0" languageName: unknown linkType: soft @@ -2228,6 +2230,15 @@ __metadata: languageName: node linkType: hard +"@types/ws@npm:^8.5.12": + version: 8.18.1 + resolution: "@types/ws@npm:8.18.1" + dependencies: + "@types/node": "npm:*" + checksum: 10c0/61aff1129143fcc4312f083bc9e9e168aa3026b7dd6e70796276dcfb2c8211c4292603f9c4864fae702f2ed86e4abd4d38aa421831c2fd7f856c931a481afbab + languageName: node + linkType: hard + "@types/yargs-parser@npm:*": version: 21.0.3 resolution: "@types/yargs-parser@npm:21.0.3" From fa210856659d227e2b9d4377f945cdc59894342b Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 20 Aug 2026 02:28:49 +0000 Subject: [PATCH 2/2] test(providers): drop ws devDependency from headers test `@polkadot/x-ws` only ships a websocket client, so the previous test relied on the `ws` package for a server. Use a minimal handshake-only server built on `node:http` instead, keeping the test dependency-free while still exercising the real websocket implementation. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Cpx2P4VETQHZ3hXGphLUAy --- packages/providers/package.json | 4 +- .../ws/__tests__/WsProviderHeaders.spec.ts | 54 +++++++++++++------ yarn.lock | 11 ---- 3 files changed, 38 insertions(+), 31 deletions(-) diff --git a/packages/providers/package.json b/packages/providers/package.json index 6bc2e12d8..20301292d 100644 --- a/packages/providers/package.json +++ b/packages/providers/package.json @@ -26,10 +26,8 @@ "directory": "dist" }, "devDependencies": { - "@types/ws": "^8.5.12", "mock-socket": "^9.3.1", - "smoldot": "^2.0.40", - "ws": "^8.18.0" + "smoldot": "^2.0.40" }, "engines": { "node": ">=18" diff --git a/packages/providers/src/ws/__tests__/WsProviderHeaders.spec.ts b/packages/providers/src/ws/__tests__/WsProviderHeaders.spec.ts index 4e164277b..681542876 100644 --- a/packages/providers/src/ws/__tests__/WsProviderHeaders.spec.ts +++ b/packages/providers/src/ws/__tests__/WsProviderHeaders.spec.ts @@ -1,35 +1,59 @@ // @vitest-environment node -import { IncomingHttpHeaders } from 'node:http'; +import { createHash } from 'node:crypto'; +import { createServer, IncomingHttpHeaders, Server } from 'node:http'; +import { Socket } from 'node:net'; import { afterAll, beforeAll, describe, expect, it } from 'vitest'; -import { WebSocketServer } from 'ws'; import { WsProvider } from '../WsProvider.js'; +// https://datatracker.ietf.org/doc/html/rfc6455#section-1.3 +const WS_GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; + +const acceptKey = (key: string = '') => { + return createHash('sha1') + .update(key + WS_GUID) + .digest('base64'); +}; + /** * Unlike WsProvider.spec.ts, this suite does not mock the underlying websocket implementation, * it verifies that custom headers are actually sent over the wire with the opening handshake, * regardless of whether `@polkadot/x-ws` resolves to the `ws` package (Node.js < 22) - * or the native WebSocket implementation (Node.js >= 22). + * or the native WebSocket implementation (Node.js >= 22, Bun). + * + * A minimal handshake-only server is used here so that no extra dependency is needed, + * `@polkadot/x-ws` only ships a websocket client. * - * A `node` environment is required here, the default `happy-dom` environment + * A `node` environment is required, the default `happy-dom` environment * provides its own global WebSocket which does not support custom headers. */ -describe('WsProvider request headers (real websocket server)', () => { - let server: WebSocketServer; +describe('WsProvider request headers (real websocket handshake)', () => { + let server: Server; let endpoint: string; + let sockets: Socket[] = []; let receivedHeaders: IncomingHttpHeaders; beforeAll(async () => { - server = new WebSocketServer({ port: 0 }); + server = createServer(); - server.on('connection', (socket, request) => { + server.on('upgrade', (request, socket) => { receivedHeaders = request.headers; + sockets.push(socket as Socket); - socket.on('message', (data) => { - const { id } = JSON.parse(data.toString()); - socket.send(JSON.stringify({ id, jsonrpc: '2.0', result: 'ok' })); - }); + // Ignore errors from clients going away abruptly + socket.on('error', () => {}); + + socket.write( + [ + 'HTTP/1.1 101 Switching Protocols', + 'Upgrade: websocket', + 'Connection: Upgrade', + `Sec-WebSocket-Accept: ${acceptKey(request.headers['sec-websocket-key'])}`, + '\r\n', + ].join('\r\n'), + ); }); + server.listen(0); await new Promise((resolve) => server.once('listening', resolve)); const { port } = server.address() as { port: number }; @@ -37,6 +61,7 @@ describe('WsProvider request headers (real websocket server)', () => { }); afterAll(async () => { + sockets.forEach((socket) => socket.destroy()); await new Promise((resolve) => server.close(() => resolve())); }); @@ -54,9 +79,6 @@ describe('WsProvider request headers (real websocket server)', () => { expect(receivedHeaders['authorization']).toBe('Bearer secret-token'); expect(receivedHeaders['x-client-id']).toBe('example-client'); - - // Make sure the connection is fully functional with headers attached - await expect(provider.send('test_method', [])).resolves.toBe('ok'); } finally { await provider.disconnect().catch(() => {}); } @@ -70,8 +92,6 @@ describe('WsProvider request headers (real websocket server)', () => { expect(receivedHeaders['authorization']).toBeUndefined(); expect(receivedHeaders['sec-websocket-protocol']).toBeUndefined(); - - await expect(provider.send('test_method', [])).resolves.toBe('ok'); } finally { await provider.disconnect().catch(() => {}); } diff --git a/yarn.lock b/yarn.lock index 8e5858be9..5d249c744 100644 --- a/yarn.lock +++ b/yarn.lock @@ -394,10 +394,8 @@ __metadata: dependencies: "@dedot/utils": "npm:^1.3.0" "@polkadot/x-ws": "npm:^14.0.1" - "@types/ws": "npm:^8.5.12" mock-socket: "npm:^9.3.1" smoldot: "npm:^2.0.40" - ws: "npm:^8.18.0" languageName: unknown linkType: soft @@ -2230,15 +2228,6 @@ __metadata: languageName: node linkType: hard -"@types/ws@npm:^8.5.12": - version: 8.18.1 - resolution: "@types/ws@npm:8.18.1" - dependencies: - "@types/node": "npm:*" - checksum: 10c0/61aff1129143fcc4312f083bc9e9e168aa3026b7dd6e70796276dcfb2c8211c4292603f9c4864fae702f2ed86e4abd4d38aa421831c2fd7f856c931a481afbab - languageName: node - linkType: hard - "@types/yargs-parser@npm:*": version: 21.0.3 resolution: "@types/yargs-parser@npm:21.0.3"