Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using xid-js in browser #1

Open
josephbuchma opened this issue Jan 24, 2023 · 0 comments
Open

Using xid-js in browser #1

josephbuchma opened this issue Jan 24, 2023 · 0 comments

Comments

@josephbuchma
Copy link

I want to generate xids in browser. The code below is based on this repository. I used base32-encode package instead of custom encoder implementation, and RFC4648-HEX instead of Crockford to be compatible with pg-xid

Would be nice to make xid-js isomorphic, and have the ability to provide a custom encoder.

import base32Encode from 'base32-encode'

const crypto = window.crypto

const randBuf = new Uint8Array(4)

function randInt() {
	crypto.getRandomValues(randBuf)
	return bin2int(randBuf)
}

function machineId() {
	const lsKey = 'xid-machine-id'
	const storedId = localStorage.getItem(lsKey)
	if (storedId) {
		return parseInt(storedId)
	}
	const id = randInt()
	localStorage.setItem(lsKey, `${id}`)
	return id
}

const mid = machineId() & 0xffffff
const pid = randInt() & 0xffff

let seq = randInt()
let time = (Date.now() / 1000) | 0

const buf = new ArrayBuffer(12)
const view = new DataView(buf, 0, 12)
view.setUint32(0, time)
setArrayBufBytesAtOffset(buf, uint32FirstNBytes(mid, 3), 4)

view.setUint16(7, pid)

function xid(): string {
	const now = (Date.now() / 1000) | 0
	if (time !== now) {
		view.setUint32(0, now)
		time = now
	}
	const c = seq & 0xffffff
	seq += 1
	setArrayBufBytesAtOffset(buf, uint32FirstNBytes(c, 3), 9)

	return base32Encode(buf, 'RFC4648-HEX', { padding: false })
		.substring(0, 20)
		.toLowerCase()
}

function uint32FirstNBytes(uint32: number, numbBytes: number): ArrayBuffer {
	const buf = new ArrayBuffer(4)
	const view = new DataView(buf)
	view.setUint32(0, uint32)
	return buf.slice(buf.byteLength - numbBytes)
}

function setArrayBufBytesAtOffset(
	dest: ArrayBuffer,
	bytes: ArrayBuffer,
	offset: number
) {
	new Uint8Array(dest).set(new Uint8Array(bytes), offset)
}

function bin2int(bin: Uint8Array) {
	let i = 0
	const len = bin.length
	let num = 0
	while (i < len) {
		num <<= 8
		num += bin[i]
		i++
	}
	return num
}

export default xid
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant