diff --git a/packages/blockchain-link/package.json b/packages/blockchain-link/package.json index c6f5e289b21..4c4a1dd4d3c 100644 --- a/packages/blockchain-link/package.json +++ b/packages/blockchain-link/package.json @@ -44,6 +44,7 @@ "devDependencies": { "@babel/register": "^7.13.14", "@babel/runtime": "^7.13.10", + "@trezor/utils": "*", "babel-eslint": "^10.1.0", "babel-loader": "^8.2.1", "eslint-config-airbnb-base": "^14.2.1", diff --git a/packages/blockchain-link/src/index.ts b/packages/blockchain-link/src/index.ts index cdacb0acc09..1e0a889a519 100644 --- a/packages/blockchain-link/src/index.ts +++ b/packages/blockchain-link/src/index.ts @@ -1,12 +1,14 @@ import { EventEmitter } from 'events'; +import { createDeferred } from '@trezor/utils'; import { CustomError } from './constants/errors'; import { MESSAGES, RESPONSES } from './constants'; -import { create as createDeferred, Deferred } from './utils/deferred'; import { BlockchainSettings } from './types'; import * as ResponseTypes from './types/responses'; import * as MessageTypes from './types/messages'; import { Events } from './types/events'; +import type { Deferred } from '@trezor/utils'; + const workerWrapper = (factory: BlockchainSettings['worker']): Worker => { if (typeof factory === 'function') return factory(); if (typeof factory === 'string' && typeof Worker !== 'undefined') return new Worker(factory); diff --git a/packages/blockchain-link/src/workers/blockbook/websocket.ts b/packages/blockchain-link/src/workers/blockbook/websocket.ts index a25ad8484e2..05fac9d61ae 100644 --- a/packages/blockchain-link/src/workers/blockbook/websocket.ts +++ b/packages/blockchain-link/src/workers/blockbook/websocket.ts @@ -1,7 +1,8 @@ import WebSocket from 'ws'; import { EventEmitter } from 'events'; +import { createDeferred } from '@trezor/utils'; + import { CustomError } from '../../constants/errors'; -import { create as createDeferred, Deferred } from '../../utils/deferred'; import { BlockNotification, AddressNotification, @@ -18,6 +19,7 @@ import { EstimateFeeParams, AccountBalanceHistoryParams, } from '../../types/params'; +import type { Deferred } from '@trezor/utils'; const NOT_INITIALIZED = new CustomError('websocket_not_initialized'); diff --git a/packages/blockchain-link/src/workers/blockfrost/websocket.ts b/packages/blockchain-link/src/workers/blockfrost/websocket.ts index 9514173c2f7..c53292de6c7 100644 --- a/packages/blockchain-link/src/workers/blockfrost/websocket.ts +++ b/packages/blockchain-link/src/workers/blockfrost/websocket.ts @@ -1,10 +1,13 @@ import WebSocket from 'ws'; import { EventEmitter } from 'events'; +import { createDeferred } from '@trezor/utils'; + import { CustomError } from '../../constants/errors'; -import { create as createDeferred, Deferred } from '../../utils/deferred'; import { Send, BlockContent } from '../../types/blockfrost'; import { AccountInfoParams, EstimateFeeParams } from '../../types/params'; +import type { Deferred } from '@trezor/utils'; + const NOT_INITIALIZED = new CustomError('websocket_not_initialized'); interface Subscription { diff --git a/packages/integration-tests/projects/suite-web/plugins/websocket-client.js b/packages/integration-tests/projects/suite-web/plugins/websocket-client.js index 6694492d647..b63f2e49f08 100644 --- a/packages/integration-tests/projects/suite-web/plugins/websocket-client.js +++ b/packages/integration-tests/projects/suite-web/plugins/websocket-client.js @@ -1,26 +1,10 @@ /* eslint-disable @typescript-eslint/no-var-requires */ const WebSocket = require('ws'); const { EventEmitter } = require('events'); +const { createDeferred } = require('@trezor/utils'); const NOT_INITIALIZED = new Error('websocket_not_initialized'); -const createDeferred = id => { - let localResolve = t => () => {}; - let localReject = e => () => {}; - - const promise = new Promise((resolve, reject) => { - localResolve = resolve; - localReject = reject; - }); - - return { - id, - resolve: localResolve, - reject: localReject, - promise, - }; -}; - // Making the timeout high because the controller in trezor-user-env // must synchronously run actions on emulator and they may take a long time // (for example in case of Shamir backup) diff --git a/packages/suite/src/actions/suite/metadataActions.ts b/packages/suite/src/actions/suite/metadataActions.ts index b52fad280f4..c66a2f5ae56 100644 --- a/packages/suite/src/actions/suite/metadataActions.ts +++ b/packages/suite/src/actions/suite/metadataActions.ts @@ -1,6 +1,6 @@ import TrezorConnect from 'trezor-connect'; +import { createDeferred } from '@trezor/utils'; import { METADATA } from '@suite-actions/constants'; -import { createDeferred } from '@suite-utils/deferred'; import { Dispatch, GetState } from '@suite-types'; import { MetadataProviderType, @@ -216,7 +216,7 @@ export const disableMetadata = () => (dispatch: Dispatch) => { }; export const initProvider = () => (dispatch: Dispatch) => { - const decision = createDeferred(); + const decision = createDeferred(-1); dispatch(modalActions.openModal({ type: 'metadata-provider', decision })); return decision.promise; }; diff --git a/packages/suite/src/actions/suite/modalActions.ts b/packages/suite/src/actions/suite/modalActions.ts index d9885efadd8..61d10d550c9 100644 --- a/packages/suite/src/actions/suite/modalActions.ts +++ b/packages/suite/src/actions/suite/modalActions.ts @@ -1,8 +1,8 @@ import TrezorConnect, { UI } from 'trezor-connect'; +import { createDeferred, Deferred, DeferredResponse } from '@trezor/utils'; import { MODAL, SUITE } from '@suite-actions/constants'; import { Route, Dispatch, GetState, TrezorDevice } from '@suite-types'; import { Account, WalletAccountTransaction } from '@wallet-types'; -import { createDeferred, Deferred, DeferredResponse } from '@suite-utils/deferred'; export type UserContextPayload = | { @@ -213,7 +213,7 @@ type DeferredPayload = { type: T } & DeferredR export const openDeferredModal = (payload: DeferredPayload) => (dispatch: Dispatch) => { - const dfd = createDeferred['decision']>>(); + const dfd = createDeferred['decision']>>(-1); dispatch({ type: MODAL.OPEN_USER_CONTEXT, payload: { diff --git a/packages/suite/src/components/suite/modals/confirm/CoinmarketBuyTerms/index.tsx b/packages/suite/src/components/suite/modals/confirm/CoinmarketBuyTerms/index.tsx index 7b51532c0e2..2341bdd43ae 100644 --- a/packages/suite/src/components/suite/modals/confirm/CoinmarketBuyTerms/index.tsx +++ b/packages/suite/src/components/suite/modals/confirm/CoinmarketBuyTerms/index.tsx @@ -2,7 +2,7 @@ import { Button, Icon, variables, Checkbox, H3 } from '@trezor/components'; import React, { useState } from 'react'; import { Translation, Modal } from '@suite-components'; import styled, { css } from 'styled-components'; -import { Deferred } from '@suite-utils/deferred'; +import type { Deferred } from '@trezor/utils'; const Text = styled.div<{ isLast?: boolean; isFirst?: boolean }>` padding: 20px 0; diff --git a/packages/suite/src/components/suite/modals/confirm/CoinmarketExchangeDexTerms/index.tsx b/packages/suite/src/components/suite/modals/confirm/CoinmarketExchangeDexTerms/index.tsx index 2e29b9f01c8..af453524a9a 100644 --- a/packages/suite/src/components/suite/modals/confirm/CoinmarketExchangeDexTerms/index.tsx +++ b/packages/suite/src/components/suite/modals/confirm/CoinmarketExchangeDexTerms/index.tsx @@ -2,7 +2,7 @@ import { Button, Icon, variables, Checkbox } from '@trezor/components'; import React, { useState } from 'react'; import { Translation, Modal } from '@suite-components'; import styled, { css } from 'styled-components'; -import { Deferred } from '@suite-utils/deferred'; +import type { Deferred } from '@trezor/utils'; const Text = styled.div<{ isLast?: boolean; isFirst?: boolean }>` padding: 20px 0; diff --git a/packages/suite/src/components/suite/modals/confirm/CoinmarketExchangeTerms/index.tsx b/packages/suite/src/components/suite/modals/confirm/CoinmarketExchangeTerms/index.tsx index 124353be97f..ed888c293aa 100644 --- a/packages/suite/src/components/suite/modals/confirm/CoinmarketExchangeTerms/index.tsx +++ b/packages/suite/src/components/suite/modals/confirm/CoinmarketExchangeTerms/index.tsx @@ -2,7 +2,7 @@ import { Button, Icon, variables, Checkbox, H3 } from '@trezor/components'; import React, { useState } from 'react'; import { Translation, Modal } from '@suite-components'; import styled, { css } from 'styled-components'; -import { Deferred } from '@suite-utils/deferred'; +import type { Deferred } from '@trezor/utils'; const Text = styled.div<{ isLast?: boolean; isFirst?: boolean }>` padding: 20px 0; diff --git a/packages/suite/src/components/suite/modals/confirm/CoinmarketSellTerms/index.tsx b/packages/suite/src/components/suite/modals/confirm/CoinmarketSellTerms/index.tsx index 01eaaa70a9b..5f415157a3e 100644 --- a/packages/suite/src/components/suite/modals/confirm/CoinmarketSellTerms/index.tsx +++ b/packages/suite/src/components/suite/modals/confirm/CoinmarketSellTerms/index.tsx @@ -2,7 +2,7 @@ import { Button, Icon, variables, Checkbox, H3 } from '@trezor/components'; import React, { useState } from 'react'; import { Translation, Modal } from '@suite-components'; import styled, { css } from 'styled-components'; -import { Deferred } from '@suite-utils/deferred'; +import type { Deferred } from '@trezor/utils'; const Text = styled.div<{ isLast?: boolean; isFirst?: boolean }>` padding: 20px 0; diff --git a/packages/suite/src/components/suite/modals/metadata/MetadataProvider/index.tsx b/packages/suite/src/components/suite/modals/metadata/MetadataProvider/index.tsx index 2ec1049a537..ec033dd1493 100644 --- a/packages/suite/src/components/suite/modals/metadata/MetadataProvider/index.tsx +++ b/packages/suite/src/components/suite/modals/metadata/MetadataProvider/index.tsx @@ -5,7 +5,7 @@ import { P, Button, variables } from '@trezor/components'; import { Translation, Modal } from '@suite-components'; import { useActions } from '@suite-hooks'; import * as metadataActions from '@suite-actions/metadataActions'; -import { Deferred } from '@suite-utils/deferred'; +import type { Deferred } from '@trezor/utils'; import { MetadataProviderType } from '@suite-types/metadata'; import { isEnabled } from '@suite-utils/features'; diff --git a/packages/suite/src/hooks/suite/useAsyncDebounce.ts b/packages/suite/src/hooks/suite/useAsyncDebounce.ts index b82f6607efd..aded4aac724 100644 --- a/packages/suite/src/hooks/suite/useAsyncDebounce.ts +++ b/packages/suite/src/hooks/suite/useAsyncDebounce.ts @@ -1,5 +1,5 @@ import { useCallback, useRef } from 'react'; -import { createDeferred } from '@suite-utils/deferred'; +import { createDeferred } from '@trezor/utils'; type TimeoutType = ReturnType; // resolves to Timeout type in react-native, number otherwise @@ -14,7 +14,7 @@ export const useAsyncDebounce = () => { // clear previous timeout if (timeout.current) clearTimeout(timeout.current); // set new timeout - const timeoutDfd = createDeferred(); + const timeoutDfd = createDeferred(-1); // @ts-ignore needed with @types/react-native 0.63.45, could be a bug const newTimeout = setTimeout(timeoutDfd.resolve, 300); // @ts-ignore needed with @types/react-native 0.63.45, could be a bug diff --git a/packages/suite/src/reducers/wallet/discoveryReducer.ts b/packages/suite/src/reducers/wallet/discoveryReducer.ts index 5386bc5092a..a955a5f67a3 100644 --- a/packages/suite/src/reducers/wallet/discoveryReducer.ts +++ b/packages/suite/src/reducers/wallet/discoveryReducer.ts @@ -1,7 +1,7 @@ import produce from 'immer'; import { DISCOVERY } from '@wallet-actions/constants'; import { STORAGE } from '@suite-actions/constants'; -import { Deferred, createDeferred } from '@suite-utils/deferred'; +import { Deferred, createDeferred } from '@trezor/utils'; import { ObjectValues } from '@suite/types/utils'; import { Action as SuiteAction } from '@suite-types'; import { WalletAction, Network } from '@wallet-types'; @@ -46,7 +46,7 @@ const start = (draft: State, payload: PartialDiscovery) => { draft[index] = { ...draft[index], ...payload, - running: createDeferred(), + running: createDeferred(-1), }; } }; diff --git a/packages/suite/src/utils/suite/deferred.ts b/packages/suite/src/utils/suite/deferred.ts deleted file mode 100644 index 820904dd302..00000000000 --- a/packages/suite/src/utils/suite/deferred.ts +++ /dev/null @@ -1,28 +0,0 @@ -export interface Deferred { - data?: Data; - promise: Promise; - resolve: (t: Response) => void; - reject: (e: Error) => void; -} - -// unwrap promise response from Deferred -export type DeferredResponse = D extends Deferred ? R : never; - -export const createDeferred = ( - data?: Data, -): Deferred => { - let localResolve: (t: Response) => void = () => {}; - let localReject: (e: Error) => void = () => {}; - - const promise: Promise = new Promise((resolve, reject) => { - localResolve = resolve; - localReject = reject; - }); - - return { - data, - resolve: localResolve, - reject: localReject, - promise, - }; -}; diff --git a/packages/suite/src/utils/suite/oauth.ts b/packages/suite/src/utils/suite/oauth.ts index 8587cb5e152..e140a87c8bd 100644 --- a/packages/suite/src/utils/suite/oauth.ts +++ b/packages/suite/src/utils/suite/oauth.ts @@ -2,7 +2,7 @@ import { getPrefixedURL } from '@suite-utils/router'; import { METADATA } from '@suite-actions/constants'; -import { Deferred, createDeferred } from '@suite-utils/deferred'; +import { Deferred, createDeferred } from '@trezor/utils'; import { urlHashParams, urlSearchParams } from '@suite-utils/metadata'; /** @@ -142,7 +142,7 @@ const getWebHandlerInstance = ( */ export const extractCredentialsFromAuthorizationFlow = (url: string) => { const originalParams = urlHashParams(url); - const dfd: Deferred = createDeferred(); + const dfd: Deferred = createDeferred(-1); const { desktopApi } = window; diff --git a/packages/suite/src/utils/wallet/promiseUtils.ts b/packages/suite/src/utils/wallet/promiseUtils.ts deleted file mode 100644 index 1fd353af2ab..00000000000 --- a/packages/suite/src/utils/wallet/promiseUtils.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const resolveAfter = (msec: number, ...params: any[]): Promise => - new Promise(resolve => { - setTimeout(resolve, msec, ...params); - }); diff --git a/packages/transport/src/lowlevel/sharedConnectionWorker.ts b/packages/transport/src/lowlevel/sharedConnectionWorker.ts index e8f5424e08c..321153283a3 100644 --- a/packages/transport/src/lowlevel/sharedConnectionWorker.ts +++ b/packages/transport/src/lowlevel/sharedConnectionWorker.ts @@ -6,9 +6,8 @@ // about intent to acquire/release and then send another message when that is done. // Other windows then can acquire/release -// @ts-ignore -import { create as createDefered } from '../utils/defered'; -import type { Deferred } from '../utils/defered'; +import { createDeferred } from '@trezor/utils'; +import type { Deferred } from '@trezor/utils'; import type { TrezorDeviceInfoDebug } from './sharedPlugin'; import type { MessageFromSharedWorker, MessageToSharedWorker } from './withSharedConnections'; @@ -34,7 +33,7 @@ let waitPromise: Promise = Promise.resolve(); type PortObject = { postMessage: (message: Object) => void }; function startLock(): void { - const newLock = createDefered(); + const newLock = createDeferred(-1); lock = newLock; setTimeout(() => newLock.reject(new Error(`Timed out`)), 10 * 1000); } diff --git a/packages/transport/src/lowlevel/withSharedConnections.ts b/packages/transport/src/lowlevel/withSharedConnections.ts index 05a94429779..65b5fdf5d9d 100644 --- a/packages/transport/src/lowlevel/withSharedConnections.ts +++ b/packages/transport/src/lowlevel/withSharedConnections.ts @@ -1,12 +1,13 @@ // @ts-nocheck -import { create as createDefered, resolveTimeoutPromise } from '../utils/defered'; +import { createDeferred } from '@trezor/utils'; +import { resolveTimeoutPromise } from '../utils/defered'; import { parseConfigure } from './protobuf/messages'; import { buildAndSend } from './send'; import { receiveAndParse } from './receive'; import type { LowlevelTransportSharedPlugin, TrezorDeviceInfoDebug } from './sharedPlugin'; -import type { Deferred } from '../utils/defered'; +import type { Deferred } from '@trezor/utils'; import type { MessageFromTrezor, TrezorDeviceInfoWithSession, AcquireInput } from '../types'; import { postModuleMessage } from './sharedConnectionWorker'; @@ -249,9 +250,9 @@ export default class LowlevelTransportWithSharedConnections { const session: string = messBack2.number; if (debugLink) { - this.deferedDebugOnRelease[session] = createDefered(); + this.deferedDebugOnRelease[session] = createDeferred(-1); } else { - this.deferedNormalOnRelease[session] = createDefered(); + this.deferedNormalOnRelease[session] = createDeferred(-1); } return session; } @@ -425,7 +426,7 @@ export default class LowlevelTransportWithSharedConnections { this.latestId++; const id = this.latestId; - this.defereds[id] = createDefered(); + this.defereds[id] = createDeferred(-1); // when shared worker is not loaded as a shared loader, use it as a module instead if (this.sharedWorker != null) { diff --git a/packages/transport/src/utils/defered.ts b/packages/transport/src/utils/defered.ts index 3cbbb9b441e..46b34223177 100644 --- a/packages/transport/src/utils/defered.ts +++ b/packages/transport/src/utils/defered.ts @@ -1,30 +1,4 @@ -export type Deferred = { - promise: Promise; - resolve: (t: T) => void; - reject: (e: Error) => void; - rejectingPromise: Promise; -}; - -export function create(): Deferred { - let localResolve: (t: T) => void = () => {}; - let localReject: (e?: Error) => void = () => {}; - - const promise = new Promise((resolve, reject) => { - localResolve = resolve; - localReject = reject; - }); - const rejectingPromise = promise.then(() => { - throw new Error(`Promise is always rejecting`); - }); - rejectingPromise.catch(() => {}); - - return { - resolve: localResolve, - reject: localReject, - promise, - rejectingPromise, - }; -} +// todo: move to @trezor/utils. probably "resolveAfter"? export function resolveTimeoutPromise(delay: number, result: T): Promise { return new Promise(resolve => { @@ -33,11 +7,3 @@ export function resolveTimeoutPromise(delay: number, result: T): Promise { }, delay); }); } - -export function rejectTimeoutPromise(delay: number, error: Error): Promise { - return new Promise((_resolve, reject) => { - setTimeout(() => { - reject(error); - }, delay); - }); -} diff --git a/packages/blockchain-link/src/utils/deferred.ts b/packages/utils/src/promise.ts similarity index 68% rename from packages/blockchain-link/src/utils/deferred.ts rename to packages/utils/src/promise.ts index 440cd6a4058..c459f0b1f6e 100644 --- a/packages/blockchain-link/src/utils/deferred.ts +++ b/packages/utils/src/promise.ts @@ -1,8 +1,5 @@ -export function create(id: number | string): Deferred { - // intentionally ignore below lines in test coverage, they will be overridden in promise creation - /* istanbul ignore next */ +export const createDeferred = (id: number | string) => { let localResolve: (t: T) => void = () => {}; - /* istanbul ignore next */ let localReject: (e?: Error) => void = () => {}; const promise: Promise = new Promise((resolve, reject) => { @@ -16,7 +13,7 @@ export function create(id: number | string): Deferred { reject: localReject, promise, }; -} +}; export interface Deferred { id: number | string; @@ -24,3 +21,6 @@ export interface Deferred { resolve: (t: T) => void; reject: (e: Error) => void; } + +// unwrap promise response from Deferred +export type DeferredResponse = D extends Deferred ? R : never;