@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
@@ -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 projectRoot = services.resolveWithProjectDirectory(args.projectRoot);
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, projectRoot, outputDir.`,
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('Project root for cartridge discovery. Default: project directory. Set to override the project directory.'),
162
- outputDir: z.string().optional().describe('Output directory override. Default: project root'),
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, { services }) {
165
- return executeScaffoldCustomApi(args, services, executeOverrides);
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", "STOREFRONTNEXT_DEPRECATED"];
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", "STOREFRONTNEXT_DEPRECATED"];
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
  */
@@ -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
  */
@@ -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, STOREFRONTNEXT_DEPRECATED",
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.10.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.10.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.23.0"
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",
@@ -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
@@ -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.