Skip to content

Commit cf1b46f

Browse files
committed
support api paths
1 parent cddee26 commit cf1b46f

2 files changed

Lines changed: 428 additions & 75 deletions

File tree

packages/b2c-vs-extension/src/extension.ts

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {createScapiSchemasClient, toOrganizationId} from '@salesforce/b2c-toolin
88
import {findDwJson, resolveConfig} from '@salesforce/b2c-tooling-sdk/config';
99
import {configureLogger} from '@salesforce/b2c-tooling-sdk/logging';
1010
import {findAndDeployCartridges, getActiveCodeVersion} from '@salesforce/b2c-tooling-sdk/operations/code';
11+
import {getPathKeys, type OpenApiSchemaInput} from '@salesforce/b2c-tooling-sdk/schemas';
1112
import {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(/"https:\/\/[^"]+"/);
@@ -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

Comments
 (0)