From 1bef371aa3f03414a3cc0f467ae1610558b4a98a Mon Sep 17 00:00:00 2001 From: Jeremy Ruppel Date: Thu, 30 Jul 2026 19:27:04 +0000 Subject: [PATCH] refactor(site): use uuid package instead of generateUUID helper Replace the generateUUID helper added in #27661 with the existing uuid dependency (v4). Delete the helper and its tests. Keep isUUID. --- .../TemplateBuilder/TemplateBuilderPage.tsx | 4 +- site/src/utils/uuid.test.ts | 65 ------------------- site/src/utils/uuid.ts | 32 --------- 3 files changed, 2 insertions(+), 99 deletions(-) delete mode 100644 site/src/utils/uuid.test.ts diff --git a/site/src/pages/TemplateBuilder/TemplateBuilderPage.tsx b/site/src/pages/TemplateBuilder/TemplateBuilderPage.tsx index befcaba55c98c..e1a443b6580c9 100644 --- a/site/src/pages/TemplateBuilder/TemplateBuilderPage.tsx +++ b/site/src/pages/TemplateBuilder/TemplateBuilderPage.tsx @@ -1,6 +1,7 @@ import { type FC, useCallback, useEffect, useMemo, useState } from "react"; import { useMutation, useQuery } from "react-query"; import { Navigate, useNavigate, useSearchParams } from "react-router"; +import { v4 as uuidv4 } from "uuid"; import { deploymentConfig } from "#/api/queries/deployment"; import { createTemplateFromBuilder, @@ -11,7 +12,6 @@ import { Loader } from "#/components/Loader/Loader"; import { useAuthenticated } from "#/hooks/useAuthenticated"; import { linkToTemplate, useLinks } from "#/modules/navigation"; import { pageTitle } from "#/utils/page"; -import { generateUUID } from "#/utils/uuid"; import { TemplateBuilderPageView } from "./TemplateBuilderPageView"; import type { SelectedBaseMeta, @@ -30,7 +30,7 @@ const TemplateBuilderPage: FC = () => { // Stable session ID for the lifetime of this page mount, shared // across wizard_entry and compose_completion telemetry events. - const sessionId = useMemo(() => generateUUID(), []); + const sessionId = useMemo(() => uuidv4(), []); const builderDisabled = data?.config?.template_builder?.disabled ?? false; const wizardReady = diff --git a/site/src/utils/uuid.test.ts b/site/src/utils/uuid.test.ts deleted file mode 100644 index 9e381b918e388..0000000000000 --- a/site/src/utils/uuid.test.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { afterEach, describe, expect, it, vi } from "vitest"; -import { generateUUID, isUUID } from "./uuid"; - -describe("generateUUID", () => { - afterEach(() => { - vi.restoreAllMocks(); - }); - - it("delegates to crypto.randomUUID when available", () => { - const uuid = "11111111-1111-4111-8111-111111111111"; - const randomUUID = vi.spyOn(crypto, "randomUUID").mockReturnValue(uuid); - - expect(generateUUID()).toBe(uuid); - expect(randomUUID).toHaveBeenCalledTimes(1); - }); - - it("returns a valid version 4 UUID via the native path", () => { - expect(isUUID(generateUUID())).toBe(true); - }); - - describe("fallback (crypto.randomUUID unavailable)", () => { - afterEach(() => { - vi.unstubAllGlobals(); - }); - - it("sets the version and variant bits regardless of random input", () => { - // All-zero bytes leave only the version and variant bits that - // generateUUID sets itself. - vi.stubGlobal("crypto", { - getRandomValues: (array: T): T => { - if (array instanceof Uint8Array) { - array.fill(0); - } - return array; - }, - }); - - const uuid = generateUUID(); - expect(isUUID(uuid)).toBe(true); - expect(uuid).toBe("00000000-0000-4000-8000-000000000000"); - }); - - it("preserves the remaining random bits", () => { - // All-one bytes verify only the version and variant nibbles are - // masked (4 and b), leaving every other bit untouched. - vi.stubGlobal("crypto", { - getRandomValues: (array: T): T => { - if (array instanceof Uint8Array) { - array.fill(0xff); - } - return array; - }, - }); - - const uuid = generateUUID(); - expect(isUUID(uuid)).toBe(true); - expect(uuid).toBe("ffffffff-ffff-4fff-bfff-ffffffffffff"); - }); - }); - - it("generates unique values across calls", () => { - const uuids = new Set(Array.from({ length: 1000 }, () => generateUUID())); - expect(uuids.size).toBe(1000); - }); -}); diff --git a/site/src/utils/uuid.ts b/site/src/utils/uuid.ts index 3ae65ff62fc6d..999bbbb4da532 100644 --- a/site/src/utils/uuid.ts +++ b/site/src/utils/uuid.ts @@ -3,35 +3,3 @@ export const isUUID = (text: string) => { /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; return UUID.test(text); }; - -/** - * Generate a random RFC 4122 version 4 UUID. - * - * Uses `crypto.randomUUID()` when the runtime provides it. Falls back to - * generating random bytes with `crypto.getRandomValues()` and formatting - * them as a v4 UUID for environments where `randomUUID` is unavailable - * (for example, non-secure contexts). - */ -export const generateUUID = (): string => { - if (typeof crypto.randomUUID === "function") { - return crypto.randomUUID(); - } - - const bytes = crypto.getRandomValues(new Uint8Array(16)); - // Set the version (4) and variant (RFC 4122) bits. - bytes[6] = (bytes[6] & 0x0f) | 0x40; - bytes[8] = (bytes[8] & 0x3f) | 0x80; - - const hex: string[] = []; - for (const byte of bytes) { - hex.push(byte.toString(16).padStart(2, "0")); - } - - return [ - hex.slice(0, 4).join(""), - hex.slice(4, 6).join(""), - hex.slice(6, 8).join(""), - hex.slice(8, 10).join(""), - hex.slice(10, 16).join(""), - ].join("-"); -};