@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.
Files changed (110) hide show
  1. package/README.md +15 -62
  2. package/dist/commands/mcp.d.ts +14 -7
  3. package/dist/commands/mcp.js +91 -12
  4. package/dist/registry.d.ts +3 -3
  5. package/dist/registry.js +7 -14
  6. package/dist/server-context.d.ts +1 -1
  7. package/dist/server-context.js +1 -1
  8. package/dist/services.d.ts +29 -1
  9. package/dist/services.js +48 -1
  10. package/dist/tools/adapter.d.ts +25 -1
  11. package/dist/tools/adapter.js +53 -8
  12. package/dist/tools/cartridges/index.js +14 -3
  13. package/dist/tools/diagnostics/config-inspect.js +3 -2
  14. package/dist/tools/diagnostics/debug-list-sessions.js +1 -1
  15. package/dist/tools/diagnostics/debug-start-session.js +22 -9
  16. package/dist/tools/diagnostics/log-watch-registry.d.ts +3 -0
  17. package/dist/tools/diagnostics/log-watch-registry.js +1 -0
  18. package/dist/tools/diagnostics/logs-watch-list.js +1 -0
  19. package/dist/tools/diagnostics/logs-watch-start.js +6 -1
  20. package/dist/tools/diagnostics/mrt-log-watch-registry.d.ts +3 -0
  21. package/dist/tools/diagnostics/mrt-log-watch-registry.js +0 -0
  22. package/dist/tools/diagnostics/mrt-logs-watch-list.js +1 -0
  23. package/dist/tools/diagnostics/mrt-logs-watch-start.js +7 -1
  24. package/dist/tools/diagnostics/session-registry.d.ts +3 -0
  25. package/dist/tools/diagnostics/session-registry.js +4 -3
  26. package/dist/tools/index.d.ts +0 -1
  27. package/dist/tools/index.js +0 -1
  28. package/dist/tools/mrt/index.js +13 -3
  29. package/dist/tools/project-context.d.ts +53 -0
  30. package/dist/tools/project-context.js +55 -0
  31. package/dist/tools/scapi/metrics-get.js +1 -0
  32. package/dist/tools/scapi/scapi-custom-api-generate-scaffold.d.ts +8 -1
  33. package/dist/tools/scapi/scapi-custom-api-generate-scaffold.js +41 -7
  34. package/dist/tools/scapi/scapi-custom-apis-get-status.js +1 -0
  35. package/dist/tools/scapi/scapi-schemas-list.js +1 -0
  36. package/dist/utils/constants.d.ts +2 -13
  37. package/dist/utils/constants.js +1 -20
  38. package/oclif.manifest.json +2 -2
  39. package/package.json +3 -3
  40. package/content/sfnext/auth.md +0 -62
  41. package/content/sfnext/components.md +0 -123
  42. package/content/sfnext/config.md +0 -180
  43. package/content/sfnext/data-fetching.md +0 -323
  44. package/content/sfnext/extensions.md +0 -80
  45. package/content/sfnext/i18n.md +0 -121
  46. package/content/sfnext/page-designer.md +0 -78
  47. package/content/sfnext/performance.md +0 -80
  48. package/content/sfnext/pitfalls.md +0 -141
  49. package/content/sfnext/quick-reference.md +0 -226
  50. package/content/sfnext/state-management.md +0 -75
  51. package/content/sfnext/styling.md +0 -51
  52. package/content/sfnext/testing.md +0 -232
  53. package/dist/tools/storefrontnext/figma/figma-to-component/figma-url-parser.d.ts +0 -24
  54. package/dist/tools/storefrontnext/figma/figma-to-component/figma-url-parser.js +0 -53
  55. package/dist/tools/storefrontnext/figma/figma-to-component/index.d.ts +0 -42
  56. package/dist/tools/storefrontnext/figma/figma-to-component/index.js +0 -326
  57. package/dist/tools/storefrontnext/figma/generate-component/decision.d.ts +0 -40
  58. package/dist/tools/storefrontnext/figma/generate-component/decision.js +0 -312
  59. package/dist/tools/storefrontnext/figma/generate-component/formatter.d.ts +0 -9
  60. package/dist/tools/storefrontnext/figma/generate-component/formatter.js +0 -92
  61. package/dist/tools/storefrontnext/figma/generate-component/index.d.ts +0 -114
  62. package/dist/tools/storefrontnext/figma/generate-component/index.js +0 -99
  63. package/dist/tools/storefrontnext/figma/map-tokens/css-parser.d.ts +0 -71
  64. package/dist/tools/storefrontnext/figma/map-tokens/css-parser.js +0 -260
  65. package/dist/tools/storefrontnext/figma/map-tokens/index.d.ts +0 -61
  66. package/dist/tools/storefrontnext/figma/map-tokens/index.js +0 -235
  67. package/dist/tools/storefrontnext/figma/map-tokens/token-matcher.d.ts +0 -65
  68. package/dist/tools/storefrontnext/figma/map-tokens/token-matcher.js +0 -268
  69. package/dist/tools/storefrontnext/index.d.ts +0 -30
  70. package/dist/tools/storefrontnext/index.js +0 -28
  71. package/dist/tools/storefrontnext/page-designer-decorator/analyzer.d.ts +0 -169
  72. package/dist/tools/storefrontnext/page-designer-decorator/analyzer.js +0 -567
  73. package/dist/tools/storefrontnext/page-designer-decorator/index.d.ts +0 -252
  74. package/dist/tools/storefrontnext/page-designer-decorator/index.js +0 -617
  75. package/dist/tools/storefrontnext/page-designer-decorator/rules/1-mode-selection.d.ts +0 -8
  76. package/dist/tools/storefrontnext/page-designer-decorator/rules/1-mode-selection.js +0 -65
  77. package/dist/tools/storefrontnext/page-designer-decorator/rules/2a-auto-mode.d.ts +0 -13
  78. package/dist/tools/storefrontnext/page-designer-decorator/rules/2a-auto-mode.js +0 -87
  79. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-0-interactive-overview.d.ts +0 -4
  80. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-0-interactive-overview.js +0 -55
  81. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-1-interactive-analyze.d.ts +0 -22
  82. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-1-interactive-analyze.js +0 -109
  83. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-2-interactive-select-props.d.ts +0 -21
  84. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-2-interactive-select-props.js +0 -60
  85. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-3-interactive-configure-attrs.d.ts +0 -27
  86. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-3-interactive-configure-attrs.js +0 -68
  87. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-4-interactive-configure-regions.d.ts +0 -4
  88. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-4-interactive-configure-regions.js +0 -65
  89. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-5-interactive-confirm-generation.d.ts +0 -11
  90. package/dist/tools/storefrontnext/page-designer-decorator/rules/2b-5-interactive-confirm-generation.js +0 -92
  91. package/dist/tools/storefrontnext/page-designer-decorator/rules.d.ts +0 -51
  92. package/dist/tools/storefrontnext/page-designer-decorator/rules.js +0 -70
  93. package/dist/tools/storefrontnext/page-designer-decorator/templates/decorator-generator.d.ts +0 -116
  94. package/dist/tools/storefrontnext/page-designer-decorator/templates/decorator-generator.js +0 -350
  95. package/dist/tools/storefrontnext/sfnext-development-guidelines.d.ts +0 -9
  96. package/dist/tools/storefrontnext/sfnext-development-guidelines.js +0 -141
  97. package/dist/tools/storefrontnext/site-theming/color-contrast.d.ts +0 -92
  98. package/dist/tools/storefrontnext/site-theming/color-contrast.js +0 -186
  99. package/dist/tools/storefrontnext/site-theming/color-mapping.d.ts +0 -16
  100. package/dist/tools/storefrontnext/site-theming/color-mapping.js +0 -131
  101. package/dist/tools/storefrontnext/site-theming/guidance-merger.d.ts +0 -11
  102. package/dist/tools/storefrontnext/site-theming/guidance-merger.js +0 -78
  103. package/dist/tools/storefrontnext/site-theming/index.d.ts +0 -14
  104. package/dist/tools/storefrontnext/site-theming/index.js +0 -123
  105. package/dist/tools/storefrontnext/site-theming/response-builder.d.ts +0 -16
  106. package/dist/tools/storefrontnext/site-theming/response-builder.js +0 -316
  107. package/dist/tools/storefrontnext/site-theming/theming-store.d.ts +0 -62
  108. package/dist/tools/storefrontnext/site-theming/theming-store.js +0 -417
  109. package/dist/tools/storefrontnext/site-theming/types.d.ts +0 -35
  110. package/dist/tools/storefrontnext/site-theming/types.js +0 -7
@@ -1,323 +0,0 @@
1
- # Data Fetching Patterns
2
-
3
- ## Loader Functions
4
-
5
- **IMPORTANT**: This project **mandates server-only data loading**. Every UI route must only export a `loader` function.
6
-
7
- ### Critical Rule: Synchronous Loaders for Streaming
8
-
9
- **IMPORTANT**: Loaders should be **synchronous functions that return objects containing promises**, NOT async functions. This enables non-blocking page transitions and streaming SSR.
10
-
11
- ```typescript
12
- // ✅ CORRECT - Synchronous loader returning promises
13
- export function loader({ context }: LoaderFunctionArgs): ProductPageData {
14
- const clients = createApiClients(context);
15
- return {
16
- product: clients.shopperProducts.getProduct({...}), // Promise - streams
17
- reviews: clients.shopperProducts.getReviews({...}), // Promise - streams
18
- };
19
- }
20
-
21
- // ❌ AVOID - Async loader blocks page transitions
22
- export async function loader({ context }: LoaderFunctionArgs): Promise<ProductPageData> {
23
- const product = await clients.shopperProducts.getProduct({...}); // Blocks!
24
- return { product };
25
- }
26
- ```
27
-
28
- **Why this matters:**
29
- - Async loaders with `await` **block the entire page transition** until all data resolves
30
- - Synchronous loaders returning promises allow React to **stream data progressively**
31
- - Each promise resolves independently, enabling granular Suspense boundaries
32
- - Users see content as it becomes available, not all at once
33
-
34
- **Behavior**:
35
- - Initial load: Runs on server (SSR)
36
- - Navigation: Runs on server (XHR/fetch to server)
37
- - SCAPI requests always on MRT
38
-
39
- ## Data Loading Strategies
40
-
41
- ### Pattern 1: Awaited Data (Blocking)
42
-
43
- ```typescript
44
- // ⚠️ BLOCKS rendering until all data is ready
45
- export async function loader({ params, context }: LoaderFunctionArgs) {
46
- const clients = createApiClients(context);
47
- return {
48
- product: await clients.shopperProducts.getProduct({
49
- params: { path: { id: params.productId } }
50
- }).then(({ data }) => data)
51
- };
52
- }
53
- ```
54
-
55
- **Use when:** Critical data must be available before rendering (SEO, above-the-fold content)
56
-
57
- ### Pattern 2: Deferred Data (Streaming)
58
-
59
- ```typescript
60
- // ✅ RECOMMENDED - Streams data progressively
61
- export function loader({ params, context }: LoaderFunctionArgs) {
62
- const clients = createApiClients(context);
63
- return {
64
- // Return promises directly - they'll stream to client
65
- product: clients.shopperProducts.getProduct({
66
- params: { path: { id: params.productId } }
67
- }).then(({ data }) => data),
68
-
69
- reviews: clients.shopperProducts.getReviews({
70
- params: { path: { id: params.productId } }
71
- }).then(({ data }) => data)
72
- };
73
- }
74
- ```
75
-
76
- **Use when:** Non-critical data can load after initial render
77
-
78
- ### Pattern 3: Mixed Strategy
79
-
80
- ```typescript
81
- // ✅ BEST OF BOTH - Critical data awaited, rest streamed
82
- export async function loader({ params, context }: LoaderFunctionArgs) {
83
- const clients = createApiClients(context);
84
-
85
- // Await critical data
86
- const product = await clients.shopperProducts.getProduct({
87
- params: { path: { id: params.productId } }
88
- }).then(({ data }) => data);
89
-
90
- return {
91
- product, // Resolved
92
- reviews: clients.shopperProducts.getReviews({
93
- params: { path: { id: params.productId } }
94
- }).then(({ data }) => data), // Streamed
95
- recommendations: clients.shopperProducts.getRecommendations({
96
- params: { path: { id: params.productId } }
97
- }).then(({ data }) => data) // Streamed
98
- };
99
- }
100
- ```
101
-
102
- ## Action Functions
103
-
104
- Handle mutations (form submissions, cart updates):
105
-
106
- ```typescript
107
- import {data, redirect} from 'react-router';
108
-
109
- export async function action({request, context}: ActionFunctionArgs) {
110
- const formData = await request.formData();
111
- const productId = formData.get('productId') as string;
112
-
113
- const clients = createApiClients(context);
114
-
115
- try {
116
- await clients.shopperBasketsV2.addItemToBasket({
117
- params: {
118
- path: {basketId},
119
- body: {productId, quantity: 1},
120
- },
121
- });
122
-
123
- return data({success: true});
124
- } catch (error) {
125
- return data({success: false, error: error.message}, {status: 400});
126
- }
127
- }
128
- ```
129
-
130
- ## Interactive Data Fetching: useScapiFetcher
131
-
132
- For on-demand, user-triggered data fetching (after page load), use the `useScapiFetcher` hook instead of loaders.
133
-
134
- ### `loader` vs `useScapiFetcher`
135
-
136
- | Aspect | `loader` | `useScapiFetcher` |
137
- |--------|----------|-------------------|
138
- | **When it runs** | Route navigation (page load) | On-demand (user interaction) |
139
- | **Triggered by** | URL change | Component code (useEffect, button click) |
140
- | **Data availability** | Before/during component render (streamed) | After component mounts |
141
- | **Execution context** | Server (MRT) | Triggers server route |
142
- | **Use case** | Initial page data | Dynamic, interactive fetching |
143
-
144
- ### How `useScapiFetcher` Works
145
-
146
- ```text
147
- Component calls useScapiFetcher()
148
-
149
- Hook builds URL: /resource/api/client/{encoded-params}
150
-
151
- fetcher.load() or fetcher.submit()
152
-
153
- resource.api.client.$resource.ts loader/action runs ON SERVER
154
-
155
- createApiClients(context) makes SCAPI call (server-side)
156
-
157
- JSON response returned to component
158
- ```
159
-
160
- **Important:** Even though you call `useScapiFetcher` from the browser, the actual SCAPI requests still happen **on the server** through the resource route, keeping credentials secure.
161
-
162
- ### Example: Search Suggestions
163
-
164
- ```typescript
165
- import { useScapiFetcher } from '@/hooks/use-scapi-fetcher';
166
- import { useMemo, useCallback } from 'react';
167
-
168
- export function useSearchSuggestions({ q, limit, currency }) {
169
- // Prepare SCAPI parameters
170
- const parameters = useMemo(
171
- () => ({
172
- params: {
173
- query: { q, limit, currency }
174
- }
175
- }),
176
- [q, limit, currency]
177
- );
178
-
179
- // Hook automatically routes to server
180
- const fetcher = useScapiFetcher(
181
- 'shopperSearch', // SCAPI client
182
- 'getSearchSuggestions', // Method name
183
- parameters // Parameters
184
- );
185
-
186
- const refetch = useCallback(async () => {
187
- await fetcher.load(); // Triggers server request
188
- }, [fetcher]);
189
-
190
- return {
191
- data: fetcher.data,
192
- isLoading: fetcher.state === 'loading',
193
- refetch
194
- };
195
- }
196
- ```
197
-
198
- ### When to Use Each Approach
199
-
200
- | Scenario | Use |
201
- |----------|-----|
202
- | Load product data when visiting `/product/123` | `loader` |
203
- | Load checkout data | `loader` |
204
- | Search suggestions as user types | `useScapiFetcher` |
205
- | Update customer profile in modal | `useScapiFetcher` |
206
- | Load recommendations after page loads | `useScapiFetcher` |
207
- | Fetch bonus products when modal opens | `useScapiFetcher` |
208
- | Infinite scroll / Load more | `useScapiFetcher` |
209
-
210
- ### Timeline Comparison
211
-
212
- ```text
213
- ┌─────────────────────────────────────────────────────────────────┐
214
- │ loader (Server) │
215
- ├─────────────────────────────────────────────────────────────────┤
216
- │ User clicks link → Server loader() → Stream data → Page render │
217
- │ │
218
- │ Timeline: [navigate] → [server fetch] → [stream to client] │
219
- │ │
220
- │ Data available: Streamed during render via Suspense │
221
- └─────────────────────────────────────────────────────────────────┘
222
-
223
- ┌─────────────────────────────────────────────────────────────────┐
224
- │ useScapiFetcher │
225
- ├─────────────────────────────────────────────────────────────────┤
226
- │ Page loads → Component mounts → User types → fetcher.load() │
227
- │ │
228
- │ Timeline: [render] → [user action] → [fetch] → [re-render] │
229
- │ │
230
- │ Data available: AFTER user action, component re-renders │
231
- └─────────────────────────────────────────────────────────────────┘
232
- ```
233
-
234
- ## API Client Usage
235
-
236
- Always use `createApiClients(context)`:
237
-
238
- ```typescript
239
- import { createApiClients } from '@/lib/api-clients';
240
-
241
- export function loader({ context }: LoaderFunctionArgs) {
242
- const clients = createApiClients(context);
243
-
244
- // All SCAPI clients with full type safety:
245
- clients.shopperProducts.getProduct({...});
246
- clients.shopperCustomers.getCustomer({...});
247
- clients.shopperBasketsV2.getBasket({...});
248
- clients.shopperSearch.productSearch({...});
249
- clients.shopperOrders.getOrder({...});
250
- }
251
- ```
252
-
253
- ## Parallel vs Sequential
254
-
255
- ```typescript
256
- // ✅ GOOD - Parallel requests
257
- export function loader({ context }: LoaderFunctionArgs) {
258
- const clients = createApiClients(context);
259
-
260
- return {
261
- product: clients.shopperProducts.getProduct({...}),
262
- reviews: clients.shopperProducts.getReviews({...}),
263
- recommendations: clients.shopperProducts.getRecommendations({...})
264
- };
265
- // All three requests start simultaneously
266
- }
267
-
268
- // ❌ BAD - Sequential requests
269
- export async function loader({ context }: LoaderFunctionArgs) {
270
- const clients = createApiClients(context);
271
-
272
- const product = await clients.shopperProducts.getProduct({...});
273
- const reviews = await clients.shopperProducts.getReviews({...});
274
- const recommendations = await clients.shopperProducts.getRecommendations({...});
275
-
276
- return { product, reviews, recommendations };
277
- // Each request waits for the previous to complete
278
- }
279
- ```
280
-
281
- ## Understanding Data Flow
282
-
283
- ### Initial Page Load (SSR)
284
-
285
- ```text
286
- Browser → MRT Server
287
-
288
- loader() runs on server
289
-
290
- SCAPI requests on MRT
291
-
292
- HTML response → Browser
293
- ```
294
-
295
- **Key characteristics:**
296
- - The `loader()` runs on the server
297
- - SCAPI requests happen server-side (direct in production, proxied in dev)
298
- - Full HTML is returned to browser
299
- - Client hydrates the HTML
300
-
301
- ### Subsequent Navigation (SPA)
302
-
303
- All routes use server `loader` for both SSR and SPA navigation:
304
-
305
- ```text
306
- User clicks link → React Router intercepts
307
-
308
- Browser makes fetch() to server
309
-
310
- MRT Server receives request
311
-
312
- Same loader() runs on server
313
-
314
- SCAPI requests on MRT
315
-
316
- JSON response → Browser
317
-
318
- React updates DOM
319
- ```
320
-
321
- **Key Point:** The loader function code is identical for both SSR and SPA navigation. The only difference is the response format (HTML vs JSON). This is why SCAPI credentials stay secure and MRT orchestration works consistently.
322
-
323
- **Reference:** See README-DATA.md for complete data fetching documentation.
@@ -1,80 +0,0 @@
1
- # Extension Development
2
-
3
- ## Structure
4
-
5
- ```
6
- src/extensions/my-extension/
7
- ├── plugin-config.json # Plugin configuration
8
- ├── components/ # Extension components
9
- ├── routes/ # Extension routes
10
- ├── locales/ # Extension translations
11
- └── providers/ # Extension providers
12
- ```
13
-
14
- ## Plugin Configuration
15
-
16
- **Insert component into plugin point**:
17
-
18
- ```json
19
- {
20
- "components": [
21
- {
22
- "pluginId": "header.before.cart",
23
- "path": "extensions/my-extension/components/badge.tsx",
24
- "order": 0
25
- }
26
- ],
27
- "contextProviders": [
28
- {
29
- "path": "extensions/my-extension/providers/my-provider.tsx",
30
- "order": 0
31
- }
32
- ]
33
- }
34
- ```
35
-
36
- ## Extension Routes
37
-
38
- Files in `routes/` auto-register:
39
-
40
- ```typescript
41
- // src/extensions/my-extension/routes/my-route.tsx
42
- export function loader() {
43
- return { message: 'Hello' };
44
- }
45
-
46
- export default function MyRoute() {
47
- const { message } = useLoaderData();
48
- return <div>{message}</div>;
49
- }
50
- ```
51
-
52
- ## Extension Translations
53
-
54
- Auto-namespaced as `extPascalCase`:
55
-
56
- ```
57
- src/extensions/my-extension/locales/
58
- ├── en-US/translations.json
59
- └── it-IT/translations.json
60
- ```
61
-
62
- ```typescript
63
- const {t} = useTranslation('extMyExtension');
64
- t('welcome');
65
- ```
66
-
67
- ## Integration Markers
68
-
69
- ```typescript
70
- // Single line
71
- /** @sfdc-extension-line SFDC_EXT_MY_FEATURE */
72
- import myFeature from '@extensions/my-feature';
73
-
74
- // Block
75
- {/* @sfdc-extension-block-start SFDC_EXT_MY_FEATURE */}
76
- <Link to="/my-feature">My Feature</Link>
77
- {/* @sfdc-extension-block-end SFDC_EXT_MY_FEATURE */}
78
- ```
79
-
80
- For full documentation, read: src/extensions/README.md
@@ -1,121 +0,0 @@
1
- # Internationalization (i18n)
2
-
3
- ## Overview
4
-
5
- - **Server instance**: Has access to all translations for all languages
6
- - **Client instance**: Dynamically imports translations as JavaScript chunks
7
- - **Dual API**: `useTranslation()` for components, `getTranslation()` for everything else
8
-
9
- ## Adding Translations
10
-
11
- **In `src/locales/{language}/translations.json`**:
12
-
13
- ```json
14
- {
15
- "product": {
16
- "title": "Product Details",
17
- "addToCart": "Add to Cart",
18
- "greeting": "Hello, {{name}}!",
19
- "itemCount": {
20
- "zero": "No items",
21
- "one": "{{count}} item",
22
- "other": "{{count}} items"
23
- }
24
- }
25
- }
26
- ```
27
-
28
- ## Usage
29
-
30
- **2. Use in React components:**
31
-
32
- ```typescript
33
- import { useTranslation } from 'react-i18next';
34
-
35
- export function ProductCard() {
36
- const { t } = useTranslation('product');
37
-
38
- return (
39
- <div>
40
- <h1>{t('title')}</h1>
41
- <button>{t('addToCart')}</button>
42
- <p>{t('greeting', { name: 'John' })}</p>
43
- <p>{t('itemCount', { count: 5 })}</p>
44
- </div>
45
- );
46
- }
47
- ```
48
-
49
- **3. Use in non-component code:**
50
-
51
- ```typescript
52
- import { getTranslation } from '@/lib/i18next';
53
-
54
- // Client-side or utilities
55
- const { t } = getTranslation();
56
- const message = t('product:addToCart');
57
-
58
- // Server-side (loaders/actions)
59
- export function loader(args: LoaderFunctionArgs) {
60
- const { t } = getTranslation(args.context);
61
- return { title: t('product:title') };
62
- }
63
- ```
64
-
65
- ## Validation Schemas with Translations
66
-
67
- **CRITICAL**: Use factory pattern for Zod schemas to avoid race conditions:
68
-
69
- ```typescript
70
- // ❌ WRONG - Module-level schema (race condition)
71
- export const schema = z.object({
72
- email: z.string().email(t('validation:emailInvalid'))
73
- });
74
-
75
- // ✅ CORRECT - Factory function
76
- import type { TFunction } from 'i18next';
77
-
78
- export const createSchema = (t: TFunction) => {
79
- return z.object({
80
- email: z.string().email(t('validation:emailInvalid'))
81
- });
82
- };
83
-
84
- // Usage in component
85
- import { useMemo } from 'react';
86
- import { useTranslation } from 'react-i18next';
87
-
88
- function MyForm() {
89
- const { t } = useTranslation();
90
- const schema = useMemo(() => createSchema(t), [t]);
91
-
92
- const form = useForm({ resolver: zodResolver(schema) });
93
- }
94
- ```
95
-
96
- ## Language Switching
97
-
98
- ```typescript
99
- import LocaleSwitcher from '@/components/locale-switcher';
100
-
101
- export function Footer() {
102
- return <footer><LocaleSwitcher /></footer>;
103
- }
104
- ```
105
-
106
- ## Extension Translations
107
-
108
- Extensions use `extPascalCase` namespace:
109
-
110
- ```
111
- src/extensions/my-extension/locales/
112
- ├── en-US/translations.json
113
- └── it-IT/translations.json
114
- ```
115
-
116
- ```typescript
117
- const {t} = useTranslation('extMyExtension');
118
- t('welcome');
119
- ```
120
-
121
- **Reference:** See README-I18N.md for complete internationalization documentation.
@@ -1,78 +0,0 @@
1
- # Page Designer Integration
2
-
3
- ## Overview
4
-
5
- Page Designer is Commerce Cloud's visual editor in Business Manager: merchants build and edit storefront pages (home, category, etc.) without code. The app gets page structure (regions, components, attributes) from the **Shopper Experience API** and renders it via a **component registry** and `<Region>`.
6
-
7
- ## Concepts
8
-
9
- | Concept | Role |
10
- |--------|------|
11
- | **Page** | Fetched in route loaders via `fetchPageFromLoader(args, { pageId })`. |
12
- | **Region** | Named area on a page; rendered with `<Region page={...} regionId="..." componentData={...} />`. |
13
- | **Component** | Content block (hero, grid, carousel, etc.) with a `typeId` and attributes; registered in `@/lib/registry`. |
14
- | **Registry** | Static registry in `@/lib/static-registry.ts` is **auto-generated** by the staticRegistry Vite plugin — do not edit by hand. |
15
-
16
- ## Which pages use Page Designer
17
-
18
- Only **content pages** that merchants edit in Business Manager use Page Designer; cart, checkout, account, and auth do not.
19
-
20
- | Uses Page Designer | Does not |
21
- |--------------------|----------|
22
- | Home (`pageId: 'homepage'`), Category/PLP (`plp`), Search (`search`), Product/PDP (`pdp`) | Cart, Checkout, Account, Order confirmation, Auth |
23
-
24
- To add a new content page: define a page type and ID in Commerce Cloud, then in your route use `fetchPageFromLoader(args, { pageId })` and `collectComponentDataPromises(args, pagePromise)`, and render `<Region>` for each region.
25
-
26
- ## Getting started
27
-
28
- ### Route (new Page Designer page)
29
-
30
- - **In the loader**: call `fetchPageFromLoader(args, { pageId: '...' })` and `collectComponentDataPromises(args, pagePromise)`; return `page` and `componentData` (keep loaders synchronous; return promises for streaming).
31
- - **In the layout**: for each region, render `<Region page={loaderData.page} regionId="..." componentData={loaderData.componentData} />` with optional `fallbackElement` and `errorElement` for Suspense/error boundaries.
32
- - **On the route module**: add `@PageType({ name, description, supportedAspectTypes })` and `@RegionDefinition([{ id, name, description, maxComponents }])` so Business Manager knows the page type and regions. Example routes: home (`_app._index.tsx`), category/PLP (`_app.category.$categoryId.tsx`).
33
-
34
- ### Component (new Page Designer component)
35
-
36
- - **Add a metadata class** with `@Component('typeId', { name, description })` and `@AttributeDefinition()` (and optionally `@AttributeDefinition({ type: 'image' })`, `type: 'url'`, etc.) for each prop you want editable in Page Designer. Use `@RegionDefinition([...])` if the component has nested regions (e.g. a grid with slots).
37
- - **Implement the React component** so it accepts those props (and strips Page Designer–only props like `component`, `page`, `componentData`, `designMetadata` before spreading to the DOM). If the component needs server data (e.g. products for a carousel), export a `loader({ componentData, context })` and optionally a `fallback` component; the registry calls the loader during `collectComponentDataPromises` and passes resolved data as the `data` prop.
38
- - **Use the MCP tool `sfnext_add_page_designer_decorator`** to generate decorators instead of writing them by hand. Example components: `components/hero/index.tsx`, `components/content-card/index.tsx`, `components/product-carousel/index.tsx`.
39
-
40
- ### After changes
41
-
42
- - **Rebuild the app** so the static registry (`lib/static-registry.ts`) is regenerated by the staticRegistry Vite plugin. Do not edit the static registry by hand.
43
-
44
- ### Design mode
45
-
46
- - **Edit** and **Preview** mode are detected from the request via `isDesignModeActive(request)` and `isPreviewModeActive(request)` from `@salesforce/storefront-next-runtime/design/mode`. The root layout exposes `pageDesignerMode` in loader data (`'EDIT' | 'PREVIEW' | undefined`) so the tree can adapt (e.g. show outlines, disable interactions) when running inside Page Designer.
47
-
48
-
49
- ## MCP tools (recommended)
50
-
51
- Use the **B2C DX MCP server** for Page Designer work instead of hand-writing decorators and metadata. Configure the B2C DX MCP server in your IDE (e.g. in MCP settings) so these tools are available.
52
-
53
- ### 1. `sfnext_add_page_designer_decorator` (STOREFRONTNEXT toolset)
54
-
55
- Adds Page Designer decorators to an existing React component so it can be used in Business Manager. The tool analyzes the component, picks suitable props, infers types (e.g. `*Url`/`*Link` → url, `*Image` → image, `is*`/`show*` → boolean), and generates `@Component('typeId', { name, description })`, `@AttributeDefinition()` on a metadata class, and optionally `@RegionDefinition([...])` for nested regions. It skips complex or UI-only props (e.g. className, style, callbacks).
56
-
57
- - **Auto mode** (fast): Ask in your IDE: *"Add Page Designer support to [ComponentName] with autoMode"*. The tool runs in one turn with no prompts.
58
- - **Interactive mode** (control): Ask *"Add Page Designer support to [ComponentName]"* and answer questions about typeId, which props to expose, types, and optional nested regions.
59
-
60
- ### 2. `cartridge_deploy` (CARTRIDGES toolset)
61
-
62
- Packages the cartridge, uploads it to Commerce Cloud via WebDAV, and unpacks it on the server. **Run `pnpm generate:cartridge` or `pnpm build` before `cartridge_deploy`.** Requires Commerce Cloud credentials (e.g. `dw.json` or explicit config). Use after generating metadata so the new/updated metadata is available in Business Manager.
63
-
64
- ### Typical workflow
65
-
66
- 1. **`sfnext_add_page_designer_decorator`** — Add decorators to the component (use autoMode for a quick first pass).
67
- 2. **Rebuild** — The static registry is auto-generated at build time by the staticRegistry Vite plugin.
68
- 3. **`cartridge_deploy`** — Deploy to Commerce Cloud so merchants can use the component in Business Manager.
69
-
70
- ## Best Practices
71
-
72
- 1. **Keep loaders synchronous**: Return promises for Page Designer pages to enable streaming
73
- 2. **Use registry for components**: Register all Page Designer components with proper `typeId`
74
- 3. **Handle design mode**: Adapt UI when `pageDesignerMode` is `'EDIT'` or `'PREVIEW'`
75
- 4. **Rebuild after registry changes**: Static registry is generated at build time
76
- 5. **Use MCP tools**: Leverage `sfnext_add_page_designer_decorator` for faster development
77
-
78
- **Reference:** See README.md for complete Page Designer documentation and MCP tool setup.
@@ -1,80 +0,0 @@
1
- # Performance Optimization
2
-
3
- ## Bundle Size Limits
4
-
5
- The application enforces strict bundle size limits defined in `package.json` under the `bundlesize` configuration. Refer to `package.json` for the complete list of limits.
6
-
7
- **Check bundle size:**
8
-
9
- ```bash
10
- pnpm bundlesize:test # Verify limits
11
- pnpm bundlesize:analyze # Analyze composition
12
- ```
13
-
14
- ## Built-in Metrics
15
-
16
- Enable in `config.server.ts`:
17
-
18
- ```typescript
19
- {
20
- performance: {
21
- metrics: {
22
- serverPerformanceMetricsEnabled: true,
23
- clientPerformanceMetricsEnabled: true,
24
- serverTimingHeaderEnabled: false // Debug only
25
- }
26
- }
27
- }
28
- ```
29
-
30
- Tracks:
31
-
32
- - SSR operations and rendering time
33
- - SCAPI API calls with parallelization
34
- - Authentication operations
35
- - Client-side navigations
36
-
37
- ## Best Practices
38
-
39
- ### 1. Parallel Data Fetching
40
-
41
- **Key principle:** Return all promises simultaneously in loaders to enable parallel requests. Avoid sequential `await` calls.
42
-
43
- **Reference:** See `data-fetching` section for detailed parallel vs sequential patterns and code examples.
44
-
45
- ### 2. Image Optimization
46
-
47
- Use the `DynamicImage` component with WebP format:
48
-
49
- ```typescript
50
- import { DynamicImage } from '@/components/dynamic-image';
51
-
52
- <DynamicImage
53
- src={product.image.link}
54
- alt={product.image.alt}
55
- width={400}
56
- height={400}
57
- format="webp" // Default format
58
- />
59
- ```
60
-
61
- ### 3. Progressive Streaming
62
-
63
- **Key principle:** Use synchronous loaders returning promises to enable progressive streaming. Await only critical data, stream the rest.
64
-
65
- **Reference:** See `data-fetching` section for detailed streaming patterns including mixed strategies (awaited + streamed).
66
-
67
- ### 4. Lighthouse Audits
68
-
69
- Monitor performance metrics:
70
-
71
- - Preload critical CSS
72
- - Use WebP images by default
73
- - Lazy load below-the-fold content
74
- - Optimize font loading
75
-
76
- ```bash
77
- pnpm lighthouse:ci # Run Lighthouse CI
78
- ```
79
-
80
- **Reference:** See README-PERFORMANCE.md for complete performance optimization documentation.