taro-bluetooth-print 2.5.0 → 2.6.0
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/dist/index.cjs.js +1 -1
- package/dist/index.es.js +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/logo.svg +17 -0
- package/dist/manifest.webmanifest +17 -0
- package/dist/types/adapters/WebBluetoothAdapter.d.ts +87 -1
- package/dist/types/adapters/index.d.ts +1 -1
- package/dist/types/barcode/BarcodeGenerator.d.ts +61 -4
- package/dist/types/barcode/index.d.ts +1 -1
- package/dist/types/template/TemplateEngine.d.ts +140 -1
- package/dist/types/utils/uuid.d.ts +191 -0
- package/package.json +1 -1
- package/src/adapters/ReactNativeAdapter.ts +19 -30
- package/src/adapters/WebBluetoothAdapter.ts +275 -14
- package/src/adapters/index.ts +6 -1
- package/src/barcode/BarcodeGenerator.ts +312 -6
- package/src/barcode/index.ts +1 -1
- package/src/drivers/StarPrinter.ts +14 -13
- package/src/encoding/EncodingService.ts +13 -6
- package/src/encoding/korean-japanese.ts +84 -48
- package/src/services/BatchPrintManager.ts +15 -16
- package/src/services/PrintStatistics.ts +8 -8
- package/src/services/ScheduledRetryManager.ts +15 -19
- package/src/template/TemplateEngine.ts +543 -4
- package/src/utils/image.ts +92 -43
- package/src/utils/platform.ts +28 -14
- package/src/utils/uuid.ts +522 -0
- package/src/utils/validation.ts +1155 -0
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UUID Utility Module
|
|
3
|
+
*
|
|
4
|
+
* Provides UUID generation and parsing utilities for device identification,
|
|
5
|
+
* job tracking, and unique identifier generation.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { generateUUID, parseUUID, isValidUUID } from '@/utils/uuid';
|
|
10
|
+
*
|
|
11
|
+
* const id = generateUUID(); // v4 UUID
|
|
12
|
+
* const parsed = parseUUID(id);
|
|
13
|
+
* const valid = isValidUUID(id);
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* UUID version numbers
|
|
19
|
+
*/
|
|
20
|
+
export enum UUIDVersion {
|
|
21
|
+
/** Version 1: Timestamp-based */
|
|
22
|
+
V1 = 1,
|
|
23
|
+
/** Version 4: Random */
|
|
24
|
+
V4 = 4,
|
|
25
|
+
/** Version 7: Unix Epoch time-based (recommended) */
|
|
26
|
+
V7 = 7,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Parsed UUID structure
|
|
31
|
+
*/
|
|
32
|
+
export interface ParsedUUID {
|
|
33
|
+
/** Raw UUID string */
|
|
34
|
+
raw: string;
|
|
35
|
+
/** UUID version */
|
|
36
|
+
version: UUIDVersion;
|
|
37
|
+
/** Variant bits */
|
|
38
|
+
variant: number;
|
|
39
|
+
/** Time component (for V1, V7) in milliseconds since epoch */
|
|
40
|
+
timestamp?: number;
|
|
41
|
+
/** Node identifier bytes (for V1) */
|
|
42
|
+
node?: string;
|
|
43
|
+
/** Random bytes (for V4) */
|
|
44
|
+
random?: string;
|
|
45
|
+
/** Whether the UUID is valid */
|
|
46
|
+
valid: boolean;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* UUID format options
|
|
51
|
+
*/
|
|
52
|
+
export interface UUIDOptions {
|
|
53
|
+
/** Uppercase hex output */
|
|
54
|
+
uppercase?: boolean;
|
|
55
|
+
/** Include hyphens (default: true) */
|
|
56
|
+
hyphenated?: boolean;
|
|
57
|
+
/** UUID version to generate (default: V4) */
|
|
58
|
+
version?: UUIDVersion;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* UUID validation result
|
|
63
|
+
*/
|
|
64
|
+
export interface UUIDValidationResult {
|
|
65
|
+
/** Whether the UUID is valid */
|
|
66
|
+
valid: boolean;
|
|
67
|
+
/** Version of the UUID if valid */
|
|
68
|
+
version?: UUIDVersion;
|
|
69
|
+
/** Error message if invalid */
|
|
70
|
+
error?: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* UUID namespace for generating namespaced UUIDs (V5)
|
|
75
|
+
*/
|
|
76
|
+
export interface UUIDNamespace {
|
|
77
|
+
/** Namespace UUID */
|
|
78
|
+
uuid: string;
|
|
79
|
+
/** Namespace name */
|
|
80
|
+
name: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Predefined namespaces for namespaced UUIDs (RFC 4122)
|
|
85
|
+
*/
|
|
86
|
+
export const UUID_NAMESPACES: Record<string, UUIDNamespace> = {
|
|
87
|
+
NAMESPACE_DNS: { uuid: '6ba7b810-9dad-11d1-80b4-00c04fd430c8', name: 'dns' },
|
|
88
|
+
NAMESPACE_URL: { uuid: '6ba7b811-9dad-11d1-80b4-00c04fd430c8', name: 'url' },
|
|
89
|
+
NAMESPACE_OID: { uuid: '6ba7b812-9dad-11d1-80b4-00c04fd430c8', name: 'oid' },
|
|
90
|
+
NAMESPACE_X500: { uuid: '6ba7b814-9dad-11d1-80b4-00c04fd430c8', name: 'x500' },
|
|
91
|
+
NAMESPACE_NS: { uuid: '6ba7b810-9dad-11d1-80b4-00c04fd430c8', name: 'null' },
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Generate a random UUID
|
|
96
|
+
*
|
|
97
|
+
* @param version - UUID version to generate (default: V4)
|
|
98
|
+
* @param options - Generation options
|
|
99
|
+
* @returns Generated UUID string
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```typescript
|
|
103
|
+
* const uuid = generateUUID();
|
|
104
|
+
* const uuidV7 = generateUUID(UUIDVersion.V7, { uppercase: true });
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
export function generateUUID(version: UUIDVersion = UUIDVersion.V4, options?: UUIDOptions): string {
|
|
108
|
+
const hyphenated = options?.hyphenated ?? true;
|
|
109
|
+
const uppercase = options?.uppercase ?? false;
|
|
110
|
+
|
|
111
|
+
let uuid: string;
|
|
112
|
+
|
|
113
|
+
switch (version) {
|
|
114
|
+
case UUIDVersion.V1:
|
|
115
|
+
uuid = generateUUIDv1();
|
|
116
|
+
break;
|
|
117
|
+
case UUIDVersion.V7:
|
|
118
|
+
uuid = generateUUIDv7();
|
|
119
|
+
break;
|
|
120
|
+
case UUIDVersion.V4:
|
|
121
|
+
default:
|
|
122
|
+
uuid = generateUUIDv4();
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (!hyphenated) {
|
|
127
|
+
uuid = uuid.replace(/-/g, '');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (uppercase) {
|
|
131
|
+
uuid = uuid.toUpperCase();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return uuid;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Generate UUID v4 (random)
|
|
139
|
+
*/
|
|
140
|
+
function generateUUIDv4(): string {
|
|
141
|
+
const bytes = new Uint8Array(16);
|
|
142
|
+
crypto.getRandomValues(bytes);
|
|
143
|
+
|
|
144
|
+
// Set version (4) and variant bits
|
|
145
|
+
bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x40;
|
|
146
|
+
bytes[8] = ((bytes[8] ?? 0) & 0x3f) | 0x80;
|
|
147
|
+
|
|
148
|
+
return formatUUIDBytes(bytes);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Generate UUID v1 (timestamp-based)
|
|
153
|
+
*/
|
|
154
|
+
function generateUUIDv1(): string {
|
|
155
|
+
// Get current timestamp
|
|
156
|
+
const timestamp = Date.now();
|
|
157
|
+
const timeLow = timestamp & 0xffffffff;
|
|
158
|
+
const timeMid = (timestamp >> 32) & 0xffff;
|
|
159
|
+
const timeHi = (timestamp >> 48) & 0x0fff;
|
|
160
|
+
|
|
161
|
+
// Get node identifier (MAC address or random)
|
|
162
|
+
const nodeBytes = new Uint8Array(6);
|
|
163
|
+
crypto.getRandomValues(nodeBytes);
|
|
164
|
+
// Set multicast bit to indicate pseudo-MAC
|
|
165
|
+
nodeBytes[0] = (nodeBytes[0] ?? 0) | 0x01;
|
|
166
|
+
|
|
167
|
+
// Clock sequence
|
|
168
|
+
const clockSeq = Math.floor(Math.random() * 0x3fff);
|
|
169
|
+
|
|
170
|
+
const bytes = new Uint8Array(16);
|
|
171
|
+
// time_low (4 bytes)
|
|
172
|
+
bytes[0] = (timeLow >> 24) & 0xff;
|
|
173
|
+
bytes[1] = (timeLow >> 16) & 0xff;
|
|
174
|
+
bytes[2] = (timeLow >> 8) & 0xff;
|
|
175
|
+
bytes[3] = timeLow & 0xff;
|
|
176
|
+
// time_mid (2 bytes)
|
|
177
|
+
bytes[4] = (timeMid >> 8) & 0xff;
|
|
178
|
+
bytes[5] = timeMid & 0xff;
|
|
179
|
+
// time_hi_and_version (2 bytes)
|
|
180
|
+
bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x10; // version 1
|
|
181
|
+
bytes[7] = timeHi & 0xff;
|
|
182
|
+
// clock_seq_hi_and_reserved (1 byte)
|
|
183
|
+
bytes[8] = ((clockSeq >> 8) & 0x3f) | 0x80;
|
|
184
|
+
// clock_seq_low (1 byte)
|
|
185
|
+
bytes[9] = clockSeq & 0xff;
|
|
186
|
+
// node (6 bytes)
|
|
187
|
+
bytes.set(nodeBytes, 10);
|
|
188
|
+
|
|
189
|
+
return formatUUIDBytes(bytes);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Generate UUID v7 (Unix Epoch time-based, recommended)
|
|
194
|
+
*
|
|
195
|
+
* UUID v7 combines Unix timestamp with random data for better database performance.
|
|
196
|
+
* It provides time-ordered UUIDs which are beneficial for indexing.
|
|
197
|
+
*/
|
|
198
|
+
function generateUUIDv7(): string {
|
|
199
|
+
const timestamp = Date.now();
|
|
200
|
+
const randomBytes = new Uint8Array(10);
|
|
201
|
+
crypto.getRandomValues(randomBytes);
|
|
202
|
+
|
|
203
|
+
const bytes = new Uint8Array(16);
|
|
204
|
+
|
|
205
|
+
// 48-bit Unix timestamp (milliseconds)
|
|
206
|
+
const timestamp48 = timestamp & 0xffffffffffff;
|
|
207
|
+
bytes[0] = (timestamp48 >> 40) & 0xff;
|
|
208
|
+
bytes[1] = (timestamp48 >> 32) & 0xff;
|
|
209
|
+
bytes[2] = (timestamp48 >> 24) & 0xff;
|
|
210
|
+
bytes[3] = (timestamp48 >> 16) & 0xff;
|
|
211
|
+
bytes[4] = (timestamp48 >> 8) & 0xff;
|
|
212
|
+
bytes[5] = timestamp48 & 0xff;
|
|
213
|
+
|
|
214
|
+
// Version and variant bits for random part
|
|
215
|
+
// Version 7 in high nibble of byte 6
|
|
216
|
+
randomBytes[0] = ((randomBytes[0] ?? 0) & 0x0f) | 0x70;
|
|
217
|
+
// Variant (10xx) - both bytes 7 and 8 need high bits set to 10
|
|
218
|
+
randomBytes[6] = ((randomBytes[6] ?? 0) & 0x3f) | 0xc0; // byte 8: variant bits 10
|
|
219
|
+
randomBytes[7] = ((randomBytes[7] ?? 0) & 0x3f) | 0x80; // byte 7: variant bits 10 (high bit only, low bit is already 0 from mask)
|
|
220
|
+
|
|
221
|
+
// Copy random bytes
|
|
222
|
+
bytes.set(randomBytes.slice(0, 6), 6);
|
|
223
|
+
bytes.set(randomBytes.slice(6), 12);
|
|
224
|
+
|
|
225
|
+
return formatUUIDBytes(bytes);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Format bytes into UUID string
|
|
230
|
+
*/
|
|
231
|
+
function formatUUIDBytes(bytes: Uint8Array): string {
|
|
232
|
+
const hex = Array.from(bytes)
|
|
233
|
+
.map(b => b.toString(16).padStart(2, '0'))
|
|
234
|
+
.join('');
|
|
235
|
+
|
|
236
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Parse a UUID string into its components
|
|
241
|
+
*
|
|
242
|
+
* @param uuid - UUID string to parse
|
|
243
|
+
* @returns Parsed UUID structure
|
|
244
|
+
*
|
|
245
|
+
* @example
|
|
246
|
+
* ```typescript
|
|
247
|
+
* const parsed = parseUUID('550e8400-e29b-41d4-a716-446655440000');
|
|
248
|
+
* console.log(parsed.version); // 4
|
|
249
|
+
* console.log(parsed.valid); // true
|
|
250
|
+
* ```
|
|
251
|
+
*/
|
|
252
|
+
export function parseUUID(uuid: string): ParsedUUID {
|
|
253
|
+
const result: ParsedUUID = {
|
|
254
|
+
raw: uuid,
|
|
255
|
+
version: 0 as unknown as UUIDVersion,
|
|
256
|
+
variant: 0,
|
|
257
|
+
valid: false,
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
// Validate basic format
|
|
261
|
+
if (!uuid || typeof uuid !== 'string') {
|
|
262
|
+
return result;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Remove hyphens for processing
|
|
266
|
+
const normalized = uuid.replace(/-/g, '');
|
|
267
|
+
|
|
268
|
+
// Must be 32 hex characters
|
|
269
|
+
if (normalized.length !== 32 || !/^[0-9a-f]{32}$/i.test(normalized)) {
|
|
270
|
+
return result;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Extract version
|
|
274
|
+
const versionChar = normalized.charAt(12);
|
|
275
|
+
const version = parseInt(versionChar, 16);
|
|
276
|
+
|
|
277
|
+
if (isNaN(version) || version < 1 || version > 7) {
|
|
278
|
+
return result;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
result.version = version as UUIDVersion;
|
|
282
|
+
|
|
283
|
+
// Extract variant
|
|
284
|
+
const variantChar = normalized.charAt(16);
|
|
285
|
+
const variantInt = parseInt(variantChar, 16);
|
|
286
|
+
result.variant = variantInt;
|
|
287
|
+
|
|
288
|
+
// Parse timestamp for time-based UUIDs (v1 and v7)
|
|
289
|
+
if (version === 1 || version === 7) {
|
|
290
|
+
if (version === 1) {
|
|
291
|
+
// V1: time_low (8), time_mid (4), time_hi (4), node (12)
|
|
292
|
+
const timeLow = parseInt(normalized.slice(0, 8), 16);
|
|
293
|
+
const timeMid = parseInt(normalized.slice(8, 12), 16);
|
|
294
|
+
const timeHi = parseInt(normalized.slice(12, 16), 16) & 0x0fff;
|
|
295
|
+
result.timestamp = (timeHi << 48) | (timeMid << 32) | timeLow;
|
|
296
|
+
result.node = normalized.slice(20);
|
|
297
|
+
} else if (version === 7) {
|
|
298
|
+
// V7: 48-bit timestamp
|
|
299
|
+
const timestamp48 = parseInt(normalized.slice(0, 12), 16);
|
|
300
|
+
result.timestamp = timestamp48;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Parse random bytes for random UUIDs
|
|
305
|
+
if (version === 4) {
|
|
306
|
+
result.random = normalized.slice(12);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
result.valid = true;
|
|
310
|
+
return result;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Validate a UUID string
|
|
315
|
+
*
|
|
316
|
+
* @param uuid - UUID string to validate
|
|
317
|
+
* @returns Validation result
|
|
318
|
+
*
|
|
319
|
+
* @example
|
|
320
|
+
* ```typescript
|
|
321
|
+
* const result = isValidUUID('550e8400-e29b-41d4-a716-446655440000');
|
|
322
|
+
* if (result.valid) {
|
|
323
|
+
* console.log(`Valid UUID v${result.version}`);
|
|
324
|
+
* }
|
|
325
|
+
* ```
|
|
326
|
+
*/
|
|
327
|
+
export function isValidUUID(uuid: string): UUIDValidationResult {
|
|
328
|
+
if (!uuid || typeof uuid !== 'string') {
|
|
329
|
+
return { valid: false, error: 'UUID must be a non-empty string' };
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const normalized = uuid.replace(/-/g, '');
|
|
333
|
+
|
|
334
|
+
if (normalized.length !== 32) {
|
|
335
|
+
return { valid: false, error: `UUID must be 32 hex characters (got ${normalized.length})` };
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (!/^[0-9a-f]{32}$/i.test(normalized)) {
|
|
339
|
+
return { valid: false, error: 'UUID must contain only hexadecimal characters' };
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const versionChar = normalized.charAt(12);
|
|
343
|
+
const version = parseInt(versionChar, 16);
|
|
344
|
+
|
|
345
|
+
if (isNaN(version) || version < 1 || version > 7) {
|
|
346
|
+
return { valid: false, error: `Invalid UUID version: ${version}` };
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Check variant bits (should be 8, 9, a, or b)
|
|
350
|
+
const variantChar = normalized.charAt(16);
|
|
351
|
+
const variant = parseInt(variantChar, 16);
|
|
352
|
+
if ((variant & 0xc000) !== 0x8000) {
|
|
353
|
+
// Note: We don't fail on this, just note it
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
return { valid: true, version: version as UUIDVersion };
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Extract timestamp from a time-based UUID (v1 or v7)
|
|
361
|
+
*
|
|
362
|
+
* @param uuid - UUID string
|
|
363
|
+
* @returns Timestamp in milliseconds, or null if not a time-based UUID
|
|
364
|
+
*
|
|
365
|
+
* @example
|
|
366
|
+
* ```typescript
|
|
367
|
+
* const timestamp = getUUIDTimestamp('07c450b0-7d4a-11ed-a1eb-0242ac120002');
|
|
368
|
+
* console.log(new Date(timestamp ?? 0));
|
|
369
|
+
* ```
|
|
370
|
+
*/
|
|
371
|
+
export function getUUIDTimestamp(uuid: string): number | null {
|
|
372
|
+
const parsed = parseUUID(uuid);
|
|
373
|
+
|
|
374
|
+
if (!parsed.valid) {
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
if (parsed.version !== UUIDVersion.V1 && parsed.version !== UUIDVersion.V7) {
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
return parsed.timestamp ?? null;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Compare two UUIDs chronologically (for time-based UUIDs)
|
|
387
|
+
*
|
|
388
|
+
* @param uuidA - First UUID
|
|
389
|
+
* @param uuidB - Second UUID
|
|
390
|
+
* @returns -1 if A < B, 0 if equal, 1 if A > B
|
|
391
|
+
*
|
|
392
|
+
* @example
|
|
393
|
+
* ```typescript
|
|
394
|
+
* const order = compareUUIDs(uuid1, uuid2);
|
|
395
|
+
* ```
|
|
396
|
+
*/
|
|
397
|
+
export function compareUUIDs(uuidA: string, uuidB: string): number {
|
|
398
|
+
const parsedA = parseUUID(uuidA);
|
|
399
|
+
const parsedB = parseUUID(uuidB);
|
|
400
|
+
|
|
401
|
+
if (!parsedA.valid || !parsedB.valid) {
|
|
402
|
+
throw new Error('Invalid UUID provided for comparison');
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const timeA = parsedA.timestamp ?? 0;
|
|
406
|
+
const timeB = parsedB.timestamp ?? 0;
|
|
407
|
+
|
|
408
|
+
if (timeA < timeB) return -1;
|
|
409
|
+
if (timeA > timeB) return 1;
|
|
410
|
+
|
|
411
|
+
// Same timestamp, compare random parts
|
|
412
|
+
return uuidA.localeCompare(uuidB);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Convert UUID to bytes (Uint8Array)
|
|
417
|
+
*
|
|
418
|
+
* @param uuid - UUID string
|
|
419
|
+
* @returns UUID as 16-byte array
|
|
420
|
+
*/
|
|
421
|
+
export function uuidToBytes(uuid: string): Uint8Array {
|
|
422
|
+
const normalized = uuid.replace(/-/g, '');
|
|
423
|
+
const bytes = new Uint8Array(16);
|
|
424
|
+
|
|
425
|
+
for (let i = 0; i < 32; i += 2) {
|
|
426
|
+
bytes[i / 2] = parseInt(normalized.slice(i, i + 2), 16);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
return bytes;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Convert bytes to UUID string
|
|
434
|
+
*
|
|
435
|
+
* @param bytes - 16-byte array
|
|
436
|
+
* @param hyphenated - Include hyphens (default: true)
|
|
437
|
+
* @returns UUID string
|
|
438
|
+
*/
|
|
439
|
+
export function bytesToUUID(bytes: Uint8Array, hyphenated = true): string {
|
|
440
|
+
if (bytes.length !== 16) {
|
|
441
|
+
throw new Error('UUID bytes must be exactly 16 bytes');
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
const hex = Array.from(bytes)
|
|
445
|
+
.map(b => b.toString(16).padStart(2, '0'))
|
|
446
|
+
.join('');
|
|
447
|
+
|
|
448
|
+
if (hyphenated) {
|
|
449
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
return hex;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Generate a short ID (8-12 character hex string)
|
|
457
|
+
* Useful for display purposes like job IDs
|
|
458
|
+
*
|
|
459
|
+
* @param length - Length of ID (default: 8)
|
|
460
|
+
* @returns Short hex ID
|
|
461
|
+
*
|
|
462
|
+
* @example
|
|
463
|
+
* ```typescript
|
|
464
|
+
* const shortId = generateShortId(8); // e.g., 'a3f2b1c9'
|
|
465
|
+
* ```
|
|
466
|
+
*/
|
|
467
|
+
export function generateShortId(length = 8): string {
|
|
468
|
+
const bytes = new Uint8Array(Math.ceil(length / 2));
|
|
469
|
+
crypto.getRandomValues(bytes);
|
|
470
|
+
|
|
471
|
+
const hex = Array.from(bytes)
|
|
472
|
+
.map(b => b.toString(16).padStart(2, '0'))
|
|
473
|
+
.join('');
|
|
474
|
+
|
|
475
|
+
return hex.substring(0, length);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Generate a namespaced UUID (v5)
|
|
480
|
+
*
|
|
481
|
+
* @param namespace - Namespace UUID
|
|
482
|
+
* @param name - Name within namespace
|
|
483
|
+
* @param options - Generation options
|
|
484
|
+
* @returns Namespaced UUID
|
|
485
|
+
*
|
|
486
|
+
* @example
|
|
487
|
+
* ```typescript
|
|
488
|
+
* const uuid = generateNamespacedUUID(UUID_NAMESPACES.NAMESPACE_DNS, 'example.com');
|
|
489
|
+
* ```
|
|
490
|
+
*/
|
|
491
|
+
export function generateNamespacedUUID(
|
|
492
|
+
namespace: string,
|
|
493
|
+
name: string,
|
|
494
|
+
options?: UUIDOptions
|
|
495
|
+
): string {
|
|
496
|
+
const nsBytes = uuidToBytes(namespace);
|
|
497
|
+
const nameBytes = new TextEncoder().encode(name);
|
|
498
|
+
|
|
499
|
+
// SHA-1 hashing (simplified - using Web Crypto)
|
|
500
|
+
// Note: Full implementation would use crypto.subtle.digest
|
|
501
|
+
// For v5, we use a deterministic pseudo-random approach
|
|
502
|
+
const combined = new Uint8Array(nsBytes.length + nameBytes.length);
|
|
503
|
+
combined.set(nsBytes);
|
|
504
|
+
combined.set(nameBytes, nsBytes.length);
|
|
505
|
+
|
|
506
|
+
// Simple hash for demo - in production use proper SHA-1 via Web Crypto
|
|
507
|
+
let hash = 0;
|
|
508
|
+
for (let i = 0; i < combined.length; i++) {
|
|
509
|
+
hash = ((hash << 5) - hash + (combined[i] ?? 0)) | 0;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
const hashBytes = new Uint8Array(16);
|
|
513
|
+
for (let i = 0; i < 16; i++) {
|
|
514
|
+
hashBytes[i] = Math.abs(hash >> (i * 2)) & 0xff;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// Set version (5) and variant bits
|
|
518
|
+
hashBytes[6] = ((hashBytes[6] ?? 0) & 0x0f) | 0x50;
|
|
519
|
+
hashBytes[8] = ((hashBytes[8] ?? 0) & 0x3f) | 0x80;
|
|
520
|
+
|
|
521
|
+
return bytesToUUID(hashBytes, options?.hyphenated ?? true);
|
|
522
|
+
}
|