@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.
- package/LICENSE +21 -0
- package/README.md +39 -0
- package/app/api/account.ts +8 -0
- package/app/api/categories.ts +3 -0
- package/app/api/checkout.ts +6 -0
- package/app/api/images.ts +4 -0
- package/app/api/markets.ts +3 -0
- package/app/api/product.ts +3 -0
- package/app/api/products.ts +4 -0
- package/app/api/search.ts +4 -0
- package/app/app.config.ts +29 -0
- package/app/assets/css/cover.css +25 -0
- package/app/components/account/AccountMenu.vue +30 -0
- package/app/components/account/AccountShell.vue +18 -0
- package/app/components/account/AccountSidebar.vue +90 -0
- package/app/components/account/address/AccountAddressCard.vue +287 -0
- package/app/components/account/carts/AccountCartsTable.vue +284 -0
- package/app/components/account/dashboard/AccountDashboard.vue +351 -0
- package/app/components/account/directorder/AccountDirectOrder.vue +512 -0
- package/app/components/account/governance/AccountApprovalLimitsTable.vue +221 -0
- package/app/components/account/governance/AccountCostCenterDetail.vue +276 -0
- package/app/components/account/governance/AccountCostCentersTable.vue +252 -0
- package/app/components/account/governance/AccountRequisitionDetail.vue +295 -0
- package/app/components/account/governance/AccountRequisitionsTable.vue +255 -0
- package/app/components/account/governance/AccountWorkflowDetail.vue +215 -0
- package/app/components/account/governance/AccountWorkflowsTable.vue +168 -0
- package/app/components/account/governance/GovernanceApprovalLimitModal.vue +183 -0
- package/app/components/account/governance/GovernanceCostCenterModal.vue +188 -0
- package/app/components/account/governance/GovernanceWorkflowModal.vue +191 -0
- package/app/components/account/orderlists/AccountOrderListDetail.vue +349 -0
- package/app/components/account/orderlists/AccountOrderListsTable.vue +352 -0
- package/app/components/account/orders/AccountOrderDetail.vue +376 -0
- package/app/components/account/orders/AccountOrdersTable.vue +281 -0
- package/app/components/account/preferences/AccountPreferences.vue +50 -0
- package/app/components/auth/AuthForgotPasswordPanel.vue +88 -0
- package/app/components/auth/AuthLoginPanel.vue +103 -0
- package/app/components/auth/AuthLoginTeaser.vue +24 -0
- package/app/components/auth/AuthPageHeader.vue +21 -0
- package/app/components/auth/AuthRegisterPanel.vue +431 -0
- package/app/components/auth/AuthRegisterTeaser.vue +24 -0
- package/app/components/auth/AuthResetPasswordPanel.vue +115 -0
- package/app/components/cart/CartButton.vue +42 -0
- package/app/components/cart/actions/CartCostCenterModal.vue +110 -0
- package/app/components/cart/actions/CartExportModal.vue +82 -0
- package/app/components/cart/actions/CartPositionTextsModal.vue +92 -0
- package/app/components/cart/actions/CartSaveToListModal.vue +177 -0
- package/app/components/cart/actions/CartWorkflowPickerModal.vue +64 -0
- package/app/components/cart/drawer/CartDrawer.vue +49 -0
- package/app/components/cart/item/CartItem.vue +318 -0
- package/app/components/cart/manage/CartNameModal.vue +68 -0
- package/app/components/cart/position/CartPosition.vue +369 -0
- package/app/components/cart/quickadd/CartQuickAdd.vue +145 -0
- package/app/components/cart/recommend/CartCrossSell.vue +102 -0
- package/app/components/cart/recommend/CartRecommendCard.vue +59 -0
- package/app/components/cart/recommend/CartReorderStrip.vue +108 -0
- package/app/components/cart/requisition/CartRequisitionGroup.vue +74 -0
- package/app/components/cart/skeleton/CartSkeleton.vue +18 -0
- package/app/components/cart/summary/CartSummary.vue +25 -0
- package/app/components/cart/summary/CartSummaryBreakdown.vue +35 -0
- package/app/components/cart/switcher/CartSwitcher.vue +147 -0
- package/app/components/cart/target/CartTargetModal.vue +129 -0
- package/app/components/cart/view/CartApprovalsPanel.vue +89 -0
- package/app/components/cart/view/CartListHeader.vue +86 -0
- package/app/components/cart/view/CartPositionList.vue +94 -0
- package/app/components/cart/view/CartSummaryPanel.vue +254 -0
- package/app/components/cart/view/CartView.vue +310 -0
- package/app/components/category/info/CategoryPrice.vue +47 -0
- package/app/components/category/info/CategorySku.vue +15 -0
- package/app/components/category/info/CategoryStock.vue +25 -0
- package/app/components/category/list/CategoryItemCount.vue +27 -0
- package/app/components/category/list/CategoryListPagination.vue +81 -0
- package/app/components/category/skeleton/CategoryDetailSkeleton.vue +12 -0
- package/app/components/category/skeleton/CategoryListSkeleton.vue +65 -0
- package/app/components/category/view/CategoryViewToggle.vue +33 -0
- package/app/components/category/view/GridView.vue +78 -0
- package/app/components/category/view/ListView.vue +80 -0
- package/app/components/checkout/confirmation/CheckoutConfirmationView.vue +289 -0
- package/app/components/checkout/form/CheckoutSchemaForm.vue +72 -0
- package/app/components/checkout/onepage/CheckoutAddressPickerModal.vue +260 -0
- package/app/components/checkout/onepage/CheckoutAddressSection.vue +186 -0
- package/app/components/checkout/onepage/CheckoutDeliverySection.vue +158 -0
- package/app/components/checkout/onepage/CheckoutGate.vue +67 -0
- package/app/components/checkout/onepage/CheckoutGuestDetailsSection.vue +154 -0
- package/app/components/checkout/onepage/CheckoutNotesSection.vue +62 -0
- package/app/components/checkout/onepage/CheckoutOnePageView.vue +77 -0
- package/app/components/checkout/onepage/CheckoutPaymentSection.vue +181 -0
- package/app/components/checkout/onepage/CheckoutSectionTitle.vue +18 -0
- package/app/components/checkout/onepage/CheckoutSummarySection.vue +211 -0
- package/app/components/checkout/onepage/CheckoutWorkflowPanel.vue +38 -0
- package/app/components/layout/AppLogo.vue +21 -0
- package/app/components/layout/footer/Footer.vue +148 -0
- package/app/components/layout/header/AppBar.vue +75 -0
- package/app/components/layout/header/CategoryNav.vue +93 -0
- package/app/components/layout/header/HeaderActionItem.vue +81 -0
- package/app/components/layout/header/LocaleSwitcher.vue +123 -0
- package/app/components/layout/header/MainNav.vue +61 -0
- package/app/components/layout/header/MobileMenu.vue +81 -0
- package/app/components/layout/header/TopBar.vue +63 -0
- package/app/components/listing/ListingView.vue +227 -0
- package/app/components/product/detail/ProductDetailAddToCart.vue +188 -0
- package/app/components/product/detail/ProductDetailDescription.vue +20 -0
- package/app/components/product/detail/ProductDetailImageGallery.vue +58 -0
- package/app/components/product/detail/ProductDetailPricing.vue +108 -0
- package/app/components/product/detail/ProductDetailSaveToList.vue +291 -0
- package/app/components/product/detail/ProductDetailSpecifications.vue +33 -0
- package/app/components/product/detail/ProductDetailStock.vue +36 -0
- package/app/components/search/filter/SearchFacets.vue +256 -0
- package/app/components/search/filter/SearchFacetsDrawer.vue +58 -0
- package/app/components/ui/AppShell.vue +7 -0
- package/app/components/ui/debug/PiniaStateCard.vue +106 -0
- package/app/components/ui/feedback/EmptyState.vue +30 -0
- package/app/components/ui/feedback/ErrorBoundary.vue +44 -0
- package/app/components/ui/feedback/NotFound.vue +34 -0
- package/app/components/ui/forms/CountrySelection.vue +14 -0
- package/app/components/ui/forms/FormKitDatePicker.vue +124 -0
- package/app/components/ui/forms/PasswordInput.vue +136 -0
- package/app/components/ui/forms/SearchInput.vue +213 -0
- package/app/components/ui/table/TableSortButton.vue +51 -0
- package/app/components/ui/table/TableToolbar.vue +66 -0
- package/app/composables/useAccount.ts +27 -0
- package/app/composables/useAccountAddresses.ts +116 -0
- package/app/composables/useAccountOrders.ts +18 -0
- package/app/composables/useAppUrl.ts +38 -0
- package/app/composables/useAuthStore.ts +202 -0
- package/app/composables/useB2BContext.ts +23 -0
- package/app/composables/useCartActions.ts +25 -0
- package/app/composables/useCartCalculation.ts +90 -0
- package/app/composables/useCartSelection.ts +46 -0
- package/app/composables/useCartStore.ts +837 -0
- package/app/composables/useCartSummaryFormatting.ts +28 -0
- package/app/composables/useCategories.ts +29 -0
- package/app/composables/useCheckoutOnePage.ts +438 -0
- package/app/composables/useCheckoutProfileSource.ts +8 -0
- package/app/composables/useCheckoutSchema.ts +28 -0
- package/app/composables/useDataTable.ts +14 -0
- package/app/composables/useFormValidation.ts +29 -0
- package/app/composables/useIcons.ts +17 -0
- package/app/composables/useLocalePreferences.ts +45 -0
- package/app/composables/useMarkets.ts +15 -0
- package/app/composables/useProduct.ts +89 -0
- package/app/composables/useProductCard.ts +8 -0
- package/app/composables/useProductCardActions.ts +106 -0
- package/app/composables/useProductImage.ts +12 -0
- package/app/composables/useProductListing.ts +210 -0
- package/app/composables/useProductUrl.ts +17 -0
- package/app/composables/useProducts.ts +130 -0
- package/app/composables/useSearch.ts +12 -0
- package/app/composables/useThemeStore.ts +81 -0
- package/app/composables/useViewMode.ts +18 -0
- package/app/config/countries.ts +74 -0
- package/app/config/icons.ts +283 -0
- package/app/config/navigation.ts +191 -0
- package/app/config/palette.ts +13 -0
- package/app/config/themes.ts +20 -0
- package/app/formkit.config.ts +50 -0
- package/app/interfaces/account/address-list.ts +34 -0
- package/app/interfaces/account/order-list.ts +47 -0
- package/app/interfaces/account/order-lists.ts +35 -0
- package/app/interfaces/account/profile.ts +17 -0
- package/app/interfaces/account.ts +3 -0
- package/app/interfaces/address.ts +9 -0
- package/app/interfaces/auth.ts +104 -0
- package/app/interfaces/b2b.ts +234 -0
- package/app/interfaces/cart-calculation.ts +131 -0
- package/app/interfaces/cart-item.ts +45 -0
- package/app/interfaces/checkout-draft.ts +4 -0
- package/app/interfaces/checkout.ts +43 -0
- package/app/interfaces/delivery.ts +13 -0
- package/app/interfaces/market.ts +24 -0
- package/app/interfaces/payment.ts +19 -0
- package/app/interfaces/persisted-cart.ts +10 -0
- package/app/interfaces/product-detail.ts +54 -0
- package/app/interfaces/product-list.ts +33 -0
- package/app/interfaces/search-facets.ts +14 -0
- package/app/interfaces/validation.ts +14 -0
- package/app/layouts/default.vue +78 -0
- package/app/layouts/focus.vue +80 -0
- package/app/plugins/formkit-locale.client.ts +23 -0
- package/app/shared/constants.ts +1 -0
- package/app/validations/companyName.ts +18 -0
- package/app/validations/emailFormat.ts +10 -0
- package/app/validations/formValidationConfig.ts +50 -0
- package/app/validations/maxLength.ts +12 -0
- package/app/validations/minLength.ts +9 -0
- package/app/validations/optionalCompanyName.ts +23 -0
- package/app/validations/passwordsMatch.ts +5 -0
- package/app/validations/phoneNumber.ts +19 -0
- package/app/validations/required.ts +11 -0
- package/app/validations/termsRequired.ts +4 -0
- package/app/validations/types.ts +10 -0
- package/app/validations/zipCode.ts +15 -0
- package/i18n/locales/de/account.json +458 -0
- package/i18n/locales/de/auth.json +155 -0
- package/i18n/locales/de/cart.json +263 -0
- package/i18n/locales/de/checkout.json +217 -0
- package/i18n/locales/de/common.json +80 -0
- package/i18n/locales/de/cover.json +33 -0
- package/i18n/locales/de/order.json +1 -0
- package/i18n/locales/de/product.json +71 -0
- package/i18n/locales/de/search.json +54 -0
- package/i18n/locales/de/validation.json +12 -0
- package/i18n/locales/en/account.json +458 -0
- package/i18n/locales/en/auth.json +155 -0
- package/i18n/locales/en/cart.json +263 -0
- package/i18n/locales/en/checkout.json +217 -0
- package/i18n/locales/en/common.json +80 -0
- package/i18n/locales/en/cover.json +33 -0
- package/i18n/locales/en/order.json +1 -0
- package/i18n/locales/en/product.json +71 -0
- package/i18n/locales/en/search.json +54 -0
- package/i18n/locales/en/validation.json +12 -0
- package/nuxt.config.ts +109 -0
- package/package.json +65 -0
- package/public/img/product-placeholder.svg +8 -0
- package/public/templates/direct-order-template.csv +3 -0
- package/public/templates/direct-order-template.xlsx +0 -0
- package/server/api/account/address/[id].delete.ts +51 -0
- package/server/api/account/address/[id].put.ts +83 -0
- package/server/api/account/address/index.post.ts +60 -0
- package/server/api/account/addresses.get.ts +25 -0
- package/server/api/account/context.get.ts +16 -0
- package/server/api/account/governance/[domain]/[id].put.ts +57 -0
- package/server/api/account/governance/[domain].post.ts +111 -0
- package/server/api/account/order-lists/[id].delete.ts +22 -0
- package/server/api/account/order-lists/[id].get.ts +17 -0
- package/server/api/account/order-lists/[id].put.ts +46 -0
- package/server/api/account/order-lists/index.get.ts +14 -0
- package/server/api/account/order-lists/index.post.ts +38 -0
- package/server/api/account/orders/[id].get.ts +35 -0
- package/server/api/account/orders.get.ts +35 -0
- package/server/api/account/profile.get.ts +56 -0
- package/server/api/account/profile.put.ts +128 -0
- package/server/api/account/requisitions/[id].get.ts +15 -0
- package/server/api/account/requisitions.get.ts +23 -0
- package/server/api/auth/login.post.ts +37 -0
- package/server/api/auth/logout.post.ts +4 -0
- package/server/api/auth/me.get.ts +3 -0
- package/server/api/auth/personas.get.ts +7 -0
- package/server/api/auth/recovery.post.ts +32 -0
- package/server/api/auth/recovery.put.ts +37 -0
- package/server/api/auth/register.post.ts +126 -0
- package/server/api/cart/calculate.post.ts +25 -0
- package/server/api/cart/export.post.ts +81 -0
- package/server/api/cart/index.delete.ts +10 -0
- package/server/api/cart/index.get.ts +10 -0
- package/server/api/cart/sync.post.ts +14 -0
- package/server/api/carts/[id]/activate.post.ts +18 -0
- package/server/api/carts/[id]/index.delete.ts +18 -0
- package/server/api/carts/[id]/index.put.ts +19 -0
- package/server/api/carts/[id]/items.post.ts +21 -0
- package/server/api/carts/index.get.ts +14 -0
- package/server/api/carts/index.post.ts +14 -0
- package/server/api/categories/[slug].get.ts +22 -0
- package/server/api/categories/index.get.ts +11 -0
- package/server/api/checkout/profile.get.ts +21 -0
- package/server/api/checkout/schema/[key].get.ts +19 -0
- package/server/api/checkout/session.post.ts +8 -0
- package/server/api/images/detail/[filename].get.ts +18 -0
- package/server/api/images/list/[filename].get.ts +17 -0
- package/server/api/markets.get.ts +9 -0
- package/server/api/orders/index.post.ts +376 -0
- package/server/api/payment/methods.post.ts +65 -0
- package/server/api/product/[id].get.ts +29 -0
- package/server/api/products/[id].get.ts +30 -0
- package/server/api/products/index.get.ts +21 -0
- package/server/api/requisitions/index.post.ts +67 -0
- package/server/api/shipping/rates.post.ts +70 -0
- package/server/api/themes/index.get.ts +9 -0
- package/server/api/typesense/drop.get.ts +22 -0
- package/server/api/typesense/health.get.ts +9 -0
- package/server/api/typesense/search.post.ts +199 -0
- package/server/api/typesense/seed.get.ts +112 -0
- package/server/api/typesense/suggest.post.ts +69 -0
- package/server/config/account/organization.json +146 -0
- package/server/config/account/personas.json +169 -0
- package/server/config/account/user.json +8 -0
- package/server/config/account/workflows.json +19 -0
- package/server/data/account/address-list.json +103 -0
- package/server/data/account/order-list.json +491 -0
- package/server/data/account/order-lists.json +149 -0
- package/server/data/account/profile.json +9 -0
- package/server/data/account/registration-requests.json +3 -0
- package/server/data/account/requisitions.json +686 -0
- package/server/data/categories.json +186 -0
- package/server/data/forms/checkout/add-address.json +24 -0
- package/server/data/list/5137-1.png +0 -0
- package/server/data/list/5498-1.png +0 -0
- package/server/data/list/5498-2.png +0 -0
- package/server/data/list/5498-3.png +0 -0
- package/server/data/list/5498-4.png +0 -0
- package/server/data/list/5498-5.png +0 -0
- package/server/data/list/5498-6.png +0 -0
- package/server/data/list/5519-1.png +0 -0
- package/server/data/list/5713-1.png +0 -0
- package/server/data/list/5789-1.png +0 -0
- package/server/data/list/5930-1.png +0 -0
- package/server/data/list/6127-1.png +0 -0
- package/server/data/list/6234-1.png +0 -0
- package/server/data/list/6238-1.png +0 -0
- package/server/data/list/6246-1.png +0 -0
- package/server/data/list/6270-1.png +0 -0
- package/server/data/list/6330-1.png +0 -0
- package/server/data/list/6336-1.png +0 -0
- package/server/data/list/6360-1.png +0 -0
- package/server/data/list/6363-1.png +0 -0
- package/server/data/list/6375-1.png +0 -0
- package/server/data/list/6385-1.png +0 -0
- package/server/data/list/6413-1.png +0 -0
- package/server/data/list/6418-1.png +0 -0
- package/server/data/list/6465-1.png +0 -0
- package/server/data/list/6477-1.png +0 -0
- package/server/data/list/6509-1.png +0 -0
- package/server/data/list/6545-1.png +0 -0
- package/server/data/list/6548-1.png +0 -0
- package/server/data/list/6566-1.png +0 -0
- package/server/data/list/6581-1.png +0 -0
- package/server/data/list/6609-1.png +0 -0
- package/server/data/list/6611-1.png +0 -0
- package/server/data/list/6641-1.png +0 -0
- package/server/data/list/6659-1.png +0 -0
- package/server/data/list/6662-1.png +0 -0
- package/server/data/list/6689-1.png +0 -0
- package/server/data/list/6698-1.png +0 -0
- package/server/data/list/6701-1.png +0 -0
- package/server/data/list/6752-1.png +0 -0
- package/server/data/list/6755-1.png +0 -0
- package/server/data/list/6837-1.png +0 -0
- package/server/data/list/6841-1.png +0 -0
- package/server/data/list/6844-1.png +0 -0
- package/server/data/list/6846-1.png +0 -0
- package/server/data/list/6886-1.png +0 -0
- package/server/data/list/6895-1.png +0 -0
- package/server/data/list/6897-1.png +0 -0
- package/server/data/list/6919-1.png +0 -0
- package/server/data/list/6977-1.png +0 -0
- package/server/data/list/6983-1.png +0 -0
- package/server/data/list/6984-1.png +0 -0
- package/server/data/list/6985-1.png +0 -0
- package/server/data/list/6986-1.png +0 -0
- package/server/data/list/6989-1.png +0 -0
- package/server/data/list/6995-1.png +0 -0
- package/server/data/list/6998-1.png +0 -0
- package/server/data/markets.json +24 -0
- package/server/data/product-detail.json +2450 -0
- package/server/data/product-list.json +2450 -0
- package/server/data/themes.json +8 -0
- package/server/interfaces/account.ts +20 -0
- package/server/interfaces/auth.ts +32 -0
- package/server/interfaces/b2bContext.ts +23 -0
- package/server/interfaces/cart.ts +46 -0
- package/server/interfaces/cartCalculation.ts +17 -0
- package/server/interfaces/category.ts +12 -0
- package/server/interfaces/checkoutProfile.ts +5 -0
- package/server/interfaces/log.ts +3 -0
- package/server/interfaces/market.ts +10 -0
- package/server/interfaces/product.ts +21 -0
- package/server/interfaces/schema.ts +20 -0
- package/server/interfaces/theme.ts +10 -0
- package/server/services/ApiAuthService.ts +138 -0
- package/server/services/ApiCartService.ts +254 -0
- package/server/services/ApiCategoryService.ts +25 -0
- package/server/services/ApiMarketService.ts +71 -0
- package/server/services/ApiProductService.ts +53 -0
- package/server/services/LocalFileCategoryService.ts +23 -0
- package/server/services/LocalFileCheckoutProfileService.ts +117 -0
- package/server/services/LocalFileProductService.ts +128 -0
- package/server/services/LocalFileSchemaService.ts +70 -0
- package/server/services/LocalFileThemeService.ts +18 -0
- package/server/services/LogService.ts +28 -0
- package/server/services/MockAccountService.ts +58 -0
- package/server/services/MockAuthService.ts +105 -0
- package/server/services/MockB2BContextService.ts +149 -0
- package/server/services/MockCartCalculationService.ts +395 -0
- package/server/services/MockMarketService.ts +18 -0
- package/server/services/SdkAccountService.ts +56 -0
- package/server/services/SdkAuthService.ts +83 -0
- package/server/services/SessionCartService.ts +31 -0
- package/server/utils/accountService.ts +30 -0
- package/server/utils/authCookie.ts +13 -0
- package/server/utils/authService.ts +43 -0
- package/server/utils/b2bService.ts +49 -0
- package/server/utils/cartService.ts +59 -0
- package/server/utils/categoryService.ts +19 -0
- package/server/utils/checkoutProfileService.ts +9 -0
- package/server/utils/checkoutSession.ts +38 -0
- package/server/utils/coverData.ts +84 -0
- package/server/utils/governanceStore.ts +38 -0
- package/server/utils/i18n.ts +76 -0
- package/server/utils/inventoryService.ts +14 -0
- package/server/utils/liveCatalog.ts +234 -0
- package/server/utils/liveInventories.ts +76 -0
- package/server/utils/liveOrders.ts +139 -0
- package/server/utils/livePrices.ts +93 -0
- package/server/utils/locale.ts +39 -0
- package/server/utils/logService.ts +19 -0
- package/server/utils/marketService.ts +24 -0
- package/server/utils/orderService.ts +14 -0
- package/server/utils/paymentService.ts +14 -0
- package/server/utils/priceService.ts +14 -0
- package/server/utils/productService.ts +28 -0
- package/server/utils/productsSchema.ts +30 -0
- package/server/utils/revenexxApi.ts +136 -0
- package/server/utils/schemaService.ts +25 -0
- package/server/utils/serviceMode.ts +70 -0
- package/server/utils/shippingService.ts +14 -0
- package/server/utils/shopSdk.ts +88 -0
- package/server/utils/themeService.ts +16 -0
- package/server/utils/typesense.ts +27 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { H3Event } from "h3";
|
|
2
|
+
|
|
3
|
+
import type { CartItem } from "../../app/interfaces/cart-item";
|
|
4
|
+
|
|
5
|
+
import type { ICartService } from "../interfaces/cart";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Stores cart data in process memory, keyed by the cart session cookie.
|
|
9
|
+
* Each deployment restart clears all carts — acceptable for mock mode.
|
|
10
|
+
*/
|
|
11
|
+
export class SessionCartService implements ICartService {
|
|
12
|
+
private readonly store = new Map<string, CartItem[]>();
|
|
13
|
+
|
|
14
|
+
async getItems(event: H3Event): Promise<CartItem[]> {
|
|
15
|
+
return this.store.get(getOrCreateCartSessionId(event)) ?? [];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async saveItems(event: H3Event, items: CartItem[]): Promise<void> {
|
|
19
|
+
const cartId = getOrCreateCartSessionId(event);
|
|
20
|
+
if (items.length === 0) {
|
|
21
|
+
this.store.delete(cartId);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
this.store.set(cartId, items);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async clearItems(event: H3Event): Promise<void> {
|
|
29
|
+
this.store.delete(getOrCreateCartSessionId(event));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { H3Event } from "h3";
|
|
2
|
+
|
|
3
|
+
import type { IAccountService } from "../interfaces/account";
|
|
4
|
+
import { MockAccountService } from "../services/MockAccountService";
|
|
5
|
+
import { SdkAccountService } from "../services/SdkAccountService";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Registry of available account service implementations.
|
|
9
|
+
* The active implementation is selected by the `accountService` key in app.config.ts:
|
|
10
|
+
* - "mock" — demo identity from the bundled config asset
|
|
11
|
+
* - "sdk" — live identity via the revenexx web SDK (requires NUXT_WEB_SDK_*
|
|
12
|
+
* runtime config and an authenticated session)
|
|
13
|
+
*/
|
|
14
|
+
const serviceRegistry: Record<string, IAccountService> = {
|
|
15
|
+
mock: new MockAccountService("account/user.json"),
|
|
16
|
+
sdk: new SdkAccountService(),
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Returns the account service registered for the current app configuration.
|
|
21
|
+
* Falls back to "mock" if the configured key is not found.
|
|
22
|
+
*/
|
|
23
|
+
export function getAccountService(event?: H3Event): IAccountService {
|
|
24
|
+
const key = resolveServiceKey(event, {
|
|
25
|
+
domain: "accountService",
|
|
26
|
+
mockKey: "mock",
|
|
27
|
+
liveKey: "sdk",
|
|
28
|
+
});
|
|
29
|
+
return serviceRegistry[key] ?? serviceRegistry["mock"]!;
|
|
30
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CookieSerializeOptions } from "cookie-es";
|
|
2
|
+
|
|
3
|
+
export const SESSION_COOKIE_NAME = "cover-session";
|
|
4
|
+
|
|
5
|
+
export function sessionCookieOptions(expire?: string): CookieSerializeOptions {
|
|
6
|
+
return {
|
|
7
|
+
httpOnly: true,
|
|
8
|
+
secure: !import.meta.dev,
|
|
9
|
+
sameSite: "lax",
|
|
10
|
+
path: "/",
|
|
11
|
+
...(expire ? { expires: new Date(expire) } : {}),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { H3Event } from "h3";
|
|
2
|
+
|
|
3
|
+
import type { IAuthService } from "../interfaces/auth";
|
|
4
|
+
import { ApiAuthService } from "../services/ApiAuthService";
|
|
5
|
+
import { MockAuthService } from "../services/MockAuthService";
|
|
6
|
+
import { SdkAuthService } from "../services/SdkAuthService";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Registry of available auth implementations:
|
|
10
|
+
* - "mock" — offline login as bundled B2B demo personas (buyer/approver/admin)
|
|
11
|
+
* - "api" — live authentication via the public revenexx API (customers app)
|
|
12
|
+
* - "sdk" — live authentication via the revenexx web SDK (direct platform)
|
|
13
|
+
*/
|
|
14
|
+
const mockAuthService = new MockAuthService("account/personas.json");
|
|
15
|
+
|
|
16
|
+
const serviceRegistry: Record<string, IAuthService> = {
|
|
17
|
+
mock: mockAuthService,
|
|
18
|
+
api: new ApiAuthService(),
|
|
19
|
+
sdk: new SdkAuthService(),
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export function getAuthService(event?: H3Event): IAuthService {
|
|
23
|
+
const key = resolveServiceKey(event, {
|
|
24
|
+
domain: "authService",
|
|
25
|
+
mockKey: "mock",
|
|
26
|
+
liveKey: "api",
|
|
27
|
+
});
|
|
28
|
+
return serviceRegistry[key] ?? serviceRegistry["mock"]!;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Resolved registry key for endpoints that branch outside the interface. */
|
|
32
|
+
export function resolveAuthServiceKey(event?: H3Event): string {
|
|
33
|
+
return resolveServiceKey(event, {
|
|
34
|
+
domain: "authService",
|
|
35
|
+
mockKey: "mock",
|
|
36
|
+
liveKey: "api",
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** The mock instance — exposed for the personas listing endpoint. */
|
|
41
|
+
export function getMockAuthService(): MockAuthService {
|
|
42
|
+
return mockAuthService;
|
|
43
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { H3Event } from "h3";
|
|
2
|
+
|
|
3
|
+
import type { OrganizationSettings } from "../../app/interfaces/b2b";
|
|
4
|
+
|
|
5
|
+
import type { IB2BContextService, IRequisitionService } from "../interfaces/b2bContext";
|
|
6
|
+
import type { ICartCalculationService } from "../interfaces/cartCalculation";
|
|
7
|
+
import { MockB2BContextService, MockRequisitionService } from "../services/MockB2BContextService";
|
|
8
|
+
import { MockCartCalculationService } from "../services/MockCartCalculationService";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Dev-panel override for organization settings: a JSON cookie set by the
|
|
12
|
+
* demo shop lets every B2B feature flag be toggled per browser session —
|
|
13
|
+
* the demo equivalent of tenant configuration in a management center.
|
|
14
|
+
*/
|
|
15
|
+
export const ORG_SETTINGS_COOKIE = "cover-org-settings";
|
|
16
|
+
|
|
17
|
+
export function resolveOrgSettingsOverride(event?: H3Event): Partial<OrganizationSettings> | undefined {
|
|
18
|
+
if (!event) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
const raw = getCookie(event, ORG_SETTINGS_COOKIE);
|
|
22
|
+
if (!raw) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(raw) as Partial<OrganizationSettings>;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function getB2BContextService(event?: H3Event): IB2BContextService {
|
|
34
|
+
// Per-request instantiation: the service carries the request's settings
|
|
35
|
+
// override; the underlying data reads are cached by Nitro's storage.
|
|
36
|
+
return new MockB2BContextService(resolveOrgSettingsOverride(event));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const requisitionService: IRequisitionService = new MockRequisitionService();
|
|
40
|
+
|
|
41
|
+
export function getRequisitionService(): IRequisitionService {
|
|
42
|
+
return requisitionService;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const cartCalculationService: ICartCalculationService = new MockCartCalculationService();
|
|
46
|
+
|
|
47
|
+
export function getCartCalculationService(): ICartCalculationService {
|
|
48
|
+
return cartCalculationService;
|
|
49
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { getCookie, setCookie } from "h3";
|
|
2
|
+
import type { H3Event } from "h3";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
|
|
5
|
+
import type { ICartManager, ICartService } from "../interfaces/cart";
|
|
6
|
+
import { ApiCartService } from "../services/ApiCartService";
|
|
7
|
+
import { SessionCartService } from "../services/SessionCartService";
|
|
8
|
+
|
|
9
|
+
const CART_SESSION_COOKIE = "cover-cart-session";
|
|
10
|
+
const CART_SESSION_MAX_AGE = 60 * 60 * 24 * 30; // 30 days
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Registry of available cart implementations:
|
|
14
|
+
* - "mock" — in-memory session cart (multi-cart stays client-local)
|
|
15
|
+
* - "api" — live carts via the public revenexx API (carts app)
|
|
16
|
+
*/
|
|
17
|
+
const apiCartService = new ApiCartService();
|
|
18
|
+
|
|
19
|
+
const serviceRegistry: Record<string, ICartService> = {
|
|
20
|
+
mock: new SessionCartService(),
|
|
21
|
+
api: apiCartService,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export function getCartService(event?: H3Event): ICartService {
|
|
25
|
+
const key = resolveServiceKey(event, {
|
|
26
|
+
domain: "cartService",
|
|
27
|
+
mockKey: "mock",
|
|
28
|
+
liveKey: "api",
|
|
29
|
+
});
|
|
30
|
+
return serviceRegistry[key] ?? serviceRegistry["mock"]!;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** The multi-cart manager — live mode only; null in mock mode. */
|
|
34
|
+
export function getCartManager(event?: H3Event): ICartManager | null {
|
|
35
|
+
const key = resolveServiceKey(event, {
|
|
36
|
+
domain: "cartService",
|
|
37
|
+
mockKey: "mock",
|
|
38
|
+
liveKey: "api",
|
|
39
|
+
});
|
|
40
|
+
return key === "api" ? apiCartService : null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Returns the cart session ID from the request cookie, creating and setting a
|
|
45
|
+
* new one if it does not exist. Guests own their live session carts by it.
|
|
46
|
+
*/
|
|
47
|
+
export function getOrCreateCartSessionId(event: H3Event): string {
|
|
48
|
+
let id = getCookie(event, CART_SESSION_COOKIE);
|
|
49
|
+
if (!id) {
|
|
50
|
+
id = randomUUID();
|
|
51
|
+
setCookie(event, CART_SESSION_COOKIE, id, {
|
|
52
|
+
httpOnly: true,
|
|
53
|
+
sameSite: "lax",
|
|
54
|
+
path: "/",
|
|
55
|
+
maxAge: CART_SESSION_MAX_AGE,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return id;
|
|
59
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { H3Event } from "h3";
|
|
2
|
+
|
|
3
|
+
import type { ICategoryService } from "../interfaces/category";
|
|
4
|
+
import { ApiCategoryService } from "../services/ApiCategoryService";
|
|
5
|
+
import { LocalFileCategoryService } from "../services/LocalFileCategoryService";
|
|
6
|
+
|
|
7
|
+
const serviceRegistry: Record<string, ICategoryService> = {
|
|
8
|
+
mock: new LocalFileCategoryService("categories.json"),
|
|
9
|
+
api: new ApiCategoryService(),
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export function getCategoryService(event?: H3Event): ICategoryService {
|
|
13
|
+
const key = resolveServiceKey(event, {
|
|
14
|
+
domain: "categoryService",
|
|
15
|
+
mockKey: "mock",
|
|
16
|
+
liveKey: "api",
|
|
17
|
+
});
|
|
18
|
+
return serviceRegistry[key] ?? serviceRegistry["mock"]!;
|
|
19
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ICheckoutProfileService } from "../interfaces/checkoutProfile";
|
|
2
|
+
import { LocalFileCheckoutProfileService } from "../services/LocalFileCheckoutProfileService";
|
|
3
|
+
|
|
4
|
+
const checkoutProfileServiceInstance: ICheckoutProfileService
|
|
5
|
+
= new LocalFileCheckoutProfileService();
|
|
6
|
+
|
|
7
|
+
export function getCheckoutProfileService(): ICheckoutProfileService {
|
|
8
|
+
return checkoutProfileServiceInstance;
|
|
9
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
const TTL_MS = 2 * 60 * 60 * 1000; // 2 hours
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* In-memory token store: token → expiry timestamp.
|
|
7
|
+
*
|
|
8
|
+
* Tokens are generated when the checkout flow is loaded, and consumed
|
|
9
|
+
* (one-time use) when an order is submitted. This avoids relying on
|
|
10
|
+
* browser cookies, which can be stripped by reverse proxies.
|
|
11
|
+
*
|
|
12
|
+
* Note: in-memory state is per-process. For multi-instance deployments
|
|
13
|
+
* replace this with a shared store (Redis, DB, etc.).
|
|
14
|
+
*/
|
|
15
|
+
const tokenStore = new Map<string, number>();
|
|
16
|
+
|
|
17
|
+
export function createCheckoutSession(): string {
|
|
18
|
+
const token = randomBytes(32).toString("hex");
|
|
19
|
+
tokenStore.set(token, Date.now() + TTL_MS);
|
|
20
|
+
return token;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Validates and consumes a checkout session token (one-time use).
|
|
25
|
+
* Returns true if the token was valid and has been removed from the store.
|
|
26
|
+
*/
|
|
27
|
+
export function consumeCheckoutSession(token: string): boolean {
|
|
28
|
+
if (!token) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
const expiry = tokenStore.get(token);
|
|
32
|
+
if (expiry === undefined || Date.now() > expiry) {
|
|
33
|
+
tokenStore.delete(token);
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
tokenStore.delete(token);
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data access for the cover BFF mock implementations.
|
|
3
|
+
*
|
|
4
|
+
* The layer ships its demo data as Nitro server assets (registered in the
|
|
5
|
+
* layer's nuxt.config via nitro.serverAssets), so reads work identically in
|
|
6
|
+
* dev and in production builds — regardless of which app consumes the layer.
|
|
7
|
+
*
|
|
8
|
+
* Mutable demo state (e.g. the account address book) lives in the consuming
|
|
9
|
+
* app's `data` storage (.data/kv in dev), seeded from the bundled asset on
|
|
10
|
+
* first read. The layer package itself is never written to.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
function dataAssets() {
|
|
14
|
+
return useStorage("assets:cover-data");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function configAssets() {
|
|
18
|
+
return useStorage("assets:cover-config");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function localeAssets() {
|
|
22
|
+
return useStorage("assets:cover-locales");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function mutableData() {
|
|
26
|
+
return useStorage("data");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function readJsonFrom<T>(storage: ReturnType<typeof useStorage>, key: string): Promise<T> {
|
|
30
|
+
const raw = await storage.getItemRaw(key);
|
|
31
|
+
if (raw === null || raw === undefined) {
|
|
32
|
+
throw new Error(`cover data asset not found: ${key}`);
|
|
33
|
+
}
|
|
34
|
+
const text = typeof raw === "string" ? raw : Buffer.from(raw as Uint8Array).toString("utf-8");
|
|
35
|
+
return JSON.parse(text) as T;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Reads a JSON file from the layer's server/data assets. */
|
|
39
|
+
export async function readCoverDataJson<T>(key: string): Promise<T> {
|
|
40
|
+
return readJsonFrom<T>(dataAssets(), key);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Reads a binary file (e.g. product image) from the layer's server/data assets. */
|
|
44
|
+
export async function readCoverDataRaw(key: string): Promise<Buffer | null> {
|
|
45
|
+
const raw = await dataAssets().getItemRaw(key);
|
|
46
|
+
if (raw === null || raw === undefined) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
return typeof raw === "string" ? Buffer.from(raw) : Buffer.from(raw as Uint8Array);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Reads a JSON file from the layer's server/config assets. */
|
|
53
|
+
export async function readCoverConfigJson<T>(key: string): Promise<T> {
|
|
54
|
+
return readJsonFrom<T>(configAssets(), key);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Reads a locale namespace JSON ({locale}/{namespace}.json) from the layer's i18n assets. */
|
|
58
|
+
export async function readCoverLocaleJson<T>(locale: string, namespace: string): Promise<T | null> {
|
|
59
|
+
try {
|
|
60
|
+
return await readJsonFrom<T>(localeAssets(), `${locale}/${namespace}.json`);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Reads mutable demo state from the app's data storage, seeding it from the
|
|
69
|
+
* bundled asset of the same key on first access.
|
|
70
|
+
*/
|
|
71
|
+
export async function readCoverMutableJson<T>(key: string): Promise<T> {
|
|
72
|
+
const existing = await mutableData().getItem<T>(key);
|
|
73
|
+
if (existing !== null && existing !== undefined) {
|
|
74
|
+
return existing;
|
|
75
|
+
}
|
|
76
|
+
const seeded = await readCoverDataJson<T>(key);
|
|
77
|
+
await mutableData().setItem(key, seeded as unknown as object);
|
|
78
|
+
return seeded;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Persists mutable demo state to the app's data storage. */
|
|
82
|
+
export async function writeCoverMutableJson<T>(key: string, value: T): Promise<void> {
|
|
83
|
+
await mutableData().setItem(key, value as unknown as object);
|
|
84
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ApprovalLimit, ApprovalWorkflow, CostCenter } from "../../app/interfaces/b2b";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Mutable governance records created through the account area (demo
|
|
5
|
+
* persistence). They extend the bundled organization configuration:
|
|
6
|
+
* `added` arrays append, `patches` overlay base records by id.
|
|
7
|
+
*/
|
|
8
|
+
export interface GovernanceOverrides {
|
|
9
|
+
costCenters: CostCenter[];
|
|
10
|
+
costCenterPatches: Record<string, Partial<CostCenter>>;
|
|
11
|
+
approvalLimits: ApprovalLimit[];
|
|
12
|
+
workflows: ApprovalWorkflow[];
|
|
13
|
+
workflowPatches: Record<string, Partial<ApprovalWorkflow>>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const KEY = "account/governance-overrides.json";
|
|
17
|
+
|
|
18
|
+
const EMPTY: GovernanceOverrides = {
|
|
19
|
+
costCenters: [],
|
|
20
|
+
costCenterPatches: {},
|
|
21
|
+
approvalLimits: [],
|
|
22
|
+
workflows: [],
|
|
23
|
+
workflowPatches: {},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export async function readGovernanceOverrides(): Promise<GovernanceOverrides> {
|
|
27
|
+
try {
|
|
28
|
+
const stored = await readCoverMutableJson<Partial<GovernanceOverrides>>(KEY);
|
|
29
|
+
return { ...EMPTY, ...stored };
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return { ...EMPTY };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function writeGovernanceOverrides(overrides: GovernanceOverrides): Promise<void> {
|
|
37
|
+
await writeCoverMutableJson(KEY, overrides);
|
|
38
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
type TranslationRecord = Record<string, unknown>;
|
|
2
|
+
|
|
3
|
+
const cache = new Map<string, TranslationRecord>();
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Loads locale namespaces from the layer's i18n server assets into the cache.
|
|
7
|
+
* Call this once per request before using the synchronous serverT() — e.g.
|
|
8
|
+
* at the top of an event handler or service method.
|
|
9
|
+
*/
|
|
10
|
+
export async function preloadLocaleNamespaces(locale: string, namespaces: string[]): Promise<void> {
|
|
11
|
+
const fallbackLocale = String(useRuntimeConfig().public.defaultLocale);
|
|
12
|
+
const wanted = locale === fallbackLocale ? [locale] : [locale, fallbackLocale];
|
|
13
|
+
await Promise.all(wanted.flatMap(loc => namespaces.map(async (ns) => {
|
|
14
|
+
const key = `${loc}/${ns}`;
|
|
15
|
+
if (cache.has(key)) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const data = await readCoverLocaleJson<TranslationRecord>(loc, ns);
|
|
19
|
+
cache.set(key, data ?? {});
|
|
20
|
+
})));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function getNamespace(locale: string, namespace: string): TranslationRecord {
|
|
24
|
+
return cache.get(`${locale}/${namespace}`) ?? {};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function getNestedValue(obj: TranslationRecord, keyPath: string): string | undefined {
|
|
28
|
+
const parts = keyPath.split(".");
|
|
29
|
+
let current: unknown = obj;
|
|
30
|
+
for (const part of parts) {
|
|
31
|
+
if (current === null || typeof current !== "object") {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
current = (current as TranslationRecord)[part];
|
|
35
|
+
}
|
|
36
|
+
return typeof current === "string" ? current : undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Server-side translation utility for pre-translating BFF responses.
|
|
41
|
+
* Reads from the cached locale namespaces — the relevant namespaces must be
|
|
42
|
+
* loaded first via preloadLocaleNamespaces().
|
|
43
|
+
* @param key - dot-separated key path (e.g. "steps.address.title")
|
|
44
|
+
* @param locale - resolved locale from resolveLocale()
|
|
45
|
+
* @param namespace - locale file namespace (default: "checkout")
|
|
46
|
+
* @param params - interpolation values for {placeholder} tokens
|
|
47
|
+
*/
|
|
48
|
+
export function serverT(
|
|
49
|
+
key: string,
|
|
50
|
+
locale: string,
|
|
51
|
+
namespace = "checkout",
|
|
52
|
+
params?: Record<string, string | number>,
|
|
53
|
+
): string {
|
|
54
|
+
const interpolate = (template: string): string => {
|
|
55
|
+
if (!params) {
|
|
56
|
+
return template;
|
|
57
|
+
}
|
|
58
|
+
return template.replace(/\{(\w+)\}/g, (match, name: string) =>
|
|
59
|
+
name in params ? String(params[name]) : match,
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const value = getNestedValue(getNamespace(locale, namespace), key);
|
|
64
|
+
if (value !== undefined) {
|
|
65
|
+
return interpolate(value);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const fallbackLocale = String(useRuntimeConfig().public.defaultLocale);
|
|
69
|
+
if (locale !== fallbackLocale) {
|
|
70
|
+
const fallbackValue = getNestedValue(getNamespace(fallbackLocale, namespace), key);
|
|
71
|
+
if (fallbackValue !== undefined) {
|
|
72
|
+
return interpolate(fallbackValue);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return key;
|
|
76
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { H3Event } from "h3";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The inventories domain has no service class — endpoints branch on the
|
|
5
|
+
* resolved registry key ("mock" = demo data already carries stocks,
|
|
6
|
+
* "api" = the inventories app via the public revenexx API).
|
|
7
|
+
*/
|
|
8
|
+
export function resolveInventoryServiceKey(event?: H3Event): string {
|
|
9
|
+
return resolveServiceKey(event, {
|
|
10
|
+
domain: "inventoryService",
|
|
11
|
+
mockKey: "mock",
|
|
12
|
+
liveKey: "api",
|
|
13
|
+
});
|
|
14
|
+
}
|