@@ -8,6 +8,7 @@ import {createScapiSchemasClient, toOrganizationId} from '@salesforce/b2c-toolin
88import { findDwJson , resolveConfig } from '@salesforce/b2c-tooling-sdk/config' ;
99import { configureLogger } from '@salesforce/b2c-tooling-sdk/logging' ;
1010import { findAndDeployCartridges , getActiveCodeVersion } from '@salesforce/b2c-tooling-sdk/operations/code' ;
11+ import { getPathKeys , type OpenApiSchemaInput } from '@salesforce/b2c-tooling-sdk/schemas' ;
1112import { randomUUID } from 'node:crypto' ;
1213
1314/** Standard B2C Commerce WebDAV root directories. */
@@ -648,6 +649,115 @@ function activateInner(context: vscode.ExtensionContext, log: vscode.OutputChann
648649 return ;
649650 }
650651
652+ if ( msg . type === 'scapiFetchSchemaPaths' ) {
653+ const tenantId = ( msg . tenantId ?? '' ) . trim ( ) ;
654+ const apiFamily = ( msg . apiFamily ?? '' ) . trim ( ) ;
655+ const apiName = ( msg . apiName ?? '' ) . trim ( ) ;
656+ log . appendLine (
657+ `[SCAPI] Fetch schema paths: tenantId=${ tenantId } apiFamily=${ apiFamily } apiName=${ apiName } ` ,
658+ ) ;
659+ if ( ! tenantId || ! apiFamily || ! apiName ) {
660+ log . appendLine ( '[SCAPI] Fetch paths failed: Tenant Id, API Family, and API Name are required.' ) ;
661+ panel . webview . postMessage ( {
662+ type : 'scapiSchemaPathsResult' ,
663+ success : false ,
664+ error : 'Tenant Id, API Family, and API Name are required.' ,
665+ } ) ;
666+ return ;
667+ }
668+ try {
669+ const config = getConfig ( ) ;
670+ const shortCode = config . values . shortCode ;
671+ if ( ! shortCode ) {
672+ log . appendLine ( '[SCAPI] Fetch paths failed: Short code not found.' ) ;
673+ panel . webview . postMessage ( {
674+ type : 'scapiSchemaPathsResult' ,
675+ success : false ,
676+ error : 'Short code not found.' ,
677+ } ) ;
678+ return ;
679+ }
680+ if ( ! config . hasOAuthConfig ( ) ) {
681+ log . appendLine ( '[SCAPI] Fetch paths failed: OAuth credentials required.' ) ;
682+ panel . webview . postMessage ( {
683+ type : 'scapiSchemaPathsResult' ,
684+ success : false ,
685+ error : 'OAuth credentials required.' ,
686+ } ) ;
687+ return ;
688+ }
689+ const oauthStrategy = config . createOAuth ( ) ;
690+ const schemasClient = createScapiSchemasClient ( { shortCode, tenantId} , oauthStrategy ) ;
691+ const orgId = toOrganizationId ( tenantId ) ;
692+ const apiVersion = 'v1' ;
693+ log . appendLine ( `[SCAPI] GET schema: orgId=${ orgId } ${ apiFamily } /${ apiName } /${ apiVersion } ` ) ;
694+ const { data, error, response} = await schemasClient . GET (
695+ '/organizations/{organizationId}/schemas/{apiFamily}/{apiName}/{apiVersion}' ,
696+ { params : { path : { organizationId : orgId , apiFamily, apiName, apiVersion} } } ,
697+ ) ;
698+ if ( error ) {
699+ const errMsg = getApiErrorMessage ( error , response ) ;
700+ log . appendLine ( `[SCAPI] Fetch paths error: ${ errMsg } ` ) ;
701+ log . appendLine ( `[SCAPI] Error detail: ${ JSON . stringify ( { error, status : response ?. status } ) } ` ) ;
702+ panel . webview . postMessage ( {
703+ type : 'scapiSchemaPathsResult' ,
704+ success : false ,
705+ error : errMsg ,
706+ } ) ;
707+ return ;
708+ }
709+ const pathKeys = data && typeof data === 'object' ? getPathKeys ( data as OpenApiSchemaInput ) : [ ] ;
710+ log . appendLine (
711+ `[SCAPI] Schema response: hasData=${ Boolean ( data ) } pathKeysCount=${ pathKeys . length } pathKeys=${ JSON . stringify ( pathKeys . slice ( 0 , 5 ) ) } ${ pathKeys . length > 5 ? '...' : '' } ` ,
712+ ) ;
713+ const orgPathPrefix = 'organizations/{organizationId}' ;
714+ const paths = pathKeys
715+ . map ( ( p ) => {
716+ if ( typeof p !== 'string' ) return '' ;
717+ const withoutLeadingSlash = p . replace ( / ^ \/ / , '' ) ;
718+ const suffix = withoutLeadingSlash . startsWith ( orgPathPrefix + '/' )
719+ ? withoutLeadingSlash . slice ( orgPathPrefix . length + 1 )
720+ : withoutLeadingSlash === orgPathPrefix
721+ ? ''
722+ : withoutLeadingSlash ;
723+ return suffix ;
724+ } )
725+ . filter ( Boolean )
726+ . sort ( ) ;
727+ log . appendLine (
728+ `[SCAPI] Normalized paths (${ paths . length } ): ${ JSON . stringify ( paths . slice ( 0 , 10 ) ) } ${ paths . length > 10 ? '...' : '' } ` ,
729+ ) ;
730+ const schemaInfo = data && typeof data === 'object' && 'info' in data ? ( data as { info ?: Record < string , unknown > } ) . info : undefined ;
731+ const apiTypeRaw =
732+ schemaInfo ?. [ 'x-api-type' ] ?? schemaInfo ?. [ 'x-apiType' ] ?? schemaInfo ?. [ 'x_api_type' ] ;
733+ const apiType = typeof apiTypeRaw === 'string' ? apiTypeRaw : undefined ;
734+ if ( schemaInfo && ! apiType ) {
735+ log . appendLine (
736+ `[SCAPI] Schema info keys (no x-api-type): ${ Object . keys ( schemaInfo ) . join ( ', ' ) } ` ,
737+ ) ;
738+ } else if ( apiType ) {
739+ log . appendLine ( `[SCAPI] API type: ${ apiType } ` ) ;
740+ }
741+ panel . webview . postMessage ( {
742+ type : 'scapiSchemaPathsResult' ,
743+ success : true ,
744+ paths,
745+ apiType : apiType ?? null ,
746+ } ) ;
747+ } catch ( err ) {
748+ const message = err instanceof Error ? err . message : String ( err ) ;
749+ const stack = err instanceof Error ? err . stack : '' ;
750+ log . appendLine ( `[SCAPI] Fetch paths exception: ${ message } ` ) ;
751+ if ( stack ) log . appendLine ( `[SCAPI] Stack: ${ stack } ` ) ;
752+ panel . webview . postMessage ( {
753+ type : 'scapiSchemaPathsResult' ,
754+ success : false ,
755+ error : message ,
756+ } ) ;
757+ }
758+ return ;
759+ }
760+
651761 if ( msg . type === 'scapiExecuteCurl' ) {
652762 const curlText = ( msg . curlText ?? '' ) . trim ( ) ;
653763 const urlMatch = curlText . match ( / " h t t p s : \/ \/ [ ^ " ] + " / ) ;
@@ -949,6 +1059,7 @@ function activateInner(context: vscode.ExtensionContext, log: vscode.OutputChann
9491059 success : true ,
9501060 clientId,
9511061 secret : clientSecret ,
1062+ scopes : defaultScopes ,
9521063 } ) ;
9531064 } catch ( err ) {
9541065 const message = err instanceof Error ? err . message : String ( err ) ;
0 commit comments