@salesforce/b2c-dx-mcp 1.10.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -62
- package/dist/commands/mcp.d.ts +14 -7
- package/dist/commands/mcp.js +91 -12
- package/dist/registry.d.ts +3 -3
- package/dist/registry.js +7 -14
- package/dist/server-context.d.ts +1 -1
- package/dist/server-context.js +1 -1
- package/dist/services.d.ts +29 -1
- package/dist/services.js +48 -1
- package/dist/tools/adapter.d.ts +25 -1
- package/dist/tools/adapter.js +53 -8
- package/dist/tools/cartridges/index.js +14 -3
- package/dist/tools/diagnostics/config-inspect.js +3 -2
- package/dist/tools/diagnostics/debug-list-sessions.js +1 -1
- package/dist/tools/diagnostics/debug-start-session.js +22 -9
- package/dist/tools/diagnostics/log-watch-registry.d.ts +3 -0
- package/dist/tools/diagnostics/log-watch-registry.js +1 -0
- package/dist/tools/diagnostics/logs-watch-list.js +1 -0
- package/dist/tools/diagnostics/logs-watch-start.js +6 -1
- package/dist/tools/diagnostics/mrt-log-watch-registry.d.ts +3 -0
- package/dist/tools/diagnostics/mrt-log-watch-registry.js +0 -0
- package/dist/tools/diagnostics/mrt-logs-watch-list.js +1 -0
- package/dist/tools/diagnostics/mrt-logs-watch-start.js +7 -1
- package/dist/tools/diagnostics/session-registry.d.ts +3 -0
- package/dist/tools/diagnostics/session-registry.js +4 -3
- package/dist/tools/index.d.ts +0 -1
- package/dist/tools/index.js +0 -1
- package/dist/tools/mrt/index.js +13 -3
- package/dist/tools/project-context.d.ts +53 -0
- package/dist/tools/project-context.js +55 -0
- package/dist/tools/scapi/metrics-get.js +1 -0
- package/dist/tools/scapi/scapi-custom-api-generate-scaffold.d.ts +8 -1
- package/dist/tools/scapi/scapi-custom-api-generate-scaffold.js +41 -7
- package/dist/tools/scapi/scapi-custom-apis-get-status.js +1 -0
- package/dist/tools/scapi/scapi-schemas-list.js +1 -0
- package/dist/utils/constants.d.ts +2 -13
- package/dist/utils/constants.js +1 -20
- package/oclif.manifest.json +2 -2
- package/package.json +3 -3
- package/content/sfnext/auth.md +0 -62
- package/content/sfnext/components.md +0 -123
- package/content/sfnext/config.md +0 -180
- package/content/sfnext/data-fetching.md +0 -323
- package/content/sfnext/extensions.md +0 -80
- package/content/sfnext/i18n.md +0 -121
- package/content/sfnext/page-designer.md +0 -78
- package/content/sfnext/performance.md +0 -80
- package/content/sfnext/pitfalls.md +0 -141
- package/content/sfnext/quick-reference.md +0 -226
- package/content/sfnext/state-management.md +0 -75
- package/content/sfnext/styling.md +0 -51
- package/content/sfnext/testing.md +0 -232
- package/dist/tools/storefrontnext/figma/figma-to-component/figma-url-parser.d.ts +0 -24
- package/dist/tools/storefrontnext/figma/figma-to-component/figma-url-parser.js +0 -53
- package/dist/tools/storefrontnext/figma/figma-to-component/index.d.ts +0 -42
- package/dist/tools/storefrontnext/figma/figma-to-component/index.js +0 -326
- package/dist/tools/storefrontnext/figma/generate-component/decision.d.ts +0 -40
- package/dist/tools/storefrontnext/figma/generate-component/decision.js +0 -312
- package/dist/tools/storefrontnext/figma/generate-component/formatter.d.ts +0 -9
- package/dist/tools/storefrontnext/figma/generate-component/formatter.js +0 -92
- package/dist/tools/storefrontnext/figma/generate-component/index.d.ts +0 -114
- package/dist/tools/storefrontnext/figma/generate-component/index.js +0 -99
- package/dist/tools/storefrontnext/figma/map-tokens/css-parser.d.ts +0 -71
- package/dist/tools/storefrontnext/figma/map-tokens/css-parser.js +0 -260
- package/dist/tools/storefrontnext/figma/map-tokens/index.d.ts +0 -61
- package/dist/tools/storefrontnext/figma/map-tokens/index.js +0 -235
- package/dist/tools/storefrontnext/figma/map-tokens/token-matcher.d.ts +0 -65
- package/dist/tools/storefrontnext/figma/map-tokens/token-matcher.js +0 -268
- package/dist/tools/storefrontnext/index.d.ts +0 -30
- package/dist/tools/storefrontnext/index.js +0 -28
- package/dist/tools/storefrontnext/page-designer-decorator/analyzer.d.ts +0 -169
- package/dist/tools/storefrontnext/page-designer-decorator/analyzer.js +0 -567
- package/dist/tools/storefrontnext/page-designer-decorator/index.d.ts +0 -252
- package/dist/tools/storefrontnext/page-designer-decorator/index.js +0 -617
- package/dist/tools/storefrontnext/page-designer-decorator/rules/1-mode-selection.d.ts +0 -8
- package/dist/tools/storefrontnext/page-designer-decorator/rules/1-mode-selection.js +0 -65
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2a-auto-mode.d.ts +0 -13
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2a-auto-mode.js +0 -87
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-0-interactive-overview.d.ts +0 -4
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-0-interactive-overview.js +0 -55
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-1-interactive-analyze.d.ts +0 -22
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-1-interactive-analyze.js +0 -109
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-2-interactive-select-props.d.ts +0 -21
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-2-interactive-select-props.js +0 -60
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-3-interactive-configure-attrs.d.ts +0 -27
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-3-interactive-configure-attrs.js +0 -68
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-4-interactive-configure-regions.d.ts +0 -4
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-4-interactive-configure-regions.js +0 -65
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-5-interactive-confirm-generation.d.ts +0 -11
- package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-5-interactive-confirm-generation.js +0 -92
- package/dist/tools/storefrontnext/page-designer-decorator/rules.d.ts +0 -51
- package/dist/tools/storefrontnext/page-designer-decorator/rules.js +0 -70
- package/dist/tools/storefrontnext/page-designer-decorator/templates/decorator-generator.d.ts +0 -116
- package/dist/tools/storefrontnext/page-designer-decorator/templates/decorator-generator.js +0 -350
- package/dist/tools/storefrontnext/sfnext-development-guidelines.d.ts +0 -9
- package/dist/tools/storefrontnext/sfnext-development-guidelines.js +0 -141
- package/dist/tools/storefrontnext/site-theming/color-contrast.d.ts +0 -92
- package/dist/tools/storefrontnext/site-theming/color-contrast.js +0 -186
- package/dist/tools/storefrontnext/site-theming/color-mapping.d.ts +0 -16
- package/dist/tools/storefrontnext/site-theming/color-mapping.js +0 -131
- package/dist/tools/storefrontnext/site-theming/guidance-merger.d.ts +0 -11
- package/dist/tools/storefrontnext/site-theming/guidance-merger.js +0 -78
- package/dist/tools/storefrontnext/site-theming/index.d.ts +0 -14
- package/dist/tools/storefrontnext/site-theming/index.js +0 -123
- package/dist/tools/storefrontnext/site-theming/response-builder.d.ts +0 -16
- package/dist/tools/storefrontnext/site-theming/response-builder.js +0 -316
- package/dist/tools/storefrontnext/site-theming/theming-store.d.ts +0 -62
- package/dist/tools/storefrontnext/site-theming/theming-store.js +0 -417
- package/dist/tools/storefrontnext/site-theming/types.d.ts +0 -35
- package/dist/tools/storefrontnext/site-theming/types.js +0 -7
|
@@ -21,7 +21,8 @@ const CUSTOM_API_SCAFFOLD_ID = 'custom-api';
|
|
|
21
21
|
* Exported for tests so we can inject getScaffold / resolveScaffoldParameters and cover error branches.
|
|
22
22
|
*/
|
|
23
23
|
export async function executeScaffoldCustomApi(args, services, overrides) {
|
|
24
|
-
const
|
|
24
|
+
const projectDirectory = services.resolveProjectDirectory(args.projectDirectory);
|
|
25
|
+
const projectRoot = services.resolveWithProjectDirectory(args.cartridgeDirectory ?? args.projectRoot, args.projectDirectory);
|
|
25
26
|
const getScaffold = overrides?.getScaffold ??
|
|
26
27
|
(async (id, opts) => {
|
|
27
28
|
const registry = createScaffoldRegistry();
|
|
@@ -34,6 +35,8 @@ export async function executeScaffoldCustomApi(args, services, overrides) {
|
|
|
34
35
|
outputDir: projectRoot,
|
|
35
36
|
dryRun: false,
|
|
36
37
|
files: [],
|
|
38
|
+
projectDirectory,
|
|
39
|
+
projectRoot,
|
|
37
40
|
error: `Scaffold not found: ${CUSTOM_API_SCAFFOLD_ID}. Ensure @salesforce/b2c-tooling-sdk is installed.`,
|
|
38
41
|
};
|
|
39
42
|
}
|
|
@@ -44,6 +47,8 @@ export async function executeScaffoldCustomApi(args, services, overrides) {
|
|
|
44
47
|
outputDir: projectRoot,
|
|
45
48
|
dryRun: false,
|
|
46
49
|
files: [],
|
|
50
|
+
projectDirectory,
|
|
51
|
+
projectRoot,
|
|
47
52
|
error: 'No cartridges found in project. Custom API scaffold requires an existing cartridge. Create a cartridge first: use `b2c scaffold cartridge --name app_custom`, or manually create a directory with a `.project` file (e.g., cartridges/app_custom/.project).',
|
|
48
53
|
};
|
|
49
54
|
}
|
|
@@ -73,6 +78,8 @@ export async function executeScaffoldCustomApi(args, services, overrides) {
|
|
|
73
78
|
outputDir: projectRoot,
|
|
74
79
|
dryRun: false,
|
|
75
80
|
files: [],
|
|
81
|
+
projectDirectory,
|
|
82
|
+
projectRoot,
|
|
76
83
|
error: `Parameter validation failed: ${message}`,
|
|
77
84
|
};
|
|
78
85
|
}
|
|
@@ -83,11 +90,13 @@ export async function executeScaffoldCustomApi(args, services, overrides) {
|
|
|
83
90
|
outputDir: projectRoot,
|
|
84
91
|
dryRun: false,
|
|
85
92
|
files: [],
|
|
93
|
+
projectDirectory,
|
|
94
|
+
projectRoot,
|
|
86
95
|
error: `Missing required parameter: ${missingRequired[0].name}. For cartridgeName, ensure the cartridge exists in the project (under projectRoot).`,
|
|
87
96
|
};
|
|
88
97
|
}
|
|
89
98
|
const outputDir = resolveOutputDirectory({
|
|
90
|
-
outputDir: args.outputDir,
|
|
99
|
+
outputDir: args.outputDirectory ?? args.outputDir,
|
|
91
100
|
scaffold,
|
|
92
101
|
projectRoot,
|
|
93
102
|
});
|
|
@@ -108,6 +117,8 @@ export async function executeScaffoldCustomApi(args, services, overrides) {
|
|
|
108
117
|
skipReason: f.skipReason,
|
|
109
118
|
})),
|
|
110
119
|
postInstructions: result.postInstructions,
|
|
120
|
+
projectDirectory,
|
|
121
|
+
projectRoot,
|
|
111
122
|
};
|
|
112
123
|
}
|
|
113
124
|
catch (error) {
|
|
@@ -117,6 +128,8 @@ export async function executeScaffoldCustomApi(args, services, overrides) {
|
|
|
117
128
|
outputDir,
|
|
118
129
|
dryRun: false,
|
|
119
130
|
files: [],
|
|
131
|
+
projectDirectory,
|
|
132
|
+
projectRoot,
|
|
120
133
|
error: `Scaffold generation failed: ${message}`,
|
|
121
134
|
};
|
|
122
135
|
}
|
|
@@ -136,10 +149,11 @@ export function createScaffoldCustomApiTool(loadServices, executeOverrides) {
|
|
|
136
149
|
name: 'scapi_custom_api_generate_scaffold',
|
|
137
150
|
description: `Generate a new custom SCAPI endpoint (OAS 3.0 schema, api.json, script.js) in an existing cartridge. \
|
|
138
151
|
Required: apiName (kebab-case). Optional: cartridgeName (defaults to first cartridge found in project), apiType (shopper|admin) default to shopper, \
|
|
139
|
-
apiDescription,
|
|
152
|
+
apiDescription, cartridgeDirectory, outputDirectory.`,
|
|
140
153
|
toolsets: ['PWAV3', 'SCAPI', 'STOREFRONTNEXT'],
|
|
141
154
|
isGA: true,
|
|
142
155
|
requiresInstance: false,
|
|
156
|
+
usesProjectContext: true,
|
|
143
157
|
inputSchema: {
|
|
144
158
|
apiName: z
|
|
145
159
|
.string()
|
|
@@ -155,14 +169,34 @@ apiDescription, projectRoot, outputDir.`,
|
|
|
155
169
|
.optional()
|
|
156
170
|
.describe('Admin (no siteId) or shopper (siteId, customer-facing). Default: shopper'),
|
|
157
171
|
apiDescription: z.string().optional().describe('Short description of the API.'),
|
|
172
|
+
cartridgeDirectory: z
|
|
173
|
+
.string()
|
|
174
|
+
.nullish()
|
|
175
|
+
.describe('Optional cartridge discovery root, resolved relative to projectDirectory. Defaults to projectDirectory.'),
|
|
158
176
|
projectRoot: z
|
|
159
177
|
.string()
|
|
160
178
|
.nullish()
|
|
161
|
-
.describe('
|
|
162
|
-
|
|
179
|
+
.describe('Deprecated alias for cartridgeDirectory. cartridgeDirectory takes precedence.'),
|
|
180
|
+
outputDirectory: z
|
|
181
|
+
.string()
|
|
182
|
+
.optional()
|
|
183
|
+
.describe('Optional output directory. Relative paths resolve from cartridgeDirectory.'),
|
|
184
|
+
outputDir: z
|
|
185
|
+
.string()
|
|
186
|
+
.optional()
|
|
187
|
+
.describe('Deprecated alias for outputDirectory. outputDirectory takes precedence.'),
|
|
163
188
|
},
|
|
164
|
-
async execute(args,
|
|
165
|
-
|
|
189
|
+
async execute(args, context) {
|
|
190
|
+
const output = await executeScaffoldCustomApi(args, context.services, executeOverrides);
|
|
191
|
+
context.setResolvedDirectory('cartridgeDirectory', {
|
|
192
|
+
path: output.projectRoot,
|
|
193
|
+
source: args.cartridgeDirectory || args.projectRoot ? 'argument' : 'projectDirectory',
|
|
194
|
+
});
|
|
195
|
+
context.setResolvedDirectory('outputDirectory', {
|
|
196
|
+
path: output.outputDir,
|
|
197
|
+
source: args.outputDirectory || args.outputDir ? 'argument' : 'projectDirectory',
|
|
198
|
+
});
|
|
199
|
+
return output;
|
|
166
200
|
},
|
|
167
201
|
formatOutput(output) {
|
|
168
202
|
if (output.error) {
|
|
@@ -94,6 +94,7 @@ CLI: b2c scapi custom status`,
|
|
|
94
94
|
toolsets: ['PWAV3', 'SCAPI', 'STOREFRONTNEXT'],
|
|
95
95
|
isGA: true,
|
|
96
96
|
requiresInstance: false,
|
|
97
|
+
usesConfigurationContext: true,
|
|
97
98
|
inputSchema: {
|
|
98
99
|
status: z.enum(['active', 'not_registered']).optional().describe('Filter by status. Omit for all.'),
|
|
99
100
|
groupBy: z.enum(['site', 'type']).optional().describe('Group by siteId or type (Admin/Shopper).'),
|
|
@@ -199,6 +199,7 @@ export function createScapiSchemasListTool(loadServices) {
|
|
|
199
199
|
toolsets: ['PWAV3', 'SCAPI', 'STOREFRONTNEXT'],
|
|
200
200
|
isGA: true,
|
|
201
201
|
requiresInstance: false, // SCAPI uses OAuth directly, doesn't need B2CInstance (hostname)
|
|
202
|
+
usesConfigurationContext: true,
|
|
202
203
|
inputSchema: {
|
|
203
204
|
apiFamily: z.string().optional().describe('API family (e.g., "checkout", "product", "custom").'),
|
|
204
205
|
apiName: z.string().optional().describe('API name (e.g., "shopper-baskets", "shopper-products").'),
|
|
@@ -5,22 +5,11 @@ export declare const ALL_TOOLSETS = "ALL";
|
|
|
5
5
|
/**
|
|
6
6
|
* Available toolsets that can be enabled.
|
|
7
7
|
*/
|
|
8
|
-
export declare const TOOLSETS: readonly ["CARTRIDGES", "DIAGNOSTICS", "MRT", "PWAV3", "SCAPI", "STOREFRONTNEXT"
|
|
9
|
-
/**
|
|
10
|
-
* Deprecated toolsets. These can only be enabled by explicitly naming them via
|
|
11
|
-
* `--toolsets`; they are never auto-activated by project detection and are NOT
|
|
12
|
-
* included when `--toolsets ALL` is used.
|
|
13
|
-
*
|
|
14
|
-
* `STOREFRONTNEXT_DEPRECATED` holds the legacy `sfnext_*` MCP tools. They are
|
|
15
|
-
* superseded by the `storefront-next` and `storefront-next-figma` agent-skills
|
|
16
|
-
* plugins and are not compatible with the Storefront Next 1.0 GA release. They
|
|
17
|
-
* will be removed in a future release.
|
|
18
|
-
*/
|
|
19
|
-
export declare const DEPRECATED_TOOLSETS: readonly ["STOREFRONTNEXT_DEPRECATED"];
|
|
8
|
+
export declare const TOOLSETS: readonly ["CARTRIDGES", "DIAGNOSTICS", "MRT", "PWAV3", "SCAPI", "STOREFRONTNEXT"];
|
|
20
9
|
/**
|
|
21
10
|
* Valid toolset names including the special "ALL" value.
|
|
22
11
|
*/
|
|
23
|
-
export declare const VALID_TOOLSET_NAMES: readonly ["ALL", "CARTRIDGES", "DIAGNOSTICS", "MRT", "PWAV3", "SCAPI", "STOREFRONTNEXT"
|
|
12
|
+
export declare const VALID_TOOLSET_NAMES: readonly ["ALL", "CARTRIDGES", "DIAGNOSTICS", "MRT", "PWAV3", "SCAPI", "STOREFRONTNEXT"];
|
|
24
13
|
/**
|
|
25
14
|
* Type representing a valid toolset name.
|
|
26
15
|
*/
|
package/dist/utils/constants.js
CHANGED
|
@@ -10,26 +10,7 @@ export const ALL_TOOLSETS = 'ALL';
|
|
|
10
10
|
/**
|
|
11
11
|
* Available toolsets that can be enabled.
|
|
12
12
|
*/
|
|
13
|
-
export const TOOLSETS = [
|
|
14
|
-
'CARTRIDGES',
|
|
15
|
-
'DIAGNOSTICS',
|
|
16
|
-
'MRT',
|
|
17
|
-
'PWAV3',
|
|
18
|
-
'SCAPI',
|
|
19
|
-
'STOREFRONTNEXT',
|
|
20
|
-
'STOREFRONTNEXT_DEPRECATED',
|
|
21
|
-
];
|
|
22
|
-
/**
|
|
23
|
-
* Deprecated toolsets. These can only be enabled by explicitly naming them via
|
|
24
|
-
* `--toolsets`; they are never auto-activated by project detection and are NOT
|
|
25
|
-
* included when `--toolsets ALL` is used.
|
|
26
|
-
*
|
|
27
|
-
* `STOREFRONTNEXT_DEPRECATED` holds the legacy `sfnext_*` MCP tools. They are
|
|
28
|
-
* superseded by the `storefront-next` and `storefront-next-figma` agent-skills
|
|
29
|
-
* plugins and are not compatible with the Storefront Next 1.0 GA release. They
|
|
30
|
-
* will be removed in a future release.
|
|
31
|
-
*/
|
|
32
|
-
export const DEPRECATED_TOOLSETS = ['STOREFRONTNEXT_DEPRECATED'];
|
|
13
|
+
export const TOOLSETS = ['CARTRIDGES', 'DIAGNOSTICS', 'MRT', 'PWAV3', 'SCAPI', 'STOREFRONTNEXT'];
|
|
33
14
|
/**
|
|
34
15
|
* Valid toolset names including the special "ALL" value.
|
|
35
16
|
*/
|
package/oclif.manifest.json
CHANGED
|
@@ -388,7 +388,7 @@
|
|
|
388
388
|
"type": "boolean"
|
|
389
389
|
},
|
|
390
390
|
"toolsets": {
|
|
391
|
-
"description": "Toolsets to enable (comma-separated). Options: all, CARTRIDGES, DIAGNOSTICS, MRT, PWAV3, SCAPI, STOREFRONTNEXT
|
|
391
|
+
"description": "Toolsets to enable (comma-separated). Options: all, CARTRIDGES, DIAGNOSTICS, MRT, PWAV3, SCAPI, STOREFRONTNEXT",
|
|
392
392
|
"env": "SFCC_TOOLSETS",
|
|
393
393
|
"name": "toolsets",
|
|
394
394
|
"hasDynamicHelp": false,
|
|
@@ -429,5 +429,5 @@
|
|
|
429
429
|
"enableJsonFlag": false
|
|
430
430
|
}
|
|
431
431
|
},
|
|
432
|
-
"version": "1.
|
|
432
|
+
"version": "2.1.0"
|
|
433
433
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/b2c-dx-mcp",
|
|
3
3
|
"description": "MCP server for B2C Commerce developer experience tools",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "2.1.0",
|
|
5
5
|
"author": "Salesforce",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"repository": "SalesforceCommerceCloud/b2c-developer-tooling",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"yaml": "2.9.0",
|
|
81
81
|
"postcss": "8.5.15",
|
|
82
82
|
"zod": "3.25.76",
|
|
83
|
-
"@salesforce/b2c-tooling-sdk": "1.
|
|
83
|
+
"@salesforce/b2c-tooling-sdk": "1.24.1"
|
|
84
84
|
},
|
|
85
85
|
"devDependencies": {
|
|
86
86
|
"@eslint/compat": "^1",
|
|
@@ -126,7 +126,7 @@
|
|
|
126
126
|
"test": "c8 mocha --forbid-only --ignore \"test/e2e/**\" \"test/**/*.test.ts\"",
|
|
127
127
|
"test:ci": "c8 mocha --forbid-only --reporter json --reporter-option output=test-results.json --ignore \"test/e2e/**\" \"test/**/*.test.ts\"",
|
|
128
128
|
"test:ci:win": "c8 --check-coverage=false mocha --forbid-only --reporter json --reporter-option output=test-results.json --ignore \"test/e2e/**\" \"test/**/*.test.ts\"",
|
|
129
|
-
"test:agent": "mocha --forbid-only --reporter min --ignore \"test/e2e/**\" \"test/**/*.test.ts\"",
|
|
129
|
+
"test:agent": "pnpm run pretest && mocha --forbid-only --reporter min --ignore \"test/e2e/**\" \"test/**/*.test.ts\"",
|
|
130
130
|
"test:e2e": "mocha --forbid-only \"test/e2e/**/*.test.ts\"",
|
|
131
131
|
"test:e2e:ci": "mocha --forbid-only --reporter json --reporter-option output=test-results-e2e.json \"test/e2e/**/*.test.ts\"",
|
|
132
132
|
"coverage": "c8 report",
|
package/content/sfnext/auth.md
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# Authentication & Session Management
|
|
2
|
-
|
|
3
|
-
## Architecture
|
|
4
|
-
|
|
5
|
-
Split-cookie architecture with server/client contexts:
|
|
6
|
-
|
|
7
|
-
- **Server middleware** (`auth.server.ts`): Manages SLAS tokens, writes cookies
|
|
8
|
-
- **Client middleware** (`auth.client.ts`): Reads cookies, maintains cache
|
|
9
|
-
- **React Context** (`AuthProvider`): Provides auth state to components
|
|
10
|
-
|
|
11
|
-
## Cookie Design
|
|
12
|
-
|
|
13
|
-
| Cookie Name | Purpose | User Type | Expiry | HttpOnly |
|
|
14
|
-
|-------------|---------|-----------|--------|----------|
|
|
15
|
-
| `cc-nx-g` | Guest refresh token | Guest | 30 days | No |
|
|
16
|
-
| `cc-nx` | Registered refresh token | Registered | 90 days | No |
|
|
17
|
-
| `cc-at` | Access token | Both | 30 min | No |
|
|
18
|
-
| `usid` | User session ID | Both | Matches refresh | No |
|
|
19
|
-
| `customerId` | Customer ID | Registered | Matches refresh | No |
|
|
20
|
-
|
|
21
|
-
**Key Points**:
|
|
22
|
-
|
|
23
|
-
- Only ONE refresh token exists (guest OR registered, never both)
|
|
24
|
-
- User type derived from which refresh token exists
|
|
25
|
-
- Cookies auto-namespaced with `siteId`
|
|
26
|
-
- Tokens auto-refresh when expired
|
|
27
|
-
|
|
28
|
-
## Usage in Loaders/Actions
|
|
29
|
-
|
|
30
|
-
```typescript
|
|
31
|
-
import { getAuth } from '@/middlewares/auth.server';
|
|
32
|
-
|
|
33
|
-
export function loader({ context }: LoaderFunctionArgs) {
|
|
34
|
-
const auth = getAuth(context);
|
|
35
|
-
|
|
36
|
-
// Access auth properties
|
|
37
|
-
const accessToken = auth.access_token;
|
|
38
|
-
const customerId = auth.customer_id;
|
|
39
|
-
const isGuest = auth.userType === 'guest';
|
|
40
|
-
const isRegistered = auth.userType === 'registered';
|
|
41
|
-
|
|
42
|
-
return { isGuest, customerId };
|
|
43
|
-
}
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Usage in Components
|
|
47
|
-
|
|
48
|
-
```typescript
|
|
49
|
-
import { useAuth } from '@/providers/auth';
|
|
50
|
-
|
|
51
|
-
export function MyComponent() {
|
|
52
|
-
const auth = useAuth();
|
|
53
|
-
|
|
54
|
-
if (auth?.userType === 'guest') {
|
|
55
|
-
return <LoginPrompt />;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return <div>Welcome, customer {auth?.customer_id}</div>;
|
|
59
|
-
}
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
**Reference:** See README-AUTH.md for complete authentication documentation.
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
# Component Patterns
|
|
2
|
-
|
|
3
|
-
## Use the `createPage` HOC
|
|
4
|
-
|
|
5
|
-
The `createPage` higher-order component standardizes page patterns with built-in Suspense and page key handling:
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
import { use } from 'react';
|
|
9
|
-
import { createPage } from '@/components/create-page';
|
|
10
|
-
|
|
11
|
-
// Define your view component
|
|
12
|
-
function ProductView({
|
|
13
|
-
product,
|
|
14
|
-
category
|
|
15
|
-
}: {
|
|
16
|
-
product: Promise<Product>;
|
|
17
|
-
category?: Promise<Category>
|
|
18
|
-
}) {
|
|
19
|
-
const productData = use(product);
|
|
20
|
-
const categoryData = category ? use(category) : null;
|
|
21
|
-
|
|
22
|
-
return (
|
|
23
|
-
<div>
|
|
24
|
-
<h1>{productData.name}</h1>
|
|
25
|
-
{categoryData && <p>Category: {categoryData.name}</p>}
|
|
26
|
-
</div>
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Create page with fallback
|
|
31
|
-
const ProductPage = createPage({
|
|
32
|
-
component: ProductView,
|
|
33
|
-
fallback: <ProductSkeleton />
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
export default ProductPage;
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
**Benefits:**
|
|
40
|
-
|
|
41
|
-
- Eliminates repetitive Suspense/Await boilerplate
|
|
42
|
-
- Consistent loading states across pages
|
|
43
|
-
- Built-in page key management for navigation transitions
|
|
44
|
-
- Type-safe with full TypeScript support
|
|
45
|
-
|
|
46
|
-
## shadcn/ui Components
|
|
47
|
-
|
|
48
|
-
**RULES**:
|
|
49
|
-
|
|
50
|
-
- ✅ Add via: `npx shadcn@latest add <component-name>`
|
|
51
|
-
- ❌ DO NOT modify `src/components/ui/` directly
|
|
52
|
-
- ✅ Create custom components elsewhere
|
|
53
|
-
|
|
54
|
-
## Suspense Boundaries
|
|
55
|
-
|
|
56
|
-
Use granular Suspense boundaries for better UX:
|
|
57
|
-
|
|
58
|
-
```typescript
|
|
59
|
-
// ✅ RECOMMENDED - Multiple Suspense boundaries
|
|
60
|
-
export default function ProductPage({ loaderData: { product, reviews } }) {
|
|
61
|
-
return (
|
|
62
|
-
<div>
|
|
63
|
-
<Suspense fallback={<ProductHeaderSkeleton />}>
|
|
64
|
-
<Await resolve={product}>
|
|
65
|
-
{(data) => <ProductHeader product={data} />}
|
|
66
|
-
</Await>
|
|
67
|
-
</Suspense>
|
|
68
|
-
|
|
69
|
-
<Suspense fallback={<ReviewsSkeleton />}>
|
|
70
|
-
<Await resolve={reviews}>
|
|
71
|
-
{(data) => <ProductReviews reviews={data} />}
|
|
72
|
-
</Await>
|
|
73
|
-
</Suspense>
|
|
74
|
-
</div>
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// ⚠️ OK - Single Suspense boundary (less granular)
|
|
79
|
-
export default createPage({
|
|
80
|
-
component: ProductView,
|
|
81
|
-
fallback: <ProductPageSkeleton />
|
|
82
|
-
});
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
## File Organization
|
|
86
|
-
|
|
87
|
-
```
|
|
88
|
-
src/components/product-tile/
|
|
89
|
-
├── index.tsx # Component
|
|
90
|
-
├── index.test.tsx # Tests
|
|
91
|
-
└── stories/
|
|
92
|
-
├── index.stories.tsx # Storybook stories
|
|
93
|
-
└── __snapshots__/ # Storybook snapshots (optional)
|
|
94
|
-
└── product-tile-snapshot.tsx.snap
|
|
95
|
-
|
|
96
|
-
# Skeleton components are separate components
|
|
97
|
-
src/components/product-skeleton/
|
|
98
|
-
├── index.tsx
|
|
99
|
-
├── index.test.tsx
|
|
100
|
-
└── stories/
|
|
101
|
-
└── index.stories.tsx
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
## Styling
|
|
105
|
-
|
|
106
|
-
**Tailwind CSS 4** is the only styling approach allowed. Use utility classes directly in components.
|
|
107
|
-
|
|
108
|
-
**Key rules:**
|
|
109
|
-
|
|
110
|
-
- ✅ Use Tailwind utility classes
|
|
111
|
-
- ✅ Use `cn()` utility for conditional classes
|
|
112
|
-
- ❌ NO inline styles, NO CSS modules, NO separate CSS files
|
|
113
|
-
|
|
114
|
-
**See `styling` section for:** Tailwind CSS 4, Shadcn/ui components, icons, responsive design, theme configuration, dark mode, best practices
|
|
115
|
-
|
|
116
|
-
## Best Practices
|
|
117
|
-
|
|
118
|
-
1. **Extract view components** - Separate data handling from presentation
|
|
119
|
-
2. **Type safety** - Define proper TypeScript interfaces
|
|
120
|
-
3. **Consistent fallbacks** - Reusable skeleton components
|
|
121
|
-
4. **Colocate tests** - Keep tests next to components
|
|
122
|
-
5. **Story coverage** - Create stories for all reusable components
|
|
123
|
-
6. **Tailwind utilities only** - Use Tailwind CSS classes, avoid inline styles or CSS modules
|
package/content/sfnext/config.md
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
# Configuration Management
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
All configuration is centralized in `config.server.ts` with environment variable overrides via `.env` files. The configuration system provides type-safe access to app settings with automatic parsing and validation.
|
|
6
|
-
|
|
7
|
-
## Required Variables
|
|
8
|
-
|
|
9
|
-
Copy `.env.default` to `.env` and set these required Commerce Cloud credentials:
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
PUBLIC__app__commerce__api__clientId=your-client-id
|
|
13
|
-
PUBLIC__app__commerce__api__organizationId=your-org-id
|
|
14
|
-
PUBLIC__app__commerce__api__siteId=your-site-id
|
|
15
|
-
PUBLIC__app__commerce__api__shortCode=your-short-code
|
|
16
|
-
PUBLIC__app__defaultSiteId=your-site-id
|
|
17
|
-
PUBLIC__app__commerce__sites='[{"id":"your-site-id","defaultLocale":"en-US","defaultCurrency":"USD","supportedLocales":[{"id":"en-US","preferredCurrency":"USD"}],"supportedCurrencies":["USD"]}]'
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
**Note:** The `commerce.sites` array defines your site configuration including locales, currencies, and supported options. See `.env.default` for a complete example with multiple locales and currencies.
|
|
21
|
-
|
|
22
|
-
## Adding Configuration
|
|
23
|
-
|
|
24
|
-
1. **Define type in `src/config/schema.ts`**:
|
|
25
|
-
|
|
26
|
-
```typescript
|
|
27
|
-
export type Config = {
|
|
28
|
-
app: {
|
|
29
|
-
myFeature: {
|
|
30
|
-
enabled: boolean;
|
|
31
|
-
maxItems: number;
|
|
32
|
-
};
|
|
33
|
-
};
|
|
34
|
-
};
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
2. **Add defaults in `config.server.ts`**:
|
|
38
|
-
|
|
39
|
-
```typescript
|
|
40
|
-
export default defineConfig({
|
|
41
|
-
app: {
|
|
42
|
-
myFeature: {
|
|
43
|
-
enabled: false,
|
|
44
|
-
maxItems: 10,
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
});
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
3. **Override via environment variables**:
|
|
51
|
-
|
|
52
|
-
```bash
|
|
53
|
-
PUBLIC__app__myFeature__enabled=true
|
|
54
|
-
PUBLIC__app__myFeature__maxItems=20
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
## Usage Patterns
|
|
58
|
-
|
|
59
|
-
**In React Components**:
|
|
60
|
-
|
|
61
|
-
```typescript
|
|
62
|
-
import { useConfig } from '@/config';
|
|
63
|
-
|
|
64
|
-
export function MyComponent() {
|
|
65
|
-
const config = useConfig();
|
|
66
|
-
|
|
67
|
-
if (config.myFeature.enabled) {
|
|
68
|
-
const maxItems = config.myFeature.maxItems;
|
|
69
|
-
// Your feature code
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
**In Server Loaders/Actions**:
|
|
75
|
-
|
|
76
|
-
```typescript
|
|
77
|
-
import { getConfig } from '@/config';
|
|
78
|
-
|
|
79
|
-
export function loader({ context }: LoaderFunctionArgs) {
|
|
80
|
-
const config = getConfig(context);
|
|
81
|
-
|
|
82
|
-
if (config.myFeature.enabled) {
|
|
83
|
-
// Your loader code
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
**In Client Loaders**:
|
|
89
|
-
|
|
90
|
-
```typescript
|
|
91
|
-
import { getConfig } from '@/config';
|
|
92
|
-
|
|
93
|
-
export function clientLoader() {
|
|
94
|
-
const config = getConfig(); // No context needed - uses window.__APP_CONFIG__
|
|
95
|
-
|
|
96
|
-
if (config.myFeature.enabled) {
|
|
97
|
-
// Your loader code
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
**Note:** `getConfig()` and `useConfig()` return `AppConfig` which is the `app` section of the full `Config` type. So you access properties directly (e.g., `config.myFeature.enabled`) without the `app` prefix.
|
|
103
|
-
|
|
104
|
-
## Environment Variable Rules
|
|
105
|
-
|
|
106
|
-
Use the `PUBLIC__` prefix with double underscores (`__`) to set any config path:
|
|
107
|
-
|
|
108
|
-
```bash
|
|
109
|
-
# Environment variable → Config path (in Config type) → Access via getConfig()/useConfig()
|
|
110
|
-
PUBLIC__app__commerce__sites='[...]' → config.app.commerce.sites → config.commerce.sites
|
|
111
|
-
PUBLIC__app__defaultSiteId=RefArchGlobal → config.app.defaultSiteId → config.defaultSiteId
|
|
112
|
-
PUBLIC__app__myFeature__enabled=true → config.app.myFeature.enabled → config.myFeature.enabled
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
**Multi-site Configuration Example:**
|
|
116
|
-
|
|
117
|
-
```bash
|
|
118
|
-
PUBLIC__app__commerce__sites='[
|
|
119
|
-
{
|
|
120
|
-
"id": "RefArchGlobal",
|
|
121
|
-
"defaultLocale": "en-US",
|
|
122
|
-
"defaultCurrency": "USD",
|
|
123
|
-
"supportedLocales": [
|
|
124
|
-
{"id": "en-US", "preferredCurrency": "USD"},
|
|
125
|
-
{"id": "de-DE", "preferredCurrency": "EUR"}
|
|
126
|
-
],
|
|
127
|
-
"supportedCurrencies": ["USD", "EUR"]
|
|
128
|
-
}
|
|
129
|
-
]'
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
**Accessing Site Configuration:**
|
|
133
|
-
|
|
134
|
-
```typescript
|
|
135
|
-
const config = getConfig(context);
|
|
136
|
-
const currentSite = config.commerce.sites[0]; // Get first site
|
|
137
|
-
const locale = currentSite.defaultLocale; // "en-US"
|
|
138
|
-
const currency = currentSite.defaultCurrency; // "USD"
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
Values are automatically parsed (numbers, booleans, JSON arrays/objects).
|
|
142
|
-
|
|
143
|
-
Rules:
|
|
144
|
-
1. **`PUBLIC__` prefix**: Exposed to browser (client-safe values)
|
|
145
|
-
2. **No prefix**: Server-only (secrets, never exposed)
|
|
146
|
-
3. **`__` separator**: Navigate nested paths (`PUBLIC__app__commerce__sites`)
|
|
147
|
-
4. **Case-insensitive**: All casings work (normalized to match `config.server.ts`)
|
|
148
|
-
5. **Auto-parsing**: Strings, numbers, booleans, JSON arrays/objects
|
|
149
|
-
6. **Validation**: Paths must exist in `config.server.ts` (prevents typos)
|
|
150
|
-
7. **Depth limit**: Maximum 10 levels deep (use JSON values for deeper nesting)
|
|
151
|
-
8. **Path precedence**: More specific paths override less specific ones
|
|
152
|
-
9. **Protected paths**: `app__engagement` cannot be overridden via environment variables
|
|
153
|
-
10. **MRT limits**: Variable names max 512 characters, total PUBLIC__ values max 32KB
|
|
154
|
-
|
|
155
|
-
**Note:** Site configuration (locales, currencies) is now managed via `PUBLIC__app__commerce__sites` array instead of individual `PUBLIC__app__site__locale` variables. This enables multi-site support.
|
|
156
|
-
|
|
157
|
-
**Setting nested objects with JSON:**
|
|
158
|
-
|
|
159
|
-
```bash
|
|
160
|
-
# Instead of multiple variables:
|
|
161
|
-
PUBLIC__app__myFeature__option1=value1
|
|
162
|
-
PUBLIC__app__myFeature__option2=value2
|
|
163
|
-
|
|
164
|
-
# Use a single JSON value:
|
|
165
|
-
PUBLIC__app__myFeature='{"option1":"value1","option2":"value2","nested":{"enabled":true}}'
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
## Security
|
|
169
|
-
|
|
170
|
-
```bash
|
|
171
|
-
# ✅ Safe for client (PUBLIC__ prefix)
|
|
172
|
-
PUBLIC__app__commerce__api__clientId=abc123
|
|
173
|
-
|
|
174
|
-
# ✅ Server-only (no prefix)
|
|
175
|
-
COMMERCE_API_SLAS_SECRET=your-secret
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
Read server-only secrets directly from `process.env` - never add to config.
|
|
179
|
-
|
|
180
|
-
**Reference:** See src/config/README.md for complete configuration documentation.
|