Last active
January 28, 2023 13:13
-
-
Save origin1tech/17eb8259084d2edab3f005c84f10d2bb to your computer and use it in GitHub Desktop.
JavaScript Firebase UID Generation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export interface IUID { | |
generate(): string; | |
timestamp(uid: string, asDate?: boolean): number | Date; | |
} | |
/** | |
* SEE --> https://gist.github.com/mikelehen/3596a30bd69384624c11 | |
* | |
* Generator that creates 20-character string identifiers with the following properties: | |
* | |
* 1. They're based on timestamp so that they sort *after* any existing ids. | |
* 2. They contain 72-bits of random data after the timestamp so that IDs won't collide. | |
* 3. They sort *lexicographically* (timestamp converted to chars which will sort) | |
* 4. They're monotonically increasing. This is done by storing previous random bits | |
* increasing them only by one. | |
*/ | |
// ASCII ordered base64 web safe chars. | |
const ASCII_CHARS = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz'; | |
export const uid: IUID = { | |
/** | |
* Generate | |
* Generates uid push identifier. | |
*/ | |
generate: (function () { | |
// Timestamp of last push, used to prevent local | |
// collisions if you push twice in one ms. | |
let lastPushTime = 0; | |
// We generate 72-bits of randomness which get | |
// turned into 12 characters and appended to the | |
// timestamp to prevent collisions with other clients. | |
// We store the last characters we generated because | |
// in the event of a collision, we'll use those same | |
// characters except "incremented" by one. | |
const lastRandChars = []; | |
return function () { | |
let now = new Date().getTime(); | |
let duplicateTime = (now === lastPushTime); | |
lastPushTime = now; | |
let timeStampChars: string[] = new Array(8); | |
let i: number; | |
for (i = 7; i >= 0; i--) { | |
timeStampChars[i] = PUSH_CHARS.charAt(now % 64); | |
// NOTE: Can't use << here because javascript | |
// will convert to int and lose the upper bits. | |
now = Math.floor(now / 64); | |
} | |
if (now !== 0) throw new Error('We should have converted the entire timestamp.'); | |
let id = timeStampChars.join(''); | |
if (!duplicateTime) { | |
for (i = 0; i < 12; i++) { | |
lastRandChars[i] = Math.floor(Math.random() * 64); | |
} | |
} | |
// If the timestamp hasn't changed since | |
// last push, use the same random number, | |
// except incremented by 1. | |
else { | |
for (i = 11; i >= 0 && lastRandChars[i] === 63; i--) { | |
lastRandChars[i] = 0; | |
} | |
lastRandChars[i]++; | |
} | |
for (i = 0; i < 12; i++) { | |
id += ASCII_CHARS.charAt(lastRandChars[i]); | |
} | |
if (id.length !== 20) | |
throw new Error('Length should be 20.'); | |
return id; | |
}; | |
})(), | |
/** | |
* Timestamp | |
* Gets timestamp from provided uid. | |
*/ | |
timestamp: (function () { | |
return function (id: string, asDate?: boolean): number | Date { | |
let time = 0; | |
const data = id.substr(0, 8); | |
for (let i = 0; i < 8; i++) { | |
time = time * 64 + ASCII_CHARS.indexOf(data[i]); | |
} | |
if (asDate) | |
return new Date(time); | |
return time; | |
}; | |
})() | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I think you still need to change
PUSH_CHARS
intoASCII_CHARS