@vendure-platform/create 0.1.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 (531) hide show
  1. package/README.md +70 -0
  2. package/dist/assets/demo-data/branding/logo.svg +4 -0
  3. package/dist/assets/demo-data/images/absorbent-pad.webp +0 -0
  4. package/dist/assets/demo-data/images/adjustable-wrench.webp +0 -0
  5. package/dist/assets/demo-data/images/anchor-bolt.webp +0 -0
  6. package/dist/assets/demo-data/images/angle-grinder.webp +0 -0
  7. package/dist/assets/demo-data/images/barrier-tape.webp +0 -0
  8. package/dist/assets/demo-data/images/bench-grinder.webp +0 -0
  9. package/dist/assets/demo-data/images/bracket.webp +0 -0
  10. package/dist/assets/demo-data/images/broom.webp +0 -0
  11. package/dist/assets/demo-data/images/bucket.webp +0 -0
  12. package/dist/assets/demo-data/images/cable-gland.webp +0 -0
  13. package/dist/assets/demo-data/images/cable-tie.webp +0 -0
  14. package/dist/assets/demo-data/images/cable-tray.webp +0 -0
  15. package/dist/assets/demo-data/images/cable.webp +0 -0
  16. package/dist/assets/demo-data/images/chimney-base-kit.webp +0 -0
  17. package/dist/assets/demo-data/images/chimney-cowl-bird-guard.webp +0 -0
  18. package/dist/assets/demo-data/images/chimney-cowl-open.webp +0 -0
  19. package/dist/assets/demo-data/images/chimney-storm-collar.webp +0 -0
  20. package/dist/assets/demo-data/images/chimney-wall-bracket.webp +0 -0
  21. package/dist/assets/demo-data/images/circular-saw.webp +0 -0
  22. package/dist/assets/demo-data/images/cleaning-spray.webp +0 -0
  23. package/dist/assets/demo-data/images/conduit.webp +0 -0
  24. package/dist/assets/demo-data/images/cordless-drill.webp +0 -0
  25. package/dist/assets/demo-data/images/drill-bits.webp +0 -0
  26. package/dist/assets/demo-data/images/dust-mask.webp +0 -0
  27. package/dist/assets/demo-data/images/ear-defenders.webp +0 -0
  28. package/dist/assets/demo-data/images/ear-plugs.webp +0 -0
  29. package/dist/assets/demo-data/images/extension-lead.webp +0 -0
  30. package/dist/assets/demo-data/images/eye-wash-station.webp +0 -0
  31. package/dist/assets/demo-data/images/face-shield.webp +0 -0
  32. package/dist/assets/demo-data/images/file-set.webp +0 -0
  33. package/dist/assets/demo-data/images/first-aid-kit.webp +0 -0
  34. package/dist/assets/demo-data/images/floor-sign.webp +0 -0
  35. package/dist/assets/demo-data/images/flue-bend-45.webp +0 -0
  36. package/dist/assets/demo-data/images/flue-bend-90.webp +0 -0
  37. package/dist/assets/demo-data/images/flue-section-1000mm.webp +0 -0
  38. package/dist/assets/demo-data/images/flue-section-250mm.webp +0 -0
  39. package/dist/assets/demo-data/images/flue-section-500mm.webp +0 -0
  40. package/dist/assets/demo-data/images/fuse.webp +0 -0
  41. package/dist/assets/demo-data/images/glove-dispenser.webp +0 -0
  42. package/dist/assets/demo-data/images/grinding-disc.webp +0 -0
  43. package/dist/assets/demo-data/images/hacksaw.webp +0 -0
  44. package/dist/assets/demo-data/images/hammer.webp +0 -0
  45. package/dist/assets/demo-data/images/hand-sanitiser.webp +0 -0
  46. package/dist/assets/demo-data/images/head-torch.webp +0 -0
  47. package/dist/assets/demo-data/images/heat-gun.webp +0 -0
  48. package/dist/assets/demo-data/images/hex-bolt.webp +0 -0
  49. package/dist/assets/demo-data/images/hex-key-set.webp +0 -0
  50. package/dist/assets/demo-data/images/hex-nut.webp +0 -0
  51. package/dist/assets/demo-data/images/hi-vis-jacket.webp +0 -0
  52. package/dist/assets/demo-data/images/hi-vis-vest.webp +0 -0
  53. package/dist/assets/demo-data/images/hose-clamp.webp +0 -0
  54. package/dist/assets/demo-data/images/impact-driver.webp +0 -0
  55. package/dist/assets/demo-data/images/jigsaw.webp +0 -0
  56. package/dist/assets/demo-data/images/junction-box.webp +0 -0
  57. package/dist/assets/demo-data/images/knee-pads.webp +0 -0
  58. package/dist/assets/demo-data/images/machine-screw.webp +0 -0
  59. package/dist/assets/demo-data/images/made-to-order-configurable-chimney.webp +0 -0
  60. package/dist/assets/demo-data/images/mallet.webp +0 -0
  61. package/dist/assets/demo-data/images/mcb.webp +0 -0
  62. package/dist/assets/demo-data/images/mop.webp +0 -0
  63. package/dist/assets/demo-data/images/paper-towels.webp +0 -0
  64. package/dist/assets/demo-data/images/pipe-wrench.webp +0 -0
  65. package/dist/assets/demo-data/images/pliers-set.webp +0 -0
  66. package/dist/assets/demo-data/images/pry-bar.webp +0 -0
  67. package/dist/assets/demo-data/images/rcd.webp +0 -0
  68. package/dist/assets/demo-data/images/reciprocating-saw.webp +0 -0
  69. package/dist/assets/demo-data/images/rivet.webp +0 -0
  70. package/dist/assets/demo-data/images/roof-flashing-high-pitch.webp +0 -0
  71. package/dist/assets/demo-data/images/roof-flashing-low-pitch.webp +0 -0
  72. package/dist/assets/demo-data/images/safety-boots.webp +0 -0
  73. package/dist/assets/demo-data/images/safety-glasses.webp +0 -0
  74. package/dist/assets/demo-data/images/safety-harness.webp +0 -0
  75. package/dist/assets/demo-data/images/safety-helmet.webp +0 -0
  76. package/dist/assets/demo-data/images/safety-sign.webp +0 -0
  77. package/dist/assets/demo-data/images/sanding-disc.webp +0 -0
  78. package/dist/assets/demo-data/images/saw-blade.webp +0 -0
  79. package/dist/assets/demo-data/images/screwdriver-set.webp +0 -0
  80. package/dist/assets/demo-data/images/screwdriver.webp +0 -0
  81. package/dist/assets/demo-data/images/self-tapping-screw.webp +0 -0
  82. package/dist/assets/demo-data/images/socket-set.webp +0 -0
  83. package/dist/assets/demo-data/images/socket.webp +0 -0
  84. package/dist/assets/demo-data/images/spanner-set.webp +0 -0
  85. package/dist/assets/demo-data/images/spanner.webp +0 -0
  86. package/dist/assets/demo-data/images/spill-kit.webp +0 -0
  87. package/dist/assets/demo-data/images/spirit-level.webp +0 -0
  88. package/dist/assets/demo-data/images/switch.webp +0 -0
  89. package/dist/assets/demo-data/images/tape-measure.webp +0 -0
  90. package/dist/assets/demo-data/images/terminal-block.webp +0 -0
  91. package/dist/assets/demo-data/images/threaded-rod.webp +0 -0
  92. package/dist/assets/demo-data/images/torque-wrench.webp +0 -0
  93. package/dist/assets/demo-data/images/utility-knife.webp +0 -0
  94. package/dist/assets/demo-data/images/wall-pass-sleeve.webp +0 -0
  95. package/dist/assets/demo-data/images/wall-plug.webp +0 -0
  96. package/dist/assets/demo-data/images/washer.webp +0 -0
  97. package/dist/assets/demo-data/images/waste-bin.webp +0 -0
  98. package/dist/assets/demo-data/images/wire-connector.webp +0 -0
  99. package/dist/assets/demo-data/images/wire-cutters.webp +0 -0
  100. package/dist/assets/demo-data/images/wood-screw.webp +0 -0
  101. package/dist/assets/demo-data/images/work-gloves.webp +0 -0
  102. package/dist/assets/demo-data/images/work-light.webp +0 -0
  103. package/dist/assets/demo-data/initial-data.json +667 -0
  104. package/dist/assets/demo-data/products.csv +779 -0
  105. package/dist/assets/storefront/.env.example +14 -0
  106. package/dist/assets/storefront/.env.local +1 -0
  107. package/dist/assets/storefront/components.json +22 -0
  108. package/dist/assets/storefront/eslint.config.mjs +23 -0
  109. package/dist/assets/storefront/graphql.config.yml +2 -0
  110. package/dist/assets/storefront/messages/de.json +1196 -0
  111. package/dist/assets/storefront/messages/en.json +1196 -0
  112. package/dist/assets/storefront/next-env.d.ts +6 -0
  113. package/dist/assets/storefront/next.config.ts +73 -0
  114. package/dist/assets/storefront/package.json +77 -0
  115. package/dist/assets/storefront/postcss.config.mjs +5 -0
  116. package/dist/assets/storefront/public/next.svg +22 -0
  117. package/dist/assets/storefront/public/scenarios/b2b-wholesale/hero/hero-bg.webp +0 -0
  118. package/dist/assets/storefront/public/scenarios/b2b-wholesale/logo.svg +4 -0
  119. package/dist/assets/storefront/public/scenarios/default/logo.svg +4 -0
  120. package/dist/assets/storefront/public/scenarios/kaminpro/hero/hero-bg.webp +0 -0
  121. package/dist/assets/storefront/public/scenarios/kaminpro/logo.svg +7 -0
  122. package/dist/assets/storefront/public/vendure.svg +4 -0
  123. package/dist/assets/storefront/src/app/[locale]/(catalog)/catalog/page.tsx +65 -0
  124. package/dist/assets/storefront/src/app/[locale]/(catalog)/collection/[slug]/loading.tsx +24 -0
  125. package/dist/assets/storefront/src/app/[locale]/(catalog)/collection/[slug]/page.tsx +194 -0
  126. package/dist/assets/storefront/src/app/[locale]/(catalog)/layout.tsx +9 -0
  127. package/dist/assets/storefront/src/app/[locale]/(catalog)/product/[slug]/actions.ts +139 -0
  128. package/dist/assets/storefront/src/app/[locale]/(catalog)/product/[slug]/loading.tsx +46 -0
  129. package/dist/assets/storefront/src/app/[locale]/(catalog)/product/[slug]/page.tsx +330 -0
  130. package/dist/assets/storefront/src/app/[locale]/(catalog)/search/actions.ts +11 -0
  131. package/dist/assets/storefront/src/app/[locale]/(catalog)/search/loading.tsx +20 -0
  132. package/dist/assets/storefront/src/app/[locale]/(catalog)/search/page.tsx +97 -0
  133. package/dist/assets/storefront/src/app/[locale]/(catalog)/search/search-analytics-tracker.tsx +46 -0
  134. package/dist/assets/storefront/src/app/[locale]/(catalog)/search/search-results.tsx +53 -0
  135. package/dist/assets/storefront/src/app/[locale]/(catalog)/search/search-term.tsx +26 -0
  136. package/dist/assets/storefront/src/app/[locale]/(scenario)/[...path]/page.tsx +31 -0
  137. package/dist/assets/storefront/src/app/[locale]/accept-invitation/[token]/accept-invitation-client.tsx +56 -0
  138. package/dist/assets/storefront/src/app/[locale]/accept-invitation/[token]/actions.ts +32 -0
  139. package/dist/assets/storefront/src/app/[locale]/accept-invitation/[token]/page.tsx +85 -0
  140. package/dist/assets/storefront/src/app/[locale]/accept-invitation/[token]/sign-out-and-retry.tsx +26 -0
  141. package/dist/assets/storefront/src/app/[locale]/account/addresses/actions.ts +125 -0
  142. package/dist/assets/storefront/src/app/[locale]/account/addresses/address-form.tsx +180 -0
  143. package/dist/assets/storefront/src/app/[locale]/account/addresses/addresses-client.tsx +292 -0
  144. package/dist/assets/storefront/src/app/[locale]/account/addresses/loading.tsx +48 -0
  145. package/dist/assets/storefront/src/app/[locale]/account/addresses/page.tsx +54 -0
  146. package/dist/assets/storefront/src/app/[locale]/account/approvals/actions.ts +28 -0
  147. package/dist/assets/storefront/src/app/[locale]/account/approvals/page.tsx +340 -0
  148. package/dist/assets/storefront/src/app/[locale]/account/company/actions.ts +33 -0
  149. package/dist/assets/storefront/src/app/[locale]/account/company/addresses/actions.ts +83 -0
  150. package/dist/assets/storefront/src/app/[locale]/account/company/addresses/address-form.tsx +267 -0
  151. package/dist/assets/storefront/src/app/[locale]/account/company/addresses/addresses-client.tsx +253 -0
  152. package/dist/assets/storefront/src/app/[locale]/account/company/addresses/page.tsx +75 -0
  153. package/dist/assets/storefront/src/app/[locale]/account/company/business-units/actions.ts +70 -0
  154. package/dist/assets/storefront/src/app/[locale]/account/company/business-units/business-unit-form.tsx +153 -0
  155. package/dist/assets/storefront/src/app/[locale]/account/company/business-units/business-units-client.tsx +210 -0
  156. package/dist/assets/storefront/src/app/[locale]/account/company/business-units/page.tsx +66 -0
  157. package/dist/assets/storefront/src/app/[locale]/account/company/business-units/types.ts +8 -0
  158. package/dist/assets/storefront/src/app/[locale]/account/company/edit-company-form.tsx +57 -0
  159. package/dist/assets/storefront/src/app/[locale]/account/company/page.tsx +89 -0
  160. package/dist/assets/storefront/src/app/[locale]/account/company/payment-methods/page.tsx +65 -0
  161. package/dist/assets/storefront/src/app/[locale]/account/company/payment-methods/payment-methods-client.tsx +55 -0
  162. package/dist/assets/storefront/src/app/[locale]/account/company/roles/page.tsx +66 -0
  163. package/dist/assets/storefront/src/app/[locale]/account/company/roles/roles-client.tsx +93 -0
  164. package/dist/assets/storefront/src/app/[locale]/account/company/tax-ids/actions.ts +51 -0
  165. package/dist/assets/storefront/src/app/[locale]/account/company/tax-ids/page.tsx +57 -0
  166. package/dist/assets/storefront/src/app/[locale]/account/company/tax-ids/tax-ids-client.tsx +326 -0
  167. package/dist/assets/storefront/src/app/[locale]/account/company/users/actions.ts +74 -0
  168. package/dist/assets/storefront/src/app/[locale]/account/company/users/edit-user-form.tsx +157 -0
  169. package/dist/assets/storefront/src/app/[locale]/account/company/users/invite-user-form.tsx +133 -0
  170. package/dist/assets/storefront/src/app/[locale]/account/company/users/page.tsx +104 -0
  171. package/dist/assets/storefront/src/app/[locale]/account/company/users/users-client.tsx +266 -0
  172. package/dist/assets/storefront/src/app/[locale]/account/error.tsx +24 -0
  173. package/dist/assets/storefront/src/app/[locale]/account/layout.tsx +50 -0
  174. package/dist/assets/storefront/src/app/[locale]/account/orders/[code]/page.tsx +463 -0
  175. package/dist/assets/storefront/src/app/[locale]/account/orders/[code]/reorder-actions.ts +160 -0
  176. package/dist/assets/storefront/src/app/[locale]/account/orders/[code]/reorder-dialog.tsx +386 -0
  177. package/dist/assets/storefront/src/app/[locale]/account/orders/loading.tsx +45 -0
  178. package/dist/assets/storefront/src/app/[locale]/account/orders/page.tsx +309 -0
  179. package/dist/assets/storefront/src/app/[locale]/account/profile/actions.ts +106 -0
  180. package/dist/assets/storefront/src/app/[locale]/account/profile/change-password-form.tsx +82 -0
  181. package/dist/assets/storefront/src/app/[locale]/account/profile/edit-email-form.tsx +88 -0
  182. package/dist/assets/storefront/src/app/[locale]/account/profile/edit-profile-form.tsx +80 -0
  183. package/dist/assets/storefront/src/app/[locale]/account/profile/loading.tsx +54 -0
  184. package/dist/assets/storefront/src/app/[locale]/account/profile/page.tsx +44 -0
  185. package/dist/assets/storefront/src/app/[locale]/account/quick-order/actions.ts +103 -0
  186. package/dist/assets/storefront/src/app/[locale]/account/quick-order/file-upload-tab.tsx +148 -0
  187. package/dist/assets/storefront/src/app/[locale]/account/quick-order/manual-entry-tab.tsx +112 -0
  188. package/dist/assets/storefront/src/app/[locale]/account/quick-order/page.tsx +26 -0
  189. package/dist/assets/storefront/src/app/[locale]/account/quick-order/preview-table.tsx +170 -0
  190. package/dist/assets/storefront/src/app/[locale]/account/quick-order/quick-order-form.tsx +243 -0
  191. package/dist/assets/storefront/src/app/[locale]/account/quick-order/save-to-list-dialog.tsx +153 -0
  192. package/dist/assets/storefront/src/app/[locale]/account/quick-order/sku-autocomplete.tsx +118 -0
  193. package/dist/assets/storefront/src/app/[locale]/account/quick-order/text-input-tab.tsx +40 -0
  194. package/dist/assets/storefront/src/app/[locale]/account/quotes/[id]/page.tsx +260 -0
  195. package/dist/assets/storefront/src/app/[locale]/account/quotes/actions.ts +253 -0
  196. package/dist/assets/storefront/src/app/[locale]/account/quotes/new/new-quote-form.tsx +28 -0
  197. package/dist/assets/storefront/src/app/[locale]/account/quotes/new/page.tsx +51 -0
  198. package/dist/assets/storefront/src/app/[locale]/account/quotes/page.tsx +248 -0
  199. package/dist/assets/storefront/src/app/[locale]/account/shopping-lists/[id]/loading.tsx +44 -0
  200. package/dist/assets/storefront/src/app/[locale]/account/shopping-lists/[id]/page.tsx +51 -0
  201. package/dist/assets/storefront/src/app/[locale]/account/shopping-lists/[id]/shopping-list-detail-client.tsx +562 -0
  202. package/dist/assets/storefront/src/app/[locale]/account/shopping-lists/actions.ts +235 -0
  203. package/dist/assets/storefront/src/app/[locale]/account/shopping-lists/create-shopping-list-form.tsx +86 -0
  204. package/dist/assets/storefront/src/app/[locale]/account/shopping-lists/loading.tsx +48 -0
  205. package/dist/assets/storefront/src/app/[locale]/account/shopping-lists/page.tsx +176 -0
  206. package/dist/assets/storefront/src/app/[locale]/account/store-credits/actions.ts +31 -0
  207. package/dist/assets/storefront/src/app/[locale]/account/store-credits/claim-form.tsx +41 -0
  208. package/dist/assets/storefront/src/app/[locale]/account/store-credits/page.tsx +190 -0
  209. package/dist/assets/storefront/src/app/[locale]/account/store-credits/reveal-code.tsx +38 -0
  210. package/dist/assets/storefront/src/app/[locale]/account/verify-email/page.tsx +117 -0
  211. package/dist/assets/storefront/src/app/[locale]/cart/actions.ts +128 -0
  212. package/dist/assets/storefront/src/app/[locale]/cart/cart-items.tsx +228 -0
  213. package/dist/assets/storefront/src/app/[locale]/cart/cart-line-actions.tsx +55 -0
  214. package/dist/assets/storefront/src/app/[locale]/cart/cart-quantity-control.tsx +158 -0
  215. package/dist/assets/storefront/src/app/[locale]/cart/cart-remove-button.tsx +36 -0
  216. package/dist/assets/storefront/src/app/[locale]/cart/cart.tsx +151 -0
  217. package/dist/assets/storefront/src/app/[locale]/cart/code-input.tsx +49 -0
  218. package/dist/assets/storefront/src/app/[locale]/cart/loading.tsx +10 -0
  219. package/dist/assets/storefront/src/app/[locale]/cart/order-summary.tsx +178 -0
  220. package/dist/assets/storefront/src/app/[locale]/cart/page.tsx +33 -0
  221. package/dist/assets/storefront/src/app/[locale]/cart/promotion-code.tsx +142 -0
  222. package/dist/assets/storefront/src/app/[locale]/cart/reapproval-confirm.tsx +76 -0
  223. package/dist/assets/storefront/src/app/[locale]/cart/request-quote-button.tsx +80 -0
  224. package/dist/assets/storefront/src/app/[locale]/checkout/actions.ts +192 -0
  225. package/dist/assets/storefront/src/app/[locale]/checkout/cancel-quote-checkout-button.tsx +30 -0
  226. package/dist/assets/storefront/src/app/[locale]/checkout/checkout-flow.tsx +214 -0
  227. package/dist/assets/storefront/src/app/[locale]/checkout/checkout-provider.tsx +181 -0
  228. package/dist/assets/storefront/src/app/[locale]/checkout/loading.tsx +90 -0
  229. package/dist/assets/storefront/src/app/[locale]/checkout/order-summary.tsx +160 -0
  230. package/dist/assets/storefront/src/app/[locale]/checkout/page.tsx +154 -0
  231. package/dist/assets/storefront/src/app/[locale]/checkout/steps/delivery-step.tsx +107 -0
  232. package/dist/assets/storefront/src/app/[locale]/checkout/steps/payment-step.tsx +110 -0
  233. package/dist/assets/storefront/src/app/[locale]/checkout/steps/review-step.tsx +180 -0
  234. package/dist/assets/storefront/src/app/[locale]/checkout/steps/shipping-address-step.tsx +518 -0
  235. package/dist/assets/storefront/src/app/[locale]/checkout/types.ts +7 -0
  236. package/dist/assets/storefront/src/app/[locale]/error.tsx +28 -0
  237. package/dist/assets/storefront/src/app/[locale]/forgot-password/actions.ts +28 -0
  238. package/dist/assets/storefront/src/app/[locale]/forgot-password/forgot-password-form.tsx +128 -0
  239. package/dist/assets/storefront/src/app/[locale]/forgot-password/page.tsx +24 -0
  240. package/dist/assets/storefront/src/app/[locale]/globals.css +72 -0
  241. package/dist/assets/storefront/src/app/[locale]/layout.tsx +202 -0
  242. package/dist/assets/storefront/src/app/[locale]/not-found.tsx +26 -0
  243. package/dist/assets/storefront/src/app/[locale]/order-confirmation/[code]/order-confirmation.tsx +296 -0
  244. package/dist/assets/storefront/src/app/[locale]/order-confirmation/[code]/page.tsx +18 -0
  245. package/dist/assets/storefront/src/app/[locale]/page.tsx +125 -0
  246. package/dist/assets/storefront/src/app/[locale]/register/actions.ts +50 -0
  247. package/dist/assets/storefront/src/app/[locale]/register/page.tsx +82 -0
  248. package/dist/assets/storefront/src/app/[locale]/register/registration-form.tsx +237 -0
  249. package/dist/assets/storefront/src/app/[locale]/register-company/actions.ts +40 -0
  250. package/dist/assets/storefront/src/app/[locale]/register-company/page.tsx +43 -0
  251. package/dist/assets/storefront/src/app/[locale]/register-company/registration-form.tsx +48 -0
  252. package/dist/assets/storefront/src/app/[locale]/reset-password/actions.ts +40 -0
  253. package/dist/assets/storefront/src/app/[locale]/reset-password/page.tsx +32 -0
  254. package/dist/assets/storefront/src/app/[locale]/reset-password/reset-password-form.tsx +96 -0
  255. package/dist/assets/storefront/src/app/[locale]/shopping-list/[code]/add-to-cart-button.tsx +31 -0
  256. package/dist/assets/storefront/src/app/[locale]/shopping-list/[code]/loading.tsx +29 -0
  257. package/dist/assets/storefront/src/app/[locale]/shopping-list/[code]/page.tsx +157 -0
  258. package/dist/assets/storefront/src/app/[locale]/sign-in/actions.ts +76 -0
  259. package/dist/assets/storefront/src/app/[locale]/sign-in/login-form.tsx +177 -0
  260. package/dist/assets/storefront/src/app/[locale]/sign-in/page.tsx +81 -0
  261. package/dist/assets/storefront/src/app/[locale]/verify/actions.ts +41 -0
  262. package/dist/assets/storefront/src/app/[locale]/verify/page.tsx +40 -0
  263. package/dist/assets/storefront/src/app/[locale]/verify/verify-content.tsx +127 -0
  264. package/dist/assets/storefront/src/app/[locale]/verify-pending/page.tsx +67 -0
  265. package/dist/assets/storefront/src/app/api/clear-company-context/route.ts +26 -0
  266. package/dist/assets/storefront/src/app/api/draft/disable/route.ts +12 -0
  267. package/dist/assets/storefront/src/app/api/draft/route.ts +17 -0
  268. package/dist/assets/storefront/src/app/api/revalidate/route.ts +110 -0
  269. package/dist/assets/storefront/src/app/api/search-analytics/route.ts +16 -0
  270. package/dist/assets/storefront/src/app/favicon.ico +0 -0
  271. package/dist/assets/storefront/src/components/commerce/account-nav-items.ts +56 -0
  272. package/dist/assets/storefront/src/components/commerce/account-sidebar.tsx +112 -0
  273. package/dist/assets/storefront/src/components/commerce/active-filters.tsx +107 -0
  274. package/dist/assets/storefront/src/components/commerce/approval-decision-form.tsx +70 -0
  275. package/dist/assets/storefront/src/components/commerce/approval-status-badge.tsx +37 -0
  276. package/dist/assets/storefront/src/components/commerce/business-unit-switcher.tsx +56 -0
  277. package/dist/assets/storefront/src/components/commerce/catalog-search-bar.tsx +83 -0
  278. package/dist/assets/storefront/src/components/commerce/category-product-section.tsx +69 -0
  279. package/dist/assets/storefront/src/components/commerce/category-sidebar.tsx +133 -0
  280. package/dist/assets/storefront/src/components/commerce/collection-hero-banner.tsx +36 -0
  281. package/dist/assets/storefront/src/components/commerce/company-state-badge.tsx +32 -0
  282. package/dist/assets/storefront/src/components/commerce/company-switcher.tsx +58 -0
  283. package/dist/assets/storefront/src/components/commerce/configurator-form.tsx +606 -0
  284. package/dist/assets/storefront/src/components/commerce/facet-filters.tsx +286 -0
  285. package/dist/assets/storefront/src/components/commerce/gift-card-pdp.tsx +43 -0
  286. package/dist/assets/storefront/src/components/commerce/gift-card-product-info.tsx +137 -0
  287. package/dist/assets/storefront/src/components/commerce/highlighted-text.tsx +30 -0
  288. package/dist/assets/storefront/src/components/commerce/instant-search-dropdown.tsx +377 -0
  289. package/dist/assets/storefront/src/components/commerce/order-status-badge.tsx +41 -0
  290. package/dist/assets/storefront/src/components/commerce/packaging-unit-selector.tsx +146 -0
  291. package/dist/assets/storefront/src/components/commerce/permission-gate.tsx +20 -0
  292. package/dist/assets/storefront/src/components/commerce/price-range-filter.tsx +111 -0
  293. package/dist/assets/storefront/src/components/commerce/price-tiers.tsx +98 -0
  294. package/dist/assets/storefront/src/components/commerce/price.tsx +29 -0
  295. package/dist/assets/storefront/src/components/commerce/product-card-list.tsx +121 -0
  296. package/dist/assets/storefront/src/components/commerce/product-card.tsx +89 -0
  297. package/dist/assets/storefront/src/components/commerce/product-carousel.tsx +42 -0
  298. package/dist/assets/storefront/src/components/commerce/product-grid.tsx +54 -0
  299. package/dist/assets/storefront/src/components/commerce/product-image-carousel.tsx +127 -0
  300. package/dist/assets/storefront/src/components/commerce/product-info.tsx +525 -0
  301. package/dist/assets/storefront/src/components/commerce/product-list-expansion.tsx +393 -0
  302. package/dist/assets/storefront/src/components/commerce/product-list-view.tsx +34 -0
  303. package/dist/assets/storefront/src/components/commerce/product-sidebar.tsx +175 -0
  304. package/dist/assets/storefront/src/components/commerce/product-view-switcher.tsx +107 -0
  305. package/dist/assets/storefront/src/components/commerce/quote-action-buttons.tsx +235 -0
  306. package/dist/assets/storefront/src/components/commerce/quote-activity-timeline.tsx +320 -0
  307. package/dist/assets/storefront/src/components/commerce/quote-comment-form.tsx +52 -0
  308. package/dist/assets/storefront/src/components/commerce/quote-csv-export-button.tsx +97 -0
  309. package/dist/assets/storefront/src/components/commerce/quote-product-search.tsx +139 -0
  310. package/dist/assets/storefront/src/components/commerce/quote-request-form.tsx +252 -0
  311. package/dist/assets/storefront/src/components/commerce/quote-status-badge.tsx +41 -0
  312. package/dist/assets/storefront/src/components/commerce/quote-validity-indicator.tsx +33 -0
  313. package/dist/assets/storefront/src/components/commerce/quote-version-comparison.tsx +88 -0
  314. package/dist/assets/storefront/src/components/commerce/related-products.tsx +56 -0
  315. package/dist/assets/storefront/src/components/commerce/shop-by-category.tsx +59 -0
  316. package/dist/assets/storefront/src/components/commerce/shopping-list-toggle.tsx +158 -0
  317. package/dist/assets/storefront/src/components/commerce/sort-dropdown.tsx +51 -0
  318. package/dist/assets/storefront/src/components/commerce/store-credit-summary.tsx +45 -0
  319. package/dist/assets/storefront/src/components/commerce/subcollection-tiles.tsx +56 -0
  320. package/dist/assets/storefront/src/components/layout/auth-page-shell.tsx +15 -0
  321. package/dist/assets/storefront/src/components/layout/draft-mode-action.ts +8 -0
  322. package/dist/assets/storefront/src/components/layout/draft-mode-indicator.tsx +54 -0
  323. package/dist/assets/storefront/src/components/layout/draft-mode-link.tsx +29 -0
  324. package/dist/assets/storefront/src/components/layout/footer.tsx +168 -0
  325. package/dist/assets/storefront/src/components/layout/navbar/actions.ts +33 -0
  326. package/dist/assets/storefront/src/components/layout/navbar/cart-icon.tsx +50 -0
  327. package/dist/assets/storefront/src/components/layout/navbar/channel-picker-wrapper.tsx +19 -0
  328. package/dist/assets/storefront/src/components/layout/navbar/channel-picker.tsx +53 -0
  329. package/dist/assets/storefront/src/components/layout/navbar/currency-picker-wrapper.tsx +21 -0
  330. package/dist/assets/storefront/src/components/layout/navbar/currency-picker.tsx +52 -0
  331. package/dist/assets/storefront/src/components/layout/navbar/language-picker.tsx +51 -0
  332. package/dist/assets/storefront/src/components/layout/navbar/login-button.tsx +34 -0
  333. package/dist/assets/storefront/src/components/layout/navbar/mobile-nav.tsx +74 -0
  334. package/dist/assets/storefront/src/components/layout/navbar/nav-menu-items.tsx +51 -0
  335. package/dist/assets/storefront/src/components/layout/navbar/navbar-cart.tsx +5 -0
  336. package/dist/assets/storefront/src/components/layout/navbar/navbar-collections.tsx +291 -0
  337. package/dist/assets/storefront/src/components/layout/navbar/navbar-link.tsx +28 -0
  338. package/dist/assets/storefront/src/components/layout/navbar/navbar-user.tsx +147 -0
  339. package/dist/assets/storefront/src/components/layout/navbar/theme-switcher.tsx +39 -0
  340. package/dist/assets/storefront/src/components/layout/navbar.tsx +117 -0
  341. package/dist/assets/storefront/src/components/layout/search-input.tsx +71 -0
  342. package/dist/assets/storefront/src/components/providers/awaiting-approval-banner.tsx +58 -0
  343. package/dist/assets/storefront/src/components/providers/cart-count-server.tsx +31 -0
  344. package/dist/assets/storefront/src/components/providers/company-context-guard.tsx +47 -0
  345. package/dist/assets/storefront/src/components/providers/company-permissions-server.tsx +14 -0
  346. package/dist/assets/storefront/src/components/providers/theme-provider.tsx +16 -0
  347. package/dist/assets/storefront/src/components/shared/breadcrumbs.tsx +39 -0
  348. package/dist/assets/storefront/src/components/shared/catalog-sidebar-skeleton.tsx +21 -0
  349. package/dist/assets/storefront/src/components/shared/country-select.tsx +83 -0
  350. package/dist/assets/storefront/src/components/shared/error-state.tsx +16 -0
  351. package/dist/assets/storefront/src/components/shared/pagination.tsx +119 -0
  352. package/dist/assets/storefront/src/components/shared/prefetch-link.tsx +36 -0
  353. package/dist/assets/storefront/src/components/shared/product-grid-skeleton.tsx +26 -0
  354. package/dist/assets/storefront/src/components/shared/scenario-paused.tsx +80 -0
  355. package/dist/assets/storefront/src/components/shared/skeletons/cart-skeleton.tsx +48 -0
  356. package/dist/assets/storefront/src/components/shared/skeletons/navbar-user-skeleton.tsx +9 -0
  357. package/dist/assets/storefront/src/components/shared/skeletons/search-input-skeleton.tsx +7 -0
  358. package/dist/assets/storefront/src/components/shared/skeletons/search-results-skeleton.tsx +17 -0
  359. package/dist/assets/storefront/src/components/ui/accordion.tsx +66 -0
  360. package/dist/assets/storefront/src/components/ui/alert-dialog.tsx +157 -0
  361. package/dist/assets/storefront/src/components/ui/alert.tsx +66 -0
  362. package/dist/assets/storefront/src/components/ui/aspect-ratio.tsx +11 -0
  363. package/dist/assets/storefront/src/components/ui/avatar.tsx +53 -0
  364. package/dist/assets/storefront/src/components/ui/badge.tsx +46 -0
  365. package/dist/assets/storefront/src/components/ui/breadcrumb.tsx +109 -0
  366. package/dist/assets/storefront/src/components/ui/button.tsx +58 -0
  367. package/dist/assets/storefront/src/components/ui/calendar.tsx +213 -0
  368. package/dist/assets/storefront/src/components/ui/card.tsx +92 -0
  369. package/dist/assets/storefront/src/components/ui/carousel.tsx +241 -0
  370. package/dist/assets/storefront/src/components/ui/chart.tsx +357 -0
  371. package/dist/assets/storefront/src/components/ui/checkbox.tsx +32 -0
  372. package/dist/assets/storefront/src/components/ui/collapsible.tsx +33 -0
  373. package/dist/assets/storefront/src/components/ui/command.tsx +184 -0
  374. package/dist/assets/storefront/src/components/ui/context-menu.tsx +252 -0
  375. package/dist/assets/storefront/src/components/ui/dialog.tsx +143 -0
  376. package/dist/assets/storefront/src/components/ui/drawer.tsx +135 -0
  377. package/dist/assets/storefront/src/components/ui/dropdown-menu.tsx +257 -0
  378. package/dist/assets/storefront/src/components/ui/empty-state.tsx +37 -0
  379. package/dist/assets/storefront/src/components/ui/field.tsx +244 -0
  380. package/dist/assets/storefront/src/components/ui/form.tsx +167 -0
  381. package/dist/assets/storefront/src/components/ui/hover-card.tsx +44 -0
  382. package/dist/assets/storefront/src/components/ui/input-otp.tsx +77 -0
  383. package/dist/assets/storefront/src/components/ui/input.tsx +21 -0
  384. package/dist/assets/storefront/src/components/ui/kbd-shortcut.tsx +20 -0
  385. package/dist/assets/storefront/src/components/ui/label.tsx +24 -0
  386. package/dist/assets/storefront/src/components/ui/menubar.tsx +276 -0
  387. package/dist/assets/storefront/src/components/ui/navigation-menu.tsx +168 -0
  388. package/dist/assets/storefront/src/components/ui/pagination.tsx +127 -0
  389. package/dist/assets/storefront/src/components/ui/popover.tsx +48 -0
  390. package/dist/assets/storefront/src/components/ui/progress.tsx +31 -0
  391. package/dist/assets/storefront/src/components/ui/radio-group.tsx +45 -0
  392. package/dist/assets/storefront/src/components/ui/resizable.tsx +56 -0
  393. package/dist/assets/storefront/src/components/ui/scroll-area.tsx +58 -0
  394. package/dist/assets/storefront/src/components/ui/select.tsx +185 -0
  395. package/dist/assets/storefront/src/components/ui/separator.tsx +28 -0
  396. package/dist/assets/storefront/src/components/ui/sheet.tsx +139 -0
  397. package/dist/assets/storefront/src/components/ui/sidebar.tsx +728 -0
  398. package/dist/assets/storefront/src/components/ui/skeleton.tsx +13 -0
  399. package/dist/assets/storefront/src/components/ui/slider.tsx +63 -0
  400. package/dist/assets/storefront/src/components/ui/sonner.tsx +25 -0
  401. package/dist/assets/storefront/src/components/ui/switch.tsx +31 -0
  402. package/dist/assets/storefront/src/components/ui/table.tsx +116 -0
  403. package/dist/assets/storefront/src/components/ui/tabs.tsx +66 -0
  404. package/dist/assets/storefront/src/components/ui/textarea.tsx +18 -0
  405. package/dist/assets/storefront/src/components/ui/toggle-group.tsx +73 -0
  406. package/dist/assets/storefront/src/components/ui/toggle.tsx +47 -0
  407. package/dist/assets/storefront/src/components/ui/tooltip.tsx +61 -0
  408. package/dist/assets/storefront/src/config/branding.ts +4 -0
  409. package/dist/assets/storefront/src/config/scenario-meta.ts +46 -0
  410. package/dist/assets/storefront/src/config/scenario.ts +313 -0
  411. package/dist/assets/storefront/src/contexts/auth-context.tsx +35 -0
  412. package/dist/assets/storefront/src/graphql.ts +14 -0
  413. package/dist/assets/storefront/src/hooks/use-mobile.ts +19 -0
  414. package/dist/assets/storefront/src/i18n/locale-utils.ts +33 -0
  415. package/dist/assets/storefront/src/i18n/locales.ts +18 -0
  416. package/dist/assets/storefront/src/i18n/navigation.ts +35 -0
  417. package/dist/assets/storefront/src/i18n/request.ts +19 -0
  418. package/dist/assets/storefront/src/i18n/routing.ts +19 -0
  419. package/dist/assets/storefront/src/i18n/server.ts +16 -0
  420. package/dist/assets/storefront/src/lib/actions/switch-channel.ts +32 -0
  421. package/dist/assets/storefront/src/lib/actions/switch-currency.ts +25 -0
  422. package/dist/assets/storefront/src/lib/auth.ts +18 -0
  423. package/dist/assets/storefront/src/lib/backend-health.ts +38 -0
  424. package/dist/assets/storefront/src/lib/cart-count-context.tsx +59 -0
  425. package/dist/assets/storefront/src/lib/cart-guard-utils.ts +10 -0
  426. package/dist/assets/storefront/src/lib/cart-guard.ts +104 -0
  427. package/dist/assets/storefront/src/lib/channel-server.ts +28 -0
  428. package/dist/assets/storefront/src/lib/channel.ts +2 -0
  429. package/dist/assets/storefront/src/lib/company-context.ts +35 -0
  430. package/dist/assets/storefront/src/lib/company-permissions-context.tsx +40 -0
  431. package/dist/assets/storefront/src/lib/currency-server.ts +20 -0
  432. package/dist/assets/storefront/src/lib/currency.ts +2 -0
  433. package/dist/assets/storefront/src/lib/format.ts +48 -0
  434. package/dist/assets/storefront/src/lib/metadata.ts +85 -0
  435. package/dist/assets/storefront/src/lib/quantity.test.js +20 -0
  436. package/dist/assets/storefront/src/lib/quantity.ts +20 -0
  437. package/dist/assets/storefront/src/lib/search-bar-context.tsx +45 -0
  438. package/dist/assets/storefront/src/lib/search-helpers.ts +69 -0
  439. package/dist/assets/storefront/src/lib/use-recent-searches.ts +55 -0
  440. package/dist/assets/storefront/src/lib/utils.ts +6 -0
  441. package/dist/assets/storefront/src/lib/vendure/actions.ts +96 -0
  442. package/dist/assets/storefront/src/lib/vendure/api.ts +164 -0
  443. package/dist/assets/storefront/src/lib/vendure/approval-utils.ts +21 -0
  444. package/dist/assets/storefront/src/lib/vendure/cached.ts +71 -0
  445. package/dist/assets/storefront/src/lib/vendure/fragments.ts +213 -0
  446. package/dist/assets/storefront/src/lib/vendure/instant-search-action.ts +104 -0
  447. package/dist/assets/storefront/src/lib/vendure/mutations.ts +1136 -0
  448. package/dist/assets/storefront/src/lib/vendure/queries.ts +1406 -0
  449. package/dist/assets/storefront/src/middleware.ts +11 -0
  450. package/dist/assets/storefront/src/scenarios/b2b-wholesale/branding.ts +180 -0
  451. package/dist/assets/storefront/src/scenarios/b2b-wholesale/hero.tsx +122 -0
  452. package/dist/assets/storefront/src/scenarios/b2b-wholesale/index.ts +21 -0
  453. package/dist/assets/storefront/src/scenarios/b2b-wholesale/meta.ts +3 -0
  454. package/dist/assets/storefront/src/scenarios/default/branding.ts +148 -0
  455. package/dist/assets/storefront/src/scenarios/default/hero.tsx +107 -0
  456. package/dist/assets/storefront/src/scenarios/default/index.ts +12 -0
  457. package/dist/assets/storefront/src/scenarios/default/meta.ts +3 -0
  458. package/dist/assets/storefront/src/scenarios/kaminpro/auth-gate.tsx +36 -0
  459. package/dist/assets/storefront/src/scenarios/kaminpro/branding.ts +238 -0
  460. package/dist/assets/storefront/src/scenarios/kaminpro/cart-items.tsx +359 -0
  461. package/dist/assets/storefront/src/scenarios/kaminpro/hero.tsx +123 -0
  462. package/dist/assets/storefront/src/scenarios/kaminpro/index.ts +50 -0
  463. package/dist/assets/storefront/src/scenarios/kaminpro/meta.ts +9 -0
  464. package/dist/assets/storefront/src/scenarios/kaminpro/pdp/components/banners.tsx +21 -0
  465. package/dist/assets/storefront/src/scenarios/kaminpro/pdp/components/bom-basket.tsx +221 -0
  466. package/dist/assets/storefront/src/scenarios/kaminpro/pdp/components/btn.tsx +38 -0
  467. package/dist/assets/storefront/src/scenarios/kaminpro/pdp/components/chip.tsx +35 -0
  468. package/dist/assets/storefront/src/scenarios/kaminpro/pdp/components/config-header.tsx +72 -0
  469. package/dist/assets/storefront/src/scenarios/kaminpro/pdp/components/field-row.tsx +126 -0
  470. package/dist/assets/storefront/src/scenarios/kaminpro/pdp/components/info-dot.tsx +38 -0
  471. package/dist/assets/storefront/src/scenarios/kaminpro/pdp/components/login-notice.tsx +81 -0
  472. package/dist/assets/storefront/src/scenarios/kaminpro/pdp/components/module-panel.tsx +144 -0
  473. package/dist/assets/storefront/src/scenarios/kaminpro/pdp/components/quote-dialog.tsx +110 -0
  474. package/dist/assets/storefront/src/scenarios/kaminpro/pdp/components/schematic.tsx +674 -0
  475. package/dist/assets/storefront/src/scenarios/kaminpro/pdp/components/why-panel.tsx +66 -0
  476. package/dist/assets/storefront/src/scenarios/kaminpro/pdp/configurator-pdp.tsx +43 -0
  477. package/dist/assets/storefront/src/scenarios/kaminpro/pdp/configurator-shell.tsx +320 -0
  478. package/dist/assets/storefront/src/scenarios/kaminpro/pdp/lib/data.ts +150 -0
  479. package/dist/assets/storefront/src/scenarios/kaminpro/pdp/lib/types.ts +30 -0
  480. package/dist/assets/storefront/src/scenarios/kaminpro/pdp/styles.css +104 -0
  481. package/dist/assets/storefront/src/scenarios/kaminpro/shop-by-system.tsx +97 -0
  482. package/dist/assets/storefront/src/scenarios/kaminpro/system-finder/decision-tree.ts +261 -0
  483. package/dist/assets/storefront/src/scenarios/kaminpro/system-finder/page.tsx +21 -0
  484. package/dist/assets/storefront/src/scenarios/kaminpro/system-finder/wizard.tsx +600 -0
  485. package/dist/assets/storefront/src/schema.graphql.placeholder +5 -0
  486. package/dist/assets/storefront/tsconfig.json +37 -0
  487. package/dist/assets/templates/CLAUDE.md.hbs +63 -0
  488. package/dist/assets/templates/README.md.hbs +53 -0
  489. package/dist/assets/templates/custom-populate.ts.hbs +28 -0
  490. package/dist/assets/templates/docker-compose.yml.hbs +29 -0
  491. package/dist/assets/templates/env.hbs +44 -0
  492. package/dist/assets/templates/environment.d.ts.hbs +32 -0
  493. package/dist/assets/templates/gitignore.hbs +7 -0
  494. package/dist/assets/templates/index.ts.hbs +16 -0
  495. package/dist/assets/templates/npmrc.hbs +1 -0
  496. package/dist/assets/templates/populate.ts.hbs +27 -0
  497. package/dist/assets/templates/root-package.json.hbs +17 -0
  498. package/dist/assets/templates/server-package.json.hbs +31 -0
  499. package/dist/assets/templates/tsconfig.dashboard.json.hbs +17 -0
  500. package/dist/assets/templates/tsconfig.root.json.hbs +16 -0
  501. package/dist/assets/templates/tsconfig.server.json.hbs +20 -0
  502. package/dist/assets/templates/vendure-config.ts.hbs +80 -0
  503. package/dist/assets/templates/vite.config.mts.hbs +27 -0
  504. package/dist/bin/run.d.ts +2 -0
  505. package/dist/bin/run.js +79 -0
  506. package/dist/bin/run.js.map +1 -0
  507. package/dist/cli.d.ts +6 -0
  508. package/dist/cli.js +154 -0
  509. package/dist/cli.js.map +1 -0
  510. package/dist/git-init.d.ts +4 -0
  511. package/dist/git-init.js +60 -0
  512. package/dist/git-init.js.map +1 -0
  513. package/dist/index.d.ts +4 -0
  514. package/dist/index.js +13 -0
  515. package/dist/index.js.map +1 -0
  516. package/dist/plugin-registry.d.ts +10 -0
  517. package/dist/plugin-registry.js +485 -0
  518. package/dist/plugin-registry.js.map +1 -0
  519. package/dist/scaffolder.d.ts +10 -0
  520. package/dist/scaffolder.js +218 -0
  521. package/dist/scaffolder.js.map +1 -0
  522. package/dist/storefront-copier.d.ts +6 -0
  523. package/dist/storefront-copier.js +68 -0
  524. package/dist/storefront-copier.js.map +1 -0
  525. package/dist/template-renderer.d.ts +30 -0
  526. package/dist/template-renderer.js +177 -0
  527. package/dist/template-renderer.js.map +1 -0
  528. package/dist/types.d.ts +60 -0
  529. package/dist/types.js +3 -0
  530. package/dist/types.js.map +1 -0
  531. package/package.json +48 -0
@@ -0,0 +1,313 @@
1
+ import type { ReactElement } from 'react';
2
+ import type { ConfiguratorSystem, ProductDetail } from '@/lib/vendure/queries';
3
+ import type { ShoppingListInfo } from '@/app/[locale]/account/shopping-lists/actions';
4
+ import type { ProductInfoProps } from '@/components/commerce/product-info';
5
+ import type { ProductSidebarProps } from '@/components/commerce/product-sidebar';
6
+ import type { ProductImageCarouselProps } from '@/components/commerce/product-image-carousel';
7
+ import type { RelatedProductsProps } from '@/components/commerce/related-products';
8
+ import type { ShopByCategoryProps } from '@/components/commerce/shop-by-category';
9
+ import { defaultScenario } from '@/scenarios/default';
10
+ import { bauDirektScenario } from '@/scenarios/b2b-wholesale';
11
+ import { kaminProScenario } from '@/scenarios/kaminpro';
12
+
13
+ // =============================================================
14
+ // Branding — pure serializable data (no React components)
15
+ // =============================================================
16
+
17
+ export interface StorefrontBranding {
18
+ siteName: string;
19
+ siteDescription: string;
20
+
21
+ logo: { src: string; alt: string; width: number; height: number };
22
+ logoInverted?: { src: string; alt: string; width: number; height: number };
23
+
24
+ /** CSS custom property overrides, keyed by variable name (e.g. '--primary', '--radius') */
25
+ colors: {
26
+ dark: Record<string, string>;
27
+ light: Record<string, string>;
28
+ };
29
+
30
+ /** Navigation links shown in the top navbar. Defaults to Catalog, Orders, Quotes. */
31
+ navLinks?: Array<{ href: string; label: string }>;
32
+
33
+ /**
34
+ * By default the Navbar appends an `Unternehmen` link for logged-in
35
+ * company-bound users. Opt out to keep the scenario nav strip fixed —
36
+ * useful for demos that want to keep the nav narrow regardless of
37
+ * who's signed in.
38
+ */
39
+ hideCompanyNavLink?: boolean;
40
+
41
+ /**
42
+ * Hide the globe / language-picker dropdown in the navbar. Useful for
43
+ * single-locale scenarios where offering a locale switch suggests
44
+ * translations exist when they don't. The underlying routing still
45
+ * carries the locale prefix; only the UI affordance is suppressed.
46
+ */
47
+ hideLanguagePicker?: boolean;
48
+
49
+ /** Demo accounts shown on the sign-in page for quick login. */
50
+ demoAccounts?: Array<{ email: string; label: string; description: string }>;
51
+
52
+ footer: {
53
+ copyright: string;
54
+ poweredByLinks?: Array<{ label: string; href: string }>;
55
+ };
56
+
57
+ metadata: {
58
+ themeColor: string;
59
+ defaultDescription: string;
60
+ homepageTitle: string;
61
+ homepageDescription: string;
62
+ };
63
+
64
+ /**
65
+ * Optional typography opt-ins. Default scenarios get the standard Geist
66
+ * stack; opting in swaps the whole site onto the scenario's preferred
67
+ * typeface. Kept as a narrow flag set rather than a free-form font
68
+ * descriptor so next/font imports can stay at module scope (required by
69
+ * next/font — dynamic imports are not supported).
70
+ */
71
+ fonts?: {
72
+ /**
73
+ * Use the "technical documentation" stack: `Inter Tight` for prose
74
+ * and `JetBrains Mono` for code/monospace contexts. Also adds the
75
+ * `.kp-app` class to `<body>` so scenario-scoped utility styles
76
+ * (caps tracking, tabular nums, slim scrollbars) engage.
77
+ */
78
+ technical?: boolean;
79
+ };
80
+ }
81
+
82
+ // =============================================================
83
+ // Component override types
84
+ // =============================================================
85
+
86
+ /**
87
+ * A component type that supports both sync (Client) and async (Server) components.
88
+ * React's ComponentType can't express async Server Components — see
89
+ * https://github.com/DefinitelyTyped/DefinitelyTyped/discussions/65079
90
+ */
91
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
92
+ export type ServerComponent<P = {}> = (props: P) => ReactElement | Promise<ReactElement>;
93
+
94
+ /** Props for a full PDP page override */
95
+ export interface PdpPageProps {
96
+ product: ProductDetail;
97
+ searchParams: { [key: string]: string | string[] | undefined };
98
+ breadcrumbs: Array<{ name: string; href?: string }>;
99
+ shoppingLists: ShoppingListInfo[] | null;
100
+ currencyCode: string;
101
+ /** Active channel token — pass to publicClient queries for correct channel isolation in 'use cache' functions. */
102
+ channelToken?: string;
103
+ /**
104
+ * Fetched `ConfiguratorSystem` for products carrying a
105
+ * `configuratorSystemCode` custom field. `null` for non-configurable
106
+ * products (a conditional PDP override would normally gate on this).
107
+ */
108
+ configuratorSystem?: ConfiguratorSystem | null;
109
+ }
110
+
111
+ /** Slot-level overrides for the default PDP layout */
112
+ export interface PdpSlotOverrides {
113
+ ProductInfo?: ServerComponent<ProductInfoProps>;
114
+ ProductSidebar?: ServerComponent<ProductSidebarProps>;
115
+ ProductImageCarousel?: ServerComponent<ProductImageCarouselProps>;
116
+ RelatedProducts?: ServerComponent<RelatedProductsProps>;
117
+ }
118
+
119
+ /**
120
+ * Full-page PDP override that only engages when `shouldApply` returns true
121
+ * for the current product. Non-matching products fall through to the default
122
+ * PDP composition (or to `slots` if both are provided on a future extension).
123
+ */
124
+ export interface ConditionalPdpOverride {
125
+ shouldApply: (product: ProductDetail) => boolean;
126
+ component: ServerComponent<PdpPageProps>;
127
+ }
128
+
129
+ /** Slot-level overrides for the default homepage layout */
130
+ export interface HomeSlotOverrides {
131
+ Hero?: ServerComponent;
132
+ /**
133
+ * Replace the default `ShopByCategory` tile row. The base component only
134
+ * renders when every top-level collection has a `featuredAsset`; an
135
+ * override is free to ignore that rule.
136
+ */
137
+ ShopByCategory?: ServerComponent<ShopByCategoryProps>;
138
+ }
139
+
140
+ /** Slot-level overrides for the default cart page. */
141
+ export interface CartSlotOverrides {
142
+ /**
143
+ * Replace the `<CartItems>` component inside the cart page. The override
144
+ * receives the same props as the built-in component and is responsible
145
+ * for rendering the entire line-items column (not the order summary /
146
+ * promotion-code sidebar).
147
+ *
148
+ * Typed as `ComponentType<any>` to avoid locking the storefront into the
149
+ * built-in `ActiveOrder` shape — a scenario override can query its own
150
+ * extra fields and declare a stricter type locally.
151
+ */
152
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
153
+ CartItems?: ServerComponent<any>;
154
+ }
155
+
156
+ // =============================================================
157
+ // Channel switching
158
+ // =============================================================
159
+
160
+ export interface ChannelOption {
161
+ /** The vendure-token header value */
162
+ token: string;
163
+ /** Human-readable label shown in the picker UI (e.g. "Österreich") */
164
+ label: string;
165
+ /** ISO 3166-1 alpha-2 country code (e.g. "AT", "DE") */
166
+ countryCode: string;
167
+ }
168
+
169
+ export interface ChannelsConfig {
170
+ /** Available channels for this scenario */
171
+ available: ChannelOption[];
172
+ /** Token of the channel to use when no cookie is set */
173
+ defaultToken: string;
174
+ }
175
+
176
+ // =============================================================
177
+ // Scenario Config
178
+ // =============================================================
179
+
180
+ export interface ScenarioConfig {
181
+ branding: StorefrontBranding;
182
+
183
+ /** Multi-channel configuration. When present, enables the ChannelPicker in the navbar. */
184
+ channels?: ChannelsConfig;
185
+
186
+ /**
187
+ * Per-page overrides. Each key accepts EITHER:
188
+ * - A ServerComponent to replace the entire page
189
+ * - An object with slot keys to override individual sections
190
+ */
191
+ overrides?: {
192
+ pdp?: ServerComponent<PdpPageProps> | ConditionalPdpOverride | PdpSlotOverrides;
193
+ home?: ServerComponent | HomeSlotOverrides;
194
+ cart?: CartSlotOverrides;
195
+ };
196
+
197
+ /** Scenario-specific routes. The route page file checks this to render or return notFound(). */
198
+ routes?: Record<string, ServerComponent>;
199
+ }
200
+
201
+ /**
202
+ * Type guard: is the override a full page component (a function), versus a
203
+ * slot-overrides object?
204
+ *
205
+ * NOTE: this guard discriminates ONLY on `typeof === 'function'`. If a future
206
+ * override variant is added that is itself callable (e.g. a higher-order
207
+ * component returning a slot map), this guard breaks. Only add object-valued
208
+ * variants to the override unions.
209
+ */
210
+ export function isFullPageOverride(
211
+ override: unknown,
212
+ ): override is (...args: unknown[]) => unknown {
213
+ return typeof override === 'function';
214
+ }
215
+
216
+ /** Type guard: is the override a conditional `{ shouldApply, component }` form? */
217
+ export function isConditionalPdpOverride(
218
+ override: unknown,
219
+ ): override is ConditionalPdpOverride {
220
+ return (
221
+ typeof override === 'object' &&
222
+ override !== null &&
223
+ typeof (override as ConditionalPdpOverride).shouldApply === 'function' &&
224
+ typeof (override as ConditionalPdpOverride).component === 'function'
225
+ );
226
+ }
227
+
228
+ // =============================================================
229
+ // Registry — add new scenarios here
230
+ // =============================================================
231
+
232
+ const registry: Record<string, ScenarioConfig> = {
233
+ default: defaultScenario,
234
+ 'b2b-wholesale': bauDirektScenario,
235
+ kaminpro: kaminProScenario,
236
+ };
237
+
238
+ // Safe to cache at module level: NEXT_PUBLIC_SCENARIO is baked at build time, so
239
+ // the active scenario never changes within a single process/build.
240
+ let _cached: ScenarioConfig | undefined;
241
+
242
+ export function getScenarioConfig(): ScenarioConfig {
243
+ if (_cached) return _cached;
244
+ const scenario = process.env.NEXT_PUBLIC_SCENARIO || 'default';
245
+ if (!registry[scenario]) {
246
+ console.warn(
247
+ `[scenario] Unknown scenario "${scenario}" — falling back to "default". ` +
248
+ `Did you register it in scenario.ts?`,
249
+ );
250
+ }
251
+ _cached = registry[scenario] ?? registry.default;
252
+ return _cached;
253
+ }
254
+
255
+ export function getBranding(): StorefrontBranding {
256
+ return getScenarioConfig().branding;
257
+ }
258
+
259
+ export function getChannelsConfig(): ChannelsConfig | undefined {
260
+ return getScenarioConfig().channels;
261
+ }
262
+
263
+ const _brandingStyleTag = (() => {
264
+ const { colors, fonts } = getBranding();
265
+ const darkVars = Object.entries(colors.dark)
266
+ .map(([k, v]) => `${k}: ${v}`)
267
+ .join('; ') + ';';
268
+ const lightVars = Object.entries(colors.light)
269
+ .map(([k, v]) => `${k}: ${v}`)
270
+ .join('; ') + ';';
271
+
272
+ let base = `:root { ${darkVars} } .light { ${lightVars} }`;
273
+
274
+ // Scenario-scoped typography overrides. The `.kp-app` class is only
275
+ // added to <body> when `fonts.technical === true`, so these rules
276
+ // are dormant for every other scenario.
277
+ if (fonts?.technical) {
278
+ base += `
279
+ .kp-app {
280
+ --font-geist-sans: var(--font-inter-tight);
281
+ --font-geist-mono: var(--font-jetbrains-mono);
282
+ font-feature-settings: 'ss01', 'cv11', 'tnum';
283
+ letter-spacing: -0.005em;
284
+ }
285
+ .kp-app .caps {
286
+ font-size: 10.5px;
287
+ font-weight: 600;
288
+ letter-spacing: 0.08em;
289
+ text-transform: uppercase;
290
+ }
291
+ .kp-app .mono {
292
+ font-family: var(--font-jetbrains-mono), ui-monospace, monospace;
293
+ }
294
+ .kp-app :where(table, .tabular-nums) { font-variant-numeric: tabular-nums; }
295
+ /* Slim scrollbars in scenario-scoped scroll containers (same rules as
296
+ the configurator's scroll-slim utility, just widened in scope). */
297
+ .kp-app *::-webkit-scrollbar { width: 8px; height: 8px; }
298
+ .kp-app *::-webkit-scrollbar-track { background: transparent; }
299
+ .kp-app *::-webkit-scrollbar-thumb {
300
+ background: var(--border);
301
+ border-radius: 4px;
302
+ border: 2px solid var(--background);
303
+ }
304
+ .kp-app *::-webkit-scrollbar-thumb:hover { background: var(--muted-foreground); }
305
+ `;
306
+ }
307
+
308
+ return base;
309
+ })();
310
+
311
+ export function getBrandingStyleTag(): string {
312
+ return _brandingStyleTag;
313
+ }
@@ -0,0 +1,35 @@
1
+ 'use client';
2
+
3
+ import {createContext, ReactNode, useContext} from 'react';
4
+ import {ResultOf} from '@/graphql';
5
+ import {ActiveCustomerFragment} from '@/lib/vendure/fragments';
6
+
7
+ type ActiveCustomer = ResultOf<typeof ActiveCustomerFragment>;
8
+
9
+ interface AuthContextType {
10
+ activeCustomer: Promise<ActiveCustomer | null>;
11
+ }
12
+
13
+ const AuthContext = createContext<AuthContextType | undefined>(undefined);
14
+
15
+ interface AuthProviderProps {
16
+ children: ReactNode;
17
+ initialActiveCustomerPromise: Promise<ActiveCustomer | null>;
18
+ }
19
+
20
+ export function AuthProvider({children, initialActiveCustomerPromise}: AuthProviderProps) {
21
+
22
+ return (
23
+ <AuthContext.Provider value={{activeCustomer: initialActiveCustomerPromise}}>
24
+ {children}
25
+ </AuthContext.Provider>
26
+ );
27
+ }
28
+
29
+ export function useAuth() {
30
+ const context = useContext(AuthContext);
31
+ if (context === undefined) {
32
+ throw new Error('useAuth must be used within an AuthProvider');
33
+ }
34
+ return context;
35
+ }
@@ -0,0 +1,14 @@
1
+ import { initGraphQLTada } from 'gql.tada';
2
+ import type { introspection } from './graphql-env.d.ts';
3
+
4
+ export const graphql = initGraphQLTada<{
5
+ introspection: introspection;
6
+ scalars: {
7
+ DateTime: string,
8
+ JSON: Record<string, unknown>,
9
+ Money: number
10
+ }
11
+ }>();
12
+
13
+ export type { FragmentOf, ResultOf, VariablesOf } from 'gql.tada';
14
+ export { readFragment } from 'gql.tada';
@@ -0,0 +1,19 @@
1
+ import * as React from "react"
2
+
3
+ const MOBILE_BREAKPOINT = 768
4
+
5
+ export function useIsMobile() {
6
+ const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
7
+
8
+ React.useEffect(() => {
9
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
10
+ const onChange = () => {
11
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
12
+ }
13
+ mql.addEventListener("change", onChange)
14
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
15
+ return () => mql.removeEventListener("change", onChange)
16
+ }, [])
17
+
18
+ return !!isMobile
19
+ }
@@ -0,0 +1,33 @@
1
+ import {routing, type Locale} from './routing';
2
+
3
+ const INTL_LOCALE_MAP: Record<Locale, string> = {en: 'en-US', de: 'de-DE'};
4
+ const OG_LOCALE_MAP: Record<Locale, string> = {en: 'en_US', de: 'de_DE'};
5
+
6
+ /** Map a routing locale to a full BCP-47 tag for Intl APIs. Falls back to the raw locale. */
7
+ export function toIntlLocale(locale: string): string {
8
+ return INTL_LOCALE_MAP[locale as Locale] ?? locale;
9
+ }
10
+
11
+ /** Map a routing locale to an OpenGraph-style locale. Falls back to the raw locale. */
12
+ export function toOgLocale(locale: string): string {
13
+ return OG_LOCALE_MAP[locale as Locale] ?? locale;
14
+ }
15
+
16
+ /** Prepend a locale prefix to a path. Ensures no double-prefixing. */
17
+ export function applyLocalePrefix(path: string, locale: string): string {
18
+ const stripped = stripLocalePrefix(path);
19
+ return `/${locale}${stripped === '/' ? '' : stripped}`;
20
+ }
21
+
22
+ /** Strip locale prefix from a path. Returns the path unchanged if no prefix matches. */
23
+ export function stripLocalePrefix(path: string): string {
24
+ for (const locale of routing.locales) {
25
+ if (path.startsWith(`/${locale}/`)) {
26
+ return path.slice(locale.length + 1) || '/';
27
+ }
28
+ if (path === `/${locale}`) {
29
+ return '/';
30
+ }
31
+ }
32
+ return path;
33
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Single source of truth for the set of locales the storefront supports.
3
+ *
4
+ * Kept in its own tiny module so modules outside the routing graph
5
+ * (e.g. server actions, helpers that need to narrow `string → Locale`)
6
+ * can import the `Locale` type without pulling `routing.ts`'s full
7
+ * import surface — `routing.ts` itself is imported by client components
8
+ * via `@/i18n/navigation`, so anything it drags in ends up in client
9
+ * bundles.
10
+ */
11
+ export const LOCALES = ['en', 'de'] as const;
12
+
13
+ export type Locale = (typeof LOCALES)[number];
14
+
15
+ export const localeNames: Record<Locale, string> = {
16
+ en: 'English',
17
+ de: 'Deutsch',
18
+ };
@@ -0,0 +1,35 @@
1
+ import {createNavigation} from 'next-intl/navigation';
2
+ import {routing} from './routing';
3
+
4
+ const nav = createNavigation(routing);
5
+
6
+ export const Link = nav.Link;
7
+ export const usePathname = nav.usePathname;
8
+ export const useRouter = nav.useRouter;
9
+ export const getPathname = nav.getPathname;
10
+
11
+ /**
12
+ * Locale-aware redirect that accepts a plain pathname string.
13
+ *
14
+ * next-intl 4.9+ changed nav.redirect() to require {href, locale} instead
15
+ * of a plain string. This wrapper preserves the simpler call-site API used
16
+ * across ~30 server actions and pages: redirect('/path').
17
+ *
18
+ * ⚠ MUST BE AWAITED. This is an async function — a bare `redirect('/path')`
19
+ * call returns a floating Promise and the NEXT_REDIRECT never gets thrown,
20
+ * so the caller keeps executing past the "redirect". Always write:
21
+ *
22
+ * await redirect('/path');
23
+ *
24
+ * (Unlike `redirect` from `next/navigation`, which is synchronous and
25
+ * throws immediately.)
26
+ *
27
+ * Uses a dynamic import for getLocale to avoid pulling next-intl/server
28
+ * into the module's top-level scope (which would break client component
29
+ * bundling since this module also exports Link).
30
+ */
31
+ export async function redirect(pathname: string, type?: 'push' | 'replace'): Promise<never> {
32
+ const {getLocale} = await import('next-intl/server');
33
+ const locale = await getLocale();
34
+ return nav.redirect({href: pathname, locale}, type);
35
+ }
@@ -0,0 +1,19 @@
1
+ import {hasLocale} from 'next-intl';
2
+ import {getRequestConfig} from 'next-intl/server';
3
+ import {routing} from './routing';
4
+
5
+ // Static per-locale imports. When adding a new locale to routing.locales,
6
+ // add a corresponding entry here.
7
+ const messageImports = {
8
+ en: () => import('../../messages/en.json'),
9
+ de: () => import('../../messages/de.json'),
10
+ } as const;
11
+
12
+ export default getRequestConfig(async ({requestLocale}) => {
13
+ const requested = await requestLocale;
14
+ const locale = hasLocale(routing.locales, requested) ? requested : routing.defaultLocale;
15
+ return {
16
+ locale,
17
+ messages: (await messageImports[locale]()).default,
18
+ };
19
+ });
@@ -0,0 +1,19 @@
1
+ import {defineRouting} from 'next-intl/routing';
2
+ import {getScenarioMeta} from '@/config/scenario-meta';
3
+ import {LOCALES, type Locale, localeNames} from './locales';
4
+
5
+ // Scenarios declare their preferred default locale in their own
6
+ // `meta.ts` (a client-safe projection that never imports React or
7
+ // server-only APIs). `getScenarioMeta()` resolves the active scenario
8
+ // at build time from `NEXT_PUBLIC_SCENARIO` and returns its meta.
9
+ // Scenarios that don't declare a `defaultLocale` inherit the first
10
+ // entry in `LOCALES`.
11
+ const scenarioDefaultLocale = getScenarioMeta().defaultLocale ?? LOCALES[0];
12
+
13
+ export const routing = defineRouting({
14
+ locales: LOCALES,
15
+ defaultLocale: scenarioDefaultLocale,
16
+ });
17
+
18
+ export type {Locale};
19
+ export {localeNames};
@@ -0,0 +1,16 @@
1
+ import {getLocale} from 'next-intl/server';
2
+ import {hasLocale} from 'next-intl';
3
+ import {routing, type Locale} from './routing';
4
+
5
+ /**
6
+ * Resolve the current locale from request context with validation.
7
+ * Falls back to defaultLocale if the resolved locale isn't in routing config.
8
+ *
9
+ * Use this in non-cached server components and server actions.
10
+ * For 'use cache' scopes or route files (layout/page), prefer rootLocale()
11
+ * from 'next/root-params' directly (the SWC transform only works in route files).
12
+ */
13
+ export async function getRouteLocale(): Promise<Locale> {
14
+ const loc = await getLocale();
15
+ return hasLocale(routing.locales, loc) ? (loc as Locale) : routing.defaultLocale;
16
+ }
@@ -0,0 +1,32 @@
1
+ 'use server';
2
+
3
+ import {cookies} from 'next/headers';
4
+ import {revalidatePath} from 'next/cache';
5
+ import {CHANNEL_COOKIE} from '@/lib/channel';
6
+ import {CURRENCY_COOKIE} from '@/lib/currency';
7
+ import {getChannelsConfig} from '@/config/scenario';
8
+
9
+ export async function switchChannel(token: string) {
10
+ const channelsConfig = getChannelsConfig();
11
+ if (!channelsConfig) {
12
+ return {success: false, message: 'Channel switching not configured'};
13
+ }
14
+ if (!channelsConfig.available.some(c => c.token === token)) {
15
+ return {success: false, message: 'Invalid channel token'};
16
+ }
17
+
18
+ const jar = await cookies();
19
+ jar.set(CHANNEL_COOKIE, token, {
20
+ path: '/',
21
+ maxAge: 60 * 60 * 24 * 365,
22
+ sameSite: 'lax',
23
+ httpOnly: true,
24
+ });
25
+
26
+ // Clear currency preference — the new channel may have different available currencies,
27
+ // so let getActiveCurrencyCode() fall back to the new channel's default.
28
+ jar.delete(CURRENCY_COOKIE);
29
+
30
+ revalidatePath('/', 'layout');
31
+ return {success: true};
32
+ }
@@ -0,0 +1,25 @@
1
+ 'use server';
2
+
3
+ import {cookies} from 'next/headers';
4
+ import {revalidatePath} from 'next/cache';
5
+ import {CURRENCY_COOKIE} from '@/lib/currency';
6
+ import {getActiveChannelCached} from '@/lib/vendure/cached';
7
+
8
+ export async function switchCurrency(currencyCode: string) {
9
+ const {getActiveChannelToken} = await import('@/lib/channel-server');
10
+ const channelToken = await getActiveChannelToken();
11
+ const channel = await getActiveChannelCached(channelToken);
12
+ if (!channel.availableCurrencyCodes.includes(currencyCode as never)) {
13
+ return {success: false, message: 'Invalid currency code'};
14
+ }
15
+
16
+ const jar = await cookies();
17
+ jar.set(CURRENCY_COOKIE, currencyCode, {
18
+ path: '/',
19
+ maxAge: 60 * 60 * 24 * 365,
20
+ sameSite: 'lax',
21
+ });
22
+
23
+ revalidatePath('/', 'layout');
24
+ return {success: true};
25
+ }
@@ -0,0 +1,18 @@
1
+ import {cookies} from 'next/headers';
2
+
3
+ const AUTH_TOKEN_COOKIE = process.env.VENDURE_AUTH_TOKEN_COOKIE || 'vendure-auth-token';
4
+
5
+ export async function setAuthToken(token: string) {
6
+ const cookieStore = await cookies();
7
+ cookieStore.set(AUTH_TOKEN_COOKIE, token);
8
+ }
9
+
10
+ export async function getAuthToken(): Promise<string | undefined> {
11
+ const cookieStore = await cookies();
12
+ return cookieStore.get(AUTH_TOKEN_COOKIE)?.value;
13
+ }
14
+
15
+ export async function removeAuthToken() {
16
+ const cookieStore = await cookies();
17
+ cookieStore.delete(AUTH_TOKEN_COOKIE);
18
+ }
@@ -0,0 +1,38 @@
1
+ import {cacheLife} from 'next/cache';
2
+
3
+ const HEALTH_CHECK_TIMEOUT_MS = 3000;
4
+
5
+ /**
6
+ * Pings the Vendure Shop API to check whether the backend is reachable.
7
+ *
8
+ * Used to detect when a demo scenario has been paused via the demo control
9
+ * panel — in that case the storefront still resolves (it's hosted separately
10
+ * on Vercel) but every API call fails, leaving the user with a branded but
11
+ * empty shell. When this returns false we render a "Demo Paused" page instead.
12
+ *
13
+ * Cached for 15s (cacheLife('seconds')) so a stop/start of the backend is
14
+ * reflected quickly without hammering the API on every request.
15
+ */
16
+ export async function isBackendReachable(): Promise<boolean> {
17
+ 'use cache';
18
+ cacheLife('seconds');
19
+
20
+ const apiUrl = process.env.VENDURE_SHOP_API_URL || process.env.NEXT_PUBLIC_VENDURE_SHOP_API_URL;
21
+ if (!apiUrl) return true;
22
+
23
+ const controller = new AbortController();
24
+ const timeout = setTimeout(() => controller.abort(), HEALTH_CHECK_TIMEOUT_MS);
25
+ try {
26
+ const res = await fetch(apiUrl, {
27
+ method: 'POST',
28
+ headers: {'Content-Type': 'application/json'},
29
+ body: JSON.stringify({query: '{ __typename }'}),
30
+ signal: controller.signal,
31
+ });
32
+ return res.ok;
33
+ } catch {
34
+ return false;
35
+ } finally {
36
+ clearTimeout(timeout);
37
+ }
38
+ }