@salesforce/b2c-dx-mcp 3.2.1 → 3.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 (333) hide show
  1. package/bin/run.js +5 -9
  2. package/content/guidance/b2c/b2c-hooks/references/ORDER-HOOK-LIFECYCLE.md +1 -1
  3. package/content/guidance/b2c/b2c-onboarding/SKILL.md +4 -4
  4. package/content/guidance/b2c/b2c-ordering/SKILL.md +2 -2
  5. package/content/guidance/b2c/b2c-querying-data/SKILL.md +2 -2
  6. package/content/guidance/b2c/b2c-scapi-admin/SKILL.md +3 -3
  7. package/content/guidance/b2c/b2c-scapi-admin/references/CLIENT-EXAMPLES.md +4 -4
  8. package/content/guidance/b2c/b2c-scapi-shopper/SKILL.md +6 -6
  9. package/content/guidance/b2c/b2c-scapi-shopper/references/CLIENT-EXAMPLES.md +8 -9
  10. package/content/guidance/b2c-cli/b2c-cip/SKILL.md +3 -3
  11. package/content/guidance/b2c-cli/b2c-cip/references/SALES_ANALYSIS.md +1 -1
  12. package/content/guidance/b2c-cli/b2c-config/SKILL.md +54 -25
  13. package/content/guidance/b2c-cli/b2c-content/SKILL.md +1 -1
  14. package/content/guidance/b2c-cli/b2c-debug/SKILL.md +1 -1
  15. package/content/guidance/b2c-cli/b2c-docs/SKILL.md +23 -2
  16. package/content/guidance/b2c-cli/b2c-ecdn/SKILL.md +2 -0
  17. package/content/guidance/b2c-cli/b2c-ecdn/references/ADVANCED.md +1 -1
  18. package/content/guidance/b2c-cli/b2c-job/SKILL.md +9 -3
  19. package/content/guidance/b2c-cli/b2c-job/references/IMPORT.md +1 -1
  20. package/content/guidance/b2c-cli/b2c-job/references/RUN-AND-MONITOR.md +35 -6
  21. package/content/guidance/b2c-cli/b2c-metrics/SKILL.md +1 -1
  22. package/content/guidance/b2c-cli/b2c-mrt/SKILL.md +3 -3
  23. package/content/guidance/b2c-cli/b2c-scapi-custom/SKILL.md +1 -1
  24. package/content/guidance/b2c-cli/b2c-scapi-schemas/SKILL.md +6 -2
  25. package/content/guidance/b2c-cli/b2c-site-import-export/SKILL.md +1 -1
  26. package/content/guidance/b2c-cli/b2c-sites/SKILL.md +1 -1
  27. package/content/guidance/b2c-cli/b2c-slas/SKILL.md +1 -1
  28. package/content/guidance/b2c-ops/b2c-checkout-triage/SKILL.md +2 -2
  29. package/content/guidance/b2c-ops/b2c-edge-traffic-triage/SKILL.md +69 -0
  30. package/content/guidance/b2c-ops/b2c-job-health/SKILL.md +13 -8
  31. package/content/guidance/b2c-ops/b2c-order-failure-triage/SKILL.md +1 -1
  32. package/content/guidance/b2c-ops/b2c-order-failure-triage/references/order-evidence.md +2 -2
  33. package/content/guidance/b2c-ops/b2c-production-triage/SKILL.md +5 -4
  34. package/content/guidance/index.json +981 -259
  35. package/content/guidance/mcp/{cip → b2c-mcp-cip}/SKILL.md +10 -8
  36. package/content/guidance/mcp/{b2c-config → b2c-mcp-config}/SKILL.md +10 -9
  37. package/content/guidance/mcp/{debugger → b2c-mcp-debugger}/SKILL.md +9 -8
  38. package/content/guidance/mcp/b2c-mcp-scapi/SKILL.md +98 -0
  39. package/content/guidance/mcp/b2c-mcp-scapi/references/authentication.md +34 -0
  40. package/content/guidance/mcp/b2c-mcp-scapi/references/compose-verify.md +25 -0
  41. package/content/guidance/mcp/b2c-mcp-scapi/references/confirmation.md +30 -0
  42. package/content/guidance/mcp/b2c-mcp-scapi/references/discover.md +94 -0
  43. package/content/guidance/mcp/b2c-mcp-scapi/references/jobs.md +72 -0
  44. package/content/guidance/mcp/b2c-mcp-scapi/references/workflows.md +28 -0
  45. package/content/guidance/mcp/{server → b2c-mcp-server}/SKILL.md +52 -25
  46. package/content/guidance/storefront-next/sfnext-accessibility/SKILL.md +103 -0
  47. package/content/guidance/storefront-next/sfnext-accessibility/references/checklist.md +64 -0
  48. package/content/guidance/storefront-next/sfnext-analytics-consent/SKILL.md +91 -0
  49. package/content/guidance/storefront-next/sfnext-analytics-consent/references/CUSTOM-ADAPTER.md +49 -0
  50. package/content/guidance/storefront-next/sfnext-authentication/SKILL.md +86 -79
  51. package/content/guidance/storefront-next/sfnext-authentication/references/COOKIES.md +39 -0
  52. package/content/guidance/storefront-next/sfnext-authentication/references/LOGIN-FLOWS.md +59 -0
  53. package/content/guidance/storefront-next/sfnext-commerce-features/SKILL.md +67 -0
  54. package/content/guidance/storefront-next/sfnext-commerce-features/references/FEATURE-PREREQUISITES.md +37 -0
  55. package/content/guidance/storefront-next/sfnext-components/SKILL.md +98 -136
  56. package/content/guidance/storefront-next/sfnext-components/references/COMPONENT-AUTHORING.md +118 -0
  57. package/content/guidance/storefront-next/sfnext-components/references/SHAPE-TOKENS.md +51 -0
  58. package/content/guidance/storefront-next/sfnext-components/references/STORYBOOK.md +54 -0
  59. package/content/guidance/storefront-next/sfnext-components/references/TOKEN-SYSTEM.md +53 -0
  60. package/content/guidance/storefront-next/sfnext-components/references/TROUBLESHOOTING.md +19 -0
  61. package/content/guidance/storefront-next/sfnext-configuration/SKILL.md +116 -113
  62. package/content/guidance/storefront-next/sfnext-configuration/references/ENV-VARIABLES.md +55 -0
  63. package/content/guidance/storefront-next/sfnext-configuration/references/MULTI-SITE-URLS.md +137 -0
  64. package/content/guidance/storefront-next/sfnext-data-fetching/SKILL.md +100 -150
  65. package/content/guidance/storefront-next/sfnext-data-fetching/references/ACTIONS.md +53 -0
  66. package/content/guidance/storefront-next/sfnext-data-fetching/references/API-CLIENTS.md +34 -0
  67. package/content/guidance/storefront-next/sfnext-data-fetching/references/LOADERS.md +73 -0
  68. package/content/guidance/storefront-next/sfnext-data-fetching/references/SCAPI-FETCHER.md +23 -77
  69. package/content/guidance/storefront-next/sfnext-deployment/SKILL.md +83 -97
  70. package/content/guidance/storefront-next/sfnext-deployment/references/MRT-DEPLOYMENT.md +37 -68
  71. package/content/guidance/storefront-next/sfnext-extensions/SKILL.md +73 -97
  72. package/content/guidance/storefront-next/sfnext-extensions/references/ACTION-HOOKS.md +57 -0
  73. package/content/guidance/storefront-next/sfnext-extensions/references/BASE-AUDIT.md +47 -44
  74. package/content/guidance/storefront-next/sfnext-extensions/references/CLI-AND-INSTALL.md +58 -0
  75. package/content/guidance/storefront-next/sfnext-extensions/references/EXTENSION-EXAMPLES.md +49 -86
  76. package/content/guidance/storefront-next/sfnext-hybrid-storefronts/SKILL.md +59 -114
  77. package/content/guidance/storefront-next/sfnext-hybrid-storefronts/references/HYBRID-PROXY-CONFIG.md +53 -90
  78. package/content/guidance/storefront-next/sfnext-i18n/SKILL.md +96 -131
  79. package/content/guidance/storefront-next/sfnext-i18n/references/locale-config.md +35 -0
  80. package/content/guidance/storefront-next/sfnext-overview/SKILL.md +101 -0
  81. package/content/guidance/storefront-next/sfnext-page-designer/SKILL.md +152 -131
  82. package/content/guidance/storefront-next/sfnext-page-designer/references/BUSINESS-MANAGER.md +46 -0
  83. package/content/guidance/storefront-next/sfnext-page-designer/references/COMPONENT-REGISTRY.md +86 -53
  84. package/content/guidance/storefront-next/sfnext-page-designer/references/DECORATOR-PATTERNS.md +119 -131
  85. package/content/guidance/storefront-next/sfnext-page-designer/references/REVIEW-CHECKLIST.md +83 -0
  86. package/content/guidance/storefront-next/sfnext-page-designer/references/TROUBLESHOOTING.md +35 -0
  87. package/content/guidance/storefront-next/sfnext-performance/SKILL.md +75 -105
  88. package/content/guidance/storefront-next/sfnext-performance/references/PERFORMANCE-REVIEW-CHECKLIST.md +85 -0
  89. package/content/guidance/storefront-next/sfnext-performance/references/SUSPENSE-AND-STREAMING.md +58 -0
  90. package/content/guidance/storefront-next/sfnext-project-setup/SKILL.md +103 -116
  91. package/content/guidance/storefront-next/sfnext-project-setup/references/PROJECT-STRUCTURE.md +61 -99
  92. package/content/guidance/storefront-next/sfnext-project-setup/references/SCRIPTS.md +47 -0
  93. package/content/guidance/storefront-next/sfnext-project-setup/references/SFNEXT-CLI.md +63 -0
  94. package/content/guidance/storefront-next/sfnext-quality-gates/SKILL.md +70 -0
  95. package/content/guidance/storefront-next/sfnext-quality-gates/references/lint-and-budgets.md +39 -0
  96. package/content/guidance/storefront-next/sfnext-revalidation/SKILL.md +121 -0
  97. package/content/guidance/storefront-next/sfnext-revalidation/references/POLICIES-AND-TAGS.md +55 -0
  98. package/content/guidance/storefront-next/sfnext-routing/SKILL.md +86 -143
  99. package/content/guidance/storefront-next/sfnext-routing/references/ROUTE-CONVENTIONS.md +51 -51
  100. package/content/guidance/storefront-next/sfnext-routing/references/URLS-AND-SEO-ROUTES.md +22 -0
  101. package/content/guidance/storefront-next/sfnext-scapi/SKILL.md +126 -0
  102. package/content/guidance/storefront-next/sfnext-scapi/references/WORKED-EXAMPLE.md +39 -0
  103. package/content/guidance/storefront-next/sfnext-security/SKILL.md +129 -0
  104. package/content/guidance/storefront-next/sfnext-security/references/COOKIE-DOMAIN.md +39 -0
  105. package/content/guidance/storefront-next/sfnext-security/references/TURNSTILE.md +43 -0
  106. package/content/guidance/storefront-next/sfnext-seo/SKILL.md +95 -0
  107. package/content/guidance/storefront-next/sfnext-seo/references/MULTI-DOMAIN-BASE-PATH.md +17 -0
  108. package/content/guidance/storefront-next/sfnext-seo/references/SEO-ROUTES.md +31 -0
  109. package/content/guidance/storefront-next/sfnext-state-management/SKILL.md +80 -89
  110. package/content/guidance/storefront-next/sfnext-state-management/references/PATTERNS.md +45 -0
  111. package/content/guidance/storefront-next/sfnext-testing/SKILL.md +105 -138
  112. package/content/guidance/storefront-next/sfnext-testing/references/E2E.md +38 -0
  113. package/content/guidance/storefront-next/sfnext-testing/references/STORYBOOK-PATTERNS.md +73 -94
  114. package/content/guidance/storefront-next/sfnext-testing/references/UNIT-AND-ROUTE-TESTS.md +60 -0
  115. package/content/guidance/storefront-next/sfnext-theming/SKILL.md +104 -0
  116. package/content/guidance/storefront-next/sfnext-theming/references/REBRAND-CHECKLIST.md +29 -0
  117. package/dist/commands/mcp.d.ts +8 -2
  118. package/dist/commands/mcp.js +54 -20
  119. package/dist/guidance.d.ts +4 -1
  120. package/dist/guidance.js +23 -5
  121. package/dist/registry.d.ts +2 -1
  122. package/dist/registry.js +3 -3
  123. package/dist/server.d.ts +10 -0
  124. package/dist/server.js +21 -0
  125. package/dist/skill-references.js +5 -5
  126. package/dist/tools/cartridges/index.js +1 -0
  127. package/dist/tools/cip/index.js +6 -3
  128. package/dist/tools/diagnostics/debug-capture-at-breakpoint.js +1 -1
  129. package/dist/tools/diagnostics/debug-set-breakpoints.js +1 -1
  130. package/dist/tools/diagnostics/debug-start-session.js +1 -1
  131. package/dist/tools/docs/docs-read.js +4 -2
  132. package/dist/tools/docs/docs-search.js +10 -8
  133. package/dist/tools/docs/topics.d.ts +5 -0
  134. package/dist/tools/docs/topics.js +5 -0
  135. package/dist/tools/scapi/index.d.ts +4 -1
  136. package/dist/tools/scapi/index.js +4 -2
  137. package/dist/tools/scapi/scapi-code.d.ts +2 -2
  138. package/dist/tools/scapi/scapi-code.js +106 -81
  139. package/dist/tools/scapi/scapi-schemas-list.js +93 -56
  140. package/dist/utils/types.d.ts +6 -0
  141. package/node_modules/@salesforce/b2c-agent-plugins/CHANGELOG.md +32 -0
  142. package/node_modules/@salesforce/b2c-agent-plugins/README.md +5 -0
  143. package/node_modules/@salesforce/b2c-agent-plugins/b2c/.codex-plugin/plugin.json +1 -1
  144. package/node_modules/@salesforce/b2c-agent-plugins/b2c/plugin.json +1 -1
  145. package/node_modules/@salesforce/b2c-agent-plugins/b2c/skills/b2c-hooks/references/ORDER-HOOK-LIFECYCLE.md +1 -1
  146. package/node_modules/@salesforce/b2c-agent-plugins/b2c/skills/b2c-onboarding/SKILL.md +4 -4
  147. package/node_modules/@salesforce/b2c-agent-plugins/b2c/skills/b2c-ordering/SKILL.md +2 -2
  148. package/node_modules/@salesforce/b2c-agent-plugins/b2c/skills/b2c-querying-data/SKILL.md +2 -2
  149. package/node_modules/@salesforce/b2c-agent-plugins/b2c/skills/b2c-scapi-admin/SKILL.md +3 -3
  150. package/node_modules/@salesforce/b2c-agent-plugins/b2c/skills/b2c-scapi-admin/references/CLIENT-EXAMPLES.md +4 -4
  151. package/node_modules/@salesforce/b2c-agent-plugins/b2c/skills/b2c-scapi-shopper/SKILL.md +6 -6
  152. package/node_modules/@salesforce/b2c-agent-plugins/b2c/skills/b2c-scapi-shopper/references/CLIENT-EXAMPLES.md +8 -9
  153. package/node_modules/@salesforce/b2c-agent-plugins/b2c-cli/.codex-plugin/plugin.json +1 -1
  154. package/node_modules/@salesforce/b2c-agent-plugins/b2c-cli/plugin.json +1 -1
  155. package/node_modules/@salesforce/b2c-agent-plugins/b2c-cli/skills/b2c-cip/SKILL.md +3 -3
  156. package/node_modules/@salesforce/b2c-agent-plugins/b2c-cli/skills/b2c-cip/references/SALES_ANALYSIS.md +1 -1
  157. package/node_modules/@salesforce/b2c-agent-plugins/b2c-cli/skills/b2c-config/SKILL.md +54 -25
  158. package/node_modules/@salesforce/b2c-agent-plugins/b2c-cli/skills/b2c-content/SKILL.md +1 -1
  159. package/node_modules/@salesforce/b2c-agent-plugins/b2c-cli/skills/b2c-debug/SKILL.md +1 -1
  160. package/node_modules/@salesforce/b2c-agent-plugins/b2c-cli/skills/b2c-docs/SKILL.md +23 -2
  161. package/node_modules/@salesforce/b2c-agent-plugins/b2c-cli/skills/b2c-ecdn/SKILL.md +2 -0
  162. package/node_modules/@salesforce/b2c-agent-plugins/b2c-cli/skills/b2c-ecdn/references/ADVANCED.md +1 -1
  163. package/node_modules/@salesforce/b2c-agent-plugins/b2c-cli/skills/b2c-job/SKILL.md +9 -3
  164. package/node_modules/@salesforce/b2c-agent-plugins/b2c-cli/skills/b2c-job/references/IMPORT.md +1 -1
  165. package/node_modules/@salesforce/b2c-agent-plugins/b2c-cli/skills/b2c-job/references/RUN-AND-MONITOR.md +35 -6
  166. package/node_modules/@salesforce/b2c-agent-plugins/b2c-cli/skills/b2c-metrics/SKILL.md +1 -1
  167. package/node_modules/@salesforce/b2c-agent-plugins/b2c-cli/skills/b2c-mrt/SKILL.md +3 -3
  168. package/node_modules/@salesforce/b2c-agent-plugins/b2c-cli/skills/b2c-scapi-custom/SKILL.md +1 -1
  169. package/node_modules/@salesforce/b2c-agent-plugins/b2c-cli/skills/b2c-scapi-schemas/SKILL.md +6 -2
  170. package/node_modules/@salesforce/b2c-agent-plugins/b2c-cli/skills/b2c-site-import-export/SKILL.md +1 -1
  171. package/node_modules/@salesforce/b2c-agent-plugins/b2c-cli/skills/b2c-sites/SKILL.md +1 -1
  172. package/node_modules/@salesforce/b2c-agent-plugins/b2c-cli/skills/b2c-slas/SKILL.md +1 -1
  173. package/node_modules/@salesforce/b2c-agent-plugins/b2c-ops/.codex-plugin/plugin.json +4 -3
  174. package/node_modules/@salesforce/b2c-agent-plugins/b2c-ops/README.md +1 -0
  175. package/node_modules/@salesforce/b2c-agent-plugins/b2c-ops/plugin.json +4 -3
  176. package/node_modules/@salesforce/b2c-agent-plugins/b2c-ops/skills/b2c-checkout-triage/SKILL.md +2 -2
  177. package/node_modules/@salesforce/b2c-agent-plugins/b2c-ops/skills/b2c-edge-traffic-triage/SKILL.md +69 -0
  178. package/node_modules/@salesforce/b2c-agent-plugins/b2c-ops/skills/b2c-job-health/SKILL.md +13 -8
  179. package/node_modules/@salesforce/b2c-agent-plugins/b2c-ops/skills/b2c-order-failure-triage/SKILL.md +1 -1
  180. package/node_modules/@salesforce/b2c-agent-plugins/b2c-ops/skills/b2c-order-failure-triage/references/order-evidence.md +2 -2
  181. package/node_modules/@salesforce/b2c-agent-plugins/b2c-ops/skills/b2c-production-triage/SKILL.md +5 -4
  182. package/node_modules/@salesforce/b2c-agent-plugins/figma-to-sfnext-pagedesigner/README.md +4 -4
  183. package/node_modules/@salesforce/b2c-agent-plugins/figma-to-sfnext-pagedesigner/skills/figma-to-sfnext-pagedesigner/SKILL.md +76 -73
  184. package/node_modules/@salesforce/b2c-agent-plugins/figma-to-sfnext-pagedesigner/skills/figma-to-sfnext-pagedesigner/evals/trigger-evals.json +12 -10
  185. package/node_modules/@salesforce/b2c-agent-plugins/figma-to-sfnext-pagedesigner/skills/figma-to-sfnext-pagedesigner/references/PAGE-DESIGNER-SFN.md +49 -74
  186. package/node_modules/@salesforce/b2c-agent-plugins/package.json +1 -1
  187. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/.codex-plugin/plugin.json +9 -6
  188. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/README.md +43 -22
  189. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/plugin.json +9 -6
  190. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-accessibility/SKILL.md +103 -0
  191. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-accessibility/evals/trigger-evals.json +5 -0
  192. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-accessibility/references/checklist.md +64 -0
  193. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-analytics-consent/SKILL.md +91 -0
  194. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-analytics-consent/evals/trigger-evals.json +5 -0
  195. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-analytics-consent/references/CUSTOM-ADAPTER.md +49 -0
  196. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-authentication/SKILL.md +86 -79
  197. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-authentication/evals/trigger-evals.json +5 -0
  198. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-authentication/references/COOKIES.md +39 -0
  199. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-authentication/references/LOGIN-FLOWS.md +59 -0
  200. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-commerce-features/SKILL.md +67 -0
  201. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-commerce-features/evals/trigger-evals.json +5 -0
  202. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-commerce-features/references/FEATURE-PREREQUISITES.md +37 -0
  203. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-components/SKILL.md +98 -136
  204. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-components/evals/trigger-evals.json +5 -0
  205. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-components/references/COMPONENT-AUTHORING.md +118 -0
  206. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-components/references/SHAPE-TOKENS.md +51 -0
  207. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-components/references/STORYBOOK.md +54 -0
  208. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-components/references/TOKEN-SYSTEM.md +53 -0
  209. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-components/references/TROUBLESHOOTING.md +19 -0
  210. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-configuration/SKILL.md +116 -113
  211. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-configuration/evals/trigger-evals.json +5 -0
  212. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-configuration/references/ENV-VARIABLES.md +55 -0
  213. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-configuration/references/MULTI-SITE-URLS.md +137 -0
  214. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-data-fetching/SKILL.md +100 -150
  215. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-data-fetching/evals/trigger-evals.json +5 -0
  216. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-data-fetching/references/ACTIONS.md +53 -0
  217. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-data-fetching/references/API-CLIENTS.md +34 -0
  218. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-data-fetching/references/LOADERS.md +73 -0
  219. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-data-fetching/references/SCAPI-FETCHER.md +23 -77
  220. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-deployment/SKILL.md +83 -97
  221. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-deployment/evals/trigger-evals.json +5 -0
  222. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-deployment/references/MRT-DEPLOYMENT.md +37 -68
  223. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-extensions/SKILL.md +73 -97
  224. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-extensions/evals/trigger-evals.json +5 -0
  225. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-extensions/references/ACTION-HOOKS.md +57 -0
  226. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-extensions/references/BASE-AUDIT.md +47 -44
  227. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-extensions/references/CLI-AND-INSTALL.md +58 -0
  228. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-extensions/references/EXTENSION-EXAMPLES.md +49 -86
  229. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-hybrid-storefronts/SKILL.md +59 -114
  230. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-hybrid-storefronts/evals/trigger-evals.json +5 -0
  231. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-hybrid-storefronts/references/HYBRID-PROXY-CONFIG.md +53 -90
  232. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-i18n/SKILL.md +96 -131
  233. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-i18n/evals/trigger-evals.json +5 -0
  234. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-i18n/references/locale-config.md +35 -0
  235. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-overview/SKILL.md +101 -0
  236. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-overview/evals/trigger-evals.json +5 -0
  237. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-page-designer/SKILL.md +152 -131
  238. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-page-designer/evals/trigger-evals.json +5 -0
  239. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-page-designer/references/BUSINESS-MANAGER.md +46 -0
  240. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-page-designer/references/COMPONENT-REGISTRY.md +86 -53
  241. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-page-designer/references/DECORATOR-PATTERNS.md +119 -131
  242. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-page-designer/references/REVIEW-CHECKLIST.md +83 -0
  243. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-page-designer/references/TROUBLESHOOTING.md +35 -0
  244. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-performance/SKILL.md +75 -105
  245. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-performance/evals/trigger-evals.json +5 -0
  246. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-performance/references/PERFORMANCE-REVIEW-CHECKLIST.md +85 -0
  247. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-performance/references/SUSPENSE-AND-STREAMING.md +58 -0
  248. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-project-setup/SKILL.md +103 -116
  249. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-project-setup/evals/trigger-evals.json +5 -0
  250. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-project-setup/references/PROJECT-STRUCTURE.md +61 -99
  251. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-project-setup/references/SCRIPTS.md +47 -0
  252. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-project-setup/references/SFNEXT-CLI.md +63 -0
  253. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-quality-gates/SKILL.md +70 -0
  254. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-quality-gates/evals/trigger-evals.json +5 -0
  255. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-quality-gates/references/lint-and-budgets.md +39 -0
  256. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-revalidation/SKILL.md +121 -0
  257. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-revalidation/evals/trigger-evals.json +5 -0
  258. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-revalidation/references/POLICIES-AND-TAGS.md +55 -0
  259. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-routing/SKILL.md +86 -143
  260. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-routing/evals/trigger-evals.json +5 -0
  261. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-routing/references/ROUTE-CONVENTIONS.md +51 -51
  262. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-routing/references/URLS-AND-SEO-ROUTES.md +22 -0
  263. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-scapi/SKILL.md +126 -0
  264. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-scapi/evals/trigger-evals.json +5 -0
  265. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-scapi/references/WORKED-EXAMPLE.md +39 -0
  266. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-security/SKILL.md +129 -0
  267. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-security/evals/trigger-evals.json +5 -0
  268. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-security/references/COOKIE-DOMAIN.md +39 -0
  269. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-security/references/TURNSTILE.md +43 -0
  270. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-seo/SKILL.md +95 -0
  271. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-seo/evals/trigger-evals.json +5 -0
  272. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-seo/references/MULTI-DOMAIN-BASE-PATH.md +17 -0
  273. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-seo/references/SEO-ROUTES.md +31 -0
  274. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-state-management/SKILL.md +80 -89
  275. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-state-management/evals/trigger-evals.json +5 -0
  276. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-state-management/references/PATTERNS.md +45 -0
  277. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-testing/SKILL.md +105 -138
  278. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-testing/evals/trigger-evals.json +5 -0
  279. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-testing/references/E2E.md +38 -0
  280. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-testing/references/STORYBOOK-PATTERNS.md +73 -94
  281. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-testing/references/UNIT-AND-ROUTE-TESTS.md +60 -0
  282. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-theming/SKILL.md +104 -0
  283. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-theming/evals/trigger-evals.json +5 -0
  284. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-theming/references/REBRAND-CHECKLIST.md +29 -0
  285. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next-figma/skills/sfnext-create-figma-kit/SKILL.md +3 -3
  286. package/oclif.manifest.json +21 -4
  287. package/package.json +4 -4
  288. package/content/guidance/mcp/scapi/SKILL.md +0 -203
  289. package/content/guidance/mcp/scapi/references/jobs.md +0 -30
  290. package/content/guidance/storefront-next/sfnext-create-component/SKILL.md +0 -195
  291. package/content/guidance/storefront-next/sfnext-create-component/references/COMPONENT-AUTHORING.md +0 -206
  292. package/content/guidance/storefront-next/sfnext-create-component/references/PROJECT-STRUCTURE.md +0 -43
  293. package/content/guidance/storefront-next/sfnext-create-component/references/TOKEN-SYSTEM.md +0 -130
  294. package/content/guidance/storefront-next/sfnext-create-component/references/TROUBLESHOOTING.md +0 -34
  295. package/content/guidance/storefront-next/sfnext-create-vertical/SKILL.md +0 -135
  296. package/content/guidance/storefront-next/sfnext-create-vertical/references/COMPONENT-AUTHORING.md +0 -206
  297. package/content/guidance/storefront-next/sfnext-create-vertical/references/PROJECT-STRUCTURE.md +0 -43
  298. package/content/guidance/storefront-next/sfnext-create-vertical/references/TOKEN-SYSTEM.md +0 -130
  299. package/content/guidance/storefront-next/sfnext-create-vertical/references/TROUBLESHOOTING.md +0 -34
  300. package/content/guidance/storefront-next/sfnext-custom-apis/SKILL.md +0 -221
  301. package/content/guidance/storefront-next/sfnext-custom-apis/references/WORKFLOW-EXAMPLES.md +0 -294
  302. package/content/guidance/storefront-next/sfnext-data-fetching/references/LOADER-PATTERNS.md +0 -102
  303. package/content/guidance/storefront-next/sfnext-project-setup/references/ENV-VARIABLES.md +0 -82
  304. package/content/guidance/storefront-next/sfnext-scapi-management/SKILL.md +0 -203
  305. package/content/guidance/storefront-next/sfnext-scapi-management/references/CLI-COMMANDS.md +0 -122
  306. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-create-component/SKILL.md +0 -195
  307. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-create-component/evals/trigger-evals.json +0 -12
  308. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-create-component/references/COMPONENT-AUTHORING.md +0 -206
  309. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-create-component/references/PROJECT-STRUCTURE.md +0 -43
  310. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-create-component/references/TOKEN-SYSTEM.md +0 -130
  311. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-create-component/references/TROUBLESHOOTING.md +0 -34
  312. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-create-vertical/SKILL.md +0 -135
  313. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-create-vertical/evals/trigger-evals.json +0 -12
  314. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-create-vertical/references/COMPONENT-AUTHORING.md +0 -206
  315. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-create-vertical/references/PROJECT-STRUCTURE.md +0 -43
  316. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-create-vertical/references/TOKEN-SYSTEM.md +0 -130
  317. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-create-vertical/references/TROUBLESHOOTING.md +0 -34
  318. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-custom-apis/SKILL.md +0 -221
  319. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-custom-apis/evals/trigger-evals.json +0 -12
  320. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-custom-apis/references/WORKFLOW-EXAMPLES.md +0 -294
  321. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-data-fetching/references/LOADER-PATTERNS.md +0 -102
  322. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-project-setup/references/ENV-VARIABLES.md +0 -82
  323. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-scapi-management/SKILL.md +0 -203
  324. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-scapi-management/evals/trigger-evals.json +0 -12
  325. package/node_modules/@salesforce/b2c-agent-plugins/storefront-next/skills/sfnext-scapi-management/references/CLI-COMMANDS.md +0 -122
  326. /package/content/guidance/mcp/{scapi → b2c-mcp-scapi}/references/custom-apis.md +0 -0
  327. /package/content/guidance/mcp/{scapi → b2c-mcp-scapi}/references/custom-properties.md +0 -0
  328. /package/content/guidance/mcp/{scapi → b2c-mcp-scapi}/references/products.md +0 -0
  329. /package/content/guidance/mcp/{scapi → b2c-mcp-scapi}/references/promotions.md +0 -0
  330. /package/content/guidance/mcp/{scapi → b2c-mcp-scapi}/references/saving.md +0 -0
  331. /package/content/guidance/mcp/{scapi → b2c-mcp-scapi}/references/snippets.md +0 -0
  332. /package/content/guidance/mcp/{scapi → b2c-mcp-scapi}/references/tokens.md +0 -0
  333. /package/content/guidance/mcp/{server → b2c-mcp-server}/references/files.md +0 -0
@@ -0,0 +1,129 @@
1
+ ---
2
+ name: sfnext-security
3
+ description: >-
4
+ Configure Storefront Next security response headers, Content Security Policy (CSP), CSP contributors, Cloudflare Turnstile bot protection, and the shared cookie domain. Use for "Refused to load the script/connect/image" CSP violations, adding a third-party origin, app.security.headers, defaultCspDirectives, csp reportOnly rollout, writing a CSP contributor under src/middlewares/csp-contributors, HSTS or Permissions-Policy, Turnstile widget or enforceTurnstile, TURNSTILE_SECRET_KEYS, log-only rollout, or app.cookies.domain across subdomains. Do not use for auth tokens, cookie names or login flows (use `storefront-next:sfnext-authentication`), SFRA proxy routing (use `storefront-next:sfnext-hybrid-storefronts`), or consent banners and tracking (use `storefront-next:sfnext-analytics-consent`).
5
+ ---
6
+
7
+ # Storefront Next Security
8
+
9
+ Security is configured under `app.security` in `config.server.ts`: `security.headers` for response headers and CSP, `security.turnstile` for bot protection. Cookie sharing is `app.cookies.domain`. Your project ships deeper docs: `docs/README-SECURITY-HEADERS.md`, `docs/README-TURNSTILE.md`, `docs/README-COOKIE-DOMAIN.md`. Read them for details; this skill is the task guide.
10
+
11
+ ## Default headers
12
+
13
+ Every storefront gets these with no opt-in, from `@salesforce/storefront-next-runtime/security` via the `securityHeadersMiddleware` in `src/middlewares/security-headers.server.ts`:
14
+
15
+ | Header | Default |
16
+ |---|---|
17
+ | `Content-Security-Policy` | Strict, nonce-based (no `'unsafe-inline'` scripts, no `'unsafe-eval'`) |
18
+ | `Strict-Transport-Security` | Sent on Managed Runtime only, suppressed locally |
19
+ | `X-Frame-Options` | `SAMEORIGIN` |
20
+ | `X-Content-Type-Options` | `nosniff` |
21
+ | `Referrer-Policy` | `strict-origin-when-cross-origin` |
22
+ | `Permissions-Policy` | `camera=(), microphone=(), geolocation=()` |
23
+
24
+ The CSP directive table (which origins `script-src`, `connect-src`, `img-src`, and `frame-src` allow by default) is in `docs/README-SECURITY-HEADERS.md`. The per-request nonce is read in `root.tsx` and must be forwarded to any inline `<script>` you render (for example the JSON-LD component takes a `nonce` prop).
25
+
26
+ ## Allow a new third-party origin
27
+
28
+ The violation message names the directive to extend ("Refused to connect to ..." means `connect-src`). Spread the defaults, because **each directive you set fully replaces the default**:
29
+
30
+ ```ts
31
+ // config.server.ts
32
+ import { defaultCspDirectives } from '@salesforce/storefront-next-runtime/security';
33
+
34
+ security: {
35
+ headers: {
36
+ csp: {
37
+ directives: {
38
+ ...defaultCspDirectives,
39
+ 'script-src': [...defaultCspDirectives['script-src']!, 'https://cdn.example.com'],
40
+ 'connect-src': [...defaultCspDirectives['connect-src']!, 'https://api.example.com'],
41
+ },
42
+ },
43
+ },
44
+ },
45
+ ```
46
+
47
+ Use exact origins, not wildcards. Do not load third-party scripts synchronously in the document head; load them after interaction or idle (see `storefront-next:sfnext-performance`).
48
+
49
+ Env-var override is awkward for directives (names contain hyphens, and a JSON override replaces the whole map). Use `config.server.ts` for directives and env vars for toggles:
50
+
51
+ ```bash
52
+ PUBLIC__app__security__headers__csp__reportOnly=true
53
+ PUBLIC__app__security__headers__hsts=false
54
+ ```
55
+
56
+ ## Roll out or relax safely
57
+
58
+ - Migrating or adding many origins: set `csp: { reportOnly: true }`, watch DevTools violations, extend the directives, then remove `reportOnly`. A startup warning is logged while it is on.
59
+ - Disable one header with `hsts: false` or `permissionsPolicy: false`. `headers: { enabled: false }` disables everything; use it for debugging only. A startup warning is logged whenever any header is disabled.
60
+
61
+ ## CSP contributors
62
+
63
+ A contributor lets a feature add its own exact origins to the CSP at boot instead of hand-editing directives. Shipped examples in `src/middlewares/csp-contributors/`: `cimulate.ts` (Shopper Agent widget, active when enabled in config), `data360.ts` (`connect-src` for the tenant ingestion host), and `openstreetmap.ts` (a deliberate no-op; replace it to permit map tiles).
64
+
65
+ Shape (see `data360.ts` for the smallest real one):
66
+
67
+ ```ts
68
+ import type { CspContributor, CspContribution } from '@salesforce/storefront-next-runtime/security';
69
+ import { toCspOrigin } from './to-csp-origin.js';
70
+
71
+ export function createMyFeatureCspContributor(cfg: { enabled?: boolean; apiUrl?: string } | undefined): CspContributor {
72
+ const origin = cfg?.apiUrl ? toCspOrigin(cfg.apiUrl) : null;
73
+ return {
74
+ id: 'my-feature',
75
+ isActive: () => cfg?.enabled === true && origin !== null,
76
+ contribute: (): CspContribution => (origin ? { 'connect-src': [origin] } : {}),
77
+ };
78
+ }
79
+ ```
80
+
81
+ Then add it to the `contributors` array in `src/middlewares/security-headers.server.ts`. Rules:
82
+
83
+ - Derive origins from config you already have; `toCspOrigin` returns `null` for unsafe values.
84
+ - The runtime validates contributors at boot: https only, no wildcards, no credentials, no whitespace.
85
+ - Contribute only while the feature is active, so disabled features never widen the policy.
86
+ - Add a colocated `*.test.ts` like the shipped ones.
87
+
88
+ Use a contributor for a feature toggled by config; use the `defaultCspDirectives` spread for one-off origins.
89
+
90
+ ## Turnstile bot protection
91
+
92
+ Cloudflare Turnstile guards passwordless email, checkout registration, and order lookup. It is **fail-open** on Cloudflare outages (so a Turnstile incident never blocks checkout) and fail-closed on real bot signals (forged, replayed, or missing tokens).
93
+
94
+ Config (`config.server.ts`, overridable with `PUBLIC__` env vars): `security.turnstile.enabled`, `mode` (`managed`, `non-interactive`, `invisible`), `sites` (per-site site keys), and `verification.mode` (`enforce`, `log-only`, `disabled`).
95
+
96
+ | Variable | Purpose |
97
+ |---|---|
98
+ | `TURNSTILE_SECRET_KEYS` | JSON map of site key to secret key. Server-only. Required for `enforce` and `log-only` |
99
+ | `PUBLIC__app__security__turnstile__enabled` | Master switch; when false the widget never renders |
100
+ | `PUBLIC__app__security__turnstile__sites` | JSON per-site keys |
101
+ | `PUBLIC__app__security__turnstile__verification__mode` | `enforce`, `log-only`, `disabled` |
102
+
103
+ Rollout: deploy with `verification.mode` set to `log-only`, read the logs for `would_block`, then switch to `enforce`. Shoppers start without a `cc-tv_<siteId>` attestation cookie after the switch, which is expected.
104
+
105
+ Add protection to a new server action by rendering `TurnstileWidget` (`src/components/security/turnstile-widget.tsx`) in the form and calling `enforceTurnstile` (`src/lib/turnstile/enforce.server.ts`) in the action before doing work. Pass `request`, `config`, `turnstileToken`, `logger`, `actionName`, `email`, and `turnstileCookieName`; set the `cc-tv` cookie from the returned `cookieValue` when it is non-null. Copy an existing caller such as `src/routes/action.authorize-passwordless-email.ts`. Cloudflare test keys and a manual test matrix: [references/TURNSTILE.md](references/TURNSTILE.md).
106
+
107
+ ## Cookie domain
108
+
109
+ Cookies are host-only by default. To share them across subdomains or with SFRA, set `app.cookies.domain` (or `commerce.sites[].cookies.domain` per site; env `PUBLIC__app__cookies__domain=.example.com`) **and** match Business Manager: Site Preferences, Hybrid Auth Settings, cookie-domain level `0` for host-only, `2` for the first-level parent domain. Level `1` is rejected. A mismatch silently breaks sessions. Full checklist: [references/COOKIE-DOMAIN.md](references/COOKIE-DOMAIN.md).
110
+
111
+ ## Pitfalls
112
+
113
+ | Symptom | Cause / fix |
114
+ |---|---|
115
+ | Added origin to `script-src` and other scripts broke | You replaced the directive. Spread `defaultCspDirectives['script-src']` first |
116
+ | Inline script blocked | Missing `nonce`. Read it from root loader data and pass it on |
117
+ | CSS/JS fail on local Safari after enabling your own `upgrade-insecure-requests` | The default suppresses it locally for a reason; keep the default |
118
+ | Login does not stick after setting `cookies.domain` | Domain is not a parent of the serving host, or Business Manager level mismatches |
119
+ | Turnstile widget never appears | Expected when Cloudflare says no challenge is needed (`interaction-only`); check network tab and `cc-tv_<siteId>` |
120
+ | Everything blocked in Turnstile tests | Secret keys missing in `TURNSTILE_SECRET_KEYS` for the configured site key |
121
+
122
+ ## Related Skills
123
+
124
+ - `storefront-next:sfnext-authentication` - cookies, sessions, login flows that Turnstile protects
125
+ - `storefront-next:sfnext-hybrid-storefronts` - SFRA proxy and `dwsid` session bridge
126
+ - `storefront-next:sfnext-configuration` - `config.server.ts` and `PUBLIC__` overrides
127
+ - `storefront-next:sfnext-performance` - loading third-party scripts safely
128
+ - `storefront-next:sfnext-analytics-consent` - tracking consent and analytics adapters
129
+ - `storefront-next:sfnext-deployment` - Managed Runtime environment variables
@@ -0,0 +1,39 @@
1
+ # Cookie domain reference
2
+
3
+ Full guide: `docs/README-COOKIE-DOMAIN.md` in your project.
4
+
5
+ ## Resolution order
6
+
7
+ 1. `commerce.sites[].cookies.domain` (per site)
8
+ 2. `app.cookies.domain` (global; env `PUBLIC__app__cookies__domain`)
9
+ 3. Unset: host-only cookies
10
+
11
+ The domain is applied to every cookie the storefront writes (auth, session, site, locale, currency). It must be a parent of the serving host or the browser silently drops the cookies. A leading dot is optional.
12
+
13
+ ## Business Manager match
14
+
15
+ Business Manager, Merchant Tools, Site Preferences, Hybrid Auth Settings:
16
+
17
+ | Storefront `cookies.domain` | BM level | Result |
18
+ |---|---|---|
19
+ | unset | 0 | OK, host-only everywhere |
20
+ | `.example.com` | 2 | OK, shared across subdomains |
21
+ | `.example.com` | 0 | Broken cross-subdomain session |
22
+ | unset | 2 | Duplicate host-only vs domain-scoped cookies |
23
+
24
+ Level 1 is rejected. Salesforce-managed sites need a request to the team managing Business Manager.
25
+
26
+ ## Verify
27
+
28
+ ```bash
29
+ curl -sI https://www.example.com/ | grep -i '^set-cookie:'
30
+ ```
31
+
32
+ - Every cookie carries the same `Domain=`.
33
+ - No same-name duplicates (one host-only, one domain-scoped).
34
+ - A session persists between `www.` and `account.` hosts; in hybrid mode `dwsid` is shared with SFRA pages.
35
+ - Logout clears the domain-scoped cookies.
36
+
37
+ ## Rollout
38
+
39
+ Changing the domain on a live site leaves old cookies next to new ones until they expire, and a host-only cookie shadows a domain-scoped one of the same name. Expect transient session glitches; roll out in a low-traffic window. A per-site empty string inherits the global domain; it cannot force host-only.
@@ -0,0 +1,43 @@
1
+ # Turnstile reference
2
+
3
+ Deep design lives in `docs/README-TURNSTILE.md` in your project. Quick facts:
4
+
5
+ ## Modules
6
+
7
+ - `src/components/security/turnstile-widget.tsx` - client widget (`siteKey`, `onSuccess`, `onError`, `onExpire`, `onTimeout`, `onBypass`). Mounts with `appearance: 'interaction-only'`, so it is hidden unless Cloudflare needs shopper input.
8
+ - `src/lib/turnstile/enforce.server.ts` - `enforceTurnstile` and `resolveVerificationMode`.
9
+ - `src/lib/turnstile/constants.ts` - cookie base name `cc-tv` (written as `cc-tv_<siteId>`, 30 minute TTL).
10
+
11
+ ## Enforcement points
12
+
13
+ `action.authorize-passwordless-email`, `action.initiate-checkout-registration`, the order-lookup request-code action, and the passwordless submit and OTP resend on the login route. The OTP verification actions rely on the earlier challenge plus the code itself.
14
+
15
+ ## Fail-open vs fail-closed
16
+
17
+ Open (request allowed, logged at warn): siteverify network failure or 5xx, `internal-error`, sustained elevated failure rate, CDN probe failure, client script timeout. Closed: `invalid-input-response`, `timeout-or-duplicate`, missing token while Cloudflare looks healthy, origin mismatch, misconfigured site key.
18
+
19
+ ## Verification mode
20
+
21
+ | Value | Behavior |
22
+ |---|---|
23
+ | `enforce` | Blocks failures |
24
+ | `log-only` | Runs full verification, only logs `would_block`; no shopper blocked, no `cc-tv` cookie issued |
25
+ | `disabled` | Skips verification |
26
+
27
+ `TURNSTILE_VERIFICATION_ENABLED` is deprecated; use `PUBLIC__app__security__turnstile__verification__mode`. `TURNSTILE_CDN_PROBE_URL` overrides the health probe URL for tests.
28
+
29
+ ## Cloudflare test keys (local development)
30
+
31
+ | Site key | Secret key | Behavior |
32
+ |---|---|---|
33
+ | `1x00000000000000000000AA` | `1x0000000000000000000000000000000AA` | Always passes, silent |
34
+ | `2x00000000000000000000AB` | `2x0000000000000000000000000000000AA` | Always blocks, silent |
35
+ | `3x00000000000000000000FF` | `1x0000000000000000000000000000000AA` | Forces an interactive challenge (only visible widget) |
36
+
37
+ Set the site key in `security.turnstile.sites` and `TURNSTILE_SECRET_KEYS` to a JSON map of site key to secret key. The passwordless login form only renders when the `emailVerificationEnabled` site preference is on (Business Manager, Storefront Login Preferences); see `docs/README-TURNSTILE.md` for seeding it locally.
38
+
39
+ ## Manual checks
40
+
41
+ - Interactive key `3x...FF` with a passing secret: widget appears, then the OTP modal opens.
42
+ - Always-block key: no widget, a generic "We couldn't verify your information" alert, no OTP modal.
43
+ - Block `challenges.cloudflare.com` locally: no widget, flow continues (graceful degradation).
@@ -0,0 +1,95 @@
1
+ ---
2
+ name: sfnext-seo
3
+ description: >-
4
+ Storefront Next SEO and AEO/GEO: the SeoMeta component (title, description, noIndex, Open Graph, X cards), JsonLd structured data, canonical URLs and the query-parameter allowlist, hreflang, configurable product/category URLs via url.seoRoutes, semantic URL builders (createProductUrl, createCategoryUrl, useSeoUrlContext), redirectToCanonicalPath, crawler rendering and pagination, and how multi-domain and base path affect generated URLs. Use when adding meta tags or JSON-LD to a route, enabling or changing seoRoutes, fixing duplicate or wrong canonical or og:url URLs, or when a build fails for a missing site in seoRoutes. Do not use for route file naming (use `storefront-next:sfnext-routing`), site/locale config in general (use `storefront-next:sfnext-configuration`), or translations (use `storefront-next:sfnext-i18n`).
5
+ ---
6
+
7
+ # Storefront Next SEO
8
+
9
+ In-project references: `docs/README-SEO.md`, `docs/README-AEO-GEO.md`, `docs/README-MULTI-SITE.md` (URL Config), `docs/README-MULTI-DOMAIN.md`, `docs/README-BASE-PATH.md`, `docs/migrations/seo-url-rules/README.md`. Read them for depth; this skill is the task map.
10
+
11
+ ## Page metadata: SeoMeta
12
+
13
+ ```tsx
14
+ import { SeoMeta } from '@/components/seo-meta';
15
+
16
+ <SeoMeta title={t('meta.title', { defaultValue: 'My Page' })} description={t('meta.description', { defaultValue: '...' })} />
17
+ <SeoMeta title="Checkout" noIndex /> {/* private/transactional pages */}
18
+ <SeoMeta rawTitle title="Store Name" /> {/* no " | Site Name" suffix */}
19
+ <SeoMeta title={name} openGraph={{ type: 'product', url: pageUrl, image }} />
20
+ ```
21
+
22
+ Props (verified in `src/components/seo-meta/index.tsx`): `title`, `rawTitle`, `description`, `noIndex`, `siteName`, `twitter`, `openGraph`. Open Graph input auto-derives X card tags unless `twitter` is set. Use `noIndex` for cart, checkout, account, and other non-public pages. Root-level canonical and hreflang descriptors come from `src/utils/seo.ts` and `src/utils/canonical-url.ts`; routes do not add them.
23
+
24
+ ## Structured data: JsonLd
25
+
26
+ ```tsx
27
+ import { JsonLd } from '@/components/json-ld';
28
+
29
+ <JsonLd data={productSchema} id="product-schema" nonce={nonce} />
30
+ ```
31
+
32
+ Pass the CSP nonce so the inline script is allowed. Builders live in `src/utils/product-schema.ts`, `category-schema.ts`, `schema-url.ts`. PDP emits `Product`; PLP emits `CollectionPage` + `ItemList` (see `docs/README-AEO-GEO.md`).
33
+
34
+ ## One URL everywhere
35
+
36
+ Canonical `<link>`, `og:url` and JSON-LD `url` must agree. In loaders:
37
+
38
+ ```ts
39
+ import { buildSeoPageUrl } from '@/lib/seo/page-url.server';
40
+ import { redirectToCanonicalPath } from '@/lib/seo/canonical-redirect.server';
41
+
42
+ redirectToCanonicalPath(requestUrl); // 301 for trailing slash
43
+ const pageUrl = buildSeoPageUrl(context, requestUrl); // origin + canonical path/query
44
+ ```
45
+
46
+ Only allowlisted query params survive in canonicals (`CONTENT_PARAMS` in `src/utils/canonical-url.ts`: `q`, `offset`, `sort`, `refine`, `pid` by default). Add a param only if it changes main page content, and add a test next to `canonical-url.test.ts`.
47
+
48
+ ## Configurable URLs: url.seoRoutes
49
+
50
+ ```ts
51
+ // config.server.ts
52
+ url: {
53
+ prefix: '/:siteId/:localeId',
54
+ seoRoutes: {
55
+ RefArchGlobal: { product: { prefix: 'p' }, category: { prefix: 'c', mode: 'id-suffix' } },
56
+ },
57
+ }
58
+ ```
59
+
60
+ Key rules (full playbook in [references/SEO-ROUTES.md](references/SEO-ROUTES.md)):
61
+
62
+ - Build-time: changing `seoRoutes` requires a rebuild and redeploy (restart the dev server locally).
63
+ - Every active site needs an entry, or URL generation throws / the build fails.
64
+ - Business Manager URL settings are the source of truth; `seoRoutes` is a manual copy that must be kept in sync.
65
+ - Do not rename route files. Routes are already generic; the config maps prefixes.
66
+ - Build links with the semantic builders, never hardcoded `/product/...` strings:
67
+
68
+ ```tsx
69
+ import { createProductUrl, createCategoryUrl } from '@/route-paths';
70
+ import { useSeoUrlContext } from '@/hooks/use-seo-url-context';
71
+
72
+ const ctx = useSeoUrlContext();
73
+ <Link to={createProductUrl({ productId, slug }, ctx)} />
74
+ ```
75
+
76
+ `seoFallback.sites` in config supplies per-site fallback behavior when a SEO URL cannot be resolved; see `docs/README-MULTI-SITE.md`.
77
+
78
+ ## Multi-domain and base path
79
+
80
+ - Origin for canonicals comes from `getAppOrigin` (honors forwarded host, falls back to `EXTERNAL_DOMAIN_NAME`). Each custom domain must be attached to the Managed Runtime environment. See [references/MULTI-DOMAIN-BASE-PATH.md](references/MULTI-DOMAIN-BASE-PATH.md).
81
+ - Mapping domains to sites uses an `X-Site-Id` header set by your CDN.
82
+ - A base path (`MRT_ENV_BASE_PATH`, set from the push config) prefixes asset and route URLs; use `getBasePath()` rather than hardcoding.
83
+
84
+ ## Crawlers
85
+
86
+ Crawlers receive full HTML rendering; category pages stay crawlable through a `?page=N` parameter with rel prev/next links, while the canonical stays the base category URL. Verify with `curl` and a crawler user agent. Check `docs/README-SEO.md` "Crawler Rendering and Pagination" before changing streaming behavior.
87
+
88
+ ## Related Skills
89
+
90
+ - `storefront-next:sfnext-routing` - route modules and URL patterns
91
+ - `storefront-next:sfnext-configuration` - config.server.ts and env overrides
92
+ - `storefront-next:sfnext-i18n` - locales, hreflang inputs
93
+ - `storefront-next:sfnext-hybrid-storefronts` - URLs owned by another storefront
94
+ - `storefront-next:sfnext-security` - CSP nonce for JSON-LD
95
+ - `storefront-next:sfnext-performance` - streaming vs crawler rendering
@@ -0,0 +1,17 @@
1
+ # Multi-domain and base path effects on URLs
2
+
3
+ In-project docs: `docs/README-MULTI-DOMAIN.md`, `docs/README-BASE-PATH.md`, `docs/README-MULTI-SITE.md`.
4
+
5
+ ## Multiple domains, one environment
6
+
7
+ - Attach every domain to the Managed Runtime environment (custom domains in the MRT project; see `b2c-cli:b2c-mrt`).
8
+ - The request host is read from the forwarded host header; `getAppOrigin` uses it for canonical, hreflang, and og URLs. `EXTERNAL_DOMAIN_NAME` is a fallback only.
9
+ - To choose the Commerce site per domain, have the CDN send an `X-Site-Id` header (for example `site-a.shop.com` -> `RefArch`).
10
+ - Only trust forwarded host behind your CDN; the doc has a section on trusting the forwarded host.
11
+ - Images on custom domains need `realmHostMappings`; cookies are host-only by default (see `docs/README-COOKIE-DOMAIN.md`).
12
+
13
+ ## Base path
14
+
15
+ - `MRT_ENV_BASE_PATH` is set by Managed Runtime from the push configuration (`ssrParameters.envBasePath`).
16
+ - Server code reads `process.env.MRT_ENV_BASE_PATH`; client code derives it from the bundle path. Use `getBasePath()` (defined in your project's `src/lib/utils.ts`) when building URLs by hand.
17
+ - Canonical URLs must include the base path; use `buildSeoPageUrl` instead of concatenating strings.
@@ -0,0 +1,31 @@
1
+ # Adopting url.seoRoutes
2
+
3
+ Source: `docs/migrations/seo-url-rules/README.md` and `docs/README-MULTI-SITE.md` (URL Config) in your project. Trust the code if they differ; verify `apply-seo-url-config` behavior in `@salesforce/storefront-next-dev`.
4
+
5
+ ## What it changes
6
+
7
+ Without `seoRoutes` the storefront serves the built-in `/product/{id}` and `/category/{id}` grammar. With it, each site gets its own product and category prefix (for example `/p/{slug}/{id}`), matching Business Manager URL settings.
8
+
9
+ ## Checklist before enabling
10
+
11
+ 1. Runtime and dev packages are on a release that supports `seoRoutes` (see `docs/COMPATIBILITY.md`).
12
+ 2. Every active site has an entry in `url.seoRoutes`; a missing site fails.
13
+ 3. Decide the category mode per site: `id-suffix` (slug plus trailing category id) or slug-path (pure slug hierarchy).
14
+ 4. Protect routes that must not be captured by a product/category prefix with `protectedPaths` (build-time option described in the URL Config section).
15
+ 5. Leaf routes vs segments: check how the build validates overlapping prefixes.
16
+ 6. Keep Business Manager URL settings identical; there is no automatic sync.
17
+
18
+ ## Avoid breaking indexed URLs
19
+
20
+ - Keep old URL shapes redirecting to the new canonical ones; `redirectToCanonicalPath` only normalizes trailing slashes, so test old `/product/{id}` URLs explicitly.
21
+ - Audit hardcoded links; replace them with `createProductUrl` / `createCategoryUrl` and `useSeoUrlContext()`.
22
+ - Legacy category paths can be converted with `createCategoryUrlFromLegacyPath` in `@/route-paths`.
23
+ - Deploy, then crawl canonical, hreflang, and JSON-LD URLs for consistency.
24
+
25
+ ## Hybrid deployments
26
+
27
+ If part of the catalog is served by another storefront, the storefront only owns the URLs routed to it; see `storefront-next:sfnext-hybrid-storefronts` and `docs/README-HYBRID-PROXY.md`.
28
+
29
+ ## Verifying
30
+
31
+ Run `pnpm typecheck && pnpm test`, then request a product and category URL for each site and check the canonical `<link>`.
@@ -1,123 +1,114 @@
1
1
  ---
2
2
  name: sfnext-state-management
3
- description: Manage client-side state in Storefront Next using React context providers and feature-level Zustand stores. Use when handling basket/auth UI state, creating extension stores (for example store locator), or syncing client-visible state after server mutations. NOT for server-side data loading — see sfnext-data-fetching for loader patterns.
3
+ description: >-
4
+ Choose the right state mechanism in a Storefront Next project: loader and action data, useRouteLoaderData, URL state with useSearchParams, cookies and sessions, optimistic UI (fetcher.formData, useNavigation, useOptimistic), React context providers (BasketProvider, AuthProvider, wishlist, product-context), and small useSyncExternalStore stores such as the mini-cart store. Use for "where should this state live", "useBasket", "useAuth", "share state between components", "optimistic add to cart", "global client state", "hydration mismatch from a store", or "do I need Zustand". Do not use for fetching or mutating data (use `storefront-next:sfnext-data-fetching`), controlling loader re-runs (use `storefront-next:sfnext-revalidation`), or login flows and sessions (use `storefront-next:sfnext-authentication`).
4
5
  ---
5
6
 
6
- # State Management Skill
7
+ # Storefront Next State Management
7
8
 
8
- This skill covers client-side state management in Storefront Next with server-first data loading.
9
+ Server state lives in loaders and actions. Client state is small and local. There is no global client store library in the template (Zustand was removed): use the tools below in this order. `docs/README-STATE.md` and `docs/README-DATA.md` in your project cover each in depth.
9
10
 
10
- ## Overview
11
+ ## Decision table
11
12
 
12
- Storefront Next keeps business data on the server (`loader`/`action`) and uses client state for UX continuity. In practice, app-wide state is commonly exposed through providers (for example auth/basket), while complex extension-specific state can use Zustand.
13
+ | State | Use |
14
+ |---|---|
15
+ | Data from SCAPI | `loader` + `loaderData`; `action` for writes |
16
+ | Another route's loader data | `useRouteLoaderData('routes/_app')` (route id = file path without extension) |
17
+ | Filters, sort, pagination, tab | URL: `useSearchParams` / `useParams` (shareable, SSR-friendly) |
18
+ | Must survive requests, read by server | cookies (`createCookie` from `@/lib/cookie-utils.server`) or session helpers |
19
+ | Pending or optimistic result | `fetcher.formData`, `useNavigation`, `useOptimistic` |
20
+ | Form fields, toggles, open/close in one component | `useState` / `useReducer` |
21
+ | Shared by a subtree | React context with a provider at the owning layout |
22
+ | Shared app-wide and read outside React, or high-frequency | module-level `useSyncExternalStore` store |
23
+ | Request-scoped server values (site, auth, basket) | router `context` (middleware), read with `context.get(...)` |
13
24
 
14
- | State Type | Mechanism | Example |
15
- | --------------------- | ------------------------------ | ------------------------------------------------------ |
16
- | Server data | React Router `loader` | Product details, category listings |
17
- | App-wide client state | React context providers | Session display state, basket snapshot/hydration state |
18
- | Feature client state | Zustand store | Store locator modal/search state |
19
- | Mutations | React Router `action` (server) | Add to cart, update profile |
25
+ Prefer the earliest row that works. Never copy loader data into `useState` to "cache" it.
20
26
 
21
- ## Zustand Store Pattern (Feature-Level)
27
+ ## Existing providers and stores
22
28
 
23
- ```typescript
24
- // src/extensions/store-locator/stores/store-locator-store.ts
25
- import {createStore} from 'zustand/vanilla';
29
+ | Need | API |
30
+ |---|---|
31
+ | Basket | `BasketProvider` in `src/providers/basket.tsx`: `useBasket({ autoLoad })`, `useBasketSnapshot`, `useBasketHydrated`, `useBasketError`, `useBasketUpdater`, `useBasketReset`, `useBasketLoader`, `useBasketReconcile`; `BasketCookieReconciler` syncs the cookie |
32
+ | Session info | `useAuth()` from `@/providers/auth` |
33
+ | Product / variant selection | `@/providers/product-context`, `@/providers/product-view` |
34
+ | Image widths | `DynamicImageProvider` (`@/providers/dynamic-image`) |
35
+ | Wishlist | `src/providers/wishlist.ts` (module-level store) |
36
+ | Mini-cart open state | `useMiniCartStore`, `setMiniCartOpen` in `src/hooks/mini-cart-store.ts` |
37
+ | Cart toast | `src/hooks/cart-mutation-toast-store.ts` |
38
+ | Shopper context | `useShopperContext` (`@/hooks/use-shopper-context`) |
26
39
 
27
- type StoreLocatorState = {
28
- isOpen: boolean;
29
- mode: 'input' | 'device';
30
- selectedStoreInfo: SelectedStoreInfo | null;
31
- };
40
+ The basket is loaded through `useScapiFetcher('shopperBasketsV2', 'getBasket')` and is updated from action results via `updateBasketResource` (server side, `@/middlewares/basket.server`), so after a basket action components simply re-render from `useBasket()`. The `__sfdc_basket` cookie carries the basket id; `__sfdc_usertype` is the user-type hint. Do not read these directly in components; use the hooks. Server reads: `getBasket`, `getBasketSnapshot`, `ensureBasketId`, `destroyBasket`, and `getAuth`, `updateAuth`, `destroyAuth` from `@/middlewares/auth.server`.
32
41
 
33
- type StoreLocatorActions = {
34
- open: () => void;
35
- close: () => void;
36
- setSelectedStoreInfo: (info: SelectedStoreInfo) => void;
37
- };
42
+ ## Optimistic UI
38
43
 
39
- type StoreLocatorStore = StoreLocatorState & StoreLocatorActions;
40
-
41
- export const createStoreLocatorStore = (init?: Partial<StoreLocatorState>) => {
42
- return createStore<StoreLocatorStore>()((set) => ({
43
- isOpen: false,
44
- mode: 'input',
45
- selectedStoreInfo: init?.selectedStoreInfo ?? null,
46
- open: () => set({isOpen: true}),
47
- close: () => set({isOpen: false}),
48
- setSelectedStoreInfo: (selectedStoreInfo) => set({selectedStoreInfo}),
49
- }));
50
- };
44
+ ```tsx
45
+ const fetcher = useFetcher<typeof action>();
46
+ const removing = fetcher.formData?.get('itemId') === item.itemId;
47
+ return <li hidden={removing}>...</li>;
51
48
  ```
52
49
 
53
- ## Context Integration
50
+ Use `useOptimistic` for values the server will confirm, and `useNavigation` for URL-driven pending states. Roll back by reading the confirmed `loaderData`/basket value; never hand-maintain a parallel copy.
54
51
 
55
- Expose app-level state to components via providers/hooks:
52
+ ## A small external store
56
53
 
57
- ```typescript
58
- import { useBasket, useBasketSnapshot } from '@/providers/basket';
54
+ Use when state is global, changes often, or must be set outside React. Follow `src/hooks/mini-cart-store.ts`:
59
55
 
60
- // In components
61
- function CartIcon() {
62
- const basket = useBasket();
63
- const snapshot = useBasketSnapshot();
56
+ ```ts
57
+ import { useSyncExternalStore } from 'react';
64
58
 
65
- const itemCount =
66
- basket?.productItems?.length ??
67
- snapshot?.uniqueProductCount ??
68
- 0;
59
+ interface State { open: boolean }
60
+ let state: State = { open: false };
61
+ const SERVER_STATE: State = Object.freeze({ open: false });
62
+ const listeners = new Set<() => void>();
69
63
 
70
- return <Badge count={itemCount} />;
64
+ const subscribe = (l: () => void) => { listeners.add(l); return () => void listeners.delete(l); };
65
+ export const setOpen = (open: boolean) => {
66
+ if (open === state.open) return; // skip no-op writes
67
+ state = { ...state, open };
68
+ listeners.forEach((l) => l());
69
+ };
70
+ export function useDrawerStore<T>(select: (s: State) => T): T {
71
+ return useSyncExternalStore(subscribe, () => select(state), () => select(SERVER_STATE));
71
72
  }
72
73
  ```
73
74
 
74
- ## Post-Mutation Sync Pattern
75
-
76
- Keep mutations on the server and update request-context resources there:
75
+ Rules:
77
76
 
78
- ```typescript
79
- import {data} from 'react-router';
80
- import {getBasket, updateBasketResource} from '@/middlewares/basket.server';
77
+ - `getSnapshot` must return a referentially stable value when nothing changed. Select primitives; a selector that allocates per call loops forever.
78
+ - Provide a server snapshot and mutate only from events or effects so SSR and the first client render match (no hydration warnings).
79
+ - Split stores by independent writers so each consumer subscribes to a slice.
80
+ - For an instance-based store (one per widget), create it in a factory and provide it by context, as `createStoreLocatorStore` does in the store-locator extension.
81
81
 
82
- export async function action({request, context}: ActionFunctionArgs) {
83
- const formData = await request.formData();
84
- const productId = formData.get('productId') as string;
82
+ ## Context providers
85
83
 
86
- const basketResource = await getBasket(context);
87
- const clients = createApiClients(context);
84
+ - Put the provider at the lowest layout that contains all consumers.
85
+ - Memoize the `value` (`useMemo`, `useCallback`) and split read-only state from updaters into separate contexts so updater-only consumers do not re-render.
86
+ - Use a selector pattern for large contexts (see README-STATE "Context Selector Pattern").
87
+ - Values used only inside callbacks belong in `useRef`, not context state.
88
+ - Compose providers with `src/providers/compose-providers.tsx`.
88
89
 
89
- const {data: updatedBasket} = await clients.basket.addItemToBasket({
90
- params: {path: {basketId: basketResource.current?.basketId ?? ''}},
91
- body: {productId, quantity: 1},
92
- });
93
-
94
- // Sync basket resource in request context for current response/revalidation flow
95
- updateBasketResource(context, updatedBasket);
96
-
97
- return data({success: true, basket: updatedBasket});
98
- }
99
- ```
90
+ More patterns and anti-patterns in [PATTERNS.md](references/PATTERNS.md).
100
91
 
101
- ## Best Practices
92
+ ## Common mistakes
102
93
 
103
- 1. **Server-first data** — Load/mutate commerce data with `loader`/`action`
104
- 2. **Provider-first app state** — Use providers for shared basket/auth UI state
105
- 3. **Scoped Zustand usage** — Use Zustand for feature-local complexity (typically extensions)
106
- 4. **Sync in server actions** — Update server basket/auth resources inside `action` handlers
107
- 5. **Keep state minimal** — Store only what cannot be derived cheaply
94
+ | Mistake | Instead |
95
+ |---|---|
96
+ | `useEffect` that fetches on mount and stores in state | loader (or streamed promise) |
97
+ | Copying `loaderData` or basket into `useState` | read directly; derive with plain expressions |
98
+ | Filters in `useState` | `useSearchParams` |
99
+ | Reading cookies in components | loader returns the value, or use the provider hook |
100
+ | New context for one component's state | `useState` in that component |
101
+ | Adding Zustand or Redux | the mechanisms above; check `storefront-next:sfnext-overview` for conventions |
108
102
 
109
- ## When to Use Each Mechanism
103
+ ## Finding more
110
104
 
111
- | Scenario | Use |
112
- | ----------------------------- | -------------------------------------------------------- |
113
- | Product data on page load | `loader` |
114
- | Shopping cart badge count | Basket provider hooks (`useBasket`, `useBasketSnapshot`) |
115
- | Complex extension UI workflow | Zustand store |
116
- | Search results | `loader` |
117
- | Add to cart | Server `action` + resource update |
105
+ `AGENTS.md` ("Key Documentation"), `docs/README-STATE.md`, `docs/README-DATA.md`. `b2c docs search "storefront next state"` or the `docs_search` MCP tool.
118
106
 
119
107
  ## Related Skills
120
108
 
121
- - `storefront-next:sfnext-data-fetching` - Server-side data loading with loaders (NOT client state)
122
- - `storefront-next:sfnext-authentication` - Auth state management
123
- - `storefront-next:sfnext-components` - Using store data in components
109
+ - `storefront-next:sfnext-data-fetching` - loaders, actions, fetchers
110
+ - `storefront-next:sfnext-revalidation` - when providers make a re-run unnecessary
111
+ - `storefront-next:sfnext-performance` - hydration stability and render scope
112
+ - `storefront-next:sfnext-authentication` - `useAuth` and session lifecycle
113
+ - `storefront-next:sfnext-commerce-features` - cart, wishlist, checkout features
114
+ - `storefront-next:sfnext-components` - component conventions
@@ -0,0 +1,45 @@
1
+ # State patterns and anti-patterns
2
+
3
+ ## Render scope should not exceed data-change scope
4
+
5
+ If a value changes often but only event handlers read it, do not store it in state or Context. Keep it in a `useRef` or read it at call time (for example `window.matchMedia(...).matches` inside the handler). Every state change re-renders the component and all consumers of a Context value.
6
+
7
+ Hidden subscribers: a component that subscribes to a store but renders nothing visible (an invisible drawer) still re-renders. Return `null` early or move the subscription to the component that renders the content.
8
+
9
+ ## Provider value stability
10
+
11
+ ```tsx
12
+ const value = useMemo(() => ({ items, isOpen }), [items, isOpen]);
13
+ const actions = useMemo(() => ({ open, close }), [open, close]); // useCallback inside
14
+ return (
15
+ <StateContext.Provider value={value}>
16
+ <ActionsContext.Provider value={actions}>{children}</ActionsContext.Provider>
17
+ </StateContext.Provider>
18
+ );
19
+ ```
20
+
21
+ Check each field read during render: if a consumer uses only `isOpen`, it still re-renders when `items` changes with one combined context. Split or use a selector.
22
+
23
+ ## Manager components
24
+
25
+ A component that only subscribes to data to perform a side effect (for example syncing the basket cookie, like `BasketCookieReconciler`) should render `null` and live as a leaf so the parent is not re-rendered.
26
+
27
+ ## Server versus client snapshots
28
+
29
+ For `useSyncExternalStore`, `getServerSnapshot` must equal what the first client render will read, or React warns and re-renders. Read browser-only data (storage, matchMedia) after mount in an effect and then write it into the store.
30
+
31
+ ## URL state
32
+
33
+ Prefer URL state for anything a shopper might share or reload. Changing search params triggers navigation and loader re-run; see `storefront-next:sfnext-revalidation` to skip re-runs for client-only params. Use `setSearchParams(next, { replace: true, preventScrollReset: true })` for high-frequency updates such as typing.
34
+
35
+ ## Cookies
36
+
37
+ Cookies written by the server are set from `action` or middleware responses. Use the helpers in `src/lib/cookie-utils.server.ts` (site-scoped names, domain resolution, `createCookie`). Do not store personal data or tokens in cookies readable by scripts. Consent state is covered by `storefront-next:sfnext-analytics-consent`.
38
+
39
+ ## Derived state
40
+
41
+ Compute derived values during render. `useMemo` is for expensive pure computations of UI-derived values; it does not fix transforming loader data in render (do that in the loader) and must not wrap promises.
42
+
43
+ ## Testing state
44
+
45
+ Render with the real provider in tests, or mock the hook module (`vi.mock('@/providers/basket')`). For stores, call the exported setters inside `act` and reset module state between tests. See `storefront-next:sfnext-testing`.