@doswiftly/cli 0.1.18 → 0.1.20

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 (277) hide show
  1. package/README.md +23 -323
  2. package/dist/commands/check.js +1 -1
  3. package/dist/commands/check.js.map +1 -1
  4. package/dist/commands/deploy.d.ts +20 -0
  5. package/dist/commands/deploy.d.ts.map +1 -1
  6. package/dist/commands/deploy.js +249 -17
  7. package/dist/commands/deploy.js.map +1 -1
  8. package/dist/commands/doctor.js +3 -3
  9. package/dist/commands/doctor.js.map +1 -1
  10. package/dist/commands/init.js +4 -4
  11. package/dist/commands/sdk.js +5 -5
  12. package/dist/commands/sdk.js.map +1 -1
  13. package/dist/commands/template.js +4 -4
  14. package/dist/commands/template.js.map +1 -1
  15. package/dist/commands/types.js +5 -5
  16. package/dist/commands/types.js.map +1 -1
  17. package/dist/commands/verify.js +2 -2
  18. package/dist/commands/verify.js.map +1 -1
  19. package/dist/lib/package-manager.d.ts +1 -1
  20. package/dist/lib/package-manager.js +1 -1
  21. package/package.json +4 -4
  22. package/templates/storefront-minimal/.github/workflows/build-template.yml +10 -0
  23. package/templates/storefront-minimal/wrangler.toml +11 -0
  24. package/templates/storefront-nextjs/.github/workflows/build-template.yml +10 -0
  25. package/templates/storefront-nextjs/README.md +16 -12
  26. package/templates/storefront-nextjs/app/account/orders/page.tsx +2 -2
  27. package/templates/storefront-nextjs/app/account/page.tsx +2 -2
  28. package/templates/storefront-nextjs/app/auth/login/page.tsx +1 -1
  29. package/templates/storefront-nextjs/app/auth/register/page.tsx +1 -1
  30. package/templates/storefront-nextjs/app/cart/page.tsx +1 -1
  31. package/templates/storefront-nextjs/app/categories/[slug]/page.tsx +2 -2
  32. package/templates/storefront-nextjs/app/categories/page.tsx +1 -1
  33. package/templates/storefront-nextjs/app/collections/[slug]/page.tsx +1 -1
  34. package/templates/storefront-nextjs/app/collections/page.tsx +1 -1
  35. package/templates/storefront-nextjs/app/page.tsx +1 -1
  36. package/templates/storefront-nextjs/app/products/[slug]/page.tsx +1 -1
  37. package/templates/storefront-nextjs/app/products/page.tsx +2 -2
  38. package/templates/storefront-nextjs/app/search/page.tsx +1 -1
  39. package/templates/storefront-nextjs/components/auth/auth-guard.tsx +1 -1
  40. package/templates/storefront-nextjs/components/commerce/add-to-cart-button.tsx +1 -1
  41. package/templates/storefront-nextjs/components/commerce/cart-icon.tsx +1 -1
  42. package/templates/storefront-nextjs/components/commerce/currency-selector.tsx +2 -2
  43. package/templates/storefront-nextjs/components/commerce/product-filters.tsx +1 -1
  44. package/templates/storefront-nextjs/components/commerce/product-price.tsx +1 -1
  45. package/templates/storefront-nextjs/components/commerce/search-input.tsx +1 -1
  46. package/templates/storefront-nextjs/components/commerce/sort-select.tsx +1 -1
  47. package/templates/storefront-nextjs/components/providers.tsx +1 -1
  48. package/templates/storefront-nextjs/lib/currency.tsx +3 -3
  49. package/templates/storefront-nextjs/lib/format.ts +1 -1
  50. package/templates/storefront-nextjs/lib/graphql-queries.ts +3 -3
  51. package/templates/storefront-nextjs/package.dev.json +1 -1
  52. package/templates/storefront-nextjs/package.json +1 -1
  53. package/templates/storefront-nextjs/package.json.template +1 -1
  54. package/templates/storefront-nextjs/wrangler.toml +11 -0
  55. package/templates/storefront-nextjs-shadcn/.github/workflows/build-template.yml +10 -0
  56. package/templates/storefront-nextjs-shadcn/.github/workflows/deploy.yml +47 -0
  57. package/templates/storefront-nextjs-shadcn/.github/workflows/preview.yml +47 -0
  58. package/templates/storefront-nextjs-shadcn/CLAUDE.md +172 -35
  59. package/templates/storefront-nextjs-shadcn/README.md +29 -162
  60. package/templates/storefront-nextjs-shadcn/app/{about → [locale]/about}/page.tsx +17 -14
  61. package/templates/storefront-nextjs-shadcn/app/[locale]/account/addresses/page.tsx +226 -0
  62. package/templates/storefront-nextjs-shadcn/app/[locale]/account/error.tsx +46 -0
  63. package/templates/storefront-nextjs-shadcn/app/[locale]/account/loading.tsx +19 -0
  64. package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/loyalty/page.tsx +89 -193
  65. package/templates/storefront-nextjs-shadcn/app/[locale]/account/orders/[id]/loading.tsx +60 -0
  66. package/templates/storefront-nextjs-shadcn/app/[locale]/account/orders/[id]/page.tsx +119 -0
  67. package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/orders/[id]/tracking/page.tsx +27 -25
  68. package/templates/storefront-nextjs-shadcn/app/[locale]/account/orders/page.tsx +101 -0
  69. package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/page.tsx +9 -7
  70. package/templates/storefront-nextjs-shadcn/app/[locale]/account/settings/page.tsx +208 -0
  71. package/templates/storefront-nextjs-shadcn/app/{auth → [locale]/auth}/forgot-password/page.tsx +24 -17
  72. package/templates/storefront-nextjs-shadcn/app/{auth → [locale]/auth}/login/page.tsx +5 -2
  73. package/templates/storefront-nextjs-shadcn/app/{auth → [locale]/auth}/register/page.tsx +5 -2
  74. package/templates/storefront-nextjs-shadcn/app/[locale]/blog/[slug]/loading.tsx +17 -0
  75. package/templates/storefront-nextjs-shadcn/app/{blog → [locale]/blog}/[slug]/page.tsx +44 -3
  76. package/templates/storefront-nextjs-shadcn/app/[locale]/blog/loading.tsx +19 -0
  77. package/templates/storefront-nextjs-shadcn/app/{brands → [locale]/brands}/page.tsx +2 -1
  78. package/templates/storefront-nextjs-shadcn/app/[locale]/cart/loading.tsx +26 -0
  79. package/templates/storefront-nextjs-shadcn/app/{cart → [locale]/cart}/page.tsx +20 -13
  80. package/templates/storefront-nextjs-shadcn/app/[locale]/categories/[slug]/category-products-client.tsx +58 -0
  81. package/templates/storefront-nextjs-shadcn/app/[locale]/categories/[slug]/loading.tsx +32 -0
  82. package/templates/storefront-nextjs-shadcn/app/[locale]/categories/[slug]/page.tsx +95 -0
  83. package/templates/storefront-nextjs-shadcn/app/{categories → [locale]/categories}/page.tsx +21 -12
  84. package/templates/storefront-nextjs-shadcn/app/[locale]/checkout/error.tsx +43 -0
  85. package/templates/storefront-nextjs-shadcn/app/[locale]/checkout/loading.tsx +31 -0
  86. package/templates/storefront-nextjs-shadcn/app/{checkout → [locale]/checkout}/page.tsx +334 -253
  87. package/templates/storefront-nextjs-shadcn/app/{checkout → [locale]/checkout}/success/[orderId]/page.tsx +36 -34
  88. package/templates/storefront-nextjs-shadcn/app/[locale]/collections/[handle]/loading.tsx +19 -0
  89. package/templates/storefront-nextjs-shadcn/app/{collections → [locale]/collections}/[handle]/page.tsx +6 -4
  90. package/templates/storefront-nextjs-shadcn/app/[locale]/collections/loading.tsx +18 -0
  91. package/templates/storefront-nextjs-shadcn/app/{collections → [locale]/collections}/page.tsx +20 -12
  92. package/templates/storefront-nextjs-shadcn/app/{contact → [locale]/contact}/page.tsx +24 -21
  93. package/templates/storefront-nextjs-shadcn/app/{error.tsx → [locale]/error.tsx} +13 -8
  94. package/templates/storefront-nextjs-shadcn/app/[locale]/layout.tsx +92 -0
  95. package/templates/storefront-nextjs-shadcn/app/{not-found.tsx → [locale]/not-found.tsx} +13 -18
  96. package/templates/storefront-nextjs-shadcn/app/{page.tsx → [locale]/page.tsx} +8 -4
  97. package/templates/storefront-nextjs-shadcn/app/[locale]/products/[slug]/error.tsx +43 -0
  98. package/templates/storefront-nextjs-shadcn/app/[locale]/products/[slug]/loading.tsx +29 -0
  99. package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/[slug]/page.tsx +17 -14
  100. package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/[slug]/product-client.tsx +18 -62
  101. package/templates/storefront-nextjs-shadcn/app/[locale]/products/loading.tsx +32 -0
  102. package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/page.tsx +6 -3
  103. package/templates/storefront-nextjs-shadcn/app/[locale]/products/products-client.tsx +450 -0
  104. package/templates/storefront-nextjs-shadcn/app/[locale]/search/loading.tsx +18 -0
  105. package/templates/storefront-nextjs-shadcn/app/{wishlist → [locale]/wishlist}/page.tsx +27 -28
  106. package/templates/storefront-nextjs-shadcn/app/api/auth/clear-token/route.ts +2 -86
  107. package/templates/storefront-nextjs-shadcn/app/api/auth/set-token/route.ts +2 -124
  108. package/templates/storefront-nextjs-shadcn/app/global-error.tsx +117 -0
  109. package/templates/storefront-nextjs-shadcn/app/globals.css +8 -0
  110. package/templates/storefront-nextjs-shadcn/app/layout.tsx +8 -35
  111. package/templates/storefront-nextjs-shadcn/codegen.ts +48 -31
  112. package/templates/storefront-nextjs-shadcn/components/account/address-form.tsx +25 -20
  113. package/templates/storefront-nextjs-shadcn/components/account/address-list.tsx +11 -10
  114. package/templates/storefront-nextjs-shadcn/components/account/customer-info.fragment.graphql +36 -0
  115. package/templates/storefront-nextjs-shadcn/components/account/order-details.tsx +17 -13
  116. package/templates/storefront-nextjs-shadcn/components/account/order-history.tsx +42 -30
  117. package/templates/storefront-nextjs-shadcn/components/account/order-summary.fragment.graphql +36 -0
  118. package/templates/storefront-nextjs-shadcn/components/auth/account-menu.tsx +18 -16
  119. package/templates/storefront-nextjs-shadcn/components/auth/login-form.tsx +37 -58
  120. package/templates/storefront-nextjs-shadcn/components/auth/register-form.tsx +85 -66
  121. package/templates/storefront-nextjs-shadcn/components/blog/blog-card.tsx +1 -1
  122. package/templates/storefront-nextjs-shadcn/components/blog/blog-sidebar.tsx +1 -1
  123. package/templates/storefront-nextjs-shadcn/components/brand/brand-card.tsx +1 -1
  124. package/templates/storefront-nextjs-shadcn/components/cart/cart-drawer.tsx +10 -6
  125. package/templates/storefront-nextjs-shadcn/components/cart/cart-icon.tsx +9 -6
  126. package/templates/storefront-nextjs-shadcn/components/cart/cart-item.tsx +8 -6
  127. package/templates/storefront-nextjs-shadcn/components/cart/cart-line.fragment.graphql +53 -0
  128. package/templates/storefront-nextjs-shadcn/components/cart/cart-summary.tsx +10 -8
  129. package/templates/storefront-nextjs-shadcn/components/cart/promo-code-input.tsx +8 -5
  130. package/templates/storefront-nextjs-shadcn/components/cart/shipping-estimator.tsx +38 -20
  131. package/templates/storefront-nextjs-shadcn/components/checkout/payment-method-card.tsx +15 -25
  132. package/templates/storefront-nextjs-shadcn/components/checkout/payment-step.tsx +10 -8
  133. package/templates/storefront-nextjs-shadcn/components/checkout/tax-breakdown.tsx +9 -6
  134. package/templates/storefront-nextjs-shadcn/components/commerce/currency-selector.tsx +7 -5
  135. package/templates/storefront-nextjs-shadcn/components/commerce/pagination.tsx +8 -5
  136. package/templates/storefront-nextjs-shadcn/components/commerce/product-actions.tsx +6 -4
  137. package/templates/storefront-nextjs-shadcn/components/commerce/search-input.tsx +10 -9
  138. package/templates/storefront-nextjs-shadcn/components/common/category-card.tsx +1 -1
  139. package/templates/storefront-nextjs-shadcn/components/common/collection-card.tsx +1 -1
  140. package/templates/storefront-nextjs-shadcn/components/common/price-display.tsx +35 -11
  141. package/templates/storefront-nextjs-shadcn/components/common/social-share.tsx +9 -6
  142. package/templates/storefront-nextjs-shadcn/components/discount/discount-breakdown.tsx +22 -12
  143. package/templates/storefront-nextjs-shadcn/components/discount/discount-code-input.tsx +18 -15
  144. package/templates/storefront-nextjs-shadcn/components/error/error-boundary.tsx +53 -28
  145. package/templates/storefront-nextjs-shadcn/components/filters/dynamic-attribute-filters.tsx +7 -5
  146. package/templates/storefront-nextjs-shadcn/components/filters/range-slider-filter.tsx +5 -5
  147. package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-balance.tsx +19 -15
  148. package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-input.tsx +13 -10
  149. package/templates/storefront-nextjs-shadcn/components/home/category-grid.tsx +10 -6
  150. package/templates/storefront-nextjs-shadcn/components/home/collection-card.fragment.graphql +21 -0
  151. package/templates/storefront-nextjs-shadcn/components/home/featured-collections.tsx +3 -13
  152. package/templates/storefront-nextjs-shadcn/components/home/featured-products.tsx +12 -8
  153. package/templates/storefront-nextjs-shadcn/components/home/hero-section.tsx +13 -8
  154. package/templates/storefront-nextjs-shadcn/components/home/index.ts +0 -1
  155. package/templates/storefront-nextjs-shadcn/components/home/newsletter-signup.tsx +10 -8
  156. package/templates/storefront-nextjs-shadcn/components/hydrated.tsx +24 -0
  157. package/templates/storefront-nextjs-shadcn/components/layout/breadcrumbs.tsx +41 -16
  158. package/templates/storefront-nextjs-shadcn/components/layout/category-node.fragment.graphql +22 -0
  159. package/templates/storefront-nextjs-shadcn/components/layout/currency-selector.tsx +7 -4
  160. package/templates/storefront-nextjs-shadcn/components/layout/footer.tsx +24 -23
  161. package/templates/storefront-nextjs-shadcn/components/layout/header.tsx +52 -34
  162. package/templates/storefront-nextjs-shadcn/components/layout/language-switcher.tsx +54 -0
  163. package/templates/storefront-nextjs-shadcn/components/layout/mobile-menu.tsx +33 -30
  164. package/templates/storefront-nextjs-shadcn/components/layout/navigation.tsx +27 -24
  165. package/templates/storefront-nextjs-shadcn/components/loyalty/points-balance.tsx +2 -11
  166. package/templates/storefront-nextjs-shadcn/components/loyalty/points-history.tsx +8 -25
  167. package/templates/storefront-nextjs-shadcn/components/loyalty/referral-section.tsx +32 -42
  168. package/templates/storefront-nextjs-shadcn/components/loyalty/rewards-catalog.tsx +17 -41
  169. package/templates/storefront-nextjs-shadcn/components/loyalty/tier-progress.tsx +2 -29
  170. package/templates/storefront-nextjs-shadcn/components/order/index.ts +6 -1
  171. package/templates/storefront-nextjs-shadcn/components/product/add-to-cart-button.tsx +6 -14
  172. package/templates/storefront-nextjs-shadcn/components/product/b2b-price-display.tsx +4 -2
  173. package/templates/storefront-nextjs-shadcn/components/product/filter-active-pills.tsx +72 -0
  174. package/templates/storefront-nextjs-shadcn/components/product/filter-mobile-sheet.tsx +87 -0
  175. package/templates/storefront-nextjs-shadcn/components/product/filter-price-range.tsx +140 -0
  176. package/templates/storefront-nextjs-shadcn/components/product/index.ts +9 -2
  177. package/templates/storefront-nextjs-shadcn/components/product/product-card.fragment.graphql +49 -0
  178. package/templates/storefront-nextjs-shadcn/components/product/product-card.tsx +11 -37
  179. package/templates/storefront-nextjs-shadcn/components/product/product-detail.fragment.graphql +52 -0
  180. package/templates/storefront-nextjs-shadcn/components/product/product-filters.tsx +179 -124
  181. package/templates/storefront-nextjs-shadcn/components/product/product-grid.tsx +3 -5
  182. package/templates/storefront-nextjs-shadcn/components/product/product-image.tsx +3 -7
  183. package/templates/storefront-nextjs-shadcn/components/product/product-price.tsx +2 -2
  184. package/templates/storefront-nextjs-shadcn/components/product/product-reviews.tsx +5 -4
  185. package/templates/storefront-nextjs-shadcn/components/product/product-sort.tsx +44 -19
  186. package/templates/storefront-nextjs-shadcn/components/product/product-variant-selector.tsx +8 -23
  187. package/templates/storefront-nextjs-shadcn/components/product/product-variant.fragment.graphql +51 -0
  188. package/templates/storefront-nextjs-shadcn/components/product/review-card.tsx +1 -1
  189. package/templates/storefront-nextjs-shadcn/components/product/review-form.tsx +26 -34
  190. package/templates/storefront-nextjs-shadcn/components/product/savings-display.tsx +17 -2
  191. package/templates/storefront-nextjs-shadcn/components/product/similar-products.tsx +3 -2
  192. package/templates/storefront-nextjs-shadcn/components/providers/index.ts +1 -1
  193. package/templates/storefront-nextjs-shadcn/components/providers/language-sync-provider.tsx +27 -0
  194. package/templates/storefront-nextjs-shadcn/components/providers/stores-provider.tsx +63 -0
  195. package/templates/storefront-nextjs-shadcn/components/providers/theme-provider.tsx +1 -1
  196. package/templates/storefront-nextjs-shadcn/components/returns/index.ts +2 -2
  197. package/templates/storefront-nextjs-shadcn/components/returns/return-request-form.tsx +59 -72
  198. package/templates/storefront-nextjs-shadcn/components/search/search-bar.tsx +7 -4
  199. package/templates/storefront-nextjs-shadcn/components/search/search-results.tsx +3 -2
  200. package/templates/storefront-nextjs-shadcn/components/shipping/shipping-method-selector.tsx +12 -9
  201. package/templates/storefront-nextjs-shadcn/components/ui/empty-state.tsx +23 -12
  202. package/templates/storefront-nextjs-shadcn/components/ui/form.tsx +174 -0
  203. package/templates/storefront-nextjs-shadcn/components/ui/index.ts +30 -2
  204. package/templates/storefront-nextjs-shadcn/components/ui/progress.tsx +40 -0
  205. package/templates/storefront-nextjs-shadcn/components/ui/sheet.tsx +107 -0
  206. package/templates/storefront-nextjs-shadcn/components/ui/slider.tsx +33 -0
  207. package/templates/storefront-nextjs-shadcn/components/ui/textarea.tsx +24 -0
  208. package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-button.tsx +7 -4
  209. package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-icon.tsx +4 -2
  210. package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-item.tsx +2 -10
  211. package/templates/storefront-nextjs-shadcn/generated/graphql.ts +13387 -0
  212. package/templates/storefront-nextjs-shadcn/graphql/custom.example.graphql +159 -0
  213. package/templates/storefront-nextjs-shadcn/hooks/index.ts +3 -0
  214. package/templates/storefront-nextjs-shadcn/hooks/use-auth-sync.ts +42 -0
  215. package/templates/storefront-nextjs-shadcn/hooks/use-auth.ts +17 -295
  216. package/templates/storefront-nextjs-shadcn/hooks/use-cart-actions.ts +34 -229
  217. package/templates/storefront-nextjs-shadcn/hooks/use-cart-di.ts +67 -0
  218. package/templates/storefront-nextjs-shadcn/hooks/use-cart-sync.ts +16 -12
  219. package/templates/storefront-nextjs-shadcn/i18n/navigation.ts +12 -0
  220. package/templates/storefront-nextjs-shadcn/i18n/request.ts +17 -0
  221. package/templates/storefront-nextjs-shadcn/i18n/routing.ts +17 -0
  222. package/templates/storefront-nextjs-shadcn/lib/auth/routes.ts +4 -17
  223. package/templates/storefront-nextjs-shadcn/lib/graphql/client.ts +22 -99
  224. package/templates/storefront-nextjs-shadcn/lib/graphql/config.ts +33 -0
  225. package/templates/storefront-nextjs-shadcn/lib/graphql/fragments.ts +34 -0
  226. package/templates/storefront-nextjs-shadcn/lib/graphql/hooks.ts +720 -632
  227. package/templates/storefront-nextjs-shadcn/lib/graphql/query-keys.ts +88 -0
  228. package/templates/storefront-nextjs-shadcn/lib/graphql/server.ts +132 -182
  229. package/templates/storefront-nextjs-shadcn/lib/graphql/types.ts +62 -0
  230. package/templates/storefront-nextjs-shadcn/lib/theme/theme-config.ts +0 -17
  231. package/templates/storefront-nextjs-shadcn/messages/en.json +869 -0
  232. package/templates/storefront-nextjs-shadcn/messages/pl.json +869 -0
  233. package/templates/storefront-nextjs-shadcn/next-env.d.ts +6 -0
  234. package/templates/storefront-nextjs-shadcn/next.config.ts +6 -5
  235. package/templates/storefront-nextjs-shadcn/package.dev.json +1 -3
  236. package/templates/storefront-nextjs-shadcn/package.json +14 -14
  237. package/templates/storefront-nextjs-shadcn/package.json.template +6 -7
  238. package/templates/storefront-nextjs-shadcn/proxy.ts +115 -47
  239. package/templates/storefront-nextjs-shadcn/stores/cart-store.ts +24 -56
  240. package/templates/storefront-nextjs-shadcn/stores/checkout-store.ts +64 -75
  241. package/templates/storefront-nextjs-shadcn/stores/wishlist-store.ts +178 -177
  242. package/templates/storefront-nextjs-shadcn/tsconfig.json +23 -5
  243. package/templates/storefront-nextjs-shadcn/wrangler.toml +11 -0
  244. package/templates/storefront-nextjs-shadcn/CART_INTEGRATION.md +0 -282
  245. package/templates/storefront-nextjs-shadcn/GRAPHQL_DOCUMENT_NAMES.md +0 -190
  246. package/templates/storefront-nextjs-shadcn/GRAPHQL_ERROR_HANDLING.md +0 -263
  247. package/templates/storefront-nextjs-shadcn/GRAPHQL_FIXES_SUMMARY.md +0 -135
  248. package/templates/storefront-nextjs-shadcn/GRAPHQL_INTEGRATION_COMPLETE.md +0 -142
  249. package/templates/storefront-nextjs-shadcn/INTEGRATION_CHECKLIST.md +0 -448
  250. package/templates/storefront-nextjs-shadcn/PRODUCT_DETAIL_PAGE_IMPLEMENTATION.md +0 -307
  251. package/templates/storefront-nextjs-shadcn/THEME_CUSTOMIZATION.md +0 -245
  252. package/templates/storefront-nextjs-shadcn/app/account/addresses/page.tsx +0 -215
  253. package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/page.tsx +0 -128
  254. package/templates/storefront-nextjs-shadcn/app/account/orders/page.tsx +0 -80
  255. package/templates/storefront-nextjs-shadcn/app/account/settings/page.tsx +0 -171
  256. package/templates/storefront-nextjs-shadcn/app/categories/[slug]/page.tsx +0 -78
  257. package/templates/storefront-nextjs-shadcn/app/products/products-client.tsx +0 -192
  258. package/templates/storefront-nextjs-shadcn/components/providers/currency-provider.tsx +0 -103
  259. package/templates/storefront-nextjs-shadcn/graphql/collections.example.ts +0 -168
  260. package/templates/storefront-nextjs-shadcn/graphql/products.example.ts +0 -160
  261. package/templates/storefront-nextjs-shadcn/lib/auth/cookies.ts +0 -220
  262. package/templates/storefront-nextjs-shadcn/lib/config.ts +0 -46
  263. package/templates/storefront-nextjs-shadcn/lib/currency/IMPLEMENTATION_SUMMARY.md +0 -254
  264. package/templates/storefront-nextjs-shadcn/lib/currency/README.md +0 -464
  265. package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.test.ts +0 -328
  266. package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.ts +0 -295
  267. package/templates/storefront-nextjs-shadcn/lib/currency/index.ts +0 -27
  268. package/templates/storefront-nextjs-shadcn/lib/format.ts +0 -226
  269. package/templates/storefront-nextjs-shadcn/lib/hooks.ts +0 -30
  270. package/templates/storefront-nextjs-shadcn/stores/auth-store.ts +0 -66
  271. package/templates/storefront-nextjs-shadcn/stores/currency-store.ts +0 -103
  272. /package/templates/storefront-nextjs-shadcn/app/{blog → [locale]/blog}/page.tsx +0 -0
  273. /package/templates/storefront-nextjs-shadcn/app/{brands → [locale]/brands}/[slug]/page.tsx +0 -0
  274. /package/templates/storefront-nextjs-shadcn/app/{returns → [locale]/returns}/page.tsx +0 -0
  275. /package/templates/storefront-nextjs-shadcn/app/{search → [locale]/search}/page.tsx +0 -0
  276. /package/templates/storefront-nextjs-shadcn/app/{search → [locale]/search}/search-client.tsx +0 -0
  277. /package/templates/storefront-nextjs-shadcn/app/{shipping → [locale]/shipping}/page.tsx +0 -0
@@ -1,241 +1,54 @@
1
1
  'use client';
2
2
 
3
- import { useCallback, useRef } from 'react';
4
- import { useCartStore } from '@/stores/cart-store';
5
- import { useCartCreate, useCartLinesAdd, useCartLinesUpdate, useCartLinesRemove } from '@/lib/graphql/hooks';
6
- import { toast } from 'sonner';
3
+ import { useCallback, useEffect, useRef } from 'react';
4
+ import { useCartStore, useCartStoreApi } from '@/stores/cart-store';
7
5
 
8
6
  // Debounce delay for quantity updates (prevents rate limiting)
9
7
  const QUANTITY_UPDATE_DEBOUNCE_MS = 500;
10
8
 
11
9
  /**
12
- * Hook for cart mutations — server-only, no local state manipulation.
10
+ * Hook for cart mutations — delegates orchestration to SDK cart store.
13
11
  *
14
- * All mutations go through GraphQL. React Query cache invalidation
15
- * (configured in hooks.ts) automatically updates all consumers via useCartSync.
12
+ * SDK handles: cart init, DI actions, error state, callbacks.
13
+ * Template handles: debounce, openCart UX.
16
14
  *
17
15
  * @example
18
16
  * ```typescript
19
17
  * const { addToCart, updateQuantity, removeFromCart } = useCartActions();
20
- *
21
- * await addToCart({
22
- * variantId: 'variant-123',
23
- * productId: 'product-456',
24
- * productTitle: 'T-Shirt',
25
- * variantTitle: 'Large / Blue',
26
- * price: { amount: '29.99', currencyCode: 'USD' },
27
- * quantity: 1
28
- * });
29
- *
30
- * // updateQuantity and removeFromCart take lineId (not variantId)
31
- * updateQuantity('line-abc', 3);
32
- * removeFromCart('line-abc');
18
+ * await addToCart('variant-123', 1);
33
19
  * ```
34
20
  */
35
21
  export function useCartActions() {
36
- const {
37
- setCartId,
38
- clearCart,
39
- openCart,
40
- } = useCartStore();
22
+ const api = useCartStoreApi();
23
+ const isLoading = useCartStore((s) => s.isLoading);
41
24
 
42
- // GraphQL mutations
43
- const createCartMutation = useCartCreate();
44
- const addLinesMutation = useCartLinesAdd();
45
- const updateLinesMutation = useCartLinesUpdate();
46
- const removeLinesMutation = useCartLinesRemove();
47
-
48
- // Debounce refs for quantity updates (prevents ThrottlerException on rapid clicks)
25
+ // Debounce refs for quantity updates
49
26
  const updateTimeoutRef = useRef<Map<string, NodeJS.Timeout>>(new Map());
50
- const pendingUpdatesRef = useRef<Map<string, { lineId: string; quantity: number }>>(new Map());
51
-
52
- /**
53
- * Get or create cart ID.
54
- * Reads cartId from store (fresh, not stale closure) or creates a new cart.
55
- */
56
- const getOrCreateCartId = useCallback(async (forceNew: boolean = false): Promise<string> => {
57
- const currentCartId = useCartStore.getState().cartId;
58
- if (currentCartId && !forceNew) {
59
- return currentCartId;
60
- }
61
-
62
- try {
63
- const result = await createCartMutation.mutateAsync({ input: {} });
64
-
65
- if (result.cartCreate.cart) {
66
- const newCartId = result.cartCreate.cart.id;
67
- setCartId(newCartId);
68
- return newCartId;
69
- }
70
-
71
- if (result.cartCreate.userErrors?.length > 0) {
72
- throw new Error(result.cartCreate.userErrors[0].message);
73
- }
74
-
75
- throw new Error('Failed to create cart');
76
- } catch (error: any) {
77
- console.error('Cart creation failed:', error);
78
- throw error;
79
- }
80
- }, [setCartId, createCartMutation]);
81
27
 
82
28
  /**
83
- * Check if error is a "Cart not found" error (stale/expired cart)
29
+ * Add item to cart by variant ID, delegates to SDK store.
84
30
  */
85
- const isCartNotFoundError = (error: any): boolean => {
86
- const message = error?.message || '';
87
- return message.toLowerCase().includes('cart not found') ||
88
- message.toLowerCase().includes('cart does not exist');
89
- };
90
-
91
- /**
92
- * Add item to cart (server-only).
93
- *
94
- * Creates cart if needed. On "cart not found", clears cartId, creates new cart, retries once.
95
- * React Query cache invalidation in hooks.ts updates all useCartSync consumers.
96
- */
97
- const addToCart = useCallback(async (item: {
98
- variantId: string;
99
- productId: string;
100
- productHandle?: string;
101
- productTitle: string;
102
- variantTitle: string;
103
- price: { amount: string; currencyCode: string };
104
- image?: { url: string; altText?: string | null } | null;
105
- available?: boolean;
106
- quantity?: number;
107
- }, _options?: { _forceNewCart?: boolean }) => {
108
- const forceNewCart = _options?._forceNewCart ?? false;
109
-
110
- try {
111
- const cartId = await getOrCreateCartId(forceNewCart);
112
-
113
- const result = await addLinesMutation.mutateAsync({
114
- cartId,
115
- lines: [{
116
- merchandiseId: item.variantId,
117
- quantity: item.quantity ?? 1,
118
- }],
119
- });
120
-
121
- if (result.cartLinesAdd.userErrors?.length > 0) {
122
- const errorMessage = result.cartLinesAdd.userErrors[0].message;
123
-
124
- if (isCartNotFoundError({ message: errorMessage }) && !forceNewCart) {
125
- console.warn('Cart expired, creating new cart and retrying...');
126
- setCartId(null);
127
- return addToCart(item, { _forceNewCart: true });
128
- }
129
-
130
- throw new Error(errorMessage);
131
- }
132
-
133
- // Open cart drawer to show the added item
134
- openCart();
135
- toast.success('Added to cart');
136
- } catch (error: any) {
137
- if (isCartNotFoundError(error) && !forceNewCart) {
138
- console.warn('Cart expired (caught), creating new cart and retrying...');
139
- setCartId(null);
140
- return addToCart(item, { _forceNewCart: true });
141
- }
142
-
143
- console.error('Add to cart failed:', error);
144
- toast.error(error.message || 'Failed to add to cart');
145
- throw error;
146
- }
147
- }, [setCartId, openCart, getOrCreateCartId, addLinesMutation]);
31
+ const addToCart = useCallback(async (variantId: string, quantity = 1) => {
32
+ await api.getState().addToCart([{ merchandiseId: variantId, quantity }]);
33
+ api.getState().openCart();
34
+ }, [api]);
148
35
 
149
36
  /**
150
- * Execute the actual GraphQL update for a pending quantity change
37
+ * Execute the actual quantity update via SDK store.
151
38
  */
152
39
  const executeQuantityUpdate = useCallback(async (lineId: string, quantity: number) => {
153
- try {
154
- const currentCartId = useCartStore.getState().cartId;
155
- if (!currentCartId) {
156
- throw new Error('No cart found');
157
- }
158
-
159
- const result = await updateLinesMutation.mutateAsync({
160
- cartId: currentCartId,
161
- lines: [{
162
- id: lineId,
163
- quantity,
164
- }],
165
- });
166
-
167
- if (result.cartLinesUpdate.userErrors?.length > 0) {
168
- const errorMessage = result.cartLinesUpdate.userErrors[0].message;
169
-
170
- if (isCartNotFoundError({ message: errorMessage })) {
171
- console.warn('Cart expired during update, clearing cart');
172
- clearCart();
173
- toast.error('Your cart has expired. Please add items again.');
174
- return;
175
- }
176
-
177
- throw new Error(errorMessage);
178
- }
179
- } catch (error: any) {
180
- if (isCartNotFoundError(error)) {
181
- console.warn('Cart expired during update (caught), clearing cart');
182
- clearCart();
183
- toast.error('Your cart has expired. Please add items again.');
184
- return;
185
- }
186
-
187
- console.error('Update quantity failed:', error);
188
- toast.error(error.message || 'Failed to update quantity');
189
- }
190
- }, [updateLinesMutation, clearCart]);
40
+ await api.getState().updateQuantity([{ id: lineId, quantity }]);
41
+ }, [api]);
191
42
 
192
43
  /**
193
44
  * Remove item from cart by line ID.
194
- *
195
- * Silently handles expired cart (just clears stale cartId).
196
45
  */
197
46
  const removeFromCart = useCallback(async (lineId: string) => {
198
- try {
199
- const currentCartId = useCartStore.getState().cartId;
200
- if (!currentCartId) {
201
- return;
202
- }
203
-
204
- const result = await removeLinesMutation.mutateAsync({
205
- cartId: currentCartId,
206
- lineIds: [lineId],
207
- });
208
-
209
- if (result.cartLinesRemove.userErrors?.length > 0) {
210
- const errorMessage = result.cartLinesRemove.userErrors[0].message;
211
-
212
- if (isCartNotFoundError({ message: errorMessage })) {
213
- console.warn('Cart expired during remove, clearing stale cartId');
214
- setCartId(null);
215
- return;
216
- }
217
-
218
- throw new Error(errorMessage);
219
- }
220
-
221
- toast.success('Removed from cart');
222
- } catch (error: any) {
223
- if (isCartNotFoundError(error)) {
224
- console.warn('Cart expired during remove (caught), clearing stale cartId');
225
- setCartId(null);
226
- return;
227
- }
228
-
229
- console.error('Remove from cart failed:', error);
230
- toast.error(error.message || 'Failed to remove from cart');
231
- throw error;
232
- }
233
- }, [setCartId, removeLinesMutation]);
47
+ await api.getState().removeFromCart([lineId]);
48
+ }, [api]);
234
49
 
235
50
  /**
236
- * Update item quantity (debounced, takes lineId).
237
- *
238
- * Debounces GraphQL API calls to prevent ThrottlerException on rapid clicks.
51
+ * Update item quantity (debounced).
239
52
  * If quantity <= 0, removes the item instead.
240
53
  */
241
54
  const updateQuantity = useCallback((lineId: string, quantity: number) => {
@@ -244,43 +57,35 @@ export function useCartActions() {
244
57
  return;
245
58
  }
246
59
 
247
- // Cancel any pending update for this line
248
60
  const existingTimeout = updateTimeoutRef.current.get(lineId);
249
61
  if (existingTimeout) {
250
62
  clearTimeout(existingTimeout);
251
63
  }
252
64
 
253
- // Store the pending update
254
- pendingUpdatesRef.current.set(lineId, { lineId, quantity });
255
-
256
- // Schedule debounced API call
257
65
  const timeout = setTimeout(() => {
258
- const pending = pendingUpdatesRef.current.get(lineId);
259
- if (pending) {
260
- pendingUpdatesRef.current.delete(lineId);
261
- updateTimeoutRef.current.delete(lineId);
262
- executeQuantityUpdate(pending.lineId, pending.quantity);
263
- }
66
+ updateTimeoutRef.current.delete(lineId);
67
+ executeQuantityUpdate(lineId, quantity);
264
68
  }, QUANTITY_UPDATE_DEBOUNCE_MS);
265
69
 
266
70
  updateTimeoutRef.current.set(lineId, timeout);
267
71
  }, [removeFromCart, executeQuantityUpdate]);
268
72
 
269
- /**
270
- * Clear entire cart.
271
- * Clears cartId in zustand persist → useCartSync returns empty.
272
- */
273
- const clearEntireCart = useCallback(() => {
274
- clearCart();
275
- toast.success('Cart cleared');
276
- }, [clearCart]);
73
+ // Cleanup pending debounce timeouts on unmount
74
+ useEffect(() => {
75
+ const timeouts = updateTimeoutRef.current;
76
+ return () => {
77
+ for (const timeout of timeouts.values()) {
78
+ clearTimeout(timeout);
79
+ }
80
+ timeouts.clear();
81
+ };
82
+ }, []);
277
83
 
278
84
  return {
279
85
  addToCart,
280
86
  updateQuantity,
281
87
  removeFromCart,
282
- clearCart: clearEntireCart,
283
- isLoading: createCartMutation.isPending || addLinesMutation.isPending ||
284
- updateLinesMutation.isPending || removeLinesMutation.isPending,
88
+ clearCart: useCallback(() => api.getState().clearCart(), [api]),
89
+ isLoading,
285
90
  };
286
91
  }
@@ -0,0 +1,67 @@
1
+ 'use client';
2
+
3
+ import { useMemo } from 'react';
4
+ import type { CartActions, CartData } from '@doswiftly/storefront-sdk/react';
5
+ import { assertNoUserErrors } from '@doswiftly/storefront-sdk';
6
+ import { useExecute } from '@/lib/graphql/client';
7
+ import type { CartQuery, CartCreateMutation, CartLinesAddMutation, CartLinesUpdateMutation, CartLinesRemoveMutation } from '@/generated/graphql';
8
+ import {
9
+ CartDocument,
10
+ CartCreateDocument,
11
+ CartLinesAddDocument,
12
+ CartLinesUpdateDocument,
13
+ CartLinesRemoveDocument,
14
+ } from '@/generated/graphql';
15
+
16
+ interface CartMutationResult {
17
+ cart: { id: string; totalQuantity: number } | null;
18
+ userErrors: Array<{ message: string; field?: string[]; code?: string }>;
19
+ }
20
+
21
+ function extractCartData(result: CartMutationResult): CartData {
22
+ assertNoUserErrors(result);
23
+ return { id: result.cart!.id, totalQuantity: result.cart!.totalQuantity };
24
+ }
25
+
26
+ /**
27
+ * CartActions DI implementation using template's GraphQL operations.
28
+ *
29
+ * Maps generated GraphQL documents to the SDK CartActions interface.
30
+ * Used by StoresProvider to wire createCartStore with template transport.
31
+ */
32
+ export function useCartDI(): CartActions {
33
+ const execute = useExecute();
34
+
35
+ return useMemo(
36
+ (): CartActions => ({
37
+ fetchCart: async (cartId) => {
38
+ const data = await execute<CartQuery>(CartDocument.toString(), { id: cartId });
39
+ if (!data.cart) return null;
40
+ return { id: data.cart.id, totalQuantity: data.cart.totalQuantity };
41
+ },
42
+
43
+ createCart: async () => {
44
+ const data = await execute<CartCreateMutation>(CartCreateDocument.toString(), { input: {} });
45
+ assertNoUserErrors(data.cartCreate);
46
+ if (!data.cartCreate.cart) throw new Error('Failed to create cart');
47
+ return data.cartCreate.cart.id;
48
+ },
49
+
50
+ addLines: async (cartId, lines) => {
51
+ const data = await execute<CartLinesAddMutation>(CartLinesAddDocument.toString(), { cartId, lines });
52
+ return extractCartData(data.cartLinesAdd);
53
+ },
54
+
55
+ updateLines: async (cartId, lines) => {
56
+ const data = await execute<CartLinesUpdateMutation>(CartLinesUpdateDocument.toString(), { cartId, lines });
57
+ return extractCartData(data.cartLinesUpdate);
58
+ },
59
+
60
+ removeLines: async (cartId, lineIds) => {
61
+ const data = await execute<CartLinesRemoveMutation>(CartLinesRemoveDocument.toString(), { cartId, lineIds });
62
+ return extractCartData(data.cartLinesRemove);
63
+ },
64
+ }),
65
+ [execute],
66
+ );
67
+ }
@@ -3,6 +3,8 @@
3
3
  import { useEffect } from "react";
4
4
  import { useCart } from "@/lib/graphql/hooks";
5
5
  import { useCartStore } from "@/stores/cart-store";
6
+ import { useHydrated } from "@doswiftly/storefront-sdk/react";
7
+ import type { CartLineFields } from "@/lib/graphql/fragments";
6
8
 
7
9
  /**
8
10
  * Mapped cart item for display components.
@@ -31,28 +33,30 @@ export interface CartItemData {
31
33
  */
32
34
  export function useCartSync() {
33
35
  const cartId = useCartStore((state) => state.cartId);
34
- const isHydrated = useCartStore((state) => state.isHydrated);
35
- const setCartId = useCartStore((state) => state.setCartId);
36
+ const clearCart = useCartStore((state) => state.clearCart);
37
+ const isHydrated = useHydrated();
36
38
 
37
- const { data, isLoading, error, refetch } = useCart(cartId, {
39
+ const { data, isLoading, isSuccess, error, refetch } = useCart(cartId, {
38
40
  enabled: isHydrated && Boolean(cartId),
39
41
  retry: false,
40
42
  });
41
43
 
42
44
  const cart = data?.cart;
43
45
 
44
- // Detect stale cart: cartId exists but server returns nothing
45
- const isStaleCart = isHydrated && Boolean(cartId) && !isLoading && !cart;
46
+ // Detect stale cart: cartId exists but server confirmed no cart (isSuccess + !cart).
47
+ // Using isSuccess instead of !isLoading prevents false positives when queries are
48
+ // cancelled by mutation optimistic updates (cancelled query → status='pending', not 'success').
49
+ const isStaleCart = isHydrated && Boolean(cartId) && isSuccess && !cart;
46
50
 
47
51
  // Auto-clear stale cartId
48
52
  useEffect(() => {
49
53
  if (isStaleCart) {
50
- setCartId(null);
54
+ clearCart();
51
55
  }
52
- }, [isStaleCart, setCartId]);
56
+ }, [isStaleCart, clearCart]);
53
57
 
54
58
  // Map GraphQL lines to display-friendly items
55
- const items: CartItemData[] = (cart?.lines ?? []).map((line: any) => {
59
+ const items: CartItemData[] = (cart?.lines ?? []).map((line: CartLineFields) => {
56
60
  const merchandiseTitle = line.merchandise.title ?? "";
57
61
  // Hide generic variant names like "Default" or "Default Title"
58
62
  const isDefaultVariant = /^default(\s+title)?$/i.test(merchandiseTitle);
@@ -63,10 +67,10 @@ export function useCartSync() {
63
67
  lineId: line.id,
64
68
  variantId: line.merchandise.id,
65
69
  productId: line.productId || line.merchandise.id,
66
- productHandle: line.productHandle,
70
+ productHandle: line.productHandle ?? undefined,
67
71
  productTitle,
68
72
  variantTitle,
69
- productType: line.productType,
73
+ productType: line.productType ?? undefined,
70
74
  quantity: line.quantity,
71
75
  price: {
72
76
  amount: line.merchandise.price.amount,
@@ -88,8 +92,8 @@ export function useCartSync() {
88
92
 
89
93
  // Discount data from server
90
94
  const discountCodes: string[] = (cart?.discountCodes ?? [])
91
- .filter((dc: any) => dc.applicable)
92
- .map((dc: any) => dc.code);
95
+ .filter((dc) => dc.applicable)
96
+ .map((dc) => dc.code);
93
97
  const totalDiscount = subtotal - total;
94
98
 
95
99
  return {
@@ -0,0 +1,12 @@
1
+ import { createNavigation } from 'next-intl/navigation';
2
+ import { defaultLocale, localePrefix } from './routing';
3
+
4
+ /**
5
+ * Navigation APIs for dynamic locales.
6
+ *
7
+ * No `locales` argument — any locale string accepted at runtime.
8
+ * Backend is SSOT for supportedLanguages.
9
+ * `defaultLocale` required for `as-needed` prefix mode (hides default in URL).
10
+ */
11
+ export const { Link, redirect, usePathname, useRouter, getPathname } =
12
+ createNavigation({ defaultLocale, localePrefix });
@@ -0,0 +1,17 @@
1
+ import { getRequestConfig } from 'next-intl/server';
2
+ import { defaultLocale } from './routing';
3
+
4
+ export default getRequestConfig(async ({ requestLocale }) => {
5
+ // requestLocale is set by next-intl middleware (proxy.ts) which validates
6
+ // against dynamic locales from backend. If somehow invalid, fall back.
7
+ const locale = (await requestLocale) || defaultLocale;
8
+
9
+ let messages;
10
+ try {
11
+ messages = (await import(`../messages/${locale}.json`)).default;
12
+ } catch {
13
+ messages = (await import(`../messages/${defaultLocale}.json`)).default;
14
+ }
15
+
16
+ return { locale, messages };
17
+ });
@@ -0,0 +1,17 @@
1
+ /**
2
+ * next-intl routing configuration (dynamic locales).
3
+ *
4
+ * - defaultLocale: from NEXT_PUBLIC_DEFAULT_LOCALE env var (set by CLI `doswiftly init`), fallback 'pl'.
5
+ * - localePrefix: 'as-needed' — default locale hidden in URL, others prefixed.
6
+ * - locales: NOT defined here — backend is SSOT for supportedLanguages.
7
+ * - Middleware (proxy.ts) fetches supportedLanguages dynamically per-request.
8
+ * - Navigation API (navigation.ts) accepts any locale string at runtime.
9
+ * - Layout validates against backend's shop.supportedLanguages.
10
+ *
11
+ * No `defineRouting` — we export primitives consumed by createNavigation and createMiddleware.
12
+ */
13
+
14
+ export const defaultLocale =
15
+ (process.env.NEXT_PUBLIC_DEFAULT_LOCALE as string) || 'pl';
16
+
17
+ export const localePrefix = 'as-needed' as const;
@@ -2,7 +2,7 @@
2
2
  * Auth Routes Configuration (SSOT)
3
3
  *
4
4
  * This file is the single source of truth for authentication routes.
5
- * Used by middleware.ts and can be imported by components if needed.
5
+ * Used by proxy.ts and can be imported by components if needed.
6
6
  *
7
7
  * IMPORTANT: Checkout is NOT protected to allow guest checkout (e-commerce best practice).
8
8
  * Users can optionally log in during checkout to use saved addresses.
@@ -16,6 +16,9 @@
16
16
  * export const guestOnlyRoutes = ['/auth/login', '/auth/register', '/auth/forgot-password'];
17
17
  */
18
18
 
19
+ // Re-export platform constants and matching utility from SDK
20
+ export { AUTH_COOKIE_NAME, matchesRoute } from '@doswiftly/storefront-sdk';
21
+
19
22
  /**
20
23
  * Routes that require authentication.
21
24
  * Unauthenticated users will be redirected to login.
@@ -30,12 +33,6 @@ export const protectedRoutes = ["/account"];
30
33
  */
31
34
  export const guestOnlyRoutes = ["/auth/login", "/auth/register"];
32
35
 
33
- /**
34
- * Cookie name for customer access token.
35
- * Must match the cookie name used by commerce-sdk.
36
- */
37
- export const AUTH_COOKIE_NAME = "customerAccessToken";
38
-
39
36
  /**
40
37
  * Default redirect paths
41
38
  */
@@ -45,13 +42,3 @@ export const redirects = {
45
42
  /** Where to redirect authenticated users trying to access guest-only routes */
46
43
  authenticated: "/account",
47
44
  } as const;
48
-
49
- /**
50
- * Check if a pathname matches any route in the list.
51
- * Supports both exact matches and prefix matches (e.g., /account matches /account/orders).
52
- */
53
- export function matchesRoute(pathname: string, routes: string[]): boolean {
54
- return routes.some(
55
- (route) => pathname === route || pathname.startsWith(`${route}/`)
56
- );
57
- }