@salesforce/b2c-cli 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (421) hide show
  1. package/bin/dev.js +8 -8
  2. package/bin/run.js +5 -7
  3. package/content/guidance/b2c/b2c-business-manager-extensions/SKILL.md +361 -0
  4. package/content/guidance/b2c/b2c-business-manager-extensions/references/EXTENSIONS-XML.md +458 -0
  5. package/content/guidance/b2c/b2c-controllers/SKILL.md +301 -0
  6. package/content/guidance/b2c/b2c-controllers/references/CLASSIC-PATTERNS.md +335 -0
  7. package/content/guidance/b2c/b2c-controllers/references/SFRA-PATTERNS.md +400 -0
  8. package/content/guidance/b2c/b2c-custom-api-development/SKILL.md +281 -0
  9. package/content/guidance/b2c/b2c-custom-api-development/references/CONTRACT.md +142 -0
  10. package/content/guidance/b2c/b2c-custom-api-development/references/IMPLEMENTATION.md +153 -0
  11. package/content/guidance/b2c/b2c-custom-api-development/references/TESTING.md +118 -0
  12. package/content/guidance/b2c/b2c-custom-caches/SKILL.md +279 -0
  13. package/content/guidance/b2c/b2c-custom-job-steps/SKILL.md +520 -0
  14. package/content/guidance/b2c/b2c-custom-job-steps/references/CHUNK-ORIENTED.md +377 -0
  15. package/content/guidance/b2c/b2c-custom-job-steps/references/JOBS-XML.md +212 -0
  16. package/content/guidance/b2c/b2c-custom-job-steps/references/STEPTYPES-JSON.md +373 -0
  17. package/content/guidance/b2c/b2c-custom-job-steps/references/TASK-ORIENTED.md +344 -0
  18. package/content/guidance/b2c/b2c-custom-objects/SKILL.md +327 -0
  19. package/content/guidance/b2c/b2c-custom-objects/references/OCAPI-SEARCH.md +298 -0
  20. package/content/guidance/b2c/b2c-forms/SKILL.md +242 -0
  21. package/content/guidance/b2c/b2c-forms/references/FORM-XML.md +409 -0
  22. package/content/guidance/b2c/b2c-hooks/SKILL.md +500 -0
  23. package/content/guidance/b2c/b2c-hooks/references/OCAPI-SCAPI-HOOKS.md +403 -0
  24. package/content/guidance/b2c/b2c-hooks/references/ORDER-HOOK-LIFECYCLE.md +169 -0
  25. package/content/guidance/b2c/b2c-hooks/references/SYSTEM-HOOKS.md +433 -0
  26. package/content/guidance/b2c/b2c-isml/SKILL.md +320 -0
  27. package/content/guidance/b2c/b2c-isml/references/EXPRESSIONS.md +366 -0
  28. package/content/guidance/b2c/b2c-isml/references/TAGS.md +443 -0
  29. package/content/guidance/b2c/b2c-localization/SKILL.md +344 -0
  30. package/content/guidance/b2c/b2c-localization/references/PATTERNS.md +407 -0
  31. package/content/guidance/b2c/b2c-logging/SKILL.md +352 -0
  32. package/content/guidance/b2c/b2c-logging/references/LOG-FILES.md +282 -0
  33. package/content/guidance/b2c/b2c-metadata/SKILL.md +406 -0
  34. package/content/guidance/b2c/b2c-metadata/references/SYSTEM-OBJECTS.md +320 -0
  35. package/content/guidance/b2c/b2c-metadata/references/XML-EXAMPLES.md +366 -0
  36. package/content/guidance/b2c/b2c-onboarding/SKILL.md +154 -0
  37. package/content/guidance/b2c/b2c-ordering/SKILL.md +391 -0
  38. package/content/guidance/b2c/b2c-page-designer/SKILL.md +410 -0
  39. package/content/guidance/b2c/b2c-page-designer/references/ATTRIBUTE-TYPES.md +436 -0
  40. package/content/guidance/b2c/b2c-page-designer/references/META-DEFINITIONS.md +340 -0
  41. package/content/guidance/b2c/b2c-querying-data/SKILL.md +289 -0
  42. package/content/guidance/b2c/b2c-querying-data/references/PERFORMANCE-APIS.md +74 -0
  43. package/content/guidance/b2c/b2c-scapi-admin/SKILL.md +53 -0
  44. package/content/guidance/b2c/b2c-scapi-admin/references/CLIENT-EXAMPLES.md +440 -0
  45. package/content/guidance/b2c/b2c-scapi-admin/references/INTEGRATION-PATTERNS.md +518 -0
  46. package/content/guidance/b2c/b2c-scapi-admin/references/OAUTH-SCOPES.md +337 -0
  47. package/content/guidance/b2c/b2c-scapi-shopper/SKILL.md +56 -0
  48. package/content/guidance/b2c/b2c-scapi-shopper/references/CHECKOUT-FLOW.md +466 -0
  49. package/content/guidance/b2c/b2c-scapi-shopper/references/CLIENT-EXAMPLES.md +351 -0
  50. package/content/guidance/b2c/b2c-scapi-shopper/references/COMMON-PATTERNS.md +390 -0
  51. package/content/guidance/b2c/b2c-scapi-shopper/references/SCOPES.md +290 -0
  52. package/content/guidance/b2c/b2c-slas-auth-patterns/SKILL.md +420 -0
  53. package/content/guidance/b2c/b2c-slas-auth-patterns/references/PASSKEYS.md +126 -0
  54. package/content/guidance/b2c/b2c-slas-auth-patterns/references/SESSION-BRIDGE.md +267 -0
  55. package/content/guidance/b2c/b2c-slas-auth-patterns/references/TOKEN-LIFECYCLE.md +367 -0
  56. package/content/guidance/b2c/b2c-webservices/SKILL.md +318 -0
  57. package/content/guidance/b2c/b2c-webservices/references/FTP-SERVICES.md +524 -0
  58. package/content/guidance/b2c/b2c-webservices/references/HTTP-SERVICES.md +578 -0
  59. package/content/guidance/b2c/b2c-webservices/references/SERVICES-XML.md +351 -0
  60. package/content/guidance/b2c/b2c-webservices/references/SOAP-SERVICES.md +587 -0
  61. package/content/guidance/b2c-cli/b2c-am/SKILL.md +277 -0
  62. package/content/guidance/b2c-cli/b2c-bm-users-roles/SKILL.md +210 -0
  63. package/content/guidance/b2c-cli/b2c-cap/SKILL.md +131 -0
  64. package/content/guidance/b2c-cli/b2c-cip/SKILL.md +116 -0
  65. package/content/guidance/b2c-cli/b2c-cip/references/KNOWN_TABLES.md +105 -0
  66. package/content/guidance/b2c-cli/b2c-cip/references/SALES_ANALYSIS.md +50 -0
  67. package/content/guidance/b2c-cli/b2c-cip/references/STARTER_QUERIES.md +147 -0
  68. package/content/guidance/b2c-cli/b2c-code/SKILL.md +146 -0
  69. package/content/guidance/b2c-cli/b2c-config/SKILL.md +462 -0
  70. package/content/guidance/b2c-cli/b2c-content/SKILL.md +176 -0
  71. package/content/guidance/b2c-cli/b2c-debug/SKILL.md +138 -0
  72. package/content/guidance/b2c-cli/b2c-docs/SKILL.md +301 -0
  73. package/content/guidance/b2c-cli/b2c-ecdn/SKILL.md +135 -0
  74. package/content/guidance/b2c-cli/b2c-ecdn/references/ADVANCED.md +97 -0
  75. package/content/guidance/b2c-cli/b2c-ecdn/references/SECURITY.md +75 -0
  76. package/content/guidance/b2c-cli/b2c-import-set-migrations/SKILL.md +265 -0
  77. package/content/guidance/b2c-cli/b2c-job/SKILL.md +64 -0
  78. package/content/guidance/b2c-cli/b2c-job/references/EXPORT.md +121 -0
  79. package/content/guidance/b2c-cli/b2c-job/references/IMPORT.md +55 -0
  80. package/content/guidance/b2c-cli/b2c-job/references/RUN-AND-MONITOR.md +119 -0
  81. package/content/guidance/b2c-cli/b2c-logs/SKILL.md +249 -0
  82. package/content/guidance/b2c-cli/b2c-metrics/SKILL.md +315 -0
  83. package/content/guidance/b2c-cli/b2c-mrt/SKILL.md +207 -0
  84. package/content/guidance/b2c-cli/b2c-mrt/references/BUNDLE-COMMANDS.md +203 -0
  85. package/content/guidance/b2c-cli/b2c-mrt/references/ENVIRONMENT-COMMANDS.md +218 -0
  86. package/content/guidance/b2c-cli/b2c-mrt/references/PROJECT-COMMANDS.md +154 -0
  87. package/content/guidance/b2c-cli/b2c-sandbox/SKILL.md +112 -0
  88. package/content/guidance/b2c-cli/b2c-scapi-custom/SKILL.md +126 -0
  89. package/content/guidance/b2c-cli/b2c-scapi-schemas/SKILL.md +66 -0
  90. package/content/guidance/b2c-cli/b2c-scapi-schemas/references/CLI-EXAMPLES.md +108 -0
  91. package/content/guidance/b2c-cli/b2c-site-import-export/SKILL.md +57 -0
  92. package/content/guidance/b2c-cli/b2c-site-import-export/references/IMPORT-OPTIONS.md +118 -0
  93. package/content/guidance/b2c-cli/b2c-site-import-export/references/METADATA-XML.md +381 -0
  94. package/content/guidance/b2c-cli/b2c-site-import-export/references/WORKFLOWS.md +182 -0
  95. package/content/guidance/b2c-cli/b2c-sites/SKILL.md +112 -0
  96. package/content/guidance/b2c-cli/b2c-slas/SKILL.md +182 -0
  97. package/content/guidance/b2c-cli/b2c-webdav/SKILL.md +186 -0
  98. package/content/guidance/b2c-ops/b2c-checkout-triage/SKILL.md +68 -0
  99. package/content/guidance/b2c-ops/b2c-job-health/SKILL.md +75 -0
  100. package/content/guidance/b2c-ops/b2c-job-health/references/job-logs.md +21 -0
  101. package/content/guidance/b2c-ops/b2c-order-failure-triage/SKILL.md +66 -0
  102. package/content/guidance/b2c-ops/b2c-order-failure-triage/references/order-evidence.md +87 -0
  103. package/content/guidance/b2c-ops/b2c-production-triage/SKILL.md +87 -0
  104. package/content/guidance/b2c-ops/b2c-production-triage/references/escalation.md +57 -0
  105. package/content/guidance/index.json +1949 -0
  106. package/content/guidance/storefront-next/sfnext-accessibility/SKILL.md +103 -0
  107. package/content/guidance/storefront-next/sfnext-accessibility/references/checklist.md +64 -0
  108. package/content/guidance/storefront-next/sfnext-analytics-consent/SKILL.md +91 -0
  109. package/content/guidance/storefront-next/sfnext-analytics-consent/references/CUSTOM-ADAPTER.md +49 -0
  110. package/content/guidance/storefront-next/sfnext-authentication/SKILL.md +127 -0
  111. package/content/guidance/storefront-next/sfnext-authentication/references/COOKIES.md +39 -0
  112. package/content/guidance/storefront-next/sfnext-authentication/references/LOGIN-FLOWS.md +59 -0
  113. package/content/guidance/storefront-next/sfnext-commerce-features/SKILL.md +67 -0
  114. package/content/guidance/storefront-next/sfnext-commerce-features/references/FEATURE-PREREQUISITES.md +37 -0
  115. package/content/guidance/storefront-next/sfnext-components/SKILL.md +153 -0
  116. package/content/guidance/storefront-next/sfnext-components/references/COMPONENT-AUTHORING.md +118 -0
  117. package/content/guidance/storefront-next/sfnext-components/references/SHAPE-TOKENS.md +51 -0
  118. package/content/guidance/storefront-next/sfnext-components/references/STORYBOOK.md +54 -0
  119. package/content/guidance/storefront-next/sfnext-components/references/TOKEN-SYSTEM.md +53 -0
  120. package/content/guidance/storefront-next/sfnext-components/references/TROUBLESHOOTING.md +19 -0
  121. package/content/guidance/storefront-next/sfnext-configuration/SKILL.md +163 -0
  122. package/content/guidance/storefront-next/sfnext-configuration/references/ENV-VARIABLES.md +55 -0
  123. package/content/guidance/storefront-next/sfnext-configuration/references/MULTI-SITE-URLS.md +137 -0
  124. package/content/guidance/storefront-next/sfnext-data-fetching/SKILL.md +140 -0
  125. package/content/guidance/storefront-next/sfnext-data-fetching/references/ACTIONS.md +53 -0
  126. package/content/guidance/storefront-next/sfnext-data-fetching/references/API-CLIENTS.md +34 -0
  127. package/content/guidance/storefront-next/sfnext-data-fetching/references/LOADERS.md +73 -0
  128. package/content/guidance/storefront-next/sfnext-data-fetching/references/SCAPI-FETCHER.md +39 -0
  129. package/content/guidance/storefront-next/sfnext-deployment/SKILL.md +127 -0
  130. package/content/guidance/storefront-next/sfnext-deployment/references/MRT-DEPLOYMENT.md +59 -0
  131. package/content/guidance/storefront-next/sfnext-extensions/SKILL.md +118 -0
  132. package/content/guidance/storefront-next/sfnext-extensions/references/ACTION-HOOKS.md +57 -0
  133. package/content/guidance/storefront-next/sfnext-extensions/references/BASE-AUDIT.md +68 -0
  134. package/content/guidance/storefront-next/sfnext-extensions/references/CLI-AND-INSTALL.md +58 -0
  135. package/content/guidance/storefront-next/sfnext-extensions/references/EXTENSION-EXAMPLES.md +79 -0
  136. package/content/guidance/storefront-next/sfnext-hybrid-storefronts/SKILL.md +93 -0
  137. package/content/guidance/storefront-next/sfnext-hybrid-storefronts/references/HYBRID-PROXY-CONFIG.md +86 -0
  138. package/content/guidance/storefront-next/sfnext-i18n/SKILL.md +152 -0
  139. package/content/guidance/storefront-next/sfnext-i18n/references/locale-config.md +35 -0
  140. package/content/guidance/storefront-next/sfnext-overview/SKILL.md +101 -0
  141. package/content/guidance/storefront-next/sfnext-page-designer/SKILL.md +202 -0
  142. package/content/guidance/storefront-next/sfnext-page-designer/references/BUSINESS-MANAGER.md +46 -0
  143. package/content/guidance/storefront-next/sfnext-page-designer/references/COMPONENT-REGISTRY.md +111 -0
  144. package/content/guidance/storefront-next/sfnext-page-designer/references/DECORATOR-PATTERNS.md +168 -0
  145. package/content/guidance/storefront-next/sfnext-page-designer/references/REVIEW-CHECKLIST.md +83 -0
  146. package/content/guidance/storefront-next/sfnext-page-designer/references/TROUBLESHOOTING.md +35 -0
  147. package/content/guidance/storefront-next/sfnext-performance/SKILL.md +102 -0
  148. package/content/guidance/storefront-next/sfnext-performance/references/PERFORMANCE-REVIEW-CHECKLIST.md +85 -0
  149. package/content/guidance/storefront-next/sfnext-performance/references/SUSPENSE-AND-STREAMING.md +58 -0
  150. package/content/guidance/storefront-next/sfnext-project-setup/SKILL.md +147 -0
  151. package/content/guidance/storefront-next/sfnext-project-setup/references/PROJECT-STRUCTURE.md +61 -0
  152. package/content/guidance/storefront-next/sfnext-project-setup/references/SCRIPTS.md +47 -0
  153. package/content/guidance/storefront-next/sfnext-project-setup/references/SFNEXT-CLI.md +63 -0
  154. package/content/guidance/storefront-next/sfnext-quality-gates/SKILL.md +70 -0
  155. package/content/guidance/storefront-next/sfnext-quality-gates/references/lint-and-budgets.md +39 -0
  156. package/content/guidance/storefront-next/sfnext-revalidation/SKILL.md +121 -0
  157. package/content/guidance/storefront-next/sfnext-revalidation/references/POLICIES-AND-TAGS.md +55 -0
  158. package/content/guidance/storefront-next/sfnext-routing/SKILL.md +123 -0
  159. package/content/guidance/storefront-next/sfnext-routing/references/ROUTE-CONVENTIONS.md +65 -0
  160. package/content/guidance/storefront-next/sfnext-routing/references/URLS-AND-SEO-ROUTES.md +22 -0
  161. package/content/guidance/storefront-next/sfnext-scapi/SKILL.md +126 -0
  162. package/content/guidance/storefront-next/sfnext-scapi/references/WORKED-EXAMPLE.md +39 -0
  163. package/content/guidance/storefront-next/sfnext-security/SKILL.md +129 -0
  164. package/content/guidance/storefront-next/sfnext-security/references/COOKIE-DOMAIN.md +39 -0
  165. package/content/guidance/storefront-next/sfnext-security/references/TURNSTILE.md +43 -0
  166. package/content/guidance/storefront-next/sfnext-seo/SKILL.md +95 -0
  167. package/content/guidance/storefront-next/sfnext-seo/references/MULTI-DOMAIN-BASE-PATH.md +17 -0
  168. package/content/guidance/storefront-next/sfnext-seo/references/SEO-ROUTES.md +31 -0
  169. package/content/guidance/storefront-next/sfnext-state-management/SKILL.md +114 -0
  170. package/content/guidance/storefront-next/sfnext-state-management/references/PATTERNS.md +45 -0
  171. package/content/guidance/storefront-next/sfnext-testing/SKILL.md +151 -0
  172. package/content/guidance/storefront-next/sfnext-testing/references/E2E.md +38 -0
  173. package/content/guidance/storefront-next/sfnext-testing/references/STORYBOOK-PATTERNS.md +97 -0
  174. package/content/guidance/storefront-next/sfnext-testing/references/UNIT-AND-ROUTE-TESTS.md +60 -0
  175. package/content/guidance/storefront-next/sfnext-theming/SKILL.md +104 -0
  176. package/content/guidance/storefront-next/sfnext-theming/references/REBRAND-CHECKLIST.md +29 -0
  177. package/dist/commands/cap/install.d.ts +1 -0
  178. package/dist/commands/cap/list.d.ts +1 -0
  179. package/dist/commands/cap/pull.d.ts +1 -0
  180. package/dist/commands/cap/tasks.d.ts +1 -0
  181. package/dist/commands/cap/uninstall.d.ts +1 -0
  182. package/dist/commands/cip/describe.d.ts +1 -0
  183. package/dist/commands/cip/query.d.ts +1 -0
  184. package/dist/commands/cip/report/bot-traffic-share.d.ts +1 -0
  185. package/dist/commands/cip/report/checkout-funnel-dropoff.d.ts +1 -0
  186. package/dist/commands/cip/report/controller-error-rate-trend.d.ts +1 -0
  187. package/dist/commands/cip/report/controller-health-scorecard.d.ts +1 -0
  188. package/dist/commands/cip/report/customer-registration-trends.d.ts +1 -0
  189. package/dist/commands/cip/report/discount-depth-breakdown.d.ts +1 -0
  190. package/dist/commands/cip/report/inventory-stockout-by-location.d.ts +1 -0
  191. package/dist/commands/cip/report/new-vs-returning-buyer-revenue.d.ts +1 -0
  192. package/dist/commands/cip/report/ocapi-client-usage.d.ts +1 -0
  193. package/dist/commands/cip/report/ocapi-requests.d.ts +1 -0
  194. package/dist/commands/cip/report/payment-method-performance.d.ts +1 -0
  195. package/dist/commands/cip/report/product-co-purchase-analysis.d.ts +1 -0
  196. package/dist/commands/cip/report/promotion-discount-analysis.d.ts +1 -0
  197. package/dist/commands/cip/report/promotion-roi-leaderboard.d.ts +1 -0
  198. package/dist/commands/cip/report/recommender-effectiveness.d.ts +1 -0
  199. package/dist/commands/cip/report/remote-include-performance.d.ts +1 -0
  200. package/dist/commands/cip/report/revenue-by-channel.d.ts +1 -0
  201. package/dist/commands/cip/report/sales-analytics.d.ts +1 -0
  202. package/dist/commands/cip/report/sales-summary.d.ts +1 -0
  203. package/dist/commands/cip/report/scapi-cache-hit-ratio.d.ts +1 -0
  204. package/dist/commands/cip/report/scapi-error-rate-by-status.d.ts +1 -0
  205. package/dist/commands/cip/report/scapi-latency-distribution.d.ts +1 -0
  206. package/dist/commands/cip/report/scapi-traffic-latency.d.ts +1 -0
  207. package/dist/commands/cip/report/search-query-performance.d.ts +1 -0
  208. package/dist/commands/cip/report/top-referrers.d.ts +1 -0
  209. package/dist/commands/cip/report/top-selling-products.d.ts +1 -0
  210. package/dist/commands/cip/report/zero-result-searches.d.ts +1 -0
  211. package/dist/commands/cip/tables.d.ts +1 -0
  212. package/dist/commands/code/activate.d.ts +1 -0
  213. package/dist/commands/code/delete.d.ts +1 -0
  214. package/dist/commands/code/deploy.d.ts +1 -0
  215. package/dist/commands/code/download.d.ts +1 -0
  216. package/dist/commands/code/watch.d.ts +1 -0
  217. package/dist/commands/commands/search.d.ts +35 -0
  218. package/dist/commands/commands/search.js +85 -0
  219. package/dist/commands/commands/search.js.map +1 -0
  220. package/dist/commands/content/export.d.ts +1 -0
  221. package/dist/commands/content/list.d.ts +1 -0
  222. package/dist/commands/content/validate.d.ts +1 -0
  223. package/dist/commands/debug/cli.d.ts +1 -0
  224. package/dist/commands/debug/index.d.ts +1 -0
  225. package/dist/commands/docs/cache.d.ts +1 -0
  226. package/dist/commands/docs/download.d.ts +1 -0
  227. package/dist/commands/docs/read.d.ts +1 -0
  228. package/dist/commands/docs/schema.d.ts +1 -0
  229. package/dist/commands/docs/search.d.ts +1 -0
  230. package/dist/commands/docs/skill.d.ts +41 -0
  231. package/dist/commands/docs/skill.js +183 -0
  232. package/dist/commands/docs/skill.js.map +1 -0
  233. package/dist/commands/ecdn/cache/purge.d.ts +1 -0
  234. package/dist/commands/ecdn/certificates/add.d.ts +1 -0
  235. package/dist/commands/ecdn/certificates/delete.d.ts +1 -0
  236. package/dist/commands/ecdn/certificates/list.d.ts +1 -0
  237. package/dist/commands/ecdn/certificates/update.d.ts +1 -0
  238. package/dist/commands/ecdn/certificates/validate.d.ts +1 -0
  239. package/dist/commands/ecdn/cipher-suites/get.d.ts +1 -0
  240. package/dist/commands/ecdn/cipher-suites/update.d.ts +1 -0
  241. package/dist/commands/ecdn/firewall/create.d.ts +1 -0
  242. package/dist/commands/ecdn/firewall/delete.d.ts +1 -0
  243. package/dist/commands/ecdn/firewall/get.d.ts +1 -0
  244. package/dist/commands/ecdn/firewall/list.d.ts +1 -0
  245. package/dist/commands/ecdn/firewall/reorder.d.ts +1 -0
  246. package/dist/commands/ecdn/firewall/update.d.ts +1 -0
  247. package/dist/commands/ecdn/logpush/jobs/create.d.ts +1 -0
  248. package/dist/commands/ecdn/logpush/jobs/delete.d.ts +1 -0
  249. package/dist/commands/ecdn/logpush/jobs/get.d.ts +1 -0
  250. package/dist/commands/ecdn/logpush/jobs/list.d.ts +1 -0
  251. package/dist/commands/ecdn/logpush/jobs/update.d.ts +1 -0
  252. package/dist/commands/ecdn/logpush/ownership.d.ts +1 -0
  253. package/dist/commands/ecdn/mrt-rules/create.d.ts +1 -0
  254. package/dist/commands/ecdn/mrt-rules/delete.d.ts +1 -0
  255. package/dist/commands/ecdn/mrt-rules/get.d.ts +1 -0
  256. package/dist/commands/ecdn/mrt-rules/rules/delete.d.ts +1 -0
  257. package/dist/commands/ecdn/mrt-rules/rules/update.d.ts +1 -0
  258. package/dist/commands/ecdn/mrt-rules/update.d.ts +1 -0
  259. package/dist/commands/ecdn/mtls/create.d.ts +1 -0
  260. package/dist/commands/ecdn/mtls/delete.d.ts +1 -0
  261. package/dist/commands/ecdn/mtls/get.d.ts +1 -0
  262. package/dist/commands/ecdn/mtls/issue.d.ts +1 -0
  263. package/dist/commands/ecdn/mtls/list.d.ts +1 -0
  264. package/dist/commands/ecdn/mtls/setup.d.ts +1 -0
  265. package/dist/commands/ecdn/origin-headers/delete.d.ts +1 -0
  266. package/dist/commands/ecdn/origin-headers/get.d.ts +1 -0
  267. package/dist/commands/ecdn/origin-headers/set.d.ts +1 -0
  268. package/dist/commands/ecdn/page-shield/notifications/create.d.ts +1 -0
  269. package/dist/commands/ecdn/page-shield/notifications/delete.d.ts +1 -0
  270. package/dist/commands/ecdn/page-shield/notifications/list.d.ts +1 -0
  271. package/dist/commands/ecdn/page-shield/policies/create.d.ts +1 -0
  272. package/dist/commands/ecdn/page-shield/policies/delete.d.ts +1 -0
  273. package/dist/commands/ecdn/page-shield/policies/get.d.ts +1 -0
  274. package/dist/commands/ecdn/page-shield/policies/list.d.ts +1 -0
  275. package/dist/commands/ecdn/page-shield/policies/update.d.ts +1 -0
  276. package/dist/commands/ecdn/page-shield/scripts/get.d.ts +1 -0
  277. package/dist/commands/ecdn/page-shield/scripts/list.d.ts +1 -0
  278. package/dist/commands/ecdn/rate-limit/create.d.ts +1 -0
  279. package/dist/commands/ecdn/rate-limit/delete.d.ts +1 -0
  280. package/dist/commands/ecdn/rate-limit/get.d.ts +1 -0
  281. package/dist/commands/ecdn/rate-limit/list.d.ts +1 -0
  282. package/dist/commands/ecdn/rate-limit/update.d.ts +1 -0
  283. package/dist/commands/ecdn/security/get.d.ts +1 -0
  284. package/dist/commands/ecdn/security/update.d.ts +1 -0
  285. package/dist/commands/ecdn/speed/get.d.ts +1 -0
  286. package/dist/commands/ecdn/speed/update.d.ts +1 -0
  287. package/dist/commands/ecdn/waf/groups/list.d.ts +1 -0
  288. package/dist/commands/ecdn/waf/groups/update.d.ts +1 -0
  289. package/dist/commands/ecdn/waf/managed-rules/list.d.ts +1 -0
  290. package/dist/commands/ecdn/waf/managed-rules/update.d.ts +1 -0
  291. package/dist/commands/ecdn/waf/migrate.d.ts +1 -0
  292. package/dist/commands/ecdn/waf/owasp/get.d.ts +1 -0
  293. package/dist/commands/ecdn/waf/owasp/update.d.ts +1 -0
  294. package/dist/commands/ecdn/waf/rules/get.d.ts +1 -0
  295. package/dist/commands/ecdn/waf/rules/list.d.ts +1 -0
  296. package/dist/commands/ecdn/waf/rules/update.d.ts +1 -0
  297. package/dist/commands/ecdn/waf/rulesets/list.d.ts +1 -0
  298. package/dist/commands/ecdn/waf/rulesets/update.d.ts +1 -0
  299. package/dist/commands/ecdn/zones/create.d.ts +1 -0
  300. package/dist/commands/ecdn/zones/list.d.ts +1 -0
  301. package/dist/commands/job/execution/delete.d.ts +1 -0
  302. package/dist/commands/job/export.d.ts +1 -0
  303. package/dist/commands/job/import-set.d.ts +1 -0
  304. package/dist/commands/job/import.d.ts +1 -0
  305. package/dist/commands/job/log.d.ts +1 -0
  306. package/dist/commands/job/run.d.ts +1 -0
  307. package/dist/commands/job/search.d.ts +1 -0
  308. package/dist/commands/job/wait.d.ts +1 -0
  309. package/dist/commands/logs/get.d.ts +1 -0
  310. package/dist/commands/logs/list.d.ts +1 -0
  311. package/dist/commands/logs/tail.d.ts +1 -0
  312. package/dist/commands/metrics/controller.d.ts +1 -0
  313. package/dist/commands/metrics/ecdn.d.ts +1 -0
  314. package/dist/commands/metrics/mrt.d.ts +1 -0
  315. package/dist/commands/metrics/ocapi.d.ts +1 -0
  316. package/dist/commands/metrics/overall.d.ts +1 -0
  317. package/dist/commands/metrics/sales.d.ts +1 -0
  318. package/dist/commands/metrics/scapi-hooks.d.ts +1 -0
  319. package/dist/commands/metrics/scapi.d.ts +1 -0
  320. package/dist/commands/metrics/third-party.d.ts +1 -0
  321. package/dist/commands/mrt/bundle/delete.d.ts +1 -0
  322. package/dist/commands/mrt/bundle/deploy.d.ts +1 -0
  323. package/dist/commands/mrt/bundle/download.d.ts +1 -0
  324. package/dist/commands/mrt/bundle/history.d.ts +1 -0
  325. package/dist/commands/mrt/bundle/list.d.ts +1 -0
  326. package/dist/commands/mrt/bundle/save.d.ts +1 -0
  327. package/dist/commands/mrt/bundle/upload-v2.d.ts +1 -0
  328. package/dist/commands/mrt/env/access-control/list.d.ts +1 -0
  329. package/dist/commands/mrt/env/b2c.d.ts +1 -0
  330. package/dist/commands/mrt/env/clone.d.ts +1 -0
  331. package/dist/commands/mrt/env/create.d.ts +1 -0
  332. package/dist/commands/mrt/env/delete.d.ts +1 -0
  333. package/dist/commands/mrt/env/get.d.ts +1 -0
  334. package/dist/commands/mrt/env/invalidate.d.ts +1 -0
  335. package/dist/commands/mrt/env/list.d.ts +1 -0
  336. package/dist/commands/mrt/env/redirect/clone.d.ts +1 -0
  337. package/dist/commands/mrt/env/redirect/create.d.ts +1 -0
  338. package/dist/commands/mrt/env/redirect/delete.d.ts +1 -0
  339. package/dist/commands/mrt/env/redirect/list.d.ts +1 -0
  340. package/dist/commands/mrt/env/update.d.ts +1 -0
  341. package/dist/commands/mrt/env/var/delete.d.ts +1 -0
  342. package/dist/commands/mrt/env/var/list.d.ts +1 -0
  343. package/dist/commands/mrt/env/var/push.d.ts +1 -0
  344. package/dist/commands/mrt/env/var/set.d.ts +1 -0
  345. package/dist/commands/mrt/org/b2c.d.ts +1 -0
  346. package/dist/commands/mrt/org/cert/create.d.ts +1 -0
  347. package/dist/commands/mrt/org/cert/delete.d.ts +1 -0
  348. package/dist/commands/mrt/org/cert/get.d.ts +1 -0
  349. package/dist/commands/mrt/org/cert/list.d.ts +1 -0
  350. package/dist/commands/mrt/org/cert/restart-validation.d.ts +1 -0
  351. package/dist/commands/mrt/org/list.d.ts +1 -0
  352. package/dist/commands/mrt/org/member/add.d.ts +1 -0
  353. package/dist/commands/mrt/org/member/get.d.ts +1 -0
  354. package/dist/commands/mrt/org/member/list.d.ts +1 -0
  355. package/dist/commands/mrt/org/member/remove.d.ts +1 -0
  356. package/dist/commands/mrt/org/member/update.d.ts +1 -0
  357. package/dist/commands/mrt/project/create.d.ts +1 -0
  358. package/dist/commands/mrt/project/delete.d.ts +1 -0
  359. package/dist/commands/mrt/project/get.d.ts +1 -0
  360. package/dist/commands/mrt/project/list.d.ts +1 -0
  361. package/dist/commands/mrt/project/member/add.d.ts +1 -0
  362. package/dist/commands/mrt/project/member/get.d.ts +1 -0
  363. package/dist/commands/mrt/project/member/list.d.ts +1 -0
  364. package/dist/commands/mrt/project/member/remove.d.ts +1 -0
  365. package/dist/commands/mrt/project/member/update.d.ts +1 -0
  366. package/dist/commands/mrt/project/notification/delete.d.ts +1 -0
  367. package/dist/commands/mrt/project/notification/get.d.ts +1 -0
  368. package/dist/commands/mrt/project/update.d.ts +1 -0
  369. package/dist/commands/mrt/save-credentials.d.ts +1 -0
  370. package/dist/commands/mrt/tail-logs.d.ts +1 -0
  371. package/dist/commands/mrt/user/api-key.d.ts +1 -0
  372. package/dist/commands/mrt/user/email-prefs.d.ts +1 -0
  373. package/dist/commands/mrt/user/profile.d.ts +1 -0
  374. package/dist/commands/scaffold/init.js +2 -1
  375. package/dist/commands/scaffold/init.js.map +1 -1
  376. package/dist/commands/scapi/custom/status.d.ts +1 -0
  377. package/dist/commands/scapi/schemas/get.d.ts +1 -0
  378. package/dist/commands/scapi/schemas/list.d.ts +1 -0
  379. package/dist/commands/setup/ide/tsserver-plugin.d.ts +1 -0
  380. package/dist/commands/setup/ide/vscode-types.d.ts +1 -0
  381. package/dist/commands/setup/index.js +4 -3
  382. package/dist/commands/setup/index.js.map +1 -1
  383. package/dist/commands/setup/inspect.d.ts +1 -0
  384. package/dist/commands/setup/inspect.js +17 -2
  385. package/dist/commands/setup/inspect.js.map +1 -1
  386. package/dist/commands/setup/instance/create.d.ts +1 -0
  387. package/dist/commands/setup/instance/list.d.ts +1 -0
  388. package/dist/commands/setup/instance/remove.d.ts +1 -0
  389. package/dist/commands/setup/instance/set-active.d.ts +1 -0
  390. package/dist/commands/setup/openshell.d.ts +1 -0
  391. package/dist/commands/setup/skills.d.ts +1 -0
  392. package/dist/commands/slas/client/create.d.ts +1 -0
  393. package/dist/commands/slas/client/delete.d.ts +1 -0
  394. package/dist/commands/slas/client/get.d.ts +1 -0
  395. package/dist/commands/slas/client/list.d.ts +1 -0
  396. package/dist/commands/slas/client/open.d.ts +1 -0
  397. package/dist/commands/slas/client/update.d.ts +1 -0
  398. package/dist/commands/slas/token.d.ts +1 -0
  399. package/dist/commands/slas/token.js +2 -1
  400. package/dist/commands/slas/token.js.map +1 -1
  401. package/dist/commands/webdav/get.d.ts +1 -0
  402. package/dist/commands/webdav/mkdir.d.ts +2 -0
  403. package/dist/commands/webdav/mkdir.js +5 -3
  404. package/dist/commands/webdav/mkdir.js.map +1 -1
  405. package/dist/commands/webdav/put.d.ts +2 -0
  406. package/dist/commands/webdav/put.js +5 -3
  407. package/dist/commands/webdav/put.js.map +1 -1
  408. package/dist/commands/webdav/rm.d.ts +1 -0
  409. package/dist/help.d.ts +25 -0
  410. package/dist/help.js +96 -0
  411. package/dist/help.js.map +1 -0
  412. package/dist/lib/scaffold/generate-helper.js +3 -2
  413. package/dist/lib/scaffold/generate-helper.js.map +1 -1
  414. package/dist/lib/skills.d.ts +19 -0
  415. package/dist/lib/skills.js +75 -0
  416. package/dist/lib/skills.js.map +1 -0
  417. package/dist/utils/cip/command.d.ts +1 -0
  418. package/dist/utils/ecdn/zone-command.d.ts +1 -0
  419. package/dist/utils/slas/client.d.ts +1 -0
  420. package/oclif.manifest.json +10994 -7653
  421. package/package.json +11 -5
@@ -0,0 +1,70 @@
1
+ ---
2
+ name: sfnext-quality-gates
3
+ description: >-
4
+ Run and fix the Storefront Next quality gates before a PR or deploy: OxLint (type-aware, --max-warnings 0) plus Biome formatting, lint:a11y, lint:css, typecheck, the TypeScript-only check, bundle-size budgets, Lighthouse CI, and the pre-PR checklist. Use when pnpm lint, pnpm format:check, pnpm typecheck, pnpm bundlesize or pnpm lighthouse:ci fails, for custom/color-linter or custom/header-format errors, "unused Tailwind class" findings, oxlint-disable comments, "what should I run before opening a PR", or CI red on lint. Do not use for writing tests (use `storefront-next:sfnext-testing`), accessibility fixes themselves (use `storefront-next:sfnext-accessibility`), or runtime performance tuning (use `storefront-next:sfnext-performance`).
5
+ ---
6
+
7
+ # Storefront Next Quality Gates
8
+
9
+ Your project enforces style, types, size and accessibility with a few commands. CI runs the same ones, and lint is strict: any warning fails.
10
+
11
+ ## Pre-PR checklist
12
+
13
+ ```bash
14
+ pnpm lint # OxLint (type-aware, --max-warnings 0) then Biome format check
15
+ pnpm typecheck # route typegen + tsc --noEmit
16
+ pnpm test # unit tests
17
+ pnpm storybook:test --type=snapshot # if you touched components or stories
18
+ pnpm bundlesize # if you added dependencies or large components
19
+ ```
20
+
21
+ If you changed UI, also run `pnpm storybook:test --type=interaction` and `--type=a11y` (needs `pnpm exec playwright install chromium`). Fix formatting and auto-fixable lint in one go with `pnpm lint:fix`.
22
+
23
+ ## Commands
24
+
25
+ | Command | What it does |
26
+ |---------|--------------|
27
+ | `pnpm lint` | `oxlint --type-aware --report-unused-disable-directives --max-warnings 0` (e2e excluded) then `biome format` check, then the e2e package's own lint |
28
+ | `pnpm lint:fix` | `oxlint --fix` then `biome format --write` |
29
+ | `pnpm format` / `pnpm format:check` | Biome formatting only (4-space indent, 120 columns, single quotes in JS, double in JSX) |
30
+ | `pnpm lint:a11y` | Reports only `jsx-a11y/*` findings; exit 1 if any (see `storefront-next:sfnext-accessibility`) |
31
+ | `pnpm lint:css` | After a build, checks the built app stylesheet for Tailwind candidates that only come from stories, tests or docs (dead or story-only classes). Run `pnpm build` first |
32
+ | `pnpm typecheck` | `react-router typegen` then `tsc --noEmit` (uses extra heap) |
33
+ | `node scripts/check-typescript-only.js` | Fails if `.js/.jsx/.mjs/.cjs` exist under `src/` |
34
+ | `pnpm bundlesize` | Builds with `BUNDLES_SIZE_CHECK=true`; fails if chunks exceed limits in `package.json#bundlesize` (`client` and `server` lists) |
35
+ | `pnpm bundlesize:compare` | Compares two bundle metadata files: `node scripts/compare-bundlesize.mjs --baseline <path> --candidate <path> [--tolerance <pct>]` |
36
+ | `pnpm lighthouse:ci` | `lhci autorun` using `lighthouserc.cjs` (build first; it starts the preview server itself) |
37
+ | `pnpm config:inspect` | Prints the resolved config to debug env overrides |
38
+
39
+ ESLint and Prettier are not used. OxLint owns all linting (including type-aware rules and custom plugin rules); Biome owns only formatting.
40
+
41
+ ## Custom rules you will hit
42
+
43
+ - `custom/color-linter`: use design tokens (`bg-primary`, `text-muted-foreground`), not hard-coded colors. See `storefront-next:sfnext-theming`.
44
+ - `custom/header-format`: every TS/JS file needs the Apache 2.0 license header. Copy it from any existing source file.
45
+ - `jsx-a11y/*` recommended set at error, plus `no-aria-hidden-on-focusable`, `anchor-ambiguous-text`, `no-redundant-roles` (allows `role="list"` on `ul`) and `alt-text` extended to `DynamicImage` and `ProductImage`.
46
+ - `no-restricted-imports`: browser-only `@salesforce/storefront-next-runtime/i18n/client` is blocked from server modules.
47
+ - TypeScript only in `src/`.
48
+
49
+ Fix the code rather than disabling. If a suppression is truly needed, use a scoped `// oxlint-disable-next-line <rule> -- reason`. `--report-unused-disable-directives` fails stale ones. Generated and vendored trees (SCAPI generated clients, `src/components/ui/**`, build output) are skipped by lint and format.
50
+
51
+ More: [references/lint-and-budgets.md](references/lint-and-budgets.md) and `docs/README-LINTING.md` (skip the sections about repository internals that do not apply to your project).
52
+
53
+ ## Typical failures
54
+
55
+ | Symptom | Fix |
56
+ |---------|-----|
57
+ | `pnpm lint` fails only at the end on formatting | `pnpm format` |
58
+ | Warning count > 0 | Warnings are errors here; fix or justify with a scoped disable |
59
+ | `jsx-a11y/...` error | Fix markup; run `pnpm lint:a11y` while iterating |
60
+ | Type errors about `+types/...` routes | Run `pnpm typecheck` (it regenerates route types) |
61
+ | `pnpm lint:css` cannot find stylesheet | Run `pnpm build` first |
62
+ | Lighthouse/bundle budget exceeded after adding a feature | See the budget notes in the reference; look for eager imports before raising a limit |
63
+
64
+ ## Related Skills
65
+
66
+ - `storefront-next:sfnext-testing` - unit, story and e2e tests (the test half of the checklist)
67
+ - `storefront-next:sfnext-accessibility` - fixing a11y lint and scan findings
68
+ - `storefront-next:sfnext-performance` - reducing bundle and page weight
69
+ - `storefront-next:sfnext-theming` - design tokens behind `color-linter`
70
+ - `storefront-next:sfnext-deployment` - build and push after the gates pass
@@ -0,0 +1,39 @@
1
+ # Lint configuration and performance budgets
2
+
3
+ ## Configuration files in your project
4
+
5
+ | File | Role |
6
+ |------|------|
7
+ | `.oxlintrc.json` | All lint rules, custom JS-plugin rules (`custom/*`), overrides for tests/stories, `ignorePatterns` |
8
+ | `biome.json` | Formatter only (linter and assists disabled) |
9
+ | `lint-plugins/` | Source of the `custom/color-linter` and `custom/header-format` rules |
10
+ | `e2e/biome.json` and e2e scripts | The e2e package lints and formats itself; it is not type-aware linted |
11
+
12
+ OxLint's JS-plugin loader needs Node >= 22.6; the project requires Node 24.
13
+
14
+ Test files relax some rules (fixtures use ad-hoc roles and handlers); story and test overrides are in `.oxlintrc.json`.
15
+
16
+ ## Editor integration
17
+
18
+ Install the Oxc VS Code extension for inline diagnostics and the Biome extension (set as default formatter) for format on save.
19
+
20
+ ## Bundle size
21
+
22
+ - Limits: `package.json#bundlesize` with `client` and `server` arrays of `{ name: <glob>, limit: '<size>' }`. Defaults are generous if absent.
23
+ - `pnpm bundlesize` writes `build/<env>-bundlemeta.json` per environment.
24
+ - Visualize: `cross-env BUNDLES_SIZE_ANALYZE=true pnpm build` opens `build/client-bundle-size.html` and `build/ssr-bundle-size.html` (`docs/README-PERFORMANCE.md`).
25
+ - Before adding a large dependency, check its impact with the visualizer, lazy-load it (`React.lazy` or dynamic `import()`), and prefer server-only code for heavy logic.
26
+
27
+ ## Lighthouse CI
28
+
29
+ - `lighthouserc.cjs` defines the URLs (home, a PDP, cart), number of runs, category score minimums (performance, accessibility, SEO, best-practices) and ceilings for `resource-summary:script:size` and `resource-summary:document:size` per route.
30
+ - The shipped numbers are tuned to the starter theme. Your customizations (new scripts, bigger documents, different sites or product ids in the URL list) will move them. Update URLs to pages that exist in your catalog, then measure and set ceilings deliberately, with headroom, rather than deleting assertions.
31
+ - Run `pnpm build` first; the config starts the preview server on port 3001 itself.
32
+ - Also run `pnpm bundlesize` in CI or locally so regressions show up per chunk, not just in page totals.
33
+
34
+ ## When a budget fails
35
+
36
+ 1. Identify what grew: compare bundle metadata (`pnpm bundlesize:compare`) or the visualizer.
37
+ 2. Look for eager imports of heavy modules in root, layouts or shared components; convert to lazy loads.
38
+ 3. Check that new third-party scripts are deferred (see `storefront-next:sfnext-performance`).
39
+ 4. Only then raise a limit, in the smallest increment, and note why in the commit message.
@@ -0,0 +1,121 @@
1
+ ---
2
+ name: sfnext-revalidation
3
+ description: >-
4
+ Control which Storefront Next loaders re-run after an action or navigation: shouldRevalidate exports, the policy modules in src/lib/revalidation/routes (root, cart, product, category, checkout, home, wishlist, api-client, shared), getActionPath and isAmbientMutation, and the tag primitives in src/lib/revalidation/tags (withRevalidateTags, shouldRevalidateForTags, tagGroup, tagImplications). Use for "page re-fetches after add to cart", "loader runs too often", "stale data after a mutation", "flash of skeleton after changing a swatch", "add shouldRevalidate", or when a new action or route changes which loaders fire. Do not use for writing loaders or actions (use `storefront-next:sfnext-data-fetching`), Suspense and LCP tuning (use `storefront-next:sfnext-performance`), or client-side state (use `storefront-next:sfnext-state-management`).
5
+ ---
6
+
7
+ # Storefront Next Revalidation
8
+
9
+ React Router re-runs loaders after every action submission. A storefront has deep route trees, persistent fetchers (mini-cart) and lazy modals (quick view), so one add-to-cart can re-run many loaders that never read the basket, each with its own SCAPI fan-out. This skill is how to keep only the re-runs that are needed. The authoritative guide is `docs/README-REVALIDATION.md` in your project; read it before changing policy.
10
+
11
+ ## What revalidates
12
+
13
+ An action submission (`<Form>`, `useSubmit`, `fetcher.submit`) re-runs the whole active set:
14
+
15
+ 1. the matched route chain (root, layouts, leaf),
16
+ 2. mounted resource fetchers (`fetcher.load()` of a resource route whose component is still mounted),
17
+ 3. fetchers inside open modals, drawers and sheets.
18
+
19
+ A raw `fetch()`, a SCAPI client call, or `fetcher.load()` is not a submission and triggers nothing. A route that only exports an `action` fires revalidation but has no loader to re-run.
20
+
21
+ ## When a re-run is justified
22
+
23
+ For each pair (action, active loader) it is justified only if both are true:
24
+
25
+ - **Overlap**: the action result changes something the loader reads.
26
+ - **Value not already available**: the new value does not already reach the UI another way (for example the basket provider is updated from the action result, so a cart action does not need the PDP loader to re-run).
27
+
28
+ Two waste types: no overlap, or overlap with the value already available. Do not gate a re-run that is itself the sync mechanism (a provider that refills from loader output).
29
+
30
+ ## Where the policy lives
31
+
32
+ Each route re-exports a shared policy rather than inlining logic:
33
+
34
+ ```ts
35
+ // src/routes/_app.cart.tsx
36
+ export { shouldRevalidate } from '@/lib/revalidation/routes/cart';
37
+ ```
38
+
39
+ | Module (`src/lib/revalidation/routes/`) | Used by |
40
+ |---|---|
41
+ | `root.ts` | `src/root.tsx` (`export { shouldRevalidate } from ...`); denylist of irrelevant mutations, safe default is revalidate |
42
+ | `cart.ts`, `checkout.ts`, `home.ts`, `wishlist.ts` | the matching route files |
43
+ | `product.ts` | `_app.p.$.tsx`: relevant mutations force true; navigation re-runs only on different path or `pid` |
44
+ | `category.ts` | `_app.c.$.tsx` and `_app.search.tsx`: skips client-only param changes and non-ambient mutations |
45
+ | `api-client.ts` | `resource.api.client.$resource.ts` |
46
+ | `shared.ts` | helpers: `getActionPath`, `isContextMutation`, `isIdentityMutation`, `isAmbientMutation` |
47
+
48
+ `_app.tsx` exports `shouldRevalidate() { return false }` (navigation data that no shopper action changes). `resource.basket-products.ts` opts in only when `actionResult.basket.basketId` exists.
49
+
50
+ "Ambient" mutations (site/currency, shopper context, login/signup/logout) change request-wide inputs and legitimately re-run most loaders.
51
+
52
+ ## Add a policy for a new route
53
+
54
+ Prefer suppress-by-default allowlists for expensive loaders, and defer to the default for cheap ones:
55
+
56
+ ```ts
57
+ // src/lib/revalidation/routes/store-events.ts
58
+ import type { ShouldRevalidateFunctionArgs } from 'react-router';
59
+ import { resourceRoutes } from '@/route-paths';
60
+ import { getActionPath, isAmbientMutation } from './shared';
61
+
62
+ const RELEVANT = [resourceRoutes.setSelectedStore] as readonly string[];
63
+
64
+ export function shouldRevalidate({ currentUrl, nextUrl, formMethod, formAction, defaultShouldRevalidate }: ShouldRevalidateFunctionArgs) {
65
+ if (formMethod && formMethod !== 'GET') {
66
+ const path = getActionPath(formAction, currentUrl.origin);
67
+ return Boolean(path && (isAmbientMutation(path) || RELEVANT.includes(path)));
68
+ }
69
+ if (currentUrl.pathname !== nextUrl.pathname) return true;
70
+ return defaultShouldRevalidate; // explicit revalidate() still works; client-only params stay skipped
71
+ }
72
+ ```
73
+
74
+ Steps:
75
+
76
+ 1. List what the loader reads (fetched fields, URL params, cookies, context such as currency or selected store).
77
+ 2. List the actions reachable while this route is active (page, shell, open modals and drawers). Mark overlap and availability per action.
78
+ 3. Export the policy. Admit only mutations with overlap and no other delivery path. Document each admit in a comment.
79
+ 4. If a URL-filtered loader (search params) re-runs on navigation anyway, skip revalidating when only those params change.
80
+ 5. Add a test next to the policy (`*.test.ts`), covering an admitted mutation, a skipped mutation and a navigation.
81
+ 6. Verify manually: open DevTools Network, perform the gesture, and count loader (`.data`) requests.
82
+
83
+ Gate adequacy matters: a policy that only checks `formAction` is set still re-runs on every action. Inspect the action path or `actionResult`.
84
+
85
+ ## Tags for cross-route contracts
86
+
87
+ When several routes depend on the same data, use the tag primitives in `@/lib/revalidation/tags` (the framework ships primitives only; you own the catalogs):
88
+
89
+ ```ts
90
+ // src/lib/revalidation/tags/cart.ts (yours)
91
+ export const cartTags = { all: 'cart.*', lineItem: (id: string) => `cart.lineItems:${id}` as const } as const;
92
+
93
+ // action: emit
94
+ import { withRevalidateTags } from '@/lib/revalidation/tags';
95
+ return withRevalidateTags({ basket }, [cartTags.lineItem(itemId)]);
96
+
97
+ // route: subscribe
98
+ import { shouldRevalidateForTags } from '@/lib/revalidation/tags';
99
+ export const shouldRevalidate = shouldRevalidateForTags([cartTags.all]);
100
+ ```
101
+
102
+ Spell tags only through catalog builders (a typo silently matches nothing). Syntax: dot-separated segments, optional `:id`, `.*` wildcard is subscriber-only. Helpers: `tagGroup`, `tagImplications`, `matchesTag`, `normalizeTags`, `resolveTags`; `shouldRevalidateForTags(spec, { ambient, expand })`. An untagged action falls back to default behavior. See `src/lib/revalidation/tags/index.example.test.ts` and details in [POLICIES-AND-TAGS.md](references/POLICIES-AND-TAGS.md).
103
+
104
+ ## Related levers
105
+
106
+ - Add-to-cart, promo and quantity changes update the basket through `updateBasketResource` and `BasketProvider` (`src/providers/basket.tsx`), so pages rarely need loader re-runs to show the new basket.
107
+ - `useRevalidateOnReturn` (`@/hooks/use-revalidate-on-return`) refreshes stale data when the shopper returns to the tab or page.
108
+ - Modals and drawers mount lazily; a quick-view that both loads product data and submits add-to-cart widens the active set and triggers it. Keep its fetcher unmounted until open and consider moving the submit elsewhere.
109
+ - Leave `shouldRevalidate` gates on root-level session, site and config loaders conservative: the root policy defaults to revalidate.
110
+
111
+ ## Finding more
112
+
113
+ `docs/README-REVALIDATION.md`, `docs/README-DATA.md`, `docs/README-STATE.md` and `AGENTS.md` in your project. `b2c docs search "revalidation"` or the `docs_search` MCP tool for product docs.
114
+
115
+ ## Related Skills
116
+
117
+ - `storefront-next:sfnext-data-fetching` - loaders, actions, fetchers
118
+ - `storefront-next:sfnext-performance` - review checklist (revalidation scope section)
119
+ - `storefront-next:sfnext-state-management` - providers that make a re-run unnecessary
120
+ - `storefront-next:sfnext-routing` - route files that export policies
121
+ - `storefront-next:sfnext-testing` - tests for policies
@@ -0,0 +1,55 @@
1
+ # Policies and tags reference
2
+
3
+ ## Policy inputs
4
+
5
+ `shouldRevalidate` receives `currentUrl`, `nextUrl`, `formMethod`, `formAction`, `actionStatus`, `actionResult` and `defaultShouldRevalidate`.
6
+
7
+ - Action submissions have `formMethod` other than GET. Resolve the target with `getActionPath(formAction, currentUrl.origin)` from `@/lib/revalidation/routes/shared`, then compare to `resourceRoutes` values.
8
+ - A navigation has no non-GET `formMethod`. Compare pathname and the search params the loader consumes.
9
+ - `useRevalidator().revalidate()` arrives with `defaultShouldRevalidate` true and no `formMethod`; return `defaultShouldRevalidate` for that case so explicit refreshes work.
10
+ - Treat any 2xx `actionStatus` as success, not only 200.
11
+
12
+ ## Decision table
13
+
14
+ | Situation | Policy |
15
+ |---|---|
16
+ | Loader reads only data no action changes (navigation menu) | `return false` |
17
+ | Loader reads URL filters | skip when only those params change; the navigation re-runs it with new params |
18
+ | Expensive loader, few relevant writes | allowlist (suppress by default), as in `product.ts` |
19
+ | Cheap loader, few irrelevant writes | denylist, as in `root.ts` |
20
+ | Resource fetcher backing a provider | opt in when `actionResult` carries its payload (`basket.basketId`) |
21
+ | Many routes depend on one data domain | tags |
22
+
23
+ ## Modals and drawers
24
+
25
+ Lazy modals and drawers join the active set only after opening. List each modal as potential target (loads a resource fetcher on open) and trigger (submits an action). Fix by gating the fetcher-owning route, or by not mounting the loading component until needed.
26
+
27
+ ## Tags
28
+
29
+ Primitives (`src/lib/revalidation/tags/index.ts`):
30
+
31
+ | Export | Role |
32
+ |---|---|
33
+ | `withRevalidateTags(result, tags)` | action: attach `revalidateTags` to the result |
34
+ | `shouldRevalidateForTags(spec, { ambient, expand })` | route: build a `shouldRevalidate`; `spec` is a tag array or `({ params }) => tags` |
35
+ | `tagGroup(tag, deps)` | subscriber: a tag plus the tags it depends on |
36
+ | `tagImplications(map)` | emitter side: expand an emitted tag into implied concrete tags |
37
+ | `matchesTag(pattern, emitted)` | the matcher |
38
+ | `normalizeTags`, `resolveTags` | utilities |
39
+
40
+ Matching rules: the subscriber's pattern is compared to each emitted tag segment by segment. A trailing `.*` in the pattern matches any deeper tags. A pattern that omits `:id` matches all instances; if both pin an id they must equal. An emitted `*` is a literal segment.
41
+
42
+ Ambient tags (cross-cutting dimensions such as currency) are appended to every subscription unless you pass `{ ambient: false }`. The default vocabulary is empty; define it per app with `tagImplications` if you need it.
43
+
44
+ Compose with an extra guard when needed:
45
+
46
+ ```ts
47
+ const byTags = shouldRevalidateForTags(['cart.*']);
48
+ export const shouldRevalidate = (args) => byTags(args) && args.nextUrl.searchParams.get('drawer') === 'open';
49
+ ```
50
+
51
+ Keep tag catalogs small and per domain in `src/lib/revalidation/tags/<domain>.ts`. Test them with the pattern in `index.example.test.ts`.
52
+
53
+ ## Root policy
54
+
55
+ The root policy (`routes/root.ts`) defaults to revalidate, so avoid adding expensive work to the root loader; put it in a leaf route or stream it. Request-wide state is produced by the middleware chain in `src/root.tsx`.
@@ -0,0 +1,123 @@
1
+ ---
2
+ name: sfnext-routing
3
+ description: >-
4
+ Add and change pages in a Storefront Next project: flat-file routes in src/routes, layout routes (_app, _checkout, _empty), splat routes for product and category pages, action.* and resource.* routes, src/route-paths.ts (routes, resourceRoutes, routeHref), site-aware Link and useNavigate wrappers, SeoMeta and JsonLd head tags, multi-site /:siteId/:localeId URL prefixes, url.seoRoutes and excludeRoutes, extension routes, and the SLAS callback routes. Use for "add a page", "new route", "why is my link missing the site prefix", "route file naming", "redirect to login", or a 404 on a new URL. Do not use for loader/action/fetcher data code (use `storefront-next:sfnext-data-fetching`), shouldRevalidate (use `storefront-next:sfnext-revalidation`), SEO strategy such as sitemaps and canonical rules (use `storefront-next:sfnext-seo`), or Page Designer regions (use `storefront-next:sfnext-page-designer`).
5
+ ---
6
+
7
+ # Storefront Next Routing
8
+
9
+ Storefront Next uses React Router 7 framework mode with file-based routes. Every route module lives in `src/routes/`; the file name is the URL. Your project also ships `docs/README-MULTI-SITE.md` (URL prefix, locale and site detection) and `docs/README-SEO.md` (titles, meta tags, canonical URLs); read those for depth.
10
+
11
+ ## How routes are discovered
12
+
13
+ `src/routes.ts` imports `flatRoutes` from `@salesforce/storefront-next-runtime/routing` (not `@react-router/fs-routes`). It is a drop-in wrapper that:
14
+
15
+ 1. scans `src/routes/` (test files are ignored),
16
+ 2. merges routes from `src/extensions/<name>/routes/` (see `storefront-next:sfnext-extensions`),
17
+ 3. wraps every route in the `app.url.prefix` pattern (default `/:siteId/:localeId`) through `src/app-wrapper.tsx`, and applies `app.url.seoRoutes` aliases to the product and category splats.
18
+
19
+ The two SLAS callback routes (`resource.slas-reset-password-callback.ts`, `resource.slas-passwordless-login-callback.ts`) are deliberately excluded from discovery in `src/routes.ts` and registered by hand at the bare paths `/reset-password-callback` and `/passwordless-login-callback`, outside the prefix, so a single callback URL works for all sites. If you add another server-to-server callback that cannot carry a site prefix, follow the same pattern in `src/routes.ts`.
20
+
21
+ ## Route tree (what exists)
22
+
23
+ | Pattern | Files | Notes |
24
+ |---|---|---|
25
+ | `_app` layout | `_app.tsx` | header/footer shell; loads navigation; `shouldRevalidate` returns `false` |
26
+ | Home, search, cart, wishlist | `_app._index.tsx`, `_app.search.tsx`, `_app.cart.tsx`, `_app.wishlist.tsx`, `_app.about-us.tsx` | |
27
+ | Product detail | `_app.p.$.tsx` | splat; URL shape is build-time configurable (`url.seoRoutes`) |
28
+ | Category / listing | `_app.c.$.tsx` | splat; URL shape is build-time configurable (`url.seoRoutes`) |
29
+ | Account | `_app.account.tsx` (layout + auth guard), `_app.account.overview`, `.orders`, `.orders.$orderNo`, `.addresses`, `.payment-methods`, `.wishlist`, `.passkeys`, `.store-preferences` | |
30
+ | Orders | `_app.order-confirmation.$orderNo.tsx`, `_app.order-lookup.*` (`results.$orderNo`, `verify.$orderNo`) | param is `$orderNo` |
31
+ | `_checkout` layout | `_checkout.tsx`, `_checkout.checkout.tsx` | checkout chrome |
32
+ | `_empty` layout | `_empty.tsx`, `_empty.login`, `.signup`, `.forgot-password`, `.reset-password`, `.logout`, `.maintenance`, `.oauth2.jwks`, `.preview.component`, `_empty.$.tsx` (catch-all) | no header/footer; there is no `_auth` layout |
33
+ | Mutations | `action.*.ts(x)` (cart, wishlist, checkout, OTP, passkey, consent, site context...) | no UI; see `storefront-next:sfnext-data-fetching` |
34
+ | Data endpoints | `resource.*.ts(x)` (recommendations, basket-products, category-products, analytics-proxy, `resource.api.client.$resource.ts`...) | no UI |
35
+
36
+ Naming rules (flat routes): `.` becomes `/`, `$name` is a param, `$` alone is a splat, a leading `_` segment is a pathless layout, `_index` is the index route. Pick the layout by prefix: `_app.` for standard pages, `_checkout.` for checkout, `_empty.` for header-less pages.
37
+
38
+ ## Add a page
39
+
40
+ ```tsx
41
+ // src/routes/_app.shipping-policy.tsx -> /shipping-policy
42
+ import type { Route } from './+types/_app.shipping-policy';
43
+ import { SeoMeta } from '@/components/seo-meta';
44
+ import { Link } from '@/components/link';
45
+ import { routes } from '@/route-paths';
46
+
47
+ export async function loader({ request }: Route.LoaderArgs) {
48
+ return { pageUrl: new URL(request.url).href };
49
+ }
50
+
51
+ export default function ShippingPolicy({ loaderData }: Route.ComponentProps) {
52
+ return (
53
+ <>
54
+ <SeoMeta title="Shipping policy" description="How we ship." openGraph={{ url: loaderData.pageUrl }} />
55
+ <h1>Shipping policy</h1>
56
+ <Link to={routes.cart}>Back to cart</Link>
57
+ </>
58
+ );
59
+ }
60
+ ```
61
+
62
+ Checklist for a new page:
63
+
64
+ 1. Create the file under `src/routes/` with the right layout prefix.
65
+ 2. Import types from `./+types/<file-name>` (`Route.LoaderArgs`, `Route.ComponentProps`, `Route.ActionArgs`). These are generated by `pnpm typecheck` (runs `react-router typegen`) and `pnpm dev`; run one if the import is unresolved.
66
+ 3. Add an entry to `routes` (page) or `resourceRoutes` (action/resource) in `src/route-paths.ts`. That file is the single source of truth for navigable paths. Keep it in sync when you rename or delete route files.
67
+ 4. Render `<SeoMeta>` (and `<JsonLd>` from `@/components/json-ld` for structured data) inside the component. React 19 hoists these tags to `<head>` and they work with streaming. Use `meta` exports only when a route already does.
68
+ 5. Add locale strings for user-facing text (`storefront-next:sfnext-i18n`) and a test next to the route (`storefront-next:sfnext-testing`).
69
+
70
+ ## Links and navigation: always use the project wrappers
71
+
72
+ ```tsx
73
+ import { Link, NavLink } from '@/components/link';
74
+ import { useNavigate } from '@/hooks/use-navigate';
75
+ import { href } from 'react-router';
76
+ import { routes, routeHref, resourceRoutes } from '@/route-paths';
77
+
78
+ <Link to={routes.cart}>Cart</Link>
79
+ <Link to={routeHref(routes.accountOrderDetail, { orderNo })}>Order</Link>
80
+ ```
81
+
82
+ `Link`, `NavLink` and `useNavigate` from `@/components/link` and `@/hooks/use-navigate` apply the site/locale prefix (`buildUrl`). The React Router originals compile but silently produce unprefixed URLs that break multi-site routing. `AGENTS.md` makes this a hard rule.
83
+
84
+ For product and category URLs use the helpers in `@/route-paths` (`createProductUrl`, `createCategoryUrl`, `createCategoryNavigationUrl`) with the SEO URL context so links follow `url.seoRoutes`. In server code (redirects), use `buildUrlFromContext(routes.login, context)` from `@/lib/url.server`:
85
+
86
+ ```ts
87
+ import { redirect } from 'react-router';
88
+ import { routes } from '@/route-paths';
89
+ import { buildUrlFromContext } from '@/lib/url.server';
90
+
91
+ throw redirect(buildUrlFromContext(routes.login, context));
92
+ ```
93
+
94
+ Form and fetcher `action` targets come from `resourceRoutes` (for example `resourceRoutes.cartItemAdd`), which are excluded from the site prefix via `app.url.excludeRoutes` in `config.server.ts` (`['/resource/**', '/action/**']` by default). A new `action.*` or `resource.*` route needs no prefix handling; a new page route gets it automatically.
95
+
96
+ ## URL configuration
97
+
98
+ `app.url` in `config.server.ts` (`prefix`, `excludeRoutes` and `seoRoutes` are protected config paths: set them in the file and rebuild, they cannot be overridden with `PUBLIC__` env vars; see `storefront-next:sfnext-configuration`) controls `prefix`, `excludeRoutes`, search-param mode, detection and `seoRoutes` (configurable product and category URL grammars). Changing the prefix or `seoRoutes` affects every link; follow `docs/README-MULTI-SITE.md` in your project rather than editing ad hoc.
99
+
100
+ ## Protecting routes
101
+
102
+ There is no `_auth` layout. Guard in the loader: read the session with `getAuth(context)` from `@/middlewares/auth.server` and `throw redirect(...)` to `routes.login` (see `_app.account.tsx` and `_app.wishlist.tsx`). Auth details: `storefront-next:sfnext-authentication`.
103
+
104
+ ## Rules to keep in mind
105
+
106
+ - Only server `loader` and `action` exports are allowed; no `clientLoader`/`clientAction`.
107
+ - Throw `new Response('...', { status: 404 })` for missing content so the right HTTP status reaches crawlers.
108
+ - Resource routes called from the browser should reject cross-origin requests (see `resource.recommendations.ts` for the pattern).
109
+ - Deeper references: [ROUTE-CONVENTIONS.md](references/ROUTE-CONVENTIONS.md) for exports and naming, [URLS-AND-SEO-ROUTES.md](references/URLS-AND-SEO-ROUTES.md) for prefixes and SEO aliases.
110
+
111
+ ## Finding more
112
+
113
+ Read `AGENTS.md` in your project for the doc index. For other framework questions use `b2c docs search "storefront next routing"` (or the `docs_search` MCP tool).
114
+
115
+ ## Related Skills
116
+
117
+ - `storefront-next:sfnext-data-fetching` - loaders, actions, fetchers
118
+ - `storefront-next:sfnext-revalidation` - `shouldRevalidate` policy per route
119
+ - `storefront-next:sfnext-seo` - canonical URLs, structured data, sitemaps
120
+ - `storefront-next:sfnext-page-designer` - `@PageType` and regions on routes
121
+ - `storefront-next:sfnext-extensions` - routes contributed by extensions
122
+ - `storefront-next:sfnext-authentication` - sessions and login flows
123
+ - `storefront-next:sfnext-overview` - architecture map
@@ -0,0 +1,65 @@
1
+ # Route conventions
2
+
3
+ ## File name to URL
4
+
5
+ | File | URL (before the site/locale prefix) |
6
+ |---|---|
7
+ | `_app._index.tsx` | `/` |
8
+ | `_app.cart.tsx` | `/cart` |
9
+ | `_app.account.orders.$orderNo.tsx` | `/account/orders/:orderNo` |
10
+ | `_app.p.$.tsx` | product splat (shape set by `url.seoRoutes`; use `createProductUrl`) |
11
+ | `_app.c.$.tsx` | category splat (shape set by `url.seoRoutes`; use `createCategoryUrl`) |
12
+ | `_checkout.checkout.tsx` | `/checkout` |
13
+ | `_empty.login.tsx` | `/login` |
14
+ | `action.cart-item-add.tsx` | `/action/cart-item-add` |
15
+ | `resource.recommendations.ts` | `/resource/recommendations` |
16
+ | `resource.api.client.$resource.ts` | `/resource/api/client/:resource` |
17
+
18
+ - A segment starting with `_` and no matching file content of its own is a pathless layout (`_app`, `_checkout`, `_empty`). The layout file (`_app.tsx`) renders `<Outlet />`.
19
+ - A nested layout is a route file plus children, for example `_app.account.tsx` with `_app.account.overview.tsx` beneath it.
20
+ - `.ts` is enough for routes without JSX (actions, resource routes, `_empty.logout.ts`).
21
+ - Files named `*.test.ts(x)` beside routes are ignored by route discovery.
22
+
23
+ ## Route module exports
24
+
25
+ | Export | Purpose |
26
+ |---|---|
27
+ | `loader` | server data for the route (see `storefront-next:sfnext-data-fetching`) |
28
+ | `action` | server mutation |
29
+ | default component | receives `loaderData` via `Route.ComponentProps` |
30
+ | `shouldRevalidate` | revalidation policy; most routes re-export from `@/lib/revalidation/routes/*` (see `storefront-next:sfnext-revalidation`) |
31
+ | `middleware` | route-level server middleware (root chain lives in `src/root.tsx`) |
32
+ | `ErrorBoundary` | route-scoped error UI (for example wishlist load failures) |
33
+ | `links` / `meta` | mostly used in `src/root.tsx`; prefer `<SeoMeta>` in components |
34
+ | Page Designer classes | `@PageType` and `@RegionDefinition` on an exported class, see `storefront-next:sfnext-page-designer` |
35
+
36
+ `clientLoader` and `clientAction` are not permitted.
37
+
38
+ ## Typed route props
39
+
40
+ ```tsx
41
+ import type { Route } from './+types/_app.cart';
42
+
43
+ export async function loader({ request, context, params }: Route.LoaderArgs) { /* ... */ }
44
+ export default function Cart({ loaderData }: Route.ComponentProps) { /* ... */ }
45
+ ```
46
+
47
+ The `+types` modules are generated. Run `pnpm typecheck` or `pnpm dev` to create them.
48
+
49
+ ## Layout notes
50
+
51
+ - `_app.tsx` loads navigation categories once and exports `shouldRevalidate() { return false }`, so the header data is not re-fetched on later navigations. Change this only if you add navigation that must update.
52
+ - `_empty.tsx` is a minimal `<main>` with a skip link, used by login, signup, callbacks, maintenance and the component preview.
53
+ - `_checkout.tsx` provides the checkout layout.
54
+ - `_app.account.tsx` is the account layout and redirects unauthenticated shoppers to login.
55
+
56
+ ## Head tags
57
+
58
+ `SeoMeta` props: `title`, `rawTitle`, `description`, `noIndex`, `siteName`, `twitter`, `openGraph`. Use `noIndex` on account and transactional pages. `JsonLd` takes `data`, optional `id` and `nonce`. Both can be rendered anywhere in the tree, including inside a Suspense boundary.
59
+
60
+ ## Checklist when renaming or deleting a route
61
+
62
+ 1. Update `src/route-paths.ts`.
63
+ 2. Search for the old path in links, redirects, `resourceRoutes` users and tests.
64
+ 3. Re-run `pnpm typecheck` to regenerate `+types`.
65
+ 4. If the route is referenced by `shouldRevalidate` policies in `src/lib/revalidation/routes/`, update those.
@@ -0,0 +1,22 @@
1
+ # Site prefixes, excluded routes and SEO aliases
2
+
3
+ Configuration lives under `app.url` in `config.server.ts`. Full reference: `docs/README-CONFIG-OPTIONS.md` and `docs/README-MULTI-SITE.md` in your project.
4
+
5
+ | Key | Effect |
6
+ |---|---|
7
+ | `url.prefix` | path pattern wrapped around every page route; default `/:siteId/:localeId` |
8
+ | `url.excludeRoutes` | globs that skip the prefix; default `['/resource/**', '/action/**']` |
9
+ | `url.seoRoutes` | per-site product and category URL grammars (slug segments, category modes, redirects) |
10
+
11
+ ## Rules
12
+
13
+ - Define page paths without the prefix (as in `src/route-paths.ts`). The `Link` wrapper, `useNavigate` and `buildUrlFromContext` add it.
14
+ - Never concatenate `/${siteId}/${locale}` by hand.
15
+ - Keep `_app.p.$.tsx` and `_app.c.$.tsx` as splat routes; `seoRoutes` aliases resolve through them. Do not rename them.
16
+ - Build product and category links with `createProductUrl`, `createCategoryUrl` and `createCategoryNavigationUrl` from `@/route-paths`, passing the SEO URL context (`useSeoUrlContext` in `@/hooks/use-seo-url-context`), so slugs and prefixes stay consistent.
17
+ - A loader that resolves a product or category from the URL should use the resolvers under `@/lib/seo/` (see `_app.p.$.tsx`: `resolveProductRoute` from `@/lib/seo/url-resolution.server`) instead of parsing `params` directly.
18
+ - For SEO URL strategy and Business Manager alignment see `storefront-next:sfnext-seo`.
19
+
20
+ ## Callbacks that cannot carry a prefix
21
+
22
+ SLAS redirects back to a fixed URL. Register such routes by hand in `src/routes.ts`: add the file to `IGNORED_ROUTE_FILES` and append `route('/your-callback', 'routes/your-file.ts')` after `flatRoutes(...)`, exactly as the two existing SLAS callbacks do. Then register the full URL in SLAS (see `storefront-next:sfnext-authentication`).
@@ -0,0 +1,126 @@
1
+ ---
2
+ name: sfnext-scapi
3
+ description: >-
4
+ Use and extend SCAPI clients in a Storefront Next project: createApiClients, the `@/scapi` type barrel, typing `c_*` custom attributes by overriding a built-in client, and adding your own custom API end to end with `b2c sfnext scapi` (add, available, list, remove). Use for "clients.shopperProducts", "c_ attribute is not typed", "sfnext scapi add", "add custom API to the storefront", src/scapi/ generated files, custom-clients.ts, calling a loyalty/notify-style custom endpoint from a loader or action, useScapiFetcher, personalized=none for custom clients, or 404 from a custom endpoint. Do not use for writing the cartridge/schema.yaml itself (use `b2c:b2c-custom-api-development`), endpoint registration status (use `b2c-cli:b2c-scapi-custom`), loader/caching strategy (use `storefront-next:sfnext-data-fetching`), or login/session code (use `storefront-next:sfnext-authentication`).
5
+ ---
6
+
7
+ # Storefront Next SCAPI Clients and Custom APIs
8
+
9
+ The runtime (`@salesforce/storefront-next-runtime/scapi`) already ships typed clients for the standard shopper APIs (products, search, baskets, customers, orders, and so on). You do not "add" those. `sfnext scapi add` does one of two things on top:
10
+
11
+ 1. **Override** a built-in client (client key matches, for example `shopperProducts`) with a richer schema, typically your tenant's schema expanded with `c_*` custom attributes, so `product.c_myAttr` is typed.
12
+ 2. **Add a custom API** you deployed to B2C Commerce (a new property such as `clients.loyalty`).
13
+
14
+ Which one you get is decided automatically from the client key. Deep dive: `docs/README-SCAPI.md` in your project.
15
+
16
+ ## The CLI surface
17
+
18
+ Run as `b2c sfnext scapi ...`, or inside your project as `pnpm sfnext scapi ...` (the `sfnext` bin ships with the project). Add `-d <dir>` / `--project-directory` to target another directory.
19
+
20
+ | Command | What it does |
21
+ |---|---|
22
+ | `scapi available` | Probes your tenant: for each of the built-in shopper APIs counts `c_*` attributes, lists tenant custom APIs, and prints the matching `scapi add` command. Needs OAuth. No filter flags. |
23
+ | `scapi add <apiFamily> <apiName> <apiVersion>` | Pull mode: fetch the schema from the SCAPI Schemas API. Needs OAuth. |
24
+ | `scapi add --schema <file> --name <clientKey>` | Local mode: use a YAML/JSON OpenAPI file. `--name` is required here. |
25
+ | `scapi list` | Shows registered Overrides and Custom APIs (schema, base path, locale). |
26
+ | `scapi remove <clientKey>` | Removes the registration and its generated files (one positional argument: the client key, for example `loyalty`). |
27
+
28
+ `add` flags: `--name <key>` (defaults to camelCase of the API name in pull mode), `--base-path <path>` (derived from the schema `servers[].url` if omitted), `--supports-locale` / `--no-supports-locale` (overrides inherit the built-in default), `--expand-custom-properties` (default on, pull mode only; include `c_*`, use `--no-expand-custom-properties` to skip). Re-running `add` regenerates; there is no `--force` and no `--json`. There is no install step after `add`.
29
+
30
+ **Pull mode prerequisites:** SCAPI short code (`SFCC_SHORTCODE` or `--short-code`), tenant id (`SFCC_TENANT_ID` or `--tenant-id`), and an Account Manager API client allowed the `sfcc.scapi-schemas` scope (`SFCC_CLIENT_ID` and `SFCC_CLIENT_SECRET`, or `--client-id`/`--client-secret`, or `dw.json`). The legacy names `SFCC_OAUTH_CLIENT_ID` / `SFCC_OAUTH_CLIENT_SECRET` are also accepted because the CLI resolves both. If the `@salesforce/storefront-next-dev` package is in the project, `b2c` uses that local version.
31
+
32
+ ```bash
33
+ # Which built-in APIs have c_ attributes on my tenant? Which custom APIs exist?
34
+ b2c sfnext scapi available
35
+
36
+ # Type c_* attributes on products (override; pulls schema with custom properties)
37
+ b2c sfnext scapi add product shopper-products v1
38
+
39
+ # Register a custom API from the tenant, or from a local file
40
+ b2c sfnext scapi add custom loyalty v1
41
+ b2c sfnext scapi add --schema ./loyalty-api.yaml --name loyalty --base-path /custom/loyalty/v1
42
+
43
+ b2c sfnext scapi list
44
+ b2c sfnext scapi remove loyalty
45
+ ```
46
+
47
+ For a schema-only look without touching the project use `b2c scapi schemas get/list` (see `b2c-cli:b2c-scapi-schemas`; both need `--tenant-id`).
48
+
49
+ ## What gets generated
50
+
51
+ ```
52
+ src/scapi/
53
+ index.ts barrel (generated), the only SCAPI import surface for app code
54
+ custom-clients.ts registry of overrides and custom clients (generated)
55
+ schemas/ <name>-<ver>.yaml and .meta.json
56
+ generated/ <name>-<ver>.ts, .operations.ts, (.namespace.ts for overrides)
57
+ ```
58
+
59
+ Never hand-edit these; rerun `sfnext scapi add`. Registry entries carry `key`, `basePath`, `ops`, `locale`, `orgPrefix`. Custom clients use `orgPrefix: true` (base `/custom/<name>/v1/organizations/{orgId}`); the shipped `sfnextNotify` entry is a working example.
60
+
61
+ ## Import rule
62
+
63
+ Import types and clients from the barrel, not from the runtime package:
64
+
65
+ ```typescript
66
+ import { ApiError, type ShopperProducts } from '@/scapi'; // picks up overrides
67
+ // import { ShopperProducts } from '@salesforce/storefront-next-runtime/scapi'; // bypasses overrides, lint warns
68
+ ```
69
+
70
+ Only `src/scapi/**` and `src/lib/api-clients.server.ts` may import the runtime path directly.
71
+
72
+ ## Use clients in loaders and actions
73
+
74
+ ```typescript
75
+ import { createApiClients } from '@/lib/api-clients.server';
76
+
77
+ export async function loader({ context }: LoaderFunctionArgs) {
78
+ const clients = createApiClients(context);
79
+ const { data: product } = await clients.shopperProducts.getProduct({
80
+ params: { path: { id: 'my-product-id' } },
81
+ });
82
+ const { data: rewards } = await clients.loyalty.getLoyaltyRewards(); // custom client
83
+ return { product, rewardTier: product?.c_loyaltyTier, rewards };
84
+ }
85
+ ```
86
+
87
+ - Calls return `{ data }` and **throw** `ApiError` on failure (wrap in `NormalizedApiError` from `@/lib/api/normalized-api-error` when you need a message/status).
88
+ - `createApiClients` automatically injects `organizationId`, `siteId` and (when the client supports it) `locale`. Do not pass `siteId` yourself.
89
+ - Auth comes from the shopper token in the auth middleware (`storefront-next:sfnext-authentication`); do not read tokens to call SCAPI manually. Get the shopper via `getAuth(context)` only when you need `customerId`.
90
+ - Prefer the existing helpers in `src/lib/api/*.server.ts` (search, products, basket, wishlist, order) for standard APIs, and put your own custom-API calls in a new `src/lib/api/<thing>.server.ts`.
91
+ - Calling from the browser: `useScapiFetcher(client, method, options)` goes through `/resource/api/client/...`, which only allows a short **allow-list** of operations (`src/lib/scapi/resource-policy.ts`), and `siteId`/`locale`/`organizationId` are server-owned. A new custom operation is not callable from the browser until you add it there; prefer a route loader/action. The `'helpers'` overload is deprecated. See `docs/README-PERFORMANCE.md` and `docs/README-REVALIDATION.md` for fetcher lifecycle rules.
92
+
93
+ ## End-to-end: a new custom API
94
+
95
+ 1. **Author the endpoint** (cartridge `rest-apis/<api-name>/` with `api.json`, `schema.yaml`, script) using `b2c:b2c-custom-api-development`. `api.json` maps `endpoint` to `schema` and `implementation`; auth is declared in `schema.yaml` (`ShopperToken` for storefront calls, with a `c_` scope under `security:`). The shipped `cartridges/app_storefrontnext_base/cartridge/rest-apis/sfnext-notify/` is a complete example.
96
+ 2. **Deploy and activate**: `b2c code deploy <cartridge> --reload` (reload toggles activation so endpoints re-register; see `b2c-cli:b2c-code`).
97
+ 3. **Confirm registration**: `b2c scapi custom status --tenant-id <id>` (filter with `--status not_registered`). Use `b2c-cli:b2c-scapi-custom` for 404s and `errorReason`.
98
+ 4. **Allow the scope**: add the custom scope to the SLAS client used by the storefront (`b2c-cli:b2c-slas`). The shopper token must carry it, otherwise calls get 401/403.
99
+ 5. **Register in the storefront**: `b2c sfnext scapi add custom <api-name> v1` (or `--schema` with a local copy).
100
+ 6. **Call it** from a server loader/action as above; `import type` request/response types from `@/scapi`.
101
+ 7. After schema changes repeat steps 2 and 5.
102
+
103
+ ## Non-personalized caching
104
+
105
+ Storefront Next can add `personalized=none` to eligible GET requests through one central policy. Overrides and custom clients are **left unclassified** until you review and approve their exact transports in the policy module. Do not loosen it to `() => true`. See `docs/README-SCAPI-NON-PERSONALIZED-RESPONSES.md` before approving a client.
106
+
107
+ ## Pitfalls
108
+
109
+ - Expecting `scapi add shopper-search ...` to be needed: standard clients already exist.
110
+ - Importing from `@salesforce/storefront-next-runtime/scapi` and wondering why `c_*` is untyped.
111
+ - Forgetting `--reload` after deploy, so the endpoint stays unregistered (404).
112
+ - Passing `siteId` or `locale` in `params.query`: server-owned, stripped on the resource route and injected elsewhere.
113
+ - Override key typos: the key must exactly match a built-in (`shopperProducts`, `shopperBasketsV2`, ...) or you create an unrelated custom client.
114
+ - Custom client used from the browser fetcher without allow-listing it.
115
+
116
+ Worked example of a shipped custom API: [references/WORKED-EXAMPLE.md](references/WORKED-EXAMPLE.md).
117
+
118
+ ## Related Skills
119
+
120
+ - `b2c:b2c-custom-api-development` - author the cartridge, api.json, schema.yaml, scripts
121
+ - `b2c-cli:b2c-scapi-custom` - registration status and debugging 404s
122
+ - `b2c-cli:b2c-scapi-schemas` - browse SCAPI schemas
123
+ - `b2c-cli:b2c-slas` - add custom scopes to the SLAS client
124
+ - `storefront-next:sfnext-data-fetching` - loaders, actions, caching
125
+ - `storefront-next:sfnext-authentication` - `getAuth`, sessions
126
+ - `storefront-next:sfnext-revalidation` - fetcher revalidation rules