@salesforce/b2c-cli 2.3.0 → 2.4.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 (421) hide show
  1. package/bin/dev.js +8 -8
  2. package/bin/run.js +5 -7
  3. package/content/guidance/b2c/b2c-business-manager-extensions/SKILL.md +361 -0
  4. package/content/guidance/b2c/b2c-business-manager-extensions/references/EXTENSIONS-XML.md +458 -0
  5. package/content/guidance/b2c/b2c-controllers/SKILL.md +301 -0
  6. package/content/guidance/b2c/b2c-controllers/references/CLASSIC-PATTERNS.md +335 -0
  7. package/content/guidance/b2c/b2c-controllers/references/SFRA-PATTERNS.md +400 -0
  8. package/content/guidance/b2c/b2c-custom-api-development/SKILL.md +281 -0
  9. package/content/guidance/b2c/b2c-custom-api-development/references/CONTRACT.md +142 -0
  10. package/content/guidance/b2c/b2c-custom-api-development/references/IMPLEMENTATION.md +153 -0
  11. package/content/guidance/b2c/b2c-custom-api-development/references/TESTING.md +118 -0
  12. package/content/guidance/b2c/b2c-custom-caches/SKILL.md +279 -0
  13. package/content/guidance/b2c/b2c-custom-job-steps/SKILL.md +520 -0
  14. package/content/guidance/b2c/b2c-custom-job-steps/references/CHUNK-ORIENTED.md +377 -0
  15. package/content/guidance/b2c/b2c-custom-job-steps/references/JOBS-XML.md +212 -0
  16. package/content/guidance/b2c/b2c-custom-job-steps/references/STEPTYPES-JSON.md +373 -0
  17. package/content/guidance/b2c/b2c-custom-job-steps/references/TASK-ORIENTED.md +344 -0
  18. package/content/guidance/b2c/b2c-custom-objects/SKILL.md +327 -0
  19. package/content/guidance/b2c/b2c-custom-objects/references/OCAPI-SEARCH.md +298 -0
  20. package/content/guidance/b2c/b2c-forms/SKILL.md +242 -0
  21. package/content/guidance/b2c/b2c-forms/references/FORM-XML.md +409 -0
  22. package/content/guidance/b2c/b2c-hooks/SKILL.md +500 -0
  23. package/content/guidance/b2c/b2c-hooks/references/OCAPI-SCAPI-HOOKS.md +403 -0
  24. package/content/guidance/b2c/b2c-hooks/references/ORDER-HOOK-LIFECYCLE.md +169 -0
  25. package/content/guidance/b2c/b2c-hooks/references/SYSTEM-HOOKS.md +433 -0
  26. package/content/guidance/b2c/b2c-isml/SKILL.md +320 -0
  27. package/content/guidance/b2c/b2c-isml/references/EXPRESSIONS.md +366 -0
  28. package/content/guidance/b2c/b2c-isml/references/TAGS.md +443 -0
  29. package/content/guidance/b2c/b2c-localization/SKILL.md +344 -0
  30. package/content/guidance/b2c/b2c-localization/references/PATTERNS.md +407 -0
  31. package/content/guidance/b2c/b2c-logging/SKILL.md +352 -0
  32. package/content/guidance/b2c/b2c-logging/references/LOG-FILES.md +282 -0
  33. package/content/guidance/b2c/b2c-metadata/SKILL.md +406 -0
  34. package/content/guidance/b2c/b2c-metadata/references/SYSTEM-OBJECTS.md +320 -0
  35. package/content/guidance/b2c/b2c-metadata/references/XML-EXAMPLES.md +366 -0
  36. package/content/guidance/b2c/b2c-onboarding/SKILL.md +154 -0
  37. package/content/guidance/b2c/b2c-ordering/SKILL.md +391 -0
  38. package/content/guidance/b2c/b2c-page-designer/SKILL.md +410 -0
  39. package/content/guidance/b2c/b2c-page-designer/references/ATTRIBUTE-TYPES.md +436 -0
  40. package/content/guidance/b2c/b2c-page-designer/references/META-DEFINITIONS.md +340 -0
  41. package/content/guidance/b2c/b2c-querying-data/SKILL.md +289 -0
  42. package/content/guidance/b2c/b2c-querying-data/references/PERFORMANCE-APIS.md +74 -0
  43. package/content/guidance/b2c/b2c-scapi-admin/SKILL.md +53 -0
  44. package/content/guidance/b2c/b2c-scapi-admin/references/CLIENT-EXAMPLES.md +440 -0
  45. package/content/guidance/b2c/b2c-scapi-admin/references/INTEGRATION-PATTERNS.md +518 -0
  46. package/content/guidance/b2c/b2c-scapi-admin/references/OAUTH-SCOPES.md +337 -0
  47. package/content/guidance/b2c/b2c-scapi-shopper/SKILL.md +56 -0
  48. package/content/guidance/b2c/b2c-scapi-shopper/references/CHECKOUT-FLOW.md +466 -0
  49. package/content/guidance/b2c/b2c-scapi-shopper/references/CLIENT-EXAMPLES.md +351 -0
  50. package/content/guidance/b2c/b2c-scapi-shopper/references/COMMON-PATTERNS.md +390 -0
  51. package/content/guidance/b2c/b2c-scapi-shopper/references/SCOPES.md +290 -0
  52. package/content/guidance/b2c/b2c-slas-auth-patterns/SKILL.md +420 -0
  53. package/content/guidance/b2c/b2c-slas-auth-patterns/references/PASSKEYS.md +126 -0
  54. package/content/guidance/b2c/b2c-slas-auth-patterns/references/SESSION-BRIDGE.md +267 -0
  55. package/content/guidance/b2c/b2c-slas-auth-patterns/references/TOKEN-LIFECYCLE.md +367 -0
  56. package/content/guidance/b2c/b2c-webservices/SKILL.md +318 -0
  57. package/content/guidance/b2c/b2c-webservices/references/FTP-SERVICES.md +524 -0
  58. package/content/guidance/b2c/b2c-webservices/references/HTTP-SERVICES.md +578 -0
  59. package/content/guidance/b2c/b2c-webservices/references/SERVICES-XML.md +351 -0
  60. package/content/guidance/b2c/b2c-webservices/references/SOAP-SERVICES.md +587 -0
  61. package/content/guidance/b2c-cli/b2c-am/SKILL.md +277 -0
  62. package/content/guidance/b2c-cli/b2c-bm-users-roles/SKILL.md +210 -0
  63. package/content/guidance/b2c-cli/b2c-cap/SKILL.md +131 -0
  64. package/content/guidance/b2c-cli/b2c-cip/SKILL.md +116 -0
  65. package/content/guidance/b2c-cli/b2c-cip/references/KNOWN_TABLES.md +105 -0
  66. package/content/guidance/b2c-cli/b2c-cip/references/SALES_ANALYSIS.md +50 -0
  67. package/content/guidance/b2c-cli/b2c-cip/references/STARTER_QUERIES.md +147 -0
  68. package/content/guidance/b2c-cli/b2c-code/SKILL.md +146 -0
  69. package/content/guidance/b2c-cli/b2c-config/SKILL.md +462 -0
  70. package/content/guidance/b2c-cli/b2c-content/SKILL.md +176 -0
  71. package/content/guidance/b2c-cli/b2c-debug/SKILL.md +138 -0
  72. package/content/guidance/b2c-cli/b2c-docs/SKILL.md +301 -0
  73. package/content/guidance/b2c-cli/b2c-ecdn/SKILL.md +135 -0
  74. package/content/guidance/b2c-cli/b2c-ecdn/references/ADVANCED.md +97 -0
  75. package/content/guidance/b2c-cli/b2c-ecdn/references/SECURITY.md +75 -0
  76. package/content/guidance/b2c-cli/b2c-import-set-migrations/SKILL.md +265 -0
  77. package/content/guidance/b2c-cli/b2c-job/SKILL.md +64 -0
  78. package/content/guidance/b2c-cli/b2c-job/references/EXPORT.md +121 -0
  79. package/content/guidance/b2c-cli/b2c-job/references/IMPORT.md +55 -0
  80. package/content/guidance/b2c-cli/b2c-job/references/RUN-AND-MONITOR.md +119 -0
  81. package/content/guidance/b2c-cli/b2c-logs/SKILL.md +249 -0
  82. package/content/guidance/b2c-cli/b2c-metrics/SKILL.md +315 -0
  83. package/content/guidance/b2c-cli/b2c-mrt/SKILL.md +207 -0
  84. package/content/guidance/b2c-cli/b2c-mrt/references/BUNDLE-COMMANDS.md +203 -0
  85. package/content/guidance/b2c-cli/b2c-mrt/references/ENVIRONMENT-COMMANDS.md +218 -0
  86. package/content/guidance/b2c-cli/b2c-mrt/references/PROJECT-COMMANDS.md +154 -0
  87. package/content/guidance/b2c-cli/b2c-sandbox/SKILL.md +112 -0
  88. package/content/guidance/b2c-cli/b2c-scapi-custom/SKILL.md +126 -0
  89. package/content/guidance/b2c-cli/b2c-scapi-schemas/SKILL.md +66 -0
  90. package/content/guidance/b2c-cli/b2c-scapi-schemas/references/CLI-EXAMPLES.md +108 -0
  91. package/content/guidance/b2c-cli/b2c-site-import-export/SKILL.md +57 -0
  92. package/content/guidance/b2c-cli/b2c-site-import-export/references/IMPORT-OPTIONS.md +118 -0
  93. package/content/guidance/b2c-cli/b2c-site-import-export/references/METADATA-XML.md +381 -0
  94. package/content/guidance/b2c-cli/b2c-site-import-export/references/WORKFLOWS.md +182 -0
  95. package/content/guidance/b2c-cli/b2c-sites/SKILL.md +112 -0
  96. package/content/guidance/b2c-cli/b2c-slas/SKILL.md +182 -0
  97. package/content/guidance/b2c-cli/b2c-webdav/SKILL.md +186 -0
  98. package/content/guidance/b2c-ops/b2c-checkout-triage/SKILL.md +68 -0
  99. package/content/guidance/b2c-ops/b2c-job-health/SKILL.md +75 -0
  100. package/content/guidance/b2c-ops/b2c-job-health/references/job-logs.md +21 -0
  101. package/content/guidance/b2c-ops/b2c-order-failure-triage/SKILL.md +66 -0
  102. package/content/guidance/b2c-ops/b2c-order-failure-triage/references/order-evidence.md +87 -0
  103. package/content/guidance/b2c-ops/b2c-production-triage/SKILL.md +87 -0
  104. package/content/guidance/b2c-ops/b2c-production-triage/references/escalation.md +57 -0
  105. package/content/guidance/index.json +1949 -0
  106. package/content/guidance/storefront-next/sfnext-accessibility/SKILL.md +103 -0
  107. package/content/guidance/storefront-next/sfnext-accessibility/references/checklist.md +64 -0
  108. package/content/guidance/storefront-next/sfnext-analytics-consent/SKILL.md +91 -0
  109. package/content/guidance/storefront-next/sfnext-analytics-consent/references/CUSTOM-ADAPTER.md +49 -0
  110. package/content/guidance/storefront-next/sfnext-authentication/SKILL.md +127 -0
  111. package/content/guidance/storefront-next/sfnext-authentication/references/COOKIES.md +39 -0
  112. package/content/guidance/storefront-next/sfnext-authentication/references/LOGIN-FLOWS.md +59 -0
  113. package/content/guidance/storefront-next/sfnext-commerce-features/SKILL.md +67 -0
  114. package/content/guidance/storefront-next/sfnext-commerce-features/references/FEATURE-PREREQUISITES.md +37 -0
  115. package/content/guidance/storefront-next/sfnext-components/SKILL.md +153 -0
  116. package/content/guidance/storefront-next/sfnext-components/references/COMPONENT-AUTHORING.md +118 -0
  117. package/content/guidance/storefront-next/sfnext-components/references/SHAPE-TOKENS.md +51 -0
  118. package/content/guidance/storefront-next/sfnext-components/references/STORYBOOK.md +54 -0
  119. package/content/guidance/storefront-next/sfnext-components/references/TOKEN-SYSTEM.md +53 -0
  120. package/content/guidance/storefront-next/sfnext-components/references/TROUBLESHOOTING.md +19 -0
  121. package/content/guidance/storefront-next/sfnext-configuration/SKILL.md +163 -0
  122. package/content/guidance/storefront-next/sfnext-configuration/references/ENV-VARIABLES.md +55 -0
  123. package/content/guidance/storefront-next/sfnext-configuration/references/MULTI-SITE-URLS.md +137 -0
  124. package/content/guidance/storefront-next/sfnext-data-fetching/SKILL.md +140 -0
  125. package/content/guidance/storefront-next/sfnext-data-fetching/references/ACTIONS.md +53 -0
  126. package/content/guidance/storefront-next/sfnext-data-fetching/references/API-CLIENTS.md +34 -0
  127. package/content/guidance/storefront-next/sfnext-data-fetching/references/LOADERS.md +73 -0
  128. package/content/guidance/storefront-next/sfnext-data-fetching/references/SCAPI-FETCHER.md +39 -0
  129. package/content/guidance/storefront-next/sfnext-deployment/SKILL.md +127 -0
  130. package/content/guidance/storefront-next/sfnext-deployment/references/MRT-DEPLOYMENT.md +59 -0
  131. package/content/guidance/storefront-next/sfnext-extensions/SKILL.md +118 -0
  132. package/content/guidance/storefront-next/sfnext-extensions/references/ACTION-HOOKS.md +57 -0
  133. package/content/guidance/storefront-next/sfnext-extensions/references/BASE-AUDIT.md +68 -0
  134. package/content/guidance/storefront-next/sfnext-extensions/references/CLI-AND-INSTALL.md +58 -0
  135. package/content/guidance/storefront-next/sfnext-extensions/references/EXTENSION-EXAMPLES.md +79 -0
  136. package/content/guidance/storefront-next/sfnext-hybrid-storefronts/SKILL.md +93 -0
  137. package/content/guidance/storefront-next/sfnext-hybrid-storefronts/references/HYBRID-PROXY-CONFIG.md +86 -0
  138. package/content/guidance/storefront-next/sfnext-i18n/SKILL.md +152 -0
  139. package/content/guidance/storefront-next/sfnext-i18n/references/locale-config.md +35 -0
  140. package/content/guidance/storefront-next/sfnext-overview/SKILL.md +101 -0
  141. package/content/guidance/storefront-next/sfnext-page-designer/SKILL.md +202 -0
  142. package/content/guidance/storefront-next/sfnext-page-designer/references/BUSINESS-MANAGER.md +46 -0
  143. package/content/guidance/storefront-next/sfnext-page-designer/references/COMPONENT-REGISTRY.md +111 -0
  144. package/content/guidance/storefront-next/sfnext-page-designer/references/DECORATOR-PATTERNS.md +168 -0
  145. package/content/guidance/storefront-next/sfnext-page-designer/references/REVIEW-CHECKLIST.md +83 -0
  146. package/content/guidance/storefront-next/sfnext-page-designer/references/TROUBLESHOOTING.md +35 -0
  147. package/content/guidance/storefront-next/sfnext-performance/SKILL.md +102 -0
  148. package/content/guidance/storefront-next/sfnext-performance/references/PERFORMANCE-REVIEW-CHECKLIST.md +85 -0
  149. package/content/guidance/storefront-next/sfnext-performance/references/SUSPENSE-AND-STREAMING.md +58 -0
  150. package/content/guidance/storefront-next/sfnext-project-setup/SKILL.md +147 -0
  151. package/content/guidance/storefront-next/sfnext-project-setup/references/PROJECT-STRUCTURE.md +61 -0
  152. package/content/guidance/storefront-next/sfnext-project-setup/references/SCRIPTS.md +47 -0
  153. package/content/guidance/storefront-next/sfnext-project-setup/references/SFNEXT-CLI.md +63 -0
  154. package/content/guidance/storefront-next/sfnext-quality-gates/SKILL.md +70 -0
  155. package/content/guidance/storefront-next/sfnext-quality-gates/references/lint-and-budgets.md +39 -0
  156. package/content/guidance/storefront-next/sfnext-revalidation/SKILL.md +121 -0
  157. package/content/guidance/storefront-next/sfnext-revalidation/references/POLICIES-AND-TAGS.md +55 -0
  158. package/content/guidance/storefront-next/sfnext-routing/SKILL.md +123 -0
  159. package/content/guidance/storefront-next/sfnext-routing/references/ROUTE-CONVENTIONS.md +65 -0
  160. package/content/guidance/storefront-next/sfnext-routing/references/URLS-AND-SEO-ROUTES.md +22 -0
  161. package/content/guidance/storefront-next/sfnext-scapi/SKILL.md +126 -0
  162. package/content/guidance/storefront-next/sfnext-scapi/references/WORKED-EXAMPLE.md +39 -0
  163. package/content/guidance/storefront-next/sfnext-security/SKILL.md +129 -0
  164. package/content/guidance/storefront-next/sfnext-security/references/COOKIE-DOMAIN.md +39 -0
  165. package/content/guidance/storefront-next/sfnext-security/references/TURNSTILE.md +43 -0
  166. package/content/guidance/storefront-next/sfnext-seo/SKILL.md +95 -0
  167. package/content/guidance/storefront-next/sfnext-seo/references/MULTI-DOMAIN-BASE-PATH.md +17 -0
  168. package/content/guidance/storefront-next/sfnext-seo/references/SEO-ROUTES.md +31 -0
  169. package/content/guidance/storefront-next/sfnext-state-management/SKILL.md +114 -0
  170. package/content/guidance/storefront-next/sfnext-state-management/references/PATTERNS.md +45 -0
  171. package/content/guidance/storefront-next/sfnext-testing/SKILL.md +151 -0
  172. package/content/guidance/storefront-next/sfnext-testing/references/E2E.md +38 -0
  173. package/content/guidance/storefront-next/sfnext-testing/references/STORYBOOK-PATTERNS.md +97 -0
  174. package/content/guidance/storefront-next/sfnext-testing/references/UNIT-AND-ROUTE-TESTS.md +60 -0
  175. package/content/guidance/storefront-next/sfnext-theming/SKILL.md +104 -0
  176. package/content/guidance/storefront-next/sfnext-theming/references/REBRAND-CHECKLIST.md +29 -0
  177. package/dist/commands/cap/install.d.ts +1 -0
  178. package/dist/commands/cap/list.d.ts +1 -0
  179. package/dist/commands/cap/pull.d.ts +1 -0
  180. package/dist/commands/cap/tasks.d.ts +1 -0
  181. package/dist/commands/cap/uninstall.d.ts +1 -0
  182. package/dist/commands/cip/describe.d.ts +1 -0
  183. package/dist/commands/cip/query.d.ts +1 -0
  184. package/dist/commands/cip/report/bot-traffic-share.d.ts +1 -0
  185. package/dist/commands/cip/report/checkout-funnel-dropoff.d.ts +1 -0
  186. package/dist/commands/cip/report/controller-error-rate-trend.d.ts +1 -0
  187. package/dist/commands/cip/report/controller-health-scorecard.d.ts +1 -0
  188. package/dist/commands/cip/report/customer-registration-trends.d.ts +1 -0
  189. package/dist/commands/cip/report/discount-depth-breakdown.d.ts +1 -0
  190. package/dist/commands/cip/report/inventory-stockout-by-location.d.ts +1 -0
  191. package/dist/commands/cip/report/new-vs-returning-buyer-revenue.d.ts +1 -0
  192. package/dist/commands/cip/report/ocapi-client-usage.d.ts +1 -0
  193. package/dist/commands/cip/report/ocapi-requests.d.ts +1 -0
  194. package/dist/commands/cip/report/payment-method-performance.d.ts +1 -0
  195. package/dist/commands/cip/report/product-co-purchase-analysis.d.ts +1 -0
  196. package/dist/commands/cip/report/promotion-discount-analysis.d.ts +1 -0
  197. package/dist/commands/cip/report/promotion-roi-leaderboard.d.ts +1 -0
  198. package/dist/commands/cip/report/recommender-effectiveness.d.ts +1 -0
  199. package/dist/commands/cip/report/remote-include-performance.d.ts +1 -0
  200. package/dist/commands/cip/report/revenue-by-channel.d.ts +1 -0
  201. package/dist/commands/cip/report/sales-analytics.d.ts +1 -0
  202. package/dist/commands/cip/report/sales-summary.d.ts +1 -0
  203. package/dist/commands/cip/report/scapi-cache-hit-ratio.d.ts +1 -0
  204. package/dist/commands/cip/report/scapi-error-rate-by-status.d.ts +1 -0
  205. package/dist/commands/cip/report/scapi-latency-distribution.d.ts +1 -0
  206. package/dist/commands/cip/report/scapi-traffic-latency.d.ts +1 -0
  207. package/dist/commands/cip/report/search-query-performance.d.ts +1 -0
  208. package/dist/commands/cip/report/top-referrers.d.ts +1 -0
  209. package/dist/commands/cip/report/top-selling-products.d.ts +1 -0
  210. package/dist/commands/cip/report/zero-result-searches.d.ts +1 -0
  211. package/dist/commands/cip/tables.d.ts +1 -0
  212. package/dist/commands/code/activate.d.ts +1 -0
  213. package/dist/commands/code/delete.d.ts +1 -0
  214. package/dist/commands/code/deploy.d.ts +1 -0
  215. package/dist/commands/code/download.d.ts +1 -0
  216. package/dist/commands/code/watch.d.ts +1 -0
  217. package/dist/commands/commands/search.d.ts +35 -0
  218. package/dist/commands/commands/search.js +85 -0
  219. package/dist/commands/commands/search.js.map +1 -0
  220. package/dist/commands/content/export.d.ts +1 -0
  221. package/dist/commands/content/list.d.ts +1 -0
  222. package/dist/commands/content/validate.d.ts +1 -0
  223. package/dist/commands/debug/cli.d.ts +1 -0
  224. package/dist/commands/debug/index.d.ts +1 -0
  225. package/dist/commands/docs/cache.d.ts +1 -0
  226. package/dist/commands/docs/download.d.ts +1 -0
  227. package/dist/commands/docs/read.d.ts +1 -0
  228. package/dist/commands/docs/schema.d.ts +1 -0
  229. package/dist/commands/docs/search.d.ts +1 -0
  230. package/dist/commands/docs/skill.d.ts +41 -0
  231. package/dist/commands/docs/skill.js +183 -0
  232. package/dist/commands/docs/skill.js.map +1 -0
  233. package/dist/commands/ecdn/cache/purge.d.ts +1 -0
  234. package/dist/commands/ecdn/certificates/add.d.ts +1 -0
  235. package/dist/commands/ecdn/certificates/delete.d.ts +1 -0
  236. package/dist/commands/ecdn/certificates/list.d.ts +1 -0
  237. package/dist/commands/ecdn/certificates/update.d.ts +1 -0
  238. package/dist/commands/ecdn/certificates/validate.d.ts +1 -0
  239. package/dist/commands/ecdn/cipher-suites/get.d.ts +1 -0
  240. package/dist/commands/ecdn/cipher-suites/update.d.ts +1 -0
  241. package/dist/commands/ecdn/firewall/create.d.ts +1 -0
  242. package/dist/commands/ecdn/firewall/delete.d.ts +1 -0
  243. package/dist/commands/ecdn/firewall/get.d.ts +1 -0
  244. package/dist/commands/ecdn/firewall/list.d.ts +1 -0
  245. package/dist/commands/ecdn/firewall/reorder.d.ts +1 -0
  246. package/dist/commands/ecdn/firewall/update.d.ts +1 -0
  247. package/dist/commands/ecdn/logpush/jobs/create.d.ts +1 -0
  248. package/dist/commands/ecdn/logpush/jobs/delete.d.ts +1 -0
  249. package/dist/commands/ecdn/logpush/jobs/get.d.ts +1 -0
  250. package/dist/commands/ecdn/logpush/jobs/list.d.ts +1 -0
  251. package/dist/commands/ecdn/logpush/jobs/update.d.ts +1 -0
  252. package/dist/commands/ecdn/logpush/ownership.d.ts +1 -0
  253. package/dist/commands/ecdn/mrt-rules/create.d.ts +1 -0
  254. package/dist/commands/ecdn/mrt-rules/delete.d.ts +1 -0
  255. package/dist/commands/ecdn/mrt-rules/get.d.ts +1 -0
  256. package/dist/commands/ecdn/mrt-rules/rules/delete.d.ts +1 -0
  257. package/dist/commands/ecdn/mrt-rules/rules/update.d.ts +1 -0
  258. package/dist/commands/ecdn/mrt-rules/update.d.ts +1 -0
  259. package/dist/commands/ecdn/mtls/create.d.ts +1 -0
  260. package/dist/commands/ecdn/mtls/delete.d.ts +1 -0
  261. package/dist/commands/ecdn/mtls/get.d.ts +1 -0
  262. package/dist/commands/ecdn/mtls/issue.d.ts +1 -0
  263. package/dist/commands/ecdn/mtls/list.d.ts +1 -0
  264. package/dist/commands/ecdn/mtls/setup.d.ts +1 -0
  265. package/dist/commands/ecdn/origin-headers/delete.d.ts +1 -0
  266. package/dist/commands/ecdn/origin-headers/get.d.ts +1 -0
  267. package/dist/commands/ecdn/origin-headers/set.d.ts +1 -0
  268. package/dist/commands/ecdn/page-shield/notifications/create.d.ts +1 -0
  269. package/dist/commands/ecdn/page-shield/notifications/delete.d.ts +1 -0
  270. package/dist/commands/ecdn/page-shield/notifications/list.d.ts +1 -0
  271. package/dist/commands/ecdn/page-shield/policies/create.d.ts +1 -0
  272. package/dist/commands/ecdn/page-shield/policies/delete.d.ts +1 -0
  273. package/dist/commands/ecdn/page-shield/policies/get.d.ts +1 -0
  274. package/dist/commands/ecdn/page-shield/policies/list.d.ts +1 -0
  275. package/dist/commands/ecdn/page-shield/policies/update.d.ts +1 -0
  276. package/dist/commands/ecdn/page-shield/scripts/get.d.ts +1 -0
  277. package/dist/commands/ecdn/page-shield/scripts/list.d.ts +1 -0
  278. package/dist/commands/ecdn/rate-limit/create.d.ts +1 -0
  279. package/dist/commands/ecdn/rate-limit/delete.d.ts +1 -0
  280. package/dist/commands/ecdn/rate-limit/get.d.ts +1 -0
  281. package/dist/commands/ecdn/rate-limit/list.d.ts +1 -0
  282. package/dist/commands/ecdn/rate-limit/update.d.ts +1 -0
  283. package/dist/commands/ecdn/security/get.d.ts +1 -0
  284. package/dist/commands/ecdn/security/update.d.ts +1 -0
  285. package/dist/commands/ecdn/speed/get.d.ts +1 -0
  286. package/dist/commands/ecdn/speed/update.d.ts +1 -0
  287. package/dist/commands/ecdn/waf/groups/list.d.ts +1 -0
  288. package/dist/commands/ecdn/waf/groups/update.d.ts +1 -0
  289. package/dist/commands/ecdn/waf/managed-rules/list.d.ts +1 -0
  290. package/dist/commands/ecdn/waf/managed-rules/update.d.ts +1 -0
  291. package/dist/commands/ecdn/waf/migrate.d.ts +1 -0
  292. package/dist/commands/ecdn/waf/owasp/get.d.ts +1 -0
  293. package/dist/commands/ecdn/waf/owasp/update.d.ts +1 -0
  294. package/dist/commands/ecdn/waf/rules/get.d.ts +1 -0
  295. package/dist/commands/ecdn/waf/rules/list.d.ts +1 -0
  296. package/dist/commands/ecdn/waf/rules/update.d.ts +1 -0
  297. package/dist/commands/ecdn/waf/rulesets/list.d.ts +1 -0
  298. package/dist/commands/ecdn/waf/rulesets/update.d.ts +1 -0
  299. package/dist/commands/ecdn/zones/create.d.ts +1 -0
  300. package/dist/commands/ecdn/zones/list.d.ts +1 -0
  301. package/dist/commands/job/execution/delete.d.ts +1 -0
  302. package/dist/commands/job/export.d.ts +1 -0
  303. package/dist/commands/job/import-set.d.ts +1 -0
  304. package/dist/commands/job/import.d.ts +1 -0
  305. package/dist/commands/job/log.d.ts +1 -0
  306. package/dist/commands/job/run.d.ts +1 -0
  307. package/dist/commands/job/search.d.ts +1 -0
  308. package/dist/commands/job/wait.d.ts +1 -0
  309. package/dist/commands/logs/get.d.ts +1 -0
  310. package/dist/commands/logs/list.d.ts +1 -0
  311. package/dist/commands/logs/tail.d.ts +1 -0
  312. package/dist/commands/metrics/controller.d.ts +1 -0
  313. package/dist/commands/metrics/ecdn.d.ts +1 -0
  314. package/dist/commands/metrics/mrt.d.ts +1 -0
  315. package/dist/commands/metrics/ocapi.d.ts +1 -0
  316. package/dist/commands/metrics/overall.d.ts +1 -0
  317. package/dist/commands/metrics/sales.d.ts +1 -0
  318. package/dist/commands/metrics/scapi-hooks.d.ts +1 -0
  319. package/dist/commands/metrics/scapi.d.ts +1 -0
  320. package/dist/commands/metrics/third-party.d.ts +1 -0
  321. package/dist/commands/mrt/bundle/delete.d.ts +1 -0
  322. package/dist/commands/mrt/bundle/deploy.d.ts +1 -0
  323. package/dist/commands/mrt/bundle/download.d.ts +1 -0
  324. package/dist/commands/mrt/bundle/history.d.ts +1 -0
  325. package/dist/commands/mrt/bundle/list.d.ts +1 -0
  326. package/dist/commands/mrt/bundle/save.d.ts +1 -0
  327. package/dist/commands/mrt/bundle/upload-v2.d.ts +1 -0
  328. package/dist/commands/mrt/env/access-control/list.d.ts +1 -0
  329. package/dist/commands/mrt/env/b2c.d.ts +1 -0
  330. package/dist/commands/mrt/env/clone.d.ts +1 -0
  331. package/dist/commands/mrt/env/create.d.ts +1 -0
  332. package/dist/commands/mrt/env/delete.d.ts +1 -0
  333. package/dist/commands/mrt/env/get.d.ts +1 -0
  334. package/dist/commands/mrt/env/invalidate.d.ts +1 -0
  335. package/dist/commands/mrt/env/list.d.ts +1 -0
  336. package/dist/commands/mrt/env/redirect/clone.d.ts +1 -0
  337. package/dist/commands/mrt/env/redirect/create.d.ts +1 -0
  338. package/dist/commands/mrt/env/redirect/delete.d.ts +1 -0
  339. package/dist/commands/mrt/env/redirect/list.d.ts +1 -0
  340. package/dist/commands/mrt/env/update.d.ts +1 -0
  341. package/dist/commands/mrt/env/var/delete.d.ts +1 -0
  342. package/dist/commands/mrt/env/var/list.d.ts +1 -0
  343. package/dist/commands/mrt/env/var/push.d.ts +1 -0
  344. package/dist/commands/mrt/env/var/set.d.ts +1 -0
  345. package/dist/commands/mrt/org/b2c.d.ts +1 -0
  346. package/dist/commands/mrt/org/cert/create.d.ts +1 -0
  347. package/dist/commands/mrt/org/cert/delete.d.ts +1 -0
  348. package/dist/commands/mrt/org/cert/get.d.ts +1 -0
  349. package/dist/commands/mrt/org/cert/list.d.ts +1 -0
  350. package/dist/commands/mrt/org/cert/restart-validation.d.ts +1 -0
  351. package/dist/commands/mrt/org/list.d.ts +1 -0
  352. package/dist/commands/mrt/org/member/add.d.ts +1 -0
  353. package/dist/commands/mrt/org/member/get.d.ts +1 -0
  354. package/dist/commands/mrt/org/member/list.d.ts +1 -0
  355. package/dist/commands/mrt/org/member/remove.d.ts +1 -0
  356. package/dist/commands/mrt/org/member/update.d.ts +1 -0
  357. package/dist/commands/mrt/project/create.d.ts +1 -0
  358. package/dist/commands/mrt/project/delete.d.ts +1 -0
  359. package/dist/commands/mrt/project/get.d.ts +1 -0
  360. package/dist/commands/mrt/project/list.d.ts +1 -0
  361. package/dist/commands/mrt/project/member/add.d.ts +1 -0
  362. package/dist/commands/mrt/project/member/get.d.ts +1 -0
  363. package/dist/commands/mrt/project/member/list.d.ts +1 -0
  364. package/dist/commands/mrt/project/member/remove.d.ts +1 -0
  365. package/dist/commands/mrt/project/member/update.d.ts +1 -0
  366. package/dist/commands/mrt/project/notification/delete.d.ts +1 -0
  367. package/dist/commands/mrt/project/notification/get.d.ts +1 -0
  368. package/dist/commands/mrt/project/update.d.ts +1 -0
  369. package/dist/commands/mrt/save-credentials.d.ts +1 -0
  370. package/dist/commands/mrt/tail-logs.d.ts +1 -0
  371. package/dist/commands/mrt/user/api-key.d.ts +1 -0
  372. package/dist/commands/mrt/user/email-prefs.d.ts +1 -0
  373. package/dist/commands/mrt/user/profile.d.ts +1 -0
  374. package/dist/commands/scaffold/init.js +2 -1
  375. package/dist/commands/scaffold/init.js.map +1 -1
  376. package/dist/commands/scapi/custom/status.d.ts +1 -0
  377. package/dist/commands/scapi/schemas/get.d.ts +1 -0
  378. package/dist/commands/scapi/schemas/list.d.ts +1 -0
  379. package/dist/commands/setup/ide/tsserver-plugin.d.ts +1 -0
  380. package/dist/commands/setup/ide/vscode-types.d.ts +1 -0
  381. package/dist/commands/setup/index.js +4 -3
  382. package/dist/commands/setup/index.js.map +1 -1
  383. package/dist/commands/setup/inspect.d.ts +1 -0
  384. package/dist/commands/setup/inspect.js +17 -2
  385. package/dist/commands/setup/inspect.js.map +1 -1
  386. package/dist/commands/setup/instance/create.d.ts +1 -0
  387. package/dist/commands/setup/instance/list.d.ts +1 -0
  388. package/dist/commands/setup/instance/remove.d.ts +1 -0
  389. package/dist/commands/setup/instance/set-active.d.ts +1 -0
  390. package/dist/commands/setup/openshell.d.ts +1 -0
  391. package/dist/commands/setup/skills.d.ts +1 -0
  392. package/dist/commands/slas/client/create.d.ts +1 -0
  393. package/dist/commands/slas/client/delete.d.ts +1 -0
  394. package/dist/commands/slas/client/get.d.ts +1 -0
  395. package/dist/commands/slas/client/list.d.ts +1 -0
  396. package/dist/commands/slas/client/open.d.ts +1 -0
  397. package/dist/commands/slas/client/update.d.ts +1 -0
  398. package/dist/commands/slas/token.d.ts +1 -0
  399. package/dist/commands/slas/token.js +2 -1
  400. package/dist/commands/slas/token.js.map +1 -1
  401. package/dist/commands/webdav/get.d.ts +1 -0
  402. package/dist/commands/webdav/mkdir.d.ts +2 -0
  403. package/dist/commands/webdav/mkdir.js +5 -3
  404. package/dist/commands/webdav/mkdir.js.map +1 -1
  405. package/dist/commands/webdav/put.d.ts +2 -0
  406. package/dist/commands/webdav/put.js +5 -3
  407. package/dist/commands/webdav/put.js.map +1 -1
  408. package/dist/commands/webdav/rm.d.ts +1 -0
  409. package/dist/help.d.ts +25 -0
  410. package/dist/help.js +96 -0
  411. package/dist/help.js.map +1 -0
  412. package/dist/lib/scaffold/generate-helper.js +3 -2
  413. package/dist/lib/scaffold/generate-helper.js.map +1 -1
  414. package/dist/lib/skills.d.ts +19 -0
  415. package/dist/lib/skills.js +75 -0
  416. package/dist/lib/skills.js.map +1 -0
  417. package/dist/utils/cip/command.d.ts +1 -0
  418. package/dist/utils/ecdn/zone-command.d.ts +1 -0
  419. package/dist/utils/slas/client.d.ts +1 -0
  420. package/oclif.manifest.json +10994 -7653
  421. package/package.json +11 -5
@@ -0,0 +1,103 @@
1
+ ---
2
+ name: sfnext-accessibility
3
+ description: >-
4
+ Build and fix accessible UI in a Storefront Next storefront (WCAG 2.1 AA): jsx-a11y lint findings, missing accessible names and labels, form error association, dialog focus management, aria-live status messages, keyboard behavior, color contrast, and verifying fixes with Storybook a11y/play() tests and the e2e axe scan with its baseline. Use for "accessibility", "a11y", "WCAG", "screen reader", "aria-label", "focus trap", "axe violation", pnpm lint:a11y, pnpm a11y, a11y-baseline.json, skip-a11y, STORYBOOK_A11Y_TEST_MODE, or an accessibility audit finding to fix. Do not use for general lint/typecheck gates (use `storefront-next:sfnext-quality-gates`), writing non-accessibility tests (use `storefront-next:sfnext-testing`), or color/token design (use `storefront-next:sfnext-theming`).
5
+ ---
6
+
7
+ # Storefront Next Accessibility
8
+
9
+ Target: WCAG 2.1 AA. Accessibility is checked at three levels, cheapest first:
10
+
11
+ | Level | Tool | Catches |
12
+ |-------|------|---------|
13
+ | Lint | OxLint `jsx-a11y` (`pnpm lint`, `pnpm lint:a11y`) | Missing alt/labels, invalid ARIA, non-interactive handlers, ambiguous link text |
14
+ | Component | Storybook a11y addon (axe) and `play()` assertions | Contrast and name/role issues in a rendered state; focus, live regions, dialog behavior |
15
+ | Page | e2e axe scan (`pnpm a11y`) against `e2e/a11y-baseline.json` | Page composition, layout, mobile vs desktop |
16
+
17
+ Some things no scanner finds: focus order, meaning carried by color alone, 200%/400% zoom reflow, and what a screen reader actually announces. Those need keyboard testing, a story `play()` assertion of the DOM facts behind them, or a human with assistive technology.
18
+
19
+ ## Author accessibly by default
20
+
21
+ 1. Use the project's building blocks; they are already accessible in the general case:
22
+ - Radix-based primitives in `src/components/ui/` (dialog, dropdown-menu, sheet, tooltip, ...).
23
+ - `FormLabel`/`FormControl`/`FormMessage` from `@/components/ui/form` and the wrappers in `src/components/form-fields/` (they wire `aria-describedby` and invalid state from form context).
24
+ - `src/components/product-image` and `src/components/dynamic-image` (alt text), `src/components/radio-card` (grouped options), `src/components/skip-link.tsx` (first focusable element, targets `#main-content`), `src/components/announcement-banner`.
25
+ 2. Icon-only controls need a translated accessible name: `<Button aria-label={t('close')}>`. Decorative icons get `aria-hidden="true"` and must not be focusable.
26
+ 3. Every input needs a real label; errors must be programmatically associated and announced (form-field wrappers do this).
27
+ 4. Use semantic elements first (`button`, `a`, `ul`, `h1..h6`); add ARIA only to fill gaps. Keep one `h1` per page and do not skip levels.
28
+ 5. Status changes that happen without navigation (cart updates, promo applied, errors) need an `aria-live` region (`role="status"` or `role="alert"`); the message must be rendered into an existing live region or the region must exist before content changes.
29
+ 6. Dialogs and drawers: focus moves in on open, is trapped, returns to the trigger on close, `Escape` closes. Use the Radix dialog primitives rather than hand-rolling.
30
+ 7. Respect `prefers-reduced-motion` (see `src/components/fade-through-image` and `product-zoom-modal` for the pattern).
31
+ 8. Keep visible focus styles; do not remove outlines without a replacement from the theme tokens.
32
+ 9. Do not "fix" `role="list"` on a `ul`: it is deliberate (Tailwind's `list-style: none` removes list semantics in Safari + VoiceOver), and the lint config allows it.
33
+
34
+ ## Fix the right layer
35
+
36
+ Before editing a shared primitive, check the call site.
37
+
38
+ - Call-site fix (most common): the primitive is correct but the caller passed no `aria-label`, a meaningless `alt`, or bypassed `FormLabel`. Fix the caller.
39
+ - Primitive fix: the shared component itself emits inaccessible markup. One change cascades to every usage, so keep it small and re-run the component's stories and snapshots.
40
+ - Many findings citing one primitive usually means one call-site pattern to correct, not a broken primitive.
41
+
42
+ ## Reproduce, fix, confirm
43
+
44
+ Do not call something fixed from reading code. Capture a failing signal first, then the same check passing afterwards.
45
+
46
+ 1. Name the state: default, form-error, modal-open, out-of-stock, focus-after-action, zoomed. Many violations only exist after interaction, which is why default-page scans come back clean.
47
+ 2. Reproduce:
48
+ - Lint rule: `pnpm lint:a11y`.
49
+ - Rendered axe rule: run the story with `STORYBOOK_A11Y_TEST_MODE=error` via `pnpm storybook:test --type=a11y`, or add the scenario to the e2e a11y specs.
50
+ - Focus/label/live-region issues: write a `play()` assertion (next section) and watch it fail.
51
+ 3. Fix at the right layer.
52
+ 4. Re-run the same check; also run the component's snapshot (`pnpm storybook:test --type=snapshot`, `--update` only after reviewing the diff) and `pnpm lint`.
53
+ 5. Never add a suppression (disabled axe rule, `oxlint-disable`, `aria-hidden`) just to turn a check green. A suppression is acceptable only when it targets a node you do not control and the reason is written next to it.
54
+
55
+ ## Storybook: a11y addon and play() assertions
56
+
57
+ - Default addon mode is `todo` (violations are shown, not failing). `pnpm storybook:test --type=a11y` runs in error mode, so violations fail. `STORYBOOK_DISABLE_A11Y=true` turns it off.
58
+ - Opt one story file into strict mode: spread `{ a11y: { test: 'error' } }` into `parameters` (see `src/components/checkout/storybook/checkout-strict-a11y-parameters.ts`).
59
+ - Tag `skip-a11y` excludes a story from a11y runs. Use it rarely and comment why.
60
+ - Assert accessible outcomes, not CSS classes:
61
+
62
+ ```tsx
63
+ play: async ({ canvasElement }) => {
64
+ await waitForStorybookReady(canvasElement);
65
+ const body = within(canvasElement.ownerDocument.body); // Radix portals render into <body>
66
+ const dialog = body.getByRole('dialog');
67
+ await expect(dialog).toBeInTheDocument();
68
+ await expect(body.getAllByRole('textbox')[0]).toHaveFocus();
69
+ await expect(body.getByRole('textbox', { name: /email/i })).toBeInTheDocument(); // label association
70
+ await expect(body.getByRole('status')).toHaveTextContent(/saved/i); // live region populated
71
+ },
72
+ ```
73
+
74
+ A working reference is `src/components/login/stories/otp-modal.stories.tsx`. Imports: `expect, within, userEvent` from `storybook/test`; `waitForStorybookReady` from `@storybook/test-utils`. Tag the story `interaction` so it runs under `--type=interaction`.
75
+
76
+ ## e2e axe scan and baseline
77
+
78
+ `pnpm a11y` runs axe (WCAG 2.1 A/AA tags) over key pages at desktop and mobile viewports and compares with `e2e/a11y-baseline.json`. CI fails when critical or serious violations increase or a new critical/serious rule appears; moderate and minor regressions are logged but do not block.
79
+
80
+ ```bash
81
+ pnpm a11y # scan and compare with baseline
82
+ pnpm --dir e2e a11y:report # or from e2e/: markdown + HTML report of violations
83
+ pnpm --dir e2e a11y:update-baseline # after fixing: ratchet the baseline down, review the diff, commit
84
+ pnpm a11y:scan-coverage # checks that every page route is scanned or explicitly allowlisted
85
+ ```
86
+
87
+ - Never hand-edit the baseline; regenerate it.
88
+ - New pages: add a `Scenario` in `e2e/src/specs/core/a11y/` (public, account or orders spec), then run `a11y:update-baseline`. Details: `e2e/docs/a11y.md`.
89
+ - The dev server must be running (`pnpm dev`) or use `--mode=local` as described in `storefront-next:sfnext-testing`.
90
+
91
+ ## Translated text
92
+
93
+ `jsx-a11y/anchor-ambiguous-text` only sees literal JSX text. A link whose text comes from `t('...')` is never checked, so review link and label copy in `src/locales/*/translations.json` for "click here"/"read more" style text, in every locale you ship. See `storefront-next:sfnext-i18n`.
94
+
95
+ More checklists (states, keyboard, pages to spot check): [references/checklist.md](references/checklist.md).
96
+
97
+ ## Related Skills
98
+
99
+ - `storefront-next:sfnext-quality-gates` - lint config and pre-PR checklist
100
+ - `storefront-next:sfnext-testing` - story, unit and e2e test mechanics
101
+ - `storefront-next:sfnext-components` - component and form-field conventions
102
+ - `storefront-next:sfnext-theming` - color tokens and contrast
103
+ - `storefront-next:sfnext-i18n` - translated labels and link text
@@ -0,0 +1,64 @@
1
+ # Accessibility checklists
2
+
3
+ ## Classify a finding
4
+
5
+ | Question | If yes |
6
+ |----------|--------|
7
+ | Is there a DOM fact a scanner or assertion can check (missing name, unlabeled input, empty live region, `aria-hidden` on focusable, duplicate id, empty heading, contrast)? | Automatable. Reproduce with axe (story a11y run or e2e scan) and fix. |
8
+ | Is it about focus landing in the right place, roving arrow keys, trap/return, live region populated? | Has a DOM correlate. Assert it in a story `play()`. |
9
+ | Is it reading order, meaning conveyed by color alone, zoom/reflow at 200% to 400%, or exactly what VoiceOver/NVDA speaks? | Manual. Test with the keyboard, browser zoom and a screen reader; record the result. Do not close it as "cannot reproduce" because a scanner is clean. |
10
+
11
+ For "status message is not announced": if a live region should exist in the DOM, it is assertable; if the claim is purely about speech output, test with assistive technology.
12
+
13
+ ## States to exercise
14
+
15
+ Scan or assert in each relevant state, not only the settled default:
16
+
17
+ - default
18
+ - form-error (submit empty or invalid)
19
+ - modal, drawer or menu open
20
+ - out-of-stock / unavailable variant
21
+ - after an action (focus after add-to-cart, after closing a dialog)
22
+ - zoomed to 400% / narrow viewport
23
+ - mobile and desktop viewports
24
+ - reduced motion enabled
25
+
26
+ Prefer states that do not depend on live catalog data for repeatable checks; data-dependent states (out-of-stock, specific content) can differ between local and CI backends.
27
+
28
+ ## Keyboard pass (per page or component)
29
+
30
+ - Tab order follows the visual order; nothing focusable is hidden; a visible focus indicator is always present.
31
+ - All controls operable with Enter/Space; menus, tabs, carousels and swatch groups support arrow keys as expected.
32
+ - `Escape` closes dialogs and popovers; focus returns to the trigger.
33
+ - No keyboard trap outside intentional modal containment.
34
+ - The skip link is the first Tab stop and moves focus to `#main-content`.
35
+
36
+ ## Forms
37
+
38
+ - Each field has a visible label associated through `FormLabel` or `htmlFor`.
39
+ - Error text is associated (`aria-describedby`) and the field is `aria-invalid`; on a failed submit, move focus to the first invalid field or an error summary (verify the behavior of the form you are editing).
40
+ - Required state is conveyed in text, not color alone.
41
+ - Autocomplete attributes are set for address, email and payment fields.
42
+
43
+ ## Images and media
44
+
45
+ - Product and content images use `ProductImage`/`DynamicImage` with meaningful alt text; decorative images use empty alt.
46
+ - Icon-only buttons have translated accessible names.
47
+ - Carousels: labelled region, pause/controls reachable by keyboard, reduced motion respected.
48
+
49
+ ## Content and structure
50
+
51
+ - One `h1` per page; headings in order.
52
+ - Landmarks (`header`, `nav`, `main`, `footer`) present once each with labels where repeated.
53
+ - Link text makes sense out of context, in every locale.
54
+ - Lists use list markup; keep `role="list"` on styled `ul` (Safari + VoiceOver).
55
+
56
+ ## Where to run what
57
+
58
+ | Goal | Command |
59
+ |------|---------|
60
+ | Lint-level a11y only | `pnpm lint:a11y` |
61
+ | Rendered component violations | `pnpm storybook:test --type=a11y` |
62
+ | Focus/aria behavior | `pnpm storybook:test --type=interaction` |
63
+ | Full-page scan vs baseline | `pnpm a11y` |
64
+ | Report with HTML snippets for tickets | `pnpm --dir e2e a11y:report` |
@@ -0,0 +1,91 @@
1
+ ---
2
+ name: sfnext-analytics-consent
3
+ description: >-
4
+ Storefront Next analytics: engagement adapters (Einstein, Active Data, Data 360), adding a custom adapter, tracking consent gating, PageViewTracker, useAnalytics events, and first-touch attribution (dw_attribution). Use when configuring engagement.adapters in config.server.ts, writing an adapter with hasConsent, registering it in initializeEngagementAdapters, wiring the consent banner (trackingConsent, consentCategories, dw_dnt), firing trackViewProduct/trackCartItemAdd events, debugging why no analytics events are sent, or passing campaign attribution to orders. Do not use for general config loading or env vars (use `storefront-next:sfnext-configuration`), CSP/script allowlisting of third-party tags (use `storefront-next:sfnext-security`), or SEO meta/JSON-LD (use `storefront-next:sfnext-seo`).
5
+ ---
6
+
7
+ # Storefront Next Analytics and Consent
8
+
9
+ Events flow: component -> `useAnalytics()` -> event mediator (`@salesforce/storefront-next-runtime/events`) -> each registered engagement adapter. Every adapter checks shopper consent before sending. Read `docs/README-ADAPTER-PATTERN-GUIDE.md` and `docs/README-CONSENT-TRACKING.md` in your project for the full guides; where they disagree with the code, trust the code (paths below were verified).
10
+
11
+ ## Where things live
12
+
13
+ | Concern | Location |
14
+ |---|---|
15
+ | Adapter config | `engagement.adapters.*` in `config.server.ts` |
16
+ | Adapter types, store, `hasConsent`, `buildConsentPreferences` | `@/lib/adapters` (`src/lib/adapters/engagement/`) |
17
+ | Registration of built-in adapters | `src/lib/adapters/engagement/register.ts` (`initializeEngagementAdapters`) |
18
+ | Built-in adapters | `einstein.ts`, `active-data.ts`, `data360.ts` in the same folder |
19
+ | Page view tracking | `src/analytics/page-view-tracker.tsx` (`PageViewTracker`, mounted in `src/root.tsx`) |
20
+ | Event hooks | `@/hooks/use-analytics`, `@/hooks/use-tracking-consent` |
21
+ | Attribution | `src/lib/attribution.ts`, `@/hooks/use-attribution`, `src/middlewares/attribution-forwarding.server.ts` |
22
+
23
+ ## Configure built-in adapters
24
+
25
+ ```ts
26
+ // config.server.ts
27
+ engagement: {
28
+ adapters: {
29
+ einstein: { enabled: true, consentCategory: 'analytics', host, einsteinId, realm, siteId, isProduction: false,
30
+ eventToggles: { view_page: true, view_product: true /* ... */ } },
31
+ data360: { enabled: true, consentCategory: 'analytics', appSourceId, tenantId, siteId, webStoreId: 'sfnext', eventToggles: { /* ... */ } },
32
+ activeData: { enabled: true, /* see config.server.ts */ },
33
+ },
34
+ analytics: {
35
+ trackingConsent: { enabled: true, defaultTrackingConsent: TrackingConsent.Declined,
36
+ consentCategories: ['necessary', 'analytics', 'marketing', 'personalization'] },
37
+ pageViewsBlocklist: [/* paths that must not emit view_page */],
38
+ },
39
+ }
40
+ ```
41
+
42
+ - The shipped IDs (einsteinId, realm, tenantId, ...) are sample values. Replace them with your own before go-live, or set `enabled: false`.
43
+ - An adapter with `consentCategory: 'analytics'` sends nothing unless `'analytics'` is in `trackingConsent.consentCategories`.
44
+ - `eventToggles` turns individual event types on or off per adapter. Data 360 ships only view/impression events enabled.
45
+ - The `einstein` and `data360` adapter blocks, and `activeData.enabled` / `activeData.eventToggles`, are protected config paths and cannot be overridden with `PUBLIC__` env vars; edit `config.server.ts` and rebuild. Other keys follow the `PUBLIC__app__engagement__...` pattern (see `storefront-next:sfnext-configuration`).
46
+
47
+ ## Fire events
48
+
49
+ ```tsx
50
+ import { useAnalytics } from '@/hooks/use-analytics';
51
+
52
+ const { trackViewProduct, trackCartItemAdd } = useAnalytics();
53
+ ```
54
+
55
+ `useAnalytics` returns `trackViewPage`, `trackViewProduct`, `trackCartItemAdd`, `trackCheckoutStart`, `trackCheckoutStep`, `trackViewSearch`, `trackViewCategory`, `trackClickProductIn{Category,Search,Recommender}`, `trackViewRecommender`, search-suggestion and wishlist trackers. On the server these are no-ops, so call them from effects or event handlers. Check the hook source for exact argument shapes before calling.
56
+
57
+ ## Consent
58
+
59
+ Consent is read from the auth session (`dw_dnt` cookie) by `useTrackingConsent()`, converted to a `ConsentPreferences` array by `buildConsentPreferences(trackingConsent, consentCategories, isTrackingConsentEnabled)`, and passed to every adapter. While consent is undetermined or declined, no events are sent.
60
+
61
+ ```tsx
62
+ import { useTrackingConsent } from '@/hooks/use-tracking-consent';
63
+ import { TrackingConsent } from '@/types/tracking-consent';
64
+
65
+ const { shouldShowBanner, setTrackingConsent } = useTrackingConsent();
66
+ setTrackingConsent(TrackingConsent.Accepted);
67
+ ```
68
+
69
+ Granular per-category consent (for example from a CMP) means replacing the binary banner logic that feeds `buildConsentPreferences`; adapters already gate per `consentCategory`.
70
+
71
+ ## Add a custom adapter
72
+
73
+ See [references/CUSTOM-ADAPTER.md](references/CUSTOM-ADAPTER.md). In short: implement `createMyAdapter(config): EngagementAdapter` using `hasConsent`, register it with `addAdapter('my-adapter', ...)` inside `initializeEngagementAdapters`, and add `engagement.adapters.myAdapter` config (the config type allows extra keys).
74
+
75
+ ## Attribution
76
+
77
+ A first-touch `dw_attribution` cookie captures allow-listed landing/referrer params (see `LANDING_PARAM_ALLOWLIST` in `src/lib/attribution.ts`). `attributionForwardingMiddleware` forwards it on order creation. Add a parameter by extending the allowlist; cookie size is capped (`MAX_ATTRIBUTION_COOKIE_VALUE_LENGTH`).
78
+
79
+ ## Troubleshooting
80
+
81
+ - No events at all: consent not accepted, `'analytics'` missing from `consentCategories`, adapter `enabled: false`, or the path is in `pageViewsBlocklist`. Startup logs a warning when consent categories are empty.
82
+ - Custom adapter never fires: it was not registered in `initializeEngagementAdapters`, or `eventToggles[eventType]` is falsy.
83
+ - Third-party script or beacon blocked: CSP, see `storefront-next:sfnext-security`.
84
+
85
+ ## Related Skills
86
+
87
+ - `storefront-next:sfnext-configuration` - config.server.ts, env overrides
88
+ - `storefront-next:sfnext-security` - CSP for analytics endpoints
89
+ - `storefront-next:sfnext-authentication` - session/cookies behind `dw_dnt`
90
+ - `storefront-next:sfnext-testing` - testing adapters and hooks
91
+ - `storefront-next:sfnext-seo` - page metadata and structured data
@@ -0,0 +1,49 @@
1
+ # Writing a custom engagement adapter
2
+
3
+ Verify the types in `src/lib/adapters/engagement/types.ts` in your project first.
4
+
5
+ ## 1. Implement
6
+
7
+ ```ts
8
+ // src/lib/adapters/engagement/my-adapter.ts
9
+ import { hasConsent, type EngagementAdapter, type EngagementAdapterConfig } from '@/lib/adapters';
10
+ import type { AnalyticsEvent, ConsentPreferences, EventSiteInfo } from '@salesforce/storefront-next-runtime/events';
11
+
12
+ export function createMyAdapter(config: EngagementAdapterConfig): EngagementAdapter {
13
+ return {
14
+ name: 'my-adapter',
15
+ sendEvent: async (event: AnalyticsEvent, siteInfo?: EventSiteInfo, consentPreferences?: ConsentPreferences) => {
16
+ if (!hasConsent(config.consentCategory, consentPreferences)) return;
17
+ if (!config.eventToggles[event.eventType]) return;
18
+ navigator.sendBeacon('https://example.com/collect', JSON.stringify({ event, siteInfo }));
19
+ },
20
+ };
21
+ }
22
+ ```
23
+
24
+ `hasConsent(category, prefs)` is in `src/lib/adapters/engagement/utils.ts`; read it for the behavior when `category` is undefined.
25
+
26
+ ## 2. Register
27
+
28
+ In `src/lib/adapters/engagement/register.ts`, inside `initializeEngagementAdapters(appConfig)`:
29
+
30
+ ```ts
31
+ const mine = appConfig?.engagement?.adapters?.myAdapter;
32
+ if (mine?.enabled) {
33
+ addAdapter('my-adapter', createMyAdapter({ consentCategory: mine.consentCategory, eventToggles: mine.eventToggles || {}, ...mine }));
34
+ }
35
+ ```
36
+
37
+ Follow the try/catch and logger pattern used for the built-in adapters.
38
+
39
+ ## 3. Configure
40
+
41
+ Add `engagement.adapters.myAdapter: { enabled: true, consentCategory: 'marketing', eventToggles: { view_page: true } }` in `config.server.ts`. Add `'marketing'` (or your category) to `trackingConsent.consentCategories`.
42
+
43
+ ## 4. Allow the endpoint in CSP
44
+
45
+ Beacons to a new host need `connect-src` (and script hosts need `script-src`). See `storefront-next:sfnext-security`.
46
+
47
+ ## 5. Test
48
+
49
+ Unit-test the adapter with and without consent (see the `*.test.ts` files beside the built-in adapters for the pattern).
@@ -0,0 +1,127 @@
1
+ ---
2
+ name: sfnext-authentication
3
+ description: >-
4
+ Work with Storefront Next's server-only authentication and session architecture (SLAS guest/registered tokens, httpOnly cookies, auth.server.ts middleware). Use for getAuth, useAuth, updateAuth, destroyAuth, protecting account routes, login/logout actions, guest-to-registered basket/wishlist merge, "session expired" redirects, 401 recovery loops, cc-at/cc-nx/usid/dwsid cookies, cookie names or expiry, passwordless login, social login, OTP email verification, passkeys, guest order lookup, or refresh-token lifetime settings. Do not use for Turnstile, CSP headers or cookie-domain config (use `storefront-next:sfnext-security`), calling SCAPI clients (use `storefront-next:sfnext-scapi`), or sharing sessions with SFRA (use `storefront-next:sfnext-hybrid-storefronts`).
5
+ ---
6
+
7
+ # Storefront Next Authentication
8
+
9
+ Authentication is **server-only**. One middleware (`src/middlewares/auth.server.ts`, registered in the `middleware` array of `src/root.tsx`) runs on every request: it reads cookies, validates or refreshes the SLAS access token, performs a guest login when nothing usable exists, and writes `Set-Cookie`. Tokens never reach the browser. Components only see a small non-sensitive slice through `useAuth()`.
10
+
11
+ Read `docs/README-AUTH.md` in your project for the full reference; this skill is the task-oriented summary. Route modules use server `loader`/`action` only, never `clientLoader`/`clientAction`.
12
+
13
+ ## Request flow
14
+
15
+ 1. Valid access token (JWT `exp` in the future): use it.
16
+ 2. Expired access token with a refresh token: refresh, rewrite `cc-at`.
17
+ 3. No tokens: guest login.
18
+ 4. Registered shopper whose refresh fails: 307 to `/login?returnUrl=<path>&error=session_expired` (site/locale prefix included) and a fresh guest session is created in parallel. Guests are silently re-issued a guest session.
19
+ 5. A SCAPI call returning 401 throws `AuthTokenInvalidError`; the middleware clears state, re-runs login/refresh and 307-redirects to the same URL. The short-lived `cc-auth-recover` cookie (30 s) prevents loops.
20
+
21
+ User type comes from the access-token JWT (registered tokens carry an `rcid` claim), not from which cookie exists. `customerId` is **not** a cookie; it is derived per request from the JWT.
22
+
23
+ ## Read auth on the server
24
+
25
+ ```typescript
26
+ import { getAuth } from '@/middlewares/auth.server';
27
+ import type { LoaderFunctionArgs } from 'react-router';
28
+
29
+ export async function loader({ context }: LoaderFunctionArgs) {
30
+ const auth = getAuth(context); // full SessionData, server only
31
+ const isRegistered = auth.userType === 'registered';
32
+ return { isRegistered }; // never return auth.accessToken / refreshToken
33
+ }
34
+ ```
35
+
36
+ ## Read auth in components
37
+
38
+ ```tsx
39
+ import { useAuth } from '@/providers/auth';
40
+
41
+ function AccountBadge() {
42
+ const auth = useAuth(); // PublicSessionData | undefined
43
+ return auth?.userType === 'registered' ? <span>Welcome back</span> : <SignInLink />;
44
+ }
45
+ ```
46
+
47
+ `PublicSessionData` is exactly `customerId`, `userType`, `usid`, `encUserId`, `trackingConsent`. The root loader derives it with `getPublicSessionData` (from `@/middlewares/auth.utils`) and passes it to `AuthProvider`; there is no client `getAuth`.
48
+
49
+ ## Protect a route
50
+
51
+ Branch inside the server loader. Prefer the existing account layout (`src/routes/_app.account.tsx`) for anything under `/account` instead of adding per-route checks.
52
+
53
+ ```typescript
54
+ import { redirect } from 'react-router';
55
+ import { getAuth } from '@/middlewares/auth.server';
56
+ import { buildUrlFromContext } from '@/lib/url.server';
57
+ import { routes } from '@/route-paths';
58
+
59
+ export async function loader({ context }: LoaderFunctionArgs) {
60
+ if (getAuth(context).userType !== 'registered') {
61
+ throw redirect(buildUrlFromContext(routes.login, context)); // keeps site/locale prefix
62
+ }
63
+ // ...
64
+ }
65
+ ```
66
+
67
+ ## Log in and out
68
+
69
+ Never write auth cookies yourself. Use the helpers exported from `@/middlewares/auth.server`:
70
+
71
+ ```typescript
72
+ import { loginRegisteredUser, updateAuth } from '@/middlewares/auth.server';
73
+
74
+ export async function action({ request, context }: ActionFunctionArgs) {
75
+ const form = await request.formData();
76
+ const tokens = await loginRegisteredUser(context, String(form.get('email')), String(form.get('password')));
77
+ updateAuth(context, tokens); // re-derives userType/customerId/usid, swaps cc-nx-g for cc-nx
78
+ return redirect('/account');
79
+ }
80
+ ```
81
+
82
+ `updateAuth` accepts a SLAS token response or an updater function (`updateAuth(context, (cur) => ({ ...cur, codeVerifier }))`). Logout: `destroyAuth(context)` clears every auth cookie on the response; the shipped `src/routes/_empty.logout.ts` also calls `clients.auth.logout` and `destroyBasket`. Prefer `src/lib/api/auth/standard-login.server.ts` and `social-login.server.ts` over hand-rolled flows: they already handle the merge below.
83
+
84
+ Other exported helpers: `loginGuestUser`, `refreshAccessToken`, `authorizePasswordless`, `getPasswordLessAccessToken`, `getPasswordResetToken`, `resetPasswordWithToken`, `requestOtp`, `verifyOtp`, `flashAuth(context, message)` (clear session plus an error message), `clearInvalidSessionAndRestoreGuest(context)` (deleted customer or corrupted session).
85
+
86
+ ## Guest to registered merge
87
+
88
+ `customerId` changes from the guest `gcid` to the registered `rcid` at the token swap, and SCAPI rejects the guest id under the registered token. So: snapshot guest-owned data (wishlist) **before** the swap, then `mergeBasket` and `mergeWishlist` **after**. `src/lib/api/auth/social-login.server.ts` is the reference implementation. `dw_dnt` tracking consent is preserved across the swap.
89
+
90
+ ## Common SCAPI calls for account data
91
+
92
+ These are real operations: `clients.shopperCustomers.getCustomerOrders`, `getCustomerProductLists` (wishlists), `getCustomer`. Use the existing helpers (`src/lib/api/order.server.ts`, `wishlist.server.ts`, `customer.server.ts`) rather than calling clients directly. Client setup and the `@/lib/api-clients.server` import are covered in `storefront-next:sfnext-scapi`.
93
+
94
+ ## Configuration
95
+
96
+ | Setting | Where |
97
+ |---|---|
98
+ | Refresh-token lifetime | `PUBLIC_COMMERCE_API_GUEST_REFRESH_TOKEN_EXPIRY_SECONDS` (max 30 days), `PUBLIC_COMMERCE_API_REGISTERED_REFRESH_TOKEN_EXPIRY_SECONDS` (max 90 days) |
99
+ | Feature flags | `features.passwordlessLogin`, `features.passkey`, `features.socialLogin`, `features.otpRequest`, `auth.otpLength` in `config.server.ts` |
100
+ | Private SLAS client | `commerce.api.privateKeyEnabled` (required for passwordless / OTP) |
101
+ | Cookie domain | `app.cookies.domain` (see `storefront-next:sfnext-security`) |
102
+
103
+ `secure` on cookies is only set on deployed (HTTPS) environments; local `pnpm dev` over `http://localhost` writes non-secure cookies so Safari keeps them.
104
+
105
+ ## Pitfalls
106
+
107
+ - Reading tokens with `document.cookie`: impossible by design (httpOnly). Use `useAuth()` or loader data.
108
+ - Returning `getAuth(context)` from a loader leaks tokens into the page. Return only derived values.
109
+ - Refreshing tokens manually in routes: the middleware already does it.
110
+ - Logging `accessToken` or `refreshToken`: never.
111
+ - Changing the cookie domain on a live site leaves old host-only cookies shadowing new ones; roll out in a quiet window.
112
+ - A loop of redirects to `/login?error=session_expired` usually means refresh tokens are being rejected (SLAS client config, or cookie domain mismatch between hosts).
113
+
114
+ ## References
115
+
116
+ - [COOKIES.md](references/COOKIES.md): full cookie inventory, namespacing, expiry, hints.
117
+ - [LOGIN-FLOWS.md](references/LOGIN-FLOWS.md): passwordless, social, OTP, passkeys, password reset, guest order lookup, email cartridge prerequisites.
118
+ - In your project: `docs/README-AUTH.md`, `docs/README-EMAIL-VERIFICATION.md`, `docs/README-GUEST-ORDER-LOOKUP.md`, `docs/README-EMAIL-CARTRIDGE.md`.
119
+
120
+ ## Related Skills
121
+
122
+ - `storefront-next:sfnext-security` - Turnstile bot protection, CSP for social providers, cookie domain
123
+ - `storefront-next:sfnext-scapi` - SCAPI clients and custom APIs
124
+ - `storefront-next:sfnext-hybrid-storefronts` - shared `dwsid` session bridge with SFRA
125
+ - `storefront-next:sfnext-analytics-consent` - `dw_dnt` tracking consent
126
+ - `storefront-next:sfnext-configuration` - `config.server.ts` and `PUBLIC__` overrides
127
+ - `b2c-cli:b2c-slas` - manage SLAS clients and scopes
@@ -0,0 +1,39 @@
1
+ # Storefront Next Auth Cookies
2
+
3
+ Source of truth in your project: `docs/README-AUTH.md` (Cookie Architecture) and the constants in `src/middlewares/auth.utils.ts`. Cookie serialization lives in `src/lib/cookie-utils.server.ts` (`getCookieConfig`, `createCookie`).
4
+
5
+ All auth cookies are `HttpOnly`, so client JavaScript cannot read them. The only exception is `dw_dnt` (the consent banner reads it). The browser still sends every cookie on each request, which is what lets the server middleware and a hybrid B2C Commerce (SFRA) storefront read them.
6
+
7
+ | Cookie | Purpose | User type | Lifetime | Notes |
8
+ |---|---|---|---|---|
9
+ | `cc-nx-g` | Guest refresh token | Guest | Guest refresh expiry (max 30 days) | Mutually exclusive with `cc-nx` |
10
+ | `cc-nx` | Registered refresh token | Registered | Registered refresh expiry (max 90 days) | Written on login; deletes `cc-nx-g` |
11
+ | `cc-at` | Access token | Both | JWT `exp` | Refreshed by middleware |
12
+ | `usid` | SLAS user session id (JWT `sub`) | Both | Refresh expiry, else access expiry | Keep httpOnly; never expose to JS |
13
+ | `enc_user_id` | Encoded user id | Registered | Refresh expiry | Needed for some SLAS calls |
14
+ | `idp_access_token` | Social-login IDP access token | Both | Access expiry | Social login only |
15
+ | `id_token` | OIDC ID token | Both | Access expiry | |
16
+ | `idp_refresh_token` | Social-login IDP refresh token | Both | Refresh expiry | |
17
+ | `dw_dnt` | Tracking consent (value is the `TrackingConsent` enum) | Both | Session | Not httpOnly, not site-namespaced; cookie is the source of truth |
18
+ | `dwsid` | B2C Commerce session id (hybrid bridge) | Both | Session | Not site-namespaced; taken from the SLAS `Set-Cookie` header |
19
+ | `cc-cv` | PKCE code verifier | Both | 5 minutes | Social login flow |
20
+ | `cc-auth-recover` | 401 / session-expiry redirect loop guard | Both | 30 seconds | Set by middleware, cleared on follow-up request |
21
+
22
+ Related non-auth cookies you may see: `cc-tv_<siteId>` (Turnstile attestation, 30 min, see `storefront-next:sfnext-security`), `glo_order_*` / `glo_cd_*` (guest order lookup), site-context cookies for site, locale and currency, a JS-readable `__sfdc_usertype_<siteId>` hint that carries only guest/registered so cached app-shell HTML can restore header state, and a JS-readable basket snapshot cookie. The hint and basket cookies never carry tokens.
23
+
24
+ ## Rules
25
+
26
+ - **Namespacing.** Cookies are suffixed with the site id (for example `cc-nx_RefArch`) so multi-site deployments do not collide. `dwsid` and `dw_dnt` are deliberately excluded (`COOKIE_NAMESPACE_EXCLUSIONS`) so B2C Commerce and external scripts can read them.
27
+ - **No `userType` cookie.** It is derived from the access-token JWT (`rcid` claim means registered). The refresh-cookie name is only a cold-start fallback and a write-time decision about which refresh cookie to set or delete.
28
+ - **No `customerId` cookie.** Derived from the JWT. A legacy `customer_id` cookie is only deleted on logout and error paths.
29
+ - **Value source.** Token strings come from the SLAS token response body; `userType`, `customerId`, `usid`, expiry and consent are decoded from the JWT so they cannot drift from the token. `dwsid` is the exception (SLAS `Set-Cookie`).
30
+ - **Expiry overrides.** `PUBLIC_COMMERCE_API_GUEST_REFRESH_TOKEN_EXPIRY_SECONDS` and `PUBLIC_COMMERCE_API_REGISTERED_REFRESH_TOKEN_EXPIRY_SECONDS` can shorten the refresh lifetime; values above 30 / 90 days are capped.
31
+ - **Defaults.** `path: '/'`, `sameSite: 'lax'`, `secure` only on deployed HTTPS (gated on `isRemote()`); `SameSite=None` cookies used by Page Designer design mode always stay `Secure`. The resolved `app.cookies.domain` (or per-site `commerce.sites[].cookies.domain`) applies to every cookie the storefront writes.
32
+ - **Never write auth cookies directly.** Use `updateAuth` / `destroyAuth`; the middleware owns serialization and deletes cookies with expired `Set-Cookie` headers.
33
+
34
+ ## Debugging checklist
35
+
36
+ 1. DevTools > Application > Cookies: do you see duplicates of the same name (host-only plus domain-scoped)? See cookie-domain rollout notes in `storefront-next:sfnext-security`.
37
+ 2. Login works but does not stick on Safari over `http://localhost`: `secure` cookies are refused; confirm you are on `pnpm dev`/`pnpm preview` (which write non-secure cookies) and not a tunnel or HTTPS proxy with mismatched host.
38
+ 3. Hybrid pages lose the session: confirm `dwsid` is present on both storefronts and the cookie-domain settings agree on both sides.
39
+ 4. Repeated `session_expired` redirects: check the SLAS client's refresh-token settings and that the cookie domain matches the serving host.
@@ -0,0 +1,59 @@
1
+ # Login Flows
2
+
3
+ All flows end in `updateAuth(context, tokenResponse)` from `@/middlewares/auth.server`. Prefer the existing route and library code over new implementations:
4
+
5
+ | Flow | Entry points in your project |
6
+ |---|---|
7
+ | Password login | `src/routes/_empty.login.tsx`, `src/lib/api/auth/standard-login.server.ts` |
8
+ | Registration | `src/routes/_empty.signup.tsx`, `src/lib/api/auth/register.server.ts` |
9
+ | Password reset | `src/routes/_empty.reset-password.tsx`, `action.request-password-reset.ts`, `resource.slas-reset-password-callback.ts`, `src/lib/api/auth/reset-password.server.ts` |
10
+ | Passwordless / OTP | `action.authorize-passwordless-email.ts`, `action.verify-passwordless-otp.ts`, `action.otp-request.ts`, `action.otp-verify.ts`, `resource.slas-passwordless-login-callback.ts`, `src/lib/auth/passwordless-login.server.ts` |
11
+ | Social login | `src/lib/api/auth/social-login.server.ts` |
12
+ | Passkeys | `action.passkey-*.ts`, `resource.passkey-status.ts`, `_app.account.passkeys.tsx`, `src/components/passkeys/`, `src/lib/auth/passkey-support.ts`, `webauthn.ts` |
13
+ | Guest order lookup | `_app.order-lookup.*`, `action.order-lookup-*.ts`, `src/lib/order/` |
14
+
15
+ Auth helpers used by these flows (`authorizePasswordless`, `getPasswordLessAccessToken`, `requestOtp`, `verifyOtp`, `getPasswordResetToken`, `resetPasswordWithToken`, passkey start/finish functions) are exported from `@/middlewares/auth.server`.
16
+
17
+ ## Passwordless (magic link) and OTP
18
+
19
+ - Enable in `config.server.ts` under `features.passwordlessLogin` (`enabled`, `mode: 'email' | 'callback'`, `callbackUri` default `/passwordless-login-callback`, `landingUri` default `/login`). The callback URL must be allowlisted in the SLAS client. The callback route takes no site/locale prefix so one SLAS entry covers all sites.
20
+ - Requires a SLAS **private** client: set `commerce.api.privateKeyEnabled: true`. If it is `false`, passwordless is disabled at runtime regardless of other settings.
21
+ - `features.otpRequest.mode`: `email` (SLAS sends the code; supports email verification) or `callback` (SLAS POSTs the code to your `callbackUri` and you deliver it; no email-verification UI). `auth.otpLength` must be 6 or 8 and match the SLAS client.
22
+ - Email verification UI (verified badge, change email, passwordless registration) turns on with the Business Manager preference **Enable Email Verification** (Site Preferences > Storefront Login Preferences; up to 5 minutes to propagate). Changing login email also needs **Enable Loginid Updates for SCAPI** (request via Salesforce support) and B2C 24.7 or later.
23
+ - Full detail and troubleshooting table: `docs/README-EMAIL-VERIFICATION.md`.
24
+
25
+ ## Email delivery (email cartridge)
26
+
27
+ Magic links, password resets and OTPs are sent by the `app_storefrontnext_base` cartridge's `POST /notify` custom API, called server-side via `clients.sfnextNotify` (`src/lib/notify/notify.server.ts`). One-time setup:
28
+
29
+ 1. `sfnext setup-base-cartridge --slas-client-id <id>` registers the `c_sfnext_notify` scope on the SLAS client (idempotent; needs `SFCC_SHORTCODE`, `SFCC_TENANT_ID` and OAuth client credentials).
30
+ 2. Deploy the cartridge (`pnpm cartridge:deploy --reload`) and add `app_storefrontnext_base` to the site cartridge path.
31
+ 3. Complete the Business Manager steps in `docs/README-EMAIL-CARTRIDGE.md` (storefront host allowlist preference, etc.).
32
+
33
+ To change how mail is sent, customize the cartridge's `sendNotification` helper rather than the storefront. Deploy and endpoint registration checks: `b2c-cli:b2c-code`, `b2c-cli:b2c-scapi-custom`.
34
+
35
+ ## Social login
36
+
37
+ - Enable `features.socialLogin` (`enabled`, `providers`, `callbackUri` default `/social-callback`). Each provider also needs setup in Account Manager / SLAS.
38
+ - Flow is authorization-code with PKCE: generate the challenge, store the verifier via `updateAuth(context, (cur) => ({ ...cur, codeVerifier }))` (lands in httpOnly `cc-cv`, 5 minutes), redirect to the IDP, exchange the code in the callback and call `updateAuth(context, tokenResponse)`.
39
+ - Adding a provider beyond the defaults usually needs CSP changes (`connect-src`, redirect/popup origins): see `storefront-next:sfnext-security`.
40
+ - Guest wishlist/basket must be captured before and merged after the token swap; copy the shape of `social-login.server.ts`.
41
+ - In a hybrid setup add `^/social-callback.*` to `HYBRID_ROUTING_RULES` (see `storefront-next:sfnext-hybrid-storefronts`).
42
+
43
+ ## Passkeys
44
+
45
+ Enable with `features.passkey.enabled`. Registration is authorized by an OTP whose delivery follows `features.passkey.mode` (`email` or `callback`, same allowlisting rules as above). Passkeys are managed on `/account/passkeys`.
46
+
47
+ ## Guest order lookup
48
+
49
+ Lets a guest find an order by order number plus email, confirm a 6-digit access code (valid 15 minutes, fixed by SCAPI) and view a redacted read-only order.
50
+
51
+ - Set `guestOrderLookup.enabled: true` (default `false`). When off, both pages 404 and the actions return `FEATURE_DISABLED`.
52
+ - Set `GUEST_ORDER_LOOKUP_COOKIE_SECRET` (falls back to `CLIENT_SECRET`); without a secret the feature fails closed with `CONFIGURATION_ERROR`.
53
+ - Implement the B2C Commerce hook `sfcc.app.order.sendOrderAccessCode(order, accessCode)` in a cartridge; the storefront never sends this email itself (the shipped email cartridge covers it).
54
+ - `guestOrderLookup.allowedFields` is an allow-list applied to the order before it reaches the browser; `cooldownSeconds` and `orderNumberPattern` tune abuse controls. Turnstile is enforced on the request-code step only (`guestOrderLookup.turnstile`).
55
+ - Full detail: `docs/README-GUEST-ORDER-LOOKUP.md`.
56
+
57
+ ## Bot protection on login
58
+
59
+ The passwordless/OTP email step, checkout registration and order lookup can be gated with Cloudflare Turnstile. Configuration and rollout are in `storefront-next:sfnext-security`.
@@ -0,0 +1,67 @@
1
+ ---
2
+ name: sfnext-commerce-features
3
+ description: >-
4
+ Catalogue and router for optional Storefront Next commerce features: Shopper Context (qualifiers, source codes), Order Management returns/cancel/tracking (SOM/OMS), delivery estimates, feature stubs (@feature-stub), guest order lookup, the app_storefrontnext_base email cartridge, and the shipped extensions (bnpl, bopis, multiship, store-locator, ratings-reviews, customer-preferences, product-content, shipping-delivery, theme-switcher). For each: which flag, SLAS scope, Business Manager setting, cartridge, or extension registry entry it needs, and which in-project doc to read. Use when asked how to enable a feature, why a feature does not render, what prerequisites a feature has, or which stubs are mock data. Do not use for building a new extension (use `storefront-next:sfnext-extensions`), config loading (use `storefront-next:sfnext-configuration`), or SLAS login flows (use `storefront-next:sfnext-authentication`).
5
+ ---
6
+
7
+ # Storefront Next Commerce Features
8
+
9
+ Start with the feature table, then read the named doc in your project's `docs/` folder. Do not assume a feature is live: several ship as UI scaffolds with mock data (see Feature stubs).
10
+
11
+ ## Feature table
12
+
13
+ | Feature | Enable with | Also needs | Read |
14
+ |---|---|---|---|
15
+ | Shopper Context | `features.shopperContext.enabled` (env: `PUBLIC__app__features__shopperContext__enabled=true`), default off | Shopper Context API access for the SLAS client; qualifiers arrive as URL params or via the `useShopperContext` hook, stored in cookies | `docs/README-SHOPPER-CONTEXT.md` |
16
+ | Returns, cancel, tracking (Order Management) | Nothing to toggle | Salesforce Order Management connected to the B2C instance; order loader expands `['oms','oms_shipments']`; without `omsData` only tracking shows | `docs/README-ORDER-MANAGEMENT.md` |
17
+ | Delivery estimates | Keep extension `SFDC_EXT_SHIPPING_DELIVERY` installed | SLAS scopes `sfcc.shopper-delivery-estimates` and `sfcc.shopper-standard`, a delivery-estimate Commerce App bound to `sfcc.app.shipping.estimate`, online products on the site | `docs/README-DELIVERY-ESTIMATES.md` |
18
+ | Guest order lookup | `guestOrderLookup.enabled: true` in `config.server.ts` | `GUEST_ORDER_LOOKUP_COOKIE_SECRET` (or `CLIENT_SECRET` fallback) and a cartridge implementing hook `sfcc.app.order.sendOrderAccessCode` to email the code | `docs/README-GUEST-ORDER-LOOKUP.md` |
19
+ | Email cartridge (`app_storefrontnext_base`) | Deploy cartridge, add to site cartridge path | SLAS scope `c_sfnext_notify` (`sfnext setup-base-cartridge --slas-client-id <id>`), import preference metadata, set `Storefront Hosts` global custom preference, callback mode in storefront config | `docs/README-EMAIL-CARTRIDGE.md` |
20
+ | Feature stubs | n/a | Mock UI scaffolds, not integrations | `docs/README-FEATURE-STUBS.md` |
21
+
22
+ ## Extensions shipped in src/extensions
23
+
24
+ Registry: `src/extensions/config.json` (keys `SFDC_EXT_*`). Each extension contributes components to `UITarget` points through its `target-config.json`. To install or remove one, follow the install/uninstall instructions in `instructions/*.mdc` when the registry entry references them; building new extensions is `storefront-next:sfnext-extensions`.
25
+
26
+ | Extension | Registry key | Notes |
27
+ |---|---|---|
28
+ | Store Locator | `SFDC_EXT_STORE_LOCATOR` | Find stores by location. Guided install/uninstall in `instructions/`. |
29
+ | Multiship | `SFDC_EXT_MULTISHIP` | Ship items to several addresses in one order. Guided install/uninstall. |
30
+ | Buy Online Pickup In Store | `SFDC_EXT_BOPIS` | Depends on Store Locator and Multiship. Guided install/uninstall. |
31
+ | Shipping and Delivery | `SFDC_EXT_SHIPPING_DELIVERY` | Registers `sfcc.pdp.estimatedDelivery`; see delivery estimates row. |
32
+ | Buy Now Pay Later (demo) | `SFDC_EXT_BNPL` | Mock fixtures; `sfcc.pdp.bnpl.message` target. Replace API function bodies to integrate a provider. |
33
+ | Ratings and Reviews (demo) | `SFDC_EXT_RATINGS_REVIEWS` | Mock fixtures for PDP, cart modal, order detail CTA. Integrate Bazaarvoice, PowerReviews, etc. by replacing API bodies. |
34
+ | Product Content (demo) | `SFDC_EXT_PRODUCT_CONTENT` | Returns/warranty card, FAQ, collapsibles (`sfcc.pdp.returnsWarranty`, `sfcc.pdp.faq`, `sfcc.pdp.collapsibles`). Fixtures in `lib/api/product-content.server.ts`. |
35
+ | Customer Preferences (demo) | `SFDC_EXT_CUSTOMER_PREFERENCES` | Interests/preferences on the account page. Mock data. |
36
+ | Theme switcher | none in registry | Folder `src/extensions/theme-switcher` has no registry entry in the shipped project; check your project before relying on it. |
37
+
38
+ Demo extensions are "(Demo)" in `config.json`. Treat them as reference implementations: read the extension `README.md` and replace fixture functions before go-live.
39
+
40
+ ## Feature stubs
41
+
42
+ Working UI with no backend (express checkout buttons, BNPL, returns and warranty, customer interests, and others). Find all of them:
43
+
44
+ ```bash
45
+ grep -r "@feature-stub" src/
46
+ ```
47
+
48
+ Each marker explains how to strip or wire it. Review the list before launch so mock content does not ship.
49
+
50
+ ## Decision flow when "the feature is not showing"
51
+
52
+ 1. Flag off? (`shopperContext`, `guestOrderLookup`) - check `config.server.ts` and env overrides.
53
+ 2. Extension missing from `src/extensions/config.json`, or dependencies not installed (BOPIS needs Store Locator and Multiship)?
54
+ 3. Missing SLAS scope on the shopper client (see `storefront-next:sfnext-authentication`)? Confirm in your SLAS client config, then re-login to get a fresh token.
55
+ 4. Backend not configured: OMS not connected, Commerce App not bound, cartridge not on the site cartridge path.
56
+ 5. Result is mock data: it is a stub.
57
+
58
+ More detail per group: [references/FEATURE-PREREQUISITES.md](references/FEATURE-PREREQUISITES.md).
59
+
60
+ ## Related Skills
61
+
62
+ - `storefront-next:sfnext-extensions` - UITarget, target-config.json, authoring extensions
63
+ - `storefront-next:sfnext-configuration` - feature flags and env overrides
64
+ - `storefront-next:sfnext-authentication` - SLAS scopes and clients
65
+ - `storefront-next:sfnext-scapi` - calling the backing SCAPI endpoints
66
+ - `storefront-next:sfnext-deployment` - deploying cartridges and bundles
67
+ - `b2c-cli:b2c-mrt` - Managed Runtime environment variables