Skip to content

Commit 6be308a

Browse files
authored
VS Code Safety Mode + content library fixes (#399)
* Enforce Safety Mode in VS Code extension Register the SDK safety middleware on the global middleware registry from the extension so destructive HTTP calls honor SFCC_SAFETY_LEVEL, SFCC_SAFETY_CONFIRM, SFCC_SAFETY_CONFIG, and per-instance `safety` blocks in dw.json. Rebuild the guard on config reset so instance switches re-apply the policy. Add registerSafeCommand() that evaluates every VS Code command against the guard (command rules like { "command": "b2c-dx.sandbox.delete", "action": "block" }), mirroring BaseCommand's per-command evaluation. Replace vscode.commands.registerCommand across all feature areas. Sandbox destructive ops additionally run through runWithSafety() for an idiomatic VS Code modal when the policy requires confirm. * Fix Content Libraries tree not updating on instance switch ContentConfigProvider was clearing only the library cache on config reset, so browsed libraries from the previous instance persisted in the tree. Also reset the browsed libraries list so getRootChildren() re-seeds from the new instance's contentLibrary on the next refresh. * Support assetQuery as a first-class config field Add assetQuery to NormalizedConfig and DwJsonConfig so it can be set per-instance in dw.json, project-wide in package.json under "b2c", or via SFCC_ASSET_QUERY. Wire it through the dw.json↔normalized mapping, merge, env source array parsing, and PackageJsonSource allow-list. The VS Code Content Libraries tree and export commands now pass the resolved value to fetchContentLibrary/exportContent; b2c content export falls back to the config value when --asset-query isn't provided (default remains ["image.path"]).
1 parent a51d82e commit 6be308a

22 files changed

Lines changed: 323 additions & 140 deletions

File tree

.changeset/asset-query-config.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@salesforce/b2c-tooling-sdk': minor
3+
'@salesforce/b2c-cli': minor
4+
'b2c-vs-extension': minor
5+
---
6+
7+
Support `assetQuery` as a first-class config field. Set it in `dw.json` (per-instance), in `package.json` under `b2c`, or via `SFCC_ASSET_QUERY` to control which JSON dot-paths are extracted as assets during content library parsing. The VS Code Content Libraries tree and `b2c content export` both honor it automatically; the `--asset-query` flag still wins when provided, and the fallback remains `["image.path"]`.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'b2c-vs-extension': patch
3+
---
4+
5+
Fix Content Libraries tree not updating when switching instances. The tree previously kept libraries from the old instance; it now re-seeds from the newly active instance's configured `contentLibrary` on switch.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'b2c-vs-extension': minor
3+
---
4+
5+
Enforce Safety Mode in the VS Code extension. Destructive operations initiated from the extension (sandbox delete/stop/restart, WebDAV writes, jobs, etc.) now honor `SFCC_SAFETY_LEVEL`, `SFCC_SAFETY_CONFIRM`, `SFCC_SAFETY_CONFIG`, and the per-instance `safety` block in `dw.json`, consistent with the CLI. Every extension command is also evaluated against command rules (e.g. `{ "command": "b2c-dx.sandbox.delete", "action": "block" }`), and confirmation-mode policies surface a native VS Code modal before the command runs.

packages/b2c-cli/src/commands/content/export.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,8 @@ export default class ContentExport extends JobCommand<typeof ContentExport> {
4848
}),
4949
'asset-query': Flags.string({
5050
char: 'q',
51-
description: 'JSON dot-paths for asset extraction',
51+
description: 'JSON dot-paths for asset extraction (falls back to config "assetQuery", then ["image.path"])',
5252
multiple: true,
53-
default: ['image.path'],
5453
}),
5554
regex: Flags.boolean({
5655
char: 'r',
@@ -117,12 +116,13 @@ export default class ContentExport extends JobCommand<typeof ContentExport> {
117116
}
118117

119118
const waitOptions = flags.timeout ? {timeoutSeconds: flags.timeout} : undefined;
119+
const assetQuery = flags['asset-query'] ?? this.resolvedConfig.values.assetQuery ?? ['image.path'];
120120

121121
if (flags['dry-run']) {
122122
const {library} = await this.operations.fetchContentLibrary(this.instance, libraryId, {
123123
libraryFile: flags['library-file'],
124124
isSiteLibrary: flags['site-library'],
125-
assetQuery: flags['asset-query'],
125+
assetQuery,
126126
keepOrphans: flags['keep-orphans'],
127127
waitOptions,
128128
});
@@ -222,7 +222,7 @@ export default class ContentExport extends JobCommand<typeof ContentExport> {
222222

223223
const result = await this.operations.exportContent(this.instance, pageIds, libraryId, outputPath, {
224224
isSiteLibrary: flags['site-library'],
225-
assetQuery: flags['asset-query'],
225+
assetQuery,
226226
libraryFile: flags['library-file'],
227227
offline: flags.offline,
228228
folders: flags.folder,

packages/b2c-tooling-sdk/src/config/dw-json.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ export interface DwJsonConfig {
8585
catalogs?: string[];
8686
/** Library IDs for WebDAV browsing */
8787
libraries?: string[];
88+
/** JSON dot-paths for asset extraction during content library parsing (defaults to ['image.path']) */
89+
assetQuery?: string[];
8890
/** Optional CIP analytics host override */
8991
cipHost?: string;
9092
/** Path to PKCS12 certificate file for mTLS (two-factor auth) */

packages/b2c-tooling-sdk/src/config/mapping.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ export function mapDwJsonToNormalizedConfig(json: DwJsonConfig): NormalizedConfi
161161
contentLibrary: json.contentLibrary,
162162
catalogs: json.catalogs,
163163
libraries: json.libraries,
164+
assetQuery: json.assetQuery,
164165
cipHost: json.cipHost,
165166
instanceName: json.name,
166167
authMethods: json.authMethods,
@@ -291,6 +292,9 @@ export function mapNormalizedConfigToDwJson(config: Partial<NormalizedConfig>, n
291292
if (config.libraries !== undefined) {
292293
result.libraries = config.libraries;
293294
}
295+
if (config.assetQuery !== undefined) {
296+
result.assetQuery = config.assetQuery;
297+
}
294298
if (config.cipHost !== undefined) {
295299
result.cipHost = config.cipHost;
296300
}
@@ -442,6 +446,7 @@ export function mergeConfigsWithProtection(
442446
contentLibrary: overrides.contentLibrary ?? base.contentLibrary,
443447
catalogs: overrides.catalogs ?? base.catalogs,
444448
libraries: overrides.libraries ?? base.libraries,
449+
assetQuery: overrides.assetQuery ?? base.assetQuery,
445450
cipHost: overrides.cipHost ?? base.cipHost,
446451
sandboxApiHost: overrides.sandboxApiHost ?? base.sandboxApiHost,
447452
realm: overrides.realm ?? base.realm,

packages/b2c-tooling-sdk/src/config/sources/env-source.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ const ENV_VAR_MAP: Record<string, keyof NormalizedConfig> = {
4040
SFCC_CARTRIDGES: 'cartridges',
4141
SFCC_CATALOGS: 'catalogs',
4242
SFCC_LIBRARIES: 'libraries',
43+
SFCC_ASSET_QUERY: 'assetQuery',
4344
SFCC_AUTH_METHODS: 'authMethods',
4445
SFCC_ACCOUNT_MANAGER_HOST: 'accountManagerHost',
4546
SFCC_SANDBOX_API_HOST: 'sandboxApiHost',
@@ -59,7 +60,14 @@ const ENV_VAR_MAP: Record<string, keyof NormalizedConfig> = {
5960
};
6061

6162
/** Fields that should be parsed as comma-separated arrays. */
62-
const ARRAY_FIELDS = new Set<keyof NormalizedConfig>(['scopes', 'authMethods', 'cartridges', 'catalogs', 'libraries']);
63+
const ARRAY_FIELDS = new Set<keyof NormalizedConfig>([
64+
'scopes',
65+
'authMethods',
66+
'cartridges',
67+
'catalogs',
68+
'libraries',
69+
'assetQuery',
70+
]);
6371

6472
/** Fields that should be parsed as booleans. */
6573
const BOOLEAN_FIELDS = new Set<keyof NormalizedConfig>(['selfSigned']);

packages/b2c-tooling-sdk/src/config/sources/package-json-source.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const ALLOWED_FIELDS: (keyof NormalizedConfig)[] = [
2525
'shortCode',
2626
'clientId',
2727
'contentLibrary',
28+
'assetQuery',
2829
'mrtProject',
2930
'mrtOrigin',
3031
'accountManagerHost',
@@ -39,6 +40,7 @@ interface PackageJsonB2CConfig {
3940
shortCode?: string;
4041
clientId?: string;
4142
contentLibrary?: string;
43+
assetQuery?: string[];
4244
mrtProject?: string;
4345
mrtOrigin?: string;
4446
accountManagerHost?: string;

packages/b2c-tooling-sdk/src/config/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,13 @@ export interface NormalizedConfig {
115115
/** Library IDs for WebDAV browsing */
116116
libraries?: string[];
117117

118+
/**
119+
* JSON dot-paths for asset extraction from component data during
120+
* content library parsing. Used by `content export` and the VS Code
121+
* content library browser. Defaults to `['image.path']` when unset.
122+
*/
123+
assetQuery?: string[];
124+
118125
// CIP
119126
/** Optional CIP analytics host override */
120127
cipHost?: string;

packages/b2c-vs-extension/src/api-browser/index.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66
import * as vscode from 'vscode';
77
import type {B2CExtensionConfig} from '../config-provider.js';
8+
import {registerSafeCommand} from '../safety.js';
89
import {ApiBrowserTreeDataProvider, type SchemaEntry} from './api-browser-tree-provider.js';
910
import {SwaggerWebviewManager} from './swagger-webview.js';
1011

@@ -21,16 +22,13 @@ export function registerApiBrowser(
2122
showCollapseAll: true,
2223
});
2324

24-
const refreshDisposable = vscode.commands.registerCommand('b2c-dx.apiBrowser.refresh', () => {
25+
const refreshDisposable = registerSafeCommand('b2c-dx.apiBrowser.refresh', () => {
2526
treeProvider.refresh();
2627
});
2728

28-
const openSwaggerDisposable = vscode.commands.registerCommand(
29-
'b2c-dx.apiBrowser.openSwagger',
30-
(schema: SchemaEntry) => {
31-
swaggerManager.openSwaggerPanel(schema);
32-
},
33-
);
29+
const openSwaggerDisposable = registerSafeCommand('b2c-dx.apiBrowser.openSwagger', (schema: SchemaEntry) => {
30+
swaggerManager.openSwaggerPanel(schema);
31+
});
3432

3533
configProvider.onDidReset(() => {
3634
treeProvider.refresh();

0 commit comments

Comments
 (0)