Skip to content

Instantly share code, notes, and snippets.

@origin1tech
Last active January 28, 2023 13:13
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save origin1tech/17eb8259084d2edab3f005c84f10d2bb to your computer and use it in GitHub Desktop.
Save origin1tech/17eb8259084d2edab3f005c84f10d2bb to your computer and use it in GitHub Desktop.
JavaScript Firebase UID Generation
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;
};
})()
};
@maartentibau
Copy link

I think you still need to change PUSH_CHARS into ASCII_CHARS

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment