uniku 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cuid2/cuid2.d.mts.map +1 -1
- package/build/cuid2/cuid2.mjs +1 -1
- package/build/cuid2/cuid2.mjs.map +1 -1
- package/build/ksuid/ksuid.d.mts.map +1 -1
- package/build/ksuid/ksuid.mjs +1 -1
- package/build/ksuid/ksuid.mjs.map +1 -1
- package/build/objectid/objectid.d.mts.map +1 -1
- package/build/objectid/objectid.mjs +1 -1
- package/build/objectid/objectid.mjs.map +1 -1
- package/build/tsid/tsid.d.mts.map +1 -1
- package/build/tsid/tsid.mjs +1 -1
- package/build/tsid/tsid.mjs.map +1 -1
- package/build/ulid/ulid.d.mts.map +1 -1
- package/build/ulid/ulid.mjs +1 -1
- package/build/ulid/ulid.mjs.map +1 -1
- package/build/uuid/v4.d.mts +0 -1
- package/build/uuid/v4.d.mts.map +1 -1
- package/build/uuid/v4.mjs +1 -1
- package/build/uuid/v4.mjs.map +1 -1
- package/build/uuid/v7.d.mts +3 -0
- package/build/uuid/v7.d.mts.map +1 -1
- package/build/uuid/v7.mjs +1 -1
- package/build/uuid/v7.mjs.map +1 -1
- package/build/uuid-CnQIYoQi.mjs +2 -0
- package/build/uuid-CnQIYoQi.mjs.map +1 -0
- package/build/validation-CTNpXm94.mjs +2 -0
- package/build/validation-CTNpXm94.mjs.map +1 -0
- package/package.json +1 -1
- package/src/common/validation.ts +7 -0
- package/src/cuid2/cuid2.ts +7 -3
- package/src/ksuid/ksuid.ts +19 -17
- package/src/objectid/objectid.ts +25 -17
- package/src/tsid/tsid.ts +83 -53
- package/src/ulid/crockford.ts +2 -2
- package/src/ulid/ulid.ts +35 -24
- package/src/uuid/common/uuid.ts +12 -1
- package/src/uuid/v4.ts +25 -28
- package/src/uuid/v7.ts +75 -47
- package/build/uuid-BBjwHv7J.mjs +0 -2
- package/build/uuid-BBjwHv7J.mjs.map +0 -1
package/src/uuid/common/uuid.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ParseError } from '../../errors'
|
|
1
|
+
import { BufferError, ParseError } from '../../errors'
|
|
2
2
|
import { hexValue } from './hex'
|
|
3
3
|
|
|
4
4
|
const UUID_BYTE_LENGTH = 16
|
|
@@ -93,6 +93,17 @@ const UUID_CHAR_IS_HIGH: boolean[] = [
|
|
|
93
93
|
const HEX_TABLE: string[] = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'))
|
|
94
94
|
|
|
95
95
|
export function formatUuid(bytes: Uint8Array): string {
|
|
96
|
+
if (bytes.length !== UUID_BYTE_LENGTH) {
|
|
97
|
+
throw new BufferError(
|
|
98
|
+
'UUID_BYTES_INVALID_LENGTH',
|
|
99
|
+
`UUID bytes must be exactly ${UUID_BYTE_LENGTH} bytes, got ${bytes.length}`,
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return formatUuidUnchecked(bytes)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function formatUuidUnchecked(bytes: Uint8Array): string {
|
|
96
107
|
// Direct string concatenation - optimized for V8's string builder.
|
|
97
108
|
// This approach avoids loop overhead and intermediate allocations.
|
|
98
109
|
// See: https://github.com/uuidjs/uuid/pull/434
|
package/src/uuid/v4.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { rng } from '../common/random'
|
|
2
|
+
import { isWritableRange } from '../common/validation'
|
|
2
3
|
import { BufferError, InvalidInputError } from '../errors'
|
|
3
|
-
import { formatUuid, parseUuid } from './common/uuid'
|
|
4
|
+
import { formatUuid, formatUuidUnchecked, parseUuid } from './common/uuid'
|
|
4
5
|
|
|
5
6
|
const randomUUID = /*@__PURE__*/ globalThis.crypto.randomUUID.bind(globalThis.crypto)
|
|
7
|
+
const UUID_BYTES = 16
|
|
8
|
+
const reusableBuf = new Uint8Array(UUID_BYTES)
|
|
6
9
|
|
|
7
10
|
export type UuidV4Options = {
|
|
8
11
|
/**
|
|
9
12
|
* 16 bytes of random data to use for UUID generation.
|
|
10
|
-
* Note: Bytes at index 6 and 8 will be modified in-place to set version/variant bits.
|
|
11
13
|
*/
|
|
12
14
|
random?: Uint8Array
|
|
13
15
|
}
|
|
@@ -27,34 +29,15 @@ export type UuidV4 = {
|
|
|
27
29
|
|
|
28
30
|
const UUID_V4_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
|
|
29
31
|
|
|
30
|
-
function
|
|
31
|
-
if (rnds.length < 16) {
|
|
32
|
-
throw new InvalidInputError('UUID_RANDOM_BYTES_TOO_SHORT', 'Random bytes length must be >= 16')
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Set RFC 4122 version (4) and variant (10xx) bits.
|
|
36
|
-
// Note: This modifies the input array in-place.
|
|
37
|
-
rnds[6] = (rnds[6] & 0x0f) | 0x40
|
|
38
|
-
rnds[8] = (rnds[8] & 0x3f) | 0x80
|
|
39
|
-
|
|
40
|
-
if (!buf) {
|
|
41
|
-
// No output buffer provided - return the modified random bytes directly
|
|
42
|
-
return rnds
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (offset < 0 || offset + 16 > buf.length) {
|
|
46
|
-
throw new BufferError(
|
|
47
|
-
'UUID_BUFFER_OUT_OF_BOUNDS',
|
|
48
|
-
`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`,
|
|
49
|
-
)
|
|
50
|
-
}
|
|
51
|
-
|
|
32
|
+
function writeV4BytesUnchecked(rnds: Uint8Array, buf: Uint8Array, offset: number): void {
|
|
52
33
|
// Copy 16 UUID bytes into the provided buffer slice.
|
|
53
|
-
for (let i = 0; i <
|
|
34
|
+
for (let i = 0; i < UUID_BYTES; i += 1) {
|
|
54
35
|
buf[offset + i] = rnds[i]
|
|
55
36
|
}
|
|
56
37
|
|
|
57
|
-
|
|
38
|
+
// Set RFC 4122 version (4) and variant (10xx) bits on owned output only.
|
|
39
|
+
buf[offset + 6] = (buf[offset + 6] & 0x0f) | 0x40
|
|
40
|
+
buf[offset + 8] = (buf[offset + 8] & 0x3f) | 0x80
|
|
58
41
|
}
|
|
59
42
|
|
|
60
43
|
/*
|
|
@@ -78,8 +61,22 @@ function _v4<TBuf extends Uint8Array = Uint8Array>(
|
|
|
78
61
|
buf?: TBuf,
|
|
79
62
|
offset?: number,
|
|
80
63
|
): string | TBuf {
|
|
81
|
-
const
|
|
82
|
-
|
|
64
|
+
const random = options?.random
|
|
65
|
+
if (random && random.length < UUID_BYTES) {
|
|
66
|
+
throw new InvalidInputError('UUID_RANDOM_BYTES_TOO_SHORT', `Random bytes length must be >= ${UUID_BYTES}`)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const outputOffset = buf ? (offset ?? 0) : 0
|
|
70
|
+
if (buf && !isWritableRange(buf, outputOffset, UUID_BYTES)) {
|
|
71
|
+
throw new BufferError(
|
|
72
|
+
'UUID_BUFFER_OUT_OF_BOUNDS',
|
|
73
|
+
`UUID byte range ${outputOffset}:${outputOffset + UUID_BYTES - 1} is out of buffer bounds`,
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const output = buf ?? reusableBuf
|
|
78
|
+
writeV4BytesUnchecked(random ?? rng(), output, outputOffset)
|
|
79
|
+
return buf ?? formatUuidUnchecked(output)
|
|
83
80
|
}
|
|
84
81
|
|
|
85
82
|
function isValid(id: unknown): id is string {
|
package/src/uuid/v7.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { rng } from '../common/random'
|
|
2
|
+
import { isIntegerInRange, isWritableRange } from '../common/validation'
|
|
2
3
|
import { BufferError, InvalidInputError } from '../errors'
|
|
3
|
-
import { formatUuid, parseUuid } from './common/uuid'
|
|
4
|
+
import { formatUuid, formatUuidUnchecked, parseUuid } from './common/uuid'
|
|
4
5
|
|
|
5
6
|
export type UuidV7Options = {
|
|
6
7
|
/**
|
|
@@ -9,6 +10,9 @@ export type UuidV7Options = {
|
|
|
9
10
|
*/
|
|
10
11
|
random?: Uint8Array
|
|
11
12
|
msecs?: number
|
|
13
|
+
/**
|
|
14
|
+
* Unsigned 32-bit sequence value.
|
|
15
|
+
*/
|
|
12
16
|
seq?: number
|
|
13
17
|
}
|
|
14
18
|
|
|
@@ -27,10 +31,13 @@ export type UuidV7 = {
|
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
const UUID_V7_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
|
|
34
|
+
const UUID_BYTES = 16
|
|
35
|
+
const MAX_MSECS = 0xffffffffffff
|
|
36
|
+
const MAX_SEQ = 0xffffffff
|
|
30
37
|
|
|
31
38
|
// Reusable buffer for string output path - avoids allocation per call.
|
|
32
|
-
// Safe because bytes are consumed synchronously by
|
|
33
|
-
const reusableBuf = new Uint8Array(
|
|
39
|
+
// Safe because bytes are consumed synchronously by formatUuidUnchecked().
|
|
40
|
+
const reusableBuf = new Uint8Array(UUID_BYTES)
|
|
34
41
|
|
|
35
42
|
type V7State = {
|
|
36
43
|
msecs: number
|
|
@@ -47,29 +54,7 @@ type V7State = {
|
|
|
47
54
|
*/
|
|
48
55
|
const state: V7State = { msecs: -Infinity, seq: 0 }
|
|
49
56
|
|
|
50
|
-
function
|
|
51
|
-
rnds: Uint8Array,
|
|
52
|
-
msecs: number | undefined,
|
|
53
|
-
seq: number | undefined,
|
|
54
|
-
buf: Uint8Array,
|
|
55
|
-
offset = 0,
|
|
56
|
-
): Uint8Array {
|
|
57
|
-
if (rnds.length < 16) {
|
|
58
|
-
throw new InvalidInputError('UUID_RANDOM_BYTES_TOO_SHORT', 'Random bytes length must be >= 16')
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (offset < 0 || offset + 16 > buf.length) {
|
|
62
|
-
throw new BufferError(
|
|
63
|
-
'UUID_BUFFER_OUT_OF_BOUNDS',
|
|
64
|
-
`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`,
|
|
65
|
-
)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
msecs ??= Date.now()
|
|
69
|
-
// Derive a 31-bit sequence if not provided by the caller.
|
|
70
|
-
// Uses the same formula as the hot path for consistency.
|
|
71
|
-
seq ??= (rnds[6] << 23) | (rnds[7] << 16) | (rnds[8] << 8) | rnds[9]
|
|
72
|
-
|
|
57
|
+
function writeV7BytesUnchecked(rnds: Uint8Array, msecs: number, seq: number, buf: Uint8Array, offset: number): void {
|
|
73
58
|
// Keep this inline on the UUID v7 hot path. Using writeTimestamp48() here
|
|
74
59
|
// benchmarked slower than the direct byte writes.
|
|
75
60
|
buf[offset++] = (msecs / 0x10000000000) & 0xff
|
|
@@ -91,8 +76,50 @@ function v7Bytes(
|
|
|
91
76
|
buf[offset++] = rnds[13]
|
|
92
77
|
buf[offset++] = rnds[14]
|
|
93
78
|
buf[offset++] = rnds[15]
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function writeV7Bytes(rnds: Uint8Array, msecs: number, seq: number, buf: Uint8Array, offset: number): void {
|
|
82
|
+
if (!isWritableRange(buf, offset, UUID_BYTES)) {
|
|
83
|
+
throw new BufferError(
|
|
84
|
+
'UUID_BUFFER_OUT_OF_BOUNDS',
|
|
85
|
+
`UUID byte range ${offset}:${offset + UUID_BYTES - 1} is out of buffer bounds`,
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
writeV7BytesUnchecked(rnds, msecs, seq, buf, offset)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function v7WithOptions<TBuf extends Uint8Array = Uint8Array>(
|
|
92
|
+
options: UuidV7Options,
|
|
93
|
+
buf?: TBuf,
|
|
94
|
+
offset = 0,
|
|
95
|
+
): string | TBuf {
|
|
96
|
+
const optMsecs = options.msecs
|
|
97
|
+
if (optMsecs !== undefined && !isIntegerInRange(optMsecs, 0, MAX_MSECS)) {
|
|
98
|
+
throw new InvalidInputError(
|
|
99
|
+
'UUID_TIMESTAMP_OUT_OF_RANGE',
|
|
100
|
+
`Timestamp must be an integer between 0 and ${MAX_MSECS}`,
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
const optSeq = options.seq
|
|
104
|
+
if (optSeq !== undefined && !isIntegerInRange(optSeq, 0, MAX_SEQ)) {
|
|
105
|
+
throw new InvalidInputError('UUID_SEQUENCE_OUT_OF_RANGE', `Sequence must be an integer between 0 and ${MAX_SEQ}`)
|
|
106
|
+
}
|
|
107
|
+
const optRandom = options.random
|
|
108
|
+
if (optRandom && optRandom.length < UUID_BYTES) {
|
|
109
|
+
throw new InvalidInputError('UUID_RANDOM_BYTES_TOO_SHORT', `Random bytes length must be >= ${UUID_BYTES}`)
|
|
110
|
+
}
|
|
94
111
|
|
|
95
|
-
|
|
112
|
+
const rnds = optRandom ?? rng()
|
|
113
|
+
const msecs = optMsecs ?? Date.now()
|
|
114
|
+
// Derive a 31-bit sequence if not provided by the caller, matching the default hot path.
|
|
115
|
+
const seq = optSeq ?? (rnds[6] << 23) | (rnds[7] << 16) | (rnds[8] << 8) | rnds[9]
|
|
116
|
+
|
|
117
|
+
if (buf) {
|
|
118
|
+
writeV7Bytes(rnds, msecs, seq, buf, offset)
|
|
119
|
+
return buf
|
|
120
|
+
}
|
|
121
|
+
writeV7BytesUnchecked(rnds, msecs, seq, reusableBuf, 0)
|
|
122
|
+
return formatUuidUnchecked(reusableBuf)
|
|
96
123
|
}
|
|
97
124
|
|
|
98
125
|
/*
|
|
@@ -104,31 +131,32 @@ function v7(options?: UuidV7Options, buf?: undefined, offset?: number): string
|
|
|
104
131
|
*/
|
|
105
132
|
function v7<TBuf extends Uint8Array = Uint8Array>(options: UuidV7Options | undefined, buf: TBuf, offset?: number): TBuf
|
|
106
133
|
function v7<TBuf extends Uint8Array = Uint8Array>(options?: UuidV7Options, buf?: TBuf, offset?: number): string | TBuf {
|
|
107
|
-
let bytes: Uint8Array
|
|
108
|
-
|
|
109
134
|
if (options) {
|
|
110
|
-
|
|
135
|
+
return v7WithOptions(options, buf, offset)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// HOT PATH: Inline state management and byte generation for best performance
|
|
139
|
+
const now = Date.now()
|
|
140
|
+
const rnds = rng()
|
|
141
|
+
|
|
142
|
+
// Update state (inlined for performance)
|
|
143
|
+
if (now > state.msecs) {
|
|
144
|
+
state.seq = (rnds[6] << 23) | (rnds[7] << 16) | (rnds[8] << 8) | rnds[9]
|
|
145
|
+
state.msecs = now
|
|
111
146
|
} else {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
// Update state (inlined for performance)
|
|
117
|
-
if (now > state.msecs) {
|
|
118
|
-
state.seq = (rnds[6] << 23) | (rnds[7] << 16) | (rnds[8] << 8) | rnds[9]
|
|
119
|
-
state.msecs = now
|
|
120
|
-
} else {
|
|
121
|
-
state.seq = (state.seq + 1) | 0
|
|
122
|
-
if (state.seq < 0) {
|
|
123
|
-
state.seq = 0
|
|
124
|
-
state.msecs++
|
|
125
|
-
}
|
|
147
|
+
state.seq = (state.seq + 1) | 0
|
|
148
|
+
if (state.seq < 0) {
|
|
149
|
+
state.seq = 0
|
|
150
|
+
state.msecs++
|
|
126
151
|
}
|
|
127
|
-
|
|
128
|
-
bytes = v7Bytes(rnds, state.msecs, state.seq, buf ?? reusableBuf, buf ? offset : 0)
|
|
129
152
|
}
|
|
130
153
|
|
|
131
|
-
|
|
154
|
+
if (buf) {
|
|
155
|
+
writeV7Bytes(rnds, state.msecs, state.seq, buf, offset ?? 0)
|
|
156
|
+
return buf
|
|
157
|
+
}
|
|
158
|
+
writeV7BytesUnchecked(rnds, state.msecs, state.seq, reusableBuf, 0)
|
|
159
|
+
return formatUuidUnchecked(reusableBuf)
|
|
132
160
|
}
|
|
133
161
|
|
|
134
162
|
function timestamp(id: string): number {
|
package/build/uuid-BBjwHv7J.mjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{ParseError as e}from"./errors.mjs";function t(e){return e>=48&&e<=57?e-48:e>=65&&e<=70?e-65+10:e>=97&&e<=102?e-97+10:-1}const n=[0,0,1,1,2,2,3,3,-1,4,4,5,5,-1,6,6,7,7,-1,8,8,9,9,-1,10,10,11,11,12,12,13,13,14,14,15,15],r=[!0,!1,!0,!1,!0,!1,!0,!1,!1,!0,!1,!0,!1,!1,!0,!1,!0,!1,!1,!0,!1,!0,!1,!1,!0,!1,!0,!1,!0,!1,!0,!1,!0,!1,!0,!1],i=Array.from({length:256},(e,t)=>t.toString(16).padStart(2,`0`));function a(e){return i[e[0]]+i[e[1]]+i[e[2]]+i[e[3]]+`-`+i[e[4]]+i[e[5]]+`-`+i[e[6]]+i[e[7]]+`-`+i[e[8]]+i[e[9]]+`-`+i[e[10]]+i[e[11]]+i[e[12]]+i[e[13]]+i[e[14]]+i[e[15]]}function o(i){if(i.length!==36)throw new e(`UUID_INVALID_LENGTH`,`UUID string must be 36 characters, got ${i.length}`);if(i[8]!==`-`||i[13]!==`-`||i[18]!==`-`||i[23]!==`-`)throw new e(`UUID_INVALID_SEPARATORS`,`UUID string has invalid separators at positions 8, 13, 18, 23. Received: "${i}"`);let a=new Uint8Array(16);for(let o=0;o<36;o+=1){let s=n[o];if(s===-1)continue;let c=t(i.charCodeAt(o));if(c===-1)throw new e(`UUID_INVALID_HEX_CHAR`,`UUID string contains invalid hex character at position ${o}`);r[o]?a[s]=c<<4:a[s]|=c}return a}export{o as n,a as t};
|
|
2
|
-
//# sourceMappingURL=uuid-BBjwHv7J.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"uuid-BBjwHv7J.mjs","names":[],"sources":["../src/uuid/common/hex.ts","../src/uuid/common/uuid.ts"],"sourcesContent":["// ASCII code ranges for hex character validation\nconst ASCII_0 = 48 // '0'\nconst ASCII_9 = 57 // '9'\nconst ASCII_A = 65 // 'A'\nconst ASCII_F = 70 // 'F'\nconst ASCII_a = 97 // 'a'\nconst ASCII_f = 102 // 'f'\n\n/**\n * Convert a hex character ASCII code to its numeric value (0-15).\n * Returns -1 for invalid hex characters.\n */\nexport function hexValue(code: number): number {\n if (code >= ASCII_0 && code <= ASCII_9) {\n return code - ASCII_0\n }\n if (code >= ASCII_A && code <= ASCII_F) {\n return code - ASCII_A + 10\n }\n if (code >= ASCII_a && code <= ASCII_f) {\n return code - ASCII_a + 10\n }\n return -1 // Invalid hex character\n}\n","import { ParseError } from '../../errors'\nimport { hexValue } from './hex'\n\nconst UUID_BYTE_LENGTH = 16\nconst UUID_STRING_LENGTH = 36\n\n// Mapping from UUID string position to byte index.\n// -1 indicates a dash position that should be skipped.\n// This avoids intermediate string allocations during parsing.\nconst UUID_CHAR_TO_BYTE: number[] = [\n 0,\n 0,\n 1,\n 1,\n 2,\n 2,\n 3,\n 3, // chars 0-7 → bytes 0-3\n -1, // char 8 is '-'\n 4,\n 4,\n 5,\n 5, // chars 9-12 → bytes 4-5\n -1, // char 13 is '-'\n 6,\n 6,\n 7,\n 7, // chars 14-17 → bytes 6-7\n -1, // char 18 is '-'\n 8,\n 8,\n 9,\n 9, // chars 19-22 → bytes 8-9\n -1, // char 23 is '-'\n 10,\n 10,\n 11,\n 11,\n 12,\n 12,\n 13,\n 13,\n 14,\n 14,\n 15,\n 15, // chars 24-35 → bytes 10-15\n]\n\n// Whether each position is the high nibble (true) or low nibble (false)\nconst UUID_CHAR_IS_HIGH: boolean[] = [\n true,\n false,\n true,\n false,\n true,\n false,\n true,\n false, // chars 0-7\n false, // dash (ignored)\n true,\n false,\n true,\n false, // chars 9-12\n false, // dash\n true,\n false,\n true,\n false, // chars 14-17\n false, // dash\n true,\n false,\n true,\n false, // chars 19-22\n false, // dash\n true,\n false,\n true,\n false,\n true,\n false,\n true,\n false,\n true,\n false,\n true,\n false, // chars 24-35\n]\n\n// Pre-computed lookup table for byte-to-hex conversion (0x00 -> \"00\", 0xff -> \"ff\")\n//\n// Note: this table must remain defined in the same module as `formatUuid`, otherwise the v8 optimizer\n// will cause a performance drop of ~36%.\nconst HEX_TABLE: string[] = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'))\n\nexport function formatUuid(bytes: Uint8Array): string {\n // Direct string concatenation - optimized for V8's string builder.\n // This approach avoids loop overhead and intermediate allocations.\n // See: https://github.com/uuidjs/uuid/pull/434\n return (\n HEX_TABLE[bytes[0]] +\n HEX_TABLE[bytes[1]] +\n HEX_TABLE[bytes[2]] +\n HEX_TABLE[bytes[3]] +\n '-' +\n HEX_TABLE[bytes[4]] +\n HEX_TABLE[bytes[5]] +\n '-' +\n HEX_TABLE[bytes[6]] +\n HEX_TABLE[bytes[7]] +\n '-' +\n HEX_TABLE[bytes[8]] +\n HEX_TABLE[bytes[9]] +\n '-' +\n HEX_TABLE[bytes[10]] +\n HEX_TABLE[bytes[11]] +\n HEX_TABLE[bytes[12]] +\n HEX_TABLE[bytes[13]] +\n HEX_TABLE[bytes[14]] +\n HEX_TABLE[bytes[15]]\n )\n}\n\nexport function parseUuid(value: string): Uint8Array {\n if (value.length !== UUID_STRING_LENGTH) {\n throw new ParseError('UUID_INVALID_LENGTH', `UUID string must be 36 characters, got ${value.length}`)\n }\n\n // Validate separator positions directly (more efficient than full loop)\n if (value[8] !== '-' || value[13] !== '-' || value[18] !== '-' || value[23] !== '-') {\n throw new ParseError(\n 'UUID_INVALID_SEPARATORS',\n `UUID string has invalid separators at positions 8, 13, 18, 23. Received: \"${value}\"`,\n )\n }\n\n // Parse bytes directly from UUID string without intermediate string allocations.\n // This avoids the 9 allocations (5 slices + 4 concatenations) of the naive approach.\n const bytes = new Uint8Array(UUID_BYTE_LENGTH)\n\n for (let i = 0; i < UUID_STRING_LENGTH; i += 1) {\n const byteIdx = UUID_CHAR_TO_BYTE[i]\n if (byteIdx === -1) continue // Skip dash positions\n\n const nibble = hexValue(value.charCodeAt(i))\n if (nibble === -1) {\n throw new ParseError('UUID_INVALID_HEX_CHAR', `UUID string contains invalid hex character at position ${i}`)\n }\n\n if (UUID_CHAR_IS_HIGH[i]) {\n bytes[byteIdx] = nibble << 4\n } else {\n bytes[byteIdx] |= nibble\n }\n }\n\n return bytes\n}\n"],"mappings":"0CAYA,SAAgB,EAAS,EAAsB,CAU7C,OATI,GAAQ,IAAW,GAAQ,GACtB,EAAO,GAEZ,GAAQ,IAAW,GAAQ,GACtB,EAAO,GAAU,GAEtB,GAAQ,IAAW,GAAQ,IACtB,EAAO,GAAU,GAEnB,EACT,CCpBA,MAMM,EAA8B,CAClC,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,GACA,EACA,EACA,EACA,EACA,GACA,EACA,EACA,EACA,EACA,GACA,EACA,EACA,EACA,EACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,EACF,EAGM,EAA+B,CACnC,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,EACF,EAMM,EAAsB,MAAM,KAAK,CAAE,OAAQ,GAAI,GAAI,EAAG,IAAM,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAG,GAAG,CAAC,EAEjG,SAAgB,EAAW,EAA2B,CAIpD,OACE,EAAU,EAAM,IAChB,EAAU,EAAM,IAChB,EAAU,EAAM,IAChB,EAAU,EAAM,IAChB,IACA,EAAU,EAAM,IAChB,EAAU,EAAM,IAChB,IACA,EAAU,EAAM,IAChB,EAAU,EAAM,IAChB,IACA,EAAU,EAAM,IAChB,EAAU,EAAM,IAChB,IACA,EAAU,EAAM,KAChB,EAAU,EAAM,KAChB,EAAU,EAAM,KAChB,EAAU,EAAM,KAChB,EAAU,EAAM,KAChB,EAAU,EAAM,IAEpB,CAEA,SAAgB,EAAU,EAA2B,CACnD,GAAI,EAAM,SAAW,GACnB,MAAM,IAAI,EAAW,sBAAuB,0CAA0C,EAAM,QAAQ,EAItG,GAAI,EAAM,KAAO,KAAO,EAAM,MAAQ,KAAO,EAAM,MAAQ,KAAO,EAAM,MAAQ,IAC9E,MAAM,IAAI,EACR,0BACA,6EAA6E,EAAM,EACrF,EAKF,IAAM,EAAQ,IAAI,WAAW,EAAgB,EAE7C,IAAK,IAAI,EAAI,EAAG,EAAI,GAAoB,GAAK,EAAG,CAC9C,IAAM,EAAU,EAAkB,GAClC,GAAI,IAAY,GAAI,SAEpB,IAAM,EAAS,EAAS,EAAM,WAAW,CAAC,CAAC,EAC3C,GAAI,IAAW,GACb,MAAM,IAAI,EAAW,wBAAyB,0DAA0D,GAAG,EAGzG,EAAkB,GACpB,EAAM,GAAW,GAAU,EAE3B,EAAM,IAAY,CAEtB,CAEA,OAAO,CACT"}
|