From a71a23d877e9e3d1e46be6d50c9c543bcfa2c6f7 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 13 Apr 2026 14:12:52 -0700 Subject: [PATCH 1/4] fix(atlassian): unify error message extraction across all Jira, JSM, and Confluence routes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add parseAtlassianErrorMessage() to jira/utils.ts as single source of truth for parsing all 5 Atlassian error formats. Update 51 proxy routes (18 JSM, 5 Jira, 28 Confluence) to use it instead of hardcoded generic errors. Remove dead errorExtractor field from 95 Atlassian tool files — the compat loop in extractErrorMessage() already handles all formats without it. Consolidate duplicate parseJsmErrorMessage into a re-export from the shared utility. Co-Authored-By: Claude Opus 4.6 --- .../api/tools/confluence/attachment/route.ts | 12 ++-- .../api/tools/confluence/attachments/route.ts | 12 ++-- .../api/tools/confluence/blogposts/route.ts | 56 ++++++++++------- .../app/api/tools/confluence/comment/route.ts | 28 +++++---- .../api/tools/confluence/comments/route.ts | 23 +++---- .../api/tools/confluence/create-page/route.ts | 28 +++------ .../app/api/tools/confluence/labels/route.ts | 34 ++++++----- .../tools/confluence/page-ancestors/route.ts | 11 ++-- .../tools/confluence/page-children/route.ts | 11 ++-- .../confluence/page-descendants/route.ts | 12 ++-- .../tools/confluence/page-properties/route.ts | 45 +++++++------- .../tools/confluence/page-versions/route.ts | 28 ++++++--- .../app/api/tools/confluence/page/route.ts | 57 ++++++++++-------- .../tools/confluence/pages-by-label/route.ts | 11 ++-- .../app/api/tools/confluence/pages/route.ts | 31 ++++------ .../tools/confluence/search-in-space/route.ts | 11 ++-- .../app/api/tools/confluence/search/route.ts | 11 ++-- .../tools/confluence/selector-spaces/route.ts | 14 +++-- .../tools/confluence/space-blogposts/route.ts | 12 ++-- .../tools/confluence/space-labels/route.ts | 11 ++-- .../api/tools/confluence/space-pages/route.ts | 12 ++-- .../confluence/space-permissions/route.ts | 12 ++-- .../confluence/space-properties/route.ts | 34 ++++++----- .../app/api/tools/confluence/space/route.ts | 51 ++++++++++------ .../app/api/tools/confluence/spaces/route.ts | 12 ++-- .../app/api/tools/confluence/tasks/route.ts | 45 +++++++++----- .../confluence/upload-attachment/route.ts | 18 +++--- .../app/api/tools/confluence/user/route.ts | 12 ++-- .../api/tools/jira/add-attachment/route.ts | 4 +- apps/sim/app/api/tools/jira/issues/route.ts | 22 ++----- apps/sim/app/api/tools/jira/projects/route.ts | 24 ++++---- apps/sim/app/api/tools/jira/update/route.ts | 4 +- apps/sim/app/api/tools/jira/write/route.ts | 4 +- apps/sim/app/api/tools/jsm/approvals/route.ts | 17 +++++- apps/sim/app/api/tools/jsm/comment/route.ts | 12 +++- apps/sim/app/api/tools/jsm/comments/route.ts | 12 +++- apps/sim/app/api/tools/jsm/customers/route.ts | 17 +++++- .../app/api/tools/jsm/organization/route.ts | 17 +++++- .../app/api/tools/jsm/organizations/route.ts | 12 +++- .../app/api/tools/jsm/participants/route.ts | 17 +++++- apps/sim/app/api/tools/jsm/queues/route.ts | 12 +++- apps/sim/app/api/tools/jsm/request/route.ts | 44 +++++++------- apps/sim/app/api/tools/jsm/requests/route.ts | 12 +++- .../api/tools/jsm/requesttypefields/route.ts | 12 +++- .../app/api/tools/jsm/requesttypes/route.ts | 12 +++- .../tools/jsm/selector-requesttypes/route.ts | 9 ++- .../tools/jsm/selector-servicedesks/route.ts | 9 ++- .../app/api/tools/jsm/servicedesks/route.ts | 12 +++- apps/sim/app/api/tools/jsm/sla/route.ts | 12 +++- .../sim/app/api/tools/jsm/transition/route.ts | 12 +++- .../app/api/tools/jsm/transitions/route.ts | 12 +++- .../blocks/blocks/jira_service_management.ts | 2 +- apps/sim/tools/confluence/add_label.ts | 2 - apps/sim/tools/confluence/create_blogpost.ts | 2 - apps/sim/tools/confluence/create_comment.ts | 2 - apps/sim/tools/confluence/create_page.ts | 2 - .../tools/confluence/create_page_property.ts | 2 - apps/sim/tools/confluence/create_space.ts | 2 - .../tools/confluence/create_space_property.ts | 2 - .../sim/tools/confluence/delete_attachment.ts | 2 - apps/sim/tools/confluence/delete_blogpost.ts | 2 - apps/sim/tools/confluence/delete_comment.ts | 2 - apps/sim/tools/confluence/delete_label.ts | 2 - apps/sim/tools/confluence/delete_page.ts | 2 - .../tools/confluence/delete_page_property.ts | 2 - apps/sim/tools/confluence/delete_space.ts | 2 - .../tools/confluence/delete_space_property.ts | 2 - apps/sim/tools/confluence/get_blogpost.ts | 2 - .../tools/confluence/get_page_ancestors.ts | 2 - .../sim/tools/confluence/get_page_children.ts | 2 - .../tools/confluence/get_page_descendants.ts | 2 - apps/sim/tools/confluence/get_page_version.ts | 2 - .../tools/confluence/get_pages_by_label.ts | 2 - apps/sim/tools/confluence/get_space.ts | 2 - apps/sim/tools/confluence/get_task.ts | 2 - apps/sim/tools/confluence/get_user.ts | 2 - apps/sim/tools/confluence/list_attachments.ts | 2 - apps/sim/tools/confluence/list_blogposts.ts | 2 - .../confluence/list_blogposts_in_space.ts | 2 - apps/sim/tools/confluence/list_comments.ts | 2 - apps/sim/tools/confluence/list_labels.ts | 2 - .../tools/confluence/list_page_properties.ts | 2 - .../tools/confluence/list_page_versions.ts | 2 - .../tools/confluence/list_pages_in_space.ts | 2 - .../sim/tools/confluence/list_space_labels.ts | 2 - .../confluence/list_space_permissions.ts | 2 - .../tools/confluence/list_space_properties.ts | 2 - apps/sim/tools/confluence/list_spaces.ts | 2 - apps/sim/tools/confluence/list_tasks.ts | 2 - apps/sim/tools/confluence/retrieve.ts | 2 - apps/sim/tools/confluence/search.ts | 2 - apps/sim/tools/confluence/search_in_space.ts | 2 - apps/sim/tools/confluence/update.ts | 2 - apps/sim/tools/confluence/update_blogpost.ts | 2 - apps/sim/tools/confluence/update_comment.ts | 2 - apps/sim/tools/confluence/update_space.ts | 2 - apps/sim/tools/confluence/update_task.ts | 2 - .../sim/tools/confluence/upload_attachment.ts | 2 - apps/sim/tools/jira/add_attachment.ts | 2 - apps/sim/tools/jira/add_comment.ts | 2 - apps/sim/tools/jira/add_watcher.ts | 2 - apps/sim/tools/jira/add_worklog.ts | 2 - apps/sim/tools/jira/assign_issue.ts | 2 - apps/sim/tools/jira/bulk_read.ts | 2 - apps/sim/tools/jira/create_issue_link.ts | 2 - apps/sim/tools/jira/delete_attachment.ts | 2 - apps/sim/tools/jira/delete_comment.ts | 2 - apps/sim/tools/jira/delete_issue.ts | 2 - apps/sim/tools/jira/delete_issue_link.ts | 2 - apps/sim/tools/jira/delete_worklog.ts | 2 - apps/sim/tools/jira/get_attachments.ts | 2 - apps/sim/tools/jira/get_comments.ts | 2 - apps/sim/tools/jira/get_users.ts | 2 - apps/sim/tools/jira/get_worklogs.ts | 2 - apps/sim/tools/jira/remove_watcher.ts | 2 - apps/sim/tools/jira/retrieve.ts | 2 - apps/sim/tools/jira/search_issues.ts | 2 - apps/sim/tools/jira/search_users.ts | 2 - apps/sim/tools/jira/transition_issue.ts | 2 - apps/sim/tools/jira/update.ts | 2 - apps/sim/tools/jira/update_comment.ts | 2 - apps/sim/tools/jira/update_worklog.ts | 2 - apps/sim/tools/jira/utils.ts | 41 +++++++++++++ apps/sim/tools/jira/write.ts | 2 - apps/sim/tools/jsm/add_comment.ts | 2 - apps/sim/tools/jsm/add_customer.ts | 2 - apps/sim/tools/jsm/add_organization.ts | 2 - apps/sim/tools/jsm/add_participants.ts | 2 - apps/sim/tools/jsm/answer_approval.ts | 2 - apps/sim/tools/jsm/create_organization.ts | 2 - apps/sim/tools/jsm/create_request.ts | 4 +- apps/sim/tools/jsm/get_approvals.ts | 2 - apps/sim/tools/jsm/get_comments.ts | 2 - apps/sim/tools/jsm/get_customers.ts | 2 - apps/sim/tools/jsm/get_form_structure.ts | 2 - apps/sim/tools/jsm/get_form_templates.ts | 2 - apps/sim/tools/jsm/get_issue_forms.ts | 2 - apps/sim/tools/jsm/get_organizations.ts | 2 - apps/sim/tools/jsm/get_participants.ts | 2 - apps/sim/tools/jsm/get_queues.ts | 2 - apps/sim/tools/jsm/get_request.ts | 2 - apps/sim/tools/jsm/get_request_type_fields.ts | 2 - apps/sim/tools/jsm/get_request_types.ts | 2 - apps/sim/tools/jsm/get_requests.ts | 2 - apps/sim/tools/jsm/get_service_desks.ts | 2 - apps/sim/tools/jsm/get_sla.ts | 2 - apps/sim/tools/jsm/get_transitions.ts | 2 - apps/sim/tools/jsm/transition_request.ts | 2 - apps/sim/tools/jsm/utils.ts | 60 ++++--------------- 149 files changed, 651 insertions(+), 618 deletions(-) diff --git a/apps/sim/app/api/tools/confluence/attachment/route.ts b/apps/sim/app/api/tools/confluence/attachment/route.ts index f0265fe1f29..f87b22c2243 100644 --- a/apps/sim/app/api/tools/confluence/attachment/route.ts +++ b/apps/sim/app/api/tools/confluence/attachment/route.ts @@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluenceAttachmentAPI') @@ -53,15 +54,16 @@ export async function DELETE(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to delete Confluence attachment (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } return NextResponse.json({ attachmentId, deleted: true }) diff --git a/apps/sim/app/api/tools/confluence/attachments/route.ts b/apps/sim/app/api/tools/confluence/attachments/route.ts index 4d25840bde9..9935626eb99 100644 --- a/apps/sim/app/api/tools/confluence/attachments/route.ts +++ b/apps/sim/app/api/tools/confluence/attachments/route.ts @@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluenceAttachmentsAPI') @@ -64,15 +65,16 @@ export async function GET(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to list Confluence attachments (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() diff --git a/apps/sim/app/api/tools/confluence/blogposts/route.ts b/apps/sim/app/api/tools/confluence/blogposts/route.ts index cdfa12f5935..abb95ac321b 100644 --- a/apps/sim/app/api/tools/confluence/blogposts/route.ts +++ b/apps/sim/app/api/tools/confluence/blogposts/route.ts @@ -4,6 +4,7 @@ import { z } from 'zod' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluenceBlogPostsAPI') @@ -98,14 +99,16 @@ export async function GET(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = errorData?.message || `Failed to list blog posts (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() @@ -197,14 +200,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = errorData?.message || `Failed to create blog post (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() @@ -253,14 +258,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = errorData?.message || `Failed to get blog post (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() @@ -326,7 +333,10 @@ export async function PUT(request: NextRequest) { }) if (!currentResponse.ok) { - throw new Error(`Failed to fetch current blog post: ${currentResponse.status}`) + const errorText = await currentResponse.text() + throw new Error( + parseAtlassianErrorMessage(currentResponse.status, currentResponse.statusText, errorText) + ) } const currentPost = await currentResponse.json() @@ -362,14 +372,16 @@ export async function PUT(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = errorData?.message || `Failed to update blog post (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() @@ -426,14 +438,16 @@ export async function DELETE(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = errorData?.message || `Failed to delete blog post (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } return NextResponse.json({ blogPostId, deleted: true }) diff --git a/apps/sim/app/api/tools/confluence/comment/route.ts b/apps/sim/app/api/tools/confluence/comment/route.ts index 3486f975a5d..0da0754311f 100644 --- a/apps/sim/app/api/tools/confluence/comment/route.ts +++ b/apps/sim/app/api/tools/confluence/comment/route.ts @@ -4,6 +4,7 @@ import { z } from 'zod' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluenceCommentAPI') @@ -81,7 +82,10 @@ export async function PUT(request: NextRequest) { }) if (!getResponse.ok) { - throw new Error(`Failed to fetch current comment: ${getResponse.status}`) + const errorText = await getResponse.text() + throw new Error( + parseAtlassianErrorMessage(getResponse.status, getResponse.statusText, errorText) + ) } const currentComment = await getResponse.json() @@ -111,15 +115,16 @@ export async function PUT(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to update Confluence comment (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() @@ -169,15 +174,16 @@ export async function DELETE(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to delete Confluence comment (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } return NextResponse.json({ commentId, deleted: true }) diff --git a/apps/sim/app/api/tools/confluence/comments/route.ts b/apps/sim/app/api/tools/confluence/comments/route.ts index 8c7b03ac044..9d9cb7706d9 100644 --- a/apps/sim/app/api/tools/confluence/comments/route.ts +++ b/apps/sim/app/api/tools/confluence/comments/route.ts @@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluenceCommentsAPI') @@ -69,15 +70,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to create Confluence comment (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() @@ -149,15 +151,16 @@ export async function GET(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to list Confluence comments (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() diff --git a/apps/sim/app/api/tools/confluence/create-page/route.ts b/apps/sim/app/api/tools/confluence/create-page/route.ts index c11dbbc7f62..38a8d5ea940 100644 --- a/apps/sim/app/api/tools/confluence/create-page/route.ts +++ b/apps/sim/app/api/tools/confluence/create-page/route.ts @@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluenceCreatePageAPI') @@ -101,31 +102,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - - let errorMessage = `Failed to create Confluence page (${response.status})` - if (errorData?.message) { - errorMessage = errorData.message - } else if (errorData?.errors && Array.isArray(errorData.errors)) { - const firstError = errorData.errors[0] - if (firstError?.title) { - if (firstError.title.includes("'spaceId'") && firstError.title.includes('Long')) { - errorMessage = - 'Invalid Space ID. Use the list spaces operation to find valid space IDs.' - } else { - errorMessage = firstError.title - } - } else { - errorMessage = JSON.stringify(errorData.errors) - } - } - - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() diff --git a/apps/sim/app/api/tools/confluence/labels/route.ts b/apps/sim/app/api/tools/confluence/labels/route.ts index 020811ff653..97fa0bf0740 100644 --- a/apps/sim/app/api/tools/confluence/labels/route.ts +++ b/apps/sim/app/api/tools/confluence/labels/route.ts @@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluenceLabelsAPI') @@ -73,15 +74,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to add Confluence label (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() @@ -158,15 +160,16 @@ export async function GET(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to list Confluence labels (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() @@ -248,15 +251,16 @@ export async function DELETE(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to delete Confluence label (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } return NextResponse.json({ diff --git a/apps/sim/app/api/tools/confluence/page-ancestors/route.ts b/apps/sim/app/api/tools/confluence/page-ancestors/route.ts index 743cce75a5f..a19c9409dbc 100644 --- a/apps/sim/app/api/tools/confluence/page-ancestors/route.ts +++ b/apps/sim/app/api/tools/confluence/page-ancestors/route.ts @@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluencePageAncestorsAPI') @@ -62,14 +63,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = errorData?.message || `Failed to get page ancestors (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() diff --git a/apps/sim/app/api/tools/confluence/page-children/route.ts b/apps/sim/app/api/tools/confluence/page-children/route.ts index 7cd7a41bd0e..9f6ce831d91 100644 --- a/apps/sim/app/api/tools/confluence/page-children/route.ts +++ b/apps/sim/app/api/tools/confluence/page-children/route.ts @@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluencePageChildrenAPI') @@ -66,14 +67,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = errorData?.message || `Failed to get child pages (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() diff --git a/apps/sim/app/api/tools/confluence/page-descendants/route.ts b/apps/sim/app/api/tools/confluence/page-descendants/route.ts index e437b737503..7a83448f118 100644 --- a/apps/sim/app/api/tools/confluence/page-descendants/route.ts +++ b/apps/sim/app/api/tools/confluence/page-descendants/route.ts @@ -7,6 +7,7 @@ import { validatePaginationCursor, } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluencePageDescendantsAPI') @@ -74,15 +75,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to get page descendants (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() diff --git a/apps/sim/app/api/tools/confluence/page-properties/route.ts b/apps/sim/app/api/tools/confluence/page-properties/route.ts index f8c3ce0ee29..8faca8da5f9 100644 --- a/apps/sim/app/api/tools/confluence/page-properties/route.ts +++ b/apps/sim/app/api/tools/confluence/page-properties/route.ts @@ -4,6 +4,7 @@ import { z } from 'zod' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluencePagePropertiesAPI') @@ -95,15 +96,16 @@ export async function GET(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to list page properties (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() @@ -176,15 +178,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to create page property (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() @@ -267,15 +270,16 @@ export async function PUT(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to update page property (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() @@ -343,15 +347,16 @@ export async function DELETE(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to delete page property (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } return NextResponse.json({ propertyId, pageId, deleted: true }) diff --git a/apps/sim/app/api/tools/confluence/page-versions/route.ts b/apps/sim/app/api/tools/confluence/page-versions/route.ts index 799fc28b0a9..6f328e534a7 100644 --- a/apps/sim/app/api/tools/confluence/page-versions/route.ts +++ b/apps/sim/app/api/tools/confluence/page-versions/route.ts @@ -8,6 +8,7 @@ import { validatePaginationCursor, } from '@/lib/core/security/input-validation' import { cleanHtmlContent, getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluencePageVersionsAPI') @@ -91,15 +92,22 @@ export async function POST(request: NextRequest) { ]) if (!versionResponse.ok) { - const errorData = await versionResponse.json().catch(() => null) + const errorText = await versionResponse.text() logger.error('Confluence API error response:', { status: versionResponse.status, statusText: versionResponse.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to get page version (${versionResponse.status})` - return NextResponse.json({ error: errorMessage }, { status: versionResponse.status }) + return NextResponse.json( + { + error: parseAtlassianErrorMessage( + versionResponse.status, + versionResponse.statusText, + errorText + ), + }, + { status: versionResponse.status } + ) } const versionData = await versionResponse.json() @@ -166,14 +174,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = errorData?.message || `Failed to list page versions (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() diff --git a/apps/sim/app/api/tools/confluence/page/route.ts b/apps/sim/app/api/tools/confluence/page/route.ts index 191ddcef6f6..b3d9ea72f32 100644 --- a/apps/sim/app/api/tools/confluence/page/route.ts +++ b/apps/sim/app/api/tools/confluence/page/route.ts @@ -4,6 +4,7 @@ import { z } from 'zod' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluencePageAPI') @@ -110,19 +111,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - logger.error(`Confluence API error: ${response.status} ${response.statusText}`) - let errorMessage - - try { - const errorData = await response.json() - logger.error('Error details:', JSON.stringify(errorData, null, 2)) - errorMessage = errorData.message || `Failed to fetch Confluence page (${response.status})` - } catch (e) { - logger.error('Could not parse error response as JSON:', e) - errorMessage = `Failed to fetch Confluence page: ${response.status} ${response.statusText}` - } - - return NextResponse.json({ error: errorMessage }, { status: response.status }) + const errorText = await response.text() + logger.error('Confluence API error response:', { + status: response.status, + statusText: response.statusText, + error: errorText, + }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() @@ -194,7 +192,14 @@ export async function PUT(request: NextRequest) { }) if (!currentPageResponse.ok) { - throw new Error(`Failed to fetch current page: ${currentPageResponse.status}`) + const errorText = await currentPageResponse.text() + throw new Error( + parseAtlassianErrorMessage( + currentPageResponse.status, + currentPageResponse.statusText, + errorText + ) + ) } const currentPage = await currentPageResponse.json() @@ -238,17 +243,16 @@ export async function PUT(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || - (errorData?.errors && JSON.stringify(errorData.errors)) || - `Failed to update Confluence page (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() @@ -302,15 +306,16 @@ export async function DELETE(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to delete Confluence page (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } return NextResponse.json({ pageId, deleted: true }) diff --git a/apps/sim/app/api/tools/confluence/pages-by-label/route.ts b/apps/sim/app/api/tools/confluence/pages-by-label/route.ts index bef62261690..85d99b7ca09 100644 --- a/apps/sim/app/api/tools/confluence/pages-by-label/route.ts +++ b/apps/sim/app/api/tools/confluence/pages-by-label/route.ts @@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluencePagesByLabelAPI') @@ -63,14 +64,16 @@ export async function GET(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = errorData?.message || `Failed to get pages by label (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() diff --git a/apps/sim/app/api/tools/confluence/pages/route.ts b/apps/sim/app/api/tools/confluence/pages/route.ts index 739dc06591c..949a27de427 100644 --- a/apps/sim/app/api/tools/confluence/pages/route.ts +++ b/apps/sim/app/api/tools/confluence/pages/route.ts @@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateJiraCloudId } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluencePagesAPI') @@ -66,26 +67,16 @@ export async function POST(request: NextRequest) { logger.info('Response status:', response.status, response.statusText) if (!response.ok) { - logger.error(`Confluence API error: ${response.status} ${response.statusText}`) - let errorMessage - - try { - const errorData = await response.json() - logger.error('Error details:', JSON.stringify(errorData, null, 2)) - errorMessage = errorData.message || `Failed to fetch Confluence pages (${response.status})` - } catch (e) { - logger.error('Could not parse error response as JSON:', e) - - try { - const text = await response.text() - logger.error('Response text:', text) - errorMessage = `Failed to fetch Confluence pages: ${response.status} ${response.statusText}` - } catch (_textError) { - errorMessage = `Failed to fetch Confluence pages: ${response.status} ${response.statusText}` - } - } - - return NextResponse.json({ error: errorMessage }, { status: response.status }) + const errorText = await response.text() + logger.error('Confluence API error response:', { + status: response.status, + statusText: response.statusText, + error: errorText, + }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() diff --git a/apps/sim/app/api/tools/confluence/search-in-space/route.ts b/apps/sim/app/api/tools/confluence/search-in-space/route.ts index 8a3dcf1a159..55638857d5b 100644 --- a/apps/sim/app/api/tools/confluence/search-in-space/route.ts +++ b/apps/sim/app/api/tools/confluence/search-in-space/route.ts @@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluenceSearchInSpaceAPI') @@ -83,14 +84,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = errorData?.message || `Failed to search in space (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() diff --git a/apps/sim/app/api/tools/confluence/search/route.ts b/apps/sim/app/api/tools/confluence/search/route.ts index f31f992797f..901ffcc39bb 100644 --- a/apps/sim/app/api/tools/confluence/search/route.ts +++ b/apps/sim/app/api/tools/confluence/search/route.ts @@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateJiraCloudId } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' export const dynamic = 'force-dynamic' @@ -60,14 +61,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = errorData?.message || `Failed to search Confluence (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() diff --git a/apps/sim/app/api/tools/confluence/selector-spaces/route.ts b/apps/sim/app/api/tools/confluence/selector-spaces/route.ts index 7ae61d3e983..cd94c4a1ddb 100644 --- a/apps/sim/app/api/tools/confluence/selector-spaces/route.ts +++ b/apps/sim/app/api/tools/confluence/selector-spaces/route.ts @@ -5,6 +5,7 @@ import { validateJiraCloudId } from '@/lib/core/security/input-validation' import { generateRequestId } from '@/lib/core/utils/request' import { refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluenceSelectorSpacesAPI') @@ -67,15 +68,16 @@ export async function POST(request: Request) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) - logger.error('Confluence API error:', { + const errorText = await response.text() + logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: errorData, + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to list Confluence spaces (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() diff --git a/apps/sim/app/api/tools/confluence/space-blogposts/route.ts b/apps/sim/app/api/tools/confluence/space-blogposts/route.ts index 4607f9f57e7..ffad0fd50a9 100644 --- a/apps/sim/app/api/tools/confluence/space-blogposts/route.ts +++ b/apps/sim/app/api/tools/confluence/space-blogposts/route.ts @@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluenceSpaceBlogPostsAPI') @@ -83,15 +84,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to list blog posts in space (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() diff --git a/apps/sim/app/api/tools/confluence/space-labels/route.ts b/apps/sim/app/api/tools/confluence/space-labels/route.ts index be28cd2c92d..4af4dd9d016 100644 --- a/apps/sim/app/api/tools/confluence/space-labels/route.ts +++ b/apps/sim/app/api/tools/confluence/space-labels/route.ts @@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluenceSpaceLabelsAPI') @@ -63,14 +64,16 @@ export async function GET(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = errorData?.message || `Failed to list space labels (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() diff --git a/apps/sim/app/api/tools/confluence/space-pages/route.ts b/apps/sim/app/api/tools/confluence/space-pages/route.ts index fcf17efa0cf..086ea56fa86 100644 --- a/apps/sim/app/api/tools/confluence/space-pages/route.ts +++ b/apps/sim/app/api/tools/confluence/space-pages/route.ts @@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluenceSpacePagesAPI') @@ -83,15 +84,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to list pages in space (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() diff --git a/apps/sim/app/api/tools/confluence/space-permissions/route.ts b/apps/sim/app/api/tools/confluence/space-permissions/route.ts index 8a046a0f6c3..7f8a652acd5 100644 --- a/apps/sim/app/api/tools/confluence/space-permissions/route.ts +++ b/apps/sim/app/api/tools/confluence/space-permissions/route.ts @@ -7,6 +7,7 @@ import { validatePaginationCursor, } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluenceSpacePermissionsAPI') @@ -74,15 +75,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to list space permissions (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() diff --git a/apps/sim/app/api/tools/confluence/space-properties/route.ts b/apps/sim/app/api/tools/confluence/space-properties/route.ts index 5bdd176aff8..588822de507 100644 --- a/apps/sim/app/api/tools/confluence/space-properties/route.ts +++ b/apps/sim/app/api/tools/confluence/space-properties/route.ts @@ -7,6 +7,7 @@ import { validatePaginationCursor, } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluenceSpacePropertiesAPI') @@ -99,15 +100,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to delete space property (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } return NextResponse.json({ spaceId, propertyId, deleted: true }) @@ -128,15 +130,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to create space property (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() @@ -173,15 +176,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to list space properties (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() diff --git a/apps/sim/app/api/tools/confluence/space/route.ts b/apps/sim/app/api/tools/confluence/space/route.ts index ffe58f037a0..cdb0d316fa6 100644 --- a/apps/sim/app/api/tools/confluence/space/route.ts +++ b/apps/sim/app/api/tools/confluence/space/route.ts @@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluenceSpaceAPI') @@ -57,15 +58,16 @@ export async function GET(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to get Confluence space (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() @@ -136,14 +138,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = errorData?.message || `Failed to create space (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() @@ -216,8 +220,15 @@ export async function PUT(request: NextRequest) { }, }) if (!currentResponse.ok) { + const errorText = await currentResponse.text() return NextResponse.json( - { error: `Failed to fetch current space: ${currentResponse.status}` }, + { + error: parseAtlassianErrorMessage( + currentResponse.status, + currentResponse.statusText, + errorText + ), + }, { status: currentResponse.status } ) } @@ -242,14 +253,16 @@ export async function PUT(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = errorData?.message || `Failed to update space (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() @@ -314,14 +327,16 @@ export async function DELETE(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = errorData?.message || `Failed to delete space (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } return NextResponse.json({ spaceId, deleted: true }) diff --git a/apps/sim/app/api/tools/confluence/spaces/route.ts b/apps/sim/app/api/tools/confluence/spaces/route.ts index 0ce8dd0ee81..066b0812044 100644 --- a/apps/sim/app/api/tools/confluence/spaces/route.ts +++ b/apps/sim/app/api/tools/confluence/spaces/route.ts @@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateJiraCloudId } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluenceSpacesAPI') @@ -54,15 +55,16 @@ export async function GET(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to list Confluence spaces (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() diff --git a/apps/sim/app/api/tools/confluence/tasks/route.ts b/apps/sim/app/api/tools/confluence/tasks/route.ts index e74ca3b5400..c6b1dae4b07 100644 --- a/apps/sim/app/api/tools/confluence/tasks/route.ts +++ b/apps/sim/app/api/tools/confluence/tasks/route.ts @@ -8,6 +8,7 @@ import { validatePathSegment, } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluenceTasksAPI') @@ -72,9 +73,17 @@ export async function POST(request: NextRequest) { }) if (!getResponse.ok) { - const errorData = await getResponse.json().catch(() => null) - const errorMessage = errorData?.message || `Failed to fetch task (${getResponse.status})` - return NextResponse.json({ error: errorMessage }, { status: getResponse.status }) + const errorText = await getResponse.text() + return NextResponse.json( + { + error: parseAtlassianErrorMessage( + getResponse.status, + getResponse.statusText, + errorText + ), + }, + { status: getResponse.status } + ) } const currentTask = await getResponse.json() @@ -99,14 +108,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = errorData?.message || `Failed to update task (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() @@ -150,14 +161,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = errorData?.message || `Failed to get task (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() @@ -233,14 +246,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = errorData?.message || `Failed to list tasks (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() diff --git a/apps/sim/app/api/tools/confluence/upload-attachment/route.ts b/apps/sim/app/api/tools/confluence/upload-attachment/route.ts index 599d70b7540..ab18f49e784 100644 --- a/apps/sim/app/api/tools/confluence/upload-attachment/route.ts +++ b/apps/sim/app/api/tools/confluence/upload-attachment/route.ts @@ -5,6 +5,7 @@ import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security import { processSingleFileToUserFile } from '@/lib/uploads/utils/file-utils' import { downloadFileFromStorage } from '@/lib/uploads/utils/file-utils.server' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluenceUploadAttachmentAPI') @@ -105,21 +106,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - - let errorMessage = `Failed to upload attachment to Confluence (${response.status})` - if (errorData?.message) { - errorMessage = errorData.message - } else if (errorData?.errorMessage) { - errorMessage = errorData.errorMessage - } - - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() diff --git a/apps/sim/app/api/tools/confluence/user/route.ts b/apps/sim/app/api/tools/confluence/user/route.ts index 5b81116d804..306722e9bda 100644 --- a/apps/sim/app/api/tools/confluence/user/route.ts +++ b/apps/sim/app/api/tools/confluence/user/route.ts @@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateJiraCloudId, validatePathSegment } from '@/lib/core/security/input-validation' import { getConfluenceCloudId } from '@/tools/confluence/utils' +import { parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('ConfluenceUserAPI') @@ -62,15 +63,16 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json().catch(() => null) + const errorText = await response.text() logger.error('Confluence API error response:', { status: response.status, statusText: response.statusText, - error: JSON.stringify(errorData, null, 2), + error: errorText, }) - const errorMessage = - errorData?.message || `Failed to get Confluence user (${response.status})` - return NextResponse.json({ error: errorMessage }, { status: response.status }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() diff --git a/apps/sim/app/api/tools/jira/add-attachment/route.ts b/apps/sim/app/api/tools/jira/add-attachment/route.ts index 110a915703b..2b5e39fa255 100644 --- a/apps/sim/app/api/tools/jira/add-attachment/route.ts +++ b/apps/sim/app/api/tools/jira/add-attachment/route.ts @@ -5,7 +5,7 @@ import { checkInternalAuth } from '@/lib/auth/hybrid' import { RawFileInputArraySchema } from '@/lib/uploads/utils/file-schemas' import { processFilesToUserFiles } from '@/lib/uploads/utils/file-utils' import { downloadFileFromStorage } from '@/lib/uploads/utils/file-utils.server' -import { getJiraCloudId } from '@/tools/jira/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' const logger = createLogger('JiraAddAttachmentAPI') @@ -77,7 +77,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { success: false, - error: `Failed to upload attachments: ${response.statusText}`, + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), }, { status: response.status } ) diff --git a/apps/sim/app/api/tools/jira/issues/route.ts b/apps/sim/app/api/tools/jira/issues/route.ts index dfebb1d9e16..673123f9fe9 100644 --- a/apps/sim/app/api/tools/jira/issues/route.ts +++ b/apps/sim/app/api/tools/jira/issues/route.ts @@ -2,19 +2,15 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' -import { getJiraCloudId } from '@/tools/jira/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' export const dynamic = 'force-dynamic' const logger = createLogger('JiraIssuesAPI') -const createErrorResponse = async (response: Response, defaultMessage: string) => { - try { - const errorData = await response.json() - return errorData.message || errorData.errorMessages?.[0] || defaultMessage - } catch { - return defaultMessage - } +const createErrorResponse = async (response: Response) => { + const errorText = await response.text().catch(() => '') + return parseAtlassianErrorMessage(response.status, response.statusText, errorText) } const validateRequiredParams = (domain: string | null, accessToken: string | null) => { @@ -70,10 +66,7 @@ export async function POST(request: NextRequest) { if (!response.ok) { logger.error(`Jira API error: ${response.status} ${response.statusText}`) - const errorMessage = await createErrorResponse( - response, - `Failed to fetch Jira issues (${response.status})` - ) + const errorMessage = await createErrorResponse(response) if (response.status === 401 || response.status === 403) { return NextResponse.json( { @@ -199,10 +192,7 @@ export async function GET(request: NextRequest) { }) if (!response.ok) { - const errorMessage = await createErrorResponse( - response, - `Failed to fetch issues (${response.status})` - ) + const errorMessage = await createErrorResponse(response) if (response.status === 401 || response.status === 403) { return NextResponse.json( { diff --git a/apps/sim/app/api/tools/jira/projects/route.ts b/apps/sim/app/api/tools/jira/projects/route.ts index 994320cb463..a2b1b4aad42 100644 --- a/apps/sim/app/api/tools/jira/projects/route.ts +++ b/apps/sim/app/api/tools/jira/projects/route.ts @@ -2,7 +2,7 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' -import { getJiraCloudId } from '@/tools/jira/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' export const dynamic = 'force-dynamic' @@ -60,16 +60,12 @@ export async function GET(request: NextRequest) { logger.info(`Response status: ${response.status} ${response.statusText}`) if (!response.ok) { - logger.error(`Jira API error: ${response.status} ${response.statusText}`) - let errorMessage - try { - const errorData = await response.json() - logger.error('Error details:', errorData) - errorMessage = errorData.message || `Failed to fetch projects (${response.status})` - } catch (_e) { - errorMessage = `Failed to fetch projects: ${response.status} ${response.statusText}` - } - return NextResponse.json({ error: errorMessage }, { status: response.status }) + const errorText = await response.text() + logger.error('Jira API error:', { status: response.status, error: errorText }) + return NextResponse.json( + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { status: response.status } + ) } const data = await response.json() @@ -148,10 +144,10 @@ export async function POST(request: NextRequest) { }) if (!response.ok) { - const errorData = await response.json() - logger.error('Error details:', errorData) + const errorText = await response.text() + logger.error('Jira API error:', { status: response.status, error: errorText }) return NextResponse.json( - { error: errorData.message || `Failed to fetch project (${response.status})` }, + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, { status: response.status } ) } diff --git a/apps/sim/app/api/tools/jira/update/route.ts b/apps/sim/app/api/tools/jira/update/route.ts index c77dceb41b1..7fad78159c0 100644 --- a/apps/sim/app/api/tools/jira/update/route.ts +++ b/apps/sim/app/api/tools/jira/update/route.ts @@ -3,7 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server' import { z } from 'zod' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation' -import { getJiraCloudId } from '@/tools/jira/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' export const dynamic = 'force-dynamic' @@ -188,7 +188,7 @@ export async function PUT(request: NextRequest) { }) return NextResponse.json( - { error: `Jira API error: ${response.status} ${response.statusText}`, details: errorText }, + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, { status: response.status } ) } diff --git a/apps/sim/app/api/tools/jira/write/route.ts b/apps/sim/app/api/tools/jira/write/route.ts index cf3168e751e..c7a89c80d9d 100644 --- a/apps/sim/app/api/tools/jira/write/route.ts +++ b/apps/sim/app/api/tools/jira/write/route.ts @@ -2,7 +2,7 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' -import { getJiraCloudId } from '@/tools/jira/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' export const dynamic = 'force-dynamic' @@ -197,7 +197,7 @@ export async function POST(request: NextRequest) { }) return NextResponse.json( - { error: `Jira API error: ${response.status} ${response.statusText}`, details: errorText }, + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, { status: response.status } ) } diff --git a/apps/sim/app/api/tools/jsm/approvals/route.ts b/apps/sim/app/api/tools/jsm/approvals/route.ts index e579121e8b5..26c15e753c6 100644 --- a/apps/sim/app/api/tools/jsm/approvals/route.ts +++ b/apps/sim/app/api/tools/jsm/approvals/route.ts @@ -7,7 +7,12 @@ import { validateJiraCloudId, validateJiraIssueKey, } from '@/lib/core/security/input-validation' -import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' +import { + getJiraCloudId, + getJsmApiBaseUrl, + getJsmHeaders, + parseJsmErrorMessage, +} from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -98,7 +103,10 @@ export async function POST(request: NextRequest) { }) return NextResponse.json( - { error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText }, + { + error: parseJsmErrorMessage(response.status, response.statusText, errorText), + details: errorText, + }, { status: response.status } ) } @@ -151,7 +159,10 @@ export async function POST(request: NextRequest) { }) return NextResponse.json( - { error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText }, + { + error: parseJsmErrorMessage(response.status, response.statusText, errorText), + details: errorText, + }, { status: response.status } ) } diff --git a/apps/sim/app/api/tools/jsm/comment/route.ts b/apps/sim/app/api/tools/jsm/comment/route.ts index 946a17bb20b..8f75209ec18 100644 --- a/apps/sim/app/api/tools/jsm/comment/route.ts +++ b/apps/sim/app/api/tools/jsm/comment/route.ts @@ -2,7 +2,12 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation' -import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' +import { + getJiraCloudId, + getJsmApiBaseUrl, + getJsmHeaders, + parseJsmErrorMessage, +} from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -80,7 +85,10 @@ export async function POST(request: NextRequest) { }) return NextResponse.json( - { error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText }, + { + error: parseJsmErrorMessage(response.status, response.statusText, errorText), + details: errorText, + }, { status: response.status } ) } diff --git a/apps/sim/app/api/tools/jsm/comments/route.ts b/apps/sim/app/api/tools/jsm/comments/route.ts index d68c51b8bd3..9c4a4a4e874 100644 --- a/apps/sim/app/api/tools/jsm/comments/route.ts +++ b/apps/sim/app/api/tools/jsm/comments/route.ts @@ -2,7 +2,12 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation' -import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' +import { + getJiraCloudId, + getJsmApiBaseUrl, + getJsmHeaders, + parseJsmErrorMessage, +} from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -82,7 +87,10 @@ export async function POST(request: NextRequest) { }) return NextResponse.json( - { error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText }, + { + error: parseJsmErrorMessage(response.status, response.statusText, errorText), + details: errorText, + }, { status: response.status } ) } diff --git a/apps/sim/app/api/tools/jsm/customers/route.ts b/apps/sim/app/api/tools/jsm/customers/route.ts index cf9fcf7e63d..7cd11ab5798 100644 --- a/apps/sim/app/api/tools/jsm/customers/route.ts +++ b/apps/sim/app/api/tools/jsm/customers/route.ts @@ -2,7 +2,12 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' -import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' +import { + getJiraCloudId, + getJsmApiBaseUrl, + getJsmHeaders, + parseJsmErrorMessage, +} from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -95,7 +100,10 @@ export async function POST(request: NextRequest) { }) return NextResponse.json( - { error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText }, + { + error: parseJsmErrorMessage(response.status, response.statusText, errorText), + details: errorText, + }, { status: response.status } ) } @@ -132,7 +140,10 @@ export async function POST(request: NextRequest) { }) return NextResponse.json( - { error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText }, + { + error: parseJsmErrorMessage(response.status, response.statusText, errorText), + details: errorText, + }, { status: response.status } ) } diff --git a/apps/sim/app/api/tools/jsm/organization/route.ts b/apps/sim/app/api/tools/jsm/organization/route.ts index c0fc932035f..97d1bb2c9b6 100644 --- a/apps/sim/app/api/tools/jsm/organization/route.ts +++ b/apps/sim/app/api/tools/jsm/organization/route.ts @@ -6,7 +6,12 @@ import { validateEnum, validateJiraCloudId, } from '@/lib/core/security/input-validation' -import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' +import { + getJiraCloudId, + getJsmApiBaseUrl, + getJsmHeaders, + parseJsmErrorMessage, +} from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -86,7 +91,10 @@ export async function POST(request: NextRequest) { }) return NextResponse.json( - { error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText }, + { + error: parseJsmErrorMessage(response.status, response.statusText, errorText), + details: errorText, + }, { status: response.status } ) } @@ -154,7 +162,10 @@ export async function POST(request: NextRequest) { }) return NextResponse.json( - { error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText }, + { + error: parseJsmErrorMessage(response.status, response.statusText, errorText), + details: errorText, + }, { status: response.status } ) } diff --git a/apps/sim/app/api/tools/jsm/organizations/route.ts b/apps/sim/app/api/tools/jsm/organizations/route.ts index 79971e27dac..fece6be1239 100644 --- a/apps/sim/app/api/tools/jsm/organizations/route.ts +++ b/apps/sim/app/api/tools/jsm/organizations/route.ts @@ -2,7 +2,12 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' -import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' +import { + getJiraCloudId, + getJsmApiBaseUrl, + getJsmHeaders, + parseJsmErrorMessage, +} from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -69,7 +74,10 @@ export async function POST(request: NextRequest) { }) return NextResponse.json( - { error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText }, + { + error: parseJsmErrorMessage(response.status, response.statusText, errorText), + details: errorText, + }, { status: response.status } ) } diff --git a/apps/sim/app/api/tools/jsm/participants/route.ts b/apps/sim/app/api/tools/jsm/participants/route.ts index 93a0293d136..f7a3e612808 100644 --- a/apps/sim/app/api/tools/jsm/participants/route.ts +++ b/apps/sim/app/api/tools/jsm/participants/route.ts @@ -6,7 +6,12 @@ import { validateJiraCloudId, validateJiraIssueKey, } from '@/lib/core/security/input-validation' -import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' +import { + getJiraCloudId, + getJsmApiBaseUrl, + getJsmHeaders, + parseJsmErrorMessage, +} from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -95,7 +100,10 @@ export async function POST(request: NextRequest) { }) return NextResponse.json( - { error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText }, + { + error: parseJsmErrorMessage(response.status, response.statusText, errorText), + details: errorText, + }, { status: response.status } ) } @@ -146,7 +154,10 @@ export async function POST(request: NextRequest) { }) return NextResponse.json( - { error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText }, + { + error: parseJsmErrorMessage(response.status, response.statusText, errorText), + details: errorText, + }, { status: response.status } ) } diff --git a/apps/sim/app/api/tools/jsm/queues/route.ts b/apps/sim/app/api/tools/jsm/queues/route.ts index 2921008efcb..fc3d2517ac8 100644 --- a/apps/sim/app/api/tools/jsm/queues/route.ts +++ b/apps/sim/app/api/tools/jsm/queues/route.ts @@ -2,7 +2,12 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' -import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' +import { + getJiraCloudId, + getJsmApiBaseUrl, + getJsmHeaders, + parseJsmErrorMessage, +} from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -78,7 +83,10 @@ export async function POST(request: NextRequest) { }) return NextResponse.json( - { error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText }, + { + error: parseJsmErrorMessage(response.status, response.statusText, errorText), + details: errorText, + }, { status: response.status } ) } diff --git a/apps/sim/app/api/tools/jsm/request/route.ts b/apps/sim/app/api/tools/jsm/request/route.ts index 93f9fa10cf0..95644de2e3b 100644 --- a/apps/sim/app/api/tools/jsm/request/route.ts +++ b/apps/sim/app/api/tools/jsm/request/route.ts @@ -6,26 +6,17 @@ import { validateJiraCloudId, validateJiraIssueKey, } from '@/lib/core/security/input-validation' -import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' +import { + getJiraCloudId, + getJsmApiBaseUrl, + getJsmHeaders, + parseJsmErrorMessage, +} from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' const logger = createLogger('JsmRequestAPI') -function parseJsmErrorMessage(status: number, statusText: string, errorText: string): string { - try { - const errorData = JSON.parse(errorText) - if (errorData.errorMessage) { - return `JSM API error: ${errorData.errorMessage}` - } - } catch { - if (errorText) { - return `JSM API error: ${errorText}` - } - } - return `JSM API error: ${status} ${statusText}` -} - export async function POST(request: NextRequest) { const auth = await checkInternalAuth(request) if (!auth.success || !auth.userId) { @@ -85,13 +76,30 @@ export async function POST(request: NextRequest) { const url = `${baseUrl}/request` logger.info('Creating request at:', { url, serviceDeskId, requestTypeId }) + logger.info('Raw formAnswers param:', { + formAnswers, + type: typeof formAnswers, + isObject: typeof formAnswers === 'object', + keys: formAnswers && typeof formAnswers === 'object' ? Object.keys(formAnswers) : null, + }) const requestBody: Record = { serviceDeskId, requestTypeId, } - if (summary || description || requestFieldValues) { + if (formAnswers && typeof formAnswers === 'object') { + // When form answers are provided, use them as the primary data source. + // Per Atlassian docs, fields linked to form questions must NOT also appear + // in requestFieldValues — doing so causes a 400 error. + requestBody.form = { answers: formAnswers } + + // Only include explicit requestFieldValues if the caller provided them + // (they know which fields are safe to include alongside form answers). + if (requestFieldValues && typeof requestFieldValues === 'object') { + requestBody.requestFieldValues = requestFieldValues + } + } else if (summary || description || requestFieldValues) { const fieldValues = requestFieldValues && typeof requestFieldValues === 'object' ? { @@ -106,10 +114,6 @@ export async function POST(request: NextRequest) { requestBody.requestFieldValues = fieldValues } - if (formAnswers && typeof formAnswers === 'object') { - requestBody.form = { answers: formAnswers } - } - if (raiseOnBehalfOf) { requestBody.raiseOnBehalfOf = raiseOnBehalfOf } diff --git a/apps/sim/app/api/tools/jsm/requests/route.ts b/apps/sim/app/api/tools/jsm/requests/route.ts index 70a4cc8ce94..6496c5057bc 100644 --- a/apps/sim/app/api/tools/jsm/requests/route.ts +++ b/apps/sim/app/api/tools/jsm/requests/route.ts @@ -6,7 +6,12 @@ import { validateEnum, validateJiraCloudId, } from '@/lib/core/security/input-validation' -import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' +import { + getJiraCloudId, + getJsmApiBaseUrl, + getJsmHeaders, + parseJsmErrorMessage, +} from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -118,7 +123,10 @@ export async function POST(request: NextRequest) { }) return NextResponse.json( - { error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText }, + { + error: parseJsmErrorMessage(response.status, response.statusText, errorText), + details: errorText, + }, { status: response.status } ) } diff --git a/apps/sim/app/api/tools/jsm/requesttypefields/route.ts b/apps/sim/app/api/tools/jsm/requesttypefields/route.ts index 5e86337aea6..17479251b24 100644 --- a/apps/sim/app/api/tools/jsm/requesttypefields/route.ts +++ b/apps/sim/app/api/tools/jsm/requesttypefields/route.ts @@ -2,7 +2,12 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' -import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' +import { + getJiraCloudId, + getJsmApiBaseUrl, + getJsmHeaders, + parseJsmErrorMessage, +} from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -74,7 +79,10 @@ export async function POST(request: NextRequest) { }) return NextResponse.json( - { error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText }, + { + error: parseJsmErrorMessage(response.status, response.statusText, errorText), + details: errorText, + }, { status: response.status } ) } diff --git a/apps/sim/app/api/tools/jsm/requesttypes/route.ts b/apps/sim/app/api/tools/jsm/requesttypes/route.ts index 9426fe8479a..8e921e41443 100644 --- a/apps/sim/app/api/tools/jsm/requesttypes/route.ts +++ b/apps/sim/app/api/tools/jsm/requesttypes/route.ts @@ -2,7 +2,12 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' -import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' +import { + getJiraCloudId, + getJsmApiBaseUrl, + getJsmHeaders, + parseJsmErrorMessage, +} from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -82,7 +87,10 @@ export async function POST(request: NextRequest) { }) return NextResponse.json( - { error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText }, + { + error: parseJsmErrorMessage(response.status, response.statusText, errorText), + details: errorText, + }, { status: response.status } ) } diff --git a/apps/sim/app/api/tools/jsm/selector-requesttypes/route.ts b/apps/sim/app/api/tools/jsm/selector-requesttypes/route.ts index a9ef02bec86..31de66cd4e4 100644 --- a/apps/sim/app/api/tools/jsm/selector-requesttypes/route.ts +++ b/apps/sim/app/api/tools/jsm/selector-requesttypes/route.ts @@ -4,7 +4,12 @@ import { authorizeCredentialUse } from '@/lib/auth/credential-access' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' import { generateRequestId } from '@/lib/core/utils/request' import { refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils' -import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' +import { + getJiraCloudId, + getJsmApiBaseUrl, + getJsmHeaders, + parseJsmErrorMessage, +} from '@/tools/jsm/utils' const logger = createLogger('JsmSelectorRequestTypesAPI') @@ -81,7 +86,7 @@ export async function POST(request: Request) { error: errorText, }) return NextResponse.json( - { error: `JSM API error: ${response.status} ${response.statusText}` }, + { error: parseJsmErrorMessage(response.status, response.statusText, errorText) }, { status: response.status } ) } diff --git a/apps/sim/app/api/tools/jsm/selector-servicedesks/route.ts b/apps/sim/app/api/tools/jsm/selector-servicedesks/route.ts index b4bc93032fb..a5269f628bc 100644 --- a/apps/sim/app/api/tools/jsm/selector-servicedesks/route.ts +++ b/apps/sim/app/api/tools/jsm/selector-servicedesks/route.ts @@ -4,7 +4,12 @@ import { authorizeCredentialUse } from '@/lib/auth/credential-access' import { validateJiraCloudId } from '@/lib/core/security/input-validation' import { generateRequestId } from '@/lib/core/utils/request' import { refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils' -import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' +import { + getJiraCloudId, + getJsmApiBaseUrl, + getJsmHeaders, + parseJsmErrorMessage, +} from '@/tools/jsm/utils' const logger = createLogger('JsmSelectorServiceDesksAPI') @@ -72,7 +77,7 @@ export async function POST(request: Request) { error: errorText, }) return NextResponse.json( - { error: `JSM API error: ${response.status} ${response.statusText}` }, + { error: parseJsmErrorMessage(response.status, response.statusText, errorText) }, { status: response.status } ) } diff --git a/apps/sim/app/api/tools/jsm/servicedesks/route.ts b/apps/sim/app/api/tools/jsm/servicedesks/route.ts index e6721be528d..af648deb52a 100644 --- a/apps/sim/app/api/tools/jsm/servicedesks/route.ts +++ b/apps/sim/app/api/tools/jsm/servicedesks/route.ts @@ -2,7 +2,12 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { validateJiraCloudId } from '@/lib/core/security/input-validation' -import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' +import { + getJiraCloudId, + getJsmApiBaseUrl, + getJsmHeaders, + parseJsmErrorMessage, +} from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -60,7 +65,10 @@ export async function POST(request: NextRequest) { }) return NextResponse.json( - { error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText }, + { + error: parseJsmErrorMessage(response.status, response.statusText, errorText), + details: errorText, + }, { status: response.status } ) } diff --git a/apps/sim/app/api/tools/jsm/sla/route.ts b/apps/sim/app/api/tools/jsm/sla/route.ts index dc414ac8310..e99e15aa541 100644 --- a/apps/sim/app/api/tools/jsm/sla/route.ts +++ b/apps/sim/app/api/tools/jsm/sla/route.ts @@ -2,7 +2,12 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation' -import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' +import { + getJiraCloudId, + getJsmApiBaseUrl, + getJsmHeaders, + parseJsmErrorMessage, +} from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -69,7 +74,10 @@ export async function POST(request: NextRequest) { }) return NextResponse.json( - { error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText }, + { + error: parseJsmErrorMessage(response.status, response.statusText, errorText), + details: errorText, + }, { status: response.status } ) } diff --git a/apps/sim/app/api/tools/jsm/transition/route.ts b/apps/sim/app/api/tools/jsm/transition/route.ts index 45a9e3a5c26..25274958d26 100644 --- a/apps/sim/app/api/tools/jsm/transition/route.ts +++ b/apps/sim/app/api/tools/jsm/transition/route.ts @@ -6,7 +6,12 @@ import { validateJiraCloudId, validateJiraIssueKey, } from '@/lib/core/security/input-validation' -import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' +import { + getJiraCloudId, + getJsmApiBaseUrl, + getJsmHeaders, + parseJsmErrorMessage, +} from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -96,7 +101,10 @@ export async function POST(request: NextRequest) { }) return NextResponse.json( - { error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText }, + { + error: parseJsmErrorMessage(response.status, response.statusText, errorText), + details: errorText, + }, { status: response.status } ) } diff --git a/apps/sim/app/api/tools/jsm/transitions/route.ts b/apps/sim/app/api/tools/jsm/transitions/route.ts index d1001452f99..339e648cfc4 100644 --- a/apps/sim/app/api/tools/jsm/transitions/route.ts +++ b/apps/sim/app/api/tools/jsm/transitions/route.ts @@ -2,7 +2,12 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation' -import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' +import { + getJiraCloudId, + getJsmApiBaseUrl, + getJsmHeaders, + parseJsmErrorMessage, +} from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -69,7 +74,10 @@ export async function POST(request: NextRequest) { }) return NextResponse.json( - { error: `JSM API error: ${response.status} ${response.statusText}`, details: errorText }, + { + error: parseJsmErrorMessage(response.status, response.statusText, errorText), + details: errorText, + }, { status: response.status } ) } diff --git a/apps/sim/blocks/blocks/jira_service_management.ts b/apps/sim/blocks/blocks/jira_service_management.ts index fd0cc4b84d7..8699154417e 100644 --- a/apps/sim/blocks/blocks/jira_service_management.ts +++ b/apps/sim/blocks/blocks/jira_service_management.ts @@ -290,7 +290,7 @@ Return ONLY the description text - no explanations.`, title: 'Form Answers', type: 'long-input', placeholder: - 'JSON object for form-based request types (e.g., {"summary": {"text": "Title"}, "customfield_10010": {"choices": ["10320"]}})', + 'JSON object using form question IDs as keys (e.g., {"1": {"text": "Title"}, "4": {"choices": ["5"]}, "14": {"text": "Details"}})', mode: 'advanced', condition: { field: 'operation', value: 'create_request' }, }, diff --git a/apps/sim/tools/confluence/add_label.ts b/apps/sim/tools/confluence/add_label.ts index 2ba111f529d..db931b3cf0d 100644 --- a/apps/sim/tools/confluence/add_label.ts +++ b/apps/sim/tools/confluence/add_label.ts @@ -34,8 +34,6 @@ export const confluenceAddLabelTool: ToolConfig< provider: 'confluence', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/confluence/create_blogpost.ts b/apps/sim/tools/confluence/create_blogpost.ts index e67e0f0732b..b39e91b7f18 100644 --- a/apps/sim/tools/confluence/create_blogpost.ts +++ b/apps/sim/tools/confluence/create_blogpost.ts @@ -44,8 +44,6 @@ export const confluenceCreateBlogPostTool: ToolConfig< provider: 'confluence', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/confluence/create_comment.ts b/apps/sim/tools/confluence/create_comment.ts index b09c6ddb54d..aa18a5c4a0b 100644 --- a/apps/sim/tools/confluence/create_comment.ts +++ b/apps/sim/tools/confluence/create_comment.ts @@ -31,8 +31,6 @@ export const confluenceCreateCommentTool: ToolConfig< provider: 'confluence', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/confluence/create_page.ts b/apps/sim/tools/confluence/create_page.ts index f4f70bc4afb..7a4fec8a846 100644 --- a/apps/sim/tools/confluence/create_page.ts +++ b/apps/sim/tools/confluence/create_page.ts @@ -40,8 +40,6 @@ export const confluenceCreatePageTool: ToolConfig< provider: 'confluence', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/confluence/create_page_property.ts b/apps/sim/tools/confluence/create_page_property.ts index 99fbe246fdc..36ebfb04a06 100644 --- a/apps/sim/tools/confluence/create_page_property.ts +++ b/apps/sim/tools/confluence/create_page_property.ts @@ -38,8 +38,6 @@ export const confluenceCreatePagePropertyTool: ToolConfig< provider: 'confluence', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/confluence/create_space.ts b/apps/sim/tools/confluence/create_space.ts index 4981c4adc25..f2d8b8a734a 100644 --- a/apps/sim/tools/confluence/create_space.ts +++ b/apps/sim/tools/confluence/create_space.ts @@ -39,8 +39,6 @@ export const confluenceCreateSpaceTool: ToolConfig< provider: 'confluence', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/confluence/create_space_property.ts b/apps/sim/tools/confluence/create_space_property.ts index e6fee973b82..c702f63539a 100644 --- a/apps/sim/tools/confluence/create_space_property.ts +++ b/apps/sim/tools/confluence/create_space_property.ts @@ -35,8 +35,6 @@ export const confluenceCreateSpacePropertyTool: ToolConfig< provider: 'confluence', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/confluence/delete_attachment.ts b/apps/sim/tools/confluence/delete_attachment.ts index 38159ee4d6a..37d2d093d80 100644 --- a/apps/sim/tools/confluence/delete_attachment.ts +++ b/apps/sim/tools/confluence/delete_attachment.ts @@ -30,8 +30,6 @@ export const confluenceDeleteAttachmentTool: ToolConfig< provider: 'confluence', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/confluence/delete_blogpost.ts b/apps/sim/tools/confluence/delete_blogpost.ts index 6d03a3f60e1..c53562cf283 100644 --- a/apps/sim/tools/confluence/delete_blogpost.ts +++ b/apps/sim/tools/confluence/delete_blogpost.ts @@ -31,8 +31,6 @@ export const confluenceDeleteBlogPostTool: ToolConfig< provider: 'confluence', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/confluence/delete_comment.ts b/apps/sim/tools/confluence/delete_comment.ts index 7cfb1694987..6564181dfe0 100644 --- a/apps/sim/tools/confluence/delete_comment.ts +++ b/apps/sim/tools/confluence/delete_comment.ts @@ -30,8 +30,6 @@ export const confluenceDeleteCommentTool: ToolConfig< provider: 'confluence', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/confluence/delete_label.ts b/apps/sim/tools/confluence/delete_label.ts index 182dd066340..2f92766fc67 100644 --- a/apps/sim/tools/confluence/delete_label.ts +++ b/apps/sim/tools/confluence/delete_label.ts @@ -33,8 +33,6 @@ export const confluenceDeleteLabelTool: ToolConfig< provider: 'confluence', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/confluence/delete_page.ts b/apps/sim/tools/confluence/delete_page.ts index bc7be2b8932..a648a2b37c5 100644 --- a/apps/sim/tools/confluence/delete_page.ts +++ b/apps/sim/tools/confluence/delete_page.ts @@ -32,8 +32,6 @@ export const confluenceDeletePageTool: ToolConfig< provider: 'confluence', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/confluence/delete_page_property.ts b/apps/sim/tools/confluence/delete_page_property.ts index 0bd4d04911b..d7b6c5fbb49 100644 --- a/apps/sim/tools/confluence/delete_page_property.ts +++ b/apps/sim/tools/confluence/delete_page_property.ts @@ -33,8 +33,6 @@ export const confluenceDeletePagePropertyTool: ToolConfig< provider: 'confluence', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/confluence/delete_space.ts b/apps/sim/tools/confluence/delete_space.ts index c9fa5cb315e..82442c66ad5 100644 --- a/apps/sim/tools/confluence/delete_space.ts +++ b/apps/sim/tools/confluence/delete_space.ts @@ -31,8 +31,6 @@ export const confluenceDeleteSpaceTool: ToolConfig< provider: 'confluence', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/confluence/delete_space_property.ts b/apps/sim/tools/confluence/delete_space_property.ts index 0f2a29dfdd4..9c69431aac4 100644 --- a/apps/sim/tools/confluence/delete_space_property.ts +++ b/apps/sim/tools/confluence/delete_space_property.ts @@ -33,8 +33,6 @@ export const confluenceDeleteSpacePropertyTool: ToolConfig< provider: 'confluence', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/confluence/get_blogpost.ts b/apps/sim/tools/confluence/get_blogpost.ts index c61d4894117..94c9b02de7c 100644 --- a/apps/sim/tools/confluence/get_blogpost.ts +++ b/apps/sim/tools/confluence/get_blogpost.ts @@ -49,8 +49,6 @@ export const confluenceGetBlogPostTool: ToolConfig< provider: 'confluence', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/confluence/get_page_ancestors.ts b/apps/sim/tools/confluence/get_page_ancestors.ts index 2e3ea9714e2..20b7be3ca2c 100644 --- a/apps/sim/tools/confluence/get_page_ancestors.ts +++ b/apps/sim/tools/confluence/get_page_ancestors.ts @@ -39,8 +39,6 @@ export const confluenceGetPageAncestorsTool: ToolConfig< provider: 'confluence', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/confluence/get_page_children.ts b/apps/sim/tools/confluence/get_page_children.ts index a7691245ea6..7ca7ca10eda 100644 --- a/apps/sim/tools/confluence/get_page_children.ts +++ b/apps/sim/tools/confluence/get_page_children.ts @@ -42,8 +42,6 @@ export const confluenceGetPageChildrenTool: ToolConfig< provider: 'confluence', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/confluence/get_page_descendants.ts b/apps/sim/tools/confluence/get_page_descendants.ts index 9fdb8213331..a9e0bc5a323 100644 --- a/apps/sim/tools/confluence/get_page_descendants.ts +++ b/apps/sim/tools/confluence/get_page_descendants.ts @@ -43,8 +43,6 @@ export const confluenceGetPageDescendantsTool: ToolConfig< provider: 'confluence', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/confluence/get_page_version.ts b/apps/sim/tools/confluence/get_page_version.ts index a67b709295c..dc496b38a24 100644 --- a/apps/sim/tools/confluence/get_page_version.ts +++ b/apps/sim/tools/confluence/get_page_version.ts @@ -54,8 +54,6 @@ export const confluenceGetPageVersionTool: ToolConfig< provider: 'confluence', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/confluence/get_pages_by_label.ts b/apps/sim/tools/confluence/get_pages_by_label.ts index 0220341ed16..af67210a0b0 100644 --- a/apps/sim/tools/confluence/get_pages_by_label.ts +++ b/apps/sim/tools/confluence/get_pages_by_label.ts @@ -47,8 +47,6 @@ export const confluenceGetPagesByLabelTool: ToolConfig< provider: 'confluence', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/confluence/get_space.ts b/apps/sim/tools/confluence/get_space.ts index 178ec6e21f1..fbadd7a6575 100644 --- a/apps/sim/tools/confluence/get_space.ts +++ b/apps/sim/tools/confluence/get_space.ts @@ -42,8 +42,6 @@ export const confluenceGetSpaceTool: ToolConfig< provider: 'confluence', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/confluence/get_task.ts b/apps/sim/tools/confluence/get_task.ts index 21c2c5c4284..cf0b6177654 100644 --- a/apps/sim/tools/confluence/get_task.ts +++ b/apps/sim/tools/confluence/get_task.ts @@ -41,8 +41,6 @@ export const confluenceGetTaskTool: ToolConfig = provider: 'jira', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/jira/update_comment.ts b/apps/sim/tools/jira/update_comment.ts index e49fa248332..526e724fb4c 100644 --- a/apps/sim/tools/jira/update_comment.ts +++ b/apps/sim/tools/jira/update_comment.ts @@ -31,8 +31,6 @@ export const jiraUpdateCommentTool: ToolConfig r.url).join(', ')}` ) } + +/** + * Parse error messages from Atlassian API responses (Jira, JSM, Confluence). + * Handles all known error formats: errorMessage, errorMessages[], errors[].title/detail, + * field-level errors object, and generic message fallback. + */ +export function parseAtlassianErrorMessage( + status: number, + statusText: string, + errorText: string +): string { + try { + const errorData = JSON.parse(errorText) + if (errorData.errorMessage) { + return errorData.errorMessage + } + if (Array.isArray(errorData.errorMessages) && errorData.errorMessages.length > 0) { + return errorData.errorMessages.join(', ') + } + if (Array.isArray(errorData.errors) && errorData.errors.length > 0) { + const err = errorData.errors[0] + if (err?.title) { + return err.detail ? `${err.title}: ${err.detail}` : err.title + } + } + if (errorData.errors && !Array.isArray(errorData.errors)) { + const fieldErrors = Object.entries(errorData.errors) + .map(([field, msg]) => `${field}: ${msg}`) + .join(', ') + if (fieldErrors) return fieldErrors + } + if (errorData.message) { + return errorData.message + } + } catch { + if (errorText) { + return errorText + } + } + return `${status} ${statusText}` +} diff --git a/apps/sim/tools/jira/write.ts b/apps/sim/tools/jira/write.ts index 446f043acd8..42a5f9391c5 100644 --- a/apps/sim/tools/jira/write.ts +++ b/apps/sim/tools/jira/write.ts @@ -13,8 +13,6 @@ export const jiraWriteTool: ToolConfig = { provider: 'jira', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/jsm/add_comment.ts b/apps/sim/tools/jsm/add_comment.ts index a06caaf36ca..e23069a138a 100644 --- a/apps/sim/tools/jsm/add_comment.ts +++ b/apps/sim/tools/jsm/add_comment.ts @@ -13,8 +13,6 @@ export const jsmAddCommentTool: ToolConfig = { provider: 'jira', }, - errorExtractor: 'atlassian-errors', - params: { accessToken: { type: 'string', diff --git a/apps/sim/tools/jsm/get_transitions.ts b/apps/sim/tools/jsm/get_transitions.ts index d439c174cea..d864cf747d6 100644 --- a/apps/sim/tools/jsm/get_transitions.ts +++ b/apps/sim/tools/jsm/get_transitions.ts @@ -14,8 +14,6 @@ export const jsmGetTransitionsTool: ToolConfig { 'X-ExperimentalApi': 'opt-in', } } - -/** - * Parse error messages from JSM/Forms API responses - * @param status - HTTP status code - * @param statusText - HTTP status text - * @param errorText - Raw error response body - * @returns Formatted error message string - */ -export function parseJsmErrorMessage( - status: number, - statusText: string, - errorText: string -): string { - try { - const errorData = JSON.parse(errorText) - // JSM Service Desk: singular errorMessage - if (errorData.errorMessage) { - return errorData.errorMessage - } - // Jira Platform: errorMessages array - if (Array.isArray(errorData.errorMessages) && errorData.errorMessages.length > 0) { - return errorData.errorMessages.join(', ') - } - // Confluence v2 / Forms API: RFC 7807 errors array - if (Array.isArray(errorData.errors) && errorData.errors.length > 0) { - const err = errorData.errors[0] - if (err?.title) { - return err.detail ? `${err.title}: ${err.detail}` : err.title - } - } - // Jira Platform field-level errors object - if (errorData.errors && !Array.isArray(errorData.errors)) { - const fieldErrors = Object.entries(errorData.errors) - .map(([field, msg]) => `${field}: ${msg}`) - .join(', ') - if (fieldErrors) return fieldErrors - } - // Generic message fallback - if (errorData.message) { - return errorData.message - } - } catch { - if (errorText) { - return errorText - } - } - return `${status} ${statusText}` -} From bdf3ce330057fd52bedcaa21eea489137d5965e7 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 13 Apr 2026 14:17:45 -0700 Subject: [PATCH 2/4] fix: address PR review comments from Bugbot - Remove debug logger.info for formAnswers in JSM request route - Restore user-friendly spaceId error message in Confluence create-page route - Restore details field in Jira write and update route error responses Co-Authored-By: Claude Opus 4.6 --- apps/sim/app/api/tools/confluence/create-page/route.ts | 9 +++++---- apps/sim/app/api/tools/jira/update/route.ts | 5 ++++- apps/sim/app/api/tools/jira/write/route.ts | 5 ++++- apps/sim/app/api/tools/jsm/request/route.ts | 6 ------ 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/apps/sim/app/api/tools/confluence/create-page/route.ts b/apps/sim/app/api/tools/confluence/create-page/route.ts index 38a8d5ea940..3b368a2ecd9 100644 --- a/apps/sim/app/api/tools/confluence/create-page/route.ts +++ b/apps/sim/app/api/tools/confluence/create-page/route.ts @@ -108,10 +108,11 @@ export async function POST(request: NextRequest) { statusText: response.statusText, error: errorText, }) - return NextResponse.json( - { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, - { status: response.status } - ) + let errorMessage = parseAtlassianErrorMessage(response.status, response.statusText, errorText) + if (errorMessage.includes("'spaceId'") && errorMessage.includes('Long')) { + errorMessage = 'Invalid Space ID. Use the list spaces operation to find valid space IDs.' + } + return NextResponse.json({ error: errorMessage }, { status: response.status }) } const data = await response.json() diff --git a/apps/sim/app/api/tools/jira/update/route.ts b/apps/sim/app/api/tools/jira/update/route.ts index 7fad78159c0..8ad96ba3d0c 100644 --- a/apps/sim/app/api/tools/jira/update/route.ts +++ b/apps/sim/app/api/tools/jira/update/route.ts @@ -188,7 +188,10 @@ export async function PUT(request: NextRequest) { }) return NextResponse.json( - { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), + details: errorText, + }, { status: response.status } ) } diff --git a/apps/sim/app/api/tools/jira/write/route.ts b/apps/sim/app/api/tools/jira/write/route.ts index c7a89c80d9d..6ecb49553c6 100644 --- a/apps/sim/app/api/tools/jira/write/route.ts +++ b/apps/sim/app/api/tools/jira/write/route.ts @@ -197,7 +197,10 @@ export async function POST(request: NextRequest) { }) return NextResponse.json( - { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, + { + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), + details: errorText, + }, { status: response.status } ) } diff --git a/apps/sim/app/api/tools/jsm/request/route.ts b/apps/sim/app/api/tools/jsm/request/route.ts index 95644de2e3b..8d481797fdc 100644 --- a/apps/sim/app/api/tools/jsm/request/route.ts +++ b/apps/sim/app/api/tools/jsm/request/route.ts @@ -76,12 +76,6 @@ export async function POST(request: NextRequest) { const url = `${baseUrl}/request` logger.info('Creating request at:', { url, serviceDeskId, requestTypeId }) - logger.info('Raw formAnswers param:', { - formAnswers, - type: typeof formAnswers, - isObject: typeof formAnswers === 'object', - keys: formAnswers && typeof formAnswers === 'object' ? Object.keys(formAnswers) : null, - }) const requestBody: Record = { serviceDeskId, From 29efba37747b60e1c33688d2bc621981d3092062 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 13 Apr 2026 14:25:54 -0700 Subject: [PATCH 3/4] refactor: remove re-exports from jsm/utils and import directly from source Remove re-exports of getJiraCloudId, parseAtlassianErrorMessage, and parseJsmErrorMessage from jsm/utils.ts. Update all 21 JSM routes to import directly from @/tools/jira/utils per CLAUDE.md import rules. Co-Authored-By: Claude Opus 4.6 --- apps/sim/app/api/tools/jsm/approvals/route.ts | 12 ++++-------- apps/sim/app/api/tools/jsm/comment/route.ts | 10 +++------- apps/sim/app/api/tools/jsm/comments/route.ts | 10 +++------- apps/sim/app/api/tools/jsm/customers/route.ts | 12 ++++-------- apps/sim/app/api/tools/jsm/forms/issue/route.ts | 10 +++------- apps/sim/app/api/tools/jsm/forms/structure/route.ts | 10 +++------- apps/sim/app/api/tools/jsm/forms/templates/route.ts | 10 +++------- apps/sim/app/api/tools/jsm/organization/route.ts | 12 ++++-------- apps/sim/app/api/tools/jsm/organizations/route.ts | 10 +++------- apps/sim/app/api/tools/jsm/participants/route.ts | 12 ++++-------- apps/sim/app/api/tools/jsm/queues/route.ts | 10 +++------- apps/sim/app/api/tools/jsm/request/route.ts | 12 ++++-------- apps/sim/app/api/tools/jsm/requests/route.ts | 10 +++------- .../sim/app/api/tools/jsm/requesttypefields/route.ts | 10 +++------- apps/sim/app/api/tools/jsm/requesttypes/route.ts | 10 +++------- .../app/api/tools/jsm/selector-requesttypes/route.ts | 10 +++------- .../app/api/tools/jsm/selector-servicedesks/route.ts | 10 +++------- apps/sim/app/api/tools/jsm/servicedesks/route.ts | 10 +++------- apps/sim/app/api/tools/jsm/sla/route.ts | 10 +++------- apps/sim/app/api/tools/jsm/transition/route.ts | 10 +++------- apps/sim/app/api/tools/jsm/transitions/route.ts | 10 +++------- apps/sim/tools/jsm/utils.ts | 10 ---------- 22 files changed, 68 insertions(+), 162 deletions(-) diff --git a/apps/sim/app/api/tools/jsm/approvals/route.ts b/apps/sim/app/api/tools/jsm/approvals/route.ts index 26c15e753c6..099c9483c5a 100644 --- a/apps/sim/app/api/tools/jsm/approvals/route.ts +++ b/apps/sim/app/api/tools/jsm/approvals/route.ts @@ -7,12 +7,8 @@ import { validateJiraCloudId, validateJiraIssueKey, } from '@/lib/core/security/input-validation' -import { - getJiraCloudId, - getJsmApiBaseUrl, - getJsmHeaders, - parseJsmErrorMessage, -} from '@/tools/jsm/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' +import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -104,7 +100,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { - error: parseJsmErrorMessage(response.status, response.statusText, errorText), + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), details: errorText, }, { status: response.status } @@ -160,7 +156,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { - error: parseJsmErrorMessage(response.status, response.statusText, errorText), + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), details: errorText, }, { status: response.status } diff --git a/apps/sim/app/api/tools/jsm/comment/route.ts b/apps/sim/app/api/tools/jsm/comment/route.ts index 8f75209ec18..4d119ff27b2 100644 --- a/apps/sim/app/api/tools/jsm/comment/route.ts +++ b/apps/sim/app/api/tools/jsm/comment/route.ts @@ -2,12 +2,8 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation' -import { - getJiraCloudId, - getJsmApiBaseUrl, - getJsmHeaders, - parseJsmErrorMessage, -} from '@/tools/jsm/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' +import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -86,7 +82,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { - error: parseJsmErrorMessage(response.status, response.statusText, errorText), + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), details: errorText, }, { status: response.status } diff --git a/apps/sim/app/api/tools/jsm/comments/route.ts b/apps/sim/app/api/tools/jsm/comments/route.ts index 9c4a4a4e874..ee849088717 100644 --- a/apps/sim/app/api/tools/jsm/comments/route.ts +++ b/apps/sim/app/api/tools/jsm/comments/route.ts @@ -2,12 +2,8 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation' -import { - getJiraCloudId, - getJsmApiBaseUrl, - getJsmHeaders, - parseJsmErrorMessage, -} from '@/tools/jsm/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' +import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -88,7 +84,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { - error: parseJsmErrorMessage(response.status, response.statusText, errorText), + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), details: errorText, }, { status: response.status } diff --git a/apps/sim/app/api/tools/jsm/customers/route.ts b/apps/sim/app/api/tools/jsm/customers/route.ts index 7cd11ab5798..a44041d7bb3 100644 --- a/apps/sim/app/api/tools/jsm/customers/route.ts +++ b/apps/sim/app/api/tools/jsm/customers/route.ts @@ -2,12 +2,8 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' -import { - getJiraCloudId, - getJsmApiBaseUrl, - getJsmHeaders, - parseJsmErrorMessage, -} from '@/tools/jsm/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' +import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -101,7 +97,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { - error: parseJsmErrorMessage(response.status, response.statusText, errorText), + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), details: errorText, }, { status: response.status } @@ -141,7 +137,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { - error: parseJsmErrorMessage(response.status, response.statusText, errorText), + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), details: errorText, }, { status: response.status } diff --git a/apps/sim/app/api/tools/jsm/forms/issue/route.ts b/apps/sim/app/api/tools/jsm/forms/issue/route.ts index e6f95490b17..1405ca8a267 100644 --- a/apps/sim/app/api/tools/jsm/forms/issue/route.ts +++ b/apps/sim/app/api/tools/jsm/forms/issue/route.ts @@ -2,12 +2,8 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation' -import { - getJiraCloudId, - getJsmFormsApiBaseUrl, - getJsmHeaders, - parseJsmErrorMessage, -} from '@/tools/jsm/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' +import { getJsmFormsApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -70,7 +66,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { - error: parseJsmErrorMessage(response.status, response.statusText, errorText), + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), details: errorText, }, { status: response.status } diff --git a/apps/sim/app/api/tools/jsm/forms/structure/route.ts b/apps/sim/app/api/tools/jsm/forms/structure/route.ts index 2958687dab3..f224d67970f 100644 --- a/apps/sim/app/api/tools/jsm/forms/structure/route.ts +++ b/apps/sim/app/api/tools/jsm/forms/structure/route.ts @@ -2,12 +2,8 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation' -import { - getJiraCloudId, - getJsmFormsApiBaseUrl, - getJsmHeaders, - parseJsmErrorMessage, -} from '@/tools/jsm/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' +import { getJsmFormsApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -80,7 +76,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { - error: parseJsmErrorMessage(response.status, response.statusText, errorText), + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), details: errorText, }, { status: response.status } diff --git a/apps/sim/app/api/tools/jsm/forms/templates/route.ts b/apps/sim/app/api/tools/jsm/forms/templates/route.ts index dc33e8bc5c9..65695b7d639 100644 --- a/apps/sim/app/api/tools/jsm/forms/templates/route.ts +++ b/apps/sim/app/api/tools/jsm/forms/templates/route.ts @@ -2,12 +2,8 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation' -import { - getJiraCloudId, - getJsmFormsApiBaseUrl, - getJsmHeaders, - parseJsmErrorMessage, -} from '@/tools/jsm/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' +import { getJsmFormsApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -70,7 +66,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { - error: parseJsmErrorMessage(response.status, response.statusText, errorText), + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), details: errorText, }, { status: response.status } diff --git a/apps/sim/app/api/tools/jsm/organization/route.ts b/apps/sim/app/api/tools/jsm/organization/route.ts index 97d1bb2c9b6..15b4f7302e1 100644 --- a/apps/sim/app/api/tools/jsm/organization/route.ts +++ b/apps/sim/app/api/tools/jsm/organization/route.ts @@ -6,12 +6,8 @@ import { validateEnum, validateJiraCloudId, } from '@/lib/core/security/input-validation' -import { - getJiraCloudId, - getJsmApiBaseUrl, - getJsmHeaders, - parseJsmErrorMessage, -} from '@/tools/jsm/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' +import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -92,7 +88,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { - error: parseJsmErrorMessage(response.status, response.statusText, errorText), + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), details: errorText, }, { status: response.status } @@ -163,7 +159,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { - error: parseJsmErrorMessage(response.status, response.statusText, errorText), + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), details: errorText, }, { status: response.status } diff --git a/apps/sim/app/api/tools/jsm/organizations/route.ts b/apps/sim/app/api/tools/jsm/organizations/route.ts index fece6be1239..52fb6699673 100644 --- a/apps/sim/app/api/tools/jsm/organizations/route.ts +++ b/apps/sim/app/api/tools/jsm/organizations/route.ts @@ -2,12 +2,8 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' -import { - getJiraCloudId, - getJsmApiBaseUrl, - getJsmHeaders, - parseJsmErrorMessage, -} from '@/tools/jsm/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' +import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -75,7 +71,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { - error: parseJsmErrorMessage(response.status, response.statusText, errorText), + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), details: errorText, }, { status: response.status } diff --git a/apps/sim/app/api/tools/jsm/participants/route.ts b/apps/sim/app/api/tools/jsm/participants/route.ts index f7a3e612808..ea9c31d55cc 100644 --- a/apps/sim/app/api/tools/jsm/participants/route.ts +++ b/apps/sim/app/api/tools/jsm/participants/route.ts @@ -6,12 +6,8 @@ import { validateJiraCloudId, validateJiraIssueKey, } from '@/lib/core/security/input-validation' -import { - getJiraCloudId, - getJsmApiBaseUrl, - getJsmHeaders, - parseJsmErrorMessage, -} from '@/tools/jsm/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' +import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -101,7 +97,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { - error: parseJsmErrorMessage(response.status, response.statusText, errorText), + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), details: errorText, }, { status: response.status } @@ -155,7 +151,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { - error: parseJsmErrorMessage(response.status, response.statusText, errorText), + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), details: errorText, }, { status: response.status } diff --git a/apps/sim/app/api/tools/jsm/queues/route.ts b/apps/sim/app/api/tools/jsm/queues/route.ts index fc3d2517ac8..fa3d7ad14df 100644 --- a/apps/sim/app/api/tools/jsm/queues/route.ts +++ b/apps/sim/app/api/tools/jsm/queues/route.ts @@ -2,12 +2,8 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' -import { - getJiraCloudId, - getJsmApiBaseUrl, - getJsmHeaders, - parseJsmErrorMessage, -} from '@/tools/jsm/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' +import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -84,7 +80,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { - error: parseJsmErrorMessage(response.status, response.statusText, errorText), + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), details: errorText, }, { status: response.status } diff --git a/apps/sim/app/api/tools/jsm/request/route.ts b/apps/sim/app/api/tools/jsm/request/route.ts index 8d481797fdc..858c68beaae 100644 --- a/apps/sim/app/api/tools/jsm/request/route.ts +++ b/apps/sim/app/api/tools/jsm/request/route.ts @@ -6,12 +6,8 @@ import { validateJiraCloudId, validateJiraIssueKey, } from '@/lib/core/security/input-validation' -import { - getJiraCloudId, - getJsmApiBaseUrl, - getJsmHeaders, - parseJsmErrorMessage, -} from '@/tools/jsm/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' +import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -141,7 +137,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { - error: parseJsmErrorMessage(response.status, response.statusText, errorText), + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), details: errorText, }, { status: response.status } @@ -210,7 +206,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { - error: parseJsmErrorMessage(response.status, response.statusText, errorText), + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), details: errorText, }, { status: response.status } diff --git a/apps/sim/app/api/tools/jsm/requests/route.ts b/apps/sim/app/api/tools/jsm/requests/route.ts index 6496c5057bc..f53f9c6d79c 100644 --- a/apps/sim/app/api/tools/jsm/requests/route.ts +++ b/apps/sim/app/api/tools/jsm/requests/route.ts @@ -6,12 +6,8 @@ import { validateEnum, validateJiraCloudId, } from '@/lib/core/security/input-validation' -import { - getJiraCloudId, - getJsmApiBaseUrl, - getJsmHeaders, - parseJsmErrorMessage, -} from '@/tools/jsm/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' +import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -124,7 +120,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { - error: parseJsmErrorMessage(response.status, response.statusText, errorText), + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), details: errorText, }, { status: response.status } diff --git a/apps/sim/app/api/tools/jsm/requesttypefields/route.ts b/apps/sim/app/api/tools/jsm/requesttypefields/route.ts index 17479251b24..99ee19a0838 100644 --- a/apps/sim/app/api/tools/jsm/requesttypefields/route.ts +++ b/apps/sim/app/api/tools/jsm/requesttypefields/route.ts @@ -2,12 +2,8 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' -import { - getJiraCloudId, - getJsmApiBaseUrl, - getJsmHeaders, - parseJsmErrorMessage, -} from '@/tools/jsm/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' +import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -80,7 +76,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { - error: parseJsmErrorMessage(response.status, response.statusText, errorText), + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), details: errorText, }, { status: response.status } diff --git a/apps/sim/app/api/tools/jsm/requesttypes/route.ts b/apps/sim/app/api/tools/jsm/requesttypes/route.ts index 8e921e41443..964d9aab9d1 100644 --- a/apps/sim/app/api/tools/jsm/requesttypes/route.ts +++ b/apps/sim/app/api/tools/jsm/requesttypes/route.ts @@ -2,12 +2,8 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' -import { - getJiraCloudId, - getJsmApiBaseUrl, - getJsmHeaders, - parseJsmErrorMessage, -} from '@/tools/jsm/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' +import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -88,7 +84,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { - error: parseJsmErrorMessage(response.status, response.statusText, errorText), + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), details: errorText, }, { status: response.status } diff --git a/apps/sim/app/api/tools/jsm/selector-requesttypes/route.ts b/apps/sim/app/api/tools/jsm/selector-requesttypes/route.ts index 31de66cd4e4..5962aa672bb 100644 --- a/apps/sim/app/api/tools/jsm/selector-requesttypes/route.ts +++ b/apps/sim/app/api/tools/jsm/selector-requesttypes/route.ts @@ -4,12 +4,8 @@ import { authorizeCredentialUse } from '@/lib/auth/credential-access' import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' import { generateRequestId } from '@/lib/core/utils/request' import { refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils' -import { - getJiraCloudId, - getJsmApiBaseUrl, - getJsmHeaders, - parseJsmErrorMessage, -} from '@/tools/jsm/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' +import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' const logger = createLogger('JsmSelectorRequestTypesAPI') @@ -86,7 +82,7 @@ export async function POST(request: Request) { error: errorText, }) return NextResponse.json( - { error: parseJsmErrorMessage(response.status, response.statusText, errorText) }, + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, { status: response.status } ) } diff --git a/apps/sim/app/api/tools/jsm/selector-servicedesks/route.ts b/apps/sim/app/api/tools/jsm/selector-servicedesks/route.ts index a5269f628bc..c755bc11d79 100644 --- a/apps/sim/app/api/tools/jsm/selector-servicedesks/route.ts +++ b/apps/sim/app/api/tools/jsm/selector-servicedesks/route.ts @@ -4,12 +4,8 @@ import { authorizeCredentialUse } from '@/lib/auth/credential-access' import { validateJiraCloudId } from '@/lib/core/security/input-validation' import { generateRequestId } from '@/lib/core/utils/request' import { refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils' -import { - getJiraCloudId, - getJsmApiBaseUrl, - getJsmHeaders, - parseJsmErrorMessage, -} from '@/tools/jsm/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' +import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' const logger = createLogger('JsmSelectorServiceDesksAPI') @@ -77,7 +73,7 @@ export async function POST(request: Request) { error: errorText, }) return NextResponse.json( - { error: parseJsmErrorMessage(response.status, response.statusText, errorText) }, + { error: parseAtlassianErrorMessage(response.status, response.statusText, errorText) }, { status: response.status } ) } diff --git a/apps/sim/app/api/tools/jsm/servicedesks/route.ts b/apps/sim/app/api/tools/jsm/servicedesks/route.ts index af648deb52a..7470a17aeff 100644 --- a/apps/sim/app/api/tools/jsm/servicedesks/route.ts +++ b/apps/sim/app/api/tools/jsm/servicedesks/route.ts @@ -2,12 +2,8 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { validateJiraCloudId } from '@/lib/core/security/input-validation' -import { - getJiraCloudId, - getJsmApiBaseUrl, - getJsmHeaders, - parseJsmErrorMessage, -} from '@/tools/jsm/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' +import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -66,7 +62,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { - error: parseJsmErrorMessage(response.status, response.statusText, errorText), + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), details: errorText, }, { status: response.status } diff --git a/apps/sim/app/api/tools/jsm/sla/route.ts b/apps/sim/app/api/tools/jsm/sla/route.ts index e99e15aa541..7ea1144f59c 100644 --- a/apps/sim/app/api/tools/jsm/sla/route.ts +++ b/apps/sim/app/api/tools/jsm/sla/route.ts @@ -2,12 +2,8 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation' -import { - getJiraCloudId, - getJsmApiBaseUrl, - getJsmHeaders, - parseJsmErrorMessage, -} from '@/tools/jsm/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' +import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -75,7 +71,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { - error: parseJsmErrorMessage(response.status, response.statusText, errorText), + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), details: errorText, }, { status: response.status } diff --git a/apps/sim/app/api/tools/jsm/transition/route.ts b/apps/sim/app/api/tools/jsm/transition/route.ts index 25274958d26..2e7a8743da5 100644 --- a/apps/sim/app/api/tools/jsm/transition/route.ts +++ b/apps/sim/app/api/tools/jsm/transition/route.ts @@ -6,12 +6,8 @@ import { validateJiraCloudId, validateJiraIssueKey, } from '@/lib/core/security/input-validation' -import { - getJiraCloudId, - getJsmApiBaseUrl, - getJsmHeaders, - parseJsmErrorMessage, -} from '@/tools/jsm/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' +import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -102,7 +98,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { - error: parseJsmErrorMessage(response.status, response.statusText, errorText), + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), details: errorText, }, { status: response.status } diff --git a/apps/sim/app/api/tools/jsm/transitions/route.ts b/apps/sim/app/api/tools/jsm/transitions/route.ts index 339e648cfc4..d8027a88201 100644 --- a/apps/sim/app/api/tools/jsm/transitions/route.ts +++ b/apps/sim/app/api/tools/jsm/transitions/route.ts @@ -2,12 +2,8 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation' -import { - getJiraCloudId, - getJsmApiBaseUrl, - getJsmHeaders, - parseJsmErrorMessage, -} from '@/tools/jsm/utils' +import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils' +import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils' export const dynamic = 'force-dynamic' @@ -75,7 +71,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { - error: parseJsmErrorMessage(response.status, response.statusText, errorText), + error: parseAtlassianErrorMessage(response.status, response.statusText, errorText), details: errorText, }, { status: response.status } diff --git a/apps/sim/tools/jsm/utils.ts b/apps/sim/tools/jsm/utils.ts index 83c8e2c29dd..aaf4dad250a 100644 --- a/apps/sim/tools/jsm/utils.ts +++ b/apps/sim/tools/jsm/utils.ts @@ -1,16 +1,6 @@ /** * Shared utilities for Jira Service Management tools - * Reuses the getJiraCloudId and parseAtlassianErrorMessage from the Jira integration */ -/** - * Re-export parseAtlassianErrorMessage as parseJsmErrorMessage for backwards compatibility. - * All JSM routes already import this name. - */ -export { - getJiraCloudId, - parseAtlassianErrorMessage, - parseAtlassianErrorMessage as parseJsmErrorMessage, -} from '@/tools/jira/utils' /** * Build the base URL for JSM Service Desk API From 2c8eaa84980b09ed2b3b269f90799a5eb4c16b67 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 13 Apr 2026 14:26:19 -0700 Subject: [PATCH 4/4] regen docs --- apps/docs/content/docs/en/tools/jira_service_management.mdx | 2 +- apps/docs/content/docs/en/tools/trello.mdx | 1 + apps/sim/app/(landing)/integrations/data/integrations.json | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/docs/content/docs/en/tools/jira_service_management.mdx b/apps/docs/content/docs/en/tools/jira_service_management.mdx index f2c0ed2020d..5912af4ad1d 100644 --- a/apps/docs/content/docs/en/tools/jira_service_management.mdx +++ b/apps/docs/content/docs/en/tools/jira_service_management.mdx @@ -117,7 +117,7 @@ Create a new service request in Jira Service Management | `description` | string | No | Description for the service request | | `raiseOnBehalfOf` | string | No | Account ID of customer to raise request on behalf of | | `requestFieldValues` | json | No | Request field values as key-value pairs \(overrides summary/description if provided\) | -| `formAnswers` | json | No | Form answers for form-based request types \(e.g., \{"summary": \{"text": "Title"\}, "customfield_10010": \{"choices": \["10320"\]\}\}\) | +| `formAnswers` | json | No | Form answers using numeric form question IDs as keys \(e.g., \{"1": \{"text": "Title"\}, "4": \{"choices": \["5"\]\}\}\). Keys are question IDs from the Jira Form, not Jira field names. | | `requestParticipants` | string | No | Comma-separated account IDs to add as request participants | | `channel` | string | No | Channel the request originates from \(e.g., portal, email\) | diff --git a/apps/docs/content/docs/en/tools/trello.mdx b/apps/docs/content/docs/en/tools/trello.mdx index c7a6ad57098..01e3ac67ad1 100644 --- a/apps/docs/content/docs/en/tools/trello.mdx +++ b/apps/docs/content/docs/en/tools/trello.mdx @@ -36,6 +36,7 @@ Before connecting Trello in Sim, add your Sim app origin to the **Allowed Origin Trello's authorization flow redirects back to Sim using a `return_url`. If your Sim origin is not whitelisted in Trello, Trello will block the redirect and the connection flow will fail before Sim can save the token. {/* MANUAL-CONTENT-END */} + Integrate with Trello to list board lists, list cards, create cards, update cards, review activity, and add comments. diff --git a/apps/sim/app/(landing)/integrations/data/integrations.json b/apps/sim/app/(landing)/integrations/data/integrations.json index 241e229ae52..7cfc4c475f9 100644 --- a/apps/sim/app/(landing)/integrations/data/integrations.json +++ b/apps/sim/app/(landing)/integrations/data/integrations.json @@ -2374,7 +2374,7 @@ "authType": "none", "category": "tools", "integrationTypes": ["security", "analytics", "developer-tools"], - "tags": ["monitoring", "security"] + "tags": ["identity", "monitoring"] }, { "type": "cursor_v2",