Skip to content

Commit dd1985c

Browse files
authored
improvement(chat): deployed chat no longer uses subdomains, uses sim.ai/chat/[identifier] (#1474)
* improvement(chat): deployed chat no longer uses subdomains, uses sim.ai/chat/[identifier] * ui fix * added back validate route, remove backwards compatibility for subdomain redirects * cleanup * cleanup * add chat page to conditional theme layout, and remove custom chat css * consolidate theme providers * ack pr commnets --------- Co-authored-by: waleed <waleed>
1 parent 39356f3 commit dd1985c

File tree

36 files changed

+7297
-929
lines changed

36 files changed

+7297
-929
lines changed

apps/sim/app/api/chat/[subdomain]/otp/route.ts renamed to apps/sim/app/api/chat/[identifier]/otp/route.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,13 @@ const otpVerifySchema = z.object({
113113
// Send OTP endpoint
114114
export async function POST(
115115
request: NextRequest,
116-
{ params }: { params: Promise<{ subdomain: string }> }
116+
{ params }: { params: Promise<{ identifier: string }> }
117117
) {
118-
const { subdomain } = await params
118+
const { identifier } = await params
119119
const requestId = generateRequestId()
120120

121121
try {
122-
logger.debug(`[${requestId}] Processing OTP request for subdomain: ${subdomain}`)
122+
logger.debug(`[${requestId}] Processing OTP request for identifier: ${identifier}`)
123123

124124
// Parse request body
125125
let body
@@ -136,11 +136,11 @@ export async function POST(
136136
title: chat.title,
137137
})
138138
.from(chat)
139-
.where(eq(chat.subdomain, subdomain))
139+
.where(eq(chat.identifier, identifier))
140140
.limit(1)
141141

142142
if (deploymentResult.length === 0) {
143-
logger.warn(`[${requestId}] Chat not found for subdomain: ${subdomain}`)
143+
logger.warn(`[${requestId}] Chat not found for identifier: ${identifier}`)
144144
return addCorsHeaders(createErrorResponse('Chat not found', 404), request)
145145
}
146146

@@ -227,13 +227,13 @@ export async function POST(
227227
// Verify OTP endpoint
228228
export async function PUT(
229229
request: NextRequest,
230-
{ params }: { params: Promise<{ subdomain: string }> }
230+
{ params }: { params: Promise<{ identifier: string }> }
231231
) {
232-
const { subdomain } = await params
232+
const { identifier } = await params
233233
const requestId = generateRequestId()
234234

235235
try {
236-
logger.debug(`[${requestId}] Verifying OTP for subdomain: ${subdomain}`)
236+
logger.debug(`[${requestId}] Verifying OTP for identifier: ${identifier}`)
237237

238238
// Parse request body
239239
let body
@@ -248,11 +248,11 @@ export async function PUT(
248248
authType: chat.authType,
249249
})
250250
.from(chat)
251-
.where(eq(chat.subdomain, subdomain))
251+
.where(eq(chat.identifier, identifier))
252252
.limit(1)
253253

254254
if (deploymentResult.length === 0) {
255-
logger.warn(`[${requestId}] Chat not found for subdomain: ${subdomain}`)
255+
logger.warn(`[${requestId}] Chat not found for identifier: ${identifier}`)
256256
return addCorsHeaders(createErrorResponse('Chat not found', 404), request)
257257
}
258258

apps/sim/app/api/chat/[subdomain]/route.test.ts renamed to apps/sim/app/api/chat/[identifier]/route.test.ts

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
/**
2-
* Tests for chat subdomain API route
2+
* Tests for chat identifier API route
33
*
44
* @vitest-environment node
55
*/
66
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
77
import { createMockRequest } from '@/app/api/__test-utils__/utils'
88

9-
describe('Chat Subdomain API Route', () => {
9+
describe('Chat Identifier API Route', () => {
1010
const createMockStream = () => {
1111
return new ReadableStream({
1212
start(controller) {
@@ -134,11 +134,11 @@ describe('Chat Subdomain API Route', () => {
134134
})
135135

136136
describe('GET endpoint', () => {
137-
it('should return chat info for a valid subdomain', async () => {
137+
it('should return chat info for a valid identifier', async () => {
138138
const req = createMockRequest('GET')
139-
const params = Promise.resolve({ subdomain: 'test-chat' })
139+
const params = Promise.resolve({ identifier: 'test-chat' })
140140

141-
const { GET } = await import('@/app/api/chat/[subdomain]/route')
141+
const { GET } = await import('@/app/api/chat/[identifier]/route')
142142

143143
const response = await GET(req, { params })
144144

@@ -152,7 +152,7 @@ describe('Chat Subdomain API Route', () => {
152152
expect(data.customizations).toHaveProperty('welcomeMessage', 'Welcome to the test chat')
153153
})
154154

155-
it('should return 404 for non-existent subdomain', async () => {
155+
it('should return 404 for non-existent identifier', async () => {
156156
vi.doMock('@sim/db', () => {
157157
const mockLimit = vi.fn().mockReturnValue([])
158158
const mockWhere = vi.fn().mockReturnValue({ limit: mockLimit })
@@ -167,9 +167,9 @@ describe('Chat Subdomain API Route', () => {
167167
})
168168

169169
const req = createMockRequest('GET')
170-
const params = Promise.resolve({ subdomain: 'nonexistent' })
170+
const params = Promise.resolve({ identifier: 'nonexistent' })
171171

172-
const { GET } = await import('@/app/api/chat/[subdomain]/route')
172+
const { GET } = await import('@/app/api/chat/[identifier]/route')
173173

174174
const response = await GET(req, { params })
175175

@@ -201,9 +201,9 @@ describe('Chat Subdomain API Route', () => {
201201
})
202202

203203
const req = createMockRequest('GET')
204-
const params = Promise.resolve({ subdomain: 'inactive-chat' })
204+
const params = Promise.resolve({ identifier: 'inactive-chat' })
205205

206-
const { GET } = await import('@/app/api/chat/[subdomain]/route')
206+
const { GET } = await import('@/app/api/chat/[identifier]/route')
207207

208208
const response = await GET(req, { params })
209209

@@ -222,9 +222,9 @@ describe('Chat Subdomain API Route', () => {
222222
}))
223223

224224
const req = createMockRequest('GET')
225-
const params = Promise.resolve({ subdomain: 'password-protected-chat' })
225+
const params = Promise.resolve({ identifier: 'password-protected-chat' })
226226

227-
const { GET } = await import('@/app/api/chat/[subdomain]/route')
227+
const { GET } = await import('@/app/api/chat/[identifier]/route')
228228

229229
const response = await GET(req, { params })
230230

@@ -243,9 +243,9 @@ describe('Chat Subdomain API Route', () => {
243243
describe('POST endpoint', () => {
244244
it('should handle authentication requests without input', async () => {
245245
const req = createMockRequest('POST', { password: 'test-password' })
246-
const params = Promise.resolve({ subdomain: 'password-protected-chat' })
246+
const params = Promise.resolve({ identifier: 'password-protected-chat' })
247247

248-
const { POST } = await import('@/app/api/chat/[subdomain]/route')
248+
const { POST } = await import('@/app/api/chat/[identifier]/route')
249249

250250
const response = await POST(req, { params })
251251

@@ -259,9 +259,9 @@ describe('Chat Subdomain API Route', () => {
259259

260260
it('should return 400 for requests without input', async () => {
261261
const req = createMockRequest('POST', {})
262-
const params = Promise.resolve({ subdomain: 'test-chat' })
262+
const params = Promise.resolve({ identifier: 'test-chat' })
263263

264-
const { POST } = await import('@/app/api/chat/[subdomain]/route')
264+
const { POST } = await import('@/app/api/chat/[identifier]/route')
265265

266266
const response = await POST(req, { params })
267267

@@ -280,9 +280,9 @@ describe('Chat Subdomain API Route', () => {
280280
}))
281281

282282
const req = createMockRequest('POST', { input: 'Hello' })
283-
const params = Promise.resolve({ subdomain: 'protected-chat' })
283+
const params = Promise.resolve({ identifier: 'protected-chat' })
284284

285-
const { POST } = await import('@/app/api/chat/[subdomain]/route')
285+
const { POST } = await import('@/app/api/chat/[identifier]/route')
286286

287287
const response = await POST(req, { params })
288288

@@ -343,9 +343,9 @@ describe('Chat Subdomain API Route', () => {
343343
})
344344

345345
const req = createMockRequest('POST', { input: 'Hello' })
346-
const params = Promise.resolve({ subdomain: 'test-chat' })
346+
const params = Promise.resolve({ identifier: 'test-chat' })
347347

348-
const { POST } = await import('@/app/api/chat/[subdomain]/route')
348+
const { POST } = await import('@/app/api/chat/[identifier]/route')
349349

350350
const response = await POST(req, { params })
351351

@@ -358,9 +358,9 @@ describe('Chat Subdomain API Route', () => {
358358

359359
it('should return streaming response for valid chat messages', async () => {
360360
const req = createMockRequest('POST', { input: 'Hello world', conversationId: 'conv-123' })
361-
const params = Promise.resolve({ subdomain: 'test-chat' })
361+
const params = Promise.resolve({ identifier: 'test-chat' })
362362

363-
const { POST } = await import('@/app/api/chat/[subdomain]/route')
363+
const { POST } = await import('@/app/api/chat/[identifier]/route')
364364

365365
const response = await POST(req, { params })
366366

@@ -375,9 +375,9 @@ describe('Chat Subdomain API Route', () => {
375375

376376
it('should handle streaming response body correctly', async () => {
377377
const req = createMockRequest('POST', { input: 'Hello world' })
378-
const params = Promise.resolve({ subdomain: 'test-chat' })
378+
const params = Promise.resolve({ identifier: 'test-chat' })
379379

380-
const { POST } = await import('@/app/api/chat/[subdomain]/route')
380+
const { POST } = await import('@/app/api/chat/[identifier]/route')
381381

382382
const response = await POST(req, { params })
383383

@@ -405,9 +405,9 @@ describe('Chat Subdomain API Route', () => {
405405
})
406406

407407
const req = createMockRequest('POST', { input: 'Trigger error' })
408-
const params = Promise.resolve({ subdomain: 'test-chat' })
408+
const params = Promise.resolve({ identifier: 'test-chat' })
409409

410-
const { POST } = await import('@/app/api/chat/[subdomain]/route')
410+
const { POST } = await import('@/app/api/chat/[identifier]/route')
411411

412412
const response = await POST(req, { params })
413413

@@ -430,9 +430,9 @@ describe('Chat Subdomain API Route', () => {
430430
json: vi.fn().mockRejectedValue(new Error('Invalid JSON')),
431431
} as any
432432

433-
const params = Promise.resolve({ subdomain: 'test-chat' })
433+
const params = Promise.resolve({ identifier: 'test-chat' })
434434

435-
const { POST } = await import('@/app/api/chat/[subdomain]/route')
435+
const { POST } = await import('@/app/api/chat/[identifier]/route')
436436

437437
const response = await POST(req, { params })
438438

@@ -448,9 +448,9 @@ describe('Chat Subdomain API Route', () => {
448448
input: 'Hello world',
449449
conversationId: 'test-conversation-123',
450450
})
451-
const params = Promise.resolve({ subdomain: 'test-chat' })
451+
const params = Promise.resolve({ identifier: 'test-chat' })
452452

453-
const { POST } = await import('@/app/api/chat/[subdomain]/route')
453+
const { POST } = await import('@/app/api/chat/[identifier]/route')
454454

455455
await POST(req, { params })
456456

@@ -463,9 +463,9 @@ describe('Chat Subdomain API Route', () => {
463463

464464
it('should handle missing conversationId gracefully', async () => {
465465
const req = createMockRequest('POST', { input: 'Hello world' })
466-
const params = Promise.resolve({ subdomain: 'test-chat' })
466+
const params = Promise.resolve({ identifier: 'test-chat' })
467467

468-
const { POST } = await import('@/app/api/chat/[subdomain]/route')
468+
const { POST } = await import('@/app/api/chat/[identifier]/route')
469469

470470
await POST(req, { params })
471471

apps/sim/app/api/chat/[subdomain]/route.ts renamed to apps/sim/app/api/chat/[identifier]/route.ts

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,18 @@ import {
1313
} from '@/app/api/chat/utils'
1414
import { createErrorResponse, createSuccessResponse } from '@/app/api/workflows/utils'
1515

16-
const logger = createLogger('ChatSubdomainAPI')
16+
const logger = createLogger('ChatIdentifierAPI')
1717

18-
// This endpoint handles chat interactions via the subdomain
18+
// This endpoint handles chat interactions via the identifier
1919
export async function POST(
2020
request: NextRequest,
21-
{ params }: { params: Promise<{ subdomain: string }> }
21+
{ params }: { params: Promise<{ identifier: string }> }
2222
) {
23-
const { subdomain } = await params
23+
const { identifier } = await params
2424
const requestId = generateRequestId()
2525

2626
try {
27-
logger.debug(`[${requestId}] Processing chat request for subdomain: ${subdomain}`)
27+
logger.debug(`[${requestId}] Processing chat request for identifier: ${identifier}`)
2828

2929
// Parse the request body once
3030
let parsedBody
@@ -34,7 +34,7 @@ export async function POST(
3434
return addCorsHeaders(createErrorResponse('Invalid request body', 400), request)
3535
}
3636

37-
// Find the chat deployment for this subdomain
37+
// Find the chat deployment for this identifier
3838
const deploymentResult = await db
3939
.select({
4040
id: chat.id,
@@ -47,19 +47,19 @@ export async function POST(
4747
outputConfigs: chat.outputConfigs,
4848
})
4949
.from(chat)
50-
.where(eq(chat.subdomain, subdomain))
50+
.where(eq(chat.identifier, identifier))
5151
.limit(1)
5252

5353
if (deploymentResult.length === 0) {
54-
logger.warn(`[${requestId}] Chat not found for subdomain: ${subdomain}`)
54+
logger.warn(`[${requestId}] Chat not found for identifier: ${identifier}`)
5555
return addCorsHeaders(createErrorResponse('Chat not found', 404), request)
5656
}
5757

5858
const deployment = deploymentResult[0]
5959

6060
// Check if the chat is active
6161
if (!deployment.isActive) {
62-
logger.warn(`[${requestId}] Chat is not active: ${subdomain}`)
62+
logger.warn(`[${requestId}] Chat is not active: ${identifier}`)
6363
return addCorsHeaders(createErrorResponse('This chat is currently unavailable', 403), request)
6464
}
6565

@@ -139,15 +139,15 @@ export async function POST(
139139
// This endpoint returns information about the chat
140140
export async function GET(
141141
request: NextRequest,
142-
{ params }: { params: Promise<{ subdomain: string }> }
142+
{ params }: { params: Promise<{ identifier: string }> }
143143
) {
144-
const { subdomain } = await params
144+
const { identifier } = await params
145145
const requestId = generateRequestId()
146146

147147
try {
148-
logger.debug(`[${requestId}] Fetching chat info for subdomain: ${subdomain}`)
148+
logger.debug(`[${requestId}] Fetching chat info for identifier: ${identifier}`)
149149

150-
// Find the chat deployment for this subdomain
150+
// Find the chat deployment for this identifier
151151
const deploymentResult = await db
152152
.select({
153153
id: chat.id,
@@ -162,19 +162,19 @@ export async function GET(
162162
outputConfigs: chat.outputConfigs,
163163
})
164164
.from(chat)
165-
.where(eq(chat.subdomain, subdomain))
165+
.where(eq(chat.identifier, identifier))
166166
.limit(1)
167167

168168
if (deploymentResult.length === 0) {
169-
logger.warn(`[${requestId}] Chat not found for subdomain: ${subdomain}`)
169+
logger.warn(`[${requestId}] Chat not found for identifier: ${identifier}`)
170170
return addCorsHeaders(createErrorResponse('Chat not found', 404), request)
171171
}
172172

173173
const deployment = deploymentResult[0]
174174

175175
// Check if the chat is active
176176
if (!deployment.isActive) {
177-
logger.warn(`[${requestId}] Chat is not active: ${subdomain}`)
177+
logger.warn(`[${requestId}] Chat is not active: ${identifier}`)
178178
return addCorsHeaders(createErrorResponse('This chat is currently unavailable', 403), request)
179179
}
180180

@@ -205,7 +205,7 @@ export async function GET(
205205
const authResult = await validateChatAuth(requestId, deployment, request)
206206
if (!authResult.authorized) {
207207
logger.info(
208-
`[${requestId}] Authentication required for chat: ${subdomain}, type: ${deployment.authType}`
208+
`[${requestId}] Authentication required for chat: ${identifier}, type: ${deployment.authType}`
209209
)
210210
return addCorsHeaders(
211211
createErrorResponse(authResult.error || 'Authentication required', 401),

0 commit comments

Comments
 (0)