1const hex = (byte: number): string => byte.toString(16).padStart(2, "0")
2
3/** @internal */
4export const stringify = (bytes: Uint8Array): string => {
5 const segments = [
6 bytes.subarray(0, 4),
7 bytes.subarray(4, 6),
8 bytes.subarray(6, 8),
9 bytes.subarray(8, 10),
10 bytes.subarray(10, 16)
11 ]
12
13 return segments.map((segment) => Array.from(segment, hex).join("")).join("-")
14}
15
16const randomBytes = (): Uint8Array<ArrayBuffer> => globalThis.crypto.getRandomValues(new Uint8Array(16))
17
18/** @internal */
19export function v4Bytes(): Uint8Array<ArrayBuffer>
20/** @internal */
21export function v4Bytes<A extends ArrayBufferLike>(bytes: Uint8Array<A>): Uint8Array<A>
22/** @internal */
23export function v4Bytes(bytes: Uint8Array = randomBytes()): Uint8Array {
24 bytes[6] = (bytes[6] & 0x0f) | 0x40
25 bytes[8] = (bytes[8] & 0x3f) | 0x80
26 return bytes
27}
28
29/** @internal */
30export const v4String = (bytes?: Uint8Array): string => stringify(bytes === undefined ? v4Bytes() : v4Bytes(bytes))
31
32const maxV7Timestamp = 2 ** 48 - 1
33
34/** @internal */
35export function v7Bytes(timestampMillis: number): Uint8Array<ArrayBuffer>
36/** @internal */
37export function v7Bytes<A extends ArrayBufferLike>(timestampMillis: number, bytes: Uint8Array<A>): Uint8Array<A>
38/** @internal */
39export function v7Bytes(timestampMillis: number, bytes: Uint8Array = randomBytes()): Uint8Array {
40 const timestamp = Math.min(Math.max(0, Math.trunc(timestampMillis)), maxV7Timestamp)
41
42 bytes[0] = Math.floor(timestamp / 2 ** 40)
43 bytes[1] = Math.floor(timestamp / 2 ** 32) & 0xff
44 bytes[2] = Math.floor(timestamp / 2 ** 24) & 0xff
45 bytes[3] = Math.floor(timestamp / 2 ** 16) & 0xff
46 bytes[4] = Math.floor(timestamp / 2 ** 8) & 0xff
47 bytes[5] = timestamp & 0xff
48 bytes[6] = (bytes[6] & 0x0f) | 0x70
49 bytes[8] = (bytes[8] & 0x3f) | 0x80
50 return bytes
51}
52
53/** @internal */
54export const v7String = (timestampMillis: number, bytes?: Uint8Array): string =>
55 stringify(bytes === undefined ? v7Bytes(timestampMillis) : v7Bytes(timestampMillis, bytes))