| import rng from './rng.js'; |
| import { unsafeStringify } from './stringify.js'; |
| const _state = {}; |
| function v1(options, buf, offset) { |
| let bytes; |
| const isV6 = options?._v6 ?? false; |
| if (options) { |
| const optionsKeys = Object.keys(options); |
| if (optionsKeys.length === 1 && optionsKeys[0] === '_v6') { |
| options = undefined; |
| } |
| } |
| if (options) { |
| bytes = v1Bytes(options.random ?? options.rng?.() ?? rng(), options.msecs, options.nsecs, options.clockseq, options.node, buf, offset); |
| } |
| else { |
| const now = Date.now(); |
| const rnds = rng(); |
| updateV1State(_state, now, rnds); |
| bytes = v1Bytes(rnds, _state.msecs, _state.nsecs, isV6 ? undefined : _state.clockseq, isV6 ? undefined : _state.node, buf, offset); |
| } |
| return buf ?? unsafeStringify(bytes); |
| } |
| export function updateV1State(state, now, rnds) { |
| state.msecs ??= -Infinity; |
| state.nsecs ??= 0; |
| if (now === state.msecs) { |
| state.nsecs++; |
| if (state.nsecs >= 10000) { |
| state.node = undefined; |
| state.nsecs = 0; |
| } |
| } |
| else if (now > state.msecs) { |
| state.nsecs = 0; |
| } |
| else if (now < state.msecs) { |
| state.node = undefined; |
| } |
| if (!state.node) { |
| state.node = rnds.slice(10, 16); |
| state.node[0] |= 0x01; |
| state.clockseq = ((rnds[8] << 8) | rnds[9]) & 0x3fff; |
| } |
| state.msecs = now; |
| return state; |
| } |
| function v1Bytes(rnds, msecs, nsecs, clockseq, node, buf, offset = 0) { |
| if (rnds.length < 16) { |
| throw new Error('Random bytes length must be >= 16'); |
| } |
| if (!buf) { |
| buf = new Uint8Array(16); |
| offset = 0; |
| } |
| else { |
| if (offset < 0 || offset + 16 > buf.length) { |
| throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`); |
| } |
| } |
| msecs ??= Date.now(); |
| nsecs ??= 0; |
| clockseq ??= ((rnds[8] << 8) | rnds[9]) & 0x3fff; |
| node ??= rnds.slice(10, 16); |
| msecs += 12219292800000; |
| const tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000; |
| buf[offset++] = (tl >>> 24) & 0xff; |
| buf[offset++] = (tl >>> 16) & 0xff; |
| buf[offset++] = (tl >>> 8) & 0xff; |
| buf[offset++] = tl & 0xff; |
| const tmh = ((msecs / 0x100000000) * 10000) & 0xfffffff; |
| buf[offset++] = (tmh >>> 8) & 0xff; |
| buf[offset++] = tmh & 0xff; |
| buf[offset++] = ((tmh >>> 24) & 0xf) | 0x10; |
| buf[offset++] = (tmh >>> 16) & 0xff; |
| buf[offset++] = (clockseq >>> 8) | 0x80; |
| buf[offset++] = clockseq & 0xff; |
| for (let n = 0; n < 6; ++n) { |
| buf[offset++] = node[n]; |
| } |
| return buf; |
| } |
| export default v1; |