Browse / github.com/storytold/artcraft-services / patch
chore: mark UI-only Math.random uses as reviewed (SonarCloud S2245)
chore: mark UI-only Math.random uses as reviewed (SonarCloud S2245) Resolves the 71 `typescript:S2245` findings in the frontend. Every site is UI-only: element and upload ids, title suffixes (`reference-audio-…`), suggested usernames, a cache buster, the 3D camera's initial jitter and the sidebar's demo width. None feeds a token, credential or security decision, so each is marked `NOSONAR` with that reason rather than switched to `crypto`, which would change id formats and add a secure-context requirement for no security gain. Four sites sat inside multi-line template literals; the random suffix was hoisted to a named const so the marker could not land insid
- Status
- open
- Score
- 0.00
- Adopters
- 0 other operators
- Author
- dylanmtaylor (imported from pull request #180, open)
- Base
e57ee3d63ac478a24149384bf1473ef97aa067f8- Size
- +75 −79 in 32 files
- Review
- pending
- Shared
- 2026-10-28
- Id
74bed4fd54657096571357d1
How it went
No other operator has reported using it yet.
Diff
raw · frontend/apps/artcraft-dashboard/src/components/ui/sidebar.tsx frontend/apps/artcraft-webapp/src/components/auth/signup-form.tsx frontend/apps/artcraft-webapp/src/components/prompt-box/ImagePromptRow.tsx frontend/apps/artcraft-webapp/src/components/prompt-box/MediaReferenceRow.tsx frontend/apps/artcraft-webapp/src/pages/create-audio/create-audio.tsx frontend/apps/artcraft-webapp/src/pages/create-object/components/mesh-upload.ts frontend/apps/artcraft-webapp/src/pages/create-object/create-object.tsx frontend/apps/artcraft-webapp/src/pages/create-vfx/create-vfx.tsx frontend/apps/artcraft-webapp/src/pages/create-video/create-video.tsx frontend/apps/artcraft-webapp/src/pages/create-world/components/ReferenceVideoSlot.tsx frontend/apps/artcraft-webapp/src/pages/create-world/create-world.tsx frontend/apps/artcraft-webapp/src/pages/pagedraw/base-image-selector.tsx frontend/apps/artcraft-website-next/src/components/campaign/auth-gate-modal.tsx frontend/apps/genhub/src/hooks/use-auth.tsx frontend/libs/components/image-input/src/lib/image-input.tsx frontend/libs/components/modal/src/lib/modal.tsx frontend/libs/components/pagedraw/src/lib/HistoryStack.tsx frontend/libs/components/pagedraw/src/lib/PageDraw.tsx frontend/libs/components/pagedraw/src/lib/PaintSurface.tsx frontend/libs/components/pagedraw/src/lib/stores/SceneState.ts frontend/libs/components/pagescene/src/lib/Stage3DBody.tsx frontend/libs/components/promptbox/src/lib/ImagePromptRow.tsx frontend/libs/components/promptbox/src/lib/PromptBoxAudio.tsx frontend/libs/components/promptbox/src/lib/PromptBoxImage.tsx frontend/libs/components/promptbox/src/lib/PromptBoxVideo.tsx frontend/libs/components/promptbox/src/lib/common/AudioReferenceRow.tsx frontend/libs/components/promptbox/src/lib/deck/useDeckMedia.tsx frontend/libs/components/vfx/src/lib/PromptBoxVFX.tsx frontend/libs/components/vfx/src/lib/api.ts frontend/libs/components/vfx/src/lib/store.ts frontend/libs/components/video-editor/src/lib/adapters/default/indexeddb-project-storage.ts frontend/libs/components/video-editor/src/lib/adapters/default/local-file-media-source.ts
@@ -609,7 +609,7 @@ function SidebarMenuSkeleton({ }) { // Random width between 50 to 90%. const width = React.useMemo(() => {- return `${Math.floor(Math.random() * 40) + 50}%`;+ return `${Math.floor(Math.random() * 40) + 50}%`; // NOSONAR: UI-only id or cosmetic value, never a secret. }, []); return (@@ -61,7 +61,7 @@ export const SignupForm = ({ const emailPrefix = email.split("@")[0].replace(/[^a-zA-Z0-9]/g, ""); // Ensure we don't exceed max length (7 chars from email + 3 digits = 10 total) const truncatedPrefix = emailPrefix.substring(0, 7);- const randomSuffix = Math.floor(Math.random() * 900) + 100; // 100-999+ const randomSuffix = Math.floor(Math.random() * 900) + 100; // NOSONAR: 100-999 display suffix, never a secret. const generatedUsername = `${truncatedPrefix}${randomSuffix}`; const response = await api.Signup({@@ -136,7 +136,7 @@ export const ImagePromptRow = ({ const filesToProcess = files.slice(0, availableSlots); filesToProcess.forEach(async (file) => {- const uploadId = Math.random().toString(36).substring(7);+ const uploadId = Math.random().toString(36).substring(7); // NOSONAR: UI-only id or cosmetic value, never a secret. setUploadingImages((prev) => [...prev, { id: uploadId, previewUrl: "" }]); // Downscaled preview; the committed thumbnail reuses it while the@@ -150,7 +150,7 @@ export const ImagePromptRow = ({ setUploadingImages((prev) => prev.filter((img) => img.id !== uploadId)); await uploadImage({- title: `reference-image-${Math.random().toString(36).substring(2, 15)}`,+ title: `reference-image-${Math.random().toString(36).substring(2, 15)}`, // NOSONAR: UI-only id or cosmetic value, never a secret. assetFile: file, progressCallback: (newState) => { if (newState.status === UploaderStates.success && newState.data) {@@ -196,12 +196,12 @@ export const ImagePromptRow = ({ setUploadingEndFrame(true); const previewUrl = await createImagePreviewUrl(file); await uploadImage({- title: `end-frame-${Math.random().toString(36).substring(2, 15)}`,+ title: `end-frame-${Math.random().toString(36).substring(2, 15)}`, // NOSONAR: UI-only id or cosmetic value, never a secret. assetFile: file, progressCallback: (newState) => { if (newState.status === UploaderStates.success && newState.data) { setEndFrameImage({- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: previewUrl, fullUrl: URL.createObjectURL(file), file,@@ -114,12 +114,12 @@ export const MediaReferenceRow = ({ setUploadingVideo(true); try { await uploadVideo({- title: `reference-video-${Math.random().toString(36).substring(2, 15)}`,+ title: `reference-video-${Math.random().toString(36).substring(2, 15)}`, // NOSONAR: UI-only id or cosmetic value, never a secret. assetFile: file, progressCallback: (newState) => { if (newState.status === UploaderStates.success && newState.data) { const refVideo: RefVideo = {- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: URL.createObjectURL(file), file, mediaToken: newState.data,@@ -172,12 +172,12 @@ export const MediaReferenceRow = ({ setUploadingAudio(true); try { await uploadAudio({- title: `reference-audio-${Math.random().toString(36).substring(2, 15)}`,+ title: `reference-audio-${Math.random().toString(36).substring(2, 15)}`, // NOSONAR: UI-only id or cosmetic value, never a secret. assetFile: file, progressCallback: (newState) => { if (newState.status === UploaderStates.success && newState.data) { const refAudio: RefAudio = {- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: URL.createObjectURL(file), file, mediaToken: newState.data,@@ -351,7 +351,7 @@ export default function CreateAudio() { } total += duration; added.push({- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url, file: new File([], "library-audio"), mediaToken: item.id,@@ -370,7 +370,7 @@ export default function CreateAudio() { const newImages: RefImage[] = items .slice(0, maxImageRefs) .map((item) => ({- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: item.thumbnail || item.fullImage || "", fullUrl: item.fullImage || undefined, file: new File([], "library-image"),@@ -8,7 +8,7 @@ import type { RefImage } from "../../../components/prompt-box"; export const MESH_FILE_ACCEPT = ".glb,.gltf,.fbx,.obj"; -const randomId = () => Math.random().toString(36).substring(7);+const randomId = () => Math.random().toString(36).substring(7); // NOSONAR: UI-only id or cosmetic value, never a secret. const readAsDataUrl = (file: File): Promise<string> => new Promise((resolve, reject) => {@@ -26,7 +26,7 @@ export async function uploadViewImage( const url = await readAsDataUrl(file); return new Promise((resolve) => { uploadImage({- title: `${label.toLowerCase()}-view-${Math.random().toString(36).substring(2, 10)}`,+ title: `${label.toLowerCase()}-view-${Math.random().toString(36).substring(2, 10)}`, // NOSONAR: UI-only id or cosmetic value, never a secret. assetFile: file, progressCallback: (state) => { if (state.status === UploaderStates.success && state.data) {@@ -318,7 +318,7 @@ export default function CreateObject() { const item = items[0]; if (item && libraryTarget) { const refImage: RefImage = {- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: item.thumbnail || item.fullImage || "", fullUrl: item.fullImage || undefined, file: new File([], "library-image"),@@ -135,7 +135,7 @@ export default function CreateVFX() { const id = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID()- : Math.random().toString(36).slice(2);+ : Math.random().toString(36).slice(2); // NOSONAR: UI-only id or cosmetic value, never a secret. seedFromSession({ id, status: job.status,@@ -1093,7 +1093,7 @@ export default function CreateVideo() { const newImages: RefImage[] = items .slice(0, availableSlots) .map((item) => ({- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: item.thumbnail || item.fullImage || "", fullUrl: item.fullImage || undefined, file: new File([], "library-image"),@@ -1126,7 +1126,7 @@ export default function CreateVideo() { const candidates: RefVideo[] = items .filter((item) => !!item.fullImage) .map((item) => ({- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: item.fullImage!, file: new File([], "library-video"), mediaToken: item.id,@@ -1190,7 +1190,7 @@ export default function CreateVideo() { } total += duration; added.push({- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url, file: new File([], "library-audio"), mediaToken: item.id,@@ -1213,7 +1213,7 @@ export default function CreateVideo() { const item = items[0]; if (!item) return; setEndFrameImage({- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: item.thumbnail || item.fullImage || "", fullUrl: item.fullImage || undefined, file: new File([], "library-image"),@@ -35,7 +35,7 @@ export function ReferenceVideoSlot({ progressCallback: (state) => { if (state.status === UploaderStates.success && state.data) { onChange({- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: previewUrl, file, mediaToken: state.data,@@ -271,7 +271,7 @@ export default function CreateWorld() { const newImages: RefImage[] = items .slice(0, availableSlots) .map((item) => ({- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: item.thumbnail || item.fullImage || "", fullUrl: item.fullImage || undefined, file: new File([], "library-image"),@@ -64,11 +64,10 @@ export function BaseImageSelector({ const handleBlankCanvasConfirm = (width: number, height: number) => { setIsBlankCanvasOpen(false);+ const suffix = Math.random().toString(36).substring(2, 8); // NOSONAR: UI-only id or cosmetic value, never a secret. onImageSelect({ url: "",- mediaToken: `blank_canvas_${width}x${height}_${Math.random()- .toString(36)- .substring(2, 8)}`,+ mediaToken: `blank_canvas_${width}x${height}_${suffix}`, isBlankCanvas: true, blankCanvasWidth: width, blankCanvasHeight: height,@@ -81,7 +80,7 @@ export function BaseImageSelector({ reader.onloadend = async () => { const dataUrl = reader.result as string; await uploadImage({- title: `edit-image-${Math.random().toString(36).substring(2, 15)}`,+ title: `edit-image-${Math.random().toString(36).substring(2, 15)}`, // NOSONAR: UI-only id or cosmetic value, never a secret. assetFile: file, progressCallback: (state) => { if (state.status === UploaderStates.success && state.data) {@@ -107,7 +107,7 @@ function SignupForm({ // Username generated from the email, same scheme as the Vite form: // up to 7 alphanumerics from the local part plus a 3-digit suffix. const prefix = email.split("@")[0].replace(/[^a-zA-Z0-9]/g, "").slice(0, 7);- const username = `${prefix}${Math.floor(Math.random() * 900) + 100}`;+ const username = `${prefix}${Math.floor(Math.random() * 900) + 100}`; // NOSONAR: UI-only id or cosmetic value, never a secret. const result = await signup({ username, email,@@ -73,7 +73,7 @@ export function AuthProvider({ children }: { children: ReactNode }) { const signup = useCallback( async (email: string, password: string): Promise<string | null> => {- const username = email.split('@')[0] + Math.floor(Math.random() * 1000);+ const username = email.split('@')[0] + Math.floor(Math.random() * 1000); // NOSONAR: UI-only id or cosmetic value, never a secret. const res = await api.Signup({ username, email,@@ -47,7 +47,7 @@ export function ImageInput({ const reader = new FileReader(); reader.onloadend = () => { const newImage: ImageFile = {- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: reader.result as string, file: file, };@@ -927,7 +927,7 @@ export const Modal = ({ }, [allowBackgroundInteraction]); // Register this modal in the global registry for ESC handling- const idRef = useRef<number>(Math.floor(Math.random() * 1e9));+ const idRef = useRef<number>(Math.floor(Math.random() * 1e9)); // NOSONAR: UI-only id or cosmetic value, never a secret. useEffect(() => { if (!isOpen) return;@@ -53,7 +53,7 @@ export const HistoryStack = ({ // This is used to force image reloads in different sessions // and prevent fetching CORS-tainted images from cache- const sessionRandBuster = useRef(Math.random());+ const sessionRandBuster = useRef(Math.random()); // NOSONAR: UI-only id or cosmetic value, never a secret. const scrollRef = useRef<HTMLDivElement | null>(null); const prevPendingCountRef = useRef<number>(0); @@ -857,7 +857,7 @@ const PageDraw = ({ const subscriberId: string = crypto?.randomUUID?.() ??- `inpaint-${Date.now()}-${Math.random().toString(36).slice(2)}`;+ `inpaint-${Date.now()}-${Math.random().toString(36).slice(2)}`; // NOSONAR: UI-only id or cosmetic value, never a secret. adapter.onEnqueueMeta?.({ prompt,@@ -356,7 +356,7 @@ export const PaintSurface = ({ activeTool === "inpaint") && isWithinLeftPanel(stagePoint) ) {- const lineId = `line-${activeTool}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;+ const lineId = `line-${activeTool}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; // NOSONAR: UI-only id or cosmetic value, never a secret. const opacity = activeTool === "draw" ? brushOpacity : 1; const composite =@@ -445,7 +445,7 @@ export const PaintSurface = ({ isWithinLeftPanel(stagePoint) && e.target === e.target.getStage() ) {- const id = `node-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;+ const id = `node-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; // NOSONAR: UI-only id or cosmetic value, never a secret. const commonProps = { id, x: stagePoint.x,@@ -322,7 +322,7 @@ export interface SceneState { } export const generateId = (): string => {- return Math.random().toString(36).substring(2, 9);+ return Math.random().toString(36).substring(2, 9); // NOSONAR: UI-only id or cosmetic value, never a secret. }; // Add a flag to prevent saving state during restoration@@ -340,9 +340,9 @@ export const Stage3DBody = ({ } const newIndex = cameras.length + 1; const newId = `cam${newIndex}`;- const radius = Math.random() * 5 + 7;- const theta = Math.random() * Math.PI * 2;- const phi = Math.PI / 3 + (Math.random() * Math.PI) / 6;+ const radius = Math.random() * 5 + 7; // NOSONAR: UI-only id or cosmetic value, never a secret.+ const theta = Math.random() * Math.PI * 2; // NOSONAR: UI-only id or cosmetic value, never a secret.+ const phi = Math.PI / 3 + (Math.random() * Math.PI) / 6; // NOSONAR: UI-only id or cosmetic value, never a secret. const randomX = radius * Math.sin(phi) * Math.cos(theta); const randomY = Math.abs(radius * Math.cos(phi)) + 2; const randomZ = radius * Math.sin(phi) * Math.sin(theta);@@ -448,19 +448,18 @@ export const ImagePromptRow = ({ break; } - const uploadId = Math.random().toString(36).substring(7);+ const uploadId = Math.random().toString(36).substring(7); // NOSONAR: UI-only id or cosmetic value, never a secret. setUploadingVideo({ id: uploadId, file }); if (uploadVideo) {+ const titleSuffix = Math.random().toString(36).substring(2, 15); // NOSONAR: UI-only id or cosmetic value, never a secret. await uploadVideo({- title: `reference-video-${Math.random()- .toString(36)- .substring(2, 15)}`,+ title: `reference-video-${titleSuffix}`, assetFile: file, progressCallback: (newState) => { if (newState.status === UploaderStates.success && newState.data) { const refVideo: RefVideo = {- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: URL.createObjectURL(file), file, mediaToken: newState.data,@@ -480,7 +479,7 @@ export const ImagePromptRow = ({ }); } else { const refVideo: RefVideo = {- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: URL.createObjectURL(file), file, mediaToken: "",@@ -562,19 +561,18 @@ export const ImagePromptRow = ({ break; } - const uploadId = Math.random().toString(36).substring(7);+ const uploadId = Math.random().toString(36).substring(7); // NOSONAR: UI-only id or cosmetic value, never a secret. setUploadingAudio({ id: uploadId, file }); if (uploadAudio) {+ const titleSuffix = Math.random().toString(36).substring(2, 15); // NOSONAR: UI-only id or cosmetic value, never a secret. await uploadAudio({- title: `reference-audio-${Math.random()- .toString(36)- .substring(2, 15)}`,+ title: `reference-audio-${titleSuffix}`, assetFile: file, progressCallback: (newState) => { if (newState.status === UploaderStates.success && newState.data) { const refAudio: RefAudio = {- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: URL.createObjectURL(file), file, mediaToken: newState.data,@@ -592,7 +590,7 @@ export const ImagePromptRow = ({ }); } else { const refAudio: RefAudio = {- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: URL.createObjectURL(file), file, mediaToken: "",@@ -629,7 +627,7 @@ export const ImagePromptRow = ({ : files.slice(0, availableSlots); filesToProcess.forEach(async (file) => {- const uploadId = Math.random().toString(36).substring(7);+ const uploadId = Math.random().toString(36).substring(7); // NOSONAR: UI-only id or cosmetic value, never a secret. if (uploadTarget === "end") { setUploadingEnd({ id: uploadId, file, previewUrl: "" }); } else {@@ -680,10 +678,9 @@ export const ImagePromptRow = ({ }; if (uploadImage) {+ const titleSuffix = Math.random().toString(36).substring(2, 15); // NOSONAR: UI-only id or cosmetic value, never a secret. await uploadImage({- title: `reference-image-${Math.random()- .toString(36)- .substring(2, 15)}`,+ title: `reference-image-${titleSuffix}`, assetFile: file, progressCallback: (newState) => { if (newState.status === UploaderStates.success && newState.data) {@@ -767,7 +764,7 @@ export const ImagePromptRow = ({ } currentTotal += duration; newVideos.push({- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: item.fullImage, file: new File([], "library-video"), mediaToken: item.id,@@ -794,7 +791,7 @@ export const ImagePromptRow = ({ const item = selectedItems[0]; if (item && item.fullImage) { setEndFrameImage?.({- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: item.fullImage, file: new File([], "library-image"), mediaToken: item.id,@@ -818,7 +815,7 @@ export const ImagePromptRow = ({ selectedItems.slice(0, availableSlots).forEach((item) => { if (!item.fullImage) return; newRefs.push({- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: item.fullImage, file: new File([], "library-image"), mediaToken: item.id,@@ -273,7 +273,7 @@ export const PromptBoxAudio = ({ } total += duration; added.push({- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: item.fullImage, file: new File([], "library-audio"), mediaToken: item.id,@@ -86,7 +86,7 @@ export const PromptBoxImage = ({ useEffect(() => { if (imageMediaId && url) { const referenceImage: RefImage = {- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: url, file: new File([], "library-image"), mediaToken: imageMediaId,@@ -269,7 +269,7 @@ export const PromptBoxImage = ({ useEffect(() => { if (imageMediaId && url) { const referenceImage: RefImage = {- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: url, file: new File([], "library-image"), mediaToken: imageMediaId,@@ -371,7 +371,7 @@ export const PromptBoxImage = ({ const subscriberId = crypto.randomUUID ? crypto.randomUUID()- : Math.random().toString(36).slice(2);+ : Math.random().toString(36).slice(2); // NOSONAR: UI-only id or cosmetic value, never a secret. setTimeout(() => { console.debug("Turn off blocking of prompt box...");@@ -121,7 +121,7 @@ export const PromptBoxVideo = ({ useEffect(() => { if (imageMediaId && url) { const referenceImage: RefImage = {- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: url, file: new File([], "library-image"), mediaToken: imageMediaId,@@ -324,7 +324,7 @@ export const PromptBoxVideo = ({ useEffect(() => { if (imageMediaId && url) { const referenceImage: RefImage = {- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: url, file: new File([], "library-image"), mediaToken: imageMediaId,@@ -1199,7 +1199,7 @@ export const PromptBoxVideo = ({ for (let i = 0; i < count; i++) { const subscriberId = crypto.randomUUID ? crypto.randomUUID()- : Math.random().toString(36).slice(2);+ : Math.random().toString(36).slice(2); // NOSONAR: UI-only id or cosmetic value, never a secret. subscriberIds.push(subscriberId); enqueuePromises.push(GenerateVideo(buildRequest(subscriberId))); }@@ -104,12 +104,12 @@ export const AudioReferenceRow = forwardRef< if (uploadAudio) { setIsUploadingAudio(true); await uploadAudio({- title: `reference-audio-${Math.random().toString(36).substring(2, 15)}`,+ title: `reference-audio-${Math.random().toString(36).substring(2, 15)}`, // NOSONAR: UI-only id or cosmetic value, never a secret. assetFile: file, progressCallback: (newState) => { if (newState.status === UploaderStates.success && newState.data) { const refAudio: RefAudio = {- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: URL.createObjectURL(file), file, mediaToken: newState.data,@@ -145,12 +145,12 @@ export const AudioReferenceRow = forwardRef< setIsUploadingImage(true); await uploadImage({- title: `reference-image-${Math.random().toString(36).substring(2, 15)}`,+ title: `reference-image-${Math.random().toString(36).substring(2, 15)}`, // NOSONAR: UI-only id or cosmetic value, never a secret. assetFile: file, progressCallback: (newState) => { if (newState.status === UploaderStates.success && newState.data) { const refImage: RefImage = {- id: Math.random().toString(36).substring(7),+ id: Math.random().toString(36).substring(7), // NOSONAR: UI-only id or cosmetic value, never a secret. url: URL.createObjectURL(file), file, mediaToken: newState.data,@@ -65,7 +65,7 @@ export interface UseDeckMediaOptions< ownGalleryModal?: boolean; } -const randomId = () => Math.random().toString(36).substring(7);+const randomId = () => Math.random().toString(36).substring(7); // NOSONAR: UI-only id or cosmetic value, never a secret. // A non-finite duration cap means "no limit" — leave it out of the message. const videoLimitMessage = (maxVideos: number, maxTotalSec: number) =>@@ -74,7 +74,7 @@ const videoLimitMessage = (maxVideos: number, maxTotalSec: number) => : `Max ${maxVideos} video${maxVideos === 1 ? "" : "s"}`; const randomTitle = (prefix: string) =>- `${prefix}-${Math.random().toString(36).substring(2, 15)}`;+ `${prefix}-${Math.random().toString(36).substring(2, 15)}`; // NOSONAR: UI-only id or cosmetic value, never a secret. const getVideoDurationFromSrc = (src: string): Promise<number> => new Promise((resolve) => {@@ -95,12 +95,12 @@ export const PromptBoxVFX = ({ setSourceUploading(true); await uploadVideo({- title: `vfx-source-${Math.random().toString(36).slice(2, 10)}`,+ title: `vfx-source-${Math.random().toString(36).slice(2, 10)}`, // NOSONAR: UI-only id or cosmetic value, never a secret. assetFile: file, progressCallback: (state) => { if (state.status === UploaderStates.success && state.data) { setSource({- id: Math.random().toString(36).slice(2),+ id: Math.random().toString(36).slice(2), // NOSONAR: UI-only id or cosmetic value, never a secret. url: previewUrl, mediaToken: state.data, });@@ -136,12 +136,12 @@ export const PromptBoxVFX = ({ setUploading(true); await uploadImage({- title: `vfx-${kind}-${Math.random().toString(36).slice(2, 10)}`,+ title: `vfx-${kind}-${Math.random().toString(36).slice(2, 10)}`, // NOSONAR: UI-only id or cosmetic value, never a secret. assetFile: file, progressCallback: (state) => { if (state.status === UploaderStates.success && state.data) { setRef({- id: Math.random().toString(36).slice(2),+ id: Math.random().toString(36).slice(2), // NOSONAR: UI-only id or cosmetic value, never a secret. url: previewUrl, mediaToken: state.data, });@@ -183,7 +183,7 @@ export const PromptBoxVFX = ({ return; } const ref = {- id: Math.random().toString(36).slice(2),+ id: Math.random().toString(36).slice(2), // NOSONAR: UI-only id or cosmetic value, never a secret. url: item.fullImage || item.thumbnail || "", mediaToken: item.id, };@@ -67,5 +67,5 @@ export function newIdempotencyToken(): string { if (typeof crypto !== "undefined" && crypto.randomUUID) { return crypto.randomUUID(); }- return Math.random().toString(36).slice(2) + Date.now().toString(36);+ return Math.random().toString(36).slice(2) + Date.now().toString(36); // NOSONAR: fallback idempotency token, a uniqueness key and not a secret. }@@ -93,7 +93,7 @@ export const useVFXStore = create<VFXState>()( const id = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID()- : Math.random().toString(36).slice(2);+ : Math.random().toString(36).slice(2); // NOSONAR: UI-only id or cosmetic value, never a secret. const result: VFXResult = { id, status: "pending",@@ -50,7 +50,7 @@ function tx<T>( function newId(): string { // Sufficient for local-only storage; the lib does not expose this // id outside the host process.- return `proj_${Math.random().toString(36).slice(2, 10)}${Date.now().toString(36)}`;+ return `proj_${Math.random().toString(36).slice(2, 10)}${Date.now().toString(36)}`; // NOSONAR: UI-only id or cosmetic value, never a secret. } export function createIndexedDBProjectStorage(): ProjectStorageAdapter {@@ -17,7 +17,7 @@ interface Entry { } function newId(): string {- return `media_${Math.random().toString(36).slice(2, 10)}${Date.now().toString(36)}`;+ return `media_${Math.random().toString(36).slice(2, 10)}${Date.now().toString(36)}`; // NOSONAR: UI-only id or cosmetic value, never a secret. } export function createLocalFileMediaSource(): MediaSourceAdapter {