Last active
July 25, 2023 19:06
-
-
Save nickdandakis/476bad191f3332ca79d25b15c74dc6a1 to your computer and use it in GitHub Desktop.
zero dependency ksuid implementation
This file contains 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
// KSUIDs should be 20 bytes: 4 for the timestamp and 16 for the payload | |
const TIMESTAMP_BYTES = 4; | |
const PAYLOAD_BYTES = 16; | |
const TOTAL_BYTES = TIMESTAMP_BYTES + PAYLOAD_BYTES; | |
function getCurrentTimestamp() { | |
// KSUID timestamps have a custom epoch that starts in 14e8 | |
const CUSTOM_EPOCH_DIFF = 1_400_000_000; | |
const timestamp = Math.floor(Date.now() / 1000) - CUSTOM_EPOCH_DIFF; | |
const timestampArray = new Uint8Array(TIMESTAMP_BYTES); | |
// Write the timestamp to the buffer in Big Endian format | |
new DataView(timestampArray.buffer).setUint32(0, timestamp); | |
return timestampArray; | |
} | |
function generatePayload() { | |
const payloadArray = new Uint8Array(PAYLOAD_BYTES); | |
window.crypto.getRandomValues(payloadArray); | |
return payloadArray; | |
} | |
function toBase62(uint8Array) { | |
const characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; | |
let result = ''; | |
let quotient = BigInt(`0x${Array.from(uint8Array).map(b => b.toString(16).padStart(2, '0')).join('')}`); | |
while (quotient > 0) { | |
const remainder = Number(quotient % 62n); | |
quotient /= 62n; | |
result = characters[remainder] + result; | |
} | |
return result.padStart(26, '0'); | |
} | |
function generateKSUID() { | |
const ksuidArray = new Uint8Array(TOTAL_BYTES); | |
ksuidArray.set(getCurrentTimestamp(), 0); | |
ksuidArray.set(generatePayload(), TIMESTAMP_BYTES); | |
// Convert to a base62 string for easier handling | |
return toBase62(ksuidArray); | |
} |
This file contains 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
// KSUIDs should be 20 bytes: 4 for the timestamp and 16 for the payload | |
const TIMESTAMP_BYTES = 4; | |
const PAYLOAD_BYTES = 16; | |
const TOTAL_BYTES = TIMESTAMP_BYTES + PAYLOAD_BYTES; | |
function isBrowserEnvironment() { | |
return typeof window !== 'undefined'; | |
} | |
function getCurrentTimestamp() { | |
// KSUID timestamps have a custom epoch that starts in 14e8 | |
const CUSTOM_EPOCH_DIFF = 1_400_000_000; | |
const timestamp = Math.floor(Date.now() / 1000) - CUSTOM_EPOCH_DIFF; | |
if (isBrowserEnvironment()) { | |
const timestampArray = new Uint8Array(TIMESTAMP_BYTES); | |
new DataView(timestampArray.buffer).setUint32(0, timestamp); | |
return timestampArray; | |
} else { | |
const timestampBuffer = Buffer.alloc(TIMESTAMP_BYTES); | |
timestampBuffer.writeUInt32BE(timestamp, 0); | |
return timestampBuffer; | |
} | |
} | |
function generatePayload() { | |
if (isBrowserEnvironment()) { | |
const payloadArray = new Uint8Array(PAYLOAD_BYTES); | |
window.crypto.getRandomValues(payloadArray); | |
return payloadArray; | |
} else { | |
return require('crypto').randomBytes(PAYLOAD_BYTES); | |
} | |
} | |
function toBase62(uint8Array) { | |
const characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; | |
let result = ''; | |
let quotient = BigInt(`0x${Array.from(uint8Array).map(b => b.toString(16).padStart(2, '0')).join('')}`); | |
while (quotient > 0) { | |
const remainder = Number(quotient % 62n); | |
quotient /= 62n; | |
result = characters[remainder] + result; | |
} | |
return result.padStart(26, '0'); | |
} | |
function generateKSUID() { | |
const ksuidArray = new (isBrowserEnvironment() ? Uint8Array : Buffer)(TOTAL_BYTES); | |
ksuidArray.set(getCurrentTimestamp(), 0); | |
ksuidArray.set(generatePayload(), TIMESTAMP_BYTES); | |
// Convert to a base62 string for easier handling | |
return toBase62(ksuidArray); | |
} |
This file contains 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
const crypto = require('crypto'); | |
// KSUIDs should be 20 bytes: 4 for the timestamp and 16 for the payload | |
const TIMESTAMP_BYTES = 4; | |
const PAYLOAD_BYTES = 16; | |
const TOTAL_BYTES = TIMESTAMP_BYTES + PAYLOAD_BYTES; | |
function getCurrentTimestamp() { | |
// KSUID timestamps have a custom epoch that starts in 14e8 | |
const CUSTOM_EPOCH_DIFF = 1_400_000_000; | |
const timestamp = Math.floor(Date.now() / 1000) - CUSTOM_EPOCH_DIFF; | |
const timestampBuffer = Buffer.alloc(TIMESTAMP_BYTES); | |
// Write the timestamp to the buffer in Big Endian format | |
timestampBuffer.writeUInt32BE(timestamp, 0); | |
return timestampBuffer; | |
} | |
function generatePayload() { | |
return crypto.randomBytes(PAYLOAD_BYTES); | |
} | |
function toBase62(buffer) { | |
const characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; | |
let result = ''; | |
let quotient = BigInt(`0x${buffer.toString('hex')}`); | |
while (quotient > 0) { | |
const remainder = Number(quotient % 62n); | |
quotient /= 62n; | |
result = characters[remainder] + result; | |
} | |
return result; | |
} | |
function generateKSUID() { | |
const ksuidBuffer = Buffer.alloc(TOTAL_BYTES); | |
getCurrentTimestamp().copy(ksuidBuffer, 0, 0, TIMESTAMP_BYTES); | |
generatePayload().copy(ksuidBuffer, TIMESTAMP_BYTES, 0, PAYLOAD_BYTES); | |
// Convert to a base62 string for easier handling | |
return toBase62(ksuidBuffer); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment