From 6b099a9ebc45bad71f30fc2425472d4e9eb07c8a Mon Sep 17 00:00:00 2001 From: ghzhost Date: Mon, 24 Aug 2026 09:46:18 +0000 Subject: [PATCH] feat(listen-key): implement delete listen key endpoint Closes #25 Implements the DELETE /openApi/user/auth/userDataStream endpoint following the pattern used by BingxExtendListenKeyEndpoint. Changes: - Add BingxDeleteListenKeyEndpoint class with method=delete, correct path, and listenKey param signed via DefaultSignatureParameters - Export new endpoint from src/bingx/endpoints/index.ts - Add deleteListenKey(listenKey, account) method to ListenKeyService - Unit tests: 3 tests for endpoint, 1 test for service method (4 passing) --- .../services/listen-key.service.spec.ts | 22 ++++++++++++ .../services/listen-key.service.ts | 7 ++++ .../bingx-delete-listen-key-endpoint.spec.ts | 21 +++++++++++ .../bingx-delete-listen-key-endpoint.ts | 35 +++++++++++++++++++ src/bingx/endpoints/index.ts | 1 + 5 files changed, 86 insertions(+) create mode 100644 src/bingx-client/services/listen-key.service.spec.ts create mode 100644 src/bingx/endpoints/bingx-delete-listen-key-endpoint.spec.ts create mode 100644 src/bingx/endpoints/bingx-delete-listen-key-endpoint.ts diff --git a/src/bingx-client/services/listen-key.service.spec.ts b/src/bingx-client/services/listen-key.service.spec.ts new file mode 100644 index 0000000..068ce73 --- /dev/null +++ b/src/bingx-client/services/listen-key.service.spec.ts @@ -0,0 +1,22 @@ +import { AccountInterface } from 'bingx-api/bingx/account/account.interface'; +import { BingxDeleteListenKeyEndpoint } from 'bingx-api/bingx/endpoints/bingx-delete-listen-key-endpoint'; +import { ListenKeyService } from 'bingx-api/bingx-client/services/listen-key.service'; +import { RequestExecutorInterface } from 'bingx-api/bingx/request-executor/request-executor.interface'; + +describe('listen key service', () => { + const account = {} as AccountInterface; + let execute: jest.Mock; + let service: ListenKeyService; + + beforeEach(() => { + execute = jest.fn().mockResolvedValue(undefined); + service = new ListenKeyService({ execute } as RequestExecutorInterface); + }); + + it('deletes a listen key using the delete listen key endpoint', async () => { + await service.deleteListenKey('listen-key', account); + + expect(execute).toHaveBeenCalledTimes(1); + expect(execute.mock.calls[0][0]).toBeInstanceOf(BingxDeleteListenKeyEndpoint); + }); +}); diff --git a/src/bingx-client/services/listen-key.service.ts b/src/bingx-client/services/listen-key.service.ts index 6535d93..04d64c9 100644 --- a/src/bingx-client/services/listen-key.service.ts +++ b/src/bingx-client/services/listen-key.service.ts @@ -1,4 +1,5 @@ import { AccountInterface } from 'bingx-api/bingx/account/account.interface'; +import { BingxDeleteListenKeyEndpoint } from 'bingx-api/bingx/endpoints/bingx-delete-listen-key-endpoint'; import { BingxGenerateListenKeyEndpoint } from 'bingx-api/bingx/endpoints/bingx-generate-listen-key-endpoint'; import { BingxGenerateListenKeyResponse } from 'bingx-api/bingx/endpoints/bingx-generate-listen-key-response'; import { RequestExecutorInterface } from 'bingx-api/bingx/request-executor/request-executor.interface'; @@ -13,4 +14,10 @@ export class ListenKeyService { new BingxGenerateListenKeyEndpoint(account), ); } + + async deleteListenKey(listenKey: string, account: AccountInterface): Promise { + return this.requestExecutor.execute( + new BingxDeleteListenKeyEndpoint(listenKey, account), + ); + } } diff --git a/src/bingx/endpoints/bingx-delete-listen-key-endpoint.spec.ts b/src/bingx/endpoints/bingx-delete-listen-key-endpoint.spec.ts new file mode 100644 index 0000000..372d318 --- /dev/null +++ b/src/bingx/endpoints/bingx-delete-listen-key-endpoint.spec.ts @@ -0,0 +1,21 @@ +import { ApiAccount } from 'bingx-api/bingx/account/api-account'; +import { BingxDeleteListenKeyEndpoint } from 'bingx-api/bingx/endpoints/bingx-delete-listen-key-endpoint'; + +describe('bingx delete listen key endpoint', () => { + const account = new ApiAccount('api-key', 'secret-key'); + const endpoint = new BingxDeleteListenKeyEndpoint('listen-key', account); + + it('uses the delete HTTP method', () => { + expect(endpoint.method()).toBe('delete'); + }); + + it('uses the user data stream path', () => { + expect(endpoint.path()).toBe('/openApi/user/auth/userDataStream'); + }); + + it('includes the listen key in signed parameters', () => { + expect(endpoint.parameters().asRecord()).toMatchObject({ + listenKey: 'listen-key', + }); + }); +}); diff --git a/src/bingx/endpoints/bingx-delete-listen-key-endpoint.ts b/src/bingx/endpoints/bingx-delete-listen-key-endpoint.ts new file mode 100644 index 0000000..75f2f2c --- /dev/null +++ b/src/bingx/endpoints/bingx-delete-listen-key-endpoint.ts @@ -0,0 +1,35 @@ +import { + AccountInterface, + DefaultSignatureParameters, + Endpoint, + EndpointInterface, + SignatureParametersInterface, +} from 'bingx-api/bingx'; + +export class BingxDeleteListenKeyEndpoint + extends Endpoint + implements EndpointInterface +{ + constructor( + private readonly listenKey: string, + account: AccountInterface, + ) { + super(account); + } + + method(): 'get' | 'post' | 'put' | 'patch' | 'delete' { + return 'delete'; + } + + parameters(): SignatureParametersInterface { + return new DefaultSignatureParameters({ + listenKey: this.listenKey, + }); + } + + path(): string { + return '/openApi/user/auth/userDataStream'; + } + + readonly t!: R; +} diff --git a/src/bingx/endpoints/index.ts b/src/bingx/endpoints/index.ts index 6866f8b..eab3777 100644 --- a/src/bingx/endpoints/index.ts +++ b/src/bingx/endpoints/index.ts @@ -1,5 +1,6 @@ export * from './bingx-cancel-all-orders-endpoint'; export * from './bingx-close-all-positions-endpoint'; +export * from './bingx-delete-listen-key-endpoint'; export * from './bingx-generate-listen-key-endpoint'; export * from './bingx-generate-listen-key-response'; export * from './bingx-get-perpetual-swap-account-asset-endpoint';