@@ -2,12 +2,20 @@ import { createLogger } from '@sim/logger'
22import { type NextRequest , NextResponse } from 'next/server'
33import { jsmRequestTypesSelectorContract } from '@/lib/api/contracts/selectors/jsm'
44import { parseRequest } from '@/lib/api/server'
5- import { authorizeCredentialUse } from '@/lib/auth/credential-access'
65import { validateAlphanumericId , validateJiraCloudId } from '@/lib/core/security/input-validation'
76import { generateRequestId } from '@/lib/core/utils/request'
87import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
9- import { refreshAccessTokenIfNeeded } from '@/lib/oauth/credential-service'
10- import { getJiraCloudId , parseAtlassianErrorMessage } from '@/tools/jira/utils'
8+ import { resolveAtlassianSelectorCredential } from '@/lib/selectors/application/atlassian-credential'
9+ import {
10+ resolveSelectorProviderValue ,
11+ SELECTOR_ATLASSIAN_DISCOVERY_OPTIONS ,
12+ selectorProviderFailure ,
13+ } from '@/lib/selectors/server/provider-errors'
14+ import {
15+ authenticateSelectorRequest ,
16+ resolveAuthorizedSelectorContext ,
17+ } from '@/lib/selectors/server/resolve-authorized-context'
18+ import { getJiraCloudId } from '@/tools/jira/utils'
1119import { getJsmApiBaseUrl , getJsmHeaders } from '@/tools/jsm/utils'
1220
1321const logger = createLogger ( 'JsmSelectorRequestTypesAPI' )
@@ -83,20 +91,20 @@ async function fetchAllJsmRequestTypes(
8391export const POST = withRouteHandler ( async ( request : NextRequest ) => {
8492 const requestId = generateRequestId ( )
8593 try {
94+ const authentication = await authenticateSelectorRequest ( request )
95+ if ( ! authentication . ok ) {
96+ return NextResponse . json ( { error : authentication . error } , { status : authentication . status } )
97+ }
8698 const parsed = await parseRequest ( jsmRequestTypesSelectorContract , request , { } )
8799 if ( ! parsed . success ) return parsed . response
88100
89- const { credential, workflowId, domain, serviceDeskId } = parsed . data . body
101+ const { credential, workflowId, domain : domainReference , serviceDeskId } = parsed . data . body
90102
91103 if ( ! credential ) {
92104 logger . error ( 'Missing credential in request' )
93105 return NextResponse . json ( { error : 'Credential is required' } , { status : 400 } )
94106 }
95107
96- if ( ! domain ) {
97- return NextResponse . json ( { error : 'Domain is required' } , { status : 400 } )
98- }
99-
100108 if ( ! serviceDeskId ) {
101109 return NextResponse . json ( { error : 'Service Desk ID is required' } , { status : 400 } )
102110 }
@@ -106,31 +114,50 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
106114 return NextResponse . json ( { error : serviceDeskIdValidation . error } , { status : 400 } )
107115 }
108116
109- const authz = await authorizeCredentialUse ( request , {
110- credentialId : credential ,
117+ const resolution = await resolveAuthorizedSelectorContext ( authentication . principal , {
111118 workflowId,
119+ credentialId : credential ,
120+ context : { domain : domainReference } ,
112121 } )
113- if ( ! authz . ok || ! authz . credentialOwnerUserId ) {
114- return NextResponse . json ( { error : authz . error || 'Unauthorized' } , { status : 403 } )
122+ if ( ! resolution . ok ) {
123+ return NextResponse . json ( { error : resolution . error } , { status : resolution . status } )
115124 }
116-
117- const accessToken = await refreshAccessTokenIfNeeded (
118- credential ,
119- authz . credentialOwnerUserId ,
120- requestId
121- )
122- if ( ! accessToken ) {
123- logger . error ( 'Failed to get access token' , {
124- credentialId : credential ,
125- userId : authz . credentialOwnerUserId ,
126- } )
125+ const ownerUserId = resolution . credentialAccess ?. credentialOwnerUserId
126+ if ( ! ownerUserId ) {
127+ return NextResponse . json ( { error : 'Unauthorized' } , { status : 403 } )
128+ }
129+ const bundle = await resolveAtlassianSelectorCredential ( {
130+ credentialId : credential ,
131+ credentialOwnerUserId : ownerUserId ,
132+ requestId,
133+ serviceId : 'jira' ,
134+ } )
135+ if ( ! bundle ) {
136+ logger . error ( 'Failed to get JSM selector access token' )
127137 return NextResponse . json (
128138 { error : 'Could not retrieve access token' , authRequired : true } ,
129139 { status : 401 }
130140 )
131141 }
132142
133- const cloudId = await getJiraCloudId ( domain , accessToken )
143+ const domain = resolution . context . domain as string
144+ const accessToken = bundle . accessToken
145+ const cloudIdResolution = await resolveSelectorProviderValue (
146+ 'Jira Service Management' ,
147+ async ( ) =>
148+ bundle . cloudId
149+ ? bundle . cloudId
150+ : getJiraCloudId ( domain , accessToken , SELECTOR_ATLASSIAN_DISCOVERY_OPTIONS )
151+ )
152+ if ( ! cloudIdResolution . ok ) {
153+ logger . warn ( 'JSM selector discovery failed' , {
154+ status : cloudIdResolution . upstreamStatus ?? 'unknown' ,
155+ } )
156+ return NextResponse . json ( cloudIdResolution . failure , {
157+ status : cloudIdResolution . failure . status ,
158+ } )
159+ }
160+ const cloudId = cloudIdResolution . value
134161
135162 const cloudIdValidation = validateJiraCloudId ( cloudId , 'cloudId' )
136163 if ( ! cloudIdValidation . isValid ) {
@@ -143,22 +170,9 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
143170 const { values, lastResponse } = await fetchAllJsmRequestTypes ( requestTypeUrl , accessToken )
144171
145172 if ( ! lastResponse . ok ) {
146- const errorText = await lastResponse . text ( )
147- logger . error ( 'JSM API error:' , {
148- status : lastResponse . status ,
149- statusText : lastResponse . statusText ,
150- error : errorText ,
151- } )
152- return NextResponse . json (
153- {
154- error : parseAtlassianErrorMessage (
155- lastResponse . status ,
156- lastResponse . statusText ,
157- errorText
158- ) ,
159- } ,
160- { status : lastResponse . status }
161- )
173+ logger . warn ( 'JSM selector request-type request failed' , { status : lastResponse . status } )
174+ const failure = selectorProviderFailure ( 'Jira Service Management' , lastResponse . status )
175+ return NextResponse . json ( failure , { status : failure . status } )
162176 }
163177
164178 const requestTypes = values . map ( ( rt ) => ( {
@@ -167,11 +181,8 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
167181 } ) )
168182
169183 return NextResponse . json ( { requestTypes } )
170- } catch ( error ) {
171- logger . error ( 'Error listing JSM request types:' , error )
172- return NextResponse . json (
173- { error : ( error as Error ) . message || 'Internal server error' } ,
174- { status : 500 }
175- )
184+ } catch {
185+ logger . error ( 'Error listing JSM request types' )
186+ return NextResponse . json ( { error : 'Failed to retrieve JSM request types' } , { status : 500 } )
176187 }
177188} )
0 commit comments