Skip to content

Commit af92b53

Browse files
committed
fix: replace crypto.randomUUID with universal generateId utility (#3393)
Replace all direct crypto.randomUUID() calls with a generateId() helper that falls back to the uuid package when crypto.randomUUID is unavailable. crypto.randomUUID() is only available in secure contexts (HTTPS or localhost). When Sim is self-hosted via Docker and accessed over plain HTTP on a LAN, the call throws "crypto.randomUUID is not a function" and the page white-screens. Changes: - Add generateId() utility in lib/core/utils/id.ts that tries crypto.randomUUID() first, then falls back to uuid v4 (already a dependency) - Replace all 200+ crypto.randomUUID() calls across 117 files - Keep the existing layout.tsx polyfill as defense-in-depth for third-party code - Add mockGenerateId() to the testing package for test consistency > **AI Disclosure:** This PR was authored by an AI agent (Claude, Anthropic). > All code changes, analysis, and PR description were generated autonomously. > A human (Max Calkin, @MaxwellCalkin) provided the prompt and submitted this PR. Closes #3393
1 parent 8c0a2e0 commit af92b53

File tree

119 files changed

+456
-298
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

119 files changed

+456
-298
lines changed

apps/sim/app/api/auth/shopify/authorize/route.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server'
33
import { getSession } from '@/lib/auth'
44
import { env } from '@/lib/core/config/env'
55
import { getBaseUrl } from '@/lib/core/utils/urls'
6+
import { generateId } from '@/lib/core/utils/id'
67

78
const logger = createLogger('ShopifyAuthorize')
89

@@ -161,7 +162,7 @@ export async function GET(request: NextRequest) {
161162
const baseUrl = getBaseUrl()
162163
const redirectUri = `${baseUrl}/api/auth/oauth2/callback/shopify`
163164

164-
const state = crypto.randomUUID()
165+
const state = generateId()
165166

166167
const oauthUrl =
167168
`https://${cleanShop}/admin/oauth/authorize?` +

apps/sim/app/api/copilot/chat/route.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
} from '@/lib/copilot/request-helpers'
2626
import { env } from '@/lib/core/config/env'
2727
import { resolveWorkflowIdForUser } from '@/lib/workflows/utils'
28+
import { generateId } from '@/lib/core/utils/id'
2829

2930
const logger = createLogger('CopilotChatAPI')
3031

@@ -188,7 +189,7 @@ export async function POST(req: NextRequest) {
188189
const workflowId = resolved.workflowId
189190

190191
// Ensure we have a consistent user message ID for this request
191-
const userMessageIdToUse = userMessageId || crypto.randomUUID()
192+
const userMessageIdToUse = userMessageId || generateId()
192193
try {
193194
logger.info(`[${tracker.requestId}] Received chat POST`, {
194195
hasContexts: Array.isArray(normalizedContexts),
@@ -474,7 +475,7 @@ export async function POST(req: NextRequest) {
474475
}
475476

476477
const assistantMessage = {
477-
id: crypto.randomUUID(),
478+
id: generateId(),
478479
role: 'assistant',
479480
content: responseData.content,
480481
timestamp: new Date().toISOString(),

apps/sim/app/api/credential-sets/[id]/invite/route.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { getSession } from '@/lib/auth'
1010
import { hasCredentialSetsAccess } from '@/lib/billing'
1111
import { getBaseUrl } from '@/lib/core/utils/urls'
1212
import { sendEmail } from '@/lib/messaging/email/mailer'
13+
import { generateId } from '@/lib/core/utils/id'
1314

1415
const logger = createLogger('CredentialSetInvite')
1516

@@ -105,12 +106,12 @@ export async function POST(req: NextRequest, { params }: { params: Promise<{ id:
105106
const body = await req.json()
106107
const { email } = createInviteSchema.parse(body)
107108

108-
const token = crypto.randomUUID()
109+
const token = generateId()
109110
const expiresAt = new Date()
110111
expiresAt.setDate(expiresAt.getDate() + 7)
111112

112113
const invitation = {
113-
id: crypto.randomUUID(),
114+
id: generateId(),
114115
credentialSetId: id,
115116
email: email || null,
116117
token,

apps/sim/app/api/credential-sets/[id]/members/route.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log'
77
import { getSession } from '@/lib/auth'
88
import { hasCredentialSetsAccess } from '@/lib/billing'
99
import { syncAllWebhooksForCredentialSet } from '@/lib/webhooks/utils.server'
10+
import { generateId } from '@/lib/core/utils/id'
1011

1112
const logger = createLogger('CredentialSetMembers')
1213

@@ -167,7 +168,7 @@ export async function DELETE(req: NextRequest, { params }: { params: Promise<{ i
167168
return NextResponse.json({ error: 'Member not found' }, { status: 404 })
168169
}
169170

170-
const requestId = crypto.randomUUID().slice(0, 8)
171+
const requestId = generateId().slice(0, 8)
171172

172173
// Use transaction to ensure member deletion + webhook sync are atomic
173174
await db.transaction(async (tx) => {

apps/sim/app/api/credential-sets/invite/[token]/route.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { type NextRequest, NextResponse } from 'next/server'
1111
import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log'
1212
import { getSession } from '@/lib/auth'
1313
import { syncAllWebhooksForCredentialSet } from '@/lib/webhooks/utils.server'
14+
import { generateId } from '@/lib/core/utils/id'
1415

1516
const logger = createLogger('CredentialSetInviteToken')
1617

@@ -125,11 +126,11 @@ export async function POST(req: NextRequest, { params }: { params: Promise<{ tok
125126
}
126127

127128
const now = new Date()
128-
const requestId = crypto.randomUUID().slice(0, 8)
129+
const requestId = generateId().slice(0, 8)
129130

130131
await db.transaction(async (tx) => {
131132
await tx.insert(credentialSetMember).values({
132-
id: crypto.randomUUID(),
133+
id: generateId(),
133134
credentialSetId: invitation.credentialSetId,
134135
userId: session.user.id,
135136
status: 'active',

apps/sim/app/api/credential-sets/memberships/route.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { type NextRequest, NextResponse } from 'next/server'
66
import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log'
77
import { getSession } from '@/lib/auth'
88
import { syncAllWebhooksForCredentialSet } from '@/lib/webhooks/utils.server'
9+
import { generateId } from '@/lib/core/utils/id'
910

1011
const logger = createLogger('CredentialSetMemberships')
1112

@@ -60,7 +61,7 @@ export async function DELETE(req: NextRequest) {
6061
}
6162

6263
try {
63-
const requestId = crypto.randomUUID().slice(0, 8)
64+
const requestId = generateId().slice(0, 8)
6465

6566
// Use transaction to ensure revocation + webhook sync are atomic
6667
await db.transaction(async (tx) => {

apps/sim/app/api/credential-sets/route.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { z } from 'zod'
77
import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log'
88
import { getSession } from '@/lib/auth'
99
import { hasCredentialSetsAccess } from '@/lib/billing'
10+
import { generateId } from '@/lib/core/utils/id'
1011

1112
const logger = createLogger('CredentialSets')
1213

@@ -148,7 +149,7 @@ export async function POST(req: Request) {
148149

149150
const now = new Date()
150151
const newCredentialSet = {
151-
id: crypto.randomUUID(),
152+
id: generateId(),
152153
organizationId,
153154
name,
154155
description: description || null,

apps/sim/app/api/credentials/[id]/members/route.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { type NextRequest, NextResponse } from 'next/server'
66
import { z } from 'zod'
77
import { getSession } from '@/lib/auth'
88
import { getUserEntityPermissions } from '@/lib/workspaces/permissions/utils'
9+
import { generateId } from '@/lib/core/utils/id'
910

1011
const logger = createLogger('CredentialMembersAPI')
1112

@@ -133,7 +134,7 @@ export async function POST(request: NextRequest, context: RouteContext) {
133134
}
134135

135136
await db.insert(credentialMember).values({
136-
id: crypto.randomUUID(),
137+
id: generateId(),
137138
credentialId,
138139
userId,
139140
role,

apps/sim/app/api/credentials/[id]/route.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { z } from 'zod'
77
import { getSession } from '@/lib/auth'
88
import { getCredentialActorContext } from '@/lib/credentials/access'
99
import {
10+
import { generateId } from '@/lib/core/utils/id'
1011
syncPersonalEnvCredentialsForUser,
1112
syncWorkspaceEnvCredentials,
1213
} from '@/lib/credentials/environment'
@@ -222,7 +223,7 @@ export async function DELETE(
222223
await db
223224
.insert(workspaceEnvironment)
224225
.values({
225-
id: workspaceRow?.id || crypto.randomUUID(),
226+
id: workspaceRow?.id || generateId(),
226227
workspaceId: access.credential.workspaceId,
227228
variables: current,
228229
createdAt: workspaceRow?.createdAt || new Date(),

apps/sim/app/api/credentials/draft/route.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { NextResponse } from 'next/server'
66
import { z } from 'zod'
77
import { getSession } from '@/lib/auth'
88
import { checkWorkspaceAccess } from '@/lib/workspaces/permissions/utils'
9+
import { generateId } from '@/lib/core/utils/id'
910

1011
const logger = createLogger('CredentialDraftAPI')
1112

@@ -75,7 +76,7 @@ export async function POST(request: Request) {
7576
await db
7677
.insert(pendingCredentialDraft)
7778
.values({
78-
id: crypto.randomUUID(),
79+
id: generateId(),
7980
userId,
8081
workspaceId,
8182
providerId,

0 commit comments

Comments
 (0)