diff --git a/package-lock.json b/package-lock.json index d53de06..eff863e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "coinbase-api", - "version": "1.0.6", + "version": "1.0.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "coinbase-api", - "version": "1.0.6", + "version": "1.0.7", "license": "MIT", "dependencies": { "axios": "^1.7.4", diff --git a/package.json b/package.json index 7fc3b69..4a37c5d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "coinbase-api", - "version": "1.0.6", + "version": "1.0.7", "description": "Node.js SDK for Coinbase's REST APIs and WebSockets, with TypeScript & strong end to end tests.", "scripts": { "clean": "rm -rf dist", diff --git a/src/CBAppClient.ts b/src/CBAppClient.ts index 92b24ba..c7b2c8c 100644 --- a/src/CBAppClient.ts +++ b/src/CBAppClient.ts @@ -2,6 +2,7 @@ import { AxiosRequestConfig } from 'axios'; import { BaseRestClient } from './lib/BaseRestClient.js'; import { + getParamsFromURL, REST_CLIENT_TYPE_ENUM, RestClientOptions, RestClientType, @@ -36,7 +37,7 @@ export class CBAppClient extends BaseRestClient { headers: { // Some endpoints return a warning if a version header isn't included: https://docs.cdp.coinbase.com/coinbase-app/docs/versioning // Currently set to a date from the changelog: https://docs.cdp.coinbase.com/coinbase-app/docs/changelog - 'CB-VERSION': '2024-09-13', + 'CB-VERSION': '2025-FEB-3', ...requestOptions.headers, }, }); @@ -61,14 +62,18 @@ export class CBAppClient extends BaseRestClient { * This endpoint is paginated. In case you are calling it first time, leave paginationURL empty. * If you are paginating, provide the paginationURL value from the previous response and you will receive the next page of accounts. */ - getAccounts(params?: { paginationURL?: string }): Promise<{ + getAccounts(params?: { + paginationURL?: string; + starting_after?: string; + }): Promise<{ data: CBAppAccount[]; pagination: CBAppPagination; }> { if (params?.paginationURL) { - return this.getPrivate(params.paginationURL); + const derivedParams = getParamsFromURL(params.paginationURL); + return this.getPrivate(derivedParams.endpoint, derivedParams.params); } - return this.getPrivate('/v2/accounts'); + return this.getPrivate('/v2/accounts', params); } /** @@ -116,10 +121,15 @@ export class CBAppClient extends BaseRestClient { pagination: CBAppPagination; data: CBAppAddress[]; }> { + const { account_id, ...otherParams } = params; if (params?.paginationURL) { - return this.getPrivate(params.paginationURL); + const derivedParams = getParamsFromURL(params.paginationURL); + return this.getPrivate(derivedParams.endpoint, { + ...otherParams, + ...derivedParams.params, + }); } - return this.getPrivate(`/v2/accounts/${params.account_id}/addresses`); + return this.getPrivate(`/v2/accounts/${account_id}/addresses`, otherParams); } /** @@ -155,11 +165,17 @@ export class CBAppClient extends BaseRestClient { pagination: CBAppPagination; data: CBAppTransaction[]; }> { + const { account_id, addressId, ...otherParams } = params; if (params?.paginationURL) { - return this.getPrivate(params.paginationURL); + const derivedParams = getParamsFromURL(params.paginationURL); + return this.getPrivate(derivedParams.endpoint, { + ...otherParams, + ...derivedParams.params, + }); } return this.getPrivate( - `/v2/accounts/${params.account_id}/addresses/${params.addressId}/transactions`, + `/v2/accounts/${account_id}/addresses/${addressId}/transactions`, + otherParams, ); } @@ -214,10 +230,18 @@ export class CBAppClient extends BaseRestClient { pagination: CBAppPagination; data: CBAppTransaction[]; }> { + const { account_id, ...otherParams } = params; if (params?.paginationURL) { - return this.getPrivate(params.paginationURL); + const derivedParams = getParamsFromURL(params.paginationURL); + return this.getPrivate(derivedParams.endpoint, { + ...otherParams, + ...derivedParams.params, + }); } - return this.getPrivate(`/v2/accounts/${params.account_id}/transactions`); + return this.getPrivate( + `/v2/accounts/${account_id}/transactions`, + otherParams, + ); } /** @@ -282,10 +306,15 @@ export class CBAppClient extends BaseRestClient { pagination: CBAppPagination; data: CBAppDepositWithdrawal[]; }> { + const { account_id, ...otherParams } = params; if (params?.paginationURL) { - return this.getPrivate(params.paginationURL); + const derivedParams = getParamsFromURL(params.paginationURL); + return this.getPrivate(derivedParams.endpoint, { + ...otherParams, + ...derivedParams.params, + }); } - return this.getPrivate(`/v2/accounts/${params.account_id}/deposits`); + return this.getPrivate(`/v2/accounts/${account_id}/deposits`, otherParams); } /** @@ -350,10 +379,18 @@ export class CBAppClient extends BaseRestClient { pagination: CBAppPagination; data: CBAppDepositWithdrawal[]; }> { + const { account_id, ...otherParams } = params; if (params?.paginationURL) { - return this.getPrivate(params.paginationURL); + const derivedParams = getParamsFromURL(params.paginationURL); + return this.getPrivate(derivedParams.endpoint, { + ...otherParams, + ...derivedParams.params, + }); } - return this.getPrivate(`/v2/accounts/${params.account_id}/withdrawals`); + return this.getPrivate( + `/v2/accounts/${account_id}/withdrawals`, + otherParams, + ); } /** diff --git a/src/lib/requestUtils.ts b/src/lib/requestUtils.ts index a9a3965..66e2f41 100644 --- a/src/lib/requestUtils.ts +++ b/src/lib/requestUtils.ts @@ -199,3 +199,34 @@ export function getRestBaseUrl( return exchangeBaseUrls.livenet; } + +/** + * Extract and separate request parameters in query string from the rest of the endpoint, to prevent sign issues. + * + * @param url endpoint containing params in query string; "/v2/acconuts/123123213?someParam=xyz" + * @returns + */ +export function getParamsFromURL(url: string): { + endpoint: string; + params: any; +} { + const [endpoint, paramsStr] = url.split('?'); + if (!paramsStr) { + return { + endpoint: url, + params: {}, + }; + } + + const result = { + endpoint: endpoint, + params: {} as Record, + }; + + (paramsStr || '').split('&').forEach((param) => { + const [key, value] = param.split('='); + result.params[key] = value; + }); + + return result; +}