import union from "lodash.union" ; import * as qs from "query-string" ; import { getWindowMetadata } from "@walletconnect/window-metadata" ; import { getDocument , getLocation , getNavigator } from "@walletconnect/window-getters" ; import { RelayClientMetadata , AppMetadata } from "@walletconnect/types" ; export const REACT_NATIVE_PRODUCT = "ReactNative" ; export const ENV_MAP = { reactNative : "react-native" , node : "node" , browser : "browser" , unknown : "unknown" , } ; export const EMPTY_SPACE = " " ; export const COLON = ":" ; export const SLASH = "/" ; export const DEFAULT_DEPTH = 2 ; export const ONE_THOUSAND = 1000 ; export function isNode ( ) { return ( typeof process !== "undefined" && typeof process . versions !== "undefined" && typeof process . versions . node !== "undefined" ) ; } export function isReactNative ( ) { return ! getDocument ( ) && ! ! getNavigator ( ) && navigator . product === REACT_NATIVE_PRODUCT ; } export function isBrowser ( ) { return ! isNode ( ) && ! ! getNavigator ( ) ; } export function getEnvironment ( ) { if ( isReactNative ( ) ) return ENV_MAP . reactNative ; if ( isNode ( ) ) return ENV_MAP . node ; if ( isBrowser ( ) ) return ENV_MAP . browser ; return ENV_MAP . unknown ; } export function appendToQueryString ( queryString , newQueryParams ) { let queryParams = qs . parse ( queryString ) ; queryParams = { ... queryParams , ... newQueryParams } ; queryString = qs . stringify ( queryParams ) ; return queryString ; } export function getAppMetadata ( ) { return getWindowMetadata ( ) || undefined ; } export function getRelayClientMetadata ( protocol , version ) { const env = getEnvironment ( ) ; const metadata = { protocol , version , env } ; if ( env === "browser" ) { metadata . host = getLocation ( ) ?. host || "" ; } return metadata ; } export function formatRelayRpcUrl ( protocol , version , url , projectId ? ) { const splitUrl = url . split ( "?" ) ; const metadata = getRelayClientMetadata ( protocol , version ) ; const params = projectId ? { ... metadata , projectId } : metadata ; const queryString = appendToQueryString ( splitUrl [ 1 ] || "" , params ) ; return splitUrl [ 0 ] + "?" + queryString ; } export function assertType ( obj , key , type ) { if ( ! obj [ key ] || typeof obj [ key ] !== type ) { throw new Error ( `Missing or invalid "${ key }" param` ) ; } } export function parseContextNames ( context , depth = DEFAULT_DEPTH ) { return getLastItems ( context . split ( SLASH ) , depth ) ; } export function formatMessageContext ( context ) { return parseContextNames ( context ) . join ( EMPTY_SPACE ) ; } export function formatStorageKeyName ( context ) { return parseContextNames ( context ) . join ( COLON ) ; } export function hasOverlap ( a , b ) { const matches = a . filter ( x => b . includes ( x ) ) ; return matches . length === a . length ; } export function getLastItems ( arr , depth = DEFAULT_DEPTH ) { return arr . slice ( Math . max ( arr . length - depth , 0 ) ) ; } export function mergeArrays ( a , b ) { return union ( a , b ) ; } export function mapToObj < T = any > ( map ) { return Object . fromEntries ( map . entries ( ) ) ; } export function objToMap < T = any > ( obj ) { return new Map < string , T > ( Object . entries < T > ( obj ) ) ; } export function mapEntries < A = any , B = any > ( obj , cb ) { const res = { } ; Object . keys ( obj ) . forEach ( key => { res [ key ] = cb ( obj [ key ] ) ; } ) ; return res ; } export const enumify = < T extends { [ index ] : U ; } , U extends string > ( x ) : T => x ; export function capitalizeWord ( word ) { return word . trim ( ) . replace ( /^\w/ , c => c . toUpperCase ( ) ) ; } export function capitalize ( str ) { return str . split ( EMPTY_SPACE ) . map ( w => capitalizeWord ( w ) ) . join ( EMPTY_SPACE ) ; } export function toMiliseconds ( seconds ) { return seconds * ONE_THOUSAND ; } export function fromMiliseconds ( miliseconds ) { return Math . floor ( miliseconds / ONE_THOUSAND ) ; } export function calcExpiry ( ttl , now ? ) { return fromMiliseconds ( ( now || Date . now ( ) ) + toMiliseconds ( ttl ) ) ; }