Skip to content
This repository has been archived by the owner on Apr 2, 2024. It is now read-only.

Commit

Permalink
refactor!: Switch from CJS to ESM (#901)
Browse files Browse the repository at this point in the history
  • Loading branch information
bennycode committed Oct 27, 2023
1 parent 763de73 commit 48d58a7
Show file tree
Hide file tree
Showing 61 changed files with 612 additions and 1,150 deletions.
1 change: 0 additions & 1 deletion nyc.config.coverage.json → .c8rc.coverage.json
Expand Up @@ -9,6 +9,5 @@
"lines": 100,
"per-file": false,
"reporter": ["html", "lcov", "text"],
"require": ["ts-node/register"],
"statements": 100
}
3 changes: 1 addition & 2 deletions nyc.config.json → .c8rc.json
Expand Up @@ -5,6 +5,5 @@
"extension": [".ts"],
"include": ["src/**/*.ts"],
"per-file": false,
"reporter": ["text-summary"],
"require": ["ts-node/register"]
"reporter": ["text-summary"]
}
2 changes: 1 addition & 1 deletion .eslintrc.json
Expand Up @@ -17,7 +17,7 @@
"rules": {
"@typescript-eslint/array-type": "error",
"@typescript-eslint/consistent-type-assertions": "error",
"@typescript-eslint/explicit-function-return-type": "error",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/no-namespace": "off",
"@typescript-eslint/no-this-alias": "error",
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/continuous-integration.yml
Expand Up @@ -8,12 +8,12 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
node-version: [16.x]
node-version: [18.x]
steps:
- name: 'Checkout repository'
uses: actions/checkout@v4
- name: 'Use Node.js v${{ matrix.node-version }}'
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: 'Install, lint, and test'
Expand Down
1 change: 0 additions & 1 deletion .gitignore
Expand Up @@ -3,7 +3,6 @@
.cache
.DS_Store
.idea/
.nyc_output/
.vscode/
.yarnclean
config.json
Expand Down
1 change: 1 addition & 0 deletions jasmine.json
@@ -1,6 +1,7 @@
{
"helpers": ["test/helpers/**/*.ts"],
"random": true,
"jsLoader": "import",
"spec_dir": "src",
"spec_files": ["**/*.test.ts", "**/*.test.node.ts"],
"stopSpecOnExpectationFailure": true,
Expand Down
28 changes: 14 additions & 14 deletions package.json
Expand Up @@ -19,29 +19,28 @@
"@types/jasmine": "4.3.5",
"@typescript-eslint/eslint-plugin": "5.62.0",
"@typescript-eslint/parser": "5.62.0",
"c8": "8.0.1",
"cross-env": "7.0.3",
"dotenv-defaults": "5.0.2",
"eslint": "8.46.0",
"eslint-config-prettier": "9.0.0",
"eslint-plugin-prettier": "4.2.1",
"eslint-plugin-prettier": "5.0.1",
"eslint-plugin-sort-keys-fix": "1.1.2",
"eslint-plugin-typescript-sort-keys": "2.3.0",
"eslint": "8.46.0",
"generate-changelog": "1.8.0",
"husky": "8.0.3",
"jasmine": "3.99.0",
"lint-staged": "14.0.1",
"nock": "13.3.3",
"nyc": "15.1.0",
"prettier": "2.8.8",
"pretty-quick": "3.1.3",
"prettier": "3.0.3",
"rimraf": "5.0.5",
"ts-node": "10.9.1",
"typedoc": "0.25.2",
"typedoc-plugin-markdown": "3.15.4",
"typescript": "^5.2.2"
"typedoc": "0.25.2",
"typescript": "5.2.2"
},
"engines": {
"node": ">= 10.9",
"node": ">= 18",
"yarn": ">= 1"
},
"files": [
Expand Down Expand Up @@ -77,7 +76,7 @@
"scripts": {
"build": "tsc",
"changelog:commit": "git add CHANGELOG.md && git commit -m \"docs: Updated changelog\"",
"clean": "rimraf .nyc_output coverage dist",
"clean": "rimraf coverage dist",
"demo:dump:candles": "cross-env NODE_DEBUG=coinbase-pro-node* ts-node src/demo/dump-candles.ts",
"demo:rest:get:candles": "cross-env NODE_DEBUG=coinbase-pro-node* ts-node src/demo/rest-get-candles.ts",
"demo:rest:watch:candles": "cross-env NODE_DEBUG=coinbase-pro-node* ts-node src/demo/rest-watch-candles.ts",
Expand All @@ -89,21 +88,22 @@
"dist": "yarn clean && yarn build",
"fix": "yarn fix:other && yarn fix:code",
"fix:code": "yarn lint:code --fix",
"fix:other": "yarn prettier --write",
"lint": "yarn lint:types && yarn lint:code && yarn lint:other",
"fix:other": "yarn prettier --write --log-level error",
"lint": "yarn clean && yarn lint:types && yarn lint:code && yarn lint:other",
"lint:code": "eslint --ext .js,.jsx,.ts,.tsx .",
"lint:other": "yarn prettier --list-different",
"lint:types": "tsc --noEmit",
"postversion": "git push origin && git push origin --tags && npm publish",
"prettier": "prettier --ignore-path .gitignore --loglevel silent \"**/*.{html,json,scss,yml}\"",
"prettier": "prettier --ignore-path .gitignore --log-level silent \"**/*.{json,scss,yml}\"",
"preversion": "git checkout main && git pull && yarn install && yarn lint && yarn test && yarn dist",
"release:major": "generate-changelog -M && yarn changelog:commit && yarn docs:release && npm version major",
"release:minor": "generate-changelog -m && yarn changelog:commit && yarn docs:release && npm version minor",
"release:patch": "generate-changelog -p && yarn changelog:commit && yarn docs:release && npm version patch",
"test": "nyc --nycrc-path=nyc.config.coverage.json jasmine --config=jasmine.json",
"test:dev": "nyc --nycrc-path=nyc.config.json jasmine --config=jasmine.json",
"test": "c8 --config=.c8rc.coverage.json ts-node-esm ./node_modules/.bin/jasmine --config=jasmine.json",
"test:dev": "c8 ts-node-esm ./node_modules/.bin/jasmine --config=jasmine.json",
"test:types": "yarn lint:types",
"prepare": "husky install"
},
"type": "module",
"version": "7.0.0"
}
2 changes: 1 addition & 1 deletion src/CoinbasePro.test.ts
@@ -1,4 +1,4 @@
import {CoinbasePro} from './CoinbasePro';
import {CoinbasePro} from './CoinbasePro.js';

describe('CoinbasePro', () => {
describe('constructor', () => {
Expand Down
6 changes: 3 additions & 3 deletions src/CoinbasePro.ts
@@ -1,6 +1,6 @@
import {RESTClient} from './client/RESTClient';
import {WebSocketClient} from './client/WebSocketClient';
import {RequestSetup, RequestSigner, SignedRequest} from './auth/RequestSigner';
import {RESTClient} from './client/RESTClient.js';
import {WebSocketClient} from './client/WebSocketClient.js';
import {RequestSetup, RequestSigner, SignedRequest} from './auth/RequestSigner.js';

export interface ClientAuthenticationBase {
apiKey: string;
Expand Down
12 changes: 6 additions & 6 deletions src/account/AccountAPI.test.ts
@@ -1,10 +1,10 @@
import getAccount from '../test/fixtures/rest/accounts/322dfa88-e10d-4678-856d-2930eac3e62d/GET-200.json';
import getAccountHistory from '../test/fixtures/rest/accounts/322dfa88-e10d-4678-856d-2930eac3e62d/ledger/GET-200.json';
import getHolds from '../test/fixtures/rest/accounts/322dfa88-e10d-4678-856d-2930eac3e62d/holds/GET-200.json';
import genAddress from '../test/fixtures/rest/accounts/322dfa88-e10d-4678-856d-2930eac3e62d/addresses/POST-200.json';
import listAccounts from '../test/fixtures/rest/accounts/GET-200.json';
import getAccount from '../test/fixtures/rest/accounts/322dfa88-e10d-4678-856d-2930eac3e62d/GET-200.json' assert {type: 'json'};
import getAccountHistory from '../test/fixtures/rest/accounts/322dfa88-e10d-4678-856d-2930eac3e62d/ledger/GET-200.json' assert {type: 'json'};
import getHolds from '../test/fixtures/rest/accounts/322dfa88-e10d-4678-856d-2930eac3e62d/holds/GET-200.json' assert {type: 'json'};
import genAddress from '../test/fixtures/rest/accounts/322dfa88-e10d-4678-856d-2930eac3e62d/addresses/POST-200.json' assert {type: 'json'};
import listAccounts from '../test/fixtures/rest/accounts/GET-200.json' assert {type: 'json'};
import nock from 'nock';
import {AccountAPI, AccountType} from './AccountAPI';
import {AccountAPI, AccountType} from './AccountAPI.js';

describe('AccountAPI', () => {
afterAll(() => nock.cleanAll());
Expand Down
2 changes: 1 addition & 1 deletion src/account/AccountAPI.ts
@@ -1,5 +1,5 @@
import {AxiosInstance} from 'axios';
import {ISO_8601_MS_UTC, PaginatedData, Pagination} from '../payload/common';
import {ISO_8601_MS_UTC, PaginatedData, Pagination} from '../payload/common.js';

export interface Account {
available: string;
Expand Down
2 changes: 1 addition & 1 deletion src/account/index.ts
@@ -1 +1 @@
export * from './AccountAPI';
export * from './AccountAPI.js';
4 changes: 2 additions & 2 deletions src/auth/RequestSigner.test.ts
@@ -1,5 +1,5 @@
import {RequestSetup, RequestSigner, SignedRequest} from './RequestSigner';
import {ClientAuthentication} from '../CoinbasePro';
import {RequestSetup, RequestSigner, SignedRequest} from './RequestSigner.js';
import {ClientAuthentication} from '../CoinbasePro.js';

describe('RequestSigner', () => {
describe('signRequest', () => {
Expand Down
6 changes: 3 additions & 3 deletions src/auth/RequestSigner.ts
@@ -1,6 +1,6 @@
import crypto from 'crypto';
import {ClientAuthentication} from '../CoinbasePro';
import {Buffer} from 'buffer/';
import crypto from 'node:crypto';
import {ClientAuthentication} from '../CoinbasePro.js';
import {Buffer} from 'node:buffer';

export interface RequestSetup {
httpMethod: string;
Expand Down
6 changes: 3 additions & 3 deletions src/client/RESTClient.test.ts
@@ -1,8 +1,8 @@
import {AxiosRequestConfig} from 'axios';
import nock from 'nock';
import {AccountAPI} from '../account';
import listAccounts from '../test/fixtures/rest/accounts/GET-200.json';
import {RESTClient} from './RESTClient';
import {AccountAPI} from '../account/index.js';
import listAccounts from '../test/fixtures/rest/accounts/GET-200.json' assert {type: 'json'};
import {RESTClient} from './RESTClient.js';

describe('RESTClient', () => {
function createRESTClient(): RESTClient {
Expand Down
43 changes: 23 additions & 20 deletions src/client/RESTClient.ts
Expand Up @@ -6,24 +6,24 @@ import axios, {
AxiosRequestConfig,
AxiosResponse,
} from 'axios';
import {AccountAPI} from '../account';
import {RequestSetup, SignedRequest} from '../auth/RequestSigner';
import {OrderAPI} from '../order';
import {Candle, CandleGranularity, ProductAPI, ProductEvent} from '../product';
import {UserAPI} from '../user';
import {FeeAPI} from '../fee';
import {FillAPI} from '../fill';
import querystring from 'querystring';
import {ProfileAPI} from '../profile';
import axiosRetry, {isNetworkOrIdempotentRequestError} from 'axios-retry';
import util, {DebugLogger} from 'util';
import {EventEmitter} from 'events';
import {getErrorMessage, gotRateLimited, inAirPlaneMode} from '../error/ErrorUtil';
import {CurrencyAPI} from '../currency';
import {WithdrawAPI} from '../withdraw';
import {TransferAPI} from '../transfer';
import {TimeAPI} from '../time';
import {ExchangeRateAPI} from '../exchange-rate/ExchangeRateAPI';
import {EventEmitter} from 'node:events';
import util, {DebugLogger} from 'node:util';
import querystring from 'querystring';
import {AccountAPI} from '../account/index.js';
import {RequestSetup, SignedRequest} from '../auth/RequestSigner.js';
import {CurrencyAPI} from '../currency/index.js';
import {getErrorMessage, gotRateLimited, inAirPlaneMode} from '../error/ErrorUtil.js';
import {ExchangeRateAPI} from '../exchange-rate/ExchangeRateAPI.js';
import {FeeAPI} from '../fee/index.js';
import {FillAPI} from '../fill/index.js';
import {OrderAPI} from '../order/index.js';
import {Candle, CandleGranularity, ProductAPI, ProductEvent} from '../product/index.js';
import {ProfileAPI} from '../profile/index.js';
import {TimeAPI} from '../time/index.js';
import {TransferAPI} from '../transfer/index.js';
import {UserAPI} from '../user/index.js';
import {WithdrawAPI} from '../withdraw/index.js';

export interface RESTClient {
on(
Expand Down Expand Up @@ -61,11 +61,14 @@ export class RESTClient extends EventEmitter {
private readonly httpClient: AxiosInstance;
private readonly logger: DebugLogger;

constructor(baseURL: string, private readonly signRequest: (setup: RequestSetup) => Promise<SignedRequest>) {
constructor(
baseURL: string,
private readonly signRequest: (setup: RequestSetup) => Promise<SignedRequest>
) {
super();
this.logger = util.debuglog('coinbase-pro-node');

this.httpClient = axios.create({
this.httpClient = axios.default.create({
baseURL: baseURL,
timeout: 50_000,
});
Expand All @@ -78,7 +81,7 @@ export class RESTClient extends EventEmitter {
retryDelay: (retryCount: number, error: AxiosError) => {
const errorMessage = getErrorMessage(error);
this.logger(
`#${retryCount} There was an error querying "${error.config.baseURL}${error.config.url}": ${errorMessage}`
`#${retryCount} There was an error querying "${error.config?.baseURL}${error.config?.url}": ${errorMessage}`
);
/**
* Rate limits:
Expand Down
36 changes: 18 additions & 18 deletions src/client/WebSocketClient.test.ts
@@ -1,34 +1,33 @@
import WebSocket = require('ws');
import tickerBTCUSD from '../test/fixtures/ws/ticker/BTC-USD.json';
import statusPayload from '../test/fixtures/ws/status/status.json';
import matchesBTCUSD from '../test/fixtures/ws/matches/BTC-USD.json';
import l2snapshotBTCUSD from '../test/fixtures/ws/level2/snapshot.json';
import l2updateBTCUSD from '../test/fixtures/ws/level2/l2update.json';
import fullReceivedLimitBTCUSD from '../test/fixtures/ws/full/received-limit.json';
import fullActivateBTCUSD from '../test/fixtures/ws/full/activate.json';
import fullOpenBTCUSD from '../test/fixtures/ws/full/open.json';
import fullDoneBTCUSD from '../test/fixtures/ws/full/done.json';
import fullChangeBTCUSD from '../test/fixtures/ws/full/change.json';
import emptySubscriptions from '../test/fixtures/ws/empty-subscriptions.json';
import emptySubscriptions from '../test/fixtures/ws/empty-subscriptions.json' assert {type: 'json'};
import fullActivateBTCUSD from '../test/fixtures/ws/full/activate.json' assert {type: 'json'};
import fullChangeBTCUSD from '../test/fixtures/ws/full/change.json' assert {type: 'json'};
import fullDoneBTCUSD from '../test/fixtures/ws/full/done.json' assert {type: 'json'};
import fullOpenBTCUSD from '../test/fixtures/ws/full/open.json' assert {type: 'json'};
import fullReceivedLimitBTCUSD from '../test/fixtures/ws/full/received-limit.json' assert {type: 'json'};
import l2updateBTCUSD from '../test/fixtures/ws/level2/l2update.json' assert {type: 'json'};
import l2snapshotBTCUSD from '../test/fixtures/ws/level2/snapshot.json' assert {type: 'json'};
import matchesBTCUSD from '../test/fixtures/ws/matches/BTC-USD.json' assert {type: 'json'};
import statusPayload from '../test/fixtures/ws/status/status.json' assert {type: 'json'};
import tickerBTCUSD from '../test/fixtures/ws/ticker/BTC-USD.json' assert {type: 'json'};
import {
WebSocketChannel,
WebSocketChannelName,
WebSocketClient,
WebSocketErrorMessage,
WebSocketEvent,
WebSocketRequest,
WebSocketRequestType,
WebSocketResponseType,
WebSocketRequest,
WebSocketChannel,
WebSocketErrorMessage,
} from './WebSocketClient';
import ReconnectingWebSocket from 'reconnecting-websocket';
} from './WebSocketClient.js';

const WEBSOCKET_PORT = 8087;
const WEBSOCKET_URL = `ws://localhost:${WEBSOCKET_PORT}`;

let server: WebSocket.Server;

describe('WebSocketClient', () => {
function createWebSocketClient(url: string = WEBSOCKET_URL): WebSocketClient {
function createWebSocketClient(url: string = WEBSOCKET_URL) {
return new WebSocketClient(url, () => {
return Promise.resolve({
key: '',
Expand Down Expand Up @@ -89,7 +88,8 @@ describe('WebSocketClient', () => {
it('supports custom reconnect options', async () => {
const ws = createWebSocketClient();
const socket = ws.connect({startClosed: true});
expect(socket.readyState).toBe(ReconnectingWebSocket.CLOSED);
// Info: State 3 is "ReconnectingWebSocket.CLOSED"
expect(socket.readyState).toBe(3);
});
});

Expand Down
18 changes: 11 additions & 7 deletions src/client/WebSocketClient.ts
@@ -1,8 +1,8 @@
import {EventEmitter} from 'events';
import {EventEmitter} from 'node:events';
import ReconnectingWebSocket, {Event, ErrorEvent, Options, CloseEvent} from 'reconnecting-websocket';
import WebSocket from 'ws';
import {RequestSetup, SignedRequest} from '../auth/RequestSigner';
import {OrderSide, ISO_8601_MS_UTC, UUID_V4, UserAPI, CurrencyDetail, Product} from '..';
import {RequestSetup, SignedRequest} from '../auth/RequestSigner.js';
import {OrderSide, ISO_8601_MS_UTC, UUID_V4, UserAPI, CurrencyDetail, Product} from '../index.js';

export interface WebSocketChannel {
name: WebSocketChannelName;
Expand Down Expand Up @@ -356,15 +356,18 @@ export class WebSocketClient extends EventEmitter {
};

private readonly baseURL: string;
public socket: ReconnectingWebSocket | undefined;
public socket: ReconnectingWebSocket.default | undefined;

private pingInterval?: NodeJS.Timeout;
private pongTimeout?: NodeJS.Timeout;

private pingTime: number;
private readonly pongTime: number;

constructor(baseURL: string, private readonly signRequest: (setup: RequestSetup) => Promise<SignedRequest>) {
constructor(
baseURL: string,
private readonly signRequest: (setup: RequestSetup) => Promise<SignedRequest>
) {
super();
this.baseURL = baseURL;
this.pingTime = 10_000;
Expand All @@ -378,15 +381,16 @@ export class WebSocketClient extends EventEmitter {
* will be merged with sensible default values.
* @see https://docs.cloud.coinbase.com/exchange/docs/websocket-overview
*/
connect(reconnectOptions?: Options): ReconnectingWebSocket {
connect(reconnectOptions?: Options) {
if (this.socket) {
throw Error(
`You established already a WebSocket connection. Please call "disconnect" first before creating a new one.`
);
}

const options = this.mergeOptions(reconnectOptions);
this.socket = new ReconnectingWebSocket(this.baseURL, [], options);
// Quickfix: https://github.com/pladaria/reconnecting-websocket/issues/196#issue-1963876085
this.socket = new (ReconnectingWebSocket as any)(this.baseURL, [], options) as ReconnectingWebSocket.default;

this.socket.onclose = (event: CloseEvent): void => {
this.cleanupListener();
Expand Down
4 changes: 2 additions & 2 deletions src/client/index.ts
@@ -1,2 +1,2 @@
export * from './RESTClient';
export * from './WebSocketClient';
export * from './RESTClient.js';
export * from './WebSocketClient.js';
2 changes: 1 addition & 1 deletion src/currency/CurrencyAPI.test.ts
@@ -1,5 +1,5 @@
import nock from 'nock';
import {CurrencyAPI} from './CurrencyAPI';
import {CurrencyAPI} from './CurrencyAPI.js';

describe('CurrencyAPI', () => {
afterEach(() => nock.cleanAll());
Expand Down
2 changes: 1 addition & 1 deletion src/currency/index.ts
@@ -1 +1 @@
export * from './CurrencyAPI';
export * from './CurrencyAPI.js';

0 comments on commit 48d58a7

Please sign in to comment.