UNPKG

1.69 kBJavaScriptView Raw
1const ALPHABET = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';
2
3const getRandomValues = window.crypto && window.crypto.getRandomValues &&
4 window.crypto.getRandomValues.bind(window.crypto);
5
6export default class KeyGenerator {
7 constructor() {
8 this._lastUniqueKeyTime = 0;
9 this._lastRandomValues = [];
10 }
11
12 generateUniqueKey(now) {
13 now = now || Date.now();
14 const chars = new Array(20);
15 let prefix = now;
16 for (let i = 7; i >= 0; i--) {
17 chars[i] = ALPHABET.charAt(prefix & 0x3f); // eslint-disable-line no-bitwise
18 prefix = Math.floor(prefix / 64);
19 }
20 if (now === this._lastUniqueKeyTime) {
21 let i = 11;
22 while (i >= 0 && this._lastRandomValues[i] === 63) {
23 this._lastRandomValues[i] = 0;
24 i -= 1;
25 }
26 if (i === -1) {
27 throw new Error('Internal assertion failure: ran out of unique IDs for this millisecond');
28 }
29 this._lastRandomValues[i] += 1;
30 } else {
31 this._lastUniqueKeyTime = now;
32 if (getRandomValues) {
33 /* global Uint8Array */
34 const array = new Uint8Array(12);
35 getRandomValues(array);
36 for (let i = 0; i < 12; i++) {
37 // eslint-disable-next-line no-bitwise
38 this._lastRandomValues[i] = array[i] & (i ? 0x3f : 0x0f);
39 }
40 } else {
41 for (let i = 0; i < 12; i++) {
42 // Make sure to leave some space for incrementing in the top nibble.
43 this._lastRandomValues[i] = Math.floor(Math.random() * (i ? 64 : 16));
44 }
45 }
46 }
47 for (let i = 0; i < 12; i++) {
48 chars[i + 8] = ALPHABET[this._lastRandomValues[i]];
49 }
50 return chars.join('');
51 }
52}