import { getCryptoProvider as getProvider } from "./platform" ; import { bytesToHex } from "./encoding" ; /** Generates a random UUID v4 */ export async function uuid ( ) { const bytes = await getProvider ( ) . randomBytes ( 16 ) ; bytes [ 6 ] = ( bytes [ 6 ] & 0x0f ) | 0x40 ; bytes [ 8 ] = ( bytes [ 8 ] & 0x3f ) | 0x80 ; return [ bytesToHex ( bytes . slice ( 0 , 4 ) ) , "-" , bytesToHex ( bytes . slice ( 4 , 6 ) ) , "-" , bytesToHex ( bytes . slice ( 6 , 8 ) ) , "-" , bytesToHex ( bytes . slice ( 8 , 10 ) ) , "-" , bytesToHex ( bytes . slice ( 10 , 16 ) ) ] . join ( "" ) ; } /** Caracters, by category */ export const chars = { numbers : "0123456789" , lower : "abcdefghijklmnopqrstuvwxyz" , upper : "ABCDEFGHIJKLMNOPQRSTUVWXYZ" , other : "/+()%\"=&-!:'*#?;,_.@`~$^[{]}\\|<>" } ; /** Predefined char sets for generating randing strings */ export const charSets = { full : chars . numbers + chars . upper + chars . lower + chars . other , alphanum : chars . numbers + chars . upper + chars . lower , alpha : chars . lower + chars . upper , num : chars . numbers , hexa : chars . numbers + "abcdef" } ; /** Creates a random string with a given `length`, with characters chosen from a given `charSet` */ export async function randomString ( length = 32 , charSet = charSets . full ) { const provider = getProvider ( ) ; let str = "" ; while ( str . length < length ) { const [ rnd ] = await provider . randomBytes ( 1 ) ; if ( rnd > 255 - ( 256 % charSet . length ) ) { continue ; } str += charSet [ rnd % charSet . length ] ; } return str ; } /**
 * Generates a random number between `min` and `max`.
 * Taken from https://github.com/EFForg/OpenWireless/blob/master/app/js/diceware.js
 */ export async function randomNumber ( min = 0 , max = 10 ) { if ( max < min ) { throw "Upper bound must be greater than or equal to lower bound!" ; } let rval = 0 ; const range = max - min + 1 ; const bitsNeeded = Math . ceil ( Math . log2 ( range ) ) ; if ( bitsNeeded > 53 ) { throw new Error ( "We cannot generate numbers larger than 53 bits." ) ; } const bytesNeeded = Math . ceil ( bitsNeeded / 8 ) ; const mask = Math . pow ( 2 , bitsNeeded ) - 1 ; const byteArray = await getProvider ( ) . randomBytes ( bytesNeeded ) ; let p = ( bytesNeeded - 1 ) * 8 ; for ( let i = 0 ; i < bytesNeeded ; i ++ ) { rval += byteArray [ i ] * Math . pow ( 2 , p ) ; p -= 8 ; } rval = rval & mask ; if ( rval >= range ) { return randomNumber ( min , max ) ; } return min + rval ; } /**
 * "Debounces" a function, making sure it is only called once within a certain
 * time window
 */ export function debounce ( fn , delay ) { let timeout ; return function ( ... args ) { clearTimeout ( timeout ) ; timeout = window . setTimeout ( ( ) => fn ( ... args ) , delay ) ; } ; } export function throttle ( fn , delay ) { let lastCall ; let lastRan ; return ( ... args ) => { if ( ! lastRan ) { fn ( ... args ) ; lastRan = Date . now ( ) ; } else { clearTimeout ( lastCall ) ; lastCall = setTimeout ( ( ) => { if ( Date . now ( ) - lastRan >= delay ) { fn ( ... args ) ; lastRan = Date . now ( ) ; } } , delay - ( Date . now ( ) - lastRan ) ) ; } } ; } /** Returns a promise that resolves after a given `delay`. */ export function wait ( delay ) { return new Promise < void > ( resolve => setTimeout ( resolve , delay ) ) ; } /**
 * Resolves a given locale string to the approprivate available language
 */ export function resolveLanguage ( locale , supportedLanguages ) { const localeParts = locale . toLowerCase ( ) . split ( "-" ) ; while ( localeParts . length ) { const l = localeParts . join ( "-" ) ; if ( supportedLanguages [ l ] ) { return l ; } localeParts . pop ( ) ; } return Object . keys ( supportedLanguages ) [ 0 ] ; } /**
 * Applies a number of class `mixins` to a `baseClass`
 */ export function applyMixins ( baseClass , ... mixins ) { return mixins . reduce ( ( cls , mixin ) => mixin ( cls ) , baseClass ) ; } /**
 * Escapes all regex special characters within a given string.
 */ export function escapeRegex ( str ) { return str . replace ( /[.*+?^${}()|[\]\\]/g , "\\$&" ) ; }