Skip to content

Commit 687dea5

Browse files
committed
fix(zoho-desk): review round - DC-base derivation, org-loader resilience, batched-event visibility
- deriveZohoDeskBaseFromApiDomain: preserve an already-regional desk.zoho.<tld> api_domain instead of falling back to the US (.com) data center, and map the DC TLD from any zoho(apis).<tld> host - keeps Desk calls in the right data center for residency. - fetchZohoDeskOrganizationOptions: wrap the token/org fetch in try/catch and degrade to an empty list (the org field is a free-text combobox, so manual entry still works) instead of hard-failing the selector on token/DC/network errors. - formatInput: warn (not silently drop) if Zoho ever delivers more than one event in a single payload.
1 parent 310a216 commit 687dea5

3 files changed

Lines changed: 37 additions & 13 deletions

File tree

apps/sim/blocks/blocks/zoho-desk-org-options.ts

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
import { createLogger } from '@sim/logger'
2+
import { getErrorMessage } from '@sim/utils/errors'
13
import { requestJson } from '@/lib/api/client/request'
24
import { zohoDeskListOrganizationsContract } from '@/lib/api/contracts/tools/zoho-desk'
35
import { fetchOAuthToken } from '@/hooks/selectors/helpers'
46
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
57
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
68

9+
const logger = createLogger('ZohoDeskOrgOptions')
10+
711
/**
812
* Populate a Zoho Desk organization selector from the connected credential.
913
*
@@ -23,13 +27,21 @@ export async function fetchZohoDeskOrganizationOptions(
2327
(blockValues?.manualCredential as string) ||
2428
(blockValues?.triggerCredentials as string)
2529
if (!credentialId) return []
26-
const bundle = await fetchOAuthToken(credentialId, activeWorkflowId)
27-
if (!bundle) return []
28-
const data = await requestJson(zohoDeskListOrganizationsContract, {
29-
body: { accessToken: bundle.accessToken, apiDomain: bundle.apiDomain ?? null },
30-
})
31-
return data.organizations.map((org) => ({
32-
label: org.companyName ? `${org.companyName} (${org.id})` : org.id,
33-
id: org.id,
34-
}))
30+
// Degrade to an empty list on any failure (expired token, wrong data center,
31+
// network error): the org field is a free-text combobox, so the user can still
32+
// type an organization ID manually instead of the selector hard-failing.
33+
try {
34+
const bundle = await fetchOAuthToken(credentialId, activeWorkflowId)
35+
if (!bundle) return []
36+
const data = await requestJson(zohoDeskListOrganizationsContract, {
37+
body: { accessToken: bundle.accessToken, apiDomain: bundle.apiDomain ?? null },
38+
})
39+
return data.organizations.map((org) => ({
40+
label: org.companyName ? `${org.companyName} (${org.id})` : org.id,
41+
id: org.id,
42+
}))
43+
} catch (error) {
44+
logger.warn('Failed to load Zoho Desk organizations', { message: getErrorMessage(error) })
45+
return []
46+
}
3547
}

apps/sim/lib/auth/auth.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,14 @@ function deriveZohoDeskBaseFromApiDomain(apiDomain?: string): string {
170170
const fallback = 'https://desk.zoho.com'
171171
if (!apiDomain) return fallback
172172
try {
173-
const host = new URL(apiDomain).host
174-
const match = host.match(/zohoapis\.(.+)$/i)
175-
if (match?.[1]) return `https://desk.zoho.${match[1].toLowerCase()}`
173+
const host = new URL(apiDomain).host.toLowerCase()
174+
// Already a data-center Desk host (e.g. desk.zoho.eu) - preserve it so we
175+
// never misroute a valid regional domain back to the US (.com) data center.
176+
if (/(^|\.)desk\.zoho\.[a-z.]+$/.test(host)) return `https://${host}`
177+
// Otherwise map the data-center TLD from the API host (www.zohoapis.<tld> or
178+
// any zoho.<tld>) onto the Desk REST host in the same data center.
179+
const match = host.match(/zoho(?:apis)?\.([a-z.]+)$/)
180+
if (match?.[1]) return `https://desk.zoho.${match[1]}`
176181
return fallback
177182
} catch {
178183
return fallback

apps/sim/lib/webhooks/providers/zoho-desk.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,12 +339,19 @@ export const zohoDeskHandler: WebhookProviderHandler = {
339339
}
340340
},
341341

342-
async formatInput({ body }: FormatInputContext): Promise<FormatInputResult> {
342+
async formatInput({ body, requestId }: FormatInputContext): Promise<FormatInputResult> {
343343
// Zoho Desk delivers an array of events: [{ payload, prevState, eventTime, eventType, orgId }].
344344
// Anything that is not the expected array shape is passed through unchanged.
345345
if (!Array.isArray(body)) {
346346
return { input: body }
347347
}
348+
// Zoho fires one event per notification (single-element array). Log rather
349+
// than silently drop if that ever changes, so batched deliveries are visible.
350+
if (body.length > 1) {
351+
logger.warn(
352+
`[${requestId}] Zoho Desk delivered ${body.length} events in one payload; processing the first only`
353+
)
354+
}
348355
const event = body[0]
349356
if (!event || typeof event !== 'object') {
350357
return { input: body }

0 commit comments

Comments
 (0)