| 1 | const hex = (byte: number): string => byte.toString(16).padStart(2, "0") |
| 2 | |
| 3 | /** @internal */ |
| 4 | export 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 | |
| 16 | const randomBytes = (): Uint8Array<ArrayBuffer> => globalThis.crypto.getRandomValues(new Uint8Array(16)) |
| 17 | |
| 18 | /** @internal */ |
| 19 | export function v4Bytes(): Uint8Array<ArrayBuffer> |
| 20 | /** @internal */ |
| 21 | export function v4Bytes<A extends ArrayBufferLike>(bytes: Uint8Array<A>): Uint8Array<A> |
| 22 | /** @internal */ |
| 23 | export 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 */ |
| 30 | export const v4String = (bytes?: Uint8Array): string => stringify(bytes === undefined ? v4Bytes() : v4Bytes(bytes)) |
| 31 | |
| 32 | const maxV7Timestamp = 2 ** 48 - 1 |
| 33 | |
| 34 | /** @internal */ |
| 35 | export function v7Bytes(timestampMillis: number): Uint8Array<ArrayBuffer> |
| 36 | /** @internal */ |
| 37 | export function v7Bytes<A extends ArrayBufferLike>(timestampMillis: number, bytes: Uint8Array<A>): Uint8Array<A> |
| 38 | /** @internal */ |
| 39 | export 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 */ |
| 54 | export const v7String = (timestampMillis: number, bytes?: Uint8Array): string => |
| 55 | stringify(bytes === undefined ? v7Bytes(timestampMillis) : v7Bytes(timestampMillis, bytes)) |