Skip to content

Commit 4846f6c

Browse files
authored
v0.3.37: azure OCR api key, wand SSE, CRON helm
2 parents 991f044 + be81001 commit 4846f6c

File tree

26 files changed

+1265
-711
lines changed

26 files changed

+1265
-711
lines changed

apps/sim/app/(auth)/components/social-login-buttons.tsx

Lines changed: 5 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import { useEffect, useState } from 'react'
44
import { GithubIcon, GoogleIcon } from '@/components/icons'
55
import { Button } from '@/components/ui/button'
6-
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
76
import { client } from '@/lib/auth-client'
87

98
interface SocialLoginButtonsProps {
@@ -114,58 +113,16 @@ export function SocialLoginButtons({
114113
</Button>
115114
)
116115

117-
const renderGithubButton = () => {
118-
if (githubAvailable) return githubButton
119-
120-
return (
121-
<TooltipProvider>
122-
<Tooltip>
123-
<TooltipTrigger asChild>
124-
<div>{githubButton}</div>
125-
</TooltipTrigger>
126-
<TooltipContent className='border-neutral-700 bg-neutral-800 text-white'>
127-
<p>
128-
GitHub login requires OAuth credentials to be configured. Add the following
129-
environment variables:
130-
</p>
131-
<ul className='mt-2 space-y-1 text-neutral-300 text-xs'>
132-
<li>• GITHUB_CLIENT_ID</li>
133-
<li>• GITHUB_CLIENT_SECRET</li>
134-
</ul>
135-
</TooltipContent>
136-
</Tooltip>
137-
</TooltipProvider>
138-
)
139-
}
116+
const hasAnyOAuthProvider = githubAvailable || googleAvailable
140117

141-
const renderGoogleButton = () => {
142-
if (googleAvailable) return googleButton
143-
144-
return (
145-
<TooltipProvider>
146-
<Tooltip>
147-
<TooltipTrigger asChild>
148-
<div>{googleButton}</div>
149-
</TooltipTrigger>
150-
<TooltipContent className='border-neutral-700 bg-neutral-800 text-white'>
151-
<p>
152-
Google login requires OAuth credentials to be configured. Add the following
153-
environment variables:
154-
</p>
155-
<ul className='mt-2 space-y-1 text-neutral-300 text-xs'>
156-
<li>• GOOGLE_CLIENT_ID</li>
157-
<li>• GOOGLE_CLIENT_SECRET</li>
158-
</ul>
159-
</TooltipContent>
160-
</Tooltip>
161-
</TooltipProvider>
162-
)
118+
if (!hasAnyOAuthProvider) {
119+
return null
163120
}
164121

165122
return (
166123
<div className='grid gap-3'>
167-
{renderGithubButton()}
168-
{renderGoogleButton()}
124+
{githubAvailable && githubButton}
125+
{googleAvailable && googleButton}
169126
</div>
170127
)
171128
}

apps/sim/app/(auth)/layout.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ export default function AuthLayout({ children }: { children: React.ReactNode })
2828
<img
2929
src={brand.logoUrl}
3030
alt={`${brand.name} Logo`}
31-
width={42}
32-
height={42}
33-
className='h-[42px] w-[42px] object-contain'
31+
width={56}
32+
height={56}
33+
className='h-[56px] w-[56px] object-contain'
3434
/>
3535
) : (
36-
<Image src='/sim.svg' alt={`${brand.name} Logo`} width={42} height={42} />
36+
<Image src='/sim.svg' alt={`${brand.name} Logo`} width={56} height={56} />
3737
)}
3838
</Link>
3939
</div>

apps/sim/app/(auth)/login/login-form.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -366,11 +366,13 @@ export default function LoginPage({
366366
callbackURL={callbackUrl}
367367
/>
368368

369-
<div className='relative mt-2 py-4'>
370-
<div className='absolute inset-0 flex items-center'>
371-
<div className='w-full border-neutral-700/50 border-t' />
369+
{(githubAvailable || googleAvailable) && (
370+
<div className='relative mt-2 py-4'>
371+
<div className='absolute inset-0 flex items-center'>
372+
<div className='w-full border-neutral-700/50 border-t' />
373+
</div>
372374
</div>
373-
</div>
375+
)}
374376

375377
<form onSubmit={onSubmit} className='space-y-5'>
376378
<div className='space-y-4'>

apps/sim/app/(auth)/signup/signup-form.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -381,11 +381,13 @@ function SignupFormContent({
381381
isProduction={isProduction}
382382
/>
383383

384-
<div className='relative mt-2 py-4'>
385-
<div className='absolute inset-0 flex items-center'>
386-
<div className='w-full border-neutral-700/50 border-t' />
384+
{(githubAvailable || googleAvailable) && (
385+
<div className='relative mt-2 py-4'>
386+
<div className='absolute inset-0 flex items-center'>
387+
<div className='w-full border-neutral-700/50 border-t' />
388+
</div>
387389
</div>
388-
</div>
390+
)}
389391

390392
<form onSubmit={onSubmit} className='space-y-5'>
391393
<div className='space-y-4'>

apps/sim/app/api/__test-utils__/utils.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,18 @@ export function mockExecutionDependencies() {
354354
}))
355355
}
356356

357+
/**
358+
* Mock Trigger.dev SDK (tasks.trigger and task factory) for tests that import background modules
359+
*/
360+
export function mockTriggerDevSdk() {
361+
vi.mock('@trigger.dev/sdk', () => ({
362+
tasks: {
363+
trigger: vi.fn().mockResolvedValue({ id: 'mock-task-id' }),
364+
},
365+
task: vi.fn().mockReturnValue({}),
366+
}))
367+
}
368+
357369
export function mockWorkflowAccessValidation(shouldSucceed = true) {
358370
if (shouldSucceed) {
359371
vi.mock('@/app/api/workflows/middleware', () => ({

apps/sim/app/api/wand-generate/route.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,19 @@ export async function POST(req: NextRequest) {
9595
{
9696
stream,
9797
historyLength: history.length,
98+
endpoint: useWandAzure ? azureEndpoint : 'api.openai.com',
99+
model: useWandAzure ? wandModelName : 'gpt-4o',
100+
apiVersion: useWandAzure ? azureApiVersion : 'N/A',
98101
}
99102
)
100103

101104
// For streaming responses
102105
if (stream) {
103106
try {
107+
logger.debug(
108+
`[${requestId}] Starting streaming request to ${useWandAzure ? 'Azure OpenAI' : 'OpenAI'}`
109+
)
110+
104111
const streamCompletion = await client.chat.completions.create({
105112
model: useWandAzure ? wandModelName : 'gpt-4o',
106113
messages: messages,
@@ -109,6 +116,8 @@ export async function POST(req: NextRequest) {
109116
stream: true,
110117
})
111118

119+
logger.debug(`[${requestId}] Stream connection established successfully`)
120+
112121
return new Response(
113122
new ReadableStream({
114123
async start(controller) {
@@ -118,31 +127,34 @@ export async function POST(req: NextRequest) {
118127
for await (const chunk of streamCompletion) {
119128
const content = chunk.choices[0]?.delta?.content || ''
120129
if (content) {
121-
// Use the same format as codegen API for consistency
130+
// Use SSE format identical to chat streaming
122131
controller.enqueue(
123-
encoder.encode(`${JSON.stringify({ chunk: content, done: false })}\n`)
132+
encoder.encode(`data: ${JSON.stringify({ chunk: content })}\n\n`)
124133
)
125134
}
126135
}
127136

128-
// Send completion signal
129-
controller.enqueue(encoder.encode(`${JSON.stringify({ chunk: '', done: true })}\n`))
137+
// Send completion signal in SSE format
138+
controller.enqueue(encoder.encode(`data: ${JSON.stringify({ done: true })}\n\n`))
130139
controller.close()
131140
logger.info(`[${requestId}] Wand generation streaming completed`)
132141
} catch (streamError: any) {
133142
logger.error(`[${requestId}] Streaming error`, { error: streamError.message })
134143
controller.enqueue(
135-
encoder.encode(`${JSON.stringify({ error: 'Streaming failed', done: true })}\n`)
144+
encoder.encode(
145+
`data: ${JSON.stringify({ error: 'Streaming failed', done: true })}\n\n`
146+
)
136147
)
137148
controller.close()
138149
}
139150
},
140151
}),
141152
{
142153
headers: {
143-
'Content-Type': 'text/plain',
144-
'Cache-Control': 'no-cache, no-transform',
154+
'Content-Type': 'text/event-stream',
155+
'Cache-Control': 'no-cache',
145156
Connection: 'keep-alive',
157+
'X-Accel-Buffering': 'no',
146158
},
147159
}
148160
)

apps/sim/app/api/webhooks/trigger/[path]/route.test.ts

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,22 @@ import { NextRequest } from 'next/server'
55
* @vitest-environment node
66
*/
77
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
8-
import { createMockRequest, mockExecutionDependencies } from '@/app/api/__test-utils__/utils'
8+
import {
9+
createMockRequest,
10+
mockExecutionDependencies,
11+
mockTriggerDevSdk,
12+
} from '@/app/api/__test-utils__/utils'
13+
14+
// Prefer mocking the background module to avoid loading Trigger.dev at all during tests
15+
vi.mock('@/background/webhook-execution', () => ({
16+
executeWebhookJob: vi.fn().mockResolvedValue({
17+
success: true,
18+
workflowId: 'test-workflow-id',
19+
executionId: 'test-exec-id',
20+
output: {},
21+
executedAt: new Date().toISOString(),
22+
}),
23+
}))
924

1025
const hasProcessedMessageMock = vi.fn().mockResolvedValue(false)
1126
const markMessageAsProcessedMock = vi.fn().mockResolvedValue(true)
@@ -111,6 +126,7 @@ describe('Webhook Trigger API Route', () => {
111126
vi.resetAllMocks()
112127

113128
mockExecutionDependencies()
129+
mockTriggerDevSdk()
114130

115131
vi.doMock('@/services/queue', () => ({
116132
RateLimiter: vi.fn().mockImplementation(() => ({
@@ -309,11 +325,7 @@ describe('Webhook Trigger API Route', () => {
309325
const req = createMockRequest('POST', { event: 'test', id: 'test-123' })
310326
const params = Promise.resolve({ path: 'test-path' })
311327

312-
vi.doMock('@trigger.dev/sdk', () => ({
313-
tasks: {
314-
trigger: vi.fn().mockResolvedValue({ id: 'mock-task-id' }),
315-
},
316-
}))
328+
mockTriggerDevSdk()
317329

318330
const { POST } = await import('@/app/api/webhooks/trigger/[path]/route')
319331
const response = await POST(req, { params })
@@ -339,11 +351,7 @@ describe('Webhook Trigger API Route', () => {
339351
const req = createMockRequest('POST', { event: 'bearer.test' }, headers)
340352
const params = Promise.resolve({ path: 'test-path' })
341353

342-
vi.doMock('@trigger.dev/sdk', () => ({
343-
tasks: {
344-
trigger: vi.fn().mockResolvedValue({ id: 'mock-task-id' }),
345-
},
346-
}))
354+
mockTriggerDevSdk()
347355

348356
const { POST } = await import('@/app/api/webhooks/trigger/[path]/route')
349357
const response = await POST(req, { params })
@@ -369,11 +377,7 @@ describe('Webhook Trigger API Route', () => {
369377
const req = createMockRequest('POST', { event: 'custom.header.test' }, headers)
370378
const params = Promise.resolve({ path: 'test-path' })
371379

372-
vi.doMock('@trigger.dev/sdk', () => ({
373-
tasks: {
374-
trigger: vi.fn().mockResolvedValue({ id: 'mock-task-id' }),
375-
},
376-
}))
380+
mockTriggerDevSdk()
377381

378382
const { POST } = await import('@/app/api/webhooks/trigger/[path]/route')
379383
const response = await POST(req, { params })

apps/sim/app/api/webhooks/trigger/[path]/route.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ import { tasks } from '@trigger.dev/sdk'
22
import { and, eq } from 'drizzle-orm'
33
import { type NextRequest, NextResponse } from 'next/server'
44
import { checkServerSideUsageLimits } from '@/lib/billing'
5+
import { env, isTruthy } from '@/lib/env'
56
import { createLogger } from '@/lib/logs/console/logger'
67
import {
78
handleSlackChallenge,
89
handleWhatsAppVerification,
910
validateMicrosoftTeamsSignature,
1011
} from '@/lib/webhooks/utils'
12+
import { executeWebhookJob } from '@/background/webhook-execution'
1113
import { db } from '@/db'
1214
import { subscription, webhook, workflow } from '@/db/schema'
1315
import { RateLimiter } from '@/services/queue'
@@ -17,6 +19,7 @@ const logger = createLogger('WebhookTriggerAPI')
1719

1820
export const dynamic = 'force-dynamic'
1921
export const maxDuration = 300
22+
export const runtime = 'nodejs'
2023

2124
/**
2225
* Webhook Verification Handler (GET)
@@ -330,10 +333,9 @@ export async function POST(
330333
// Continue processing - better to risk usage limit bypass than fail webhook
331334
}
332335

333-
// --- PHASE 5: Queue webhook execution via trigger.dev ---
336+
// --- PHASE 5: Queue webhook execution (trigger.dev or direct based on env) ---
334337
try {
335-
// Queue the webhook execution task
336-
const handle = await tasks.trigger('webhook-execution', {
338+
const payload = {
337339
webhookId: foundWebhook.id,
338340
workflowId: foundWorkflow.id,
339341
userId: foundWorkflow.userId,
@@ -342,11 +344,24 @@ export async function POST(
342344
headers: Object.fromEntries(request.headers.entries()),
343345
path,
344346
blockId: foundWebhook.blockId,
345-
})
347+
}
346348

347-
logger.info(
348-
`[${requestId}] Queued webhook execution task ${handle.id} for ${foundWebhook.provider} webhook`
349-
)
349+
const useTrigger = isTruthy(env.TRIGGER_DEV_ENABLED)
350+
351+
if (useTrigger) {
352+
const handle = await tasks.trigger('webhook-execution', payload)
353+
logger.info(
354+
`[${requestId}] Queued webhook execution task ${handle.id} for ${foundWebhook.provider} webhook`
355+
)
356+
} else {
357+
// Fire-and-forget direct execution to avoid blocking webhook response
358+
void executeWebhookJob(payload).catch((error) => {
359+
logger.error(`[${requestId}] Direct webhook execution failed`, error)
360+
})
361+
logger.info(
362+
`[${requestId}] Queued direct webhook execution for ${foundWebhook.provider} webhook (Trigger.dev disabled)`
363+
)
364+
}
350365

351366
// Return immediate acknowledgment with provider-specific format
352367
if (foundWebhook.provider === 'microsoftteams') {

apps/sim/app/api/workflows/[id]/execute/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ export async function POST(
540540
)
541541
}
542542

543-
// Rate limit passed - trigger the task
543+
// Rate limit passed - always use Trigger.dev for async executions
544544
const handle = await tasks.trigger('workflow-execution', {
545545
workflowId,
546546
userId: authenticatedUserId,

0 commit comments

Comments
 (0)