Skip to content

Commit

Permalink
Merge pull request #784 from nemtech/dev
Browse files Browse the repository at this point in the history
Dev -> Main
  • Loading branch information
rg911 committed May 24, 2021
2 parents 1bb1d1c + e18100f commit 3a9a3cb
Show file tree
Hide file tree
Showing 7 changed files with 1,113 additions and 1,770 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.

The changelog format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [1.0.1] - 24-May-2021

**Milestone**: Symbol Mainnet
Package | Version | Link
---|---|---
SDK Core| v1.0.1 | [symbol-sdk](https://www.npmjs.com/package/symbol-sdk)
Catbuffer | v1.0.0 | [catbuffer-typescript](https://www.npmjs.com/package/catbuffer-typescript)
Client Library | v1.0.0 | [symbol-openapi-typescript-fetch-client](https://www.npmjs.com/package/symbol-openapi-typescript-fetch-client)

- Fixed missing `utf-8` dependancy issue.
- Fixed `UnhandledPromiseRejection` issue in http repository.

## [1.0.0] - 13-Mar-2021

**Milestone**: Symbol Mainnet
Expand Down
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -11,7 +11,7 @@ The Symbol SDK for TypeScript / JavaScript allows you to develop web, mobile, an

### _Catapult-Server_ Network Compatibility (catapult-server@0.10.0.8)

Symbol network pre-launch [catapult-server](https://github.com/nemtech/catapult-server/releases/tag/v0.10.0.8), **it is recommended to use this package's 0.23.3 version and upwards for the upcoming pre-release versions and final release**.
Symbol network launched [catapult-server](https://github.com/nemtech/catapult-server/releases/tag/v1.0.0.0), **it is recommended to use this package's 1.0.0 version and upwards for the Symbol public network**.

Find the complete release notes [here](CHANGELOG.md).

Expand Down
2,709 changes: 1,013 additions & 1,696 deletions package-lock.json

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions package.json
Expand Up @@ -5,11 +5,11 @@
"scripts": {
"pretest": "npm run build",
"prepack": "npm run build",
"test": "mocha --ui bdd --recursive ./dist/test --timeout 90000",
"test": "mocha --ui bdd --recursive ./dist/test --timeout 90000 --unhandled-rejections=strict ",
"e2econfigcopy": "gulp",
"test:e2e": "npm run build && mocha --ui bdd --recursive ./dist/e2e --timeout 90000",
"test:e2e": "npm run build && mocha --ui bdd --recursive ./dist/e2e --timeout 90000 --unhandled-rejections=strict",
"e2e": "npm run bootstrap-stop && npm run bootstrap-start-detached && npm run test:e2e && npm run bootstrap-stop",
"test:all": "mocha --ui bdd --recursive ./dist/ --timeout 90000",
"test:all": "mocha --ui bdd --recursive ./dist/ --timeout 90000 --unhandled-rejections=strict",
"build": "shx rm -rf dist/ && tsc && npm run e2econfigcopy",
"test:cov": "nyc --reporter=lcov --reporter=text-summary npm t",
"test:coveralls": "npm run test:cov | coveralls",
Expand Down Expand Up @@ -91,10 +91,9 @@
"symbol-bootstrap": "^0.4.3",
"ts-mockito": "^2.6.1",
"ts-node": "^8.10.2",
"typedoc": "^0.18.0",
"typedoc": "^0.20.36",
"typescript": "^3.9.7",
"typescript-require": "^0.2.10",
"utf8": "^2.1.2"
"typescript-require": "^0.2.10"
},
"dependencies": {
"@js-joda/core": "^3.2.0",
Expand All @@ -115,6 +114,7 @@
"rxjs-compat": "^6.6.3",
"symbol-openapi-typescript-fetch-client": "0.11.2",
"tweetnacl": "^1.0.3",
"utf8": "^2.1.2",
"ws": "^7.3.1"
},
"nyc": {
Expand Down
65 changes: 28 additions & 37 deletions src/infrastructure/Http.ts
Expand Up @@ -15,10 +15,9 @@
*/

import fetch from 'node-fetch';
import { from as observableFrom, Observable, of as observableOf, of, throwError } from 'rxjs';
import { catchError, flatMap, map } from 'rxjs/operators';
import { defer, from as observableFrom, Observable, of as observableOf } from 'rxjs';
import { Configuration, NodeRoutesApi, Pagination, querystring } from 'symbol-openapi-typescript-fetch-client';
import { NetworkType } from '../model/network/NetworkType';
import { NetworkType } from '../model/network';
import { Page } from './Page';
import { RepositoryCallError } from './RepositoryCallError';

Expand All @@ -33,9 +32,9 @@ export abstract class Http {
*/
protected constructor(protected readonly url: string, protected readonly fetchApi?: any) {}

public static errorHandling(error: any): Observable<never> {
public static async errorHandling(error: any): Promise<Error> {
if (error instanceof Error) {
return throwError(error);
return error;
}
const statusCode: number = parseInt(error?.status || error?.statusCode || error?.response?.statusCode || 0);
const statusMessage: string = (
Expand All @@ -55,29 +54,23 @@ export abstract class Http {
return JSON.stringify(body);
};

const getBody = (error: any): Observable<string> => {
const getBody = async (error: any): Promise<string> => {
const body = error?.response?.body;
if (body) {
return of(toString(body));
return toString(body);
}
if (error.text) {
return observableFrom(error.text()).pipe(
map(toString),
catchError(() => of('')),
);
return toString(await error.text());
}
return of('');
return '';
};
return getBody(error).pipe(
flatMap((body: string) => {
const formattedError: RepositoryCallError = {
statusCode,
statusMessage,
body,
};
return throwError(new Error(JSON.stringify(formattedError)));
}),
);

const formattedError: RepositoryCallError = {
statusCode,
statusMessage,
body: await getBody(error),
};
return new Error(JSON.stringify(formattedError));
}

createNetworkTypeObservable(networkType?: NetworkType | Observable<NetworkType>): Observable<NetworkType> {
Expand All @@ -86,7 +79,7 @@ export abstract class Http {
} else if (networkType) {
return observableOf(networkType as NetworkType);
} else {
return this.call(new NodeRoutesApi(this.config()).getNodeInfo(), (body) => body.networkIdentifier);
return defer(() => this.call(new NodeRoutesApi(this.config()).getNodeInfo(), (body) => body.networkIdentifier));
}
}

Expand All @@ -102,20 +95,18 @@ export abstract class Http {
*/
protected call<D, M>(remoteCall: Promise<D>, mapper: (value: D) => M): Observable<M> {
return observableFrom(
remoteCall.catch((e) => {
if (e instanceof Error) {
return Promise.resolve(e);
}
return Promise.reject(e);
}),
).pipe(
map((body) => {
if (body instanceof Error) {
throw body;
}
return mapper(body);
}),
catchError(Http.errorHandling),
new Promise<M>((resolve, reject) =>
remoteCall.then(
async (a) => {
try {
resolve(mapper(a));
} catch (e) {
reject(await Http.errorHandling(e));
}
},
async (e) => reject(await Http.errorHandling(e)),
),
),
);
}

Expand Down
6 changes: 3 additions & 3 deletions src/infrastructure/RepositoryFactoryHttp.ts
Expand Up @@ -98,9 +98,9 @@ export class RepositoryFactoryHttp implements RepositoryFactory {
this.generationHash = observableOf(configs.generationHash);
this.nodePublicKey = observableOf(configs.nodePublicKey);
} else {
const nodeInfoObservable = this.createNodeRepository().getNodeInfo();
this.generationHash = this.cache(() => nodeInfoObservable.pipe(map((b) => b.networkGenerationHashSeed)));
this.nodePublicKey = this.cache(() => nodeInfoObservable.pipe(map((b) => b.nodePublicKey)));
const nodeInfoObservable = this.cache(() => this.createNodeRepository().getNodeInfo());
this.generationHash = defer(() => nodeInfoObservable.pipe(map((b) => b.networkGenerationHashSeed)));
this.nodePublicKey = defer(() => nodeInfoObservable.pipe(map((b) => b.nodePublicKey)));
}
this.websocketUrl = configs?.websocketUrl ? configs?.websocketUrl : `${url.replace(/\/$/, '')}/ws`;
this.websocketInjected = configs?.websocketInjected;
Expand Down
77 changes: 50 additions & 27 deletions test/infrastructure/RepositoryFactory.spec.ts
Expand Up @@ -16,34 +16,36 @@
import { expect } from 'chai';
import { of as observableOf, of } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { NetworkConfigurationDTO } from 'symbol-openapi-typescript-fetch-client';
import { NetworkConfigurationDTO, NodeRoutesApi } from 'symbol-openapi-typescript-fetch-client';
import { instance, mock, when } from 'ts-mockito';
import { AccountHttp } from '../../src/infrastructure/AccountHttp';
import { BlockHttp } from '../../src/infrastructure/BlockHttp';
import { ChainHttp } from '../../src/infrastructure/ChainHttp';
import { FinalizationHttp } from '../../src/infrastructure/FinalizationHttp';
import { HashLockHttp } from '../../src/infrastructure/HashLockHttp';
import { Listener } from '../../src/infrastructure/Listener';
import { MetadataHttp } from '../../src/infrastructure/MetadataHttp';
import { MosaicHttp } from '../../src/infrastructure/MosaicHttp';
import { MultisigHttp } from '../../src/infrastructure/MultisigHttp';
import { NamespaceHttp } from '../../src/infrastructure/NamespaceHttp';
import { NamespaceRepository } from '../../src/infrastructure/NamespaceRepository';
import { NetworkHttp } from '../../src/infrastructure/NetworkHttp';
import { NetworkRepository } from '../../src/infrastructure/NetworkRepository';
import { NodeHttp } from '../../src/infrastructure/NodeHttp';
import { NodeRepository } from '../../src/infrastructure/NodeRepository';
import { ReceiptHttp } from '../../src/infrastructure/ReceiptHttp';
import { RepositoryFactoryHttp } from '../../src/infrastructure/RepositoryFactoryHttp';
import { RestrictionAccountHttp } from '../../src/infrastructure/RestrictionAccountHttp';
import { RestrictionMosaicHttp } from '../../src/infrastructure/RestrictionMosaicHttp';
import { SecretLockHttp } from '../../src/infrastructure/SecretLockHttp';
import { TransactionGroup } from '../../src/infrastructure/TransactionGroup';
import { TransactionHttp } from '../../src/infrastructure/TransactionHttp';
import { TransactionStatusHttp } from '../../src/infrastructure/TransactionStatusHttp';
import { NetworkCurrencies } from '../../src/model/mosaic/NetworkCurrencies';
import { NetworkType } from '../../src/model/network/NetworkType';
import { NodeInfo } from '../../src/model/node/NodeInfo';
import {
AccountHttp,
BlockHttp,
ChainHttp,
FinalizationHttp,
HashLockHttp,
Listener,
MetadataHttp,
MosaicHttp,
MultisigHttp,
NamespaceHttp,
NamespaceRepository,
NetworkHttp,
NetworkRepository,
NodeHttp,
NodeRepository,
ReceiptHttp,
RepositoryFactoryHttp,
RestrictionAccountHttp,
RestrictionMosaicHttp,
SecretLockHttp,
TransactionGroup,
TransactionHttp,
TransactionStatusHttp,
} from '../../src/infrastructure';
import { NetworkCurrencies } from '../../src/model/mosaic';
import { NetworkType } from '../../src/model/network';
import { NodeInfo } from '../../src/model/node';

describe('RepositoryFactory', () => {
it('Should create repositories', () => {
Expand All @@ -70,6 +72,27 @@ describe('RepositoryFactory', () => {
expect(repositoryFactory.createFinalizationRepository()).to.be.not.null;
});

it('Raise error without unhandled-rejections', async () => {
const nodeRoutesApi: NodeRoutesApi = mock();

const fetchResponseMock: Partial<Response> = {
status: 666,
statusText: 'Some status text error',
text: () => Promise.resolve('This is the body'),
};
when(nodeRoutesApi.getNodeHealth()).thenReturn(Promise.reject(fetchResponseMock));
const url = 'https://invalid';
const repositoryFactory = new RepositoryFactoryHttp(url);
try {
const nodeRepository = repositoryFactory.createNodeRepository();
(nodeRepository as any).nodeRoutesApi = instance(nodeRoutesApi);
await nodeRepository.getNodeHealth().toPromise();
expect(true).to.be.false;
} catch (e) {
expect(e.message).eq('{"statusCode":666,"statusMessage":"Some status text error","body":"This is the body"}');
}
});

it('Should get GenerationHash from cache', (done) => {
let counter = 0;
const repositoryMock: NodeRepository = mock();
Expand Down

0 comments on commit 3a9a3cb

Please sign in to comment.