@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
@@ -1,190 +1,140 @@
1
1
  ---
2
2
  name: sfnext-data-fetching
3
- description: Implement server-side data fetching in Storefront Next using loaders, actions, and useScapiFetcher. Use when writing loader functions, making SCAPI calls, handling form submissions, or implementing interactive data fetching. Covers synchronous loaders, streaming patterns, createApiClients, and parallel requests. NOT for client-side Zustand state — see sfnext-state-management.
3
+ description: >-
4
+ Load and mutate data in a Storefront Next project: route loaders that call SCAPI through createApiClients from @/lib/api-clients.server, critical versus streamed (deferred) data, createBasketAction and BasketAction for cart actions, createActionError and ErrorCode, data() responses, useFetcher and the useScapiFetcher hook with its server allowlist, request-scoped dedupe and MRT timeouts, non-personalized SCAPI responses, shopper context, and custom API clients. Use for "fetch products in a loader", "stream data", "add a cart action", "call SCAPI from a component", "resource route", "NormalizedApiError", or "loader blocks the page". Do not use for route files or links (use `storefront-next:sfnext-routing`), when loaders re-run after actions (use `storefront-next:sfnext-revalidation`), Suspense/LCP tuning (use `storefront-next:sfnext-performance`), or defining SCAPI custom APIs (use `storefront-next:sfnext-scapi`).
4
5
  ---
5
6
 
6
- # Data Fetching Skill
7
+ # Storefront Next Data Fetching
7
8
 
8
- This skill covers server-side data fetching patterns in Storefront Next — loaders, actions, and the useScapiFetcher hook.
9
+ All data comes from the server. Loaders and actions run on the server with the shopper's session; the browser never calls SCAPI directly. Your project ships `docs/README-DATA.md`, `docs/README-SUSPENSE.md`, `docs/README-SCAPI-NON-PERSONALIZED-RESPONSES.md` and `docs/README-SHOPPER-CONTEXT.md`, plus the "Performance & Data Rules" in `AGENTS.md`; this skill is the quick path, those are authoritative.
9
10
 
10
- ## Overview
11
+ ## The rules (same as AGENTS.md)
11
12
 
12
- Storefront Next mandates **server-only data loading**. All SCAPI requests execute on the MRT server, never in the browser. Three mechanisms exist:
13
+ 1. Fetch on the server in `loader` (reads) and `action` (writes). There is no `clientLoader` or `clientAction`.
14
+ 2. Classify every piece of data:
15
+ - **Critical** (needed for SEO, LCP, layout stability or the HTTP status): `await` it in the loader.
16
+ - **Non-critical** (below the fold, recommendations, reviews, secondary panels): start the request, do not await it, and return the unresolved promise so it streams.
17
+ - **Interaction-driven** (only after a click, hover or input): fetch on demand with a fetcher.
18
+ 3. Never block a loader on non-critical data.
19
+ 4. Pass the promise through `loaderData` and read it under its own `<Suspense>` with `use()` or `<Await>`. Keep the promise identity stable (compose it in the loader, never `Promise.all` or `.then` in render).
20
+ 5. Export `shouldRevalidate` on routes whose loaders depend on URL filters (see `storefront-next:sfnext-revalidation`).
13
21
 
14
- | Mechanism | When It Runs | Use Case |
15
- |-----------|-------------|----------|
16
- | `loader` | Route navigation | Initial page data |
17
- | `action` | Form submission | Mutations (add to cart, update profile) |
18
- | `useScapiFetcher` | User interaction | On-demand fetching (search suggestions, infinite scroll) |
22
+ ## Loader with critical and streamed data
19
23
 
20
- ## Loader Patterns
24
+ ```tsx
25
+ import { Suspense } from 'react';
26
+ import { Await } from 'react-router';
27
+ import type { Route } from './+types/_app.example';
28
+ import { createApiClients } from '@/lib/api-clients.server';
29
+ import { fetchProductById } from '@/lib/api/products.server';
30
+ import { NormalizedApiError } from '@/lib/api/normalized-api-error';
21
31
 
22
- Loaders can be **synchronous** (returning promises for streaming) or **async** (awaiting critical data). Choose based on what the page needs:
32
+ export async function loader({ context, params }: Route.LoaderArgs) {
33
+ const clients = createApiClients(context);
23
34
 
24
- - **Sync loader** — Returns promises directly. Enables streaming SSR: the shell renders immediately while data streams in. Best when all data can render progressively.
25
- - **Async loader** — Awaits critical data before rendering. Use when data is required for SEO or the page shell (e.g., category name in breadcrumbs). Non-critical data can still be returned as promises for streaming.
35
+ // Non-critical: start now, do not await.
36
+ const related = clients.shopperSearch
37
+ .productSearch({ params: { query: { q: 'shirt', limit: 8 } } })
38
+ .then(({ data }) => data.hits ?? []);
26
39
 
27
- ```typescript
28
- // Sync — full streaming (all data renders progressively)
29
- export function loader({ params, context }: LoaderFunctionArgs): ProductPageData {
30
- const clients = createApiClients(context);
31
- return {
32
- product: clients.shopperProducts.getProduct({
33
- params: { path: { id: params.productId } }
34
- }).then(({ data }) => data),
35
- reviews: clients.shopperProducts.getReviews({
36
- params: { path: { id: params.productId } }
37
- }).then(({ data }) => data),
38
- };
40
+ // Critical: needed for status, SEO and LCP.
41
+ try {
42
+ const product = await fetchProductById(context, params.id ?? '', { expand: ['images', 'prices'] });
43
+ if (!product) throw new Response('Not found', { status: 404 });
44
+ return { product, related };
45
+ } catch (e) {
46
+ if (e instanceof NormalizedApiError && e.status) throw new Response(e.message, { status: e.status });
47
+ throw e;
48
+ }
39
49
  }
40
50
 
41
- // Async — await critical data, stream the rest (mixed strategy)
42
- export async function loader({ params, context }: LoaderFunctionArgs): Promise<CategoryPageData> {
43
- const clients = createApiClients(context);
44
-
45
- // Await critical data needed for page shell/SEO
46
- const category = await clients.shopperProducts.getCategory({
47
- params: { path: { id: params.categoryId } }
48
- }).then(({ data }) => data);
49
-
50
- return {
51
- category, // Resolved immediately
52
- products: clients.shopperSearch.productSearch({
53
- params: { query: { q: '', refine: { cgid: params.categoryId } } }
54
- }).then(({ data }) => data), // Streamed
55
- };
51
+ export default function Example({ loaderData }: Route.ComponentProps) {
52
+ return (
53
+ <>
54
+ <h1>{loaderData.product.name}</h1>
55
+ <Suspense fallback={<div className="h-40" aria-busy="true" />}>
56
+ <Await resolve={loaderData.related}>{(hits) => <ul>{hits.map((h) => <li key={h.productId}>{h.productName}</li>)}</ul>}</Await>
57
+ </Suspense>
58
+ </>
59
+ );
56
60
  }
57
61
  ```
58
62
 
59
- ## When to Use Each Pattern
60
-
61
- | Pattern | When | Example |
62
- |---------|------|---------|
63
- | Sync (full streaming) | All data can render progressively | Product page with reviews |
64
- | Async (await critical) | SEO-critical data needed for page shell | Category page (needs category name) |
65
- | Mixed | Some data critical, some deferrable | Category name (await) + product grid (stream) |
66
-
67
- See [Loader Patterns Reference](references/LOADER-PATTERNS.md) for more patterns and data flow diagrams.
63
+ Real precedent: `src/routes/_app.p.$.tsx` awaits the product (404 becomes `throw new Response(..., { status: 404 })`) and streams the Page Designer page, schema and extras; `src/components/product-grid/deferred.tsx` is the streamed-grid pattern.
68
64
 
69
- ## Action Functions
65
+ ## SCAPI clients
70
66
 
71
- Handle mutations (form submissions, cart updates):
67
+ `createApiClients(context)` from `@/lib/api-clients.server` returns `AppClients`: every generated Shopper API client (`shopperProducts`, `shopperSearch`, `shopperBasketsV2`, `shopperCustomers`, `shopperOrders`, `shopperLogin`, and more) plus generated clients for your custom APIs (`@/scapi/custom-clients`). Call shape:
72
68
 
73
- ```typescript
74
- import { data, redirect } from 'react-router';
75
-
76
- export async function action({ request, context }: ActionFunctionArgs) {
77
- const formData = await request.formData();
78
- const productId = formData.get('productId') as string;
79
-
80
- const clients = createApiClients(context);
81
-
82
- try {
83
- await clients.shopperBasketsV2.addItemToBasket({
84
- params: {
85
- path: { basketId },
86
- body: { productId, quantity: 1 },
87
- },
88
- });
89
- return data({ success: true });
90
- } catch (error) {
91
- return data({ success: false, error: error.message }, { status: 400 });
92
- }
93
- }
69
+ ```ts
70
+ const { data } = await clients.shopperBasketsV2.addItemToBasket({
71
+ params: { path: { basketId }, query: {} },
72
+ body: [{ productId, quantity: 1 }], // body is a sibling of params; this endpoint takes an array
73
+ });
94
74
  ```
95
75
 
96
- ## useScapiFetcher — Interactive Data Fetching
97
-
98
- For on-demand data fetching triggered by user interactions (after page load):
76
+ Results are `{ data }`; failures throw. Prefer the thin wrappers in `src/lib/api/*.server.ts` (`fetchProductById`, `fetchProductsByIds` which chunks to the 24-id limit, category, search, order, customer and basket helpers): they log and rethrow as `NormalizedApiError` (`@/lib/api/normalized-api-error`, with `.status` and `.cause`). Add new wrappers there rather than calling clients inline in many routes.
99
77
 
100
- ```typescript
101
- import { useScapiFetcher } from '@/hooks/use-scapi-fetcher';
78
+ The clients already wrap `fetch` with request-scoped GET/HEAD dedupe (identical calls in one request share one response; any mutation clears the cache), a hard timeout from the `MRT_REQUEST_TIMEOUT` environment variable when set, and a health observer that logs 429 and load-status headers. Do not re-implement them. More: [API-CLIENTS.md](references/API-CLIENTS.md).
102
79
 
103
- export function useSearchSuggestions({ q, limit, currency }) {
104
- const parameters = useMemo(
105
- () => ({ params: { query: { q, limit, currency } } }),
106
- [q, limit, currency]
107
- );
80
+ Trim payloads: pass only the `expand`/`select` values you render. Availability is cached about 60 seconds and prices/promotions about 15 minutes, so short-TTL data is a good candidate for streaming. Shopper-agnostic responses can be cached using the policy in `src/lib/scapi/non-personalized-response-policy.server.ts` (see the shipped README-SCAPI-NON-PERSONALIZED-RESPONSES); request `personalized: 'none'` only where the response truly is the same for all shoppers, as the navigation loader in `_app.tsx` does.
108
81
 
109
- const fetcher = useScapiFetcher(
110
- 'shopperSearch',
111
- 'getSearchSuggestions',
112
- parameters
113
- );
82
+ ## Mutations: actions
114
83
 
115
- const refetch = useCallback(async () => {
116
- await fetcher.load();
117
- }, [fetcher]);
84
+ Prefer an `action.*` route and a `<Form>` (navigating) or `useFetcher` (non-navigating).
118
85
 
119
- return {
120
- data: fetcher.data,
121
- isLoading: fetcher.state === 'loading',
122
- refetch,
123
- };
124
- }
125
- ```
86
+ Basket mutations use the factory, which loads the basket, parses `FormData`, catches errors and wraps the result:
126
87
 
127
- See [SCAPI Fetcher Reference](references/SCAPI-FETCHER.md) for the complete useScapiFetcher API.
88
+ ```ts
89
+ // src/routes/action.example-remove-item.ts
90
+ import { data } from 'react-router';
91
+ import { BasketAction, createBasketAction } from '@/lib/cart/basket-action.server';
92
+ import { createActionError } from '@/lib/action-error-helpers.server';
93
+ import { ErrorCode } from '@/lib/error-codes';
128
94
 
129
- ## API Client Usage
95
+ export const action = createBasketAction(
96
+ { method: 'POST', action: BasketAction.CartItemRemove, parse: (fd) => ({ itemId: String(fd.get('itemId') ?? '') }) },
97
+ async ({ input, basketId, clients }) => {
98
+ if (!input.itemId) {
99
+ return data({ success: false, error: createActionError({ code: ErrorCode.REQUIRED_FIELD, message: 'itemId is required' }) }, { status: 400 });
100
+ }
101
+ const { data: basket } = await clients.shopperBasketsV2.removeItemFromBasket({ params: { path: { basketId, itemId: input.itemId } } });
102
+ return basket; // factory returns { success: true, basket } and syncs the basket resource
103
+ }
104
+ );
105
+ ```
130
106
 
131
- Always use `createApiClients(context)` in loaders and actions:
107
+ Return the updated `Basket` for success. Return `data(payload, { status })` for validation errors (use `data()` from `react-router`, not `Response.json`). Thrown SCAPI 4xx errors pass their status through; others become 500. Available `BasketAction` values are listed in `src/lib/cart/basket-action.server.ts`. See the existing `action.cart-item-*.tsx` files. Details and non-basket actions: [ACTIONS.md](references/ACTIONS.md).
132
108
 
133
- ```typescript
134
- import { createApiClients } from '@/lib/api-clients';
109
+ ## Fetching from components
135
110
 
136
- export function loader({ context }: LoaderFunctionArgs) {
137
- const clients = createApiClients(context);
111
+ - Use `useFetcher` against your own `action.*`/`resource.*` routes (`resourceRoutes` in `@/route-paths`).
112
+ - Use `useScapiFetcher(client, method, { params, body })` from `@/hooks/use-scapi-fetcher` for a small allowlisted set of Shopper calls without writing a route. It returns `.load()`, `.submit(payload)`, `.data`, `.errors`, `.success`. The server enforces an allowlist in `src/lib/scapi/resource-policy.ts` (for example `shopperProducts.getProduct`, `shopperBasketsV2.getBasket`, `shopperSearch.getSearchSuggestions`, and selected `shopperCustomers` address and profile mutations). Anything else needs a dedicated route. See [SCAPI-FETCHER.md](references/SCAPI-FETCHER.md).
113
+ - Do not fetch in `useEffect` on mount what the loader could fetch (see the performance review checklist in `storefront-next:sfnext-performance`).
114
+ - Fetchers and raw `fetch` calls that do not go through a submission do not trigger revalidation; actions do, for every active loader.
138
115
 
139
- clients.shopperProducts.getProduct({...});
140
- clients.shopperCustomers.getCustomer({...});
141
- clients.shopperBasketsV2.getBasket({...});
142
- clients.shopperSearch.productSearch({...});
143
- clients.shopperOrders.getOrder({...});
144
- }
145
- ```
116
+ ## Checklist
146
117
 
147
- ## Parallel vs Sequential Requests
118
+ 1. Can the loader fetch this at request time? If yes, do it there.
119
+ 2. Is it critical? `await`; otherwise return the promise with its own Suspense and a sized skeleton.
120
+ 3. Did you request only the fields you render?
121
+ 4. Mutation errors: `createActionError` with an `ErrorCode`, return with `data(..., { status })`.
122
+ 5. New shared fetch logic goes in `src/lib/api/*.server.ts` with a test (`storefront-next:sfnext-testing`).
123
+ 6. Run `pnpm typecheck` and `pnpm test`.
148
124
 
149
- ```typescript
150
- // GOOD — Parallel requests (all start simultaneously)
151
- export function loader({ context }: LoaderFunctionArgs) {
152
- const clients = createApiClients(context);
153
- return {
154
- product: clients.shopperProducts.getProduct({...}).then(({ data }) => data),
155
- reviews: clients.shopperProducts.getReviews({...}).then(({ data }) => data),
156
- recommendations: clients.shopperProducts.getRecommendations({...}).then(({ data }) => data),
157
- };
158
- }
159
-
160
- // AVOID — Sequential awaits of independent requests (unnecessarily slow)
161
- export async function loader({ context }: LoaderFunctionArgs) {
162
- const clients = createApiClients(context);
163
- const product = await clients.shopperProducts.getProduct({...}); // Waits...
164
- const reviews = await clients.shopperProducts.getReviews({...}); // Then waits again
165
- return { product, reviews };
166
- }
167
- ```
125
+ Deeper: [LOADERS.md](references/LOADERS.md).
168
126
 
169
- ## Common Pitfalls
127
+ ## Finding more
170
128
 
171
- | Pitfall | Problem | Solution |
172
- |---------|---------|----------|
173
- | Awaiting all data | Blocks page transition unnecessarily | Only await SEO-critical data; stream the rest |
174
- | Client loaders | Not permitted in Storefront Next | Use server `loader` or `useScapiFetcher` |
175
- | Sequential `await` | Slow data loading | Return promises in parallel |
176
- | Missing `context` in `getConfig()` | Config unavailable | Pass `context` in server loaders: `getConfig(context)` |
129
+ Open `AGENTS.md` ("Key Documentation") and `docs/README-DATA.md` in your project. Search product docs with `b2c docs search "<term>"` or the `docs_search` MCP tool.
177
130
 
178
131
  ## Related Skills
179
132
 
180
- - `storefront-next:sfnext-scapi-management` - Adding/removing SCAPI clients and discovering API shapes
181
- - `storefront-next:sfnext-custom-apis` - Calling custom API endpoints from loaders/actions
182
- - `storefront-next:sfnext-routing` - Route file conventions and module exports
183
- - `storefront-next:sfnext-components` - Rendering loader data with createPage and Suspense
184
- - `storefront-next:sfnext-state-management` - Client-side Zustand stores (NOT data fetching)
185
- - `storefront-next:sfnext-authentication` - Auth context in loaders
186
-
187
- ## Reference Documentation
188
-
189
- - [Loader Patterns Reference](references/LOADER-PATTERNS.md) - Data flow diagrams and advanced patterns
190
- - [SCAPI Fetcher Reference](references/SCAPI-FETCHER.md) - Complete useScapiFetcher API and examples
133
+ - `storefront-next:sfnext-routing` - route files and links
134
+ - `storefront-next:sfnext-revalidation` - avoid wasted loader re-runs after actions
135
+ - `storefront-next:sfnext-performance` - Suspense placement, LCP, review checklist
136
+ - `storefront-next:sfnext-state-management` - basket provider and client state
137
+ - `storefront-next:sfnext-scapi` - SCAPI access and custom APIs
138
+ - `storefront-next:sfnext-authentication` - sessions behind loaders
139
+ - `b2c-cli:b2c-scapi-custom` - inspect custom API endpoints
140
+ - `b2c:b2c-custom-api-development` - build a custom API
@@ -0,0 +1,5 @@
1
+ [
2
+ {"query": "Add a loader on my Storefront Next page that awaits the product and streams recommendations so the page doesn't block", "should_trigger": true},
3
+ {"query": "How do I write a createBasketAction handler that returns a validation error?", "should_trigger": true},
4
+ {"query": "My product grid re-fetches every time I add an item to the cart; how do I stop loaders re-running after actions?", "should_trigger": false}
5
+ ]
@@ -0,0 +1,53 @@
1
+ # Actions and errors
2
+
3
+ ## Where to put a mutation
4
+
5
+ Create `src/routes/action.<name>.ts(x)` exporting only `action`. Add an entry to `resourceRoutes` in `src/route-paths.ts`. The `/action/**` paths are excluded from the site prefix. Use `<Form method="post" action={resourceRoutes.x}>` when the user should navigate or when a native form must work without JavaScript; use `useFetcher` for in-place changes (add to cart, quantity changes, toggles).
6
+
7
+ ## Basket actions: `createBasketAction`
8
+
9
+ `import { BasketAction, createBasketAction } from '@/lib/cart/basket-action.server'`
10
+
11
+ ```ts
12
+ createBasketAction(
13
+ { method: 'POST' | 'PATCH', action: BasketAction.X, parse: (fd: FormData) => input },
14
+ async ({ input, basketId, basket, context, clients, logger }) => Basket | ReturnType<typeof data>
15
+ )
16
+ ```
17
+
18
+ - The factory enforces the HTTP method, ensures a basket exists, parses form data, runs the handler and converts the result.
19
+ - Returning a `Basket` yields `{ success: true, basket }` (status 200) and updates the basket resource through `updateBasketResource` so the provider picks it up.
20
+ - Returning `data({ success: false, error }, { status })` sends validation errors.
21
+ - Throwing yields `{ success: false, error }`; a SCAPI 4xx keeps its status, anything else is 500.
22
+ - Enum values: CartItemRemove, CartItemUpdate, CartItemAdd, CartSetAdd, CartBundleAdd, CartBundleUpdate, PromoCodeAdd, PromoCodeRemove, BonusProductAdd, SwatchOrder. Add new ones in the same file when a new kind of basket mutation needs its own name.
23
+ - Request bodies for some calls are arrays (`addItemToBasket` takes `[payload]`).
24
+
25
+ Read `action.cart-item-add.tsx`, `action.cart-item-update.tsx` and `action.cart-item-remove.tsx` for complete examples.
26
+
27
+ ## Other actions
28
+
29
+ For non-basket work (customer, wishlist, consent, checkout), write a plain `action({ request, context })`: read `await request.formData()`, call `createApiClients(context)` or a `src/lib/api/*.server.ts` wrapper, and return `data(...)`. Check authentication with `getAuth(context)` where needed (`NOT_AUTHENTICATED`).
30
+
31
+ ## Error shape
32
+
33
+ ```ts
34
+ import { createActionError } from '@/lib/action-error-helpers.server';
35
+ import { ErrorCode } from '@/lib/error-codes';
36
+
37
+ createActionError({ code: ErrorCode.INVALID_INPUT, message: 'Invalid quantity' });
38
+ createActionError({ error: caughtError }); // normalizes SCAPI/unknown errors
39
+ ```
40
+
41
+ `ErrorCode` members: NOT_FOUND, NOT_AUTHENTICATED, NOT_AUTHORIZED, INVALID_INPUT, REQUIRED_FIELD, CONFLICT, EXPIRED, OPERATION_FAILED, OUT_OF_STOCK, RATE_LIMITED, METHOD_NOT_ALLOWED, UNKNOWN, SCAPI_UNSUPPORTED, CONFIGURATION_ERROR.
42
+
43
+ Response types live in `@/routes/types/action-responses` (`ActionResponse<T>`, `BasketActionResponse`). Return status codes with `data(payload, { status })` from `react-router`.
44
+
45
+ ## Client side
46
+
47
+ - `useItemFetcher({ itemId, componentName })` (`@/hooks/use-item-fetcher`) gives per-line-item fetcher keys so a row shows its own pending state.
48
+ - Optimistic UI: read `fetcher.formData`, `useNavigation`, or `useOptimistic`.
49
+ - Side effects after a fetcher finishes: `useFetcherEffect` (`@/hooks/use-fetcher-effect`) or `useScapiFetcherEffect` (`@/hooks/use-scapi-fetcher-effect`) instead of hand-written `useEffect` chains.
50
+
51
+ ## After an action
52
+
53
+ React Router revalidates every active loader by default. Decide which should re-run and declare it with `shouldRevalidate` or tags: `storefront-next:sfnext-revalidation`.
@@ -0,0 +1,34 @@
1
+ # API clients
2
+
3
+ `createApiClients(context)` (`@/lib/api-clients.server`) builds, per request, the typed clients used in loaders and actions. Cost is low; call it in each function that needs it.
4
+
5
+ ## What you get
6
+
7
+ `AppClients` (type in `@/scapi/custom-clients`) is the generated Shopper API clients merged with clients generated for your custom APIs. Authentication (shopper access token), `siteId`, locale and currency come from the request context. The `@/scapi` barrel exports schema and operation types, for example `ShopperProducts.schemas['Product']` and `ApiError`.
8
+
9
+ ## Fetch layers
10
+
11
+ Each client uses `dedupe(timeout(healthObserver(originBoundFetch)))`:
12
+
13
+ | Layer | Behavior |
14
+ |---|---|
15
+ | dedupe | within one request, identical GET/HEAD calls share one promise; any non-GET call clears the whole registry |
16
+ | timeout | aborts calls after `MRT_REQUEST_TIMEOUT` ms when that variable is set (no-op otherwise) |
17
+ | health observer | logs 429 and SCAPI load-status signals |
18
+
19
+ Consequences: it is safe for several components' loaders to request the same product; do not add your own in-memory cache keyed by request; after a write in the same request, re-reads are real calls.
20
+
21
+ ## Errors
22
+
23
+ Clients throw. In `src/lib/api/*.server.ts`, catch and `throw new NormalizedApiError(error)`; route code checks `e.status`. Map 404 to a `Response` with status 404; let unexpected errors reach the route `ErrorBoundary`.
24
+
25
+ ## Custom APIs
26
+
27
+ Generated custom-API clients appear on `AppClients` (for example a notification client). To add one: define the API with `storefront-next:sfnext-scapi` guidance, generate the client as described there, and call it as `clients.<name>.<operation>({ params, body })`.
28
+
29
+ ## Request shaping checklist
30
+
31
+ - `expand`/`select` only what the UI renders.
32
+ - `fetchProductsByIds` chunks at 24 ids; do not loop single `getProduct` calls.
33
+ - Start independent calls before awaiting (parallel), but keep non-critical calls un-awaited.
34
+ - Pass `personalized: 'none'` only for shopper-independent data, following `docs/README-SCAPI-NON-PERSONALIZED-RESPONSES.md`.
@@ -0,0 +1,73 @@
1
+ # Loader patterns
2
+
3
+ See also `docs/README-DATA.md`, `docs/README-SUSPENSE.md` and the "Performance & Data Rules" in `AGENTS.md` in your project.
4
+
5
+ ## Critical versus streamed
6
+
7
+ | Data | Treatment |
8
+ |---|---|
9
+ | Entity that decides status (product, category, order) | `await`; map SCAPI 404 to `throw new Response(msg, { status: 404 })` |
10
+ | Data visible in the first viewport, SEO tags, JSON-LD source | `await` |
11
+ | Page Designer page for the LCP region | `await` the page and render `<Region critical>` (see `storefront-next:sfnext-page-designer`) |
12
+ | Below the fold, recommendations, reviews, secondary panels | return the promise |
13
+ | Short-TTL data (availability about 60 s) that is not the LCP | prefer streaming |
14
+ | Needs a user gesture | fetcher, not loader |
15
+
16
+ Start every independent request before the first `await` so they run in parallel:
17
+
18
+ ```ts
19
+ const clients = createApiClients(context);
20
+ const extrasPromise = loadExtras(context, id); // started, not awaited
21
+ const product = await fetchProductById(context, id); // critical
22
+ return { product, extras: extrasPromise };
23
+ ```
24
+
25
+ ## Stable promises
26
+
27
+ Compose dependent work inside the loader (`extrasPromise.then(...)` there, never in render). A new promise object per render restarts Suspense and flashes the fallback. Do not wrap promises in `useMemo`. If a component must derive one, pin it with `useState(() => ...)` or re-pin via `useRef` keyed on the inputs. Full rules in `docs/README-SUSPENSE.md`.
28
+
29
+ A streamed promise that can reject needs an error path: use `<Await errorElement={...}>` or make the loader promise resolve to a fallback value (`.catch(() => [])`) when degraded output is acceptable, and log inside the loader.
30
+
31
+ ## Consuming a promise
32
+
33
+ ```tsx
34
+ <Suspense fallback={<RecommendationsSkeleton />}>
35
+ <Await resolve={loaderData.recommendations} errorElement={null}>
36
+ {(items) => <Recommendations items={items} />}
37
+ </Await>
38
+ </Suspense>
39
+ ```
40
+
41
+ - One `<Suspense>` per independent async operation; siblings may resolve independently.
42
+ - The skeleton must reserve the final height (no `fallback={null}` above the fold).
43
+ - A component that reads a promise with `use()` must have a `<Suspense>` ancestor, otherwise it blocks the first byte.
44
+ - For product listings reuse `DeferredProductGrid` (`@/components/product-grid/deferred`).
45
+
46
+ ## Shared layout data
47
+
48
+ Layout loaders (for example `_app.tsx` navigation) stream their data and child routes read it with `useRouteLoaderData('routes/_app')`. Put data that many routes need in the lowest common layout, not in each page.
49
+
50
+ ## Request context
51
+
52
+ Loaders receive `context` (`Route.LoaderArgs`). Useful accessors:
53
+
54
+ | Need | Import |
55
+ |---|---|
56
+ | Logger | `getLogger` from `@/lib/logger.server` |
57
+ | Site, locale, currency | `siteContext` from `@salesforce/storefront-next-runtime/site-context` via `context.get(siteContext)` |
58
+ | Config | `getConfig` from `@salesforce/storefront-next-runtime/config` |
59
+ | Session | `getAuth` from `@/middlewares/auth.server` |
60
+ | Basket | `getBasket`, `getBasketSnapshot`, `ensureBasketId` from `@/middlewares/basket.server` |
61
+
62
+ Middleware order is defined in `src/root.tsx` (`export const middleware`); add new request-wide state there with `createContext`/middleware instead of re-deriving it in each loader.
63
+
64
+ ## Shopper context and personalization
65
+
66
+ Shopper context (customer segments, source codes, custom qualifiers) is applied by `shopper-context` middleware and read in components with `useShopperContext`. Read `docs/README-SHOPPER-CONTEXT.md` before changing it. Personalized endpoints must not be cached as shared responses.
67
+
68
+ ## Pitfalls
69
+
70
+ - `Promise.all([...])` over critical and non-critical together re-blocks the loader; await only the critical set.
71
+ - Mutating `loaderData` on the client is unsupported; derive in the loader.
72
+ - Do not add `clientLoader`.
73
+ - Shaping or normalizing data in render (lookup maps, chained passes) belongs in the loader.
@@ -1,93 +1,39 @@
1
- # SCAPI Fetcher Reference
1
+ # `useScapiFetcher`
2
2
 
3
- ## How useScapiFetcher Works
3
+ `import { useScapiFetcher } from '@/hooks/use-scapi-fetcher'`
4
4
 
5
- ```
6
- Component calls useScapiFetcher()
7
- ↓
8
- Hook builds URL: /resource/api/client/{encoded-params}
9
- ↓
10
- fetcher.load() or fetcher.submit()
11
- ↓
12
- resource.api.client.$resource.ts loader/action runs ON SERVER
13
- ↓
14
- createApiClients(context) makes SCAPI call (server-side)
15
- ↓
16
- JSON response returned to component
17
- ```
18
-
19
- Even though `useScapiFetcher` is called from the browser, the actual SCAPI requests happen **on the server** through the resource route, keeping credentials secure.
20
-
21
- ## API
5
+ A typed wrapper over React Router's `useFetcher` that calls a Shopper client method through a single resource route (`src/routes/resource.api.client.$resource.ts`). The request is encoded (base64url of `[client, method, options]`) into `/resource/api/client/:resource`, executed on the server, and the SCAPI `data` is returned unwrapped.
22
6
 
23
- ```typescript
24
- const fetcher = useScapiFetcher(
25
- clientName, // SCAPI client: 'shopperSearch', 'shopperProducts', etc.
26
- methodName, // Method: 'getSearchSuggestions', 'productSearch', etc.
27
- parameters // SCAPI parameters object
28
- );
7
+ ```tsx
8
+ const product = useScapiFetcher('shopperProducts', 'getProduct', {
9
+ params: { path: { id: variantId }, query: { expand: ['availability', 'prices'] } },
10
+ });
29
11
 
30
- // Properties
31
- fetcher.data // Response data (undefined until loaded)
32
- fetcher.state // 'idle' | 'loading' | 'submitting'
33
- fetcher.load() // Trigger a GET request
34
- fetcher.submit() // Trigger a POST request
12
+ useEffect(() => {
13
+ if (variantId && product.state === 'idle' && !product.data && !product.errors) void product.load();
14
+ }, [variantId, product]); // keep deps stable; see checklist
35
15
  ```
36
16
 
37
- ## loader vs useScapiFetcher
17
+ Returned object: `.load()` (GET), `.submit(payload, opts)` (mutation), `.data`, `.errors`, `.success`, plus the fetcher fields such as `.state`.
38
18
 
39
- | Scenario | Use |
40
- |----------|-----|
41
- | Load product data on page visit | `loader` |
42
- | Load checkout data | `loader` |
43
- | Search suggestions as user types | `useScapiFetcher` |
44
- | Update customer profile in modal | `useScapiFetcher` |
45
- | Load recommendations after page loads | `useScapiFetcher` |
46
- | Fetch bonus products when modal opens | `useScapiFetcher` |
47
- | Infinite scroll / Load more | `useScapiFetcher` |
19
+ Real users: `src/providers/basket.tsx` (`shopperBasketsV2.getBasket`) and `src/components/cart-item-modal/*` (`shopperProducts.getProduct`).
48
20
 
49
- ## Timeline Comparison
21
+ ## Server allowlist (`src/lib/scapi/resource-policy.ts`)
50
22
 
51
- ```
52
- loader (Server):
53
- [navigate] → [server fetch] → [stream to client]
54
- Data available: Streamed during render via Suspense
23
+ - Loaders: `shopperBasketsV2.getBasket`, `shopperProducts.getProduct`, `shopperProducts.getProducts`, `shopperSearch.getSearchSuggestions`.
24
+ - Actions: `shopperCustomers.createCustomerAddress`, `updateCustomerAddress`, `removeCustomerAddress`, `updateCustomer`, `updateCustomerPassword`.
55
25
 
56
- useScapiFetcher:
57
- [render] → [user action] → [fetch] → [re-render]
58
- Data available: AFTER user action, component re-renders
59
- ```
26
+ Everything else is rejected. `organizationId`, `siteId` and `locale` are set by the server, and request bodies and headers are sanitized. The older "helpers" overload is unsupported.
60
27
 
61
- ## Complete Example: Search Suggestions
28
+ Need something else (recommendations, category products, your own custom API)? Create a `resource.*` route with a `loader`. Pattern: same-origin check, input validation, `Cache-Control: no-store` for personalized output (`resource.recommendations.ts`, `resource.category-products.ts`). To allow another client call, change `resource-policy.ts` deliberately and add a test; do not widen it casually.
62
29
 
63
- ```typescript
64
- import { useScapiFetcher } from '@/hooks/use-scapi-fetcher';
65
- import { useMemo, useCallback } from 'react';
30
+ ## Related hooks
66
31
 
67
- export function useSearchSuggestions({ q, limit, currency }) {
68
- const parameters = useMemo(
69
- () => ({
70
- params: {
71
- query: { q, limit, currency }
72
- }
73
- }),
74
- [q, limit, currency]
75
- );
32
+ - `useScapiFetcherEffect(fetcher, { onSuccess, onError })` runs callbacks once per completed request.
33
+ - `useScapiFetchClient` (`@/hooks/use-scapi-fetch`) is a lower-level, non-fetcher variant for one-off calls.
76
34
 
77
- const fetcher = useScapiFetcher(
78
- 'shopperSearch',
79
- 'getSearchSuggestions',
80
- parameters
81
- );
35
+ ## When not to use it
82
36
 
83
- const refetch = useCallback(async () => {
84
- await fetcher.load();
85
- }, [fetcher]);
37
+ If the data is knowable at request time, fetch it in the loader. Mounting a component that fires `useScapiFetcher().load()` in an effect for data the route could have streamed adds a waterfall; see the performance review checklist in `storefront-next:sfnext-performance`.
86
38
 
87
- return {
88
- data: fetcher.data,
89
- isLoading: fetcher.state === 'loading',
90
- refetch
91
- };
92
- }
93
- ```
39
+ Calls made through `useScapiFetcher().load()` are fetcher loads, not submissions, so they do not revalidate other loaders. `.submit()` is a submission and does.