From d9aee05092a7f84c80a5040ffcbc7b62504c6890 Mon Sep 17 00:00:00 2001 From: Fernando Boucquez Date: Tue, 25 Feb 2020 14:50:58 -0300 Subject: [PATCH 1/4] travis alpha deployments from master --- .travis.yml | 21 +++++++++++++-------- package-lock.json | 6 +++--- package.json | 5 +++-- travis/uploadArchives.sh | 11 +++++++++++ 4 files changed, 30 insertions(+), 13 deletions(-) create mode 100644 travis/uploadArchives.sh diff --git a/.travis.yml b/.travis.yml index fafd28714d..3b830b24ba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,17 +8,22 @@ cache: - "node_modules" before_script: - npm run build -script: +script: - npm run test:cov - npm run coveralls-report - npm install --global typedoc - typedoc --out ts-docs src - touch ./ts-docs/.nojekyll deploy: - provider: pages - skip_cleanup: true - local_dir: ts-docs - github_token: $GITHUB_TOKEN - on: - branch: master - + - provider: pages + skip_cleanup: true + local_dir: ts-docs + github_token: $GITHUB_TOKEN + on: + branch: master + - provider: script + skip_cleanup: true + script: /bin/sh travis/uploadArchives.sh + on: + branch: master + node_js: "8" diff --git a/package-lock.json b/package-lock.json index c34e5bdaf9..8ebc8ca7b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "symbol-sdk", - "version": "0.17.1", + "version": "0.17.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -4004,7 +4004,7 @@ }, "is-fullwidth-code-point": { "version": "2.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, @@ -4042,7 +4042,7 @@ }, "which-module": { "version": "2.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, diff --git a/package.json b/package.json index 73c6bad17a..210d1b3915 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "symbol-sdk", - "version": "0.17.1", + "version": "0.17.2", "description": "Reactive symbol sdk for typescript and javascript", "scripts": { "pretest": "npm run build", @@ -11,7 +11,8 @@ "build": "rm -rf dist/ && tsc && npm run e2econfigcopy", "test:cov": "nyc --reporter=lcov --reporter=text-summary npm t", "test:coveralls": "npm run test:cov | coveralls", - "coveralls-report": "cat ./coverage/lcov.info | coveralls" + "coveralls-report": "cat ./coverage/lcov.info | coveralls", + "version": "echo $npm_package_version" }, "contributors": [ { diff --git a/travis/uploadArchives.sh b/travis/uploadArchives.sh new file mode 100644 index 0000000000..99a22ba938 --- /dev/null +++ b/travis/uploadArchives.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -e + +CURRENT_VERSION=$(npm run version --silent) +NEW_VERSION="$CURRENT_VERSION-alpha-$(date +%Y%m%d%H%M)" + +echo "Uploading npm package version $NEW_VERSION" + +npm version "$NEW_VERSION" --commit-hooks false --git-tag-version false + +npm publish --tag alpha From 944cc9f2eca8f989980c0332ce85ced36a75c9fe Mon Sep 17 00:00:00 2001 From: Fernando Boucquez Date: Fri, 6 Mar 2020 11:10:17 -0300 Subject: [PATCH 2/4] Added account http unit tests. Code simplification Improved exception handling when the Observable error is in the code, not the http response. --- src/infrastructure/AccountHttp.ts | 116 +++++------- src/infrastructure/Http.ts | 2 +- test/infrastructure/AccountHttp.spec.ts | 237 ++++++++++++++++++++++++ test/infrastructure/NodeHttp.spec.ts | 2 +- 4 files changed, 281 insertions(+), 76 deletions(-) create mode 100644 test/infrastructure/AccountHttp.spec.ts diff --git a/src/infrastructure/AccountHttp.ts b/src/infrastructure/AccountHttp.ts index 8f918d2261..7cb5edce53 100644 --- a/src/infrastructure/AccountHttp.ts +++ b/src/infrastructure/AccountHttp.ts @@ -14,9 +14,8 @@ * limitations under the License. */ -import { from as observableFrom, Observable, throwError } from 'rxjs'; -import { catchError, map } from 'rxjs/operators'; -import { AccountInfoDTO, AccountRoutesApi } from 'symbol-openapi-typescript-node-client'; +import { Observable } from 'rxjs'; +import { AccountIds, AccountInfoDTO, AccountRoutesApi } from 'symbol-openapi-typescript-node-client'; import { AccountInfo } from '../model/account/AccountInfo'; import { ActivityBucket } from '../model/account/ActivityBucket'; import { Address } from '../model/account/Address'; @@ -58,25 +57,18 @@ export class AccountHttp extends Http implements AccountRepository { * @returns Observable */ public getAccountInfo(address: Address): Observable { - return observableFrom(this.accountRoutesApi.getAccountInfo(address.plain())).pipe( - map(({body}) => this.toAccountInfo(body)), - catchError((error) => throwError(this.errorHandling(error))), - ); + return this.call(this.accountRoutesApi.getAccountInfo(address.plain()), (body) => this.toAccountInfo(body)); } + /** * Gets AccountsInfo for different accounts. * @param addresses List of Address * @returns Observable */ public getAccountsInfo(addresses: Address[]): Observable { - const accountIdsBody = { - addresses: addresses.map((address) => address.plain()), - }; - return observableFrom( - this.accountRoutesApi.getAccountsInfo(accountIdsBody)).pipe( - map(({body}) => body.map(this.toAccountInfo)), - catchError((error) => throwError(this.errorHandling(error))), - ); + const accountIds = new AccountIds(); + accountIds.addresses = addresses.map((address) => address.plain()); + return this.call(this.accountRoutesApi.getAccountsInfo(accountIds), (body) => body.map(this.toAccountInfo)); } /** @@ -122,17 +114,13 @@ export class AccountHttp extends Http implements AccountRepository { public getAccountTransactions(address: Address, queryParams?: QueryParams, transactionFilter?: TransactionFilter): Observable { - return observableFrom( - this.accountRoutesApi.getAccountConfirmedTransactions(address.plain(), - this.queryParams(queryParams).pageSize, - this.queryParams(queryParams).id, - this.queryParams(queryParams).ordering, - this.transactionFilter(transactionFilter).type)).pipe( - map(({body}) => body.map((transactionDTO) => { - return CreateTransactionFromDTO(transactionDTO); - })), - catchError((error) => throwError(this.errorHandling(error))), - ); + + return this.call(this.accountRoutesApi.getAccountConfirmedTransactions(address.plain(), + this.queryParams(queryParams).pageSize, + this.queryParams(queryParams).id, + this.queryParams(queryParams).ordering, + this.transactionFilter(transactionFilter).type), + (body) => body.map((transactionDTO) => CreateTransactionFromDTO(transactionDTO))); } /** @@ -145,18 +133,13 @@ export class AccountHttp extends Http implements AccountRepository { */ public getAccountIncomingTransactions(address: Address, queryParams?: QueryParams, - transactionFilter?: TransactionFilter): Observable { - return observableFrom( - this.accountRoutesApi.getAccountIncomingTransactions(address.plain(), - this.queryParams(queryParams).pageSize, - this.queryParams(queryParams).id, - this.queryParams(queryParams).ordering), - this.transactionFilter(transactionFilter).type).pipe( - map(({body}) => body.map((transactionDTO) => { - return CreateTransactionFromDTO(transactionDTO); - })), - catchError((error) => throwError(this.errorHandling(error))), - ); + transactionFilter?: TransactionFilter): Observable { + return this.call(this.accountRoutesApi.getAccountIncomingTransactions(address.plain(), + this.queryParams(queryParams).pageSize, + this.queryParams(queryParams).id, + this.queryParams(queryParams).ordering, + this.transactionFilter(transactionFilter).type), + (body) => body.map((transactionDTO) => CreateTransactionFromDTO(transactionDTO))); } /** @@ -169,18 +152,13 @@ export class AccountHttp extends Http implements AccountRepository { */ public getAccountOutgoingTransactions(address: Address, queryParams?: QueryParams, - transactionFilter?: TransactionFilter): Observable { - return observableFrom( - this.accountRoutesApi.getAccountOutgoingTransactions(address.plain(), - this.queryParams(queryParams).pageSize, - this.queryParams(queryParams).id, - this.queryParams(queryParams).ordering), - this.transactionFilter(transactionFilter).type).pipe( - map(({body}) => body.map((transactionDTO) => { - return CreateTransactionFromDTO(transactionDTO); - })), - catchError((error) => throwError(this.errorHandling(error))), - ); + transactionFilter?: TransactionFilter): Observable { + return this.call(this.accountRoutesApi.getAccountOutgoingTransactions(address.plain(), + this.queryParams(queryParams).pageSize, + this.queryParams(queryParams).id, + this.queryParams(queryParams).ordering, + this.transactionFilter(transactionFilter).type), + (body) => body.map((transactionDTO) => CreateTransactionFromDTO(transactionDTO))); } /** @@ -194,18 +172,13 @@ export class AccountHttp extends Http implements AccountRepository { */ public getAccountUnconfirmedTransactions(address: Address, queryParams?: QueryParams, - transactionFilter?: TransactionFilter): Observable { - return observableFrom( - this.accountRoutesApi.getAccountUnconfirmedTransactions(address.plain(), - this.queryParams(queryParams).pageSize, - this.queryParams(queryParams).id, - this.queryParams(queryParams).ordering), - this.transactionFilter(transactionFilter).type).pipe( - map(({body}) => body.map((transactionDTO) => { - return CreateTransactionFromDTO(transactionDTO); - })), - catchError((error) => throwError(this.errorHandling(error))), - ); + transactionFilter?: TransactionFilter): Observable { + return this.call(this.accountRoutesApi.getAccountUnconfirmedTransactions(address.plain(), + this.queryParams(queryParams).pageSize, + this.queryParams(queryParams).id, + this.queryParams(queryParams).ordering, + this.transactionFilter(transactionFilter).type), + (body) => body.map((transactionDTO) => CreateTransactionFromDTO(transactionDTO))); } /** @@ -218,17 +191,12 @@ export class AccountHttp extends Http implements AccountRepository { */ public getAccountPartialTransactions(address: Address, queryParams?: QueryParams, - transactionFilter?: TransactionFilter): Observable { - return observableFrom( - this.accountRoutesApi.getAccountPartialTransactions(address.plain(), - this.queryParams(queryParams).pageSize, - this.queryParams(queryParams).id, - this.queryParams(queryParams).ordering), - this.transactionFilter(transactionFilter).type).pipe( - map(({body}) => body.map((transactionDTO) => { - return CreateTransactionFromDTO(transactionDTO) as AggregateTransaction; - })), - catchError((error) => throwError(this.errorHandling(error))), - ); + transactionFilter?: TransactionFilter): Observable { + return this.call(this.accountRoutesApi.getAccountPartialTransactions(address.plain(), + this.queryParams(queryParams).pageSize, + this.queryParams(queryParams).id, + this.queryParams(queryParams).ordering, + this.transactionFilter(transactionFilter).type), + (body) => body.map((transactionDTO) => CreateTransactionFromDTO(transactionDTO) as AggregateTransaction)); } } diff --git a/src/infrastructure/Http.ts b/src/infrastructure/Http.ts index 28e026ecf9..fc2a9aacd1 100644 --- a/src/infrastructure/Http.ts +++ b/src/infrastructure/Http.ts @@ -79,7 +79,7 @@ export abstract class Http { if (error.code && error.address && error.code === 'ECONNREFUSED') { return new Error(`Cannot reach node: ${error.address}:${error.port}`); } - return new Error(error); + return error; } /** diff --git a/test/infrastructure/AccountHttp.spec.ts b/test/infrastructure/AccountHttp.spec.ts new file mode 100644 index 0000000000..af989d18e5 --- /dev/null +++ b/test/infrastructure/AccountHttp.spec.ts @@ -0,0 +1,237 @@ +/* + * Copyright 2020 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { expect } from 'chai'; +import * as http from 'http'; +import { + AccountDTO, + AccountIds, + AccountInfoDTO, + AccountRoutesApi, + AccountTypeEnum, + ActivityBucketDTO, + Mosaic, + TransactionTypeEnum, +} from 'symbol-openapi-typescript-node-client'; +import { deepEqual, instance, mock, reset, when } from 'ts-mockito'; +import { DtoMapping } from '../../src/core/utils/DtoMapping'; +import { AccountHttp } from '../../src/infrastructure/AccountHttp'; +import { AccountRepository } from '../../src/infrastructure/AccountRepository'; +import { QueryParams } from '../../src/infrastructure/QueryParams'; +import { TransactionFilter } from '../../src/infrastructure/TransactionFilter'; +import { AccountInfo } from '../../src/model/account/AccountInfo'; +import { AccountType } from '../../src/model/account/AccountType'; +import { Address } from '../../src/model/account/Address'; +import { Transaction } from '../../src/model/transaction/Transaction'; +import { TransactionType } from '../../src/model/transaction/TransactionType'; + +describe('AccountHttp', () => { + + const address = Address.createFromRawAddress('MCTVW23D2MN5VE4AQ4TZIDZENGNOZXPRPR72DYSX'); + + const mosaic = new Mosaic(); + mosaic.amount = '777'; + mosaic.id = '941299B2B7E1291C'; + + const activityBucketDTO = new ActivityBucketDTO(); + activityBucketDTO.beneficiaryCount = 1; + activityBucketDTO.rawScore = 2; + activityBucketDTO.startHeight = '3'; + activityBucketDTO.totalFeesPaid = 4; + + const accountDTO = new AccountDTO(); + accountDTO.accountType = AccountTypeEnum.NUMBER_1; + accountDTO.address = address.encoded(); + accountDTO.addressHeight = '111'; + accountDTO.importance = '222'; + accountDTO.importanceHeight = '333'; + accountDTO.publicKeyHeight = '444'; + accountDTO.linkedAccountKey = 'abc'; + accountDTO.publicKey = 'AAA'; + accountDTO.activityBuckets = []; + accountDTO.mosaics = [mosaic]; + accountDTO.activityBuckets = [activityBucketDTO]; + + const accountInfoDto = new AccountInfoDTO(); + accountInfoDto.account = accountDTO; + + const url = 'http://someHost'; + const response: http.IncomingMessage = mock(); + const accountRoutesApi: AccountRoutesApi = mock(); + const accountRepository: AccountRepository = DtoMapping.assign(new AccountHttp(url), {accountRoutesApi: instance(accountRoutesApi)}); + + const transactionInfoDTO = { + meta: { + hash: '671653C94E2254F2A23EFEDB15D67C38332AED1FBD24B063C0A8E675582B6A96', + height: '18160', + id: '5A0069D83F17CF0001777E55', + index: 0, + merkleComponentHash: '81E5E7AE49998802DABC816EC10158D3A7879702FF29084C2C992CD1289877A7', + }, + transaction: { + deadline: '1000', + maxFee: '0', + signature: '939673209A13FF82397578D22CC96EB8516A6760C894D9B7535E3A1E0680' + + '07B9255CFA9A914C97142A7AE18533E381C846B69D2AE0D60D1DC8A55AD120E2B606', + signerPublicKey: '7681ED5023141D9CDCF184E5A7B60B7D466739918ED5DA30F7E71EA7B86EFF2D', + minApprovalDelta: 1, + minRemovalDelta: 1, + modifications: [ + { + cosignatoryPublicKey: '589B73FBC22063E9AE6FBAC67CB9C6EA865EF556E5' + + 'FB8B7310D45F77C1250B97', + modificationAction: 0, + }, + ], + type: 16725, + version: 1, + network: 144, + }, + }; + + before(() => { + reset(response); + reset(accountRoutesApi); + }); + + function assertAccountInfo(accountInfo: AccountInfo) { + expect(accountInfo).to.be.not.null; + expect(accountInfo.accountType).to.be.equals(AccountType.Main); + expect(accountInfo.addressHeight.toString()).to.be.equals(accountDTO.addressHeight); + expect(accountInfo.importance.toString()).to.be.equals(accountDTO.importance); + expect(accountInfo.importanceHeight.toString()).to.be.equals(accountDTO.importanceHeight); + expect(accountInfo.publicKeyHeight.toString()).to.be.equals(accountDTO.publicKeyHeight); + expect(accountInfo.publicKey).to.be.equals(accountDTO.publicKey); + expect(accountInfo.linkedAccountKey).to.be.equals(accountDTO.linkedAccountKey); + expect(accountInfo.mosaics.length).to.be.equals(1); + expect(accountInfo.mosaics[0].id.id.toHex()).to.be.equals(mosaic.id); + expect(accountInfo.mosaics[0].amount.toString()).to.be.equals(mosaic.amount); + + expect(accountInfo.activityBucket.length).to.be.equals(1); + expect(accountInfo.activityBucket[0].beneficiaryCount).to.be.equals(activityBucketDTO.beneficiaryCount); + expect(accountInfo.activityBucket[0].rawScore).to.be.equals(activityBucketDTO.rawScore); + expect(accountInfo.activityBucket[0].startHeight).to.be.equals(activityBucketDTO.startHeight); + expect(accountInfo.activityBucket[0].totalFeesPaid).to.be.equals(activityBucketDTO.totalFeesPaid); + } + + function assertTransaction(transaction: Transaction) { + expect(transaction).to.be.not.null; + expect(transaction.type).to.be.equals(transactionInfoDTO.transaction.type); + expect(transaction.deadline.toString()).to.be.equals(transactionInfoDTO.transaction.deadline); + } + + it('getAccountInfo', async () => { + when(accountRoutesApi.getAccountInfo(address.plain())).thenReturn(Promise.resolve({response, body: accountInfoDto})); + const accountInfo = await accountRepository.getAccountInfo(address).toPromise(); + assertAccountInfo(accountInfo); + }); + + it('getAccountsInfo', async () => { + const accountIds = new AccountIds(); + accountIds.addresses = [address.plain()]; + when(accountRoutesApi.getAccountsInfo(deepEqual(accountIds))).thenReturn(Promise.resolve({response, body: [accountInfoDto]})); + const accountInfos = await accountRepository.getAccountsInfo([address]).toPromise(); + assertAccountInfo(accountInfos[0]); + }); + + it('getAccountTransactions', async () => { + when(accountRoutesApi.getAccountConfirmedTransactions(address.plain(), 1, 'a', '-id', + deepEqual([TransactionTypeEnum.NUMBER_16725]))).thenReturn(Promise.resolve({ + response, + body: [transactionInfoDTO], + })); + const transactions = await accountRepository.getAccountTransactions(address, new QueryParams({ + pageSize: 1, + id: 'a', + }), new TransactionFilter({types: [TransactionType.MULTISIG_ACCOUNT_MODIFICATION]})).toPromise(); + assertTransaction(transactions[0]); + }); + + it('getAccountTransactions', async () => { + when(accountRoutesApi.getAccountConfirmedTransactions(address.plain(), undefined, undefined, + undefined, undefined)).thenReturn(Promise.resolve({ + response, + body: [transactionInfoDTO], + })); + const transactions = await accountRepository.getAccountTransactions(address).toPromise(); + assertTransaction(transactions[0]); + }); + + it('getAccountIncomingTransactions', async () => { + when(accountRoutesApi.getAccountIncomingTransactions(address.plain(), 1, 'a', '-id', + deepEqual([TransactionTypeEnum.NUMBER_16725]))).thenReturn(Promise.resolve({ + response, + body: [transactionInfoDTO], + })); + const transactions = await accountRepository.getAccountIncomingTransactions(address, new QueryParams({ + pageSize: 1, + id: 'a', + }), new TransactionFilter({types: [TransactionType.MULTISIG_ACCOUNT_MODIFICATION]})).toPromise(); + assertTransaction(transactions[0]); + }); + + it('getAccountOutgoingTransactions', async () => { + when(accountRoutesApi.getAccountOutgoingTransactions(address.plain(), 1, 'a', '-id', + deepEqual([TransactionTypeEnum.NUMBER_16725]))).thenReturn(Promise.resolve({ + response, + body: [transactionInfoDTO], + })); + const transactions = await accountRepository.getAccountOutgoingTransactions(address, new QueryParams({ + pageSize: 1, + id: 'a', + }), new TransactionFilter({types: [TransactionType.MULTISIG_ACCOUNT_MODIFICATION]})).toPromise(); + assertTransaction(transactions[0]); + }); + + it('getAccountPartialTransactions', async () => { + when(accountRoutesApi.getAccountPartialTransactions(address.plain(), 1, 'a', '-id', + deepEqual([TransactionTypeEnum.NUMBER_16725]))).thenReturn(Promise.resolve({ + response, + body: [transactionInfoDTO], + })); + const transactions = await accountRepository.getAccountPartialTransactions(address, new QueryParams({ + pageSize: 1, + id: 'a', + }), new TransactionFilter({types: [TransactionType.MULTISIG_ACCOUNT_MODIFICATION]})).toPromise(); + assertTransaction(transactions[0]); + }); + + it('getAccountUnconfirmedTransactions', async () => { + when(accountRoutesApi.getAccountUnconfirmedTransactions(address.plain(), 2, 'b', '-id', + deepEqual([TransactionTypeEnum.NUMBER_16725]))).thenReturn(Promise.resolve({ + response, + body: [transactionInfoDTO], + })); + const transactions = await accountRepository.getAccountUnconfirmedTransactions(address, new QueryParams({ + pageSize: 2, + id: 'b', + }), new TransactionFilter({types: [TransactionType.MULTISIG_ACCOUNT_MODIFICATION]})).toPromise(); + assertTransaction(transactions[0]); + }); + + it('getAccountPartialTransactions', async () => { + when(accountRoutesApi.getAccountPartialTransactions(address.plain(), 1, 'a', '-id', + deepEqual([TransactionTypeEnum.NUMBER_16725]))).thenReturn(Promise.resolve({ + response, + body: [transactionInfoDTO], + })); + const transactions = await accountRepository.getAccountPartialTransactions(address, new QueryParams({ + pageSize: 1, + id: 'a', + }), new TransactionFilter({types: [TransactionType.MULTISIG_ACCOUNT_MODIFICATION]})).toPromise(); + assertTransaction(transactions[0]); + }); + +}); diff --git a/test/infrastructure/NodeHttp.spec.ts b/test/infrastructure/NodeHttp.spec.ts index c3a15daaa7..db62b06607 100644 --- a/test/infrastructure/NodeHttp.spec.ts +++ b/test/infrastructure/NodeHttp.spec.ts @@ -142,7 +142,7 @@ describe('NodeHttp', () => { try { await nodeRepository.getNodeTime().toPromise(); } catch (e) { - expect(e.message).to.deep.equals('Error: Node time not available'); + expect(e.message).to.deep.equals('Node time not available'); } }); From e01bf44e4300fbd0ccfa96566c3fadf7ba6a8da9 Mon Sep 17 00:00:00 2001 From: Fernando Boucquez Date: Fri, 6 Mar 2020 11:12:34 -0300 Subject: [PATCH 3/4] Improved exception handling when the Observable error is in the code, not the http response. --- src/infrastructure/Http.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/infrastructure/Http.ts b/src/infrastructure/Http.ts index fc2a9aacd1..238609b4c3 100644 --- a/src/infrastructure/Http.ts +++ b/src/infrastructure/Http.ts @@ -79,7 +79,10 @@ export abstract class Http { if (error.code && error.address && error.code === 'ECONNREFUSED') { return new Error(`Cannot reach node: ${error.address}:${error.port}`); } - return error; + if (error instanceof Error) { + return error; + } + return new Error(error); } /** From 8329571596813569469dac99e57c02c8befb3fd8 Mon Sep 17 00:00:00 2001 From: Fernando Boucquez Date: Fri, 6 Mar 2020 11:18:15 -0300 Subject: [PATCH 4/4] Increase version for the new version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1c1177dae9..653e9a7f81 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "symbol-sdk", - "version": "0.17.3", + "version": "0.17.4", "description": "Reactive symbol sdk for typescript and javascript", "scripts": { "pretest": "npm run build",