diff options
Diffstat (limited to 'packages/connect')
28 files changed, 432 insertions, 330 deletions
diff --git a/packages/connect/CHANGELOG.md b/packages/connect/CHANGELOG.md index cf507dbe6..e02020204 100644 --- a/packages/connect/CHANGELOG.md +++ b/packages/connect/CHANGELOG.md @@ -1,16 +1,26 @@ # CHANGELOG -vx.x.x ------------------------- +## v0.5.0 - _January 17, 2018_ + + * Sanitize api endpoint url and remove trailing slashes (#318) + * Improve error message text in HttpClient (#318) + * Stop appending '/v0' to api endpoint url in HttpClient (#318) + +## v0.4.0 - _January 11, 2018_ + + * Prevent getFeesAsync method on HttpClient from mutating input (#296) + +## v0.3.0 - _December 8, 2017_ + * Expose WebSocketOrderbookChannel and associated types to public interface (#251) * Remove tokenA and tokenB fields from OrdersRequest (#256) -v0.2.0 - _November 29, 2017_ ------------------------- +## v0.2.0 - _November 29, 2017_ + * Add SignedOrder and TokenTradeInfo to the public interface * Add ECSignature and Order to the public interface * Remove dependency on 0x.js -v0.1.0 - _November 22, 2017_ ------------------------- +## v0.1.0 - _November 22, 2017_ + * Provide a HttpClient class for interacting with standard relayer api compliant HTTP urls diff --git a/packages/connect/README.md b/packages/connect/README.md index 900045526..63faf5271 100644 --- a/packages/connect/README.md +++ b/packages/connect/README.md @@ -1 +1,52 @@ +## @0xproject/connect + This repository contains a Javascript library that makes it easy to interact with Relayers that conform to the [Standard Relayer API](https://github.com/0xProject/standard-relayer-api) + +## Installation + +```bash +yarn add @0xproject/connect +``` + +## Usage + +* [Docs](https://0xproject.com/docs/connect) +* [Tutorials](https://0xproject.com/wiki#connect) + +## Contributing + +We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. + +Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. + +### Install Dependencies + +If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: + +```bash +yarn config set workspaces-experimental true +``` + +Then install dependencies + +```bash +yarn install +``` + +### Build + +```bash +yarn build +``` + +### Lint + +```bash +yarn lint +``` + +### Run Tests + +```bash +yarn test +``` diff --git a/packages/connect/package.json b/packages/connect/package.json index 2392d9907..a28916903 100644 --- a/packages/connect/package.json +++ b/packages/connect/package.json @@ -1,69 +1,69 @@ { - "name": "@0xproject/connect", - "version": "0.2.0", - "description": "A javascript library for interacting with the standard relayer api", - "keywords": [ - "connect", - "0xproject", - "ethereum", - "tokens", - "exchange" - ], - "main": "lib/src/index.js", - "types": "lib/src/index.d.ts", - "scripts": { - "build": "tsc", - "clean": "shx rm -rf _bundles lib test_temp", - "docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_DIR", - "upload_docs_json": "aws s3 cp generated_docs/index.json $S3_URL --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type application/json", - "copy_test_fixtures": "copyfiles -u 2 './test/fixtures/**/*.json' ./lib/test/fixtures", - "lint": "tslint --project . 'src/**/*.ts' 'test/**/*.ts'", - "run_mocha": "mocha lib/test/**/*_test.js", - "test": "run-s clean build copy_test_fixtures run_mocha", - "test:circleci": "yarn test" - }, - "repository": { - "type": "git", - "url": "https://github.com/0xProject/0x.js.git" - }, - "author": "Brandon Millman", - "license": "Apache-2.0", - "engines": { - "node": ">=6.0.0" - }, - "bugs": { - "url": "https://github.com/0xProject/0x.js/issues" - }, - "homepage": "https://github.com/0xProject/0x.js/packages/connect/README.md", - "dependencies": { - "@0xproject/assert": "^0.0.6", - "@0xproject/json-schemas": "^0.6.9", - "bignumber.js": "~4.1.0", - "isomorphic-fetch": "^2.2.1", - "lodash": "^4.17.4", - "query-string": "^5.0.1", - "websocket": "^1.0.25" - }, - "devDependencies": { - "@0xproject/tslint-config": "^0.2.0", - "@types/fetch-mock": "^5.12.1", - "@types/lodash": "^4.14.86", - "@types/mocha": "^2.2.42", - "@types/query-string": "^5.0.1", - "@types/websocket": "^0.0.34", - "chai": "^4.0.1", - "chai-as-promised": "^7.1.0", - "chai-as-promised-typescript-typings": "^0.0.3", - "chai-typescript-typings": "^0.0.1", - "copyfiles": "^1.2.0", - "dirty-chai": "^2.0.1", - "fetch-mock": "^5.13.1", - "mocha": "^4.0.1", - "npm-run-all": "^4.1.2", - "shx": "^0.2.2", - "tslint": "5.8.0", - "typedoc": "~0.8.0", - "typescript": "~2.6.1", - "web3-typescript-typings": "^0.7.2" - } + "name": "@0xproject/connect", + "version": "0.5.1", + "description": "A javascript library for interacting with the standard relayer api", + "keywords": [ + "connect", + "0xproject", + "ethereum", + "tokens", + "exchange" + ], + "main": "lib/src/index.js", + "types": "lib/src/index.d.ts", + "scripts": { + "build": "tsc", + "clean": "shx rm -rf _bundles lib test_temp", + "docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_DIR", + "upload_docs_json": "aws s3 cp generated_docs/index.json $S3_URL --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type application/json", + "copy_test_fixtures": "copyfiles -u 2 './test/fixtures/**/*.json' ./lib/test/fixtures", + "lint": "tslint --project . 'src/**/*.ts' 'test/**/*.ts'", + "run_mocha": "mocha lib/test/**/*_test.js", + "test": "run-s clean build copy_test_fixtures run_mocha", + "test:circleci": "yarn test" + }, + "repository": { + "type": "git", + "url": "https://github.com/0xProject/0x.js.git" + }, + "author": "Brandon Millman", + "license": "Apache-2.0", + "engines": { + "node": ">=6.0.0" + }, + "bugs": { + "url": "https://github.com/0xProject/0x.js/issues" + }, + "homepage": "https://github.com/0xProject/0x.js/packages/connect/README.md", + "dependencies": { + "@0xproject/assert": "^0.0.12", + "@0xproject/json-schemas": "^0.7.4", + "@0xproject/utils": "^0.2.1", + "isomorphic-fetch": "^2.2.1", + "lodash": "^4.17.4", + "query-string": "^5.0.1", + "websocket": "^1.0.25" + }, + "devDependencies": { + "@0xproject/tslint-config": "^0.4.3", + "@types/fetch-mock": "^5.12.1", + "@types/lodash": "^4.14.86", + "@types/mocha": "^2.2.42", + "@types/query-string": "^5.0.1", + "@types/websocket": "^0.0.34", + "chai": "^4.0.1", + "chai-as-promised": "^7.1.0", + "chai-as-promised-typescript-typings": "^0.0.5", + "chai-typescript-typings": "^0.0.2", + "copyfiles": "^1.2.0", + "dirty-chai": "^2.0.1", + "fetch-mock": "^5.13.1", + "mocha": "^4.0.1", + "npm-run-all": "^4.1.2", + "shx": "^0.2.2", + "tslint": "5.8.0", + "typedoc": "~0.8.0", + "typescript": "~2.6.1", + "web3-typescript-typings": "^0.9.5" + } } diff --git a/packages/connect/scripts/postpublish.js b/packages/connect/scripts/postpublish.js index e6a2cc065..24384b228 100644 --- a/packages/connect/scripts/postpublish.js +++ b/packages/connect/scripts/postpublish.js @@ -8,22 +8,20 @@ const S3BucketPath = 's3://connect-docs-jsons/'; let tag; let version; -postpublish_utils.getLatestTagAndVersionAsync(subPackageName) +postpublish_utils + .getLatestTagAndVersionAsync(subPackageName) .then(function(result) { tag = result.tag; version = result.version; - const releaseName = postpublish_utils.getReleaseName(subPackageName, version); - return postpublish_utils.publishReleaseNotes(tag, releaseName); + const releaseName = postpublish_utils.getReleaseName(subPackageName, version); + return postpublish_utils.publishReleaseNotes(tag, releaseName); }) .then(function(release) { console.log('POSTPUBLISH: Release successful, generating docs...'); const jsonFilePath = __dirname + '/../' + postpublish_utils.generatedDocsDirectoryName + '/index.json'; - return execAsync( - 'JSON_FILE_PATH=' + jsonFilePath + ' PROJECT_DIR=' + __dirname + '/.. yarn docs:json', - { - cwd, - } - ); + return execAsync('JSON_FILE_PATH=' + jsonFilePath + ' PROJECT_DIR=' + __dirname + '/.. yarn docs:json', { + cwd, + }); }) .then(function(result) { if (result.stderr !== '') { @@ -35,6 +33,7 @@ postpublish_utils.getLatestTagAndVersionAsync(subPackageName) return execAsync('S3_URL=' + s3Url + ' yarn upload_docs_json', { cwd, }); - }).catch (function(err) { + }) + .catch(function(err) { throw err; }); diff --git a/packages/connect/src/http_client.ts b/packages/connect/src/http_client.ts index 252c9e9dd..3df77b0f0 100644 --- a/packages/connect/src/http_client.ts +++ b/packages/connect/src/http_client.ts @@ -1,11 +1,10 @@ -import {assert} from '@0xproject/assert'; -import {schemas} from '@0xproject/json-schemas'; -import {BigNumber} from 'bignumber.js'; +import { assert } from '@0xproject/assert'; +import { schemas } from '@0xproject/json-schemas'; import 'isomorphic-fetch'; import * as _ from 'lodash'; import * as queryString from 'query-string'; -import {schemas as clientSchemas} from './schemas/schemas'; +import { schemas as clientSchemas } from './schemas/schemas'; import { Client, FeesRequest, @@ -19,19 +18,15 @@ import { TokenPairsItem, TokenPairsRequest, } from './types'; -import {typeConverters} from './utils/type_converters'; - -// TODO: move this and bigNumberConfigs in the 0x.js package into one place -BigNumber.config({ - EXPONENTIAL_AT: 1000, -}); +import { relayerResponseJsonParsers } from './utils/relayer_response_json_parsers'; +const TRAILING_SLASHES_REGEX = /\/+$/; /** * This class includes all the functionality related to interacting with a set of HTTP endpoints * that implement the standard relayer API v0 */ export class HttpClient implements Client { - private apiEndpointUrl: string; + private _apiEndpointUrl: string; /** * Instantiates a new HttpClient instance * @param url The relayer API base HTTP url you would like to interact with @@ -39,7 +34,7 @@ export class HttpClient implements Client { */ constructor(url: string) { assert.isHttpUrl('url', url); - this.apiEndpointUrl = url; + this._apiEndpointUrl = url.replace(TRAILING_SLASHES_REGEX, ''); // remove trailing slashes } /** * Retrieve token pair info from the API @@ -54,17 +49,8 @@ export class HttpClient implements Client { const requestOpts = { params: request, }; - const tokenPairs = await this._requestAsync('/token_pairs', HttpRequestType.Get, requestOpts); - assert.doesConformToSchema( - 'tokenPairs', tokenPairs, schemas.relayerApiTokenPairsResponseSchema); - _.each(tokenPairs, (tokenPair: object) => { - typeConverters.convertStringsFieldsToBigNumbers(tokenPair, [ - 'tokenA.minAmount', - 'tokenA.maxAmount', - 'tokenB.minAmount', - 'tokenB.maxAmount', - ]); - }); + const responseJson = await this._requestAsync('/token_pairs', HttpRequestType.Get, requestOpts); + const tokenPairs = relayerResponseJsonParsers.parseTokenPairsJson(responseJson); return tokenPairs; } /** @@ -79,9 +65,8 @@ export class HttpClient implements Client { const requestOpts = { params: request, }; - const orders = await this._requestAsync(`/orders`, HttpRequestType.Get, requestOpts); - assert.doesConformToSchema('orders', orders, schemas.signedOrdersSchema); - _.each(orders, (order: object) => typeConverters.convertOrderStringFieldsToBigNumber(order)); + const responseJson = await this._requestAsync(`/orders`, HttpRequestType.Get, requestOpts); + const orders = relayerResponseJsonParsers.parseOrdersJson(responseJson); return orders; } /** @@ -91,9 +76,8 @@ export class HttpClient implements Client { */ public async getOrderAsync(orderHash: string): Promise<SignedOrder> { assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema); - const order = await this._requestAsync(`/order/${orderHash}`, HttpRequestType.Get); - assert.doesConformToSchema('order', order, schemas.signedOrderSchema); - typeConverters.convertOrderStringFieldsToBigNumber(order); + const responseJson = await this._requestAsync(`/order/${orderHash}`, HttpRequestType.Get); + const order = relayerResponseJsonParsers.parseOrderJson(responseJson); return order; } /** @@ -106,10 +90,9 @@ export class HttpClient implements Client { const requestOpts = { params: request, }; - const orderBook = await this._requestAsync('/orderbook', HttpRequestType.Get, requestOpts); - assert.doesConformToSchema('orderBook', orderBook, schemas.relayerApiOrderBookResponseSchema); - typeConverters.convertOrderbookStringFieldsToBigNumber(orderBook); - return orderBook; + const responseJson = await this._requestAsync('/orderbook', HttpRequestType.Get, requestOpts); + const orderbook = relayerResponseJsonParsers.parseOrderbookResponseJson(responseJson); + return orderbook; } /** * Retrieve fee information from the API @@ -118,18 +101,11 @@ export class HttpClient implements Client { */ public async getFeesAsync(request: FeesRequest): Promise<FeesResponse> { assert.doesConformToSchema('request', request, schemas.relayerApiFeesPayloadSchema); - typeConverters.convertBigNumberFieldsToStrings(request, [ - 'makerTokenAmount', - 'takerTokenAmount', - 'expirationUnixTimestampSec', - 'salt', - ]); const requestOpts = { payload: request, }; - const fees = await this._requestAsync('/fees', HttpRequestType.Post, requestOpts); - assert.doesConformToSchema('fees', fees, schemas.relayerApiFeesResponseSchema); - typeConverters.convertStringsFieldsToBigNumbers(fees, ['makerFee', 'takerFee']); + const responseJson = await this._requestAsync('/fees', HttpRequestType.Post, requestOpts); + const fees = relayerResponseJsonParsers.parseFeesResponseJson(responseJson); return fees; } /** @@ -143,8 +119,11 @@ export class HttpClient implements Client { }; await this._requestAsync('/order', HttpRequestType.Post, requestOpts); } - private async _requestAsync(path: string, requestType: HttpRequestType, - requestOptions?: HttpRequestOptions): Promise<any> { + private async _requestAsync( + path: string, + requestType: HttpRequestType, + requestOptions?: HttpRequestOptions, + ): Promise<any> { const params = _.get(requestOptions, 'params'); const payload = _.get(requestOptions, 'payload'); let query = ''; @@ -152,20 +131,22 @@ export class HttpClient implements Client { const stringifiedParams = queryString.stringify(params); query = `?${stringifiedParams}`; } - const url = `${this.apiEndpointUrl}/v0${path}${query}`; + const url = `${this._apiEndpointUrl}${path}${query}`; const headers = new Headers({ 'content-type': 'application/json', }); - const response = await fetch(url, { method: requestType, body: JSON.stringify(payload), headers, }); + const json = await response.json(); if (!response.ok) { - throw Error(response.statusText); + const errorString = `${response.status} - ${response.statusText}\n${requestType} ${url}\n${JSON.stringify( + json, + )}`; + throw Error(errorString); } - const json = await response.json(); return json; } } diff --git a/packages/connect/src/index.ts b/packages/connect/src/index.ts index ec369a606..a492f5ae9 100644 --- a/packages/connect/src/index.ts +++ b/packages/connect/src/index.ts @@ -1,5 +1,5 @@ -export {HttpClient} from './http_client'; -export {WebSocketOrderbookChannel} from './ws_orderbook_channel'; +export { HttpClient } from './http_client'; +export { WebSocketOrderbookChannel } from './ws_orderbook_channel'; export { Client, ECSignature, diff --git a/packages/connect/src/schemas/relayer_fees_request_schema.ts b/packages/connect/src/schemas/relayer_fees_request_schema.ts index 9408c94a0..f20e077ba 100644 --- a/packages/connect/src/schemas/relayer_fees_request_schema.ts +++ b/packages/connect/src/schemas/relayer_fees_request_schema.ts @@ -2,7 +2,7 @@ export const relayerOrderBookRequestSchema = { id: '/RelayerOrderBookRequest', type: 'object', properties: { - baseTokenAddress: {$ref: '/Address'}, - quoteTokenAddress: {$ref: '/Address'}, + baseTokenAddress: { $ref: '/Address' }, + quoteTokenAddress: { $ref: '/Address' }, }, }; diff --git a/packages/connect/src/schemas/relayer_orderbook_request_schema.ts b/packages/connect/src/schemas/relayer_orderbook_request_schema.ts index 9408c94a0..f20e077ba 100644 --- a/packages/connect/src/schemas/relayer_orderbook_request_schema.ts +++ b/packages/connect/src/schemas/relayer_orderbook_request_schema.ts @@ -2,7 +2,7 @@ export const relayerOrderBookRequestSchema = { id: '/RelayerOrderBookRequest', type: 'object', properties: { - baseTokenAddress: {$ref: '/Address'}, - quoteTokenAddress: {$ref: '/Address'}, + baseTokenAddress: { $ref: '/Address' }, + quoteTokenAddress: { $ref: '/Address' }, }, }; diff --git a/packages/connect/src/schemas/relayer_orders_request_schema.ts b/packages/connect/src/schemas/relayer_orders_request_schema.ts index c11bc77be..570238dae 100644 --- a/packages/connect/src/schemas/relayer_orders_request_schema.ts +++ b/packages/connect/src/schemas/relayer_orders_request_schema.ts @@ -2,15 +2,15 @@ export const relayerOrdersRequestSchema = { id: '/RelayerOrdersRequest', type: 'object', properties: { - exchangeContractAddress: {$ref: '/Address'}, - tokenAddress: {$ref: '/Address'}, - makerTokenAddress: {$ref: '/Address'}, - takerTokenAddress: {$ref: '/Address'}, - tokenA: {$ref: '/Address'}, - tokenB: {$ref: '/Address'}, - maker: {$ref: '/Address'}, - taker: {$ref: '/Address'}, - trader: {$ref: '/Address'}, - feeRecipient: {$ref: '/Address'}, + exchangeContractAddress: { $ref: '/Address' }, + tokenAddress: { $ref: '/Address' }, + makerTokenAddress: { $ref: '/Address' }, + takerTokenAddress: { $ref: '/Address' }, + tokenA: { $ref: '/Address' }, + tokenB: { $ref: '/Address' }, + maker: { $ref: '/Address' }, + taker: { $ref: '/Address' }, + trader: { $ref: '/Address' }, + feeRecipient: { $ref: '/Address' }, }, }; diff --git a/packages/connect/src/schemas/relayer_token_pairs_request_schema.ts b/packages/connect/src/schemas/relayer_token_pairs_request_schema.ts index 8013e1454..379232204 100644 --- a/packages/connect/src/schemas/relayer_token_pairs_request_schema.ts +++ b/packages/connect/src/schemas/relayer_token_pairs_request_schema.ts @@ -2,7 +2,7 @@ export const relayerTokenPairsRequestSchema = { id: '/RelayerTokenPairsRequest', type: 'object', properties: { - tokenA: {$ref: '/Address'}, - tokenB: {$ref: '/Address'}, + tokenA: { $ref: '/Address' }, + tokenB: { $ref: '/Address' }, }, }; diff --git a/packages/connect/src/schemas/schemas.ts b/packages/connect/src/schemas/schemas.ts index 97ac672bf..288d6969d 100644 --- a/packages/connect/src/schemas/schemas.ts +++ b/packages/connect/src/schemas/schemas.ts @@ -1,12 +1,6 @@ -import { - relayerOrderBookRequestSchema, -} from './relayer_orderbook_request_schema'; -import { - relayerOrdersRequestSchema, -} from './relayer_orders_request_schema'; -import { - relayerTokenPairsRequestSchema, -} from './relayer_token_pairs_request_schema'; +import { relayerOrderBookRequestSchema } from './relayer_orderbook_request_schema'; +import { relayerOrdersRequestSchema } from './relayer_orders_request_schema'; +import { relayerTokenPairsRequestSchema } from './relayer_token_pairs_request_schema'; export const schemas = { relayerOrderBookRequestSchema, diff --git a/packages/connect/src/types.ts b/packages/connect/src/types.ts index d02444a3e..edb6c77a6 100644 --- a/packages/connect/src/types.ts +++ b/packages/connect/src/types.ts @@ -1,4 +1,4 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; // TODO: Consolidate Order, SignedOrder and ECSignature into a shared package instead of duplicating them from 0x.js export interface Order { @@ -57,19 +57,24 @@ export interface OrderbookChannelSubscriptionOpts { } export interface OrderbookChannelHandler { - onSnapshot: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts, - snapshot: OrderbookResponse) => void; - onUpdate: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts, - order: SignedOrder) => void; - onError: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts, - err: Error) => void; + onSnapshot: ( + channel: OrderbookChannel, + subscriptionOpts: OrderbookChannelSubscriptionOpts, + snapshot: OrderbookResponse, + ) => void; + onUpdate: ( + channel: OrderbookChannel, + subscriptionOpts: OrderbookChannelSubscriptionOpts, + order: SignedOrder, + ) => void; + onError: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts, err: Error) => void; onClose: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts) => void; } export type OrderbookChannelMessage = - SnapshotOrderbookChannelMessage | - UpdateOrderbookChannelMessage | - UnknownOrderbookChannelMessage; + | SnapshotOrderbookChannelMessage + | UpdateOrderbookChannelMessage + | UnknownOrderbookChannelMessage; export enum OrderbookChannelMessageTypes { Snapshot = 'snapshot', diff --git a/packages/connect/src/utils/orderbook_channel_message_parser.ts b/packages/connect/src/utils/orderbook_channel_message_parser.ts new file mode 100644 index 000000000..9a9ca8901 --- /dev/null +++ b/packages/connect/src/utils/orderbook_channel_message_parser.ts @@ -0,0 +1,37 @@ +import { assert } from '@0xproject/assert'; +import { schemas } from '@0xproject/json-schemas'; +import * as _ from 'lodash'; + +import { OrderbookChannelMessage, OrderbookChannelMessageTypes } from '../types'; + +import { relayerResponseJsonParsers } from './relayer_response_json_parsers'; + +export const orderbookChannelMessageParser = { + parse(utf8Data: string): OrderbookChannelMessage { + const messageObj = JSON.parse(utf8Data); + const type: string = _.get(messageObj, 'type'); + assert.assert(!_.isUndefined(type), `Message is missing a type parameter: ${utf8Data}`); + assert.isString('type', type); + switch (type) { + case OrderbookChannelMessageTypes.Snapshot: { + assert.doesConformToSchema('message', messageObj, schemas.relayerApiOrderbookChannelSnapshotSchema); + const orderbookJson = messageObj.payload; + const orderbook = relayerResponseJsonParsers.parseOrderbookResponseJson(orderbookJson); + return _.assign(messageObj, { payload: orderbook }); + } + case OrderbookChannelMessageTypes.Update: { + assert.doesConformToSchema('message', messageObj, schemas.relayerApiOrderbookChannelUpdateSchema); + const orderJson = messageObj.payload; + const order = relayerResponseJsonParsers.parseOrderJson(orderJson); + return _.assign(messageObj, { payload: order }); + } + default: { + return { + type: OrderbookChannelMessageTypes.Unknown, + requestId: 0, + payload: undefined, + }; + } + } + }, +}; diff --git a/packages/connect/src/utils/orderbook_channel_message_parsers.ts b/packages/connect/src/utils/orderbook_channel_message_parsers.ts deleted file mode 100644 index 486a416ef..000000000 --- a/packages/connect/src/utils/orderbook_channel_message_parsers.ts +++ /dev/null @@ -1,41 +0,0 @@ -import {assert} from '@0xproject/assert'; -import {schemas} from '@0xproject/json-schemas'; -import * as _ from 'lodash'; - -import { - OrderbookChannelMessage, - OrderbookChannelMessageTypes, - SignedOrder, -} from '../types'; - -import {typeConverters} from './type_converters'; - -export const orderbookChannelMessageParsers = { - parser(utf8Data: string): OrderbookChannelMessage { - const messageObj = JSON.parse(utf8Data); - const type: string = _.get(messageObj, 'type'); - assert.assert(!_.isUndefined(type), `Message is missing a type parameter: ${utf8Data}`); - assert.isString('type', type); - switch (type) { - case (OrderbookChannelMessageTypes.Snapshot): { - assert.doesConformToSchema('message', messageObj, schemas.relayerApiOrderbookChannelSnapshotSchema); - const orderbook = messageObj.payload; - typeConverters.convertOrderbookStringFieldsToBigNumber(orderbook); - return messageObj; - } - case (OrderbookChannelMessageTypes.Update): { - assert.doesConformToSchema('message', messageObj, schemas.relayerApiOrderbookChannelUpdateSchema); - const order = messageObj.payload; - typeConverters.convertOrderStringFieldsToBigNumber(order); - return messageObj; - } - default: { - return { - type: OrderbookChannelMessageTypes.Unknown, - requestId: 0, - payload: undefined, - }; - } - } - }, -}; diff --git a/packages/connect/src/utils/relayer_response_json_parsers.ts b/packages/connect/src/utils/relayer_response_json_parsers.ts new file mode 100644 index 000000000..668461bf4 --- /dev/null +++ b/packages/connect/src/utils/relayer_response_json_parsers.ts @@ -0,0 +1,37 @@ +import { assert } from '@0xproject/assert'; +import { schemas } from '@0xproject/json-schemas'; +import * as _ from 'lodash'; + +import { FeesResponse, OrderbookResponse, SignedOrder, TokenPairsItem } from '../types'; + +import { typeConverters } from './type_converters'; + +export const relayerResponseJsonParsers = { + parseTokenPairsJson(json: any): TokenPairsItem[] { + assert.doesConformToSchema('tokenPairs', json, schemas.relayerApiTokenPairsResponseSchema); + return json.map((tokenPair: any) => { + return typeConverters.convertStringsFieldsToBigNumbers(tokenPair, [ + 'tokenA.minAmount', + 'tokenA.maxAmount', + 'tokenB.minAmount', + 'tokenB.maxAmount', + ]); + }); + }, + parseOrdersJson(json: any): SignedOrder[] { + assert.doesConformToSchema('orders', json, schemas.signedOrdersSchema); + return json.map((order: object) => typeConverters.convertOrderStringFieldsToBigNumber(order)); + }, + parseOrderJson(json: any): SignedOrder { + assert.doesConformToSchema('order', json, schemas.signedOrderSchema); + return typeConverters.convertOrderStringFieldsToBigNumber(json); + }, + parseOrderbookResponseJson(json: any): OrderbookResponse { + assert.doesConformToSchema('orderBook', json, schemas.relayerApiOrderBookResponseSchema); + return typeConverters.convertOrderbookStringFieldsToBigNumber(json); + }, + parseFeesResponseJson(json: any): FeesResponse { + assert.doesConformToSchema('fees', json, schemas.relayerApiFeesResponseSchema); + return typeConverters.convertStringsFieldsToBigNumbers(json, ['makerFee', 'takerFee']); + }, +}; diff --git a/packages/connect/src/utils/type_converters.ts b/packages/connect/src/utils/type_converters.ts index c136382fd..c1808ce8a 100644 --- a/packages/connect/src/utils/type_converters.ts +++ b/packages/connect/src/utils/type_converters.ts @@ -1,15 +1,17 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; -// TODO: convert all of these to non-mutating, pure functions export const typeConverters = { - convertOrderbookStringFieldsToBigNumber(orderbook: object): void { - _.each(orderbook, (orders: object[]) => { - _.each(orders, (order: object) => this.convertOrderStringFieldsToBigNumber(order)); - }); + convertOrderbookStringFieldsToBigNumber(orderbook: any): any { + const bids = _.get(orderbook, 'bids', []); + const asks = _.get(orderbook, 'asks', []); + return { + bids: bids.map((order: any) => this.convertOrderStringFieldsToBigNumber(order)), + asks: asks.map((order: any) => this.convertOrderStringFieldsToBigNumber(order)), + }; }, - convertOrderStringFieldsToBigNumber(order: object): void { - this.convertStringsFieldsToBigNumbers(order, [ + convertOrderStringFieldsToBigNumber(order: any): any { + return this.convertStringsFieldsToBigNumbers(order, [ 'makerTokenAmount', 'takerTokenAmount', 'makerFee', @@ -18,14 +20,11 @@ export const typeConverters = { 'salt', ]); }, - convertBigNumberFieldsToStrings(obj: object, fields: string[]): void { - _.each(fields, field => { - _.update(obj, field, (value: BigNumber) => value.toString()); - }); - }, - convertStringsFieldsToBigNumbers(obj: object, fields: string[]): void { + convertStringsFieldsToBigNumbers(obj: any, fields: string[]): any { + const result = _.assign({}, obj); _.each(fields, field => { - _.update(obj, field, (value: string) => new BigNumber(value)); + _.update(result, field, (value: string) => new BigNumber(value)); }); + return result; }, }; diff --git a/packages/connect/src/ws_orderbook_channel.ts b/packages/connect/src/ws_orderbook_channel.ts index 6687025c0..822a022f4 100644 --- a/packages/connect/src/ws_orderbook_channel.ts +++ b/packages/connect/src/ws_orderbook_channel.ts @@ -1,5 +1,5 @@ -import {assert} from '@0xproject/assert'; -import {schemas} from '@0xproject/json-schemas'; +import { assert } from '@0xproject/assert'; +import { schemas } from '@0xproject/json-schemas'; import * as _ from 'lodash'; import * as WebSocket from 'websocket'; @@ -8,21 +8,20 @@ import { OrderbookChannelHandler, OrderbookChannelMessageTypes, OrderbookChannelSubscriptionOpts, - SignedOrder, WebsocketClientEventType, WebsocketConnectionEventType, } from './types'; -import {orderbookChannelMessageParsers} from './utils/orderbook_channel_message_parsers'; +import { orderbookChannelMessageParser } from './utils/orderbook_channel_message_parser'; /** * This class includes all the functionality related to interacting with a websocket endpoint * that implements the standard relayer API v0 */ export class WebSocketOrderbookChannel implements OrderbookChannel { - private apiEndpointUrl: string; - private client: WebSocket.client; - private connectionIfExists?: WebSocket.connection; - private subscriptionCounter = 0; + private _apiEndpointUrl: string; + private _client: WebSocket.client; + private _connectionIfExists?: WebSocket.connection; + private _subscriptionCounter = 0; /** * Instantiates a new WebSocketOrderbookChannel instance * @param url The relayer API base WS url you would like to interact with @@ -30,8 +29,8 @@ export class WebSocketOrderbookChannel implements OrderbookChannel { */ constructor(url: string) { assert.isUri('url', url); - this.apiEndpointUrl = url; - this.client = new WebSocket.client(); + this._apiEndpointUrl = url; + this._client = new WebSocket.client(); } /** * Subscribe to orderbook snapshots and updates from the websocket @@ -42,16 +41,19 @@ export class WebSocketOrderbookChannel implements OrderbookChannel { */ public subscribe(subscriptionOpts: OrderbookChannelSubscriptionOpts, handler: OrderbookChannelHandler): void { assert.doesConformToSchema( - 'subscriptionOpts', subscriptionOpts, schemas.relayerApiOrderbookChannelSubscribePayload); + 'subscriptionOpts', + subscriptionOpts, + schemas.relayerApiOrderbookChannelSubscribePayload, + ); assert.isFunction('handler.onSnapshot', _.get(handler, 'onSnapshot')); assert.isFunction('handler.onUpdate', _.get(handler, 'onUpdate')); assert.isFunction('handler.onError', _.get(handler, 'onError')); assert.isFunction('handler.onClose', _.get(handler, 'onClose')); - this.subscriptionCounter += 1; + this._subscriptionCounter += 1; const subscribeMessage = { type: 'subscribe', channel: 'orderbook', - requestId: this.subscriptionCounter, + requestId: this._subscriptionCounter, payload: subscriptionOpts, }; this._getConnection((error, connection) => { @@ -75,44 +77,50 @@ export class WebSocketOrderbookChannel implements OrderbookChannel { * Close the websocket and stop receiving updates */ public close() { - if (!_.isUndefined(this.connectionIfExists)) { - this.connectionIfExists.close(); + if (!_.isUndefined(this._connectionIfExists)) { + this._connectionIfExists.close(); } } private _getConnection(callback: (error?: Error, connection?: WebSocket.connection) => void) { - if (!_.isUndefined(this.connectionIfExists) && this.connectionIfExists.connected) { - callback(undefined, this.connectionIfExists); + if (!_.isUndefined(this._connectionIfExists) && this._connectionIfExists.connected) { + callback(undefined, this._connectionIfExists); } else { - this.client.on(WebsocketClientEventType.Connect, connection => { - this.connectionIfExists = connection; - callback(undefined, this.connectionIfExists); + this._client.on(WebsocketClientEventType.Connect, connection => { + this._connectionIfExists = connection; + callback(undefined, this._connectionIfExists); }); - this.client.on(WebsocketClientEventType.ConnectFailed, error => { + this._client.on(WebsocketClientEventType.ConnectFailed, error => { callback(error, undefined); }); - this.client.connect(this.apiEndpointUrl); + this._client.connect(this._apiEndpointUrl); } } - private _handleWebSocketMessage(requestId: number, subscriptionOpts: OrderbookChannelSubscriptionOpts, - message: WebSocket.IMessage, handler: OrderbookChannelHandler): void { + private _handleWebSocketMessage( + requestId: number, + subscriptionOpts: OrderbookChannelSubscriptionOpts, + message: WebSocket.IMessage, + handler: OrderbookChannelHandler, + ): void { if (!_.isUndefined(message.utf8Data)) { try { const utf8Data = message.utf8Data; - const parserResult = orderbookChannelMessageParsers.parser(utf8Data); - const type = parserResult.type; + const parserResult = orderbookChannelMessageParser.parse(utf8Data); if (parserResult.requestId === requestId) { switch (parserResult.type) { - case (OrderbookChannelMessageTypes.Snapshot): { + case OrderbookChannelMessageTypes.Snapshot: { handler.onSnapshot(this, subscriptionOpts, parserResult.payload); break; } - case (OrderbookChannelMessageTypes.Update): { + case OrderbookChannelMessageTypes.Update: { handler.onUpdate(this, subscriptionOpts, parserResult.payload); break; } default: { handler.onError( - this, subscriptionOpts, new Error(`Message has missing a type parameter: ${utf8Data}`)); + this, + subscriptionOpts, + new Error(`Message has missing a type parameter: ${utf8Data}`), + ); } } } diff --git a/packages/connect/test/fixtures/standard_relayer_api/fees.ts b/packages/connect/test/fixtures/standard_relayer_api/fees.ts index 68421880e..fecbaacff 100644 --- a/packages/connect/test/fixtures/standard_relayer_api/fees.ts +++ b/packages/connect/test/fixtures/standard_relayer_api/fees.ts @@ -1,6 +1,6 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; -import {FeesResponse} from '../../../src/types'; +import { FeesResponse } from '../../../src/types'; export const feesResponse: FeesResponse = { feeRecipient: '0x323b5d4c32345ced77393b3530b1eed0f346429d', diff --git a/packages/connect/test/fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f.ts b/packages/connect/test/fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f.ts index 9df45065c..5a03a2ff6 100644 --- a/packages/connect/test/fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f.ts +++ b/packages/connect/test/fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f.ts @@ -1,4 +1,4 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; export const orderResponse = { maker: '0x9e56625509c2f60af937f23b7b532600390e8c8b', diff --git a/packages/connect/test/fixtures/standard_relayer_api/orderbook.json b/packages/connect/test/fixtures/standard_relayer_api/orderbook.json index bd6e10e4c..825be34c2 100644 --- a/packages/connect/test/fixtures/standard_relayer_api/orderbook.json +++ b/packages/connect/test/fixtures/standard_relayer_api/orderbook.json @@ -41,4 +41,4 @@ } } ] -}
\ No newline at end of file +} diff --git a/packages/connect/test/fixtures/standard_relayer_api/orderbook.ts b/packages/connect/test/fixtures/standard_relayer_api/orderbook.ts index 529d2b450..6684ac2e5 100644 --- a/packages/connect/test/fixtures/standard_relayer_api/orderbook.ts +++ b/packages/connect/test/fixtures/standard_relayer_api/orderbook.ts @@ -1,4 +1,4 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; export const orderbookResponse = { bids: [ diff --git a/packages/connect/test/fixtures/standard_relayer_api/orders.ts b/packages/connect/test/fixtures/standard_relayer_api/orders.ts index 54c8a150d..5044777bd 100644 --- a/packages/connect/test/fixtures/standard_relayer_api/orders.ts +++ b/packages/connect/test/fixtures/standard_relayer_api/orders.ts @@ -1,4 +1,4 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; export const ordersResponse = [ { diff --git a/packages/connect/test/fixtures/standard_relayer_api/token_pairs.ts b/packages/connect/test/fixtures/standard_relayer_api/token_pairs.ts index b3ae7a1b1..f48b1e877 100644 --- a/packages/connect/test/fixtures/standard_relayer_api/token_pairs.ts +++ b/packages/connect/test/fixtures/standard_relayer_api/token_pairs.ts @@ -1,6 +1,6 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; -import {TokenPairsItem} from '../../../src/types'; +import { TokenPairsItem } from '../../../src/types'; export const tokenPairsResponse: TokenPairsItem[] = [ { diff --git a/packages/connect/test/http_client_test.ts b/packages/connect/test/http_client_test.ts index 21e7abb69..15759d911 100644 --- a/packages/connect/test/http_client_test.ts +++ b/packages/connect/test/http_client_test.ts @@ -1,24 +1,21 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import * as chaiAsPromised from 'chai-as-promised'; import * as dirtyChai from 'dirty-chai'; import * as fetchMock from 'fetch-mock'; import 'mocha'; -import {HttpClient} from '../src/index'; +import { HttpClient } from '../src/index'; -import {feesResponse} from './fixtures/standard_relayer_api/fees'; +import { feesResponse } from './fixtures/standard_relayer_api/fees'; import * as feesResponseJSON from './fixtures/standard_relayer_api/fees.json'; -import { - orderResponse, -} from './fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f'; -// tslint:disable-next-line:max-line-length +import { orderResponse } from './fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f'; import * as orderResponseJSON from './fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f.json'; -import {orderbookResponse} from './fixtures/standard_relayer_api/orderbook'; +import { orderbookResponse } from './fixtures/standard_relayer_api/orderbook'; import * as orderbookJSON from './fixtures/standard_relayer_api/orderbook.json'; -import {ordersResponse} from './fixtures/standard_relayer_api/orders'; +import { ordersResponse } from './fixtures/standard_relayer_api/orders'; import * as ordersResponseJSON from './fixtures/standard_relayer_api/orders.json'; -import {tokenPairsResponse} from './fixtures/standard_relayer_api/token_pairs'; +import { tokenPairsResponse } from './fixtures/standard_relayer_api/token_pairs'; import * as tokenPairsResponseJSON from './fixtures/standard_relayer_api/token_pairs.json'; chai.config.includeStack = true; @@ -32,14 +29,23 @@ describe('HttpClient', () => { afterEach(() => { fetchMock.restore(); }); + describe('#constructor', () => { + it('should remove trailing slashes from api url', async () => { + const urlWithTrailingSlash = 'https://slash.com/'; + const urlWithoutTrailingSlash = 'https://slash.com'; + const client = new HttpClient(urlWithTrailingSlash); + const sanitizedUrl = (client as any)._apiEndpointUrl; + expect(sanitizedUrl).to.be.deep.equal(urlWithoutTrailingSlash); + }); + }); describe('#getTokenPairsAsync', () => { - const url = `${relayUrl}/v0/token_pairs`; + const url = `${relayUrl}/token_pairs`; it('gets token pairs', async () => { fetchMock.get(url, tokenPairsResponseJSON); const tokenPairs = await relayerClient.getTokenPairsAsync(); expect(tokenPairs).to.be.deep.equal(tokenPairsResponse); }); - it('gets specfic token pairs for request', async () => { + it('gets specific token pairs for request', async () => { const tokenAddress = '0x323b5d4c32345ced77393b3530b1eed0f346429d'; const tokenPairsRequest = { tokenA: tokenAddress, @@ -50,12 +56,12 @@ describe('HttpClient', () => { expect(tokenPairs).to.be.deep.equal(tokenPairsResponse); }); it('throws an error for invalid JSON response', async () => { - fetchMock.get(url, {test: 'dummy'}); + fetchMock.get(url, { test: 'dummy' }); expect(relayerClient.getTokenPairsAsync()).to.be.rejected(); }); }); describe('#getOrdersAsync', () => { - const url = `${relayUrl}/v0/orders`; + const url = `${relayUrl}/orders`; it('gets orders', async () => { fetchMock.get(url, ordersResponseJSON); const orders = await relayerClient.getOrdersAsync(); @@ -72,20 +78,20 @@ describe('HttpClient', () => { expect(orders).to.be.deep.equal(ordersResponse); }); it('throws an error for invalid JSON response', async () => { - fetchMock.get(url, {test: 'dummy'}); + fetchMock.get(url, { test: 'dummy' }); expect(relayerClient.getOrdersAsync()).to.be.rejected(); }); }); describe('#getOrderAsync', () => { const orderHash = '0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f'; - const url = `${relayUrl}/v0/order/${orderHash}`; + const url = `${relayUrl}/order/${orderHash}`; it('gets order', async () => { fetchMock.get(url, orderResponseJSON); const order = await relayerClient.getOrderAsync(orderHash); expect(order).to.be.deep.equal(orderResponse); }); it('throws an error for invalid JSON response', async () => { - fetchMock.get(url, {test: 'dummy'}); + fetchMock.get(url, { test: 'dummy' }); expect(relayerClient.getOrderAsync(orderHash)).to.be.rejected(); }); }); @@ -94,15 +100,16 @@ describe('HttpClient', () => { baseTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d', quoteTokenAddress: '0xa2b31dacf30a9c50ca473337c01d8a201ae33e32', }; - // tslint:disable-next-line:max-line-length - const url = `${relayUrl}/v0/orderbook?baseTokenAddress=${request.baseTokenAddress}"eTokenAddress=${request.quoteTokenAddress}`; + const url = `${relayUrl}/orderbook?baseTokenAddress=${request.baseTokenAddress}"eTokenAddress=${ + request.quoteTokenAddress + }`; it('gets order book', async () => { fetchMock.get(url, orderbookJSON); const orderbook = await relayerClient.getOrderbookAsync(request); expect(orderbook).to.be.deep.equal(orderbookResponse); }); it('throws an error for invalid JSON response', async () => { - fetchMock.get(url, {test: 'dummy'}); + fetchMock.get(url, { test: 'dummy' }); expect(relayerClient.getOrderbookAsync(request)).to.be.rejected(); }); }); @@ -118,14 +125,26 @@ describe('HttpClient', () => { salt: new BigNumber('256'), expirationUnixTimestampSec: new BigNumber('42'), }; - const url = `${relayUrl}/v0/fees`; + const url = `${relayUrl}/fees`; it('gets fees', async () => { fetchMock.post(url, feesResponseJSON); const fees = await relayerClient.getFeesAsync(request); expect(fees).to.be.deep.equal(feesResponse); }); + it('does not mutate input', async () => { + fetchMock.post(url, feesResponseJSON); + const makerTokenAmountBefore = new BigNumber(request.makerTokenAmount); + const takerTokenAmountBefore = new BigNumber(request.takerTokenAmount); + const saltBefore = new BigNumber(request.salt); + const expirationUnixTimestampSecBefore = new BigNumber(request.expirationUnixTimestampSec); + await relayerClient.getFeesAsync(request); + expect(makerTokenAmountBefore).to.be.deep.equal(request.makerTokenAmount); + expect(takerTokenAmountBefore).to.be.deep.equal(request.takerTokenAmount); + expect(saltBefore).to.be.deep.equal(request.salt); + expect(expirationUnixTimestampSecBefore).to.be.deep.equal(request.expirationUnixTimestampSec); + }); it('throws an error for invalid JSON response', async () => { - fetchMock.post(url, {test: 'dummy'}); + fetchMock.post(url, { test: 'dummy' }); expect(relayerClient.getFeesAsync(request)).to.be.rejected(); }); }); diff --git a/packages/connect/test/orderbook_channel_message_parsers_test.ts b/packages/connect/test/orderbook_channel_message_parsers_test.ts index 2c776b095..3e1f44384 100644 --- a/packages/connect/test/orderbook_channel_message_parsers_test.ts +++ b/packages/connect/test/orderbook_channel_message_parsers_test.ts @@ -2,16 +2,15 @@ import * as chai from 'chai'; import * as dirtyChai from 'dirty-chai'; import 'mocha'; -import {orderbookChannelMessageParsers} from '../src/utils/orderbook_channel_message_parsers'; +import { orderbookChannelMessageParser } from '../src/utils/orderbook_channel_message_parser'; -// tslint:disable-next-line:max-line-length -import {orderResponse} from './fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f'; -import {orderbookResponse} from './fixtures/standard_relayer_api/orderbook'; +import { orderResponse } from './fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f'; +import { orderbookResponse } from './fixtures/standard_relayer_api/orderbook'; import { malformedSnapshotOrderbookChannelMessage, snapshotOrderbookChannelMessage, } from './fixtures/standard_relayer_api/snapshot_orderbook_channel_message'; -import {unknownOrderbookChannelMessage} from './fixtures/standard_relayer_api/unknown_orderbook_channel_message'; +import { unknownOrderbookChannelMessage } from './fixtures/standard_relayer_api/unknown_orderbook_channel_message'; import { malformedUpdateOrderbookChannelMessage, updateOrderbookChannelMessage, @@ -21,20 +20,20 @@ chai.config.includeStack = true; chai.use(dirtyChai); const expect = chai.expect; -describe('orderbookChannelMessageParsers', () => { +describe('orderbookChannelMessageParser', () => { describe('#parser', () => { it('parses snapshot messages', () => { - const snapshotMessage = orderbookChannelMessageParsers.parser(snapshotOrderbookChannelMessage); + const snapshotMessage = orderbookChannelMessageParser.parse(snapshotOrderbookChannelMessage); expect(snapshotMessage.type).to.be.equal('snapshot'); expect(snapshotMessage.payload).to.be.deep.equal(orderbookResponse); }); it('parses update messages', () => { - const updateMessage = orderbookChannelMessageParsers.parser(updateOrderbookChannelMessage); + const updateMessage = orderbookChannelMessageParser.parse(updateOrderbookChannelMessage); expect(updateMessage.type).to.be.equal('update'); expect(updateMessage.payload).to.be.deep.equal(orderResponse); }); it('returns unknown message for messages with unsupported types', () => { - const unknownMessage = orderbookChannelMessageParsers.parser(unknownOrderbookChannelMessage); + const unknownMessage = orderbookChannelMessageParser.parse(unknownOrderbookChannelMessage); expect(unknownMessage.type).to.be.equal('unknown'); expect(unknownMessage.payload).to.be.undefined(); }); @@ -44,7 +43,7 @@ describe('orderbookChannelMessageParsers', () => { "requestId": 1, "payload": {} }`; - const badCall = () => orderbookChannelMessageParsers.parser(typelessMessage); + const badCall = () => orderbookChannelMessageParser.parse(typelessMessage); expect(badCall).throws(`Message is missing a type parameter: ${typelessMessage}`); }); it('throws when type is not a string', () => { @@ -54,24 +53,23 @@ describe('orderbookChannelMessageParsers', () => { "requestId": 1, "payload": {} }`; - const badCall = () => orderbookChannelMessageParsers.parser(messageWithBadType); + const badCall = () => orderbookChannelMessageParser.parse(messageWithBadType); expect(badCall).throws('Expected type to be of type string, encountered: 1'); }); it('throws when snapshot message has malformed payload', () => { - const badCall = () => - orderbookChannelMessageParsers.parser(malformedSnapshotOrderbookChannelMessage); + const badCall = () => orderbookChannelMessageParser.parse(malformedSnapshotOrderbookChannelMessage); // tslint:disable-next-line:max-line-length - const errMsg = 'Validation errors: instance.payload requires property "bids", instance.payload requires property "asks"'; + const errMsg = + 'Validation errors: instance.payload requires property "bids", instance.payload requires property "asks"'; expect(badCall).throws(errMsg); }); it('throws when update message has malformed payload', () => { - const badCall = () => - orderbookChannelMessageParsers.parser(malformedUpdateOrderbookChannelMessage); + const badCall = () => orderbookChannelMessageParser.parse(malformedUpdateOrderbookChannelMessage); expect(badCall).throws(/^Expected message to conform to schema/); }); it('throws when input message is not valid JSON', () => { const nonJsonString = 'h93b{sdfs9fsd f'; - const badCall = () => orderbookChannelMessageParsers.parser(nonJsonString); + const badCall = () => orderbookChannelMessageParser.parse(nonJsonString); expect(badCall).throws('Unexpected token h in JSON at position 0'); }); }); diff --git a/packages/connect/test/ws_orderbook_channel_test.ts b/packages/connect/test/ws_orderbook_channel_test.ts index 6190a5ac3..ce404d934 100644 --- a/packages/connect/test/ws_orderbook_channel_test.ts +++ b/packages/connect/test/ws_orderbook_channel_test.ts @@ -3,9 +3,7 @@ import * as dirtyChai from 'dirty-chai'; import * as _ from 'lodash'; import 'mocha'; -import { - WebSocketOrderbookChannel, -} from '../src/ws_orderbook_channel'; +import { WebSocketOrderbookChannel } from '../src/ws_orderbook_channel'; chai.config.includeStack = true; chai.use(dirtyChai); @@ -21,26 +19,42 @@ describe('WebSocketOrderbookChannel', () => { limit: 100, }; const emptyOrderbookChannelHandler = { - onSnapshot: () => { _.noop(); }, - onUpdate: () => { _.noop(); }, - onError: () => { _.noop(); }, - onClose: () => { _.noop(); }, + onSnapshot: () => { + _.noop(); + }, + onUpdate: () => { + _.noop(); + }, + onError: () => { + _.noop(); + }, + onClose: () => { + _.noop(); + }, }; describe('#subscribe', () => { it('throws when subscriptionOpts does not conform to schema', () => { const badSubscribeCall = orderbookChannel.subscribe.bind( - orderbookChannel, {}, emptyOrderbookChannelHandler); - // tslint:disable-next-line:max-line-length - expect(badSubscribeCall).throws('Expected subscriptionOpts to conform to schema /RelayerApiOrderbookChannelSubscribePayload\nEncountered: {}\nValidation errors: instance requires property "baseTokenAddress", instance requires property "quoteTokenAddress"'); + orderbookChannel, + {}, + emptyOrderbookChannelHandler, + ); + expect(badSubscribeCall).throws( + 'Expected subscriptionOpts to conform to schema /RelayerApiOrderbookChannelSubscribePayload\nEncountered: {}\nValidation errors: instance requires property "baseTokenAddress", instance requires property "quoteTokenAddress"', + ); }); it('throws when handler has the incorrect members', () => { const badSubscribeCall = orderbookChannel.subscribe.bind(orderbookChannel, subscriptionOpts, {}); - expect(badSubscribeCall) - .throws('Expected handler.onSnapshot to be of type function, encountered: undefined'); + expect(badSubscribeCall).throws( + 'Expected handler.onSnapshot to be of type function, encountered: undefined', + ); }); it('does not throw when inputs are of correct types', () => { const goodSubscribeCall = orderbookChannel.subscribe.bind( - orderbookChannel, subscriptionOpts, emptyOrderbookChannelHandler); + orderbookChannel, + subscriptionOpts, + emptyOrderbookChannelHandler, + ); expect(goodSubscribeCall).to.not.throw(); }); }); diff --git a/packages/connect/tsconfig.json b/packages/connect/tsconfig.json index a6c8277f8..3c150236e 100644 --- a/packages/connect/tsconfig.json +++ b/packages/connect/tsconfig.json @@ -1,19 +1,12 @@ { + "extends": "../../tsconfig", "compilerOptions": { - "module": "commonjs", - "target": "es5", - "lib": [ "es2015", "dom" ], - "outDir": "lib", - "sourceMap": true, - "declaration": true, - "noImplicitAny": true, - "strictNullChecks": true + "outDir": "lib" }, "include": [ - "./src/**/*", - "./test/**/*", - "../../node_modules/chai-as-promised-typescript-typings/index.d.ts", - "../../node_modules/chai-typescript-typings/index.d.ts", - "../../node_modules/web3-typescript-typings/index.d.ts" + "./src/**/*", + "./test/**/*", + "../../node_modules/chai-as-promised-typescript-typings/index.d.ts", + "../../node_modules/chai-typescript-typings/index.d.ts" ] - } +} diff --git a/packages/connect/tslint.json b/packages/connect/tslint.json index a07795151..ffaefe83a 100644 --- a/packages/connect/tslint.json +++ b/packages/connect/tslint.json @@ -1,5 +1,3 @@ { - "extends": [ - "@0xproject/tslint-config" - ] + "extends": ["@0xproject/tslint-config"] } |