11import { and , eq } from 'drizzle-orm'
22import { type NextRequest , NextResponse } from 'next/server'
33import { createLogger } from '@/lib/logs/console/logger'
4- import { refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils'
4+ import { getOAuthToken , refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils'
55import { db } from '@/db'
66import { account , webhook } from '@/db/schema'
77
@@ -1284,29 +1284,42 @@ export async function configureGmailPolling(
12841284 const providerConfig = ( webhookData . providerConfig as Record < string , any > ) || { }
12851285
12861286 const credentialId : string | undefined = providerConfig . credentialId
1287- if ( ! credentialId ) {
1288- logger . error (
1289- `[${ requestId } ] Missing credentialId for Gmail webhook ${ webhookData . id } . Refusing to proceed.`
1290- )
1291- return false
1292- }
12931287
1294- // Resolve owner user ID from the credential and refresh token if needed
1295- const rows = await db . select ( ) . from ( account ) . where ( eq ( account . id , credentialId ) ) . limit ( 1 )
1296- if ( rows . length === 0 ) {
1297- logger . error (
1298- `[${ requestId } ] Credential ${ credentialId } not found for Gmail webhook ${ webhookData . id } `
1299- )
1300- return false
1301- }
1302- const ownerUserId = rows [ 0 ] . userId
1288+ let effectiveUserId : string | null = null
1289+ let accessToken : string | null = null
13031290
1304- const accessToken = await refreshAccessTokenIfNeeded ( credentialId , ownerUserId , requestId )
1305- if ( ! accessToken ) {
1306- logger . error (
1307- `[${ requestId } ] Failed to refresh/access Gmail token for credential ${ credentialId } `
1308- )
1309- return false
1291+ if ( credentialId ) {
1292+ const rows = await db . select ( ) . from ( account ) . where ( eq ( account . id , credentialId ) ) . limit ( 1 )
1293+ if ( rows . length === 0 ) {
1294+ logger . error (
1295+ `[${ requestId } ] Credential ${ credentialId } not found for Gmail webhook ${ webhookData . id } `
1296+ )
1297+ return false
1298+ }
1299+ effectiveUserId = rows [ 0 ] . userId
1300+ accessToken = await refreshAccessTokenIfNeeded ( credentialId , effectiveUserId , requestId )
1301+ if ( ! accessToken ) {
1302+ logger . error (
1303+ `[${ requestId } ] Failed to refresh/access Gmail token for credential ${ credentialId } `
1304+ )
1305+ return false
1306+ }
1307+ } else {
1308+ // Backward-compat: fall back to workflow owner
1309+ if ( ! userId ) {
1310+ logger . error (
1311+ `[${ requestId } ] Missing credentialId and userId for Gmail webhook ${ webhookData . id } `
1312+ )
1313+ return false
1314+ }
1315+ effectiveUserId = userId
1316+ accessToken = await getOAuthToken ( effectiveUserId , 'google-email' )
1317+ if ( ! accessToken ) {
1318+ logger . error (
1319+ `[${ requestId } ] Failed to obtain Gmail token for user ${ effectiveUserId } (fallback)`
1320+ )
1321+ return false
1322+ }
13101323 }
13111324
13121325 const maxEmailsPerPoll =
@@ -1326,8 +1339,8 @@ export async function configureGmailPolling(
13261339 . set ( {
13271340 providerConfig : {
13281341 ...providerConfig ,
1329- userId : ownerUserId ,
1330- credentialId,
1342+ userId : effectiveUserId ,
1343+ ... ( credentialId ? { credentialId } : { } ) ,
13311344 maxEmailsPerPoll,
13321345 pollingInterval,
13331346 markAsRead : providerConfig . markAsRead || false ,
@@ -1371,56 +1384,67 @@ export async function configureOutlookPolling(
13711384 const providerConfig = ( webhookData . providerConfig as Record < string , any > ) || { }
13721385
13731386 const credentialId : string | undefined = providerConfig . credentialId
1374- if ( ! credentialId ) {
1375- logger . error (
1376- `[${ requestId } ] Missing credentialId for Outlook webhook ${ webhookData . id } . Refusing to proceed.`
1377- )
1378- return false
1379- }
13801387
1381- // Resolve owner user ID from the credential and refresh token if needed
1382- const rows = await db . select ( ) . from ( account ) . where ( eq ( account . id , credentialId ) ) . limit ( 1 )
1383- if ( rows . length === 0 ) {
1384- logger . error (
1385- `[${ requestId } ] Credential ${ credentialId } not found for Outlook webhook ${ webhookData . id } `
1386- )
1387- return false
1388- }
1389- const ownerUserId = rows [ 0 ] . userId
1388+ let effectiveUserId : string | null = null
1389+ let accessToken : string | null = null
13901390
1391- const accessToken = await refreshAccessTokenIfNeeded ( credentialId , ownerUserId , requestId )
1392- if ( ! accessToken ) {
1393- logger . error (
1394- `[${ requestId } ] Failed to refresh/access Outlook token for credential ${ credentialId } `
1395- )
1396- return false
1391+ if ( credentialId ) {
1392+ const rows = await db . select ( ) . from ( account ) . where ( eq ( account . id , credentialId ) ) . limit ( 1 )
1393+ if ( rows . length === 0 ) {
1394+ logger . error (
1395+ `[${ requestId } ] Credential ${ credentialId } not found for Outlook webhook ${ webhookData . id } `
1396+ )
1397+ return false
1398+ }
1399+ effectiveUserId = rows [ 0 ] . userId
1400+ accessToken = await refreshAccessTokenIfNeeded ( credentialId , effectiveUserId , requestId )
1401+ if ( ! accessToken ) {
1402+ logger . error (
1403+ `[${ requestId } ] Failed to refresh/access Outlook token for credential ${ credentialId } `
1404+ )
1405+ return false
1406+ }
1407+ } else {
1408+ // Backward-compat: fall back to workflow owner
1409+ if ( ! userId ) {
1410+ logger . error (
1411+ `[${ requestId } ] Missing credentialId and userId for Outlook webhook ${ webhookData . id } `
1412+ )
1413+ return false
1414+ }
1415+ effectiveUserId = userId
1416+ accessToken = await getOAuthToken ( effectiveUserId , 'outlook' )
1417+ if ( ! accessToken ) {
1418+ logger . error (
1419+ `[${ requestId } ] Failed to obtain Outlook token for user ${ effectiveUserId } (fallback)`
1420+ )
1421+ return false
1422+ }
13971423 }
13981424
1399- const maxEmailsPerPoll =
1400- typeof providerConfig . maxEmailsPerPoll === 'string'
1401- ? Number . parseInt ( providerConfig . maxEmailsPerPoll , 10 ) || 25
1402- : providerConfig . maxEmailsPerPoll || 25
1403-
1404- const pollingInterval =
1405- typeof providerConfig . pollingInterval === 'string'
1406- ? Number . parseInt ( providerConfig . pollingInterval , 10 ) || 5
1407- : providerConfig . pollingInterval || 5
1425+ const providerCfg = ( webhookData . providerConfig as Record < string , any > ) || { }
14081426
14091427 const now = new Date ( )
14101428
14111429 await db
14121430 . update ( webhook )
14131431 . set ( {
14141432 providerConfig : {
1415- ...providerConfig ,
1416- userId : ownerUserId ,
1417- credentialId,
1418- maxEmailsPerPoll,
1419- pollingInterval,
1420- markAsRead : providerConfig . markAsRead || false ,
1421- includeRawEmail : providerConfig . includeRawEmail || false ,
1422- folderIds : providerConfig . folderIds || [ 'inbox' ] ,
1423- folderFilterBehavior : providerConfig . folderFilterBehavior || 'INCLUDE' ,
1433+ ...providerCfg ,
1434+ userId : effectiveUserId ,
1435+ ...( credentialId ? { credentialId } : { } ) ,
1436+ maxEmailsPerPoll :
1437+ typeof providerCfg . maxEmailsPerPoll === 'string'
1438+ ? Number . parseInt ( providerCfg . maxEmailsPerPoll , 10 ) || 25
1439+ : providerCfg . maxEmailsPerPoll || 25 ,
1440+ pollingInterval :
1441+ typeof providerCfg . pollingInterval === 'string'
1442+ ? Number . parseInt ( providerCfg . pollingInterval , 10 ) || 5
1443+ : providerCfg . pollingInterval || 5 ,
1444+ markAsRead : providerCfg . markAsRead || false ,
1445+ includeRawEmail : providerCfg . includeRawEmail || false ,
1446+ folderIds : providerCfg . folderIds || [ 'inbox' ] ,
1447+ folderFilterBehavior : providerCfg . folderFilterBehavior || 'INCLUDE' ,
14241448 lastCheckedTimestamp : now . toISOString ( ) ,
14251449 setupCompleted : true ,
14261450 } ,
0 commit comments