@thorprovider/storefront 0.3.1 → 0.4.0-mvp.2

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 (263) hide show
  1. package/README.md +321 -152
  2. package/VENDOR.md +69 -0
  3. package/assets/openspec/config.yaml +38 -0
  4. package/assets/templates/AGENTS.md +76 -0
  5. package/assets/templates/app/app/[[...slug]]/page.tsx +54 -2
  6. package/assets/templates/app/app/[[...slug]]/renderer.tsx +13 -2
  7. package/assets/templates/app/app/globals.css +5 -8
  8. package/assets/templates/app/app/layout.tsx +17 -7
  9. package/assets/templates/app/app/robots.ts +19 -0
  10. package/assets/templates/app/app/sitemap.ts +71 -0
  11. package/assets/templates/app/lib/__STOREFRONT__/actions.ts +612 -0
  12. package/assets/templates/app/lib/__STOREFRONT__/cart-state.ts +66 -0
  13. package/assets/templates/app/lib/__STOREFRONT__/catalog.ts +50 -57
  14. package/assets/templates/app/lib/__STOREFRONT__/commerce.ts +679 -0
  15. package/assets/templates/app/lib/__STOREFRONT__/composition.ts +26 -0
  16. package/assets/templates/app/lib/__STOREFRONT__/handlers.core.ts +197 -0
  17. package/assets/templates/app/lib/__STOREFRONT__/handlers.ts +5 -36
  18. package/assets/templates/app/lib/__STOREFRONT__/icon-map.ts +27 -0
  19. package/assets/templates/app/lib/__STOREFRONT__/mappers.ts +13 -11
  20. package/assets/templates/app/lib/__STOREFRONT__/registry.tsx +264 -51
  21. package/assets/templates/app/lib/__STOREFRONT__/runtime.ts +6 -3
  22. package/assets/templates/app/lib/__STOREFRONT__/schema.ts +136 -0
  23. package/assets/templates/app/lib/__STOREFRONT__/section-observation.ts +182 -0
  24. package/assets/templates/app/lib/__STOREFRONT__/section-sources.ts +130 -0
  25. package/assets/templates/app/lib/__STOREFRONT__/session.core.ts +470 -0
  26. package/assets/templates/app/lib/__STOREFRONT__/session.ts +169 -0
  27. package/assets/templates/app/lib/__STOREFRONT__/shell/content.ts +120 -0
  28. package/assets/templates/app/lib/__STOREFRONT__/shell/props.ts +38 -0
  29. package/assets/templates/app/lib/__STOREFRONT__/spec/index.ts +129 -10
  30. package/assets/templates/app/lib/__STOREFRONT__/spec/page-root.ts +5 -1
  31. package/assets/templates/app/lib/__STOREFRONT__/spec/seo.ts +191 -0
  32. package/assets/templates/app/lib/__STOREFRONT__/state.core.ts +257 -0
  33. package/assets/templates/app/lib/__STOREFRONT__/state.ts +7 -31
  34. package/assets/templates/app/lib/__STOREFRONT__/store-context.ts +161 -0
  35. package/assets/templates/app/lib/__STOREFRONT__/views/sections/cta.client.tsx +25 -0
  36. package/assets/templates/app/lib/__STOREFRONT__/views/sections/cta.tsx +16 -0
  37. package/assets/templates/app/lib/__STOREFRONT__/views/sections/faq.client.tsx +24 -0
  38. package/assets/templates/app/lib/__STOREFRONT__/views/sections/faq.tsx +5 -18
  39. package/assets/templates/app/lib/__STOREFRONT__/views/sections/index.ts +18 -0
  40. package/assets/templates/app/lib/__STOREFRONT__/views/sections/logoCloud.tsx +26 -14
  41. package/assets/templates/app/lib/__STOREFRONT__/views/sections/pricing.tsx +36 -18
  42. package/assets/templates/app/lib/__STOREFRONT__/views/sections/products.client.tsx +100 -0
  43. package/assets/templates/app/lib/__STOREFRONT__/views/sections/products.tsx +19 -0
  44. package/assets/templates/app/lib/__STOREFRONT__/views/sections/schema.cta.ts +19 -0
  45. package/assets/templates/app/lib/__STOREFRONT__/views/sections/schema.faq.ts +18 -0
  46. package/assets/templates/app/lib/__STOREFRONT__/views/sections/schema.products.ts +39 -0
  47. package/assets/templates/app/lib/__STOREFRONT__/views/sections/statistics.tsx +35 -14
  48. package/assets/templates/app/lib/__STOREFRONT__/views/sections/testimonials.tsx +31 -13
  49. package/assets/templates/app/lib/__STOREFRONT__/views/types.ts +5 -3
  50. package/assets/templates/features/checkout/handlers.ts +159 -0
  51. package/assets/templates/features/checkout/state.ts +61 -0
  52. package/assets/templates/features/customer-auth/handlers.ts +59 -0
  53. package/assets/templates/features/customer-auth/state.ts +45 -0
  54. package/assets/templates/features/recommendations/state.ts +11 -0
  55. package/assets/templates/views/account/content.ts +35 -0
  56. package/assets/templates/views/account/index.tsx +114 -0
  57. package/assets/templates/views/account/registry.tsx +439 -0
  58. package/assets/templates/views/account/schema.ts +53 -0
  59. package/assets/templates/views/cart/content.ts +11 -0
  60. package/assets/templates/views/cart/data.ts +23 -0
  61. package/assets/templates/views/cart/index.tsx +53 -0
  62. package/assets/templates/views/cart/props.ts +12 -0
  63. package/assets/templates/views/cart/registry.tsx +81 -0
  64. package/assets/templates/views/cart/schema.ts +52 -0
  65. package/assets/templates/views/category/assembly/assembly.json +29 -0
  66. package/assets/templates/views/category/assembly/index.skeleton.tsx +251 -0
  67. package/assets/templates/views/category/assembly/registry.skeleton.tsx +34 -0
  68. package/assets/templates/views/category/assembly/slots/breadcrumb/Breadcrumb/binding.json +5 -0
  69. package/assets/templates/views/category/assembly/slots/breadcrumb/Breadcrumb/catalog.part +4 -0
  70. package/assets/templates/views/category/assembly/slots/breadcrumb/Breadcrumb/element.part +7 -0
  71. package/assets/templates/views/category/assembly/slots/breadcrumb/Breadcrumb/registry.part +18 -0
  72. package/assets/templates/views/category/assembly/slots/filter/CategoryFilter2/catalog.part +5 -0
  73. package/assets/templates/views/category/assembly/slots/filter/CategoryFilter2/element.part +34 -0
  74. package/assets/templates/views/category/assembly/slots/filter/CategoryFilter2/registry.part +71 -0
  75. package/assets/templates/views/category/content.ts +30 -0
  76. package/assets/templates/views/category/data.ts +12 -0
  77. package/assets/templates/views/category/index.tsx +299 -0
  78. package/assets/templates/views/category/props.ts +23 -0
  79. package/assets/templates/views/category/registry.tsx +122 -0
  80. package/assets/templates/views/category/schema.ts +91 -0
  81. package/assets/templates/views/checkout/content.ts +105 -0
  82. package/assets/templates/views/checkout/data.ts +23 -0
  83. package/assets/templates/views/checkout/index.tsx +111 -0
  84. package/assets/templates/views/checkout/props.ts +49 -0
  85. package/assets/templates/views/checkout/registry.tsx +217 -0
  86. package/assets/templates/views/checkout/schema.ts +229 -0
  87. package/assets/templates/views/home/assembly/assembly.json +33 -0
  88. package/assets/templates/views/home/assembly/index.skeleton.tsx +90 -0
  89. package/assets/templates/views/home/assembly/registry.skeleton.tsx +25 -0
  90. package/assets/templates/views/home/assembly/slots/benefits/Feature1/binding.json +5 -0
  91. package/assets/templates/views/home/assembly/slots/benefits/Feature1/catalog.part +4 -0
  92. package/assets/templates/views/home/assembly/slots/benefits/Feature1/element.part +4 -0
  93. package/assets/templates/views/home/assembly/slots/benefits/Feature1/registry.part +11 -0
  94. package/assets/templates/views/home/assembly/slots/benefits/Feature2/binding.json +5 -0
  95. package/assets/templates/views/home/assembly/slots/benefits/Feature2/catalog.part +4 -0
  96. package/assets/templates/views/home/assembly/slots/benefits/Feature2/element.part +4 -0
  97. package/assets/templates/views/home/assembly/slots/benefits/Feature2/registry.part +10 -0
  98. package/assets/templates/views/home/assembly/slots/categories/ProductCategory2/binding.json +5 -0
  99. package/assets/templates/views/home/assembly/slots/categories/ProductCategory2/catalog.part +4 -0
  100. package/assets/templates/views/home/assembly/slots/categories/ProductCategory2/element.part +5 -0
  101. package/assets/templates/views/home/assembly/slots/categories/ProductCategory2/registry.part +16 -0
  102. package/assets/templates/views/home/assembly/slots/hero/StorefrontHero1/binding.json +5 -0
  103. package/assets/templates/views/home/assembly/slots/hero/StorefrontHero1/catalog.part +4 -0
  104. package/assets/templates/views/home/assembly/slots/hero/StorefrontHero1/element.part +5 -0
  105. package/assets/templates/views/home/assembly/slots/hero/StorefrontHero1/registry.part +26 -0
  106. package/assets/templates/views/home/content.ts +70 -0
  107. package/assets/templates/views/home/data.ts +24 -0
  108. package/assets/templates/views/home/index.tsx +57 -85
  109. package/assets/templates/views/home/props.ts +22 -0
  110. package/assets/templates/views/home/registry.tsx +38 -22
  111. package/assets/templates/views/home/schema.ts +93 -0
  112. package/assets/templates/views/product/content.ts +25 -0
  113. package/assets/templates/views/product/data.ts +50 -0
  114. package/assets/templates/views/product/index.tsx +148 -0
  115. package/assets/templates/views/product/props.ts +27 -0
  116. package/assets/templates/views/product/registry.tsx +103 -0
  117. package/assets/templates/views/product/schema.ts +121 -0
  118. package/assets/templates/views/static/content.ts +99 -0
  119. package/assets/templates/views/static/index.tsx +60 -0
  120. package/assets/templates/views/static/registry.tsx +66 -0
  121. package/assets/templates/views/static/schema.ts +45 -0
  122. package/bin/storefront.js +2424 -148
  123. package/examples/merchandising/category-led.json +37 -0
  124. package/examples/merchandising/collection-led.json +37 -0
  125. package/package.json +15 -9
  126. package/recipes/archetypes.json +28 -14
  127. package/recipes/catalog.json +400 -0
  128. package/recipes/catalog.mjs +128 -0
  129. package/recipes/catalog.schema.json +64 -0
  130. package/recipes/feature.schema.json +89 -0
  131. package/recipes/features.json +162 -0
  132. package/recipes/manifest.schema.json +69 -0
  133. package/recipes/operations.schema.json +43 -0
  134. package/recipes/recipe.schema.json +11 -2
  135. package/recipes/recipes.json +76 -19
  136. package/recipes/sections.json +34 -5
  137. package/recipes/validate.mjs +838 -32
  138. package/scripts/candidate.mjs +236 -0
  139. package/scripts/composers.mjs +160 -0
  140. package/scripts/env-file.mjs +86 -0
  141. package/scripts/file-classes.mjs +121 -0
  142. package/scripts/logical-controls.mjs +61 -0
  143. package/scripts/manifest.mjs +298 -0
  144. package/scripts/migrate-english-routes.mjs +276 -0
  145. package/scripts/operation-registry.mjs +256 -0
  146. package/scripts/operations.mjs +720 -0
  147. package/scripts/ownership-conflict.mjs +356 -0
  148. package/scripts/pinning.mjs +573 -0
  149. package/scripts/plan-apply.mjs +987 -0
  150. package/scripts/preflight.mjs +51 -0
  151. package/scripts/reconcile.mjs +549 -0
  152. package/scripts/render-templates.mjs +338 -68
  153. package/scripts/schema-validate.mjs +132 -0
  154. package/scripts/section-compat.mjs +300 -0
  155. package/scripts/section-config.mjs +253 -0
  156. package/scripts/section-operations.mjs +508 -0
  157. package/scripts/starter.mjs +17 -0
  158. package/scripts/sync-assets.mjs +22 -15
  159. package/scripts/theme/color.mjs +185 -0
  160. package/scripts/theme/css-theme.mjs +233 -0
  161. package/scripts/theme/fonts.mjs +123 -0
  162. package/scripts/theme/import-export.mjs +125 -0
  163. package/scripts/theme/preset.mjs +93 -0
  164. package/scripts/theme/theme-plan.mjs +292 -0
  165. package/scripts/theme/tokens.mjs +137 -0
  166. package/scripts/view-assembly.mjs +337 -0
  167. package/scripts/view-selection.mjs +211 -0
  168. package/skills/sf-feature/SKILL.md +80 -0
  169. package/skills/sf-setup/SKILL.md +79 -0
  170. package/skills/sf-theme-gen/SKILL.md +100 -30
  171. package/skills/sf-theme-gen/references/shadcn-theming.md +87 -0
  172. package/skills/{shadcn-theming/references/templates → sf-theme-gen/references}/theme-setup.md +15 -19
  173. package/skills/{shadcn-theming → sf-theme-gen}/references/theming-guide.md +6 -11
  174. package/skills/sf-view-gen/SKILL.md +146 -93
  175. package/skills/sf-view-gen/assets/recipes/archetypes.json +28 -14
  176. package/skills/sf-view-gen/assets/recipes/catalog.json +400 -0
  177. package/skills/sf-view-gen/assets/recipes/catalog.schema.json +64 -0
  178. package/skills/sf-view-gen/assets/recipes/features.json +162 -0
  179. package/skills/sf-view-gen/assets/recipes/recipes.json +76 -19
  180. package/skills/sf-view-gen/assets/recipes/sections.json +34 -5
  181. package/skills/sf-view-gen/assets/templates/views/sections/cta.client.tsx +25 -0
  182. package/skills/sf-view-gen/assets/templates/views/sections/cta.tsx +16 -0
  183. package/skills/sf-view-gen/assets/templates/views/sections/faq.client.tsx +13 -9
  184. package/skills/sf-view-gen/assets/templates/views/sections/faq.tsx +2 -7
  185. package/skills/sf-view-gen/assets/templates/views/sections/logoCloud.client.tsx +12 -8
  186. package/skills/sf-view-gen/assets/templates/views/sections/logoCloud.tsx +2 -7
  187. package/skills/sf-view-gen/assets/templates/views/sections/pricing.client.tsx +14 -10
  188. package/skills/sf-view-gen/assets/templates/views/sections/pricing.tsx +2 -9
  189. package/skills/sf-view-gen/assets/templates/views/sections/products.client.tsx +100 -0
  190. package/skills/sf-view-gen/assets/templates/views/sections/products.tsx +19 -0
  191. package/skills/sf-view-gen/assets/templates/views/sections/schema.cta.ts +19 -0
  192. package/skills/sf-view-gen/assets/templates/views/sections/schema.faq.ts +18 -0
  193. package/skills/sf-view-gen/assets/templates/views/sections/schema.logoCloud.ts +19 -0
  194. package/skills/sf-view-gen/assets/templates/views/sections/schema.pricing.ts +26 -0
  195. package/skills/sf-view-gen/assets/templates/views/sections/schema.products.ts +39 -0
  196. package/skills/sf-view-gen/assets/templates/views/sections/schema.statistics.ts +25 -0
  197. package/skills/sf-view-gen/assets/templates/views/sections/schema.testimonials.ts +23 -0
  198. package/skills/sf-view-gen/assets/templates/views/sections/statistics.client.tsx +16 -8
  199. package/skills/sf-view-gen/assets/templates/views/sections/statistics.tsx +2 -7
  200. package/skills/sf-view-gen/assets/templates/views/sections/testimonials.client.tsx +13 -9
  201. package/skills/sf-view-gen/assets/templates/views/sections/testimonials.tsx +2 -5
  202. package/skills/{json-render-core/SKILL.md → sf-view-gen/references/json-render-core.md} +4 -27
  203. package/skills/{json-render-next/SKILL.md → sf-view-gen/references/json-render-next.md} +5 -8
  204. package/skills/{json-render-react/SKILL.md → sf-view-gen/references/json-render-react.md} +3 -5
  205. package/skills/{json-render-shadcn/SKILL.md → sf-view-gen/references/json-render-shadcn.md} +3 -5
  206. package/skills/sf-view-gen/references/views.md +58 -33
  207. package/skills/sf-view-gen/scripts/catalog.mjs +128 -0
  208. package/skills/sf-view-gen/scripts/schema-validate.mjs +132 -0
  209. package/skills/sf-view-gen/scripts/validate.mjs +838 -32
  210. package/skills/storefront-workflow/SKILL.md +179 -0
  211. package/skills/{storefront-best-practices/reference/design.md → storefront-workflow/references/design-consistency.md} +13 -29
  212. package/CHANGELOG.md +0 -61
  213. package/commands/sf-add-view.md +0 -26
  214. package/commands/sf-theme.md +0 -20
  215. package/commands/sf-view.md +0 -25
  216. package/skills/building-storefronts/SKILL.md +0 -178
  217. package/skills/building-storefronts/references/frontend-integration.md +0 -229
  218. package/skills/json-render-remotion/SKILL.md +0 -111
  219. package/skills/json-render-solid/SKILL.md +0 -204
  220. package/skills/nextjs-shadcn/SKILL.md +0 -367
  221. package/skills/nextjs-shadcn/references/architecture.md +0 -499
  222. package/skills/nextjs-shadcn/references/project-setup.md +0 -162
  223. package/skills/nextjs-shadcn/references/shadcn-platform.md +0 -261
  224. package/skills/nextjs-shadcn/references/sidebar.md +0 -274
  225. package/skills/nextjs-shadcn/references/styling.md +0 -555
  226. package/skills/sf-view-gen/assets/templates/views/category/index.tsx +0 -86
  227. package/skills/sf-view-gen/assets/templates/views/category/registry.tsx +0 -48
  228. package/skills/sf-view-gen/assets/templates/views/checkout/index.tsx +0 -192
  229. package/skills/sf-view-gen/assets/templates/views/checkout/registry.tsx +0 -45
  230. package/skills/sf-view-gen/assets/templates/views/product/index.tsx +0 -122
  231. package/skills/sf-view-gen/assets/templates/views/product/registry.tsx +0 -49
  232. package/skills/sf-view-gen/assets/templates/views/user-panel/index.tsx +0 -168
  233. package/skills/sf-view-gen/assets/templates/views/user-panel/registry.tsx +0 -49
  234. package/skills/shadcn-component-discovery/SKILL.md +0 -273
  235. package/skills/shadcn-component-discovery/references/registries.md +0 -226
  236. package/skills/shadcn-theming/SKILL.md +0 -104
  237. package/skills/storefront-best-practices/SKILL.md +0 -421
  238. package/skills/storefront-best-practices/reference/components/breadcrumbs.md +0 -123
  239. package/skills/storefront-best-practices/reference/components/cart-popup.md +0 -189
  240. package/skills/storefront-best-practices/reference/components/country-selector.md +0 -298
  241. package/skills/storefront-best-practices/reference/components/footer.md +0 -112
  242. package/skills/storefront-best-practices/reference/components/hero.md +0 -241
  243. package/skills/storefront-best-practices/reference/components/megamenu.md +0 -239
  244. package/skills/storefront-best-practices/reference/components/navbar.md +0 -397
  245. package/skills/storefront-best-practices/reference/components/popups.md +0 -221
  246. package/skills/storefront-best-practices/reference/components/product-card.md +0 -125
  247. package/skills/storefront-best-practices/reference/components/product-reviews.md +0 -217
  248. package/skills/storefront-best-practices/reference/components/product-slider.md +0 -174
  249. package/skills/storefront-best-practices/reference/components/search.md +0 -101
  250. package/skills/storefront-best-practices/reference/connecting-to-backend.md +0 -391
  251. package/skills/storefront-best-practices/reference/features/promotions.md +0 -307
  252. package/skills/storefront-best-practices/reference/features/wishlist.md +0 -230
  253. package/skills/storefront-best-practices/reference/layouts/account.md +0 -380
  254. package/skills/storefront-best-practices/reference/layouts/cart.md +0 -316
  255. package/skills/storefront-best-practices/reference/layouts/checkout.md +0 -486
  256. package/skills/storefront-best-practices/reference/layouts/home-page.md +0 -264
  257. package/skills/storefront-best-practices/reference/layouts/order-confirmation.md +0 -231
  258. package/skills/storefront-best-practices/reference/layouts/product-details.md +0 -527
  259. package/skills/storefront-best-practices/reference/layouts/product-listing.md +0 -520
  260. package/skills/storefront-best-practices/reference/layouts/static-pages.md +0 -356
  261. package/skills/storefront-best-practices/reference/medusa.md +0 -307
  262. /package/skills/{storefront-best-practices/reference → storefront-workflow/references}/mobile-responsiveness.md +0 -0
  263. /package/skills/{storefront-best-practices/reference → storefront-workflow/references}/seo.md +0 -0
package/VENDOR.md ADDED
@@ -0,0 +1,69 @@
1
+ # Vendored material and provenance
2
+
3
+ `@thorprovider/storefront` ships exactly five **operative skills** — first-party,
4
+ authored in this package: `storefront-workflow`, `sf-view-gen`, `sf-feature`,
5
+ `sf-setup`, and `sf-theme-gen`. Everything else the suite needs is either retained
6
+ generic knowledge, shipped as a **scoped reference** an operative skill loads by
7
+ relative path, or retired and no longer shipped. This file records the origin and
8
+ the adaptation of that retained material. The generator never reads
9
+ machine-global skills at runtime; the copies below are the authority the suite
10
+ resolves.
11
+
12
+ ## First-party operative skills (not vendored)
13
+
14
+ | Skill | Path | Purpose |
15
+ |---|---|---|
16
+ | storefront-workflow | `skills/storefront-workflow/` | The four-phase model (bootstrap → compose → customize → verify) and the CLI/manifest authority |
17
+ | sf-view-gen | `skills/sf-view-gen/` | Add/modify a view via the CLI; owns the retained json-render references |
18
+ | sf-feature | `skills/sf-feature/` | Add/remove a feature bundle via the CLI |
19
+ | sf-setup | `skills/sf-setup/` | Connect or re-point the Medusa backend via `storefront setup` |
20
+ | sf-theme-gen | `skills/sf-theme-gen/` | Theme tokens, typography, identity; owns the retained theming references |
21
+
22
+ ## Retained references
23
+
24
+ Useful generic knowledge is retained **only** as references inside the operative
25
+ skill that owns the procedure. A reference is not an independently selectable
26
+ skill (it is not a `SKILL.md`).
27
+
28
+ | Retained reference | Owning skill | Upstream source | Refresh date | Adapted |
29
+ |---|---|---|---|---|
30
+ | `references/design-consistency.md` | `skills/storefront-workflow/` | `~/.config/opencode/skills/storefront-best-practices` | 2026-10-14 | Kept as a reference; UX/design-consistency guidance retained, raw Medusa SDK / React Query / direct-`/store` fetching removed |
31
+ | `references/mobile-responsiveness.md` | `skills/storefront-workflow/` | `~/.config/opencode/skills/storefront-best-practices` | 2026-10-14 | Kept as a reference; responsive/mobile guidance retained, raw SDK fetching removed |
32
+ | `references/seo.md` | `skills/storefront-workflow/` | `~/.config/opencode/skills/storefront-best-practices` | 2026-10-14 | Kept as a reference; SEO/accessibility guidance retained, entity-metadata policy preserved |
33
+ | `references/shadcn-theming.md` | `skills/sf-theme-gen/` | `~/.config/opencode/skills/shadcn-theming` | 2026-10-14 | Unavailable tooling (`TeamCreate`, `fuse-ai-pilot`) and raw `shadcn init`/`shadcn add` scaffolding-and-discovery steps removed; OKLCH token/foreground-pair rules and the lightness rule kept |
34
+ | `references/theme-setup.md` | `skills/sf-theme-gen/` | `~/.config/opencode/skills/shadcn-theming/references/templates` | 2026-10-14 | Kept as a reference; adapted to the generated storefront's external-file bounds |
35
+ | `references/theming-guide.md` | `skills/sf-theme-gen/` | `~/.config/opencode/skills/shadcn-theming/references` | 2026-10-14 | Kept as a reference; adapted to the generated storefront's external-file bounds |
36
+ | `references/json-render-core.md` | `skills/sf-view-gen/` | `~/.config/opencode/skills/json-render/core` | 2026-10-14 | Flattened from the standalone `json-render-core` skill to a reference; reachable only by relative path from `sf-view-gen` |
37
+ | `references/json-render-react.md` | `skills/sf-view-gen/` | `~/.config/opencode/skills/json-render/react` | 2026-10-14 | Flattened from the standalone `json-render-react` skill to a reference; reachable only by relative path from `sf-view-gen` |
38
+ | `references/json-render-next.md` | `skills/sf-view-gen/` | `~/.config/opencode/skills/json-render/next` | 2026-10-14 | Flattened from the standalone `json-render-next` skill to a reference; reachable only by relative path from `sf-view-gen` |
39
+ | `references/json-render-shadcn.md` | `skills/sf-view-gen/` | `~/.config/opencode/skills/json-render/shadcn` | 2026-10-14 | Flattened from the standalone `json-render-shadcn` skill to a reference; reachable only by relative path from `sf-view-gen` |
40
+ | `references/views.md` | `skills/sf-view-gen/` | Authored in this package | 2026-10-14 | First-party; documents the curated view set read from `storefront views --json` |
41
+
42
+ ## Retired
43
+
44
+ These were previously bundled flat under `skills/` as standalone installable
45
+ skills. They are no longer shipped as active skills or as retained reference
46
+ material, and `storefront update` retires an installed copy that is verifiably
47
+ unmodified.
48
+
49
+ | Retired item | Upstream source | Last bundled | Why retired |
50
+ |---|---|---|---|
51
+ | `nextjs-shadcn` | `~/.config/opencode/skills/nextjs-shadcn` | 2026-09-28 | Broadly-triggering generic skill; `shadcn init`/`shadcn add` scaffolding contradicts the CLI-only generation rule |
52
+ | `shadcn-component-discovery` | `~/.config/opencode/skills/shadcn-component-discovery` | 2026-09-28 | Broadly-triggering generic skill; UI is limited to `@thorprovider/blocks` |
53
+ | `building-storefronts` | `~/.config/opencode/skills/building-storefronts` | 2026-09-28 | Broadly-triggering generic skill; pushes raw SDK / React Query fetching the storefront cannot use |
54
+ | `json-render-solid` | `~/.config/opencode/skills/json-render/solid` | 2026-09-28 | Irrelevant renderer; the generated storefront renders React/Next only |
55
+ | `json-render-remotion` | `~/.config/opencode/skills/json-render/remotion` | 2026-09-28 | Irrelevant renderer; video timelines are out of scope for a spec-based storefront |
56
+
57
+ ## Excluded
58
+
59
+ Never bundled: the `json-render` `codegen`, `devtools`, `directives`, `image`, and
60
+ `mcp` material. They are irrelevant to a generated storefront and are not shipped
61
+ in any form.
62
+
63
+ ## Maintenance
64
+
65
+ To refresh a retained reference: re-copy the upstream material to a reference
66
+ file under the owning skill's `references/`, update the `Refresh date` above, and
67
+ bump the package version. If a reference is retired, move it to the **Retired**
68
+ table with its reason; `storefront update` retires a verifiably unmodified
69
+ installed copy of it. See the package README maintenance note.
@@ -0,0 +1,38 @@
1
+ # Storefront OpenSpec configuration — seeded by @thorprovider/storefront.
2
+ #
3
+ # This file is storefront-owned: `storefront update` re-applies it after
4
+ # re-running `openspec init`. Put customization in the storefront's own files,
5
+ # not here.
6
+ schema: spec-driven
7
+
8
+ context: |
9
+ This project is a generated Thor Commerce storefront. A storefront is defined by
10
+ its manifest (storefront.config.json) and produced by the `storefront` CLI. The
11
+ CLI is the authority for every structural change — views, features, sections,
12
+ theme, and setup — and it is the only writer of derived files. Manual edits are
13
+ limited to user-owned files (view content/props/data/schema, mappers, icon-map,
14
+ shell) plus the bounded external surface of app/globals.css and app/layout.tsx,
15
+ and must preserve the CLI-managed imports and markers.
16
+ Determinism first: a change the CLI performs deterministically stays with the CLI.
17
+ A deterministic change the CLI records in storefront.config.json is trivial and
18
+ does not require an OpenSpec change; the manifest is its record. A change that
19
+ requires judgment — content authoring, prop/data mapping, composition reshaping,
20
+ or a cross-file redesign whose acceptance is not a CLI assertion — is non-trivial
21
+ and is driven through the spec-driven loop, surfaced to the user as the five
22
+ stages explore → plan → build → verify → inform, orchestrated by the agent
23
+ without asking the user to confirm each artifact. Keep any OpenSpec change
24
+ consistent with the storefront authorities: structural edits still go through
25
+ the CLI.
26
+
27
+ rules:
28
+ proposal:
29
+ - "State the why, the observable storefront change, and the affected view(s) or feature(s); keep deferred scope explicit."
30
+ - "Do not restate this context or these rules in the artifact body."
31
+ specs:
32
+ - "New capabilities start with ## Purpose and ## ADDED Requirements; scenarios use exactly four hashtags (#### Scenario:) and every requirement has at least one."
33
+ - "Describe observable behavior, not implementation details."
34
+ design:
35
+ - "Record each decision with its why and the alternative considered; state how the change respects the CLI-as-authority and the user-owned surface."
36
+ tasks:
37
+ - "Group tasks by dependency; each task is a checkbox and states its own verification."
38
+ - "Never report the change complete until `storefront sync` and `storefront doctor` pass and the change's acceptance is met."
@@ -0,0 +1,76 @@
1
+ # AGENTS.md — __SITE_NAME__ storefront
2
+
3
+ This storefront was generated by `@thorprovider/storefront`. It is governed by a
4
+ manifest (`storefront.config.json` at the project root) and produced by the
5
+ `storefront` CLI. This file is managed: `storefront sync` regenerates it from the
6
+ package template, and `storefront doctor` reports it as drift when edited by
7
+ hand. Read it before changing anything.
8
+
9
+ ## RULE 0 — Non-negotiable
10
+
11
+ 1. **The `storefront` CLI is the authority.** Every structural change — adding or
12
+ removing a view or feature, composing sections, changing the theme mode,
13
+ connecting the backend — goes through `npx @thorprovider/storefront …`. Never
14
+ copy templates or scaffold structure by hand.
15
+ 2. **Derived files are CLI-only; never hand-edit them.** The CLI is the only
16
+ writer of derived files. If a change seems to need a capability the CLI does
17
+ not expose, first check the CLI subcommands and the `plan` → `apply`
18
+ operations envelope; if it is still missing, **STOP and report the gap** —
19
+ do not hand-edit a derived file. A hand edit is silently overwritten by the
20
+ next `sync`.
21
+ 3. **Hand-edit only user-owned files and the bounded external surface.** Manual
22
+ edits are limited to the declared user-owned files:
23
+ `lib/<name>/views/<view>/{schema,content,props,data}.ts`, `lib/<name>/mappers.ts`,
24
+ `lib/<name>/icon-map.ts`, and `lib/<name>/shell/**` — plus the bounded external
25
+ customization surface of `app/globals.css` and `app/layout.tsx`: theme design
26
+ tokens and their foreground pairs, font wiring, and global identity/metadata.
27
+ Prefer the deterministic `storefront theme` controls (colors, radius, fonts,
28
+ presets, imports) over hand edits; the bounded surface remains editable when a
29
+ value has no CLI control.
30
+ Editing the external files must preserve the CLI-managed wiring: the library
31
+ stylesheet import, the provider import and marker, the theme-mode marker, and
32
+ the block token contract. The CLI only appends that wiring idempotently, so a
33
+ restructure that removes it is drift, not a customization. Everything else is
34
+ derived (CLI-only).
35
+ 4. **Respect the architecture invariants.** UI components come only from
36
+ `@thorprovider/blocks`; data comes only from `@thorprovider/adapters` and
37
+ `@thorprovider/runtime/commerce` (never HTTP directly); routing stays the
38
+ catch-all `app/[[...slug]]/page.tsx`; `@thorprovider/medusa-extended` is not
39
+ used.
40
+ 5. **Verify after every change.** Run `npx @thorprovider/storefront sync`, then
41
+ `npx @thorprovider/storefront doctor`. `doctor` must report no drift; a build
42
+ (`yarn build`) is the final acceptance.
43
+ 6. **Drive non-trivial customization through the spec-driven loop.** A change
44
+ that needs judgment — content authoring, prop/data mapping, composition
45
+ reshaping, or a cross-file redesign whose acceptance is not a CLI assertion —
46
+ is **non-trivial**: drive it through the spec-driven loop and surface the five
47
+ stages to the user, **explore → plan → build → verify → inform**. A change the
48
+ CLI performs deterministically (theme mode, `view add|remove`,
49
+ `feature add|remove`, `setup`) is recorded in `storefront.config.json` and does
50
+ **not** require an OpenSpec change — the manifest is its record. Never ask the
51
+ user to run `openspec` or to approve individual artifacts.
52
+
53
+ ## Workflow model
54
+
55
+ **bootstrap → compose → customize → verify.** The manifest
56
+ (`storefront.config.json`) is the structural source of truth; the CLI is the only
57
+ writer of derived files; the developer (or agent) edits only user-owned files and
58
+ the bounded external surface of `app/globals.css` and `app/layout.tsx`.
59
+ Customization that needs judgment runs through the spec-driven loop surfaced as
60
+ explore → plan → build → verify → inform.
61
+ See the `storefront-workflow` skill for the full model and the ownership classes.
62
+
63
+ ## Router — intent → skill → CLI
64
+
65
+ The user states the intent in natural language; load the skill and delegate the
66
+ write to the CLI. Never edit a derived file to achieve the intent.
67
+
68
+ | Intent | Load skill | Delegate to CLI |
69
+ |---|---|---|
70
+ | Add or remove a view; compose a view's sections | `sf-view-gen` | `storefront views --json`, then `storefront view add\|remove …`; sections via `plan` → `apply` |
71
+ | Customize the theme: colors, radius, fonts, presets; identity/SEO | `sf-theme-gen` | `storefront theme` — `--brand orange`, `--primary <color>`, `--accent <color>`, `--radius <length>`, `--font-sans google:Inter`, `--set light.primary=#f97316`, `--preset <ref>`, `--import <src>`, `--export <file>`, `--mode light\|dark\|system`. Visual values live in `app/globals.css`; the mode in `storefront.config.json`. Inspect with `storefront theme --inspect`. The bounded external surface stays editable by hand |
72
+ | Add or remove a feature (e.g. `checkout`) | `sf-feature` | `storefront features --json`, then `storefront feature add\|remove …` |
73
+ | Connect or re-point the Medusa backend; change region, sales channel, or publishable key | `sf-setup` | `storefront setup --backend-url … --publishable-key … --sales-channel-id … --region-id …` |
74
+ | Edit a view's content/props/data; map props or data; reshape composition; any change whose acceptance is not a CLI assertion (non-trivial) | `storefront-workflow` | spec-driven loop surfaced as **explore → plan → build → verify → inform** — the agent drives it and never asks the user to confirm OpenSpec artifacts; structural edits still go through `storefront …`, verified with `storefront sync` then `storefront doctor` |
75
+
76
+ The step-by-step procedures live in the skills, not in this file.
@@ -1,17 +1,69 @@
1
1
  // Generated by Thor Commerce storefront (template: assets/templates/app/app/[[...slug]]/page.tsx)
2
2
 
3
3
  import { notFound } from 'next/navigation'
4
+ import { buildBreadcrumbListJsonLd, serializeJsonLd } from '@thorprovider/runtime/contracts'
4
5
  import { __STOREFRONT_CAMEL__App } from '@/lib/__STOREFRONT__/runtime'
6
+ import { readCartStateForRender } from '@/lib/__STOREFRONT__/cart-state'
5
7
  import { StorefrontRenderer } from './renderer'
6
8
 
7
9
  export const { generateMetadata, generateStaticParams } = __STOREFRONT_CAMEL__App
8
10
 
9
11
  export default async function Page({
10
12
  params,
13
+ searchParams,
11
14
  }: {
12
15
  params: Promise<{ slug?: string[] }>
16
+ searchParams: Promise<Record<string, string | string[] | undefined>>
13
17
  }) {
14
- const data = await __STOREFRONT_CAMEL__App.getPageData({ params })
18
+ // The raw URL search params are forwarded to the loader, which validates them
19
+ // through the canonical boundary before any commerce call (E2 task 5.1).
20
+ const data = await __STOREFRONT_CAMEL__App.getPageData({ params, searchParams })
15
21
  if (!data) return notFound()
16
- return <StorefrontRenderer {...data} />
22
+
23
+ // Read the signed cookie and load the backend cart for the initial render.
24
+ // This never creates a cart; a guest identity is issued by a Server Action.
25
+ const cartState = await readCartStateForRender()
26
+ const initialState = { ...(data.initialState ?? {}), ...cartState }
27
+
28
+ // Entity structured data is server-rendered from the real loaded entity and
29
+ // sanitized so entity text cannot terminate the script element.
30
+ const jsonLd = data.entitySeo?.jsonLd
31
+ // The entity OpenGraph type (`product`/`CollectionPage`) is emitted here, not
32
+ // through Next metadata: Next validates `og:type` against the OpenGraph
33
+ // vocabulary and rejects those entity types, so a raw `property` tag is the
34
+ // only way to carry the entity type into the rendered `<head>`.
35
+ const ogType = data.entitySeo?.openGraph?.type
36
+ // The navigability feature's real trail is server-rendered as a sanitized
37
+ // `BreadcrumbList` alongside the entity structured data. It is built from the
38
+ // loader's own state, so it always matches the rendered breadcrumb.
39
+ const breadcrumbItems = (data.initialState as Record<string, unknown> | undefined)
40
+ ?.breadcrumbItems
41
+ const breadcrumbJsonLd = buildBreadcrumbListJsonLd(
42
+ Array.isArray(breadcrumbItems)
43
+ ? (breadcrumbItems as { label?: string; href?: string }[])
44
+ : undefined,
45
+ )
46
+
47
+ return (
48
+ <>
49
+ {ogType ? <meta property="og:type" content={ogType} /> : null}
50
+ {jsonLd ? (
51
+ <script
52
+ type="application/ld+json"
53
+ dangerouslySetInnerHTML={{ __html: serializeJsonLd(jsonLd) }}
54
+ />
55
+ ) : null}
56
+ {breadcrumbJsonLd ? (
57
+ <script
58
+ type="application/ld+json"
59
+ dangerouslySetInnerHTML={{ __html: serializeJsonLd(breadcrumbJsonLd) }}
60
+ />
61
+ ) : null}
62
+ <StorefrontRenderer
63
+ spec={data.spec}
64
+ layoutSpec={data.layoutSpec}
65
+ initialState={initialState}
66
+ />
67
+ </>
68
+ )
17
69
  }
@@ -2,9 +2,20 @@
2
2
 
3
3
  // Generated by Thor Commerce storefront (template: assets/templates/app/app/[[...slug]]/renderer.tsx)
4
4
 
5
+ import { useRef } from 'react'
5
6
  import { PageRenderer } from '@json-render/next'
6
7
  import type { PageData } from '@json-render/next'
7
8
 
8
- export function StorefrontRenderer(data: PageData) {
9
- return <PageRenderer {...data} />
9
+ export function StorefrontRenderer({ initialState, ...data }: PageData) {
10
+ // The server recomputes `initialState` on every render, and a Server Action
11
+ // triggers an RSC refresh — so the prop is a fresh object each time even when
12
+ // its content is unchanged. `@json-render/react`'s StateProvider resets the
13
+ // client store whenever the `initialState` reference changes, which would wipe
14
+ // client-owned state (for example the account order history) after an action.
15
+ // Keep a STABLE reference while the serialized content is unchanged; a genuine
16
+ // server-side change (for example the cart) still propagates a new value.
17
+ const key = JSON.stringify(initialState ?? {})
18
+ const stable = useRef({ key, value: initialState })
19
+ if (stable.current.key !== key) stable.current = { key, value: initialState }
20
+ return <PageRenderer {...data} initialState={stable.current.value} />
10
21
  }
@@ -28,10 +28,10 @@
28
28
  --color-border: var(--border);
29
29
  --color-input: var(--input);
30
30
  --color-ring: var(--ring);
31
- --radius-sm: var(--radius-sm);
32
- --radius-md: var(--radius-md);
33
- --radius-lg: var(--radius-lg);
34
- --radius-xl: var(--radius-xl);
31
+ --radius-sm: calc(var(--radius) - 4px);
32
+ --radius-md: calc(var(--radius) - 2px);
33
+ --radius-lg: var(--radius);
34
+ --radius-xl: calc(var(--radius) + 4px);
35
35
  --font-sans: var(--font-geist-sans);
36
36
  }
37
37
 
@@ -59,10 +59,7 @@
59
59
  --border: oklch(0.88 0.003 90);
60
60
  --input: oklch(0.92 0.003 90);
61
61
  --ring: oklch(0.15 0 0);
62
- --radius-sm: 0.25rem;
63
- --radius-md: 0.375rem;
64
- --radius-lg: 0.5rem;
65
- --radius-xl: 0.75rem;
62
+ --radius: 0.5rem;
66
63
  }
67
64
 
68
65
  .dark {
@@ -2,10 +2,10 @@
2
2
 
3
3
  import type { Metadata } from 'next'
4
4
  import { Geist } from 'next/font/google'
5
+ import { ThemeProvider } from 'next-themes'
5
6
  import { StorefrontProvider } from '@thorprovider/runtime/host-glue/providers'
6
- import { themeVarsToCss, themeTokensToVars } from '@thorprovider/runtime/render-core/theme'
7
- import { DEFAULT_THEME_TOKENS } from '@thorprovider/runtime/contracts'
8
7
  import { registry } from '@/lib/__STOREFRONT__/registry'
8
+ import { getSiteUrl } from '@/lib/__STOREFRONT__/store-context'
9
9
  import './globals.css'
10
10
 
11
11
  const geist = Geist({
@@ -13,22 +13,32 @@ const geist = Geist({
13
13
  subsets: ['latin'],
14
14
  })
15
15
 
16
- const themeCss = themeVarsToCss(themeTokensToVars(DEFAULT_THEME_TOKENS))
16
+ // The canonical public origin is optional: when THOR_SITE_URL is unset no base
17
+ // URL is invented. `metadataBase` is left undefined in that case.
18
+ const siteUrl = getSiteUrl()
17
19
 
18
20
  export const metadata: Metadata = {
21
+ metadataBase: siteUrl ? new URL(siteUrl) : undefined,
19
22
  title: '__SITE_NAME__',
20
23
  description: 'Tienda online de __SITE_NAME__.',
24
+ openGraph: {
25
+ title: '__SITE_NAME__',
26
+ description: 'Tienda online de __SITE_NAME__.',
27
+ url: siteUrl,
28
+ },
21
29
  }
22
30
 
23
31
  export default function RootLayout({
24
32
  children,
25
33
  }: Readonly<{ children: React.ReactNode }>) {
26
34
  return (
27
- <html lang="es" className={geist.variable}>
35
+ <html lang="es" className={geist.variable} suppressHydrationWarning>
28
36
  <body className="font-sans antialiased">
29
- <StorefrontProvider themeCss={themeCss} registry={registry}>
30
- {children}
31
- </StorefrontProvider>
37
+ <ThemeProvider attribute="class" defaultTheme="__STOREFRONT_MODE__" enableSystem>
38
+ <StorefrontProvider registry={registry}>
39
+ {children}
40
+ </StorefrontProvider>
41
+ </ThemeProvider>
32
42
  </body>
33
43
  </html>
34
44
  )
@@ -0,0 +1,19 @@
1
+ // Generated by Thor Commerce storefront (template: assets/templates/app/app/robots.ts)
2
+ // Always served. Allows public pages, disallows private surfaces, and points at
3
+ // the sitemap only when THOR_SITE_URL is configured.
4
+
5
+ import type { MetadataRoute } from 'next'
6
+ import { __STOREFRONT_CAMEL__Spec } from '@/lib/__STOREFRONT__/spec'
7
+ import { robotsDisallowPaths, robotsSitemapUrl } from '@/lib/__STOREFRONT__/spec/seo'
8
+ import { getSiteUrl } from '@/lib/__STOREFRONT__/store-context'
9
+
10
+ export default function robots(): MetadataRoute.Robots {
11
+ return {
12
+ rules: {
13
+ userAgent: '*',
14
+ allow: '/',
15
+ disallow: robotsDisallowPaths(__STOREFRONT_CAMEL__Spec.routes ?? {}),
16
+ },
17
+ sitemap: robotsSitemapUrl(getSiteUrl()),
18
+ }
19
+ }
@@ -0,0 +1,71 @@
1
+ // Generated by Thor Commerce storefront (template: assets/templates/app/app/sitemap.ts)
2
+ // Lists the fixed public routes plus every public catalog entity, enumerated
3
+ // across adapter pagination with a bound and a cycle guard. Absolute URLs are
4
+ // emitted only when THOR_SITE_URL is configured; otherwise the sitemap is empty
5
+ // (no invented URL). An enumeration failure fails loudly (no partial sitemap).
6
+
7
+ import type { MetadataRoute } from 'next'
8
+ import { getCatalog, getCatalogResults } from '@thorprovider/runtime/commerce'
9
+ import { __STOREFRONT_CAMEL__Spec } from '@/lib/__STOREFRONT__/spec'
10
+ import {
11
+ buildSitemapEntries,
12
+ enumeratePublicEntities,
13
+ SitemapEnumerationError,
14
+ type PublicEntityPage,
15
+ } from '@/lib/__STOREFRONT__/spec/seo'
16
+ import { getSiteUrl } from '@/lib/__STOREFRONT__/store-context'
17
+
18
+ const ENTITY_PAGE_SIZE = 100
19
+ const MAX_PAGES = 100
20
+
21
+ async function productPage(cursor: string | undefined): Promise<PublicEntityPage> {
22
+ const page = cursor ? Number(cursor) : 1
23
+ const outcome = await getCatalogResults({
24
+ page,
25
+ pageSize: ENTITY_PAGE_SIZE,
26
+ sort: 'name',
27
+ })
28
+ if (!outcome.ok) {
29
+ throw new SitemapEnumerationError({
30
+ kind: 'enumeration',
31
+ message: outcome.error.message,
32
+ })
33
+ }
34
+ const items = outcome.results.products.map((product) => ({
35
+ id: product.id,
36
+ path: `/products/${product.handle}`,
37
+ }))
38
+ const total = outcome.results.total
39
+ const hasMore =
40
+ typeof total === 'number' ? page * ENTITY_PAGE_SIZE < total : items.length >= ENTITY_PAGE_SIZE
41
+ return hasMore ? { items, nextCursor: String(page + 1) } : { items }
42
+ }
43
+
44
+ async function categoryPage(): Promise<PublicEntityPage> {
45
+ const catalog = await getCatalog()
46
+ return {
47
+ items: catalog.categoriesRaw.map((category) => ({
48
+ id: category.id,
49
+ path: `/categories/${category.handle}`,
50
+ })),
51
+ }
52
+ }
53
+
54
+ export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
55
+ const siteUrl = getSiteUrl()
56
+ if (!siteUrl) return []
57
+
58
+ const routes = __STOREFRONT_CAMEL__Spec.routes ?? {}
59
+ const [products, categories] = await Promise.all([
60
+ enumeratePublicEntities(productPage, { maxPages: MAX_PAGES }),
61
+ enumeratePublicEntities(categoryPage, { maxPages: MAX_PAGES }),
62
+ ])
63
+ if (!products.ok) throw new SitemapEnumerationError(products.failure)
64
+ if (!categories.ok) throw new SitemapEnumerationError(categories.failure)
65
+
66
+ return buildSitemapEntries({
67
+ routes,
68
+ siteUrl,
69
+ entities: [...products.entities, ...categories.entities],
70
+ })
71
+ }