From 799fd2981abe010a5e4362b5c64951be5d0902c0 Mon Sep 17 00:00:00 2001 From: Sanjit K Date: Sat, 12 Jul 2025 00:14:03 -0500 Subject: [PATCH] fixed: [BUG] crypto.randomUUID is not a function Runtime Error #205. Added fallback function with manual UUID generation if crypto.randomUUID() was not available. --- apps/web/src/lib/utils.ts | 30 +++++++++++++++++++++++++++ apps/web/src/stores/media-store.ts | 3 ++- apps/web/src/stores/project-store.ts | 5 +++-- apps/web/src/stores/timeline-store.ts | 13 ++++++------ apps/web/src/types/timeline.ts | 3 ++- 5 files changed, 44 insertions(+), 10 deletions(-) diff --git a/apps/web/src/lib/utils.ts b/apps/web/src/lib/utils.ts index ae93969..dd73059 100644 --- a/apps/web/src/lib/utils.ts +++ b/apps/web/src/lib/utils.ts @@ -5,4 +5,34 @@ import { twMerge } from "tailwind-merge"; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); +} + +/** + * Generates a UUID v4 string + * Uses crypto.randomUUID() if available, otherwise falls back to a custom implementation + */ +export function generateUUID(): string { + // Use the native crypto.randomUUID if available + if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') { + return crypto.randomUUID(); + } + + // Secure fallback using crypto.getRandomValues + const bytes = new Uint8Array(16); + crypto.getRandomValues(bytes); + + // Set version 4 (UUIDv4) + bytes[6] = (bytes[6] & 0x0f) | 0x40; + // Set variant 10xxxxxx + bytes[8] = (bytes[8] & 0x3f) | 0x80; + + const hex = [...bytes].map(b => b.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('') + ); } \ No newline at end of file diff --git a/apps/web/src/stores/media-store.ts b/apps/web/src/stores/media-store.ts index 76cdd63..dc9ad90 100644 --- a/apps/web/src/stores/media-store.ts +++ b/apps/web/src/stores/media-store.ts @@ -1,6 +1,7 @@ import { create } from "zustand"; import { storageService } from "@/lib/storage/storage-service"; import { useTimelineStore } from "./timeline-store"; +import { generateUUID } from "@/lib/utils"; export type MediaType = "image" | "video" | "audio"; @@ -161,7 +162,7 @@ export const useMediaStore = create((set, get) => ({ addMediaItem: async (projectId, item) => { const newItem: MediaItem = { ...item, - id: crypto.randomUUID(), + id: generateUUID(), }; // Add to local state immediately for UI responsiveness diff --git a/apps/web/src/stores/project-store.ts b/apps/web/src/stores/project-store.ts index 913c681..e1a4a72 100644 --- a/apps/web/src/stores/project-store.ts +++ b/apps/web/src/stores/project-store.ts @@ -4,6 +4,7 @@ import { storageService } from "@/lib/storage/storage-service"; import { toast } from "sonner"; import { useMediaStore } from "./media-store"; import { useTimelineStore } from "./timeline-store"; +import { generateUUID } from "@/lib/utils"; interface ProjectStore { activeProject: TProject | null; @@ -35,7 +36,7 @@ export const useProjectStore = create((set, get) => ({ createNewProject: async (name: string) => { const newProject: TProject = { - id: crypto.randomUUID(), + id: generateUUID(), name, thumbnail: "", createdAt: new Date(), @@ -223,7 +224,7 @@ export const useProjectStore = create((set, get) => ({ existingNumbers.length > 0 ? Math.max(...existingNumbers) + 1 : 1; const newProject: TProject = { - id: crypto.randomUUID(), + id: generateUUID(), name: `(${nextNumber}) ${baseName}`, thumbnail: project.thumbnail, createdAt: new Date(), diff --git a/apps/web/src/stores/timeline-store.ts b/apps/web/src/stores/timeline-store.ts index 8c93439..bc47e09 100644 --- a/apps/web/src/stores/timeline-store.ts +++ b/apps/web/src/stores/timeline-store.ts @@ -13,6 +13,7 @@ import { useEditorStore } from "./editor-store"; import { useMediaStore, getMediaAspectRatio } from "./media-store"; import { storageService } from "@/lib/storage/storage-service"; import { useProjectStore } from "./project-store"; +import { generateUUID } from "@/lib/utils"; // Helper function to manage element naming with suffixes const getElementNameWithSuffix = ( @@ -279,7 +280,7 @@ export const useTimelineStore = create((set, get) => { : "Track"; const newTrack: TimelineTrack = { - id: crypto.randomUUID(), + id: generateUUID(), name: trackName, type, elements: [], @@ -304,7 +305,7 @@ export const useTimelineStore = create((set, get) => { : "Track"; const newTrack: TimelineTrack = { - id: crypto.randomUUID(), + id: generateUUID(), name: trackName, type, elements: [], @@ -363,7 +364,7 @@ export const useTimelineStore = create((set, get) => { const newElement: TimelineElement = { ...elementData, - id: crypto.randomUUID(), + id: generateUUID(), startTime: elementData.startTime || 0, trimStart: 0, trimEnd: 0, @@ -556,7 +557,7 @@ export const useTimelineStore = create((set, get) => { const secondDuration = element.duration - element.trimStart - element.trimEnd - relativeTime; - const secondElementId = crypto.randomUUID(); + const secondElementId = generateUUID(); updateTracksAndSave( get()._tracks.map((track) => @@ -682,7 +683,7 @@ export const useTimelineStore = create((set, get) => { // Find existing audio track or prepare to create one const existingAudioTrack = _tracks.find((t) => t.type === "audio"); - const audioElementId = crypto.randomUUID(); + const audioElementId = generateUUID(); if (existingAudioTrack) { // Add audio element to existing audio track @@ -706,7 +707,7 @@ export const useTimelineStore = create((set, get) => { } else { // Create new audio track with the audio element in a single atomic update const newAudioTrack: TimelineTrack = { - id: crypto.randomUUID(), + id: generateUUID(), name: "Audio Track", type: "audio", elements: [ diff --git a/apps/web/src/types/timeline.ts b/apps/web/src/types/timeline.ts index a759de2..17dbb5d 100644 --- a/apps/web/src/types/timeline.ts +++ b/apps/web/src/types/timeline.ts @@ -1,4 +1,5 @@ import { MediaType } from "@/stores/media-store"; +import { generateUUID } from "@/lib/utils"; export type TrackType = "media" | "text" | "audio"; @@ -111,7 +112,7 @@ export function ensureMainTrack(tracks: TimelineTrack[]): TimelineTrack[] { if (!hasMainTrack) { // Create main track if it doesn't exist const mainTrack: TimelineTrack = { - id: crypto.randomUUID(), + id: generateUUID(), name: "Main Track", type: "media", elements: [],