@salesforce/b2c-dx-mcp 0.4.4 → 0.4.5

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 (80) hide show
  1. package/README.md +82 -370
  2. package/content/pwav3/components.md +400 -0
  3. package/content/pwav3/config.md +124 -0
  4. package/content/pwav3/data-fetching.md +213 -0
  5. package/content/pwav3/extensibility.md +167 -0
  6. package/content/pwav3/i18n.md +214 -0
  7. package/content/pwav3/quick-reference.md +169 -0
  8. package/content/pwav3/routing.md +107 -0
  9. package/content/pwav3/state-management.md +193 -0
  10. package/content/pwav3/styling.md +248 -0
  11. package/content/pwav3/testing.md +124 -0
  12. package/content/site-theming/theming-accessibility.md +126 -0
  13. package/content/site-theming/theming-questions.md +208 -0
  14. package/content/site-theming/theming-validation.md +174 -0
  15. package/dist/registry.js +1 -1
  16. package/dist/services.d.ts +10 -10
  17. package/dist/services.js +19 -12
  18. package/dist/tools/cartridges/index.js +1 -6
  19. package/dist/tools/index.d.ts +1 -4
  20. package/dist/tools/index.js +1 -4
  21. package/dist/tools/mrt/index.js +1 -6
  22. package/dist/tools/pwav3/index.d.ts +12 -3
  23. package/dist/tools/pwav3/index.js +5 -63
  24. package/dist/tools/pwav3/pwa-kit-development-guidelines.d.ts +9 -0
  25. package/dist/tools/pwav3/pwa-kit-development-guidelines.js +151 -0
  26. package/dist/tools/scapi/index.d.ts +1 -1
  27. package/dist/tools/scapi/index.js +6 -1
  28. package/dist/tools/scapi/scapi-custom-api-scaffold.d.ts +60 -0
  29. package/dist/tools/scapi/scapi-custom-api-scaffold.js +175 -0
  30. package/dist/tools/storefrontnext/figma/figma-to-component/figma-url-parser.d.ts +24 -0
  31. package/dist/tools/storefrontnext/figma/figma-to-component/figma-url-parser.js +53 -0
  32. package/dist/tools/storefrontnext/figma/figma-to-component/index.d.ts +42 -0
  33. package/dist/tools/storefrontnext/figma/figma-to-component/index.js +325 -0
  34. package/dist/tools/storefrontnext/figma/generate-component/decision.d.ts +40 -0
  35. package/dist/tools/storefrontnext/figma/generate-component/decision.js +312 -0
  36. package/dist/tools/storefrontnext/figma/generate-component/formatter.d.ts +9 -0
  37. package/dist/tools/storefrontnext/figma/generate-component/formatter.js +92 -0
  38. package/dist/tools/storefrontnext/figma/generate-component/index.d.ts +114 -0
  39. package/dist/tools/storefrontnext/figma/generate-component/index.js +98 -0
  40. package/dist/tools/storefrontnext/figma/map-tokens/css-parser.d.ts +71 -0
  41. package/dist/tools/storefrontnext/figma/map-tokens/css-parser.js +260 -0
  42. package/dist/tools/storefrontnext/figma/map-tokens/index.d.ts +61 -0
  43. package/dist/tools/storefrontnext/figma/map-tokens/index.js +234 -0
  44. package/dist/tools/storefrontnext/figma/map-tokens/token-matcher.d.ts +65 -0
  45. package/dist/tools/storefrontnext/figma/map-tokens/token-matcher.js +268 -0
  46. package/dist/tools/storefrontnext/index.d.ts +17 -0
  47. package/dist/tools/storefrontnext/index.js +10 -60
  48. package/dist/tools/storefrontnext/page-designer-decorator/analyzer.js +15 -0
  49. package/dist/tools/storefrontnext/page-designer-decorator/index.js +3 -3
  50. package/dist/tools/storefrontnext/{developer-guidelines.js → sfnext-development-guidelines.js} +3 -3
  51. package/dist/tools/storefrontnext/site-theming/color-contrast.d.ts +92 -0
  52. package/dist/tools/storefrontnext/site-theming/color-contrast.js +186 -0
  53. package/dist/tools/storefrontnext/site-theming/color-mapping.d.ts +16 -0
  54. package/dist/tools/storefrontnext/site-theming/color-mapping.js +131 -0
  55. package/dist/tools/storefrontnext/site-theming/guidance-merger.d.ts +11 -0
  56. package/dist/tools/storefrontnext/site-theming/guidance-merger.js +78 -0
  57. package/dist/tools/storefrontnext/site-theming/index.d.ts +14 -0
  58. package/dist/tools/storefrontnext/site-theming/index.js +122 -0
  59. package/dist/tools/storefrontnext/site-theming/response-builder.d.ts +16 -0
  60. package/dist/tools/storefrontnext/site-theming/response-builder.js +316 -0
  61. package/dist/tools/storefrontnext/site-theming/theming-store.d.ts +62 -0
  62. package/dist/tools/storefrontnext/site-theming/theming-store.js +410 -0
  63. package/dist/tools/storefrontnext/site-theming/types.d.ts +35 -0
  64. package/dist/tools/storefrontnext/site-theming/types.js +7 -0
  65. package/oclif.manifest.json +1 -1
  66. package/package.json +8 -5
  67. /package/content/{auth.md → sfnext/auth.md} +0 -0
  68. /package/content/{components.md → sfnext/components.md} +0 -0
  69. /package/content/{config.md → sfnext/config.md} +0 -0
  70. /package/content/{data-fetching.md → sfnext/data-fetching.md} +0 -0
  71. /package/content/{extensions.md → sfnext/extensions.md} +0 -0
  72. /package/content/{i18n.md → sfnext/i18n.md} +0 -0
  73. /package/content/{page-designer.md → sfnext/page-designer.md} +0 -0
  74. /package/content/{performance.md → sfnext/performance.md} +0 -0
  75. /package/content/{pitfalls.md → sfnext/pitfalls.md} +0 -0
  76. /package/content/{quick-reference.md → sfnext/quick-reference.md} +0 -0
  77. /package/content/{state-management.md → sfnext/state-management.md} +0 -0
  78. /package/content/{styling.md → sfnext/styling.md} +0 -0
  79. /package/content/{testing.md → sfnext/testing.md} +0 -0
  80. /package/dist/tools/storefrontnext/{developer-guidelines.d.ts → sfnext-development-guidelines.d.ts} +0 -0
@@ -0,0 +1,400 @@
1
+ # Component Development
2
+
3
+ ## Component Architecture
4
+
5
+ PWA Kit applications use functional React components exclusively, leveraging React Hooks for state management and side effects. All components should be simple, modular, reusable, and follow established patterns from the Retail React App template.
6
+
7
+ ## PWA Kit Special Components
8
+
9
+ PWA Kit provides three special components that start with an underscore. These customize core application behavior:
10
+
11
+ ### app/components/_app-config/index.jsx
12
+
13
+ The top-level component for app-wide configurations. Use this for:
14
+ - Theme providers (Chakra UI via shared/ui)
15
+ - Commerce API Provider configuration
16
+ - React Query (via withReactQuery HOC)
17
+ - State management setup (Context Providers, Redux store)
18
+ - AppConfig.restore, AppConfig.freeze, AppConfig.extraGetPropsArgs — for SSR: restore/freeze serialize state (e.g., Redux); extraGetPropsArgs injects buildUrl, site, locale into getProps
19
+
20
+ **Important:** AppConfig is wrapped with `withReactQuery` to enable SSR data fetching. Do not wrap individual route components with withReactQuery—it is applied at the AppConfig level.
21
+
22
+ **Reference:** See `app/components/_app-config/index.jsx` in the template for the full implementation.
23
+
24
+ ### app/components/_app/index.jsx
25
+
26
+ The child of _app-config. Use this for layout and UI that persists throughout your app: header, footer, sidebar, layout containers, global modals (AuthModal, StoreLocatorModal).
27
+
28
+ **Reference:** See `app/components/_app/index.jsx` in the template.
29
+
30
+ ### app/components/_error/index.jsx
31
+
32
+ Renders when: (1) page not routable, (2) getProps() throws, (3) render() throws. **Props:** `message`, `stack`, `status`. Keep it simple—it must not throw.
33
+
34
+ **Reference:** See `app/components/_error/index.jsx` in the template.
35
+
36
+ ## Component Best Practices
37
+
38
+ ### Functional Components with Hooks
39
+
40
+ Always use functional components with React Hooks. Avoid class components:
41
+
42
+ ```jsx
43
+ import {useState, useEffect, useMemo, useCallback} from 'react';
44
+ import {Box, Button} from '@salesforce/retail-react-app/app/components/shared/ui';
45
+ import PropTypes from 'prop-types';
46
+
47
+ /**
48
+ * A reusable product tile component.
49
+ */
50
+ const ProductTile = ({product, onAddToCart}) => {
51
+ const [isHovered, setIsHovered] = useState(false);
52
+
53
+ // Memoize expensive computations
54
+ const discountPercent = useMemo(() => {
55
+ if (!product.priceMax || !product.price) return 0;
56
+ return Math.round(((product.priceMax - product.price) / product.priceMax) * 100);
57
+ }, [product.price, product.priceMax]);
58
+
59
+ // Memoize callbacks
60
+ const handleAddToCart = useCallback(() => {
61
+ onAddToCart(product);
62
+ }, [product, onAddToCart]);
63
+
64
+ return (
65
+ <Box
66
+ p={4}
67
+ borderWidth="1px"
68
+ borderRadius="md"
69
+ onMouseEnter={() => setIsHovered(true)}
70
+ onMouseLeave={() => setIsHovered(false)}
71
+ >
72
+ <Box>{product.name}</Box>
73
+ {discountPercent > 0 && <Box>{discountPercent}% off</Box>}
74
+ <Button onClick={handleAddToCart} isDisabled={!isHovered}>
75
+ Add to Cart
76
+ </Button>
77
+ </Box>
78
+ );
79
+ };
80
+
81
+ ProductTile.displayName = 'ProductTile';
82
+
83
+ ProductTile.propTypes = {
84
+ product: PropTypes.shape({
85
+ id: PropTypes.string.isRequired,
86
+ name: PropTypes.string.isRequired,
87
+ price: PropTypes.number,
88
+ priceMax: PropTypes.number
89
+ }).isRequired,
90
+ onAddToCart: PropTypes.func.isRequired
91
+ };
92
+
93
+ export default ProductTile;
94
+ ```
95
+
96
+ ### Key React Hooks to Use
97
+
98
+ - **useState**: Local component state
99
+ - **useEffect**: Side effects, subscriptions, data fetching
100
+ - **useContext**: Access React Context values
101
+ - **useMemo**: Memoize expensive computations
102
+ - **useCallback**: Memoize callback functions
103
+ - **useRef**: Persist values across renders, access DOM
104
+ - **useReducer**: Complex state logic
105
+
106
+ ## Chakra UI Integration
107
+
108
+ Use Chakra UI via the Retail React App shared/ui barrel for consistent, accessible, and themeable components:
109
+
110
+ ```jsx
111
+ import {
112
+ Box,
113
+ Button,
114
+ Heading,
115
+ Text,
116
+ Stack,
117
+ Flex,
118
+ Image,
119
+ Badge
120
+ } from '@salesforce/retail-react-app/app/components/shared/ui';
121
+
122
+ const ProductCard = ({product}) => {
123
+ return (
124
+ <Box maxW="sm" borderWidth="1px" borderRadius="lg" overflow="hidden">
125
+ <Image src={product.imageUrl} alt={product.name} />
126
+
127
+ <Box p="6">
128
+ <Flex align="baseline" mb={2}>
129
+ {product.isNew && (
130
+ <Badge borderRadius="full" px="2" colorScheme="teal">
131
+ New
132
+ </Badge>
133
+ )}
134
+ </Flex>
135
+
136
+ <Heading size="md" mt={2} mb={2}>
137
+ {product.name}
138
+ </Heading>
139
+
140
+ <Text color="gray.600" fontSize="sm" mb={2}>
141
+ {product.shortDescription}
142
+ </Text>
143
+
144
+ <Stack direction="row" align="center" justify="space-between">
145
+ <Text fontSize="2xl" fontWeight="bold">
146
+ ${product.price}
147
+ </Text>
148
+ <Button colorScheme="blue" size="sm">
149
+ Add to Cart
150
+ </Button>
151
+ </Stack>
152
+ </Box>
153
+ </Box>
154
+ );
155
+ };
156
+ ```
157
+
158
+ ### Responsive Design with Chakra UI
159
+
160
+ ```jsx
161
+ import {Box, SimpleGrid} from '@salesforce/retail-react-app/app/components/shared/ui';
162
+
163
+ const ProductGrid = ({products}) => {
164
+ return (
165
+ <SimpleGrid
166
+ columns={{base: 1, sm: 2, md: 3, lg: 4}}
167
+ spacing={6}
168
+ p={4}
169
+ >
170
+ {products.map((product) => (
171
+ <ProductTile key={product.id} product={product} />
172
+ ))}
173
+ </SimpleGrid>
174
+ );
175
+ };
176
+ ```
177
+
178
+ ## File Naming Conventions
179
+
180
+ ### Component Files
181
+ - Use kebab-case for all file names
182
+ - Use `.jsx` extension for components
183
+ - Use `index.jsx` for main component export in a directory
184
+
185
+ ```
186
+ app/components/
187
+ ├── product-tile/
188
+ │ ├── index.jsx # Main component export
189
+ │ ├── product-tile.test.jsx # Co-located test
190
+ │ └── README.md # Component documentation
191
+ ├── header/
192
+ │ └── index.jsx
193
+ └── footer/
194
+ └── index.jsx
195
+ ```
196
+
197
+ ### Special Component Exception
198
+ Only use underscore prefix for PWA Kit special components:
199
+ - `_app.jsx`
200
+ - `_app-config.jsx`
201
+ - `_error.jsx`
202
+
203
+ ## Component Composition
204
+
205
+ Build complex UIs by composing simple components:
206
+
207
+ ```jsx
208
+ // Small, focused components
209
+ const ProductImage = ({src, alt}) => (
210
+ <Image src={src} alt={alt} borderRadius="md" />
211
+ );
212
+
213
+ const ProductPrice = ({price, compareAtPrice}) => (
214
+ <Stack direction="row" align="center">
215
+ <Text fontSize="2xl" fontWeight="bold">${price}</Text>
216
+ {compareAtPrice && (
217
+ <Text fontSize="md" textDecoration="line-through" color="gray.500">
218
+ ${compareAtPrice}
219
+ </Text>
220
+ )}
221
+ </Stack>
222
+ );
223
+
224
+ const ProductTitle = ({title}) => (
225
+ <Heading size="lg" mb={2}>{title}</Heading>
226
+ );
227
+
228
+ // Composed product detail component
229
+ const ProductDetail = ({product}) => {
230
+ return (
231
+ <Box>
232
+ <ProductImage src={product.image} alt={product.name} />
233
+ <ProductTitle title={product.name} />
234
+ <ProductPrice
235
+ price={product.price}
236
+ compareAtPrice={product.priceMax}
237
+ />
238
+ </Box>
239
+ );
240
+ };
241
+ ```
242
+
243
+ ## Reusing Shared Components
244
+
245
+ The Retail React App template provides shared UI components in:
246
+ ```
247
+ app/components/shared/ui/
248
+ ```
249
+
250
+ Import and use these components for consistency:
251
+
252
+ ```jsx
253
+ import {Skeleton} from '@salesforce/retail-react-app/app/components/shared/ui';
254
+
255
+ const ProductSkeleton = () => (
256
+ <Skeleton height="300px" />
257
+ );
258
+ ```
259
+
260
+ ## Loading States and Skeletons
261
+
262
+ Always provide loading states for async operations:
263
+
264
+ ```jsx
265
+ import {Box, Skeleton, SkeletonText} from '@salesforce/retail-react-app/app/components/shared/ui';
266
+
267
+ const ProductDetail = ({productId}) => {
268
+ const {data: product, isLoading} = useProduct({
269
+ parameters: {id: productId}
270
+ });
271
+
272
+ if (isLoading) {
273
+ return (
274
+ <Box p={4}>
275
+ <Skeleton height="300px" mb={4} />
276
+ <SkeletonText mt="4" noOfLines={4} spacing="4" />
277
+ </Box>
278
+ );
279
+ }
280
+
281
+ return <ProductView product={product} />;
282
+ };
283
+ ```
284
+
285
+ ## Error Handling in Components
286
+
287
+ Implement graceful error handling:
288
+
289
+ ```jsx
290
+ import {Box, Alert, AlertIcon, Button} from '@salesforce/retail-react-app/app/components/shared/ui';
291
+
292
+ const ProductDetail = ({productId}) => {
293
+ const {data: product, isLoading, error, refetch} = useProduct({
294
+ parameters: {id: productId}
295
+ });
296
+
297
+ if (error) {
298
+ return (
299
+ <Alert status="error">
300
+ <AlertIcon />
301
+ Failed to load product.
302
+ <Button ml={4} size="sm" onClick={() => refetch()}>
303
+ Retry
304
+ </Button>
305
+ </Alert>
306
+ );
307
+ }
308
+
309
+ if (isLoading) return <ProductSkeleton />;
310
+ return <ProductView product={product} />;
311
+ };
312
+ ```
313
+
314
+ ## Component Documentation
315
+
316
+ Add JSDoc comments for components:
317
+
318
+ ```jsx
319
+ /**
320
+ * Displays a product tile with image, name, price, and add to cart button.
321
+ *
322
+ * @param {Object} props - Component props
323
+ * @param {Object} props.product - Product data object
324
+ * @param {string} props.product.id - Product ID
325
+ * @param {string} props.product.name - Product name
326
+ * @param {number} props.product.price - Product price
327
+ * @param {Function} props.onAddToCart - Callback when add to cart is clicked
328
+ * @returns {JSX.Element}
329
+ */
330
+ const ProductTile = ({product, onAddToCart}) => {
331
+ // Component implementation
332
+ };
333
+ ```
334
+
335
+ ## PropTypes Validation
336
+
337
+ Always define PropTypes for all component props:
338
+
339
+ ```jsx
340
+ import PropTypes from 'prop-types';
341
+
342
+ ProductTile.propTypes = {
343
+ product: PropTypes.shape({
344
+ id: PropTypes.string.isRequired,
345
+ name: PropTypes.string.isRequired,
346
+ price: PropTypes.number.isRequired,
347
+ imageUrl: PropTypes.string
348
+ }).isRequired,
349
+ onAddToCart: PropTypes.func.isRequired,
350
+ isDisabled: PropTypes.bool
351
+ };
352
+
353
+ ProductTile.defaultProps = {
354
+ isDisabled: false
355
+ };
356
+ ```
357
+
358
+ ## Display Names for Debugging
359
+
360
+ Set displayName for better debugging:
361
+
362
+ ```jsx
363
+ const ProductTile = ({product}) => {
364
+ // Component implementation
365
+ };
366
+
367
+ ProductTile.displayName = 'ProductTile';
368
+ ```
369
+
370
+ ## HTML Head Tag Management
371
+
372
+ Use React Helmet to modify document head tags:
373
+
374
+ ```jsx
375
+ import {Helmet} from 'react-helmet';
376
+
377
+ const ProductDetail = ({product}) => {
378
+ return (
379
+ <>
380
+ <Helmet>
381
+ <title>{product.name} | My Store</title>
382
+ <meta name="description" content={product.description} />
383
+ <meta property="og:title" content={product.name} />
384
+ <meta property="og:image" content={product.imageUrl} />
385
+ </Helmet>
386
+ <ProductView product={product} />
387
+ </>
388
+ );
389
+ };
390
+ ```
391
+
392
+ ## Component Testing
393
+
394
+ Co-locate test files with components using the `.test.jsx` suffix. See the Testing section for comprehensive testing patterns.
395
+
396
+ ```
397
+ app/components/product-tile/
398
+ ├── index.jsx
399
+ └── product-tile.test.jsx
400
+ ```
@@ -0,0 +1,124 @@
1
+ # Configuration
2
+
3
+ ## Overview
4
+
5
+ PWA Kit applications use configuration files to customize API access, URL formatting, SSR, and application settings. Configuration values are serialized for isomorphic rendering.
6
+
7
+ ## Configuration Files
8
+
9
+ Configuration files are located in `config/`:
10
+
11
+ ```
12
+ config/
13
+ ├── default.js # Default configuration
14
+ ├── production.js # Production overrides
15
+ ├── development.js # Development overrides
16
+ └── local.js # Local overrides (git-ignored)
17
+ ```
18
+
19
+ ### File Format Precedence
20
+
21
+ If base names are the same:
22
+ 1. `.js` (JavaScript) - Highest priority
23
+ 2. `.yml` (YAML)
24
+ 3. `.yaml` (YAML)
25
+ 4. `.json` (JSON) - Lowest priority
26
+
27
+ ## Critical Security Rule: No Secrets in Configuration
28
+
29
+ **Configuration values are serialized and sent to the client**. Never include secrets:
30
+
31
+ ```javascript
32
+ // ❌ WRONG - Secrets exposed to browser!
33
+ module.exports = {
34
+ apiKey: 'sk_live_abc123', // EXPOSED!
35
+ secretToken: process.env.SECRET // Still exposed!
36
+ };
37
+
38
+ // ✅ CORRECT - Use proxy or server-only environment variables
39
+ module.exports = {
40
+ publicApiKey: 'pk_live_xyz789', // OK - public key
41
+ apiEndpoint: '/mobify/proxy/external-api' // OK - uses proxy
42
+ };
43
+ ```
44
+
45
+ ## Standard Configuration Structure
46
+
47
+ **Reference:** See `config/default.js` and `config/sites.js` in the template for the full structure.
48
+
49
+ Key properties: `app.url` (site, locale, showDefaults), `app.defaultSite`, `app.siteAliases`, `app.sites`, `app.commerceAPI`, `app.storeLocatorEnabled`, `app.multishipEnabled`, `envBasePath`, `ssrEnabled`, `ssrParameters.proxyConfigs`.
50
+
51
+ **Note:** Use `commerceAPI` (not `commerceAPIConfig`). Feature flags live at `app.*` level.
52
+
53
+ ## Proxy Configuration
54
+
55
+ Use the proxy feature to route API requests through the storefront domain:
56
+
57
+ ```javascript
58
+ // config/default.js - merge into your module.exports
59
+ module.exports = {
60
+ // ...other config (app, ssrEnabled, etc.)
61
+ proxy: {
62
+ 'external-api': {
63
+ host: 'https://api.example.com',
64
+ path: '/v1',
65
+ caching: true
66
+ }
67
+ }
68
+ };
69
+ ```
70
+
71
+ ### Using Proxy in Code
72
+
73
+ ```javascript
74
+ // Request through proxy using /mobify/proxy/<PROXY_PATH> pattern
75
+ const response = await fetch('/mobify/proxy/external-api/users');
76
+ // This proxies to: https://api.example.com/v1/users
77
+ ```
78
+
79
+ ## Multi-Site Configuration
80
+
81
+ **Reference:** See `config/sites.js` in the template. Each site has `id`, `l10n.supportedCurrencies`, `l10n.defaultLocale`, `l10n.supportedLocales` (with `id`, `preferredCurrency`). Reference in `config/default.js` via `sites: require('./sites.js')`.
82
+
83
+ ## Accessing Configuration
84
+
85
+ Use `getConfig` from `@salesforce/pwa-kit-runtime/utils/ssr-config` in both server and client code:
86
+
87
+ ```javascript
88
+ import {getConfig} from '@salesforce/pwa-kit-runtime/utils/ssr-config';
89
+
90
+ // In components or server code
91
+ const config = getConfig();
92
+ const siteId = config.app.commerceAPI.parameters.siteId;
93
+ const storeLocatorEnabled = config.app.storeLocatorEnabled ?? true;
94
+ ```
95
+
96
+ ### In Components
97
+
98
+ ```jsx
99
+ import {getConfig} from '@salesforce/pwa-kit-runtime/utils/ssr-config';
100
+
101
+ const MyComponent = () => {
102
+ const config = getConfig();
103
+ const siteId = config.app.commerceAPI.parameters.siteId;
104
+ return <div>Site: {siteId}</div>;
105
+ };
106
+ ```
107
+
108
+ ## Feature Flags
109
+
110
+ Feature flags are at `app.*` level in config:
111
+
112
+ ```javascript
113
+ // config/default.js
114
+ module.exports = {
115
+ app: {
116
+ storeLocatorEnabled: true,
117
+ multishipEnabled: true,
118
+ partialHydrationEnabled: false,
119
+ oneClickCheckout: { enabled: false } // Developer Preview - requires private SLAS client
120
+ }
121
+ };
122
+ ```
123
+
124
+ **Note:** The checkout route can be configured to use One Click Checkout when `app.oneClickCheckout.enabled` is true. See `app/routes.jsx` and `app/pages/checkout` for feature-flag usage.