55 */
66import { createSlasClient , getApiErrorMessage } from '@salesforce/b2c-tooling-sdk' ;
77import { createOdsClient , createScapiSchemasClient , toOrganizationId } from '@salesforce/b2c-tooling-sdk/clients' ;
8- import {
9- resolveConfig ,
10- type NormalizedConfig ,
11- type ResolveConfigOptions ,
12- type ResolvedB2CConfig ,
13- } from '@salesforce/b2c-tooling-sdk/config' ;
148import { configureLogger } from '@salesforce/b2c-tooling-sdk/logging' ;
159import { findAndDeployCartridges , getActiveCodeVersion } from '@salesforce/b2c-tooling-sdk/operations/code' ;
1610import { getPathKeys , type OpenApiSchemaInput } from '@salesforce/b2c-tooling-sdk/schemas' ;
@@ -23,24 +17,10 @@ const execAsync = promisify(exec);
2317import * as fs from 'fs' ;
2418import * as path from 'path' ;
2519import * as vscode from 'vscode' ;
26- import { initializePlugins , getPluginConfigSources } from './plugins.js' ;
20+ import { B2CExtensionConfig } from './config-provider.js' ;
21+ import { initializePlugins } from './plugins.js' ;
2722import { registerWebDavTree } from './webdav-tree/index.js' ;
2823
29- /**
30- * Resolves configuration with plugin sources automatically injected.
31- */
32- function resolveConfigWithPlugins (
33- overrides : Partial < NormalizedConfig > = { } ,
34- options : ResolveConfigOptions = { } ,
35- ) : ResolvedB2CConfig {
36- const { sourcesBefore, sourcesAfter} = getPluginConfigSources ( ) ;
37- return resolveConfig ( overrides , {
38- ...options ,
39- sourcesBefore : [ ...sourcesBefore , ...( options . sourcesBefore ?? [ ] ) ] ,
40- sourcesAfter : [ ...( options . sourcesAfter ?? [ ] ) , ...sourcesAfter ] ,
41- } ) ;
42- }
43-
4424/**
4525 * Recursively finds all files under dir whose names end with .json (metadata files).
4626 * Returns paths relative to dir.
@@ -201,6 +181,9 @@ async function activateInner(context: vscode.ExtensionContext, log: vscode.Outpu
201181 // before the first resolveConfig() call. Failures are non-fatal.
202182 await initializePlugins ( ) ;
203183
184+ const configProvider = new B2CExtensionConfig ( log ) ;
185+ context . subscriptions . push ( configProvider ) ;
186+
204187 const disposable = vscode . commands . registerCommand ( 'b2c-dx.openUI' , ( ) => {
205188 vscode . window . showInformationMessage ( 'B2C DX: Opening Page Designer Assistant.' ) ;
206189
@@ -331,11 +314,10 @@ async function activateInner(context: vscode.ExtensionContext, log: vscode.Outpu
331314 { enableScripts : true } ,
332315 ) ;
333316 let prefill : { tenantId : string ; channelId : string ; shortCode ?: string } | undefined ;
334- try {
335- const workingDirectory = vscode . workspace . workspaceFolders ?. [ 0 ] ?. uri . fsPath ?? context . extensionPath ;
336- const config = resolveConfigWithPlugins ( { } , { workingDirectory} ) ;
337- const hostname = config . values . hostname ;
338- const shortCode = config . values . shortCode ;
317+ const prefillConfig = configProvider . getConfig ( ) ;
318+ if ( prefillConfig ) {
319+ const hostname = prefillConfig . values . hostname ;
320+ const shortCode = prefillConfig . values . shortCode ;
339321 const firstPart = hostname && typeof hostname === 'string' ? ( hostname . split ( '.' ) [ 0 ] ?? '' ) : '' ;
340322 const tenantId = firstPart ? firstPart . replace ( / - / g, '_' ) : '' ;
341323 if ( tenantId || shortCode ) {
@@ -345,8 +327,6 @@ async function activateInner(context: vscode.ExtensionContext, log: vscode.Outpu
345327 shortCode : typeof shortCode === 'string' ? shortCode : undefined ,
346328 } ;
347329 }
348- } catch {
349- // Prefill is optional; leave undefined if config fails
350330 }
351331 panel . webview . html = getScapiExplorerWebviewContent ( context , prefill ) ;
352332 panel . webview . onDidReceiveMessage (
@@ -364,8 +344,9 @@ async function activateInner(context: vscode.ExtensionContext, log: vscode.Outpu
364344 curlText ?: string ;
365345 } ) => {
366346 const getConfig = ( ) => {
367- const workingDirectory = vscode . workspace . workspaceFolders ?. [ 0 ] ?. uri . fsPath ?? context . extensionPath ;
368- return resolveConfigWithPlugins ( { } , { workingDirectory} ) ;
347+ const config = configProvider . getConfig ( ) ;
348+ if ( ! config ) throw new Error ( 'No B2C Commerce configuration found. Configure dw.json or SFCC_* env vars.' ) ;
349+ return config ;
369350 } ;
370351
371352 if ( msg . type === 'scapiFetchSchemas' ) {
@@ -748,8 +729,13 @@ async function activateInner(context: vscode.ExtensionContext, log: vscode.Outpu
748729 vscode . window . showErrorMessage ( 'B2C DX: Tenant Id and Channel Id are required to create a SLAS client.' ) ;
749730 return ;
750731 }
751- const workingDirectory = vscode . workspace . workspaceFolders ?. [ 0 ] ?. uri . fsPath ?? context . extensionPath ;
752- const config = resolveConfigWithPlugins ( { } , { workingDirectory} ) ;
732+ const config = configProvider . getConfig ( ) ;
733+ if ( ! config ) {
734+ vscode . window . showErrorMessage (
735+ 'B2C DX: No B2C Commerce configuration found. Configure dw.json or SFCC_* env vars.' ,
736+ ) ;
737+ return ;
738+ }
753739 const shortCode = config . values . shortCode ;
754740 if ( ! shortCode ) {
755741 vscode . window . showErrorMessage (
@@ -861,26 +847,23 @@ async function activateInner(context: vscode.ExtensionContext, log: vscode.Outpu
861847 { enableScripts : true } ,
862848 ) ;
863849 let defaultRealm = '' ;
864- try {
865- const workingDirectory = vscode . workspace . workspaceFolders ?. [ 0 ] ?. uri . fsPath ?? context . extensionPath ;
866- const config = resolveConfigWithPlugins ( { } , { workingDirectory} ) ;
867- // First part of hostname, e.g. 'zyoc' from 'zyoc-003.unified.demandware.net'
868- const hostname = config . values . hostname ;
850+ const odsConfig = configProvider . getConfig ( ) ;
851+ if ( odsConfig ) {
852+ const hostname = odsConfig . values . hostname ;
869853 const firstSegment = ( hostname && typeof hostname === 'string' ? hostname : '' ) . split ( '.' ) [ 0 ] ?? '' ;
870854 defaultRealm = firstSegment . split ( '-' ) [ 0 ] ?? '' ;
871- } catch {
872- // leave defaultRealm empty
873855 }
874856 panel . webview . html = getOdsManagementWebviewContent ( context , { defaultRealm} ) ;
875857
876- async function getOdsConfig ( ) {
877- const workingDirectory = vscode . workspace . workspaceFolders ?. [ 0 ] ?. uri . fsPath ?? context . extensionPath ;
878- return resolveConfigWithPlugins ( { } , { workingDirectory} ) ;
858+ function getOdsConfig ( ) {
859+ const config = configProvider . getConfig ( ) ;
860+ if ( ! config ) throw new Error ( 'No B2C Commerce configuration found. Configure dw.json or SFCC_* env vars.' ) ;
861+ return config ;
879862 }
880863
881864 async function fetchSandboxList ( ) : Promise < { sandboxes : unknown [ ] ; error ?: string } > {
882865 try {
883- const config = await getOdsConfig ( ) ;
866+ const config = getOdsConfig ( ) ;
884867 if ( ! config . hasOAuthConfig ( ) ) {
885868 return { sandboxes : [ ] , error : 'OAuth credentials required. Set clientId and clientSecret in dw.json.' } ;
886869 }
@@ -914,7 +897,7 @@ async function activateInner(context: vscode.ExtensionContext, log: vscode.Outpu
914897 if ( msg . type === 'odsGetDefaultRealm' ) {
915898 let defaultRealm = '' ;
916899 try {
917- const config = await getOdsConfig ( ) ;
900+ const config = getOdsConfig ( ) ;
918901 const hostname = config . values . hostname ;
919902 const firstSegment = ( hostname && typeof hostname === 'string' ? hostname : '' ) . split ( '.' ) [ 0 ] ?? '' ;
920903 defaultRealm = firstSegment . split ( '-' ) [ 0 ] ?? '' ;
@@ -926,7 +909,7 @@ async function activateInner(context: vscode.ExtensionContext, log: vscode.Outpu
926909 }
927910 if ( msg . type === 'odsSandboxClick' && msg . sandboxId ) {
928911 try {
929- const config = await getOdsConfig ( ) ;
912+ const config = getOdsConfig ( ) ;
930913 if ( ! config . hasOAuthConfig ( ) ) {
931914 panel . webview . postMessage ( {
932915 type : 'odsSandboxDetailsError' ,
@@ -967,7 +950,7 @@ async function activateInner(context: vscode.ExtensionContext, log: vscode.Outpu
967950 }
968951 if ( msg . type === 'odsDeleteClick' && msg . sandboxId ) {
969952 try {
970- const config = await getOdsConfig ( ) ;
953+ const config = getOdsConfig ( ) ;
971954 if ( ! config . hasOAuthConfig ( ) ) {
972955 vscode . window . showErrorMessage ( 'B2C DX: OAuth credentials required for ODS. Configure dw.json.' ) ;
973956 return ;
@@ -995,7 +978,7 @@ async function activateInner(context: vscode.ExtensionContext, log: vscode.Outpu
995978 }
996979 if ( msg . type === 'odsCreateSandbox' && msg . realm !== undefined && msg . ttl !== undefined ) {
997980 try {
998- const config = await getOdsConfig ( ) ;
981+ const config = getOdsConfig ( ) ;
999982 if ( ! config . hasOAuthConfig ( ) ) {
1000983 vscode . window . showErrorMessage ( 'B2C DX: OAuth credentials required for ODS. Configure dw.json.' ) ;
1001984 return ;
@@ -1113,7 +1096,7 @@ async function activateInner(context: vscode.ExtensionContext, log: vscode.Outpu
11131096 vscode . window . showErrorMessage ( message ) ;
11141097 return ;
11151098 }
1116- const config = resolveConfigWithPlugins ( { } , { workingDirectory : projectDirectory } ) ;
1099+ const config = configProvider . resolveForDirectory ( projectDirectory ) ;
11171100 if ( ! config . hasB2CInstanceConfig ( ) ) {
11181101 const message =
11191102 'B2C DX: No instance config for deploy. Configure SFCC_* env vars or dw.json in the project.' ;
@@ -1181,7 +1164,7 @@ async function activateInner(context: vscode.ExtensionContext, log: vscode.Outpu
11811164 } ,
11821165 ) ;
11831166
1184- registerWebDavTree ( context ) ;
1167+ registerWebDavTree ( context , configProvider ) ;
11851168
11861169 context . subscriptions . push (
11871170 disposable ,
0 commit comments