@revenexx/cover 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 (408) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +39 -0
  3. package/app/api/account.ts +8 -0
  4. package/app/api/categories.ts +3 -0
  5. package/app/api/checkout.ts +6 -0
  6. package/app/api/images.ts +4 -0
  7. package/app/api/markets.ts +3 -0
  8. package/app/api/product.ts +3 -0
  9. package/app/api/products.ts +4 -0
  10. package/app/api/search.ts +4 -0
  11. package/app/app.config.ts +29 -0
  12. package/app/assets/css/cover.css +25 -0
  13. package/app/components/account/AccountMenu.vue +30 -0
  14. package/app/components/account/AccountShell.vue +18 -0
  15. package/app/components/account/AccountSidebar.vue +90 -0
  16. package/app/components/account/address/AccountAddressCard.vue +287 -0
  17. package/app/components/account/carts/AccountCartsTable.vue +284 -0
  18. package/app/components/account/dashboard/AccountDashboard.vue +351 -0
  19. package/app/components/account/directorder/AccountDirectOrder.vue +512 -0
  20. package/app/components/account/governance/AccountApprovalLimitsTable.vue +221 -0
  21. package/app/components/account/governance/AccountCostCenterDetail.vue +276 -0
  22. package/app/components/account/governance/AccountCostCentersTable.vue +252 -0
  23. package/app/components/account/governance/AccountRequisitionDetail.vue +295 -0
  24. package/app/components/account/governance/AccountRequisitionsTable.vue +255 -0
  25. package/app/components/account/governance/AccountWorkflowDetail.vue +215 -0
  26. package/app/components/account/governance/AccountWorkflowsTable.vue +168 -0
  27. package/app/components/account/governance/GovernanceApprovalLimitModal.vue +183 -0
  28. package/app/components/account/governance/GovernanceCostCenterModal.vue +188 -0
  29. package/app/components/account/governance/GovernanceWorkflowModal.vue +191 -0
  30. package/app/components/account/orderlists/AccountOrderListDetail.vue +349 -0
  31. package/app/components/account/orderlists/AccountOrderListsTable.vue +352 -0
  32. package/app/components/account/orders/AccountOrderDetail.vue +376 -0
  33. package/app/components/account/orders/AccountOrdersTable.vue +281 -0
  34. package/app/components/account/preferences/AccountPreferences.vue +50 -0
  35. package/app/components/auth/AuthForgotPasswordPanel.vue +88 -0
  36. package/app/components/auth/AuthLoginPanel.vue +103 -0
  37. package/app/components/auth/AuthLoginTeaser.vue +24 -0
  38. package/app/components/auth/AuthPageHeader.vue +21 -0
  39. package/app/components/auth/AuthRegisterPanel.vue +431 -0
  40. package/app/components/auth/AuthRegisterTeaser.vue +24 -0
  41. package/app/components/auth/AuthResetPasswordPanel.vue +115 -0
  42. package/app/components/cart/CartButton.vue +42 -0
  43. package/app/components/cart/actions/CartCostCenterModal.vue +110 -0
  44. package/app/components/cart/actions/CartExportModal.vue +82 -0
  45. package/app/components/cart/actions/CartPositionTextsModal.vue +92 -0
  46. package/app/components/cart/actions/CartSaveToListModal.vue +177 -0
  47. package/app/components/cart/actions/CartWorkflowPickerModal.vue +64 -0
  48. package/app/components/cart/drawer/CartDrawer.vue +49 -0
  49. package/app/components/cart/item/CartItem.vue +318 -0
  50. package/app/components/cart/manage/CartNameModal.vue +68 -0
  51. package/app/components/cart/position/CartPosition.vue +369 -0
  52. package/app/components/cart/quickadd/CartQuickAdd.vue +145 -0
  53. package/app/components/cart/recommend/CartCrossSell.vue +102 -0
  54. package/app/components/cart/recommend/CartRecommendCard.vue +59 -0
  55. package/app/components/cart/recommend/CartReorderStrip.vue +108 -0
  56. package/app/components/cart/requisition/CartRequisitionGroup.vue +74 -0
  57. package/app/components/cart/skeleton/CartSkeleton.vue +18 -0
  58. package/app/components/cart/summary/CartSummary.vue +25 -0
  59. package/app/components/cart/summary/CartSummaryBreakdown.vue +35 -0
  60. package/app/components/cart/switcher/CartSwitcher.vue +147 -0
  61. package/app/components/cart/target/CartTargetModal.vue +129 -0
  62. package/app/components/cart/view/CartApprovalsPanel.vue +89 -0
  63. package/app/components/cart/view/CartListHeader.vue +86 -0
  64. package/app/components/cart/view/CartPositionList.vue +94 -0
  65. package/app/components/cart/view/CartSummaryPanel.vue +254 -0
  66. package/app/components/cart/view/CartView.vue +310 -0
  67. package/app/components/category/info/CategoryPrice.vue +47 -0
  68. package/app/components/category/info/CategorySku.vue +15 -0
  69. package/app/components/category/info/CategoryStock.vue +25 -0
  70. package/app/components/category/list/CategoryItemCount.vue +27 -0
  71. package/app/components/category/list/CategoryListPagination.vue +81 -0
  72. package/app/components/category/skeleton/CategoryDetailSkeleton.vue +12 -0
  73. package/app/components/category/skeleton/CategoryListSkeleton.vue +65 -0
  74. package/app/components/category/view/CategoryViewToggle.vue +33 -0
  75. package/app/components/category/view/GridView.vue +78 -0
  76. package/app/components/category/view/ListView.vue +80 -0
  77. package/app/components/checkout/confirmation/CheckoutConfirmationView.vue +289 -0
  78. package/app/components/checkout/form/CheckoutSchemaForm.vue +72 -0
  79. package/app/components/checkout/onepage/CheckoutAddressPickerModal.vue +260 -0
  80. package/app/components/checkout/onepage/CheckoutAddressSection.vue +186 -0
  81. package/app/components/checkout/onepage/CheckoutDeliverySection.vue +158 -0
  82. package/app/components/checkout/onepage/CheckoutGate.vue +67 -0
  83. package/app/components/checkout/onepage/CheckoutGuestDetailsSection.vue +154 -0
  84. package/app/components/checkout/onepage/CheckoutNotesSection.vue +62 -0
  85. package/app/components/checkout/onepage/CheckoutOnePageView.vue +77 -0
  86. package/app/components/checkout/onepage/CheckoutPaymentSection.vue +181 -0
  87. package/app/components/checkout/onepage/CheckoutSectionTitle.vue +18 -0
  88. package/app/components/checkout/onepage/CheckoutSummarySection.vue +211 -0
  89. package/app/components/checkout/onepage/CheckoutWorkflowPanel.vue +38 -0
  90. package/app/components/layout/AppLogo.vue +21 -0
  91. package/app/components/layout/footer/Footer.vue +148 -0
  92. package/app/components/layout/header/AppBar.vue +75 -0
  93. package/app/components/layout/header/CategoryNav.vue +93 -0
  94. package/app/components/layout/header/HeaderActionItem.vue +81 -0
  95. package/app/components/layout/header/LocaleSwitcher.vue +123 -0
  96. package/app/components/layout/header/MainNav.vue +61 -0
  97. package/app/components/layout/header/MobileMenu.vue +81 -0
  98. package/app/components/layout/header/TopBar.vue +63 -0
  99. package/app/components/listing/ListingView.vue +227 -0
  100. package/app/components/product/detail/ProductDetailAddToCart.vue +188 -0
  101. package/app/components/product/detail/ProductDetailDescription.vue +20 -0
  102. package/app/components/product/detail/ProductDetailImageGallery.vue +58 -0
  103. package/app/components/product/detail/ProductDetailPricing.vue +108 -0
  104. package/app/components/product/detail/ProductDetailSaveToList.vue +291 -0
  105. package/app/components/product/detail/ProductDetailSpecifications.vue +33 -0
  106. package/app/components/product/detail/ProductDetailStock.vue +36 -0
  107. package/app/components/search/filter/SearchFacets.vue +256 -0
  108. package/app/components/search/filter/SearchFacetsDrawer.vue +58 -0
  109. package/app/components/ui/AppShell.vue +7 -0
  110. package/app/components/ui/debug/PiniaStateCard.vue +106 -0
  111. package/app/components/ui/feedback/EmptyState.vue +30 -0
  112. package/app/components/ui/feedback/ErrorBoundary.vue +44 -0
  113. package/app/components/ui/feedback/NotFound.vue +34 -0
  114. package/app/components/ui/forms/CountrySelection.vue +14 -0
  115. package/app/components/ui/forms/FormKitDatePicker.vue +124 -0
  116. package/app/components/ui/forms/PasswordInput.vue +136 -0
  117. package/app/components/ui/forms/SearchInput.vue +213 -0
  118. package/app/components/ui/table/TableSortButton.vue +51 -0
  119. package/app/components/ui/table/TableToolbar.vue +66 -0
  120. package/app/composables/useAccount.ts +27 -0
  121. package/app/composables/useAccountAddresses.ts +116 -0
  122. package/app/composables/useAccountOrders.ts +18 -0
  123. package/app/composables/useAppUrl.ts +38 -0
  124. package/app/composables/useAuthStore.ts +202 -0
  125. package/app/composables/useB2BContext.ts +23 -0
  126. package/app/composables/useCartActions.ts +25 -0
  127. package/app/composables/useCartCalculation.ts +90 -0
  128. package/app/composables/useCartSelection.ts +46 -0
  129. package/app/composables/useCartStore.ts +837 -0
  130. package/app/composables/useCartSummaryFormatting.ts +28 -0
  131. package/app/composables/useCategories.ts +29 -0
  132. package/app/composables/useCheckoutOnePage.ts +438 -0
  133. package/app/composables/useCheckoutProfileSource.ts +8 -0
  134. package/app/composables/useCheckoutSchema.ts +28 -0
  135. package/app/composables/useDataTable.ts +14 -0
  136. package/app/composables/useFormValidation.ts +29 -0
  137. package/app/composables/useIcons.ts +17 -0
  138. package/app/composables/useLocalePreferences.ts +45 -0
  139. package/app/composables/useMarkets.ts +15 -0
  140. package/app/composables/useProduct.ts +89 -0
  141. package/app/composables/useProductCard.ts +8 -0
  142. package/app/composables/useProductCardActions.ts +106 -0
  143. package/app/composables/useProductImage.ts +12 -0
  144. package/app/composables/useProductListing.ts +210 -0
  145. package/app/composables/useProductUrl.ts +17 -0
  146. package/app/composables/useProducts.ts +130 -0
  147. package/app/composables/useSearch.ts +12 -0
  148. package/app/composables/useThemeStore.ts +81 -0
  149. package/app/composables/useViewMode.ts +18 -0
  150. package/app/config/countries.ts +74 -0
  151. package/app/config/icons.ts +283 -0
  152. package/app/config/navigation.ts +191 -0
  153. package/app/config/palette.ts +13 -0
  154. package/app/config/themes.ts +20 -0
  155. package/app/formkit.config.ts +50 -0
  156. package/app/interfaces/account/address-list.ts +34 -0
  157. package/app/interfaces/account/order-list.ts +47 -0
  158. package/app/interfaces/account/order-lists.ts +35 -0
  159. package/app/interfaces/account/profile.ts +17 -0
  160. package/app/interfaces/account.ts +3 -0
  161. package/app/interfaces/address.ts +9 -0
  162. package/app/interfaces/auth.ts +104 -0
  163. package/app/interfaces/b2b.ts +234 -0
  164. package/app/interfaces/cart-calculation.ts +131 -0
  165. package/app/interfaces/cart-item.ts +45 -0
  166. package/app/interfaces/checkout-draft.ts +4 -0
  167. package/app/interfaces/checkout.ts +43 -0
  168. package/app/interfaces/delivery.ts +13 -0
  169. package/app/interfaces/market.ts +24 -0
  170. package/app/interfaces/payment.ts +19 -0
  171. package/app/interfaces/persisted-cart.ts +10 -0
  172. package/app/interfaces/product-detail.ts +54 -0
  173. package/app/interfaces/product-list.ts +33 -0
  174. package/app/interfaces/search-facets.ts +14 -0
  175. package/app/interfaces/validation.ts +14 -0
  176. package/app/layouts/default.vue +78 -0
  177. package/app/layouts/focus.vue +80 -0
  178. package/app/plugins/formkit-locale.client.ts +23 -0
  179. package/app/shared/constants.ts +1 -0
  180. package/app/validations/companyName.ts +18 -0
  181. package/app/validations/emailFormat.ts +10 -0
  182. package/app/validations/formValidationConfig.ts +50 -0
  183. package/app/validations/maxLength.ts +12 -0
  184. package/app/validations/minLength.ts +9 -0
  185. package/app/validations/optionalCompanyName.ts +23 -0
  186. package/app/validations/passwordsMatch.ts +5 -0
  187. package/app/validations/phoneNumber.ts +19 -0
  188. package/app/validations/required.ts +11 -0
  189. package/app/validations/termsRequired.ts +4 -0
  190. package/app/validations/types.ts +10 -0
  191. package/app/validations/zipCode.ts +15 -0
  192. package/i18n/locales/de/account.json +458 -0
  193. package/i18n/locales/de/auth.json +155 -0
  194. package/i18n/locales/de/cart.json +263 -0
  195. package/i18n/locales/de/checkout.json +217 -0
  196. package/i18n/locales/de/common.json +80 -0
  197. package/i18n/locales/de/cover.json +33 -0
  198. package/i18n/locales/de/order.json +1 -0
  199. package/i18n/locales/de/product.json +71 -0
  200. package/i18n/locales/de/search.json +54 -0
  201. package/i18n/locales/de/validation.json +12 -0
  202. package/i18n/locales/en/account.json +458 -0
  203. package/i18n/locales/en/auth.json +155 -0
  204. package/i18n/locales/en/cart.json +263 -0
  205. package/i18n/locales/en/checkout.json +217 -0
  206. package/i18n/locales/en/common.json +80 -0
  207. package/i18n/locales/en/cover.json +33 -0
  208. package/i18n/locales/en/order.json +1 -0
  209. package/i18n/locales/en/product.json +71 -0
  210. package/i18n/locales/en/search.json +54 -0
  211. package/i18n/locales/en/validation.json +12 -0
  212. package/nuxt.config.ts +109 -0
  213. package/package.json +65 -0
  214. package/public/img/product-placeholder.svg +8 -0
  215. package/public/templates/direct-order-template.csv +3 -0
  216. package/public/templates/direct-order-template.xlsx +0 -0
  217. package/server/api/account/address/[id].delete.ts +51 -0
  218. package/server/api/account/address/[id].put.ts +83 -0
  219. package/server/api/account/address/index.post.ts +60 -0
  220. package/server/api/account/addresses.get.ts +25 -0
  221. package/server/api/account/context.get.ts +16 -0
  222. package/server/api/account/governance/[domain]/[id].put.ts +57 -0
  223. package/server/api/account/governance/[domain].post.ts +111 -0
  224. package/server/api/account/order-lists/[id].delete.ts +22 -0
  225. package/server/api/account/order-lists/[id].get.ts +17 -0
  226. package/server/api/account/order-lists/[id].put.ts +46 -0
  227. package/server/api/account/order-lists/index.get.ts +14 -0
  228. package/server/api/account/order-lists/index.post.ts +38 -0
  229. package/server/api/account/orders/[id].get.ts +35 -0
  230. package/server/api/account/orders.get.ts +35 -0
  231. package/server/api/account/profile.get.ts +56 -0
  232. package/server/api/account/profile.put.ts +128 -0
  233. package/server/api/account/requisitions/[id].get.ts +15 -0
  234. package/server/api/account/requisitions.get.ts +23 -0
  235. package/server/api/auth/login.post.ts +37 -0
  236. package/server/api/auth/logout.post.ts +4 -0
  237. package/server/api/auth/me.get.ts +3 -0
  238. package/server/api/auth/personas.get.ts +7 -0
  239. package/server/api/auth/recovery.post.ts +32 -0
  240. package/server/api/auth/recovery.put.ts +37 -0
  241. package/server/api/auth/register.post.ts +126 -0
  242. package/server/api/cart/calculate.post.ts +25 -0
  243. package/server/api/cart/export.post.ts +81 -0
  244. package/server/api/cart/index.delete.ts +10 -0
  245. package/server/api/cart/index.get.ts +10 -0
  246. package/server/api/cart/sync.post.ts +14 -0
  247. package/server/api/carts/[id]/activate.post.ts +18 -0
  248. package/server/api/carts/[id]/index.delete.ts +18 -0
  249. package/server/api/carts/[id]/index.put.ts +19 -0
  250. package/server/api/carts/[id]/items.post.ts +21 -0
  251. package/server/api/carts/index.get.ts +14 -0
  252. package/server/api/carts/index.post.ts +14 -0
  253. package/server/api/categories/[slug].get.ts +22 -0
  254. package/server/api/categories/index.get.ts +11 -0
  255. package/server/api/checkout/profile.get.ts +21 -0
  256. package/server/api/checkout/schema/[key].get.ts +19 -0
  257. package/server/api/checkout/session.post.ts +8 -0
  258. package/server/api/images/detail/[filename].get.ts +18 -0
  259. package/server/api/images/list/[filename].get.ts +17 -0
  260. package/server/api/markets.get.ts +9 -0
  261. package/server/api/orders/index.post.ts +376 -0
  262. package/server/api/payment/methods.post.ts +65 -0
  263. package/server/api/product/[id].get.ts +29 -0
  264. package/server/api/products/[id].get.ts +30 -0
  265. package/server/api/products/index.get.ts +21 -0
  266. package/server/api/requisitions/index.post.ts +67 -0
  267. package/server/api/shipping/rates.post.ts +70 -0
  268. package/server/api/themes/index.get.ts +9 -0
  269. package/server/api/typesense/drop.get.ts +22 -0
  270. package/server/api/typesense/health.get.ts +9 -0
  271. package/server/api/typesense/search.post.ts +199 -0
  272. package/server/api/typesense/seed.get.ts +112 -0
  273. package/server/api/typesense/suggest.post.ts +69 -0
  274. package/server/config/account/organization.json +146 -0
  275. package/server/config/account/personas.json +169 -0
  276. package/server/config/account/user.json +8 -0
  277. package/server/config/account/workflows.json +19 -0
  278. package/server/data/account/address-list.json +103 -0
  279. package/server/data/account/order-list.json +491 -0
  280. package/server/data/account/order-lists.json +149 -0
  281. package/server/data/account/profile.json +9 -0
  282. package/server/data/account/registration-requests.json +3 -0
  283. package/server/data/account/requisitions.json +686 -0
  284. package/server/data/categories.json +186 -0
  285. package/server/data/forms/checkout/add-address.json +24 -0
  286. package/server/data/list/5137-1.png +0 -0
  287. package/server/data/list/5498-1.png +0 -0
  288. package/server/data/list/5498-2.png +0 -0
  289. package/server/data/list/5498-3.png +0 -0
  290. package/server/data/list/5498-4.png +0 -0
  291. package/server/data/list/5498-5.png +0 -0
  292. package/server/data/list/5498-6.png +0 -0
  293. package/server/data/list/5519-1.png +0 -0
  294. package/server/data/list/5713-1.png +0 -0
  295. package/server/data/list/5789-1.png +0 -0
  296. package/server/data/list/5930-1.png +0 -0
  297. package/server/data/list/6127-1.png +0 -0
  298. package/server/data/list/6234-1.png +0 -0
  299. package/server/data/list/6238-1.png +0 -0
  300. package/server/data/list/6246-1.png +0 -0
  301. package/server/data/list/6270-1.png +0 -0
  302. package/server/data/list/6330-1.png +0 -0
  303. package/server/data/list/6336-1.png +0 -0
  304. package/server/data/list/6360-1.png +0 -0
  305. package/server/data/list/6363-1.png +0 -0
  306. package/server/data/list/6375-1.png +0 -0
  307. package/server/data/list/6385-1.png +0 -0
  308. package/server/data/list/6413-1.png +0 -0
  309. package/server/data/list/6418-1.png +0 -0
  310. package/server/data/list/6465-1.png +0 -0
  311. package/server/data/list/6477-1.png +0 -0
  312. package/server/data/list/6509-1.png +0 -0
  313. package/server/data/list/6545-1.png +0 -0
  314. package/server/data/list/6548-1.png +0 -0
  315. package/server/data/list/6566-1.png +0 -0
  316. package/server/data/list/6581-1.png +0 -0
  317. package/server/data/list/6609-1.png +0 -0
  318. package/server/data/list/6611-1.png +0 -0
  319. package/server/data/list/6641-1.png +0 -0
  320. package/server/data/list/6659-1.png +0 -0
  321. package/server/data/list/6662-1.png +0 -0
  322. package/server/data/list/6689-1.png +0 -0
  323. package/server/data/list/6698-1.png +0 -0
  324. package/server/data/list/6701-1.png +0 -0
  325. package/server/data/list/6752-1.png +0 -0
  326. package/server/data/list/6755-1.png +0 -0
  327. package/server/data/list/6837-1.png +0 -0
  328. package/server/data/list/6841-1.png +0 -0
  329. package/server/data/list/6844-1.png +0 -0
  330. package/server/data/list/6846-1.png +0 -0
  331. package/server/data/list/6886-1.png +0 -0
  332. package/server/data/list/6895-1.png +0 -0
  333. package/server/data/list/6897-1.png +0 -0
  334. package/server/data/list/6919-1.png +0 -0
  335. package/server/data/list/6977-1.png +0 -0
  336. package/server/data/list/6983-1.png +0 -0
  337. package/server/data/list/6984-1.png +0 -0
  338. package/server/data/list/6985-1.png +0 -0
  339. package/server/data/list/6986-1.png +0 -0
  340. package/server/data/list/6989-1.png +0 -0
  341. package/server/data/list/6995-1.png +0 -0
  342. package/server/data/list/6998-1.png +0 -0
  343. package/server/data/markets.json +24 -0
  344. package/server/data/product-detail.json +2450 -0
  345. package/server/data/product-list.json +2450 -0
  346. package/server/data/themes.json +8 -0
  347. package/server/interfaces/account.ts +20 -0
  348. package/server/interfaces/auth.ts +32 -0
  349. package/server/interfaces/b2bContext.ts +23 -0
  350. package/server/interfaces/cart.ts +46 -0
  351. package/server/interfaces/cartCalculation.ts +17 -0
  352. package/server/interfaces/category.ts +12 -0
  353. package/server/interfaces/checkoutProfile.ts +5 -0
  354. package/server/interfaces/log.ts +3 -0
  355. package/server/interfaces/market.ts +10 -0
  356. package/server/interfaces/product.ts +21 -0
  357. package/server/interfaces/schema.ts +20 -0
  358. package/server/interfaces/theme.ts +10 -0
  359. package/server/services/ApiAuthService.ts +138 -0
  360. package/server/services/ApiCartService.ts +254 -0
  361. package/server/services/ApiCategoryService.ts +25 -0
  362. package/server/services/ApiMarketService.ts +71 -0
  363. package/server/services/ApiProductService.ts +53 -0
  364. package/server/services/LocalFileCategoryService.ts +23 -0
  365. package/server/services/LocalFileCheckoutProfileService.ts +117 -0
  366. package/server/services/LocalFileProductService.ts +128 -0
  367. package/server/services/LocalFileSchemaService.ts +70 -0
  368. package/server/services/LocalFileThemeService.ts +18 -0
  369. package/server/services/LogService.ts +28 -0
  370. package/server/services/MockAccountService.ts +58 -0
  371. package/server/services/MockAuthService.ts +105 -0
  372. package/server/services/MockB2BContextService.ts +149 -0
  373. package/server/services/MockCartCalculationService.ts +395 -0
  374. package/server/services/MockMarketService.ts +18 -0
  375. package/server/services/SdkAccountService.ts +56 -0
  376. package/server/services/SdkAuthService.ts +83 -0
  377. package/server/services/SessionCartService.ts +31 -0
  378. package/server/utils/accountService.ts +30 -0
  379. package/server/utils/authCookie.ts +13 -0
  380. package/server/utils/authService.ts +43 -0
  381. package/server/utils/b2bService.ts +49 -0
  382. package/server/utils/cartService.ts +59 -0
  383. package/server/utils/categoryService.ts +19 -0
  384. package/server/utils/checkoutProfileService.ts +9 -0
  385. package/server/utils/checkoutSession.ts +38 -0
  386. package/server/utils/coverData.ts +84 -0
  387. package/server/utils/governanceStore.ts +38 -0
  388. package/server/utils/i18n.ts +76 -0
  389. package/server/utils/inventoryService.ts +14 -0
  390. package/server/utils/liveCatalog.ts +234 -0
  391. package/server/utils/liveInventories.ts +76 -0
  392. package/server/utils/liveOrders.ts +139 -0
  393. package/server/utils/livePrices.ts +93 -0
  394. package/server/utils/locale.ts +39 -0
  395. package/server/utils/logService.ts +19 -0
  396. package/server/utils/marketService.ts +24 -0
  397. package/server/utils/orderService.ts +14 -0
  398. package/server/utils/paymentService.ts +14 -0
  399. package/server/utils/priceService.ts +14 -0
  400. package/server/utils/productService.ts +28 -0
  401. package/server/utils/productsSchema.ts +30 -0
  402. package/server/utils/revenexxApi.ts +136 -0
  403. package/server/utils/schemaService.ts +25 -0
  404. package/server/utils/serviceMode.ts +70 -0
  405. package/server/utils/shippingService.ts +14 -0
  406. package/server/utils/shopSdk.ts +88 -0
  407. package/server/utils/themeService.ts +16 -0
  408. package/server/utils/typesense.ts +27 -0
@@ -0,0 +1,126 @@
1
+ import { ID } from "@revenexx/sdk";
2
+
3
+ interface RegistrationProfilePayload {
4
+ mode: "new" | "existing";
5
+ company: string;
6
+ vatId?: string;
7
+ customerNumber?: string;
8
+ address?: {
9
+ street: string;
10
+ streetNumber: string;
11
+ zip: string;
12
+ city: string;
13
+ country: string;
14
+ };
15
+ salutation?: string;
16
+ jobTitle?: string;
17
+ phone?: string;
18
+ }
19
+
20
+ interface RegisterPayload {
21
+ email: string;
22
+ password: string;
23
+ name?: string;
24
+ profile?: RegistrationProfilePayload;
25
+ }
26
+
27
+ // B2B registrations arrive as a registration request (BRW/IS8 pattern):
28
+ // the company profile is captured for vetting while the account itself is
29
+ // usable right away (demo persistence).
30
+ async function persistRegistrationRequest(
31
+ user: { $id: string; name: string; email: string },
32
+ profile: RegistrationProfilePayload,
33
+ ): Promise<void> {
34
+ try {
35
+ const store = await readCoverMutableJson<{ requests: unknown[] }>("account/registration-requests.json");
36
+ store.requests.unshift({
37
+ id: `REG-${Date.now()}`,
38
+ userId: user.$id,
39
+ email: user.email,
40
+ name: user.name,
41
+ submittedAt: new Date().toISOString(),
42
+ ...profile,
43
+ });
44
+ await writeCoverMutableJson("account/registration-requests.json", store);
45
+ }
46
+ catch (persistErr) {
47
+ getLogService().error("Registration request persistence failed", toErrorContext(persistErr));
48
+ }
49
+ }
50
+
51
+ export default defineEventHandler(async (event) => {
52
+ const body = await readBody<RegisterPayload>(event);
53
+ const { email, password, name, profile } = body;
54
+
55
+ // Mock mode registers offline: the user lands in the registration
56
+ // request store, which the MockAuthService accepts for login.
57
+ const serviceKey = resolveAuthServiceKey(event);
58
+ if (serviceKey === "mock") {
59
+ const user = {
60
+ $id: `reg-${Date.now()}`,
61
+ name: name ?? email,
62
+ email,
63
+ };
64
+ await persistRegistrationRequest(user, profile ?? { mode: "new", company: "" });
65
+ return user;
66
+ }
67
+
68
+ // Public-API mode: the customers app is the system of record. A company
69
+ // registration creates the organization (and its platform team) in the
70
+ // same call; the contact mirrors to a platform user behind the scenes.
71
+ if (serviceKey === "api") {
72
+ const fullName = (name ?? "").trim();
73
+ const splitAt = fullName.lastIndexOf(" ");
74
+ const firstName = splitAt > 0 ? fullName.slice(0, splitAt) : fullName;
75
+ const lastName = splitAt > 0 ? fullName.slice(splitAt + 1) : "";
76
+
77
+ try {
78
+ const { contact, user_id: userId } = await useRevenexxApi().post<{
79
+ contact: { id: string; email: string };
80
+ user_id: string;
81
+ }>("/v1/customers/auth/register", {
82
+ email,
83
+ password,
84
+ first_name: firstName || undefined,
85
+ last_name: lastName || undefined,
86
+ organization_name: profile?.company || undefined,
87
+ locale: resolveLocale(event),
88
+ });
89
+
90
+ const user = { $id: userId, name: fullName || email, email: contact.email };
91
+ if (profile?.company) {
92
+ await persistRegistrationRequest(user, profile);
93
+ }
94
+ return user;
95
+ }
96
+ catch (err) {
97
+ if (isApiUserError(err)) {
98
+ throw createError({ statusCode: err.statusCode, data: { type: apiAuthErrorType(err) } });
99
+ }
100
+ getLogService().error("API request failed: register", apiErrorContext(err));
101
+ throw createError({ statusCode: 503, data: { type: "service_unavailable" } });
102
+ }
103
+ }
104
+
105
+ try {
106
+ const user = await useShopSdkAccount().accountCreate({
107
+ userId: ID.unique(),
108
+ email,
109
+ password,
110
+ name,
111
+ });
112
+
113
+ if (profile?.company) {
114
+ await persistRegistrationRequest(user, profile);
115
+ }
116
+
117
+ return { $id: user.$id, name: user.name, email: user.email };
118
+ }
119
+ catch (err) {
120
+ if (isSdkUserError(err)) {
121
+ throw createError({ statusCode: err.code, data: { type: err.type } });
122
+ }
123
+ getLogService().error("SDK request failed: register", sdkErrorContext(err));
124
+ throw createError({ statusCode: 503, data: { type: "service_unavailable" } });
125
+ }
126
+ });
@@ -0,0 +1,25 @@
1
+ import type { CartCalculationRequest } from "../../../app/interfaces/cart-calculation";
2
+
3
+ /**
4
+ * Calculates the cart: per-line pricing, the ordered totals block, line
5
+ * hints, orderability and triggered spending limits. Works for guests
6
+ * (organization defaults) and logged-in users (role, limits, cost centers).
7
+ */
8
+ export default defineEventHandler(async (event) => {
9
+ const body = await readBody<CartCalculationRequest>(event);
10
+ if (!body || !Array.isArray(body.items)) {
11
+ throw createError({ statusCode: 400, message: "items[] required" });
12
+ }
13
+
14
+ const locale = resolveLocale(event);
15
+ const user = await getAuthService(event).me(event);
16
+
17
+ try {
18
+ const context = await getB2BContextService(event).getContext(user?.$id ?? null);
19
+ return await getCartCalculationService().calculate(body, context, locale);
20
+ }
21
+ catch (err) {
22
+ getLogService().error("Service error: cart/calculate", toErrorContext(err));
23
+ throw createError({ statusCode: 500, message: "Internal server error" });
24
+ }
25
+ });
@@ -0,0 +1,81 @@
1
+ import type { CartCalculationRequest } from "../../../app/interfaces/cart-calculation";
2
+ import type { CostCenter } from "../../../app/interfaces/b2b";
3
+
4
+ /**
5
+ * Exports the cart as CSV with the standardized 14-column structure
6
+ * (article number through position texts). Disabled per organization via
7
+ * settings.cart.exportEnabled.
8
+ */
9
+ export default defineEventHandler(async (event) => {
10
+ const body = await readBody<CartCalculationRequest>(event);
11
+ if (!body || !Array.isArray(body.items) || body.items.length === 0) {
12
+ throw createError({ statusCode: 400, message: "items[] required" });
13
+ }
14
+
15
+ const locale = resolveLocale(event);
16
+ const user = await getAuthService(event).me(event);
17
+ const context = await getB2BContextService(event).getContext(user?.$id ?? null);
18
+
19
+ if (!context.settings.cart.exportEnabled) {
20
+ throw createError({ statusCode: 403, message: "Cart export is disabled" });
21
+ }
22
+
23
+ await preloadLocaleNamespaces(locale, ["cart"]);
24
+ const t = (key: string) => serverT(key, locale, "cart");
25
+
26
+ const calculation = await getCartCalculationService().calculate(body, context, locale);
27
+ const lineById = new Map(calculation.lines.map(l => [l.id, l]));
28
+ const costCenterById = new Map<string, CostCenter>(context.costCenters.map(cc => [cc.id, cc]));
29
+
30
+ const header = [
31
+ t("export.columns.sku"),
32
+ t("export.columns.name"),
33
+ t("export.columns.dimension"),
34
+ t("export.columns.quantity"),
35
+ t("export.columns.lineTotal"),
36
+ t("export.columns.unitPrice"),
37
+ t("export.columns.available"),
38
+ t("export.columns.customSku"),
39
+ t("export.columns.costCenterCode"),
40
+ t("export.columns.costCenterLabel"),
41
+ t("export.columns.positionText1"),
42
+ t("export.columns.positionText2"),
43
+ t("export.columns.positionText3"),
44
+ t("export.columns.positionText4"),
45
+ ];
46
+
47
+ const escape = (value: string | number | undefined | null): string => {
48
+ const s = value === undefined || value === null ? "" : String(value);
49
+ return /[";\n]/.test(s) ? `"${s.replace(/"/g, "\"\"")}"` : s;
50
+ };
51
+
52
+ const rows = body.items.map((item) => {
53
+ const line = lineById.get(item.id);
54
+ const cc = item.costCenterId ? costCenterById.get(item.costCenterId) : undefined;
55
+ const texts = item.positionTexts ?? [];
56
+ return [
57
+ item.sku,
58
+ item.name,
59
+ item.name2 ?? "",
60
+ line?.adjustedQuantity ?? item.quantity,
61
+ line?.lineTotal ?? "",
62
+ line?.unitPrice ?? "",
63
+ line?.availability.availableQuantity ?? "",
64
+ item.customSku ?? "",
65
+ cc?.code ?? "",
66
+ cc?.label ?? "",
67
+ texts[0] ?? "",
68
+ texts[1] ?? "",
69
+ texts[2] ?? "",
70
+ texts[3] ?? "",
71
+ ].map(escape).join(";");
72
+ });
73
+
74
+ const csv = `\uFEFF${header.map(escape).join(";")}\n${rows.join("\n")}\n`;
75
+
76
+ setResponseHeaders(event, {
77
+ "Content-Type": "text/csv; charset=utf-8",
78
+ "Content-Disposition": `attachment; filename="cart-export.csv"`,
79
+ });
80
+ return csv;
81
+ });
@@ -0,0 +1,10 @@
1
+ export default defineEventHandler(async (event) => {
2
+ try {
3
+ await getCartService(event).clearItems(event);
4
+ return { ok: true };
5
+ }
6
+ catch (err) {
7
+ getLogService().error("Service error: cart/clear", toErrorContext(err));
8
+ throw createError({ statusCode: 500, message: "Internal server error" });
9
+ }
10
+ });
@@ -0,0 +1,10 @@
1
+ export default defineEventHandler(async (event) => {
2
+ try {
3
+ const items = await getCartService(event).getItems(event);
4
+ return { items };
5
+ }
6
+ catch (err) {
7
+ getLogService().error("Service error: cart/get", toErrorContext(err));
8
+ throw createError({ statusCode: 500, message: "Internal server error" });
9
+ }
10
+ });
@@ -0,0 +1,14 @@
1
+ import type { CartItem } from "../../../app/interfaces/cart-item";
2
+
3
+ export default defineEventHandler(async (event) => {
4
+ const { items } = await readBody<{ items: CartItem[] }>(event);
5
+
6
+ try {
7
+ await getCartService(event).saveItems(event, items ?? []);
8
+ return { ok: true };
9
+ }
10
+ catch (err) {
11
+ getLogService().error("Service error: cart/sync", toErrorContext(err));
12
+ throw createError({ statusCode: 500, message: "Internal server error" });
13
+ }
14
+ });
@@ -0,0 +1,18 @@
1
+ export default defineEventHandler(async (event) => {
2
+ const manager = getCartManager(event);
3
+ if (!manager) {
4
+ throw createError({ statusCode: 501, message: "Multi-cart management needs live mode" });
5
+ }
6
+ const id = getRouterParam(event, "id") ?? "";
7
+ if (!id) {
8
+ throw createError({ statusCode: 400, message: "Cart id is required" });
9
+ }
10
+ try {
11
+ const items = await manager.activateCart(event, id);
12
+ return { items };
13
+ }
14
+ catch (err) {
15
+ getLogService().error("Service error: carts/activate", toErrorContext(err));
16
+ throw createError({ statusCode: 500, message: "Internal server error" });
17
+ }
18
+ });
@@ -0,0 +1,18 @@
1
+ export default defineEventHandler(async (event) => {
2
+ const manager = getCartManager(event);
3
+ if (!manager) {
4
+ throw createError({ statusCode: 501, message: "Multi-cart management needs live mode" });
5
+ }
6
+ const id = getRouterParam(event, "id") ?? "";
7
+ if (!id) {
8
+ throw createError({ statusCode: 400, message: "Cart id is required" });
9
+ }
10
+ try {
11
+ await manager.deleteCart(event, id);
12
+ return { ok: true };
13
+ }
14
+ catch (err) {
15
+ getLogService().error("Service error: carts/delete", toErrorContext(err));
16
+ throw createError({ statusCode: 500, message: "Internal server error" });
17
+ }
18
+ });
@@ -0,0 +1,19 @@
1
+ export default defineEventHandler(async (event) => {
2
+ const manager = getCartManager(event);
3
+ if (!manager) {
4
+ throw createError({ statusCode: 501, message: "Multi-cart management needs live mode" });
5
+ }
6
+ const id = getRouterParam(event, "id") ?? "";
7
+ const { name } = await readBody<{ name: string }>(event);
8
+ if (!id || !name?.trim()) {
9
+ throw createError({ statusCode: 400, message: "Cart id and name are required" });
10
+ }
11
+ try {
12
+ await manager.renameCart(event, id, name);
13
+ return { ok: true };
14
+ }
15
+ catch (err) {
16
+ getLogService().error("Service error: carts/rename", toErrorContext(err));
17
+ throw createError({ statusCode: 500, message: "Internal server error" });
18
+ }
19
+ });
@@ -0,0 +1,21 @@
1
+ import type { CartItem } from "../../../../app/interfaces/cart-item";
2
+
3
+ export default defineEventHandler(async (event) => {
4
+ const manager = getCartManager(event);
5
+ if (!manager) {
6
+ throw createError({ statusCode: 501, message: "Multi-cart management needs live mode" });
7
+ }
8
+ const id = getRouterParam(event, "id") ?? "";
9
+ const { item } = await readBody<{ item: CartItem }>(event);
10
+ if (!id || !item) {
11
+ throw createError({ statusCode: 400, message: "Cart id and item are required" });
12
+ }
13
+ try {
14
+ await manager.addItemToCart(event, id, item);
15
+ return { ok: true };
16
+ }
17
+ catch (err) {
18
+ getLogService().error("Service error: carts/add-item", toErrorContext(err));
19
+ throw createError({ statusCode: 500, message: "Internal server error" });
20
+ }
21
+ });
@@ -0,0 +1,14 @@
1
+ export default defineEventHandler(async (event) => {
2
+ const manager = getCartManager(event);
3
+ if (!manager) {
4
+ // Mock mode: the demo shop manages multiple carts client-side.
5
+ return { carts: [], activeCartId: null, managed: false };
6
+ }
7
+ try {
8
+ return { ...(await manager.listCarts(event)), managed: true };
9
+ }
10
+ catch (err) {
11
+ getLogService().error("Service error: carts/list", toErrorContext(err));
12
+ throw createError({ statusCode: 500, message: "Internal server error" });
13
+ }
14
+ });
@@ -0,0 +1,14 @@
1
+ export default defineEventHandler(async (event) => {
2
+ const manager = getCartManager(event);
3
+ if (!manager) {
4
+ throw createError({ statusCode: 501, message: "Multi-cart management needs live mode" });
5
+ }
6
+ const { name, activate } = await readBody<{ name: string; activate?: boolean }>(event);
7
+ try {
8
+ return await manager.createCart(event, name ?? "", Boolean(activate));
9
+ }
10
+ catch (err) {
11
+ getLogService().error("Service error: carts/create", toErrorContext(err));
12
+ throw createError({ statusCode: 500, message: "Internal server error" });
13
+ }
14
+ });
@@ -0,0 +1,22 @@
1
+ export default defineEventHandler(async (event) => {
2
+ const locale = resolveLocale(event);
3
+ const slug = getRouterParam(event, "slug");
4
+ if (!slug) {
5
+ throw createError({ status: 400, message: "Missing slug" });
6
+ }
7
+
8
+ try {
9
+ const category = await getCategoryService(event).getCategoryBySlug(slug, locale);
10
+ if (!category) {
11
+ throw createError({ status: 404, message: "Category not found" });
12
+ }
13
+ return category;
14
+ }
15
+ catch (err) {
16
+ if (err !== null && typeof err === "object" && "statusCode" in err) {
17
+ throw err;
18
+ }
19
+ getLogService().error("Service error: categories/by-slug", { slug, ...toErrorContext(err) });
20
+ throw createError({ statusCode: 500, message: "Internal server error" });
21
+ }
22
+ });
@@ -0,0 +1,11 @@
1
+ export default defineEventHandler(async (event) => {
2
+ const locale = resolveLocale(event);
3
+
4
+ try {
5
+ return await getCategoryService(event).listCategories(locale);
6
+ }
7
+ catch (err) {
8
+ getLogService().error("Service error: categories/list", toErrorContext(err));
9
+ throw createError({ statusCode: 500, message: "Internal server error" });
10
+ }
11
+ });
@@ -0,0 +1,21 @@
1
+ export default defineEventHandler(async (event) => {
2
+ // Resolved through the registered auth service (mock or sdk); guests
3
+ // receive the guest checkout options when guest ordering is enabled.
4
+ const user = await getAuthService(event).me(event);
5
+
6
+ if (!user) {
7
+ const context = await getB2BContextService(event).getContext(null);
8
+ const guest = context.settings.checkout.guestOrdering;
9
+ if (!guest.b2b && !guest.b2c) {
10
+ throw createError({ statusCode: 401, message: "Unauthorized" });
11
+ }
12
+ }
13
+
14
+ try {
15
+ return await getCheckoutProfileService().getProfile(user?.$id ?? null);
16
+ }
17
+ catch (err) {
18
+ getLogService().error("Service error: checkout/profile", toErrorContext(err));
19
+ throw createError({ statusCode: 500, message: "Internal server error" });
20
+ }
21
+ });
@@ -0,0 +1,19 @@
1
+ export default defineEventHandler(async (event) => {
2
+ const locale = resolveLocale(event);
3
+ const key = getRouterParam(event, "key");
4
+
5
+ if (!key) {
6
+ throw createError({ statusCode: 400, message: "Missing schema key" });
7
+ }
8
+
9
+ try {
10
+ return await getSchemaService(event).getSchema(key, locale);
11
+ }
12
+ catch (err) {
13
+ if (err !== null && typeof err === "object" && "statusCode" in err) {
14
+ throw err;
15
+ }
16
+ getLogService().error("Service error: checkout/schema", { key, ...toErrorContext(err) });
17
+ throw createError({ statusCode: 500, message: "Internal server error" });
18
+ }
19
+ });
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Issues a one-time checkout session token. The one-page checkout fetches
3
+ * a fresh token right before submitting; the orders endpoint consumes it
4
+ * (see server/utils/checkoutSession.ts).
5
+ */
6
+ export default defineEventHandler(() => {
7
+ return { checkoutSessionToken: createCheckoutSession() };
8
+ });
@@ -0,0 +1,18 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join, basename } from "node:path";
3
+
4
+ export default defineEventHandler(async (event) => {
5
+ const filename = getRouterParam(event, "filename") ?? "";
6
+
7
+ if (filename !== basename(filename) || filename.includes("..")) {
8
+ throw createError({ statusCode: 400, message: "Invalid filename" });
9
+ }
10
+
11
+ const buffer = await readCoverDataRaw(`list/${filename}`);
12
+ if (!buffer) {
13
+ getLogService().error("Failed to read image asset", { filename });
14
+ throw createError({ statusCode: 404, message: "Image not found" });
15
+ }
16
+ setResponseHeader(event, "Content-Type", "image/png");
17
+ return buffer;
18
+ });
@@ -0,0 +1,17 @@
1
+ import { basename } from "node:path";
2
+
3
+ export default defineEventHandler(async (event) => {
4
+ const filename = getRouterParam(event, "filename") ?? "";
5
+
6
+ if (filename !== basename(filename) || filename.includes("..")) {
7
+ throw createError({ statusCode: 400, message: "Invalid filename" });
8
+ }
9
+
10
+ const buffer = await readCoverDataRaw(`list/${filename}`);
11
+ if (!buffer) {
12
+ getLogService().error("Failed to read image asset", { filename });
13
+ throw createError({ statusCode: 404, message: "Image not found" });
14
+ }
15
+ setResponseHeader(event, "Content-Type", "image/png");
16
+ return buffer;
17
+ });
@@ -0,0 +1,9 @@
1
+ export default defineEventHandler(async (event) => {
2
+ try {
3
+ return await getMarketService(event).listMarkets();
4
+ }
5
+ catch (err) {
6
+ getLogService().error("Service error: markets/list", toErrorContext(err));
7
+ throw createError({ statusCode: 500, message: "Internal server error" });
8
+ }
9
+ });