Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
cc6b80c
refactor(webhooks): extract provider-specific logic into handler regi…
waleedlatif1 Apr 5, 2026
ffa5864
fix(webhooks): address PR review feedback
waleedlatif1 Apr 5, 2026
403e32f
fix(webhooks): fix build error from union type indexing in processTri…
waleedlatif1 Apr 5, 2026
5d9b95a
fix(webhooks): return 401 when requireAuth is true but no token confi…
waleedlatif1 Apr 5, 2026
7b6b50b
refactor(webhooks): move signature validators into provider handler f…
waleedlatif1 Apr 5, 2026
1f92950
refactor(webhooks): move challenge handlers into provider files
waleedlatif1 Apr 5, 2026
46a1ea0
refactor(webhooks): move fetchAndProcessAirtablePayloads into airtabl…
waleedlatif1 Apr 5, 2026
adf13bc
refactor(webhooks): extract polling config functions into polling-con…
waleedlatif1 Apr 5, 2026
ced7d14
refactor(webhooks): decompose formatWebhookInput into per-provider fo…
waleedlatif1 Apr 5, 2026
0d2f78b
refactor(webhooks): decompose provider-subscriptions into handler reg…
waleedlatif1 Apr 5, 2026
3ad355e
fix(webhooks): fix attio build error, restore imap field, remove dema…
waleedlatif1 Apr 5, 2026
8bcf450
fix(webhooks): remove unused imports from utils.server.ts after rebase
waleedlatif1 Apr 5, 2026
60610b7
fix(webhooks): remove duplicate generic file processing from webhook-…
waleedlatif1 Apr 5, 2026
1478de1
fix(webhooks): validate auth token is set when requireAuth is enabled…
waleedlatif1 Apr 5, 2026
78e6de5
fix(webhooks): remove unintended rejectUnauthorized field from IMAP p…
waleedlatif1 Apr 5, 2026
7afed0d
fix(webhooks): replace crypto.randomUUID() with generateId() in ashby…
waleedlatif1 Apr 5, 2026
220aa91
refactor(webhooks): standardize logger names and remove any types fro…
waleedlatif1 Apr 5, 2026
98b4586
refactor(webhooks): remove remaining any types from deploy.ts
waleedlatif1 Apr 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refactor(webhooks): standardize logger names and remove any types fro…
…m providers

- Standardize logger names to WebhookProvider:X pattern across 6 providers
  (fathom, gmail, imap, lemlist, outlook, rss)
- Replace all `any` types in airtable handler with proper types:
  - Add AirtableTableChanges interface for API response typing
  - Change function params from `any` to `Record<string, unknown>`
  - Change AirtableChange fields from Record<string, any> to Record<string, unknown>
  - Change all catch blocks from `error: any` to `error: unknown`
  - Change input object from `any` to `Record<string, unknown>`

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
  • Loading branch information
waleedlatif1 and claude committed Apr 5, 2026
commit 220aa91dab29f11669ae159f0b35c7003f99393e
70 changes: 41 additions & 29 deletions apps/sim/lib/webhooks/providers/airtable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,28 @@ interface AirtableChange {
tableId: string
recordId: string
changeType: 'created' | 'updated'
changedFields: Record<string, any> // { fieldId: newValue }
previousFields?: Record<string, any> // { fieldId: previousValue } (optional)
changedFields: Record<string, unknown>
previousFields?: Record<string, unknown>
}

interface AirtableTableChanges {
createdRecordsById?: Record<string, { cellValuesByFieldId?: Record<string, unknown> }>
changedRecordsById?: Record<
string,
{
current?: { cellValuesByFieldId?: Record<string, unknown> }
previous?: { cellValuesByFieldId?: Record<string, unknown> }
}
>
destroyedRecordIds?: string[]
}

/**
* Process Airtable payloads
*/
async function fetchAndProcessAirtablePayloads(
webhookData: any,
workflowData: any,
webhookData: Record<string, unknown>,
workflowData: Record<string, unknown>,
requestId: string // Original request ID from the ping, used for the final execution log
) {
// Logging handles all error logging
Expand All @@ -50,8 +62,8 @@ async function fetchAndProcessAirtablePayloads(
// Capture raw payloads from Airtable for exposure to workflows
const allPayloads = []
const localProviderConfig = {
...((webhookData.providerConfig as Record<string, any>) || {}),
}
...((webhookData.providerConfig as Record<string, unknown>) || {}),
} as Record<string, unknown>

try {
const baseId = localProviderConfig.baseId
Expand All @@ -64,7 +76,7 @@ async function fetchAndProcessAirtablePayloads(
return
}

const credentialId: string | undefined = localProviderConfig.credentialId
const credentialId = localProviderConfig.credentialId as string | undefined
if (!credentialId) {
logger.error(
`[${requestId}] Missing credentialId in providerConfig for Airtable webhook ${webhookData.id}.`
Expand Down Expand Up @@ -117,15 +129,16 @@ async function fetchAndProcessAirtablePayloads(
},
updatedAt: new Date(),
})
.where(eq(webhook.id, webhookData.id))
.where(eq(webhook.id, webhookData.id as string))

localProviderConfig.externalWebhookCursor = null
logger.info(`[${requestId}] Successfully initialized cursor for webhook ${webhookData.id}`)
} catch (initError: any) {
} catch (initError: unknown) {
const err = initError as Error
logger.error(`[${requestId}] Failed to initialize cursor in DB`, {
webhookId: webhookData.id,
error: initError.message,
stack: initError.stack,
error: err.message,
stack: err.stack,
})
}
}
Expand All @@ -149,12 +162,13 @@ async function fetchAndProcessAirtablePayloads(
)
throw new Error('Airtable access token not found.')
}
} catch (tokenError: any) {
} catch (tokenError: unknown) {
const err = tokenError as Error
logger.error(
`[${requestId}] Failed to get Airtable OAuth token for credential ${credentialId}`,
{
error: tokenError.message,
stack: tokenError.stack,
error: err.message,
stack: err.stack,
credentialId,
}
)
Expand Down Expand Up @@ -222,17 +236,15 @@ async function fetchAndProcessAirtablePayloads(
for (const [tableId, tableChangesUntyped] of Object.entries(
payload.changedTablesById
)) {
const tableChanges = tableChangesUntyped as any // Assert type
const tableChanges = tableChangesUntyped as AirtableTableChanges

// Handle created records
if (tableChanges.createdRecordsById) {
const createdCount = Object.keys(tableChanges.createdRecordsById).length
changeCount += createdCount

for (const [recordId, recordDataUntyped] of Object.entries(
for (const [recordId, recordData] of Object.entries(
tableChanges.createdRecordsById
)) {
const recordData = recordDataUntyped as any // Assert type
const existingChange = consolidatedChangesMap.get(recordId)
if (existingChange) {
// Record was created and possibly updated within the same batch
Expand All @@ -258,10 +270,9 @@ async function fetchAndProcessAirtablePayloads(
const updatedCount = Object.keys(tableChanges.changedRecordsById).length
changeCount += updatedCount

for (const [recordId, recordDataUntyped] of Object.entries(
for (const [recordId, recordData] of Object.entries(
tableChanges.changedRecordsById
)) {
const recordData = recordDataUntyped as any // Assert type
const existingChange = consolidatedChangesMap.get(recordId)
const currentFields = recordData.current?.cellValuesByFieldId || {}

Expand Down Expand Up @@ -314,14 +325,15 @@ async function fetchAndProcessAirtablePayloads(
providerConfig: updatedConfig, // Use full object
updatedAt: new Date(),
})
.where(eq(webhook.id, webhookData.id))
.where(eq(webhook.id, webhookData.id as string))

localProviderConfig.externalWebhookCursor = currentCursor // Update local copy too
} catch (dbError: any) {
} catch (dbError: unknown) {
const err = dbError as Error
logger.error(`[${requestId}] Failed to persist Airtable cursor to DB`, {
webhookId: webhookData.id,
cursor: currentCursor,
error: dbError.message,
error: err.message,
})
// Error logging handled by logging session
mightHaveMore = false
Expand All @@ -337,7 +349,7 @@ async function fetchAndProcessAirtablePayloads(
} else if (nextCursor === currentCursor) {
mightHaveMore = false // Explicitly stop if cursor hasn't changed
}
} catch (fetchError: any) {
} catch (fetchError: unknown) {
logger.error(
`[${requestId}] Network error calling Airtable GET /payloads (Call ${apiCallCount}) for webhook ${webhookData.id}`,
fetchError
Expand All @@ -357,8 +369,7 @@ async function fetchAndProcessAirtablePayloads(
try {
// Build input exposing raw payloads and consolidated changes
const latestPayload = allPayloads.length > 0 ? allPayloads[allPayloads.length - 1] : null
const input: any = {
// Raw Airtable payloads as received from the API
const input: Record<string, unknown> = {
payloads: allPayloads,
latestPayload,
// Consolidated, simplified changes for convenience
Expand Down Expand Up @@ -393,11 +404,12 @@ async function fetchAndProcessAirtablePayloads(
})

return input
} catch (processingError: any) {
} catch (processingError: unknown) {
const err = processingError as Error
logger.error(`[${requestId}] CRITICAL_TRACE: Error processing Airtable changes`, {
workflowId: workflowData.id,
error: processingError.message,
stack: processingError.stack,
error: err.message,
stack: err.stack,
timestamp: new Date().toISOString(),
})

Expand Down
2 changes: 1 addition & 1 deletion apps/sim/lib/webhooks/providers/fathom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type {
WebhookProviderHandler,
} from '@/lib/webhooks/providers/types'

const logger = createLogger('FathomWebhook')
const logger = createLogger('WebhookProvider:Fathom')

export const fathomHandler: WebhookProviderHandler = {
async createSubscription(ctx: SubscriptionContext): Promise<SubscriptionResult | undefined> {
Expand Down
2 changes: 1 addition & 1 deletion apps/sim/lib/webhooks/providers/gmail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type {
} from '@/lib/webhooks/providers/types'
import { refreshAccessTokenIfNeeded, resolveOAuthAccountId } from '@/app/api/auth/oauth/utils'

const logger = createLogger('GmailWebhookSetup')
const logger = createLogger('WebhookProvider:Gmail')

export const gmailHandler: WebhookProviderHandler = {
async formatInput({ body }: FormatInputContext): Promise<FormatInputResult> {
Expand Down
2 changes: 1 addition & 1 deletion apps/sim/lib/webhooks/providers/imap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type {
WebhookProviderHandler,
} from '@/lib/webhooks/providers/types'

const logger = createLogger('ImapWebhookSetup')
const logger = createLogger('WebhookProvider:Imap')

export const imapHandler: WebhookProviderHandler = {
async formatInput({ body }: FormatInputContext): Promise<FormatInputResult> {
Expand Down
2 changes: 1 addition & 1 deletion apps/sim/lib/webhooks/providers/lemlist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type {
WebhookProviderHandler,
} from '@/lib/webhooks/providers/types'

const logger = createLogger('LemlistWebhook')
const logger = createLogger('WebhookProvider:Lemlist')

export const lemlistHandler: WebhookProviderHandler = {
async createSubscription(ctx: SubscriptionContext): Promise<SubscriptionResult | undefined> {
Expand Down
2 changes: 1 addition & 1 deletion apps/sim/lib/webhooks/providers/outlook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type {
} from '@/lib/webhooks/providers/types'
import { refreshAccessTokenIfNeeded, resolveOAuthAccountId } from '@/app/api/auth/oauth/utils'

const logger = createLogger('OutlookWebhookSetup')
const logger = createLogger('WebhookProvider:Outlook')

export const outlookHandler: WebhookProviderHandler = {
async formatInput({ body }: FormatInputContext): Promise<FormatInputResult> {
Expand Down
2 changes: 1 addition & 1 deletion apps/sim/lib/webhooks/providers/rss.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type {
WebhookProviderHandler,
} from '@/lib/webhooks/providers/types'

const logger = createLogger('RssWebhookSetup')
const logger = createLogger('WebhookProvider:Rss')

export const rssHandler: WebhookProviderHandler = {
async formatInput({ body }: FormatInputContext): Promise<FormatInputResult> {
Expand Down
Loading