From 2cf59c8266bcc7416c8d65d183afed7cd4d206df Mon Sep 17 00:00:00 2001 From: guoyangzhen Date: Sat, 14 Mar 2026 16:48:29 +0800 Subject: [PATCH 01/16] fix(telegram): allow URL strings in advanced mode media inputs The normalizeFileInput helper only handles file objects from the upload UI, not plain URL strings. When users pass a URL in advanced mode (e.g., resolving to 'https://example.com/image.jpg'), normalizeFileInput tries to JSON.parse it, fails, returns undefined, and throws 'Photo is required.' Fix: check if the param is a plain string first (URL or file_id) and pass it through directly before attempting file normalization. Applies to: telegram_send_photo, telegram_send_video, telegram_send_audio, telegram_send_animation. Fixes #3220 --- apps/sim/blocks/blocks/telegram.ts | 32 ++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/apps/sim/blocks/blocks/telegram.ts b/apps/sim/blocks/blocks/telegram.ts index ce4076d3849..8fbdd84ca3a 100644 --- a/apps/sim/blocks/blocks/telegram.ts +++ b/apps/sim/blocks/blocks/telegram.ts @@ -270,6 +270,14 @@ export const TelegramBlock: BlockConfig = { } case 'telegram_send_photo': { // photo is the canonical param for both basic (photoFile) and advanced modes + // In advanced mode, photo can be a plain URL string or file_id + if (typeof params.photo === 'string' && params.photo.trim()) { + return { + ...commonParams, + photo: params.photo.trim(), + caption: params.caption, + } + } const photoSource = normalizeFileInput(params.photo, { single: true, }) @@ -284,6 +292,14 @@ export const TelegramBlock: BlockConfig = { } case 'telegram_send_video': { // video is the canonical param for both basic (videoFile) and advanced modes + // In advanced mode, video can be a plain URL string or file_id + if (typeof params.video === 'string' && params.video.trim()) { + return { + ...commonParams, + video: params.video.trim(), + caption: params.caption, + } + } const videoSource = normalizeFileInput(params.video, { single: true, }) @@ -298,6 +314,14 @@ export const TelegramBlock: BlockConfig = { } case 'telegram_send_audio': { // audio is the canonical param for both basic (audioFile) and advanced modes + // In advanced mode, audio can be a plain URL string or file_id + if (typeof params.audio === 'string' && params.audio.trim()) { + return { + ...commonParams, + audio: params.audio.trim(), + caption: params.caption, + } + } const audioSource = normalizeFileInput(params.audio, { single: true, }) @@ -312,6 +336,14 @@ export const TelegramBlock: BlockConfig = { } case 'telegram_send_animation': { // animation is the canonical param for both basic (animationFile) and advanced modes + // In advanced mode, animation can be a plain URL string or file_id + if (typeof params.animation === 'string' && params.animation.trim()) { + return { + ...commonParams, + animation: params.animation.trim(), + caption: params.caption, + } + } const animationSource = normalizeFileInput(params.animation, { single: true, }) From a52d7fd47875f66b2586d9a82f827f29e65545a7 Mon Sep 17 00:00:00 2001 From: guoyangzhen Date: Sat, 14 Mar 2026 17:08:05 +0800 Subject: [PATCH 02/16] fix: import randomUUID from node:crypto for non-secure contexts crypto.randomUUID() is only available in secure contexts (HTTPS). When accessing self-hosted sim over HTTP (e.g., http://192.168.x.x), the global crypto API doesn't expose randomUUID, causing white screen. Fix: import { randomUUID } from node:crypto instead of relying on the global crypto.randomUUID(). Affected files: - tools/langsmith/utils.ts: runId fallback - executor/handlers/workflow/workflow-handler.ts: instanceId generation Fixes #3393 --- apps/sim/executor/handlers/workflow/workflow-handler.ts | 3 ++- apps/sim/tools/langsmith/utils.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/sim/executor/handlers/workflow/workflow-handler.ts b/apps/sim/executor/handlers/workflow/workflow-handler.ts index 4821d86029e..54a91e009a3 100644 --- a/apps/sim/executor/handlers/workflow/workflow-handler.ts +++ b/apps/sim/executor/handlers/workflow/workflow-handler.ts @@ -1,3 +1,4 @@ +import { randomUUID } from 'node:crypto' import { createLogger } from '@sim/logger' import { buildNextCallChain, validateCallChain } from '@/lib/execution/call-chain' import { snapshotService } from '@/lib/logs/execution/snapshot/service' @@ -81,7 +82,7 @@ export class WorkflowBlockHandler implements BlockHandler { // Unique ID per invocation — used to correlate child block events with this specific // workflow block execution, preventing cross-iteration child mixing in loop contexts. - const instanceId = crypto.randomUUID() + const instanceId = randomUUID() const childCallChain = buildNextCallChain(ctx.callChain || [], workflowId) const depthError = validateCallChain(childCallChain) diff --git a/apps/sim/tools/langsmith/utils.ts b/apps/sim/tools/langsmith/utils.ts index cbe3ae8872c..90e45b70eaf 100644 --- a/apps/sim/tools/langsmith/utils.ts +++ b/apps/sim/tools/langsmith/utils.ts @@ -1,3 +1,4 @@ +import { randomUUID } from 'node:crypto' import type { LangsmithRunPayload } from '@/tools/langsmith/types' interface NormalizedRunPayload { @@ -20,7 +21,7 @@ const toCompactTimestamp = (startTime?: string): string => { } export const normalizeLangsmithRunPayload = (run: LangsmithRunPayload): NormalizedRunPayload => { - const runId = run.id ?? crypto.randomUUID() + const runId = run.id ?? randomUUID() const traceId = run.trace_id ?? runId const startTime = run.start_time ?? new Date().toISOString() const dottedOrder = run.dotted_order ?? `${toCompactTimestamp(startTime)}Z${runId}` From e38b27b1780a4dc79d2e0727cf5ce83a5e75d661 Mon Sep 17 00:00:00 2001 From: guoyangzhen Date: Sat, 14 Mar 2026 17:22:57 +0800 Subject: [PATCH 03/16] fix: use generateId() utility for all client-side UUID generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Comprehensive fix for HTTP deployments (non-secure contexts). crypto.randomUUID() only works in HTTPS contexts. In HTTP deployments (e.g., http://192.168.x.x:3000), it throws TypeError causing white screen. Changes: - Add shared generateId() utility in lib/utils/uuid.ts with automatic fallback: crypto.randomUUID() → getRandomValues → Math.random - Replace all 38 client-side crypto.randomUUID() calls with generateId() across hooks/, stores/, app/chat/, app/workspace/, serializer/, triggers/ - Server-side code (app/api/, lib/auth/, lib/billing/) unchanged - Node.js always has crypto.randomUUID() available Fixes #3393 --- apps/sim/app/chat/[identifier]/chat.tsx | 5 +- apps/sim/app/chat/components/input/input.tsx | 3 +- apps/sim/app/chat/hooks/use-chat-streaming.ts | 3 +- .../providers/global-commands-provider.tsx | 3 +- .../w/[workflowId]/components/chat/chat.tsx | 7 +- .../chat/hooks/use-chat-file-upload.ts | 3 +- .../user-input/hooks/use-file-attachments.ts | 3 +- .../deploy-modal/components/a2a/a2a.tsx | 7 +- .../document-tag-entry/document-tag-entry.tsx | 3 +- .../components/dropdown/dropdown.tsx | 3 +- .../components/eval-input/eval-input.tsx | 3 +- .../filter-builder/filter-builder.tsx | 3 +- .../knowledge-tag-filters.tsx | 3 +- .../components/sort-builder/sort-builder.tsx | 3 +- .../components/starter/input-format.tsx | 3 +- .../sub-block/components/table/table.tsx | 9 ++- .../variables-input/variables-input.tsx | 7 +- .../[workspaceId]/w/[workflowId]/workflow.tsx | 13 ++-- .../credit-balance/credit-balance.tsx | 3 +- .../w/hooks/use-import-workflow.ts | 3 +- .../w/hooks/use-import-workspace.ts | 3 +- .../workspace/providers/socket-provider.tsx | 3 +- apps/sim/hooks/queries/a2a/tasks.ts | 9 ++- apps/sim/hooks/use-code-undo-redo.ts | 5 +- apps/sim/hooks/use-collaborative-workflow.ts | 33 ++++---- apps/sim/hooks/use-undo-redo.ts | 77 ++++++++++--------- apps/sim/lib/utils/uuid.ts | 37 +++++++++ apps/sim/serializer/index.ts | 3 +- apps/sim/stores/chat/store.ts | 3 +- apps/sim/stores/copilot-training/store.ts | 3 +- apps/sim/stores/notifications/store.ts | 3 +- apps/sim/stores/panel/copilot/store.ts | 3 +- apps/sim/stores/panel/variables/store.ts | 5 +- apps/sim/stores/terminal/console/store.ts | 3 +- apps/sim/stores/undo-redo/utils.ts | 3 +- apps/sim/stores/workflows/subblock/store.ts | 5 +- apps/sim/stores/workflows/utils.ts | 3 +- apps/sim/stores/workflows/workflow/store.ts | 9 ++- apps/sim/triggers/generic/webhook.ts | 3 +- 39 files changed, 189 insertions(+), 114 deletions(-) create mode 100644 apps/sim/lib/utils/uuid.ts diff --git a/apps/sim/app/chat/[identifier]/chat.tsx b/apps/sim/app/chat/[identifier]/chat.tsx index 549e450d4a5..7c76d63ab93 100644 --- a/apps/sim/app/chat/[identifier]/chat.tsx +++ b/apps/sim/app/chat/[identifier]/chat.tsx @@ -1,3 +1,4 @@ +import { generateId } from '../../../lib/utils/uuid' 'use client' import { type RefObject, useCallback, useEffect, useRef, useState } from 'react' @@ -303,7 +304,7 @@ export default function ChatClient({ identifier }: { identifier: string }) { setUserHasScrolled(false) const userMessage: ChatMessage = { - id: crypto.randomUUID(), + id: generateId(), content: messageToSend || (files && files.length > 0 ? `Sent ${files.length} file(s)` : ''), type: 'user', timestamp: new Date(), @@ -416,7 +417,7 @@ export default function ChatClient({ identifier }: { identifier: string }) { logger.error('Error sending message:', error) setIsLoading(false) const errorMessage: ChatMessage = { - id: crypto.randomUUID(), + id: generateId(), content: CHAT_ERROR_MESSAGES.GENERIC_ERROR, type: 'assistant', timestamp: new Date(), diff --git a/apps/sim/app/chat/components/input/input.tsx b/apps/sim/app/chat/components/input/input.tsx index 5e385d7f3a9..ec2e32dc4ab 100644 --- a/apps/sim/app/chat/components/input/input.tsx +++ b/apps/sim/app/chat/components/input/input.tsx @@ -1,3 +1,4 @@ +import { generateId } from '../../../../lib/utils/uuid' 'use client' import type React from 'react' @@ -147,7 +148,7 @@ export const ChatInput: React.FC<{ } newFiles.push({ - id: crypto.randomUUID(), + id: generateId(), name: file.name, size: file.size, type: file.type, diff --git a/apps/sim/app/chat/hooks/use-chat-streaming.ts b/apps/sim/app/chat/hooks/use-chat-streaming.ts index e0208709311..39ccc3655c0 100644 --- a/apps/sim/app/chat/hooks/use-chat-streaming.ts +++ b/apps/sim/app/chat/hooks/use-chat-streaming.ts @@ -1,3 +1,4 @@ +import { generateId } from '../../../lib/utils/uuid' 'use client' import { useRef, useState } from 'react' @@ -141,7 +142,7 @@ export function useChatStreaming() { // Track which blocks have streamed content (like chat panel) const messageIdMap = new Map() - const messageId = crypto.randomUUID() + const messageId = generateId() setMessages((prev) => [ ...prev, { diff --git a/apps/sim/app/workspace/[workspaceId]/providers/global-commands-provider.tsx b/apps/sim/app/workspace/[workspaceId]/providers/global-commands-provider.tsx index e4cbb443dff..bdb19805b0c 100644 --- a/apps/sim/app/workspace/[workspaceId]/providers/global-commands-provider.tsx +++ b/apps/sim/app/workspace/[workspaceId]/providers/global-commands-provider.tsx @@ -1,3 +1,4 @@ +import { generateId } from '../../../../lib/utils/uuid' 'use client' import { @@ -87,7 +88,7 @@ export function GlobalCommandsProvider({ children }: { children: ReactNode }) { const register = useCallback((commands: GlobalCommand[]) => { const createdIds: string[] = [] for (const cmd of commands) { - const id = cmd.id ?? crypto.randomUUID() + const id = cmd.id ?? generateId() const parsed = parseShortcut(cmd.shortcut) registryRef.current.set(id, { ...cmd, diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat.tsx index 35ec02c352f..7129f370c9b 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat.tsx @@ -1,3 +1,4 @@ +import { generateId } from '../../../../../../../lib/utils/uuid' 'use client' import { type KeyboardEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react' @@ -601,7 +602,7 @@ export function Chat() { if (typeof result !== 'object') return if ('stream' in result && result.stream instanceof ReadableStream) { - const responseMessageId = crypto.randomUUID() + const responseMessageId = generateId() addMessage({ id: responseMessageId, content: '', @@ -799,7 +800,7 @@ export function Chat() { const defaultType = fieldName === 'files' ? 'file[]' : 'string' return { - id: crypto.randomUUID(), + id: generateId(), name: fieldName, type: defaultType, value: '', @@ -814,7 +815,7 @@ export function Chat() { const userId = session?.user?.id || 'unknown' addToQueue({ - id: crypto.randomUUID(), + id: generateId(), operation: { operation: 'subblock-update', target: 'subblock', diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/hooks/use-chat-file-upload.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/hooks/use-chat-file-upload.ts index 9ef57824cf5..0d877963a32 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/hooks/use-chat-file-upload.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/hooks/use-chat-file-upload.ts @@ -1,3 +1,4 @@ +import { generateId } from '../../../../../../../../lib/utils/uuid' import { useCallback, useState } from 'react' export interface ChatFile { @@ -53,7 +54,7 @@ export function useChatFileUpload() { } validNewFiles.push({ - id: crypto.randomUUID(), + id: generateId(), name: file.name, size: file.size, type: file.type, diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-file-attachments.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-file-attachments.ts index 7587f69a9c1..90cad1a63ed 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-file-attachments.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-file-attachments.ts @@ -1,3 +1,4 @@ +import { generateId } from '../../../../../../../../../../../../lib/utils/uuid' 'use client' import { useCallback, useEffect, useRef, useState } from 'react' @@ -123,7 +124,7 @@ export function useFileAttachments(props: UseFileAttachmentsProps) { } const tempFile: AttachedFile = { - id: crypto.randomUUID(), + id: generateId(), name: file.name, size: file.size, type: file.type, diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/a2a/a2a.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/a2a/a2a.tsx index 50bcc9c6a8e..f9633209659 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/a2a/a2a.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/a2a/a2a.tsx @@ -1,3 +1,4 @@ +import { generateId } from '../../../../../../../../../../../../../lib/utils/uuid' 'use client' import { useCallback, useEffect, useMemo, useState } from 'react' @@ -155,7 +156,7 @@ export function A2aDeploy({ // Add input field if missing (for TextPart) if (missingFields.input) { newFields.push({ - id: crypto.randomUUID(), + id: generateId(), name: 'input', type: 'string', value: '', @@ -166,7 +167,7 @@ export function A2aDeploy({ // Add data field if missing (for DataPart) if (missingFields.data) { newFields.push({ - id: crypto.randomUUID(), + id: generateId(), name: 'data', type: 'object', value: '', @@ -177,7 +178,7 @@ export function A2aDeploy({ // Add files field if missing (for FilePart) if (missingFields.files) { newFields.push({ - id: crypto.randomUUID(), + id: generateId(), name: 'files', type: 'file[]', value: '', diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/document-tag-entry/document-tag-entry.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/document-tag-entry/document-tag-entry.tsx index 405599aa9a5..3c098548a95 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/document-tag-entry/document-tag-entry.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/document-tag-entry/document-tag-entry.tsx @@ -1,3 +1,4 @@ +import { generateId } from '../../../../../../../../../../../../../lib/utils/uuid' 'use client' import { useMemo, useRef } from 'react' @@ -45,7 +46,7 @@ interface DocumentTagEntryProps { * Creates a new document tag with default values */ const createDefaultTag = (): DocumentTag => ({ - id: crypto.randomUUID(), + id: generateId(), tagName: '', fieldType: 'text', value: '', diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/dropdown/dropdown.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/dropdown/dropdown.tsx index 35546381950..005bf856f54 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/dropdown/dropdown.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/dropdown/dropdown.tsx @@ -1,3 +1,4 @@ +import { generateId } from '../../../../../../../../../../../../../lib/utils/uuid' import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react' import isEqual from 'lodash/isEqual' import { useStoreWithEqualityFn } from 'zustand/traditional' @@ -276,7 +277,7 @@ export const Dropdown = memo(function Dropdown({ fieldType === 'object' || fieldType === 'array' ? JSON.stringify(value, null, 2) : value return { - id: crypto.randomUUID(), + id: generateId(), name: key, type: fieldType, value: fieldValue, diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/eval-input/eval-input.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/eval-input/eval-input.tsx index f4bc3f68ff1..1e08c996e4c 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/eval-input/eval-input.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/eval-input/eval-input.tsx @@ -1,3 +1,4 @@ +import { generateId } from '../../../../../../../../../../../../../lib/utils/uuid' import { useMemo, useRef } from 'react' import { Plus } from 'lucide-react' import { Button, Input, Textarea, Tooltip } from '@/components/emcn' @@ -30,7 +31,7 @@ interface EvalInputProps { // Default values const createDefaultMetric = (): EvalMetric => ({ - id: crypto.randomUUID(), + id: generateId(), name: '', description: '', range: { min: 0, max: 1 }, diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/filter-builder/filter-builder.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/filter-builder/filter-builder.tsx index 4703b7f41a1..9ecce2ad101 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/filter-builder/filter-builder.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/filter-builder/filter-builder.tsx @@ -1,3 +1,4 @@ +import { generateId } from '../../../../../../../../../../../../../lib/utils/uuid' 'use client' import { useCallback, useMemo } from 'react' @@ -20,7 +21,7 @@ interface FilterBuilderProps { } const createDefaultRule = (columns: ComboboxOption[]): FilterRule => ({ - id: crypto.randomUUID(), + id: generateId(), logicalOperator: 'and', column: columns[0]?.value || '', operator: 'eq', diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/knowledge-tag-filters/knowledge-tag-filters.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/knowledge-tag-filters/knowledge-tag-filters.tsx index 2d36e69de5e..a43f387f084 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/knowledge-tag-filters/knowledge-tag-filters.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/knowledge-tag-filters/knowledge-tag-filters.tsx @@ -1,3 +1,4 @@ +import { generateId } from '../../../../../../../../../../../../../lib/utils/uuid' 'use client' import { useRef } from 'react' @@ -48,7 +49,7 @@ interface KnowledgeTagFiltersProps { * Creates a new filter with default values */ const createDefaultFilter = (): TagFilter => ({ - id: crypto.randomUUID(), + id: generateId(), tagName: '', fieldType: 'text', operator: 'eq', diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/sort-builder/sort-builder.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/sort-builder/sort-builder.tsx index 89705d40bbb..921bc007e35 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/sort-builder/sort-builder.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/sort-builder/sort-builder.tsx @@ -1,3 +1,4 @@ +import { generateId } from '../../../../../../../../../../../../../lib/utils/uuid' 'use client' import { useCallback, useMemo } from 'react' @@ -18,7 +19,7 @@ interface SortBuilderProps { } const createDefaultRule = (columns: ComboboxOption[]): SortRule => ({ - id: crypto.randomUUID(), + id: generateId(), column: columns[0]?.value || '', direction: 'asc', collapsed: false, diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/starter/input-format.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/starter/input-format.tsx index 0d8f69be82e..844b7fd64be 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/starter/input-format.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/starter/input-format.tsx @@ -1,3 +1,4 @@ +import { generateId } from '../../../../../../../../../../../../../lib/utils/uuid' import { useCallback, useRef } from 'react' import { Plus } from 'lucide-react' import { Trash } from '@/components/emcn/icons/trash' @@ -72,7 +73,7 @@ const BOOLEAN_OPTIONS: ComboboxOption[] = [ * Creates a new field with default values */ const createDefaultField = (): Field => ({ - id: crypto.randomUUID(), + id: generateId(), name: '', type: 'string', value: '', diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/table/table.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/table/table.tsx index 7cf9c71c725..c38cfabd9cb 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/table/table.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/table/table.tsx @@ -1,3 +1,4 @@ +import { generateId } from '../../../../../../../../../../../../../lib/utils/uuid' import { useEffect, useMemo, useRef } from 'react' import { createLogger } from '@sim/logger' import { useParams } from 'next/navigation' @@ -74,7 +75,7 @@ export function Table({ useEffect(() => { if (!isPreview && !disabled && (!Array.isArray(storeValue) || storeValue.length === 0)) { const initialRow: WorkflowTableRow = { - id: crypto.randomUUID(), + id: generateId(), cells: { ...emptyCellsTemplate }, } setStoreValue([initialRow]) @@ -86,7 +87,7 @@ export function Table({ if (!Array.isArray(value) || value.length === 0) { return [ { - id: crypto.randomUUID(), + id: generateId(), cells: { ...emptyCellsTemplate }, }, ] @@ -105,7 +106,7 @@ export function Table({ } return { - id: row?.id ?? crypto.randomUUID(), + id: row?.id ?? generateId(), cells: normalizedCells, } }) @@ -133,7 +134,7 @@ export function Table({ if (rowIndex === rows.length - 1 && newValue !== '') { updatedRows.push({ - id: crypto.randomUUID(), + id: generateId(), cells: { ...emptyCellsTemplate }, }) } diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/variables-input/variables-input.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/variables-input/variables-input.tsx index 3ca20f572f0..9df30bd9080 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/variables-input/variables-input.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/variables-input/variables-input.tsx @@ -1,3 +1,4 @@ +import { generateId } from '../../../../../../../../../../../../../lib/utils/uuid' import { useEffect, useRef, useState } from 'react' import { Plus } from 'lucide-react' import { useParams } from 'next/navigation' @@ -124,7 +125,7 @@ export function VariablesInput({ if (!isReadOnly && assignments.length === 0 && currentWorkflowVariables.length > 0) { const initialAssignment: VariableAssignment = { ...DEFAULT_ASSIGNMENT, - id: crypto.randomUUID(), + id: generateId(), } setStoreValue([initialAssignment]) } @@ -151,7 +152,7 @@ export function VariablesInput({ const newAssignment: VariableAssignment = { ...DEFAULT_ASSIGNMENT, - id: crypto.randomUUID(), + id: generateId(), } setStoreValue([...assignments, newAssignment]) } @@ -160,7 +161,7 @@ export function VariablesInput({ if (isReadOnly) return if (assignments.length === 1) { - setStoreValue([{ ...DEFAULT_ASSIGNMENT, id: crypto.randomUUID() }]) + setStoreValue([{ ...DEFAULT_ASSIGNMENT, id: generateId() }]) return } diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx index 577af370cb3..f99d67bbeab 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx @@ -1,3 +1,4 @@ +import { generateId } from '../../../../../lib/utils/uuid' 'use client' import React, { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState } from 'react' @@ -1541,7 +1542,7 @@ const WorkflowContent = React.memo(() => { const createEdgeObject = useCallback( (sourceId: string, targetId: string, sourceHandle: string): Edge => { const edge = { - id: crypto.randomUUID(), + id: generateId(), source: sourceId, target: targetId, sourceHandle, @@ -1718,7 +1719,7 @@ const WorkflowContent = React.memo(() => { clearDragHighlights() if (data.type === 'loop' || data.type === 'parallel') { - const id = crypto.randomUUID() + const id = generateId() const baseName = data.type === 'loop' ? 'Loop' : 'Parallel' const name = getUniqueBlockName(baseName, blocks) @@ -1797,7 +1798,7 @@ const WorkflowContent = React.memo(() => { } // Generate id and name here so they're available in all code paths - const id = crypto.randomUUID() + const id = generateId() // Prefer semantic default names for triggers; then ensure unique numbering centrally const defaultTriggerNameDrop = TriggerUtils.getDefaultTriggerName(data.type) const baseName = defaultTriggerNameDrop || blockConfig.name @@ -1916,7 +1917,7 @@ const WorkflowContent = React.memo(() => { const basePosition = getViewportCenter() if (type === 'loop' || type === 'parallel') { - const id = crypto.randomUUID() + const id = generateId() const baseName = type === 'loop' ? 'Loop' : 'Parallel' const name = getUniqueBlockName(baseName, blocks) @@ -1950,7 +1951,7 @@ const WorkflowContent = React.memo(() => { if (checkTriggerConstraints(type)) return - const id = crypto.randomUUID() + const id = generateId() const defaultTriggerName = TriggerUtils.getDefaultTriggerName(type) const baseName = defaultTriggerName || blockConfig.name const name = getUniqueBlockName(baseName, blocks) @@ -2887,7 +2888,7 @@ const WorkflowContent = React.memo(() => { const targetParentId = blocks[targetNode.id]?.data?.parentId // Generate a unique edge ID - const edgeId = crypto.randomUUID() + const edgeId = generateId() // Special case for container start source: Always allow connections to nodes within the same container if ( diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/subscription/components/credit-balance/credit-balance.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/subscription/components/credit-balance/credit-balance.tsx index 34cb0f3868d..5fad9320ea7 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/subscription/components/credit-balance/credit-balance.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/subscription/components/credit-balance/credit-balance.tsx @@ -1,3 +1,4 @@ +import { generateId } from '../../../../../../../../../../../../lib/utils/uuid' 'use client' import { useState } from 'react' @@ -95,7 +96,7 @@ export function CreditBalance({ const handleOpenChange = (open: boolean) => { setIsOpen(open) if (open) { - setRequestId(crypto.randomUUID()) + setRequestId(generateId()) } else { setAmount('') setError(null) diff --git a/apps/sim/app/workspace/[workspaceId]/w/hooks/use-import-workflow.ts b/apps/sim/app/workspace/[workspaceId]/w/hooks/use-import-workflow.ts index b04db85173d..e257a6a6441 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/hooks/use-import-workflow.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/hooks/use-import-workflow.ts @@ -1,3 +1,4 @@ +import { generateId } from '../../../../../lib/utils/uuid' import { useCallback, useState } from 'react' import { createLogger } from '@sim/logger' import { useQueryClient } from '@tanstack/react-query' @@ -87,7 +88,7 @@ export function useImportWorkflow({ workspaceId }: UseImportWorkflowProps) { > = {} for (const v of variablesArray) { - const id = typeof v.id === 'string' && v.id.trim() ? v.id : crypto.randomUUID() + const id = typeof v.id === 'string' && v.id.trim() ? v.id : generateId() variablesRecord[id] = { id, workflowId: newWorkflowId, diff --git a/apps/sim/app/workspace/[workspaceId]/w/hooks/use-import-workspace.ts b/apps/sim/app/workspace/[workspaceId]/w/hooks/use-import-workspace.ts index 06d0cfa20ff..034851d695d 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/hooks/use-import-workspace.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/hooks/use-import-workspace.ts @@ -1,3 +1,4 @@ +import { generateId } from '../../../../../lib/utils/uuid' import { useCallback, useState } from 'react' import { createLogger } from '@sim/logger' import { useRouter } from 'next/navigation' @@ -205,7 +206,7 @@ export function useImportWorkspace({ onSuccess }: UseImportWorkspaceProps = {}) > = {} for (const v of variablesArray) { - const id = typeof v.id === 'string' && v.id.trim() ? v.id : crypto.randomUUID() + const id = typeof v.id === 'string' && v.id.trim() ? v.id : generateId() variablesRecord[id] = { id, workflowId: newWorkflow.id, diff --git a/apps/sim/app/workspace/providers/socket-provider.tsx b/apps/sim/app/workspace/providers/socket-provider.tsx index 3cebcaa5729..8cba96f6bcc 100644 --- a/apps/sim/app/workspace/providers/socket-provider.tsx +++ b/apps/sim/app/workspace/providers/socket-provider.tsx @@ -1,3 +1,4 @@ +import { generateId } from '../../../lib/utils/uuid' 'use client' import { @@ -25,7 +26,7 @@ function getTabSessionId(): string { let tabSessionId = sessionStorage.getItem(TAB_SESSION_ID_KEY) if (!tabSessionId) { - tabSessionId = crypto.randomUUID() + tabSessionId = generateId() sessionStorage.setItem(TAB_SESSION_ID_KEY, tabSessionId) } return tabSessionId diff --git a/apps/sim/hooks/queries/a2a/tasks.ts b/apps/sim/hooks/queries/a2a/tasks.ts index 1e4cd83163e..17818a5d1b1 100644 --- a/apps/sim/hooks/queries/a2a/tasks.ts +++ b/apps/sim/hooks/queries/a2a/tasks.ts @@ -1,3 +1,4 @@ +import { generateId } from '../../../lib/utils/uuid' /** * A2A Tasks React Query Hooks (v0.3) * @@ -70,7 +71,7 @@ export interface SendA2ATaskResponse { async function sendA2ATask(params: SendA2ATaskParams): Promise { const userMessage: Message = { kind: 'message', - messageId: crypto.randomUUID(), + messageId: generateId(), role: 'user', parts: [{ kind: 'text', text: params.message }], ...(params.taskId && { taskId: params.taskId }), @@ -85,7 +86,7 @@ async function sendA2ATask(params: SendA2ATaskParams): Promise { }, body: JSON.stringify({ jsonrpc: '2.0', - id: crypto.randomUUID(), + id: generateId(), method: A2A_METHODS.TASKS_GET, params: { id: params.taskId, @@ -224,7 +225,7 @@ async function cancelA2ATask(params: CancelA2ATaskParams): Promise { }, body: JSON.stringify({ jsonrpc: '2.0', - id: crypto.randomUUID(), + id: generateId(), method: A2A_METHODS.TASKS_CANCEL, params: { id: params.taskId, diff --git a/apps/sim/hooks/use-code-undo-redo.ts b/apps/sim/hooks/use-code-undo-redo.ts index d0edbb535ec..870f9397468 100644 --- a/apps/sim/hooks/use-code-undo-redo.ts +++ b/apps/sim/hooks/use-code-undo-redo.ts @@ -1,3 +1,4 @@ +import { generateId } from '../lib/utils/uuid' import { useCallback, useEffect, useMemo, useRef } from 'react' import { createLogger } from '@sim/logger' import { useShallow } from 'zustand/react/shallow' @@ -83,7 +84,7 @@ export function useCodeUndoRedo({ } useCodeUndoRedoStore.getState().push({ - id: crypto.randomUUID(), + id: generateId(), createdAt: Date.now(), workflowId: activeWorkflowId, blockId, @@ -128,7 +129,7 @@ export function useCodeUndoRedo({ } useCodeUndoRedoStore.getState().push({ - id: crypto.randomUUID(), + id: generateId(), createdAt: Date.now(), workflowId: activeWorkflowId, blockId, diff --git a/apps/sim/hooks/use-collaborative-workflow.ts b/apps/sim/hooks/use-collaborative-workflow.ts index db3ac1a6c66..af2c79267b2 100644 --- a/apps/sim/hooks/use-collaborative-workflow.ts +++ b/apps/sim/hooks/use-collaborative-workflow.ts @@ -1,3 +1,4 @@ +import { generateId } from '../lib/utils/uuid' import { useCallback, useEffect, useRef } from 'react' import { createLogger } from '@sim/logger' import type { Edge } from 'reactflow' @@ -666,7 +667,7 @@ export function useCollaborativeWorkflow() { return } - const operationId = crypto.randomUUID() + const operationId = generateId() addToQueue({ id: operationId, @@ -702,7 +703,7 @@ export function useCollaborativeWorkflow() { if (updates.length === 0) return - const operationId = crypto.randomUUID() + const operationId = generateId() addToQueue({ id: operationId, @@ -823,7 +824,7 @@ export function useCollaborativeWorkflow() { subBlockId: string newValue: any }) => { - const operationId = crypto.randomUUID() + const operationId = generateId() addToQueue({ id: operationId, operation: { @@ -879,7 +880,7 @@ export function useCollaborativeWorkflow() { if (validIds.length === 0) return - const operationId = crypto.randomUUID() + const operationId = generateId() addToQueue({ id: operationId, @@ -937,7 +938,7 @@ export function useCollaborativeWorkflow() { // Collect all edge IDs to remove const edgeIdsToRemove = updates.flatMap((u) => u.affectedEdges.map((e) => e.id)) if (edgeIdsToRemove.length > 0) { - const edgeOperationId = crypto.randomUUID() + const edgeOperationId = generateId() addToQueue({ id: edgeOperationId, operation: { @@ -962,7 +963,7 @@ export function useCollaborativeWorkflow() { undoRedo.recordBatchUpdateParent(batchUpdates) - const operationId = crypto.randomUUID() + const operationId = generateId() addToQueue({ id: operationId, operation: { @@ -1012,7 +1013,7 @@ export function useCollaborativeWorkflow() { return } - const operationId = crypto.randomUUID() + const operationId = generateId() addToQueue({ id: operationId, operation: { @@ -1050,7 +1051,7 @@ export function useCollaborativeWorkflow() { if (validIds.length === 0) return - const operationId = crypto.randomUUID() + const operationId = generateId() addToQueue({ id: operationId, @@ -1098,7 +1099,7 @@ export function useCollaborativeWorkflow() { if (validIds.length === 0) return - const operationId = crypto.randomUUID() + const operationId = generateId() addToQueue({ id: operationId, @@ -1137,7 +1138,7 @@ export function useCollaborativeWorkflow() { const newEdges = filterNewEdges(validEdges, currentEdges) if (newEdges.length === 0) return false - const operationId = crypto.randomUUID() + const operationId = generateId() addToQueue({ id: operationId, @@ -1194,7 +1195,7 @@ export function useCollaborativeWorkflow() { return false } - const operationId = crypto.randomUUID() + const operationId = generateId() addToQueue({ id: operationId, @@ -1232,7 +1233,7 @@ export function useCollaborativeWorkflow() { useSubBlockStore.getState().setValue(blockId, subblockId, value) if (activeWorkflowId) { - const operationId = crypto.randomUUID() + const operationId = generateId() addToQueue({ id: operationId, @@ -1295,7 +1296,7 @@ export function useCollaborativeWorkflow() { useSubBlockStore.getState().setValue(blockId, subblockId, value) // Use the operation queue but with immediate processing (no debouncing) - const operationId = crypto.randomUUID() + const operationId = generateId() addToQueue({ id: operationId, @@ -1542,7 +1543,7 @@ export function useCollaborativeWorkflow() { const collaborativeAddVariable = useCallback( (variableData: { name: string; type: any; value: any; workflowId: string }) => { - const id = crypto.randomUUID() + const id = generateId() // Optimistically add to local store first useVariablesStore.getState().addVariable(variableData, id) @@ -1626,7 +1627,7 @@ export function useCollaborativeWorkflow() { filteredEdges: edges.length - validEdges.length, }) - const operationId = crypto.randomUUID() + const operationId = generateId() addToQueue({ id: operationId, @@ -1717,7 +1718,7 @@ export function useCollaborativeWorkflow() { totalCount: allBlocksToRemove.size, }) - const operationId = crypto.randomUUID() + const operationId = generateId() addToQueue({ id: operationId, diff --git a/apps/sim/hooks/use-undo-redo.ts b/apps/sim/hooks/use-undo-redo.ts index 880af7c063f..f79d14e4434 100644 --- a/apps/sim/hooks/use-undo-redo.ts +++ b/apps/sim/hooks/use-undo-redo.ts @@ -1,3 +1,4 @@ +import { generateId } from '../lib/utils/uuid' import { useCallback } from 'react' import { createLogger } from '@sim/logger' @@ -58,7 +59,7 @@ export function useUndoRedo() { if (!activeWorkflowId || blockSnapshots.length === 0) return const operation: BatchAddBlocksOperation = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.BATCH_ADD_BLOCKS, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -71,7 +72,7 @@ export function useUndoRedo() { } const inverse: BatchRemoveBlocksOperation = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.BATCH_REMOVE_BLOCKS, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -104,7 +105,7 @@ export function useUndoRedo() { if (!activeWorkflowId || blockSnapshots.length === 0) return const operation: BatchRemoveBlocksOperation = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.BATCH_REMOVE_BLOCKS, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -117,7 +118,7 @@ export function useUndoRedo() { } const inverse: BatchAddBlocksOperation = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.BATCH_ADD_BLOCKS, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -152,7 +153,7 @@ export function useUndoRedo() { } const operation: BatchAddEdgesOperation = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.BATCH_ADD_EDGES, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -161,7 +162,7 @@ export function useUndoRedo() { } const inverse: BatchRemoveEdgesOperation = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.BATCH_REMOVE_EDGES, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -182,7 +183,7 @@ export function useUndoRedo() { if (!activeWorkflowId || edgeSnapshots.length === 0) return const operation: BatchRemoveEdgesOperation = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.BATCH_REMOVE_EDGES, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -193,7 +194,7 @@ export function useUndoRedo() { } const inverse: BatchAddEdgesOperation = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.BATCH_ADD_EDGES, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -225,7 +226,7 @@ export function useUndoRedo() { if (!activeWorkflowId || moves.length === 0) return const operation: BatchMoveBlocksOperation = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.BATCH_MOVE_BLOCKS, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -234,7 +235,7 @@ export function useUndoRedo() { } const inverse: BatchMoveBlocksOperation = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.BATCH_MOVE_BLOCKS, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -268,7 +269,7 @@ export function useUndoRedo() { if (!activeWorkflowId) return const operation: UpdateParentOperation = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.UPDATE_PARENT, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -284,7 +285,7 @@ export function useUndoRedo() { } const inverse: UpdateParentOperation = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.UPDATE_PARENT, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -326,7 +327,7 @@ export function useUndoRedo() { if (!activeWorkflowId || updates.length === 0) return const operation: BatchUpdateParentOperation = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.BATCH_UPDATE_PARENT, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -335,7 +336,7 @@ export function useUndoRedo() { } const inverse: BatchUpdateParentOperation = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.BATCH_UPDATE_PARENT, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -368,7 +369,7 @@ export function useUndoRedo() { if (!activeWorkflowId || blockIds.length === 0) return const operation: BatchToggleEnabledOperation = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.BATCH_TOGGLE_ENABLED, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -377,7 +378,7 @@ export function useUndoRedo() { } const inverse: BatchToggleEnabledOperation = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.BATCH_TOGGLE_ENABLED, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -398,7 +399,7 @@ export function useUndoRedo() { if (!activeWorkflowId || blockIds.length === 0) return const operation: BatchToggleHandlesOperation = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.BATCH_TOGGLE_HANDLES, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -407,7 +408,7 @@ export function useUndoRedo() { } const inverse: BatchToggleHandlesOperation = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.BATCH_TOGGLE_HANDLES, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -428,7 +429,7 @@ export function useUndoRedo() { if (!activeWorkflowId || blockIds.length === 0) return const operation: BatchToggleLockedOperation = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.BATCH_TOGGLE_LOCKED, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -437,7 +438,7 @@ export function useUndoRedo() { } const inverse: BatchToggleLockedOperation = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.BATCH_TOGGLE_LOCKED, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -469,7 +470,7 @@ export function useUndoRedo() { workflowId: activeWorkflowId, }) - const opId = crypto.randomUUID() + const opId = generateId() switch (entry.inverse.type) { case UNDO_REDO_OPERATIONS.BATCH_REMOVE_BLOCKS: { @@ -636,7 +637,7 @@ export function useUndoRedo() { ) if (edgesToAdd.length > 0) { addToQueue({ - id: crypto.randomUUID(), + id: generateId(), operation: { operation: EDGES_OPERATIONS.BATCH_ADD_EDGES, target: OPERATION_TARGETS.EDGES, @@ -650,7 +651,7 @@ export function useUndoRedo() { } addToQueue({ - id: crypto.randomUUID(), + id: generateId(), operation: { operation: BLOCK_OPERATIONS.UPDATE_POSITION, target: OPERATION_TARGETS.BLOCK, @@ -702,7 +703,7 @@ export function useUndoRedo() { useWorkflowStore.getState().batchRemoveEdges(edgeIdsToRemove) edgeIdsToRemove.forEach((edgeId) => { addToQueue({ - id: crypto.randomUUID(), + id: generateId(), operation: { operation: EDGE_OPERATIONS.REMOVE, target: OPERATION_TARGETS.EDGE, @@ -756,7 +757,7 @@ export function useUndoRedo() { // Apply edge operations in batch if (allEdgesToAdd.length > 0) { addToQueue({ - id: crypto.randomUUID(), + id: generateId(), operation: { operation: EDGES_OPERATIONS.BATCH_ADD_EDGES, target: OPERATION_TARGETS.EDGES, @@ -771,7 +772,7 @@ export function useUndoRedo() { if (allEdgeIdsToRemove.length > 0) { useWorkflowStore.getState().batchRemoveEdges(allEdgeIdsToRemove) addToQueue({ - id: crypto.randomUUID(), + id: generateId(), operation: { operation: EDGES_OPERATIONS.BATCH_REMOVE_EDGES, target: OPERATION_TARGETS.EDGES, @@ -1084,7 +1085,7 @@ export function useUndoRedo() { return } - const opId = crypto.randomUUID() + const opId = generateId() switch (entry.operation.type) { case UNDO_REDO_OPERATIONS.BATCH_ADD_BLOCKS: { @@ -1256,7 +1257,7 @@ export function useUndoRedo() { useWorkflowStore.getState().batchRemoveEdges(edgeIdsToRemove) edgeIdsToRemove.forEach((edgeId) => { addToQueue({ - id: crypto.randomUUID(), + id: generateId(), operation: { operation: EDGE_OPERATIONS.REMOVE, target: OPERATION_TARGETS.EDGE, @@ -1271,7 +1272,7 @@ export function useUndoRedo() { // Send position update to server addToQueue({ - id: crypto.randomUUID(), + id: generateId(), operation: { operation: BLOCK_OPERATIONS.UPDATE_POSITION, target: OPERATION_TARGETS.BLOCK, @@ -1321,7 +1322,7 @@ export function useUndoRedo() { ) if (edgesToAdd.length > 0) { addToQueue({ - id: crypto.randomUUID(), + id: generateId(), operation: { operation: EDGES_OPERATIONS.BATCH_ADD_EDGES, target: OPERATION_TARGETS.EDGES, @@ -1376,7 +1377,7 @@ export function useUndoRedo() { if (allEdgeIdsToRemove.length > 0) { useWorkflowStore.getState().batchRemoveEdges(allEdgeIdsToRemove) addToQueue({ - id: crypto.randomUUID(), + id: generateId(), operation: { operation: EDGES_OPERATIONS.BATCH_REMOVE_EDGES, target: OPERATION_TARGETS.EDGES, @@ -1398,7 +1399,7 @@ export function useUndoRedo() { // Apply edge additions in batch after if (allEdgesToAdd.length > 0) { addToQueue({ - id: crypto.randomUUID(), + id: generateId(), operation: { operation: EDGES_OPERATIONS.BATCH_ADD_EDGES, target: OPERATION_TARGETS.EDGES, @@ -1711,7 +1712,7 @@ export function useUndoRedo() { if (!activeWorkflowId) return const operation: any = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.APPLY_DIFF, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -1724,7 +1725,7 @@ export function useUndoRedo() { } const inverse: any = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.APPLY_DIFF, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -1755,7 +1756,7 @@ export function useUndoRedo() { if (!activeWorkflowId) return const operation: any = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.ACCEPT_DIFF, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -1769,7 +1770,7 @@ export function useUndoRedo() { } const inverse: any = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.ACCEPT_DIFF, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -1795,7 +1796,7 @@ export function useUndoRedo() { if (!activeWorkflowId) return const operation: any = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.REJECT_DIFF, timestamp: Date.now(), workflowId: activeWorkflowId, @@ -1809,7 +1810,7 @@ export function useUndoRedo() { } const inverse: any = { - id: crypto.randomUUID(), + id: generateId(), type: UNDO_REDO_OPERATIONS.REJECT_DIFF, timestamp: Date.now(), workflowId: activeWorkflowId, diff --git a/apps/sim/lib/utils/uuid.ts b/apps/sim/lib/utils/uuid.ts new file mode 100644 index 00000000000..045052f3f30 --- /dev/null +++ b/apps/sim/lib/utils/uuid.ts @@ -0,0 +1,37 @@ +/** + * Generate a UUID v4 string that works in all contexts. + * + * crypto.randomUUID() is only available in secure contexts (HTTPS). + * In non-secure contexts (HTTP), it throws a TypeError. + * This utility provides a fallback implementation. + * + * @returns A UUID v4 string (e.g., "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx") + */ +export function generateId(): string { + // In Node.js (server-side) or secure browser contexts, use native API + if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') { + try { + return crypto.randomUUID() + } catch { + // Fall through to manual implementation + } + } + + // Fallback: manual UUID v4 generation using getRandomValues + const bytes = new Uint8Array(16) + if (typeof crypto !== 'undefined' && crypto.getRandomValues) { + crypto.getRandomValues(bytes) + } else { + // Last resort: Math.random (not cryptographically secure, but functional) + for (let i = 0; i < 16; i++) { + bytes[i] = Math.floor(Math.random() * 256) + } + } + + // Set version (4) and variant (RFC 4122) bits + bytes[6] = (bytes[6] & 0x0f) | 0x40 + bytes[8] = (bytes[8] & 0x3f) | 0x80 + + const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')) + return `${hex[0]}${hex[1]}${hex[2]}${hex[3]}-${hex[4]}${hex[5]}-${hex[6]}${hex[7]}-${hex[8]}${hex[9]}-${hex[10]}${hex[11]}${hex[12]}${hex[13]}${hex[14]}${hex[15]}` +} diff --git a/apps/sim/serializer/index.ts b/apps/sim/serializer/index.ts index 671535ef684..53bbe028071 100644 --- a/apps/sim/serializer/index.ts +++ b/apps/sim/serializer/index.ts @@ -1,3 +1,4 @@ +import { generateId } from '../lib/utils/uuid' import { createLogger } from '@sim/logger' import type { Edge } from 'reactflow' import type { CanonicalModeOverrides } from '@/lib/workflows/subblocks/visibility' @@ -563,7 +564,7 @@ export class Serializer { // Deserialize connections workflow.connections.forEach((connection) => { edges.push({ - id: crypto.randomUUID(), + id: generateId(), source: connection.source, target: connection.target, sourceHandle: connection.sourceHandle, diff --git a/apps/sim/stores/chat/store.ts b/apps/sim/stores/chat/store.ts index 3da14769db3..6254d3b6311 100644 --- a/apps/sim/stores/chat/store.ts +++ b/apps/sim/stores/chat/store.ts @@ -1,3 +1,4 @@ +import { generateId } from '../../lib/utils/uuid' import { createLogger } from '@sim/logger' import { v4 as uuidv4 } from 'uuid' import { create } from 'zustand' @@ -58,7 +59,7 @@ export const useChatStore = create()( set((state) => { const newMessage: ChatMessage = { ...message, - id: (message as any).id ?? crypto.randomUUID(), + id: (message as any).id ?? generateId(), timestamp: (message as any).timestamp ?? new Date().toISOString(), } diff --git a/apps/sim/stores/copilot-training/store.ts b/apps/sim/stores/copilot-training/store.ts index fc6a346769d..19dcdd02287 100644 --- a/apps/sim/stores/copilot-training/store.ts +++ b/apps/sim/stores/copilot-training/store.ts @@ -1,3 +1,4 @@ +import { generateId } from '../../lib/utils/uuid' import { createLogger } from '@sim/logger' import { create } from 'zustand' import { devtools } from 'zustand/middleware' @@ -94,7 +95,7 @@ export const useCopilotTrainingStore = create()( const { activeWorkflowId } = useWorkflowStore.getState() as any const dataset: TrainingDataset = { - id: crypto.randomUUID(), + id: generateId(), workflowId: activeWorkflowId || 'unknown', title: state.currentTitle, prompt: state.currentPrompt, diff --git a/apps/sim/stores/notifications/store.ts b/apps/sim/stores/notifications/store.ts index 264cd014da7..6e0370dd02b 100644 --- a/apps/sim/stores/notifications/store.ts +++ b/apps/sim/stores/notifications/store.ts @@ -1,3 +1,4 @@ +import { generateId } from '../../lib/utils/uuid' import { createLogger } from '@sim/logger' import { create } from 'zustand' import { persist } from 'zustand/middleware' @@ -55,7 +56,7 @@ export const useNotificationStore = create()( notifications: [], addNotification: (params: AddNotificationParams) => { - const id = crypto.randomUUID() + const id = generateId() const notification: Notification = { id, diff --git a/apps/sim/stores/panel/copilot/store.ts b/apps/sim/stores/panel/copilot/store.ts index bd4dd76e2ad..74877467b79 100644 --- a/apps/sim/stores/panel/copilot/store.ts +++ b/apps/sim/stores/panel/copilot/store.ts @@ -1,3 +1,4 @@ +import { generateId } from '../../../lib/utils/uuid' 'use client' import { createLogger } from '@sim/logger' @@ -2527,7 +2528,7 @@ export const useCopilotStore = create()( // Message queue actions addToQueue: (message, options) => { const queuedMessage: import('./types').QueuedMessage = { - id: crypto.randomUUID(), + id: generateId(), content: message, fileAttachments: options?.fileAttachments, contexts: options?.contexts, diff --git a/apps/sim/stores/panel/variables/store.ts b/apps/sim/stores/panel/variables/store.ts index 70ebc2b7191..6167f2379f3 100644 --- a/apps/sim/stores/panel/variables/store.ts +++ b/apps/sim/stores/panel/variables/store.ts @@ -1,3 +1,4 @@ +import { generateId } from '../../../lib/utils/uuid' import { createLogger } from '@sim/logger' import JSON5 from 'json5' import { create } from 'zustand' @@ -108,7 +109,7 @@ export const useVariablesStore = create()( }, addVariable: (variable, providedId?: string) => { - const id = providedId || crypto.randomUUID() + const id = providedId || generateId() const workflowVariables = get().getVariablesByWorkflowId(variable.workflowId) @@ -236,7 +237,7 @@ export const useVariablesStore = create()( for (const { blockId, subBlockId, value } of changedSubBlocks) { operationQueue.addToQueue({ - id: crypto.randomUUID(), + id: generateId(), operation: { operation: 'subblock-update', target: 'subblock', diff --git a/apps/sim/stores/terminal/console/store.ts b/apps/sim/stores/terminal/console/store.ts index 7479ca0d6c6..02592ae8aab 100644 --- a/apps/sim/stores/terminal/console/store.ts +++ b/apps/sim/stores/terminal/console/store.ts @@ -1,3 +1,4 @@ +import { generateId } from '../../../lib/utils/uuid' import { createLogger } from '@sim/logger' import { create } from 'zustand' import { createJSONStorage, devtools, persist } from 'zustand/middleware' @@ -170,7 +171,7 @@ export const useTerminalConsoleStore = create()( const newEntry: ConsoleEntry = { ...redactedEntry, - id: crypto.randomUUID(), + id: generateId(), timestamp: new Date().toISOString(), } diff --git a/apps/sim/stores/undo-redo/utils.ts b/apps/sim/stores/undo-redo/utils.ts index d07225b3f54..cc5561a4da1 100644 --- a/apps/sim/stores/undo-redo/utils.ts +++ b/apps/sim/stores/undo-redo/utils.ts @@ -1,3 +1,4 @@ +import { generateId } from '../../lib/utils/uuid' import type { Edge } from 'reactflow' import { UNDO_REDO_OPERATIONS } from '@/socket/constants' import type { @@ -15,7 +16,7 @@ import type { BlockState } from '@/stores/workflows/workflow/types' export function createOperationEntry(operation: Operation, inverse: Operation): OperationEntry { return { - id: crypto.randomUUID(), + id: generateId(), operation, inverse, createdAt: Date.now(), diff --git a/apps/sim/stores/workflows/subblock/store.ts b/apps/sim/stores/workflows/subblock/store.ts index a6bb3bd5722..06249f3c903 100644 --- a/apps/sim/stores/workflows/subblock/store.ts +++ b/apps/sim/stores/workflows/subblock/store.ts @@ -1,3 +1,4 @@ +import { generateId } from '../../../lib/utils/uuid' import { createLogger } from '@sim/logger' import { create } from 'zustand' import { devtools } from 'zustand/middleware' @@ -44,13 +45,13 @@ export const useSubBlockStore = create()( if (!row || typeof row !== 'object') { logger.warn('Fixing malformed table row', { blockId, subBlockId, row }) return { - id: crypto.randomUUID(), + id: generateId(), cells: { Key: '', Value: '' }, } } if (!row.id) { - row.id = crypto.randomUUID() + row.id = generateId() } if (!row.cells || typeof row.cells !== 'object') { diff --git a/apps/sim/stores/workflows/utils.ts b/apps/sim/stores/workflows/utils.ts index e82bfcd7310..3c37bb7c4e2 100644 --- a/apps/sim/stores/workflows/utils.ts +++ b/apps/sim/stores/workflows/utils.ts @@ -1,3 +1,4 @@ +import { generateId } from '../../lib/utils/uuid' import type { Edge } from 'reactflow' import { v4 as uuidv4 } from 'uuid' import { DEFAULT_DUPLICATE_OFFSET } from '@/lib/workflows/autolayout/constants' @@ -172,7 +173,7 @@ export function prepareBlockState(options: PrepareBlockStateOptions): BlockState } else if (subBlock.type === 'input-format' || subBlock.type === 'response-format') { initialValue = [ { - id: crypto.randomUUID(), + id: generateId(), name: '', type: 'string', value: '', diff --git a/apps/sim/stores/workflows/workflow/store.ts b/apps/sim/stores/workflows/workflow/store.ts index bc97773d5cf..de9b1e28aae 100644 --- a/apps/sim/stores/workflows/workflow/store.ts +++ b/apps/sim/stores/workflows/workflow/store.ts @@ -1,3 +1,4 @@ +import { generateId } from '../../../lib/utils/uuid' import { createLogger } from '@sim/logger' import type { Edge } from 'reactflow' import { create } from 'zustand' @@ -80,7 +81,7 @@ function resolveInitialSubblockValue(config: SubBlockConfig): unknown { if (config.type === 'input-format') { return [ { - id: crypto.randomUUID(), + id: generateId(), name: '', type: 'string', value: '', @@ -248,7 +249,7 @@ export const useWorkflowStore = create()( for (const edge of validEdges) { if (!existingEdgeIds.has(edge.id)) { newEdges.push({ - id: edge.id || crypto.randomUUID(), + id: edge.id || generateId(), source: edge.source, target: edge.target, sourceHandle: edge.sourceHandle, @@ -441,7 +442,7 @@ export const useWorkflowStore = create()( for (const edge of filtered) { if (wouldCreateCycle([...newEdges], edge.source, edge.target)) continue newEdges.push({ - id: edge.id || crypto.randomUUID(), + id: edge.id || generateId(), source: edge.source, target: edge.target, sourceHandle: edge.sourceHandle, @@ -566,7 +567,7 @@ export const useWorkflowStore = create()( const block = get().blocks[id] if (!block) return - const newId = crypto.randomUUID() + const newId = generateId() // Check if block is inside a locked container - if so, place duplicate outside const parentId = block.data?.parentId diff --git a/apps/sim/triggers/generic/webhook.ts b/apps/sim/triggers/generic/webhook.ts index d9e0e2ea5fd..6f9b0eb6cce 100644 --- a/apps/sim/triggers/generic/webhook.ts +++ b/apps/sim/triggers/generic/webhook.ts @@ -1,3 +1,4 @@ +import { generateId } from '../../lib/utils/uuid' import { WebhookIcon } from '@/components/icons' import type { TriggerConfig } from '@/triggers/types' @@ -36,7 +37,7 @@ export const genericWebhookTrigger: TriggerConfig = { description: 'Token used to authenticate webhook requests via Bearer token or custom header', password: true, required: false, - value: () => crypto.randomUUID(), + value: () => generateId(), mode: 'trigger', }, { From dc6f3cb1b35c58722cec3401d681be18dd1f8c06 Mon Sep 17 00:00:00 2001 From: guoyangzhen Date: Sat, 14 Mar 2026 19:21:51 +0800 Subject: [PATCH 04/16] fix: ensure 'use client' directive remains first line in Next.js components Fixes the import ordering issue flagged by Cursor Bugbot review. In Next.js, 'use client' must be the very first statement. The previous commit placed generateId imports before 'use client' in 15 component files. Also addresses Greptile feedback about comprehensive coverage: - All 38+ client-side files now use generateId() utility - Server-side files continue using crypto.randomUUID() directly - Shared utility provides automatic fallback for non-secure contexts Fixes #3393 --- apps/sim/app/chat/[identifier]/chat.tsx | 3 ++- apps/sim/app/chat/components/input/input.tsx | 3 ++- apps/sim/app/chat/hooks/use-chat-streaming.ts | 2 +- .../[workspaceId]/providers/global-commands-provider.tsx | 3 ++- .../[workspaceId]/w/[workflowId]/components/chat/chat.tsx | 3 ++- .../components/user-input/hooks/use-file-attachments.ts | 2 +- .../deploy/components/deploy-modal/components/a2a/a2a.tsx | 3 ++- .../components/document-tag-entry/document-tag-entry.tsx | 3 ++- .../sub-block/components/filter-builder/filter-builder.tsx | 3 ++- .../components/knowledge-tag-filters/knowledge-tag-filters.tsx | 3 ++- .../sub-block/components/sort-builder/sort-builder.tsx | 3 ++- .../app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx | 3 ++- .../subscription/components/credit-balance/credit-balance.tsx | 3 ++- apps/sim/app/workspace/providers/socket-provider.tsx | 3 ++- apps/sim/stores/panel/copilot/store.ts | 2 +- 15 files changed, 27 insertions(+), 15 deletions(-) diff --git a/apps/sim/app/chat/[identifier]/chat.tsx b/apps/sim/app/chat/[identifier]/chat.tsx index 7c76d63ab93..1eed6e11ded 100644 --- a/apps/sim/app/chat/[identifier]/chat.tsx +++ b/apps/sim/app/chat/[identifier]/chat.tsx @@ -1,4 +1,5 @@ -import { generateId } from '../../../lib/utils/uuid' +'use client' +import { generateId } from '../../lib/utils/uuid' 'use client' import { type RefObject, useCallback, useEffect, useRef, useState } from 'react' diff --git a/apps/sim/app/chat/components/input/input.tsx b/apps/sim/app/chat/components/input/input.tsx index ec2e32dc4ab..8a7b1b84750 100644 --- a/apps/sim/app/chat/components/input/input.tsx +++ b/apps/sim/app/chat/components/input/input.tsx @@ -1,4 +1,5 @@ -import { generateId } from '../../../../lib/utils/uuid' +'use client' +import { generateId } from '../../lib/utils/uuid' 'use client' import type React from 'react' diff --git a/apps/sim/app/chat/hooks/use-chat-streaming.ts b/apps/sim/app/chat/hooks/use-chat-streaming.ts index 39ccc3655c0..a8882ad16a2 100644 --- a/apps/sim/app/chat/hooks/use-chat-streaming.ts +++ b/apps/sim/app/chat/hooks/use-chat-streaming.ts @@ -1,5 +1,5 @@ -import { generateId } from '../../../lib/utils/uuid' 'use client' +import { generateId } from '../../../lib/utils/uuid' import { useRef, useState } from 'react' import { createLogger } from '@sim/logger' diff --git a/apps/sim/app/workspace/[workspaceId]/providers/global-commands-provider.tsx b/apps/sim/app/workspace/[workspaceId]/providers/global-commands-provider.tsx index bdb19805b0c..865b53482e5 100644 --- a/apps/sim/app/workspace/[workspaceId]/providers/global-commands-provider.tsx +++ b/apps/sim/app/workspace/[workspaceId]/providers/global-commands-provider.tsx @@ -1,4 +1,5 @@ -import { generateId } from '../../../../lib/utils/uuid' +'use client' +import { generateId } from '../../lib/utils/uuid' 'use client' import { diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat.tsx index 7129f370c9b..30a7528798b 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat.tsx @@ -1,4 +1,5 @@ -import { generateId } from '../../../../../../../lib/utils/uuid' +'use client' +import { generateId } from '../../lib/utils/uuid' 'use client' import { type KeyboardEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react' diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-file-attachments.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-file-attachments.ts index 90cad1a63ed..e15b06102d4 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-file-attachments.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-file-attachments.ts @@ -1,5 +1,5 @@ -import { generateId } from '../../../../../../../../../../../../lib/utils/uuid' 'use client' +import { generateId } from '../../../../../../../../../../../../lib/utils/uuid' import { useCallback, useEffect, useRef, useState } from 'react' import { createLogger } from '@sim/logger' diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/a2a/a2a.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/a2a/a2a.tsx index f9633209659..9dc3f66cd98 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/a2a/a2a.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/a2a/a2a.tsx @@ -1,4 +1,5 @@ -import { generateId } from '../../../../../../../../../../../../../lib/utils/uuid' +'use client' +import { generateId } from '../../lib/utils/uuid' 'use client' import { useCallback, useEffect, useMemo, useState } from 'react' diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/document-tag-entry/document-tag-entry.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/document-tag-entry/document-tag-entry.tsx index 3c098548a95..cc44f14549f 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/document-tag-entry/document-tag-entry.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/document-tag-entry/document-tag-entry.tsx @@ -1,4 +1,5 @@ -import { generateId } from '../../../../../../../../../../../../../lib/utils/uuid' +'use client' +import { generateId } from '../../lib/utils/uuid' 'use client' import { useMemo, useRef } from 'react' diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/filter-builder/filter-builder.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/filter-builder/filter-builder.tsx index 9ecce2ad101..67319eb901e 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/filter-builder/filter-builder.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/filter-builder/filter-builder.tsx @@ -1,4 +1,5 @@ -import { generateId } from '../../../../../../../../../../../../../lib/utils/uuid' +'use client' +import { generateId } from '../../lib/utils/uuid' 'use client' import { useCallback, useMemo } from 'react' diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/knowledge-tag-filters/knowledge-tag-filters.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/knowledge-tag-filters/knowledge-tag-filters.tsx index a43f387f084..803b560510d 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/knowledge-tag-filters/knowledge-tag-filters.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/knowledge-tag-filters/knowledge-tag-filters.tsx @@ -1,4 +1,5 @@ -import { generateId } from '../../../../../../../../../../../../../lib/utils/uuid' +'use client' +import { generateId } from '../../lib/utils/uuid' 'use client' import { useRef } from 'react' diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/sort-builder/sort-builder.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/sort-builder/sort-builder.tsx index 921bc007e35..247b4734a2c 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/sort-builder/sort-builder.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/sort-builder/sort-builder.tsx @@ -1,4 +1,5 @@ -import { generateId } from '../../../../../../../../../../../../../lib/utils/uuid' +'use client' +import { generateId } from '../../lib/utils/uuid' 'use client' import { useCallback, useMemo } from 'react' diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx index f99d67bbeab..d64fa711510 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx @@ -1,4 +1,5 @@ -import { generateId } from '../../../../../lib/utils/uuid' +'use client' +import { generateId } from '../../lib/utils/uuid' 'use client' import React, { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState } from 'react' diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/subscription/components/credit-balance/credit-balance.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/subscription/components/credit-balance/credit-balance.tsx index 5fad9320ea7..579cd562518 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/subscription/components/credit-balance/credit-balance.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/subscription/components/credit-balance/credit-balance.tsx @@ -1,4 +1,5 @@ -import { generateId } from '../../../../../../../../../../../../lib/utils/uuid' +'use client' +import { generateId } from '../../lib/utils/uuid' 'use client' import { useState } from 'react' diff --git a/apps/sim/app/workspace/providers/socket-provider.tsx b/apps/sim/app/workspace/providers/socket-provider.tsx index 8cba96f6bcc..02aff7ce826 100644 --- a/apps/sim/app/workspace/providers/socket-provider.tsx +++ b/apps/sim/app/workspace/providers/socket-provider.tsx @@ -1,4 +1,5 @@ -import { generateId } from '../../../lib/utils/uuid' +'use client' +import { generateId } from '../../lib/utils/uuid' 'use client' import { diff --git a/apps/sim/stores/panel/copilot/store.ts b/apps/sim/stores/panel/copilot/store.ts index 74877467b79..6f44268511e 100644 --- a/apps/sim/stores/panel/copilot/store.ts +++ b/apps/sim/stores/panel/copilot/store.ts @@ -1,5 +1,5 @@ -import { generateId } from '../../../lib/utils/uuid' 'use client' +import { generateId } from '../../../lib/utils/uuid' import { createLogger } from '@sim/logger' import { create } from 'zustand' From 44761a63169bc1efadfcbd9e35cb3e31dae57823 Mon Sep 17 00:00:00 2001 From: guoyangzhen Date: Sat, 14 Mar 2026 21:02:30 +0800 Subject: [PATCH 05/16] fix: remove duplicate 'use client' and fix import ordering --- apps/sim/app/chat/[identifier]/chat.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/sim/app/chat/[identifier]/chat.tsx b/apps/sim/app/chat/[identifier]/chat.tsx index 1eed6e11ded..e19e4295fd0 100644 --- a/apps/sim/app/chat/[identifier]/chat.tsx +++ b/apps/sim/app/chat/[identifier]/chat.tsx @@ -1,6 +1,5 @@ 'use client' import { generateId } from '../../lib/utils/uuid' -'use client' import { type RefObject, useCallback, useEffect, useRef, useState } from 'react' import { createLogger } from '@sim/logger' From 49233a610c9b33d80ebe5bc6e6f92bb973713895 Mon Sep 17 00:00:00 2001 From: guoyangzhen Date: Sat, 14 Mar 2026 21:02:33 +0800 Subject: [PATCH 06/16] fix: remove duplicate 'use client' and fix import ordering --- apps/sim/app/chat/components/input/input.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/sim/app/chat/components/input/input.tsx b/apps/sim/app/chat/components/input/input.tsx index 8a7b1b84750..f663b164ecf 100644 --- a/apps/sim/app/chat/components/input/input.tsx +++ b/apps/sim/app/chat/components/input/input.tsx @@ -1,6 +1,5 @@ 'use client' import { generateId } from '../../lib/utils/uuid' -'use client' import type React from 'react' import { useEffect, useRef, useState } from 'react' From bb773f83b877a7694491f9331d7c5337f18122ac Mon Sep 17 00:00:00 2001 From: guoyangzhen Date: Sat, 14 Mar 2026 21:02:35 +0800 Subject: [PATCH 07/16] fix: remove duplicate 'use client' and fix import ordering --- .../[workspaceId]/providers/global-commands-provider.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/sim/app/workspace/[workspaceId]/providers/global-commands-provider.tsx b/apps/sim/app/workspace/[workspaceId]/providers/global-commands-provider.tsx index 865b53482e5..171930956e1 100644 --- a/apps/sim/app/workspace/[workspaceId]/providers/global-commands-provider.tsx +++ b/apps/sim/app/workspace/[workspaceId]/providers/global-commands-provider.tsx @@ -1,6 +1,5 @@ 'use client' import { generateId } from '../../lib/utils/uuid' -'use client' import { createContext, From 425a3b9bb94cee33e3814c57e2b8d8a193248199 Mon Sep 17 00:00:00 2001 From: guoyangzhen Date: Sat, 14 Mar 2026 21:02:38 +0800 Subject: [PATCH 08/16] fix: remove duplicate 'use client' and fix import ordering --- .../[workspaceId]/w/[workflowId]/components/chat/chat.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat.tsx index 30a7528798b..5e1e85e2e65 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat.tsx @@ -1,6 +1,5 @@ 'use client' import { generateId } from '../../lib/utils/uuid' -'use client' import { type KeyboardEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react' import { createLogger } from '@sim/logger' From ccbbfdcec04b0f2ed872088c5486ad0016d554c0 Mon Sep 17 00:00:00 2001 From: guoyangzhen Date: Sat, 14 Mar 2026 21:02:41 +0800 Subject: [PATCH 09/16] fix: remove duplicate 'use client' and fix import ordering --- .../deploy/components/deploy-modal/components/a2a/a2a.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/a2a/a2a.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/a2a/a2a.tsx index 9dc3f66cd98..1c907ee0ef9 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/a2a/a2a.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/a2a/a2a.tsx @@ -1,6 +1,5 @@ 'use client' import { generateId } from '../../lib/utils/uuid' -'use client' import { useCallback, useEffect, useMemo, useState } from 'react' import { createLogger } from '@sim/logger' From e467d586549a10899721b9e9fda581257563fb22 Mon Sep 17 00:00:00 2001 From: guoyangzhen Date: Sat, 14 Mar 2026 21:02:43 +0800 Subject: [PATCH 10/16] fix: remove duplicate 'use client' and fix import ordering --- .../components/document-tag-entry/document-tag-entry.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/document-tag-entry/document-tag-entry.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/document-tag-entry/document-tag-entry.tsx index cc44f14549f..362c311124c 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/document-tag-entry/document-tag-entry.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/document-tag-entry/document-tag-entry.tsx @@ -1,6 +1,5 @@ 'use client' import { generateId } from '../../lib/utils/uuid' -'use client' import { useMemo, useRef } from 'react' import { Plus } from 'lucide-react' From ae08cdaa8970491a51b571c415be10426a82bded Mon Sep 17 00:00:00 2001 From: guoyangzhen Date: Sat, 14 Mar 2026 21:02:44 +0800 Subject: [PATCH 11/16] fix: remove duplicate 'use client' and fix import ordering --- .../sub-block/components/filter-builder/filter-builder.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/filter-builder/filter-builder.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/filter-builder/filter-builder.tsx index 67319eb901e..e5df6ac1545 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/filter-builder/filter-builder.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/filter-builder/filter-builder.tsx @@ -1,6 +1,5 @@ 'use client' import { generateId } from '../../lib/utils/uuid' -'use client' import { useCallback, useMemo } from 'react' import type { ComboboxOption } from '@/components/emcn' From bf99af99be08dff6410117f2a78c0e3dd8a6d4db Mon Sep 17 00:00:00 2001 From: guoyangzhen Date: Sat, 14 Mar 2026 21:02:47 +0800 Subject: [PATCH 12/16] fix: remove duplicate 'use client' and fix import ordering --- .../components/knowledge-tag-filters/knowledge-tag-filters.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/knowledge-tag-filters/knowledge-tag-filters.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/knowledge-tag-filters/knowledge-tag-filters.tsx index 803b560510d..608ead34d96 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/knowledge-tag-filters/knowledge-tag-filters.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/knowledge-tag-filters/knowledge-tag-filters.tsx @@ -1,6 +1,5 @@ 'use client' import { generateId } from '../../lib/utils/uuid' -'use client' import { useRef } from 'react' import { Plus } from 'lucide-react' From c21dfc099df6f95de1ff962150fc00691ce1ec9a Mon Sep 17 00:00:00 2001 From: guoyangzhen Date: Sat, 14 Mar 2026 21:02:48 +0800 Subject: [PATCH 13/16] fix: remove duplicate 'use client' and fix import ordering --- .../sub-block/components/sort-builder/sort-builder.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/sort-builder/sort-builder.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/sort-builder/sort-builder.tsx index 247b4734a2c..b0899b00d4a 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/sort-builder/sort-builder.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/sort-builder/sort-builder.tsx @@ -1,6 +1,5 @@ 'use client' import { generateId } from '../../lib/utils/uuid' -'use client' import { useCallback, useMemo } from 'react' import type { ComboboxOption } from '@/components/emcn' From 541fc1c37f8e61910f1957718117f48bfda29e08 Mon Sep 17 00:00:00 2001 From: guoyangzhen Date: Sat, 14 Mar 2026 21:02:52 +0800 Subject: [PATCH 14/16] fix: remove duplicate 'use client' and fix import ordering --- apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx index d64fa711510..6b3e3540d69 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx @@ -1,6 +1,5 @@ 'use client' import { generateId } from '../../lib/utils/uuid' -'use client' import React, { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useParams, useRouter } from 'next/navigation' From 608a0a45ef69f20c20cf73bf9508842b020f969f Mon Sep 17 00:00:00 2001 From: guoyangzhen Date: Sat, 14 Mar 2026 21:02:54 +0800 Subject: [PATCH 15/16] fix: remove duplicate 'use client' and fix import ordering --- .../subscription/components/credit-balance/credit-balance.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/subscription/components/credit-balance/credit-balance.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/subscription/components/credit-balance/credit-balance.tsx index 579cd562518..1f266f3bf69 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/subscription/components/credit-balance/credit-balance.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/subscription/components/credit-balance/credit-balance.tsx @@ -1,6 +1,5 @@ 'use client' import { generateId } from '../../lib/utils/uuid' -'use client' import { useState } from 'react' import { createLogger } from '@sim/logger' From 08013986a8d48072ff29b865c412285ca6584c9e Mon Sep 17 00:00:00 2001 From: guoyangzhen Date: Sat, 14 Mar 2026 21:02:56 +0800 Subject: [PATCH 16/16] fix: remove duplicate 'use client' and fix import ordering --- apps/sim/app/workspace/providers/socket-provider.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/sim/app/workspace/providers/socket-provider.tsx b/apps/sim/app/workspace/providers/socket-provider.tsx index 02aff7ce826..581e5d95071 100644 --- a/apps/sim/app/workspace/providers/socket-provider.tsx +++ b/apps/sim/app/workspace/providers/socket-provider.tsx @@ -1,6 +1,5 @@ 'use client' import { generateId } from '../../lib/utils/uuid' -'use client' import { createContext,