diff --git a/apps/sim/tools/confluence/utils.ts b/apps/sim/tools/confluence/utils.ts index 303464bdbf2..99c2fb17d70 100644 --- a/apps/sim/tools/confluence/utils.ts +++ b/apps/sim/tools/confluence/utils.ts @@ -1,6 +1,13 @@ import type { RetryOptions } from '@/lib/knowledge/documents/utils' import { fetchWithRetry } from '@/lib/knowledge/documents/utils' +function normalizeDomain(domain: string): string { + return `https://${domain + .trim() + .replace(/^https?:\/\//i, '') + .replace(/\/+$/, '')}`.toLowerCase() +} + export async function getConfluenceCloudId( domain: string, accessToken: string, @@ -20,20 +27,27 @@ export async function getConfluenceCloudId( const resources = await response.json() - if (Array.isArray(resources) && resources.length > 0) { - const normalizedInput = `https://${domain}`.toLowerCase() - const matchedResource = resources.find((r) => r.url.toLowerCase() === normalizedInput) + if (!Array.isArray(resources) || resources.length === 0) { + throw new Error('No Confluence resources found') + } + + const normalized = normalizeDomain(domain) + const match = resources.find( + (r: { url: string }) => r.url.toLowerCase().replace(/\/+$/, '') === normalized + ) - if (matchedResource) { - return matchedResource.id - } + if (match) { + return match.id } - if (Array.isArray(resources) && resources.length > 0) { + if (resources.length === 1) { return resources[0].id } - throw new Error('No Confluence resources found') + throw new Error( + `Could not match Confluence domain "${domain}" to any accessible resource. ` + + `Available sites: ${resources.map((r: { url: string }) => r.url).join(', ')}` + ) } function decodeHtmlEntities(text: string): string { diff --git a/apps/sim/tools/jira/utils.ts b/apps/sim/tools/jira/utils.ts index 1891eba2459..dbc34086a48 100644 --- a/apps/sim/tools/jira/utils.ts +++ b/apps/sim/tools/jira/utils.ts @@ -97,6 +97,13 @@ export async function downloadJiraAttachments( return downloaded } +function normalizeDomain(domain: string): string { + return `https://${domain + .trim() + .replace(/^https?:\/\//i, '') + .replace(/\/+$/, '')}`.toLowerCase() +} + export async function getJiraCloudId(domain: string, accessToken: string): Promise { const response = await fetchWithRetry( 'https://api.atlassian.com/oauth/token/accessible-resources', @@ -116,18 +123,25 @@ export async function getJiraCloudId(domain: string, accessToken: string): Promi const resources = await response.json() - if (Array.isArray(resources) && resources.length > 0) { - const normalizedInput = `https://${domain}`.toLowerCase() - const matchedResource = resources.find((r) => r.url.toLowerCase() === normalizedInput) + if (!Array.isArray(resources) || resources.length === 0) { + throw new Error('No Jira resources found') + } - if (matchedResource) { - return matchedResource.id - } + const normalized = normalizeDomain(domain) + const match = resources.find( + (r: { url: string }) => r.url.toLowerCase().replace(/\/+$/, '') === normalized + ) + + if (match) { + return match.id } - if (Array.isArray(resources) && resources.length > 0) { + if (resources.length === 1) { return resources[0].id } - throw new Error('No Jira resources found') + throw new Error( + `Could not match Jira domain "${domain}" to any accessible resource. ` + + `Available sites: ${resources.map((r: { url: string }) => r.url).join(', ')}` + ) }