@mohasinac/appkit 4.53.0 → 4.53.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.build-stamp.json +3 -3
- package/dist/_internal/client/scaffolds/AppShell.js +1 -1
- package/dist/_internal/client/theme/ThemeProvider.js +15 -1
- package/dist/_internal/server/features/auctions/og.d.ts +3 -1
- package/dist/_internal/server/features/auctions/og.js +3 -1
- package/dist/_internal/server/features/bundles/actions.js +1 -1
- package/dist/_internal/server/features/business-documents/download.d.ts +41 -0
- package/dist/_internal/server/features/business-documents/download.js +91 -0
- package/dist/_internal/server/features/categories/adapters.d.ts +1 -1
- package/dist/_internal/server/features/categories/adapters.js +10 -0
- package/dist/_internal/server/features/categories/price-guidance-resolve.d.ts +66 -0
- package/dist/_internal/server/features/categories/price-guidance-resolve.js +138 -0
- package/dist/_internal/server/features/checkout/actions.d.ts +14 -0
- package/dist/_internal/server/features/checkout/actions.js +106 -12
- package/dist/_internal/server/features/checkout/bundle-expansion.js +17 -0
- package/dist/_internal/server/features/checkout/data.d.ts +22 -0
- package/dist/_internal/server/features/checkout/group-rule-revalidation.d.ts +34 -0
- package/dist/_internal/server/features/checkout/group-rule-revalidation.js +124 -0
- package/dist/_internal/server/features/checkout/supplier-identity.d.ts +55 -0
- package/dist/_internal/server/features/checkout/supplier-identity.js +81 -0
- package/dist/_internal/server/features/classified/metadata.js +1 -1
- package/dist/_internal/server/features/classified/og.d.ts +3 -1
- package/dist/_internal/server/features/classified/og.js +3 -1
- package/dist/_internal/server/features/digital-code/metadata.js +1 -1
- package/dist/_internal/server/features/digital-code/og.d.ts +3 -1
- package/dist/_internal/server/features/digital-code/og.js +3 -1
- package/dist/_internal/server/features/digital-code/pool.d.ts +19 -4
- package/dist/_internal/server/features/digital-code/pool.js +19 -4
- package/dist/_internal/server/features/live/metadata.js +1 -1
- package/dist/_internal/server/features/live/og.d.ts +3 -1
- package/dist/_internal/server/features/live/og.js +3 -1
- package/dist/_internal/server/features/messages/actions.js +1 -1
- package/dist/_internal/server/features/parts/og.js +1 -1
- package/dist/_internal/server/features/pre-orders/og.d.ts +3 -1
- package/dist/_internal/server/features/pre-orders/og.js +3 -1
- package/dist/_internal/server/features/price-index/market.d.ts +57 -0
- package/dist/_internal/server/features/price-index/market.js +120 -0
- package/dist/_internal/server/features/price-index/search.d.ts +18 -0
- package/dist/_internal/server/features/price-index/search.js +47 -7
- package/dist/_internal/server/features/prize-draws/og.d.ts +3 -1
- package/dist/_internal/server/features/prize-draws/og.js +3 -1
- package/dist/_internal/server/features/products/group-members.d.ts +26 -0
- package/dist/_internal/server/features/products/group-members.js +7 -1
- package/dist/_internal/server/features/products/list-public.d.ts +12 -0
- package/dist/_internal/server/features/products/list-public.js +10 -1
- package/dist/_internal/server/features/products/listing-tab-counts.d.ts +25 -1
- package/dist/_internal/server/features/products/listing-tab-counts.js +128 -10
- package/dist/_internal/server/features/products/og.d.ts +3 -1
- package/dist/_internal/server/features/products/og.js +3 -1
- package/dist/_internal/server/features/search/scoped-sources.d.ts +26 -0
- package/dist/_internal/server/features/search/scoped-sources.js +252 -0
- package/dist/_internal/server/features/search/search-everything.d.ts +57 -0
- package/dist/_internal/server/features/search/search-everything.js +70 -20
- package/dist/_internal/server/features/seo/sitemap.js +6 -0
- package/dist/_internal/server/features/shared/listing-adapters.js +4 -2
- package/dist/_internal/server/features/sticker-trace/adapters.d.ts +11 -0
- package/dist/_internal/server/features/sticker-trace/adapters.js +1 -0
- package/dist/_internal/server/features/sticker-trace/promote-to-listings.d.ts +26 -0
- package/dist/_internal/server/features/sticker-trace/promote-to-listings.js +264 -0
- package/dist/_internal/server/features/sticker-trace/sheet-actions.d.ts +3 -1
- package/dist/_internal/server/features/sticker-trace/sheet-actions.js +32 -0
- package/dist/_internal/server/features/sticker-trace/storage.d.ts +20 -1
- package/dist/_internal/server/features/sticker-trace/storage.js +20 -1
- package/dist/_internal/server/features/stores/adapters.d.ts +1 -1
- package/dist/_internal/server/features/stores/adapters.js +16 -0
- package/dist/_internal/server/features/stores/index.d.ts +1 -0
- package/dist/_internal/server/features/stores/index.js +1 -0
- package/dist/_internal/server/features/stores/tabs.d.ts +30 -0
- package/dist/_internal/server/features/stores/tabs.js +124 -0
- package/dist/_internal/shared/checkout/rules/_defaults.js +0 -2
- package/dist/_internal/shared/checkout/rules/_limits.d.ts +14 -1
- package/dist/_internal/shared/checkout/rules/_limits.js +14 -1
- package/dist/_internal/shared/checkout/rules/_registry.js +2 -0
- package/dist/_internal/shared/checkout/rules/auction.rule.js +9 -1
- package/dist/_internal/shared/checkout/rules/bundle.rule.js +13 -0
- package/dist/_internal/shared/checkout/rules/index.d.ts +2 -0
- package/dist/_internal/shared/checkout/rules/index.js +9 -0
- package/dist/_internal/shared/checkout/rules/offer.rule.js +0 -1
- package/dist/_internal/shared/checkout/rules/payment-gate.d.ts +26 -0
- package/dist/_internal/shared/checkout/rules/payment-gate.js +133 -0
- package/dist/_internal/shared/checkout/rules/prize-draw.rule.js +29 -8
- package/dist/_internal/shared/checkout/rules/spares.rule.d.ts +16 -0
- package/dist/_internal/shared/checkout/rules/spares.rule.js +5 -0
- package/dist/_internal/shared/checkout/rules/types.d.ts +26 -2
- package/dist/_internal/shared/config/schema.d.ts +122 -0
- package/dist/_internal/shared/features/cart/schema.js +3 -2
- package/dist/_internal/shared/features/products/group-rules.d.ts +75 -0
- package/dist/_internal/shared/features/products/group-rules.js +142 -0
- package/dist/_internal/shared/listing-types/_registry.d.ts +24 -0
- package/dist/_internal/shared/listing-types/_registry.js +39 -1
- package/dist/_internal/shared/listing-types/art/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/art/config.js +2 -0
- package/dist/_internal/shared/listing-types/auction/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/auction/config.js +2 -0
- package/dist/_internal/shared/listing-types/availability.js +48 -0
- package/dist/_internal/shared/listing-types/capabilities.js +19 -0
- package/dist/_internal/shared/listing-types/classified/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/classified/config.js +2 -0
- package/dist/_internal/shared/listing-types/digital-code/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/digital-code/config.js +2 -0
- package/dist/_internal/shared/listing-types/feature-flags.js +1 -0
- package/dist/_internal/shared/listing-types/live/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/live/config.js +2 -0
- package/dist/_internal/shared/listing-types/pre-order/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/pre-order/config.js +2 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.js +2 -0
- package/dist/_internal/shared/listing-types/spares/config.d.ts +74 -0
- package/dist/_internal/shared/listing-types/spares/config.js +60 -0
- package/dist/_internal/shared/listing-types/spares/ctas.d.ts +1 -0
- package/dist/_internal/shared/listing-types/spares/ctas.js +4 -0
- package/dist/_internal/shared/listing-types/spares/og.js +1 -0
- package/dist/_internal/shared/listing-types/spares/schema.d.ts +2 -0
- package/dist/_internal/shared/listing-types/spares/schema.js +3 -0
- package/dist/_internal/shared/listing-types/spares/seed-factory.d.ts +1 -0
- package/dist/_internal/shared/listing-types/spares/seed-factory.js +1 -0
- package/dist/_internal/shared/listing-types/standard/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/standard/config.js +2 -0
- package/dist/_internal/shared/listing-types/stickers/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/stickers/config.js +2 -0
- package/dist/_internal/shared/search/match.d.ts +11 -0
- package/dist/_internal/shared/search/match.js +30 -3
- package/dist/_internal/shared/search/to-groups.d.ts +52 -0
- package/dist/_internal/shared/search/to-groups.js +141 -0
- package/dist/client.d.ts +8 -2
- package/dist/client.js +4 -1
- package/dist/constants/api-endpoints.d.ts +46 -15
- package/dist/constants/api-endpoints.js +35 -5
- package/dist/constants/cache-invalidation.js +3 -1
- package/dist/constants/field-names.d.ts +6 -0
- package/dist/constants/field-names.js +6 -0
- package/dist/features/about/components/PolicyPageView.d.ts +22 -2
- package/dist/features/about/components/PolicyPageView.js +14 -2
- package/dist/features/about/components/PublicProfileView.js +2 -1
- package/dist/features/about/components/ShippingPolicyView.js +42 -2
- package/dist/features/account/components/NotificationBell.js +1 -1
- package/dist/features/account/hooks/useProfileStats.js +5 -1
- package/dist/features/addresses/repository/addresses.repository.d.ts +16 -0
- package/dist/features/addresses/repository/addresses.repository.js +21 -0
- package/dist/features/admin/actions/admin-actions.js +16 -1
- package/dist/features/admin/components/AdminCategoryEditorView.js +19 -2
- package/dist/features/admin/components/AdminNavigationView.js +1 -1
- package/dist/features/admin/components/AdminPageHeader.js +1 -1
- package/dist/features/admin/components/AdminProductEditorView.js +17 -2
- package/dist/features/admin/components/AdminSidebar.js +1 -1
- package/dist/features/admin/components/AdminSiteSettingsView.js +39 -8
- package/dist/features/admin/components/AdminSparesView.d.ts +12 -0
- package/dist/features/admin/components/AdminSparesView.js +30 -0
- package/dist/features/admin/components/AdminUsersView.js +9 -7
- package/dist/features/admin/components/index.d.ts +2 -0
- package/dist/features/admin/components/index.js +1 -0
- package/dist/features/admin/components/sections/adminSectionsTypes.js +7 -0
- package/dist/features/admin/constants/filter-tabs.d.ts +3 -0
- package/dist/features/admin/constants/filter-tabs.js +1 -0
- package/dist/features/admin/schemas/firestore.d.ts +26 -2
- package/dist/features/auctions/components/AuctionDetailPageView.js +12 -18
- package/dist/features/auth/repository/user.repository.d.ts +13 -0
- package/dist/features/auth/repository/user.repository.js +28 -0
- package/dist/features/auth/schemas/firestore.d.ts +2 -0
- package/dist/features/auth/schemas/firestore.js +2 -0
- package/dist/features/business-documents/repository/business-documents.repository.d.ts +58 -0
- package/dist/features/business-documents/repository/business-documents.repository.js +54 -0
- package/dist/features/business-documents/schemas/firestore.d.ts +105 -0
- package/dist/features/business-documents/schemas/firestore.js +75 -0
- package/dist/features/cart/actions/cart-actions.js +83 -6
- package/dist/features/cart/repository/cart.repository.js +32 -4
- package/dist/features/cart/schemas/firestore.d.ts +20 -0
- package/dist/features/cart/schemas/index.d.ts +2 -2
- package/dist/features/catalogue/components/PublicCatalogueItemDetailView.js +1 -1
- package/dist/features/categories/api/[id]/price-guidance/route.d.ts +42 -0
- package/dist/features/categories/api/[id]/price-guidance/route.js +90 -0
- package/dist/features/categories/components/BrandDetailPageView.js +32 -8
- package/dist/features/categories/components/BrandDetailTabs.d.ts +7 -1
- package/dist/features/categories/components/BrandDetailTabs.js +28 -3
- package/dist/features/categories/components/BundleCollage.js +3 -2
- package/dist/features/categories/components/BundleItemsPicker.js +3 -4
- package/dist/features/categories/components/CategoriesIndexListing.js +23 -8
- package/dist/features/categories/components/CategoryDetailPageView.js +157 -20
- package/dist/features/categories/components/CategoryDetailTabs.d.ts +7 -1
- package/dist/features/categories/components/CategoryDetailTabs.js +41 -7
- package/dist/features/categories/components/CategoryGrid.js +10 -1
- package/dist/features/categories/components/PriceGuidanceHint.d.ts +29 -0
- package/dist/features/categories/components/PriceGuidanceHint.js +61 -0
- package/dist/features/categories/components/SubcategoryCardRow.d.ts +27 -0
- package/dist/features/categories/components/SubcategoryCardRow.js +98 -0
- package/dist/features/categories/constants/category-tabs.d.ts +20 -25
- package/dist/features/categories/constants/category-tabs.js +22 -39
- package/dist/features/categories/repository/categories.repository.d.ts +12 -0
- package/dist/features/categories/repository/categories.repository.js +20 -0
- package/dist/features/categories/schemas/firestore.d.ts +22 -1
- package/dist/features/categories/schemas/firestore.js +10 -0
- package/dist/features/categories/schemas/index.d.ts +6 -0
- package/dist/features/categories/schemas/index.js +2 -0
- package/dist/features/categories/types/index.d.ts +8 -0
- package/dist/features/categories/utils/taxonomy-visual.d.ts +16 -3
- package/dist/features/categories/utils/taxonomy-visual.js +26 -10
- package/dist/features/classified/components/ClassifiedDetailPageView.js +14 -10
- package/dist/features/contact/components/ContactPageView.d.ts +33 -1
- package/dist/features/contact/components/ContactPageView.js +58 -28
- package/dist/features/digital-codes/components/DigitalCodeDetailPageView.js +14 -10
- package/dist/features/grouped/components/GroupedListingDetailView.js +9 -1
- package/dist/features/grouped/schemas/firestore.d.ts +5 -0
- package/dist/features/homepage/actions/homepage-section-actions.d.ts +3 -3
- package/dist/features/homepage/components/CollectionCardsSection.d.ts +28 -6
- package/dist/features/homepage/components/CollectionCardsSection.js +43 -8
- package/dist/features/homepage/components/HowItWorksSection.d.ts +23 -6
- package/dist/features/homepage/components/HowItWorksSection.js +4 -4
- package/dist/features/homepage/components/PromoGrid.d.ts +31 -2
- package/dist/features/homepage/components/PromoGrid.js +12 -3
- package/dist/features/homepage/components/TestimonialsCarousel.d.ts +34 -2
- package/dist/features/homepage/components/TestimonialsCarousel.js +1 -1
- package/dist/features/homepage/components/index.d.ts +0 -20
- package/dist/features/homepage/components/index.js +0 -11
- package/dist/features/homepage/index.d.ts +0 -2
- package/dist/features/homepage/index.js +0 -2
- package/dist/features/homepage/lib/section-renderer.d.ts +9 -0
- package/dist/features/homepage/lib/section-renderer.js +202 -58
- package/dist/features/homepage/repository/homepage-sections.repository.d.ts +35 -3
- package/dist/features/homepage/repository/homepage-sections.repository.js +58 -8
- package/dist/features/homepage/schemas/firestore.d.ts +106 -3
- package/dist/features/homepage/schemas/firestore.js +32 -2
- package/dist/features/homepage/schemas/index.d.ts +36 -7
- package/dist/features/homepage/schemas/index.js +39 -27
- package/dist/features/homepage/server.d.ts +0 -3
- package/dist/features/homepage/server.js +0 -3
- package/dist/features/homepage/types/index.d.ts +0 -47
- package/dist/features/homepage/types/index.js +49 -0
- package/dist/features/layout/AppLayoutShell.js +1 -1
- package/dist/features/layout/BottomNavItem.js +1 -1
- package/dist/features/layout/BottomSheet.js +1 -1
- package/dist/features/layout/TitleBarLayout.js +1 -1
- package/dist/features/live/components/LiveItemDetailPageView.js +14 -10
- package/dist/features/media/hooks/useMedia.js +17 -0
- package/dist/features/media/repository/media-assets.repository.d.ts +46 -0
- package/dist/features/media/repository/media-assets.repository.js +31 -0
- package/dist/features/media/trust-signals.d.ts +85 -0
- package/dist/features/media/trust-signals.js +126 -0
- package/dist/features/parts/components/PartDetailPageView.d.ts +14 -1
- package/dist/features/parts/components/PartDetailPageView.js +2 -2
- package/dist/features/parts/components/PartsIndexPageView.d.ts +11 -2
- package/dist/features/parts/components/PartsIndexPageView.js +2 -2
- package/dist/features/parts/components/PartsSearchBox.d.ts +9 -0
- package/dist/features/parts/components/PartsSearchBox.js +57 -0
- package/dist/features/parts/schemas/firestore.d.ts +149 -3
- package/dist/features/parts/schemas/firestore.js +184 -0
- package/dist/features/payments/repository/payout.repository.d.ts +15 -0
- package/dist/features/payments/repository/payout.repository.js +21 -0
- package/dist/features/pre-orders/components/PreOrderDetailPageView.js +12 -18
- package/dist/features/pre-orders/components/PreOrdersIndexListing.js +1 -1
- package/dist/features/price-index/components/PriceIndexToolView.d.ts +24 -1
- package/dist/features/price-index/components/PriceIndexToolView.js +299 -17
- package/dist/features/price-index/lookup-target.d.ts +48 -0
- package/dist/features/price-index/lookup-target.js +107 -0
- package/dist/features/products/components/AvailabilityScopeHint.d.ts +22 -0
- package/dist/features/products/components/AvailabilityScopeHint.js +27 -0
- package/dist/features/products/components/CompareOverlay.d.ts +20 -2
- package/dist/features/products/components/CompareOverlay.js +23 -3
- package/dist/features/products/components/CustomSectionTabContent.d.ts +31 -0
- package/dist/features/products/components/CustomSectionTabContent.js +29 -3
- package/dist/features/products/components/GroupMemberPicker.d.ts +19 -1
- package/dist/features/products/components/GroupMemberPicker.js +46 -8
- package/dist/features/products/components/GroupSettingsPanel.d.ts +11 -1
- package/dist/features/products/components/GroupSettingsPanel.js +92 -3
- package/dist/features/products/components/PrizeDrawDetailPageView.js +1 -1
- package/dist/features/products/components/PrizeDrawEntryActions.d.ts +15 -1
- package/dist/features/products/components/PrizeDrawEntryActions.js +70 -8
- package/dist/features/products/components/ProductDetailPageView.js +81 -17
- package/dist/features/products/components/ProductForm.d.ts +13 -1
- package/dist/features/products/components/ProductForm.js +16 -2
- package/dist/features/products/components/ProductsIndexListing.d.ts +16 -1
- package/dist/features/products/components/ProductsIndexListing.js +3 -3
- package/dist/features/products/components/ShowGroupSection.js +15 -2
- package/dist/features/products/components/SparesListView.d.ts +7 -0
- package/dist/features/products/components/SparesListView.js +39 -0
- package/dist/features/products/components/SublistingCarouselSection.js +2 -1
- package/dist/features/products/constants/action-defs.d.ts +1 -0
- package/dist/features/products/constants/action-defs.js +1 -0
- package/dist/features/products/repository/products.repository.d.ts +99 -0
- package/dist/features/products/repository/products.repository.js +240 -18
- package/dist/features/products/schemas/firestore.d.ts +97 -4
- package/dist/features/products/schemas/firestore.js +104 -0
- package/dist/features/products/schemas/index.d.ts +10 -19
- package/dist/features/products/schemas/index.js +23 -6
- package/dist/features/products/types/index.d.ts +45 -1
- package/dist/features/products/utils/group-member-image.d.ts +46 -0
- package/dist/features/products/utils/group-member-image.js +4 -0
- package/dist/features/products/utils/listing-badge-variant.js +4 -0
- package/dist/features/reviews/components/ReviewsList.js +1 -1
- package/dist/features/scams/components/ScamProfileView.js +1 -1
- package/dist/features/search/components/EntityTypeahead.d.ts +44 -0
- package/dist/features/search/components/EntityTypeahead.js +92 -0
- package/dist/features/search/components/Search.d.ts +12 -1
- package/dist/features/search/components/Search.js +47 -3
- package/dist/features/search/components/SearchFacetRail.d.ts +11 -0
- package/dist/features/search/components/SearchFacetRail.js +92 -0
- package/dist/features/search/components/SearchResultsClient.d.ts +33 -0
- package/dist/features/search/components/SearchResultsClient.js +103 -0
- package/dist/features/search/components/SearchResultsPageView.d.ts +15 -1
- package/dist/features/search/components/SearchResultsPageView.js +2 -2
- package/dist/features/search/components/index.d.ts +0 -6
- package/dist/features/search/components/index.js +0 -3
- package/dist/features/search/hooks/useNavSuggestions.d.ts +13 -0
- package/dist/features/search/hooks/useScopedSearch.d.ts +34 -0
- package/dist/features/search/hooks/useScopedSearch.js +114 -0
- package/dist/features/search/hooks/useSiteSearch.d.ts +26 -0
- package/dist/features/search/hooks/useSiteSearch.js +149 -0
- package/dist/features/search/index.d.ts +0 -4
- package/dist/features/search/index.js +0 -4
- package/dist/features/search/manifest.d.ts +12 -0
- package/dist/features/search/manifest.js +17 -2
- package/dist/features/search/server.d.ts +0 -3
- package/dist/features/search/server.js +0 -3
- package/dist/features/seller/components/SellerListingTypeView.d.ts +1 -1
- package/dist/features/seller/components/SellerListingTypeView.js +20 -0
- package/dist/features/seller/components/SellerPayoutSettingsView.js +35 -14
- package/dist/features/seller/components/SellerProductShell.d.ts +1 -1
- package/dist/features/seller/components/SellerProductShell.js +2 -1
- package/dist/features/seller/components/SellerProductsView.js +3 -2
- package/dist/features/seller/components/SellerSidebar.js +1 -1
- package/dist/features/seller/components/SellerSparesView.d.ts +17 -0
- package/dist/features/seller/components/SellerSparesView.js +6 -0
- package/dist/features/seller/components/index.d.ts +2 -0
- package/dist/features/seller/components/index.js +1 -0
- package/dist/features/shell/CommandPalette.js +1 -1
- package/dist/features/sticker-trace/schemas/firestore.d.ts +19 -0
- package/dist/features/stores/components/StoreAuctionsListing.js +2 -1
- package/dist/features/stores/components/StoreDetailLayoutView.d.ts +1 -1
- package/dist/features/stores/components/StoreDetailLayoutView.js +7 -82
- package/dist/features/stores/components/StoreHeader.js +1 -2
- package/dist/features/stores/components/StoreSparesPageView.d.ts +27 -0
- package/dist/features/stores/components/StoreSparesPageView.js +48 -0
- package/dist/features/stores/schemas/firestore.d.ts +19 -0
- package/dist/features/tester/seed-data/authored/buying__spares-and-groups.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__spares-and-groups.js +96 -0
- package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.js +392 -45
- package/dist/features/tester/seed-data/authored/content-discovery__category-tabs-franchise-bundles.js +54 -32
- package/dist/features/tester/seed-data/authored/content-discovery__parts-database.js +3 -2
- package/dist/features/tester/seed-data/authored/content-discovery__price-index-and-compare.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__price-index-and-compare.js +73 -0
- package/dist/features/tester/seed-data/authored/content-discovery__site-wide-index.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__site-wide-index.js +340 -0
- package/dist/features/tester/seed-data/authored/index.js +16 -0
- package/dist/features/tester/seed-data/authored/search-and-nav__header-search.d.ts +1 -0
- package/dist/features/tester/seed-data/authored/search-and-nav__header-search.js +57 -0
- package/dist/features/tester/seed-data/authored/selling__spares-and-group-editing.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__spares-and-group-editing.js +77 -0
- package/dist/features/tester/seed-data/authored/tools__sticker-promote-to-listings.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/tools__sticker-promote-to-listings.js +58 -0
- package/dist/features/tester/seed-data/authored/tools__sticker-tracer.js +5 -4
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +384 -18
- package/dist/index.d.ts +17 -57
- package/dist/index.js +35 -96
- package/dist/next/routing/route-map.d.ts +42 -1
- package/dist/next/routing/route-map.js +45 -0
- package/dist/providers/db-firebase/base.repository.d.ts +22 -0
- package/dist/providers/db-firebase/base.repository.js +36 -0
- package/dist/schemas/registry.d.ts +15 -6
- package/dist/security/blind-index-tokens.d.ts +54 -0
- package/dist/security/blind-index-tokens.js +152 -0
- package/dist/security/index.d.ts +1 -1
- package/dist/security/index.js +1 -1
- package/dist/security/settings-encryption.d.ts +35 -0
- package/dist/security/settings-encryption.js +91 -0
- package/dist/seed/_helpers/brand-rows.js +38 -14
- package/dist/seed/_helpers/category-forest.js +73 -7
- package/dist/seed/_helpers/category-images-generated.d.ts +25 -6
- package/dist/seed/_helpers/category-images-generated.js +81 -6
- package/dist/seed/_helpers/category-models.d.ts +1 -1
- package/dist/seed/_helpers/category-models.js +7 -1
- package/dist/seed/_helpers/category-parts-glossary-map.js +8 -0
- package/dist/seed/_helpers/category-parts.d.ts +1 -1
- package/dist/seed/_helpers/category-parts.js +50 -2
- package/dist/seed/_helpers/character-features.d.ts +1 -1
- package/dist/seed/_helpers/character-features.js +2 -1
- package/dist/seed/_helpers/franchise-rows.js +10 -2
- package/dist/seed/_helpers/media.d.ts +47 -0
- package/dist/seed/_helpers/media.js +34 -0
- package/dist/seed/authenticity-knowledge-seed-data.d.ts +49 -5
- package/dist/seed/authenticity-knowledge-seed-data.js +10001 -549
- package/dist/seed/categories-seed-data.js +124 -20
- package/dist/seed/grouped-listings-seed-data.js +16 -0
- package/dist/seed/homepage-sections-seed-data.js +94 -5
- package/dist/seed/index.d.ts +2 -3
- package/dist/seed/index.js +2 -2
- package/dist/seed/manifest.js +3 -0
- package/dist/seed/media-assets-seed-data.d.ts +1 -1
- package/dist/seed/media-assets-seed-data.js +746 -196
- package/dist/seed/model-composition-seed-data.js +122 -6
- package/dist/seed/part-glossary-seed-data.d.ts +1 -1
- package/dist/seed/part-glossary-seed-data.js +37219 -463
- package/dist/seed/products-art-seed-data.js +7 -18
- package/dist/seed/products-auctions-seed-data.js +56 -47
- package/dist/seed/products-beyblade-x-seed-data.d.ts +2 -0
- package/dist/seed/products-beyblade-x-seed-data.js +476 -0
- package/dist/seed/products-catalogue-seed-data.d.ts +5 -5
- package/dist/seed/products-catalogue-seed-data.js +1500 -1240
- package/dist/seed/products-classifieds-seed-data.js +9 -27
- package/dist/seed/products-digital-codes-seed-data.js +9 -18
- package/dist/seed/products-live-items-seed-data.js +5 -13
- package/dist/seed/products-preorders-seed-data.js +67 -33
- package/dist/seed/products-prize-draws-seed-data.js +8 -17
- package/dist/seed/products-spares-seed-data.d.ts +2 -0
- package/dist/seed/products-spares-seed-data.js +368 -0
- package/dist/seed/products-standard-seed-data.js +39 -126
- package/dist/seed/products-stickers-seed-data.js +59 -15
- package/dist/seed/site-settings-seed-data.js +8 -0
- package/dist/seo/json-ld.d.ts +25 -0
- package/dist/seo/json-ld.js +28 -0
- package/dist/server-entry.d.ts +3 -1
- package/dist/server-entry.js +2 -2
- package/dist/server.d.ts +11 -9
- package/dist/server.js +35 -25
- package/dist/styles.css +202 -1
- package/dist/tailwind-input.css +31 -17
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/Accordion.js +1 -1
- package/dist/ui/components/Breadcrumb.js +1 -1
- package/dist/ui/components/DetailPageGallery.js +0 -2
- package/dist/ui/components/DetailPageHero.js +0 -1
- package/dist/ui/components/DetailPageTabs.js +1 -1
- package/dist/ui/components/Divider.js +3 -3
- package/dist/ui/components/GatedPrice.js +5 -1
- package/dist/ui/components/HorizontalScroller.js +1 -1
- package/dist/ui/components/ListingLayout.js +3 -3
- package/dist/ui/components/MediaTabs.style.css +81 -0
- package/dist/ui/components/Pagination.js +1 -1
- package/dist/ui/components/PendingValue.d.ts +45 -0
- package/dist/ui/components/PendingValue.js +7 -0
- package/dist/ui/components/Radio.style.css +119 -0
- package/dist/ui/components/RatingDisplay.js +2 -2
- package/dist/ui/components/SettingsSection.js +0 -2
- package/dist/ui/components/SiteLogo.js +3 -0
- package/dist/ui/components/SiteMark.js +3 -0
- package/dist/ui/components/SortDropdown.js +1 -1
- package/dist/ui/components/SpecTable.d.ts +58 -0
- package/dist/ui/components/SpecTable.js +8 -0
- package/dist/ui/components/StarRating.js +1 -3
- package/dist/ui/components/SummaryCard.js +1 -1
- package/dist/ui/components/index.style.css +1 -0
- package/dist/ui/icons/icon-registry.d.ts +1 -0
- package/dist/ui/icons/icon-registry.js +9 -1
- package/dist/ui/index.d.ts +4 -0
- package/dist/ui/index.js +2 -0
- package/dist/utils/search-txt-query.d.ts +12 -0
- package/dist/utils/search-txt-query.js +12 -0
- package/package.json +1 -1
- package/scripts/dedupe-peer-deps.mjs +18 -0
- package/scripts/seed-cli.mjs +250 -35
- package/scripts/verify-css-build.mjs +118 -37
- package/dist/_internal/server/features/search/actions.d.ts +0 -7
- package/dist/_internal/server/features/search/actions.js +0 -21
- package/dist/_internal/server/features/search/data.d.ts +0 -15
- package/dist/_internal/server/features/search/data.js +0 -18
- package/dist/_internal/server/features/search/index.d.ts +0 -3
- package/dist/_internal/server/features/search/index.js +0 -2
- package/dist/features/homepage/api/[id]/route.d.ts +0 -23
- package/dist/features/homepage/api/[id]/route.js +0 -103
- package/dist/features/homepage/api/route.d.ts +0 -14
- package/dist/features/homepage/api/route.js +0 -140
- package/dist/features/homepage/api/sections/[id]/route.d.ts +0 -26
- package/dist/features/homepage/api/sections/[id]/route.js +0 -95
- package/dist/features/homepage/api/sections/route.d.ts +0 -13
- package/dist/features/homepage/api/sections/route.js +0 -82
- package/dist/features/homepage/components/AdvertisementBanner.d.ts +0 -14
- package/dist/features/homepage/components/AdvertisementBanner.js +0 -35
- package/dist/features/homepage/components/BeforeAfterCard.d.ts +0 -9
- package/dist/features/homepage/components/BeforeAfterCard.js +0 -73
- package/dist/features/homepage/components/FeaturedResultsSection.d.ts +0 -17
- package/dist/features/homepage/components/FeaturedResultsSection.js +0 -17
- package/dist/features/homepage/components/HeroBanner.d.ts +0 -7
- package/dist/features/homepage/components/HeroBanner.js +0 -43
- package/dist/features/homepage/components/HeroSection.d.ts +0 -7
- package/dist/features/homepage/components/HeroSection.js +0 -6
- package/dist/features/homepage/components/HomepageSkeleton.d.ts +0 -2
- package/dist/features/homepage/components/HomepageSkeleton.js +0 -21
- package/dist/features/homepage/components/HomepageView.d.ts +0 -25
- package/dist/features/homepage/components/HomepageView.js +0 -5
- package/dist/features/homepage/components/NewsletterBanner.d.ts +0 -23
- package/dist/features/homepage/components/NewsletterBanner.js +0 -37
- package/dist/features/homepage/components/SiteFeaturesSection.d.ts +0 -14
- package/dist/features/homepage/components/SiteFeaturesSection.js +0 -11
- package/dist/features/homepage/components/TrustBadges.d.ts +0 -6
- package/dist/features/homepage/components/TrustBadges.js +0 -46
- package/dist/features/homepage/components/TrustIndicatorsSection.d.ts +0 -12
- package/dist/features/homepage/components/TrustIndicatorsSection.js +0 -11
- package/dist/features/homepage/hooks/useHomepage.d.ts +0 -11
- package/dist/features/homepage/hooks/useHomepage.js +0 -17
- package/dist/features/homepage/hooks/useHomepageSections.d.ts +0 -2
- package/dist/features/homepage/hooks/useHomepageSections.js +0 -10
- package/dist/features/homepage/repository/homepage.repository.d.ts +0 -11
- package/dist/features/homepage/repository/homepage.repository.js +0 -25
- package/dist/features/search/actions/index.d.ts +0 -1
- package/dist/features/search/actions/index.js +0 -1
- package/dist/features/search/actions/search-actions.d.ts +0 -18
- package/dist/features/search/actions/search-actions.js +0 -43
- package/dist/features/search/api/route.d.ts +0 -22
- package/dist/features/search/api/route.js +0 -128
- package/dist/features/search/columns/index.d.ts +0 -17
- package/dist/features/search/columns/index.js +0 -49
- package/dist/features/search/components/SearchFiltersRow.d.ts +0 -22
- package/dist/features/search/components/SearchFiltersRow.js +0 -21
- package/dist/features/search/components/SearchResultsSection.d.ts +0 -53
- package/dist/features/search/components/SearchResultsSection.js +0 -35
- package/dist/features/search/components/SearchView.d.ts +0 -27
- package/dist/features/search/components/SearchView.js +0 -8
- package/dist/features/search/hooks/useSearch.d.ts +0 -21
- package/dist/features/search/hooks/useSearch.js +0 -33
- package/dist/features/search/repository/search.repository.d.ts +0 -14
- package/dist/features/search/repository/search.repository.js +0 -59
- package/dist/features/search/schemas/index.d.ts +0 -70
- package/dist/features/search/schemas/index.js +0 -36
- package/dist/features/search/types/index.d.ts +0 -48
- package/dist/features/stores/components/StoreScopedSearch.d.ts +0 -17
- package/dist/features/stores/components/StoreScopedSearch.js +0 -27
- package/dist/seed/defaults/homepage-sections.d.ts +0 -2
- package/dist/seed/defaults/homepage-sections.js +0 -60
- package/dist/seed/factories/homepage-section.factory.d.ts +0 -10
- package/dist/seed/factories/homepage-section.factory.js +0 -13
- /package/dist/{features/search/types/index.js → _internal/shared/listing-types/spares/og.d.ts} +0 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { isListingTypeEnabled } from "../../../shared/listing-types/feature-flags";
|
|
2
|
+
import { type ListingTabCountResult } from "../products/listing-tab-counts";
|
|
3
|
+
type SiteSettingsSnapshot = Parameters<typeof isListingTypeEnabled>[1];
|
|
4
|
+
export interface StoreTabLink {
|
|
5
|
+
value: string;
|
|
6
|
+
label: string;
|
|
7
|
+
href: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ResolvedStoreTabs {
|
|
10
|
+
/** Listing-type tabs with something in them, in `STORE_PAGE_TABS` order. */
|
|
11
|
+
dropdownTabs: StoreTabLink[];
|
|
12
|
+
/** Coupons (if any), Reviews (if any), About — always non-empty. */
|
|
13
|
+
tabs: StoreTabLink[];
|
|
14
|
+
/**
|
|
15
|
+
* Both numbers, because they answer different questions: `available` is what
|
|
16
|
+
* each tab badges, `total` is what decides whether the tab exists at all.
|
|
17
|
+
* See `ListingTabCountResult`.
|
|
18
|
+
*/
|
|
19
|
+
listingCounts: ListingTabCountResult;
|
|
20
|
+
couponsCount: number;
|
|
21
|
+
reviewsCount: number;
|
|
22
|
+
}
|
|
23
|
+
export declare function resolveStoreTabs(storeSlug: string, storeId: string | undefined, settings: SiteSettingsSnapshot): Promise<ResolvedStoreTabs>;
|
|
24
|
+
/**
|
|
25
|
+
* Where the bare `/stores/[slug]` route should land: the first listing-type
|
|
26
|
+
* tab holding anything, else Coupons, else Reviews, else About. `about` is
|
|
27
|
+
* always present in `tabs`, so this never falls through to nothing.
|
|
28
|
+
*/
|
|
29
|
+
export declare function getDefaultStoreTabPath(storeSlug: string, storeId: string | undefined, settings: SiteSettingsSnapshot): Promise<string>;
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* 🛑 Deliberately NO `"use server"`. That directive marks every export as a
|
|
3
|
+
* client-callable RPC endpoint, and these are not — they are read helpers
|
|
4
|
+
* invoked from a Server Component (`StoreDetailLayoutView`) and a server
|
|
5
|
+
* page (`/stores/[slug]`). Declaring it anyway also obliges every export to
|
|
6
|
+
* return `ActionResult<T>` (`audit-server-action-envelope`), which would
|
|
7
|
+
* wrap a path string in an envelope nobody unwraps. The sibling helpers
|
|
8
|
+
* this file sits beside — `adapters.ts`, `denormalize.ts` and
|
|
9
|
+
* `listing-tab-counts.ts`, which it calls — carry no directive either.
|
|
10
|
+
*
|
|
11
|
+
* WHY: `StoreDetailLayoutView`'s nav bar and the bare `/stores/[slug]`
|
|
12
|
+
* redirect both need "which tabs does this store actually have
|
|
13
|
+
* something in, and in what order". Before this file the redirect
|
|
14
|
+
* didn't ask the question at all — it always sent a visitor to
|
|
15
|
+
* `/products`, even for a store with zero products (and nothing else),
|
|
16
|
+
* landing on a tab that isn't even in the nav bar. Computing the answer
|
|
17
|
+
* twice (once per caller) is exactly the duplicated-predicate shape
|
|
18
|
+
* Root Cause #73 warns about, so it lives in one place.
|
|
19
|
+
* WHAT: `resolveStoreTabs` — every visible tab for a store, in priority
|
|
20
|
+
* order (listing types in `STORE_PAGE_TABS` order, then Coupons, then
|
|
21
|
+
* Reviews, then About last). `getDefaultStoreTabPath` picks the first
|
|
22
|
+
* one — the correct landing page for a store with no products.
|
|
23
|
+
*/
|
|
24
|
+
import { sieveAnd, sieveFilter, SIEVE_OP } from "../../../../utils/sieve-builder.js";
|
|
25
|
+
import { couponsRepository, reviewRepository } from "../../../../repositories/index.js";
|
|
26
|
+
import { ROUTES } from "../../../../next/routing/route-map.js";
|
|
27
|
+
import { STORE_PAGE_TABS } from "../../../../features/products/constants/listing-tabs.js";
|
|
28
|
+
import { isListingTypeEnabled, isCategoryTypeEnabled } from "../../../shared/listing-types/feature-flags.js";
|
|
29
|
+
import { pluginFor } from "../../../shared/listing-types/_registry.js";
|
|
30
|
+
import { listingTabCounts, } from "../products/listing-tab-counts.js";
|
|
31
|
+
function tabLabel(base, count) {
|
|
32
|
+
if (!count)
|
|
33
|
+
return base;
|
|
34
|
+
return `${base} (${count.toLocaleString()})`;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* tabSlug -> route builder. Mirrors `ROUTES.PUBLIC.STORE_*` exactly.
|
|
38
|
+
*
|
|
39
|
+
* 🛑 `spares` was missing here until this file was added, which meant
|
|
40
|
+
* `visibleStoreTabs` could include a tab this map had no builder for the
|
|
41
|
+
* moment a store's spares count went above zero — `STORE_LISTING_HREF[tab.id]`
|
|
42
|
+
* would resolve to `undefined`, and calling it as a function would throw.
|
|
43
|
+
* `/stores/[storeSlug]/spares/page.tsx` is a real route; the href map just
|
|
44
|
+
* never named it.
|
|
45
|
+
*/
|
|
46
|
+
const STORE_LISTING_HREF = {
|
|
47
|
+
products: (slug) => String(ROUTES.PUBLIC.STORE_PRODUCTS(slug)),
|
|
48
|
+
auctions: (slug) => String(ROUTES.PUBLIC.STORE_AUCTIONS(slug)),
|
|
49
|
+
"pre-orders": (slug) => String(ROUTES.PUBLIC.STORE_PRE_ORDERS(slug)),
|
|
50
|
+
"prize-draws": (slug) => String(ROUTES.PUBLIC.STORE_PRIZE_DRAWS(slug)),
|
|
51
|
+
bundles: (slug) => String(ROUTES.PUBLIC.STORE_BUNDLES(slug)),
|
|
52
|
+
classifieds: (slug) => String(ROUTES.PUBLIC.STORE_CLASSIFIEDS(slug)),
|
|
53
|
+
"digital-codes": (slug) => String(ROUTES.PUBLIC.STORE_DIGITAL_CODES(slug)),
|
|
54
|
+
live: (slug) => String(ROUTES.PUBLIC.STORE_LIVE(slug)),
|
|
55
|
+
// Combined art + stickers, mirroring the public /art page. This used to
|
|
56
|
+
// point at STORE_PRODUCTS, which filters to `standard` — so the tab showed
|
|
57
|
+
// a real non-zero count and landed on a page with none of those items.
|
|
58
|
+
art: (slug) => String(ROUTES.PUBLIC.STORE_ART(slug)),
|
|
59
|
+
spares: (slug) => String(ROUTES.PUBLIC.STORE_SPARES(slug)),
|
|
60
|
+
};
|
|
61
|
+
export async function resolveStoreTabs(storeSlug, storeId, settings) {
|
|
62
|
+
const [listingCounts, couponsCount, reviewsCount] = storeId
|
|
63
|
+
? await Promise.all([
|
|
64
|
+
listingTabCounts(STORE_PAGE_TABS, { storeId }),
|
|
65
|
+
// audit-public-test-data-ok: a COUNT of the store's own coupons, and
|
|
66
|
+
// `CouponDocument` carries no isTestData field — there is nothing to strip.
|
|
67
|
+
couponsRepository
|
|
68
|
+
.list({ filters: sieveAnd(sieveFilter("storeId", SIEVE_OP.EQ, storeId), sieveFilter("validity.isActive", SIEVE_OP.EQ, "true")), page: 1, pageSize: 1 })
|
|
69
|
+
.then((r) => r.total)
|
|
70
|
+
.catch(() => 0),
|
|
71
|
+
reviewRepository
|
|
72
|
+
.listAll({ filters: sieveAnd(sieveFilter("storeId", SIEVE_OP.EQ, storeId), sieveFilter("status", SIEVE_OP.EQ, "approved")), page: 1, pageSize: 1 })
|
|
73
|
+
.then((r) => r.total)
|
|
74
|
+
.catch(() => 0),
|
|
75
|
+
])
|
|
76
|
+
: [{ available: {}, total: {} }, 0, 0];
|
|
77
|
+
const visibleStoreTabs = STORE_PAGE_TABS.filter((tab) => {
|
|
78
|
+
if (tab.id === "bundles") {
|
|
79
|
+
if (!isCategoryTypeEnabled("bundle", settings))
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
else if (tab.id === pluginFor("art").tabSlug) {
|
|
83
|
+
// Combined tab — visible if either underlying listing type is enabled.
|
|
84
|
+
if (!(isListingTypeEnabled("art", settings) || isListingTypeEnabled("stickers", settings)))
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
else if (tab.listingType) {
|
|
88
|
+
if (!isListingTypeEnabled(tab.listingType, settings))
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
// A store with zero items of a given listing type shouldn't offer a tab
|
|
92
|
+
// that leads to an empty page. `undefined` means the count query FAILED,
|
|
93
|
+
// not zero, so the tab stays visible rather than hiding real stock
|
|
94
|
+
// behind a swallowed error (Root Cause #59).
|
|
95
|
+
// TOTAL, not the badge: a tab whose rows have all ended still has an
|
|
96
|
+
// archive behind the Ended/All scopes, and hiding it would strand that.
|
|
97
|
+
const count = listingCounts.total[tab.id];
|
|
98
|
+
return count === undefined || count > 0;
|
|
99
|
+
});
|
|
100
|
+
const dropdownTabs = visibleStoreTabs.map((tab) => ({
|
|
101
|
+
value: tab.id,
|
|
102
|
+
label: tabLabel(tab.label, listingCounts.available[tab.id]),
|
|
103
|
+
href: STORE_LISTING_HREF[tab.id](storeSlug),
|
|
104
|
+
}));
|
|
105
|
+
const tabs = [
|
|
106
|
+
...(couponsCount > 0
|
|
107
|
+
? [{ value: "coupons", label: tabLabel("Coupons", couponsCount), href: String(ROUTES.PUBLIC.STORE_COUPONS(storeSlug)) }]
|
|
108
|
+
: []),
|
|
109
|
+
...(reviewsCount > 0
|
|
110
|
+
? [{ value: "reviews", label: tabLabel("Reviews", reviewsCount), href: String(ROUTES.PUBLIC.STORE_REVIEWS(storeSlug)) }]
|
|
111
|
+
: []),
|
|
112
|
+
{ value: "about", label: "About", href: String(ROUTES.PUBLIC.STORE_ABOUT(storeSlug)) },
|
|
113
|
+
];
|
|
114
|
+
return { dropdownTabs, tabs, listingCounts, couponsCount, reviewsCount };
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Where the bare `/stores/[slug]` route should land: the first listing-type
|
|
118
|
+
* tab holding anything, else Coupons, else Reviews, else About. `about` is
|
|
119
|
+
* always present in `tabs`, so this never falls through to nothing.
|
|
120
|
+
*/
|
|
121
|
+
export async function getDefaultStoreTabPath(storeSlug, storeId, settings) {
|
|
122
|
+
const { dropdownTabs, tabs } = await resolveStoreTabs(storeSlug, storeId, settings);
|
|
123
|
+
return (dropdownTabs[0] ?? tabs[0]).href;
|
|
124
|
+
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
/** Default ListingCheckoutRule hook implementations. */
|
|
2
|
-
import { STANDARD_MAX_QTY_PER_LINE } from "./_limits.js";
|
|
3
2
|
export const DEFAULT_LISTING_RULE = {
|
|
4
3
|
purchaseable: true,
|
|
5
4
|
cartEligible: true,
|
|
6
5
|
cartIneligibleHint: "This listing type cannot be added to the cart.",
|
|
7
6
|
requiresShippingAddress: true,
|
|
8
7
|
nonRefundable: false,
|
|
9
|
-
maxQuantityPerLine: STANDARD_MAX_QTY_PER_LINE,
|
|
10
8
|
canMergeWithSameProduct: true,
|
|
11
9
|
maxLinesPerOrder: Infinity,
|
|
12
10
|
refundPolicy: { full: true, partial: true, partialGranularity: "item" },
|
|
@@ -28,5 +28,18 @@ export declare const PRIZE_DRAW_DURATION_DAYS_MIN = 1;
|
|
|
28
28
|
export declare const PRIZE_DRAW_DURATION_DAYS_MAX = 15;
|
|
29
29
|
/** Maximum qty per bundle purchase (bundles are always single-shot direct buys). */
|
|
30
30
|
export declare const BUNDLE_MAX_QTY_PER_TX = 1;
|
|
31
|
-
/**
|
|
31
|
+
/**
|
|
32
|
+
* Max quantity on a single cart line.
|
|
33
|
+
*
|
|
34
|
+
* 🛑 It now IS the enforcement. It used to say "enforced at addToCart" while
|
|
35
|
+
* the actual limit was four hand-written `.max(99)` literals that never
|
|
36
|
+
* referenced it — so the constant was documentation nobody read and the rule
|
|
37
|
+
* was a magic number in four places. The cart schemas import it.
|
|
38
|
+
*
|
|
39
|
+
* Its other reader, `ListingCheckoutRule.maxQuantityPerLine`, was DELETED in
|
|
40
|
+
* the same change: that field was set by auction, offer and prize-draw and read
|
|
41
|
+
* by nothing at all, and it contradicted the feature it appeared to govern —
|
|
42
|
+
* prize-draw set it to 1 while `splitMultipleOrders` right beside it existed
|
|
43
|
+
* only to chunk a quantity of 7 into [3,3,1].
|
|
44
|
+
*/
|
|
32
45
|
export declare const STANDARD_MAX_QTY_PER_LINE = 99;
|
|
@@ -28,5 +28,18 @@ export const PRIZE_DRAW_DURATION_DAYS_MIN = 1;
|
|
|
28
28
|
export const PRIZE_DRAW_DURATION_DAYS_MAX = 15;
|
|
29
29
|
/** Maximum qty per bundle purchase (bundles are always single-shot direct buys). */
|
|
30
30
|
export const BUNDLE_MAX_QTY_PER_TX = 1;
|
|
31
|
-
/**
|
|
31
|
+
/**
|
|
32
|
+
* Max quantity on a single cart line.
|
|
33
|
+
*
|
|
34
|
+
* 🛑 It now IS the enforcement. It used to say "enforced at addToCart" while
|
|
35
|
+
* the actual limit was four hand-written `.max(99)` literals that never
|
|
36
|
+
* referenced it — so the constant was documentation nobody read and the rule
|
|
37
|
+
* was a magic number in four places. The cart schemas import it.
|
|
38
|
+
*
|
|
39
|
+
* Its other reader, `ListingCheckoutRule.maxQuantityPerLine`, was DELETED in
|
|
40
|
+
* the same change: that field was set by auction, offer and prize-draw and read
|
|
41
|
+
* by nothing at all, and it contradicted the feature it appeared to govern —
|
|
42
|
+
* prize-draw set it to 1 while `splitMultipleOrders` right beside it existed
|
|
43
|
+
* only to chunk a quantity of 7 into [3,3,1].
|
|
44
|
+
*/
|
|
32
45
|
export const STANDARD_MAX_QTY_PER_LINE = 99;
|
|
@@ -20,6 +20,7 @@ import { digitalCodeRule } from "./digital-code.rule.js";
|
|
|
20
20
|
import { liveRule } from "./live.rule.js";
|
|
21
21
|
import { artRule } from "./art.rule.js";
|
|
22
22
|
import { stickersRule } from "./stickers.rule.js";
|
|
23
|
+
import { sparesRule } from "./spares.rule.js";
|
|
23
24
|
export const CHECKOUT_RULES = {
|
|
24
25
|
standard: standardRule,
|
|
25
26
|
auction: auctionRule,
|
|
@@ -30,6 +31,7 @@ export const CHECKOUT_RULES = {
|
|
|
30
31
|
live: liveRule,
|
|
31
32
|
art: artRule,
|
|
32
33
|
stickers: stickersRule,
|
|
34
|
+
spares: sparesRule,
|
|
33
35
|
};
|
|
34
36
|
export const CATEGORY_CHECKOUT_RULES = {
|
|
35
37
|
bundle: bundleRule,
|
|
@@ -4,7 +4,15 @@ export const auctionRule = {
|
|
|
4
4
|
orderType: "auction",
|
|
5
5
|
cartEligible: false, // bid-only; add-to-cart is blocked at the action layer
|
|
6
6
|
cartIneligibleHint: "Place a bid on the auction page instead.",
|
|
7
|
-
|
|
7
|
+
/*
|
|
8
|
+
* 🛑 cod + cash, NOT emi. An auction win is a committed sale of a unique lot:
|
|
9
|
+
* a buyer who never pays on delivery costs the seller the item and the
|
|
10
|
+
* auction both, and there is no second-highest bidder to fall back to once
|
|
11
|
+
* it has been marked sold. EMI is confirmed-at-order financing rather than a
|
|
12
|
+
* deferred payment, so it carries none of that risk and stays available.
|
|
13
|
+
*/
|
|
14
|
+
blockedPaymentMethods: ["cod", "cash"],
|
|
15
|
+
blockedPaymentMessage: "An auction win cannot be paid for on delivery or in cash — the lot is one of a kind and is held for you from the moment the auction closes.",
|
|
8
16
|
canMergeWithSameProduct: false,
|
|
9
17
|
refundPolicy: { full: true, partial: false, partialGranularity: "none" },
|
|
10
18
|
splitKey: (item) => `auction:${item.itemId}`,
|
|
@@ -3,4 +3,17 @@ export const bundleRule = {
|
|
|
3
3
|
cartEligible: false, // direct-checkout-only; addBundleToCart has been removed
|
|
4
4
|
orderType: "standard", // bundle orders resolve to standard orderType
|
|
5
5
|
requiresShippingAddress: true,
|
|
6
|
+
/*
|
|
7
|
+
* 🛑 cod + cash, NOT emi. A bundle is priced BELOW the sum of its members —
|
|
8
|
+
* that discount is the whole product — so a no-show on delivery costs the
|
|
9
|
+
* seller several items at once, and the bundle has meanwhile been held out of
|
|
10
|
+
* every member's own availability. EMI is confirmed-at-order financing rather
|
|
11
|
+
* than a deferred payment, so it carries none of that and stays available.
|
|
12
|
+
*
|
|
13
|
+
* 🛑 Honoured by `assertPaymentMethodAllowed`, NOT by `runSyncPreflight` —
|
|
14
|
+
* which skips multi-member lines, and a bundle line is always one. A value
|
|
15
|
+
* here relying on preflight would be a silent no-op.
|
|
16
|
+
*/
|
|
17
|
+
blockedPaymentMethods: ["cod", "cash"],
|
|
18
|
+
blockedPaymentMessage: "Bundles cannot be paid for on delivery or in cash — a bundle is priced below the sum of its parts and is reserved when you order.",
|
|
6
19
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export type { ListingCheckoutRule, CategoryCheckoutRule, CartItemProductPair, OrderItemInput, RefundPolicy, } from "./types";
|
|
2
2
|
export { CHECKOUT_RULES, CATEGORY_CHECKOUT_RULES, getListingRule, getCategoryRule, pickOrderType, getSplitKey, runSyncPreflight, } from "./_registry";
|
|
3
|
+
export { assertPaymentMethodAllowed, blockedMethodsForCart, type BlockedMethod, } from "./payment-gate";
|
|
3
4
|
export { CART_MAX_ITEMS, CHECKOUT_MAX_ORDERS_PER_TX, PRIZE_DRAW_MAX_REVEALS_PER_ORDER, PRIZE_DRAW_DURATION_DAYS_MIN, PRIZE_DRAW_DURATION_DAYS_MAX, BUNDLE_MAX_QTY_PER_TX, STANDARD_MAX_QTY_PER_LINE, } from "./_limits";
|
|
4
5
|
export { standardRule } from "./standard.rule";
|
|
5
6
|
export { auctionRule } from "./auction.rule";
|
|
@@ -12,3 +13,4 @@ export { digitalCodeRule } from "./digital-code.rule";
|
|
|
12
13
|
export { liveRule } from "./live.rule";
|
|
13
14
|
export { artRule } from "./art.rule";
|
|
14
15
|
export { stickersRule } from "./stickers.rule";
|
|
16
|
+
export { sparesRule } from "./spares.rule";
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
export { CHECKOUT_RULES, CATEGORY_CHECKOUT_RULES, getListingRule, getCategoryRule, pickOrderType, getSplitKey, runSyncPreflight, } from "./_registry.js";
|
|
2
|
+
/*
|
|
3
|
+
* The payment gate is a SEPARATE module from `_registry`, on purpose: it is the
|
|
4
|
+
* one rule check that cannot be expressed as a per-listing-type pass over
|
|
5
|
+
* single-member lines, which is all `runSyncPreflight` can see. Keeping them
|
|
6
|
+
* apart is what stops someone folding it back into preflight, where it would
|
|
7
|
+
* silently stop covering bundles and grouped lines.
|
|
8
|
+
*/
|
|
9
|
+
export { assertPaymentMethodAllowed, blockedMethodsForCart, } from "./payment-gate.js";
|
|
2
10
|
export { CART_MAX_ITEMS, CHECKOUT_MAX_ORDERS_PER_TX, PRIZE_DRAW_MAX_REVEALS_PER_ORDER, PRIZE_DRAW_DURATION_DAYS_MIN, PRIZE_DRAW_DURATION_DAYS_MAX, BUNDLE_MAX_QTY_PER_TX, STANDARD_MAX_QTY_PER_LINE, } from "./_limits.js";
|
|
3
11
|
// Individual rules — exported for tests and direct access.
|
|
4
12
|
export { standardRule } from "./standard.rule.js";
|
|
@@ -12,3 +20,4 @@ export { digitalCodeRule } from "./digital-code.rule.js";
|
|
|
12
20
|
export { liveRule } from "./live.rule.js";
|
|
13
21
|
export { artRule } from "./art.rule.js";
|
|
14
22
|
export { stickersRule } from "./stickers.rule.js";
|
|
23
|
+
export { sparesRule } from "./spares.rule.js";
|
|
@@ -2,7 +2,6 @@ import { DEFAULT_LISTING_RULE } from "./_defaults.js";
|
|
|
2
2
|
export const offerRule = {
|
|
3
3
|
...DEFAULT_LISTING_RULE,
|
|
4
4
|
orderType: "offer",
|
|
5
|
-
maxQuantityPerLine: 1,
|
|
6
5
|
canMergeWithSameProduct: false,
|
|
7
6
|
refundPolicy: { full: true, partial: false, partialGranularity: "none" },
|
|
8
7
|
splitKey: (item) => `offer:${item.itemId}`,
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { CartItemDocument } from "../../../../features/cart/schemas/firestore";
|
|
2
|
+
import type { ProductDocument } from "../../../../features/products/schemas/firestore";
|
|
3
|
+
import { type CheckoutPaymentMethod } from "../../features/checkout/config";
|
|
4
|
+
/** Why one method is unavailable, and which listing said so. */
|
|
5
|
+
export interface BlockedMethod {
|
|
6
|
+
/** The listing's own wording when it has one, else a generated sentence. */
|
|
7
|
+
message: string;
|
|
8
|
+
/** For logs and for the generated wording. */
|
|
9
|
+
label: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Which methods this cart forbids.
|
|
13
|
+
*
|
|
14
|
+
* Returned rather than thrown so the same answer can also DISABLE a payment
|
|
15
|
+
* control — one source for the refusal and the affordance, instead of a
|
|
16
|
+
* client-side guess that drifts from the server.
|
|
17
|
+
*/
|
|
18
|
+
export declare function blockedMethodsForCart(items: readonly CartItemDocument[], productById: ReadonlyMap<string, ProductDocument>): Map<CheckoutPaymentMethod, BlockedMethod>;
|
|
19
|
+
/**
|
|
20
|
+
* Throw when the chosen method is forbidden by anything in the cart.
|
|
21
|
+
*
|
|
22
|
+
* One error, not one per offending line: a buyer changes the payment method
|
|
23
|
+
* once, and listing every blocked item would be a wall of text about a single
|
|
24
|
+
* decision.
|
|
25
|
+
*/
|
|
26
|
+
export declare function assertPaymentMethodAllowed(items: readonly CartItemDocument[], productById: ReadonlyMap<string, ProductDocument>, paymentMethod: CheckoutPaymentMethod | undefined): void;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: Some listings must not be bought with a pay-later method. An auction win
|
|
3
|
+
* or a bundle is a committed sale — a buyer who never pays on delivery
|
|
4
|
+
* costs the seller the lot, and for a unique auction lot there is no
|
|
5
|
+
* second-highest bidder to fall back on once it is marked sold. The rule
|
|
6
|
+
* registry has a field for this (`blockedPaymentMethods`) and nothing
|
|
7
|
+
* reachable enforced it for every line.
|
|
8
|
+
* WHAT: One cart-wide payment check, run BEFORE the transaction.
|
|
9
|
+
*
|
|
10
|
+
* 🛑 `runSyncPreflight` STRUCTURALLY CANNOT DO THIS, and that is not a bug in
|
|
11
|
+
* preflight. It does `if (isMultiMemberLine(pair.item)) continue;` for a good
|
|
12
|
+
* reason: a bundle or grouped line's own `listingType` describes the WRAPPER,
|
|
13
|
+
* not its members, so a per-type rule applied there would be applied to the
|
|
14
|
+
* wrong thing. Both of its call sites repeat the skip independently, and the
|
|
15
|
+
* online path additionally reduces each line to `getCartItemMemberIds(item)[0]`
|
|
16
|
+
* — its FIRST member only. So a `blockedPaymentMethods` set on `bundleRule` and
|
|
17
|
+
* left to preflight would be a silent no-op: the field would be set, reviewed,
|
|
18
|
+
* and never read.
|
|
19
|
+
*
|
|
20
|
+
* This resolves every line to ALL its members, so a grouped line containing one
|
|
21
|
+
* blocked listing is caught.
|
|
22
|
+
*
|
|
23
|
+
* 🛑 IT RUNS OUTSIDE THE TRANSACTION. Preflight is invoked inside the
|
|
24
|
+
* transaction callback, so a payment-method rejection there spends a full
|
|
25
|
+
* transaction attempt to produce an answer that depends on nothing the
|
|
26
|
+
* transaction reads.
|
|
27
|
+
*
|
|
28
|
+
* EXPORTS: assertPaymentMethodAllowed, blockedMethodsForCart
|
|
29
|
+
*
|
|
30
|
+
* @tag domain:checkout
|
|
31
|
+
* @tag layer:shared
|
|
32
|
+
* @tag pattern:none
|
|
33
|
+
* @tag access:isomorphic
|
|
34
|
+
* @tag consumers:server/features/checkout
|
|
35
|
+
* @tag sideEffects:none
|
|
36
|
+
*/
|
|
37
|
+
import { ValidationError } from "../../../../errors/index.js";
|
|
38
|
+
import { CHECKOUT_PAYMENT_METHODS, } from "../../features/checkout/config.js";
|
|
39
|
+
import { getCartItemMemberIds } from "../line-members.js";
|
|
40
|
+
import { getCategoryRule, getListingRule } from "./_registry.js";
|
|
41
|
+
/**
|
|
42
|
+
* Which methods this cart forbids.
|
|
43
|
+
*
|
|
44
|
+
* Returned rather than thrown so the same answer can also DISABLE a payment
|
|
45
|
+
* control — one source for the refusal and the affordance, instead of a
|
|
46
|
+
* client-side guess that drifts from the server.
|
|
47
|
+
*/
|
|
48
|
+
export function blockedMethodsForCart(items, productById) {
|
|
49
|
+
const blocked = new Map();
|
|
50
|
+
const claim = (methods, label, message) => {
|
|
51
|
+
for (const m of methods ?? []) {
|
|
52
|
+
// First claimant wins, so the message names a real listing rather than
|
|
53
|
+
// whichever happened to be last in the cart.
|
|
54
|
+
if (blocked.has(m))
|
|
55
|
+
continue;
|
|
56
|
+
blocked.set(m, {
|
|
57
|
+
label,
|
|
58
|
+
message: message ??
|
|
59
|
+
`"${label}" cannot be paid for with ${PAYMENT_METHOD_LABEL[m] ?? m}.`,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
for (const item of items) {
|
|
64
|
+
/*
|
|
65
|
+
* A bundle's restriction lives on its CategoryCheckoutRule, not on any
|
|
66
|
+
* listing type — its members are ordinary products whose own types would
|
|
67
|
+
* otherwise answer for it. Checked first for that reason.
|
|
68
|
+
*/
|
|
69
|
+
if (item.bundleCategorySlug) {
|
|
70
|
+
const rule = getCategoryRule("bundle");
|
|
71
|
+
claim(rule?.blockedPaymentMethods, item.groupTitle ?? item.productTitle ?? "this bundle", rule?.blockedPaymentMessage);
|
|
72
|
+
}
|
|
73
|
+
/*
|
|
74
|
+
* EVERY member, not the first. `getCartItemMemberIds` returns the line's
|
|
75
|
+
* own product for a plain line and all members for a bundle or group, so
|
|
76
|
+
* one blocked member blocks the line.
|
|
77
|
+
*/
|
|
78
|
+
for (const productId of getCartItemMemberIds(item)) {
|
|
79
|
+
const product = productById.get(productId);
|
|
80
|
+
/*
|
|
81
|
+
* An unresolved member is NOT treated as unrestricted here. It is left to
|
|
82
|
+
* the stock and existence checks that already run on the same cart and
|
|
83
|
+
* fail loudly — inventing a payment refusal for a missing product would
|
|
84
|
+
* report the wrong problem.
|
|
85
|
+
*/
|
|
86
|
+
if (!product)
|
|
87
|
+
continue;
|
|
88
|
+
const type = (product.listingType ?? "standard");
|
|
89
|
+
const rule = getListingRule(type);
|
|
90
|
+
claim(rule.blockedPaymentMethods, product.title ?? type, rule.blockedPaymentMessage);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return blocked;
|
|
94
|
+
}
|
|
95
|
+
/** Human wording for the generated message. */
|
|
96
|
+
const PAYMENT_METHOD_LABEL = {
|
|
97
|
+
cod: "cash on delivery",
|
|
98
|
+
cash: "cash on pickup",
|
|
99
|
+
emi: "EMI",
|
|
100
|
+
online: "online payment",
|
|
101
|
+
upi_manual: "manual bank/UPI transfer",
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* Throw when the chosen method is forbidden by anything in the cart.
|
|
105
|
+
*
|
|
106
|
+
* One error, not one per offending line: a buyer changes the payment method
|
|
107
|
+
* once, and listing every blocked item would be a wall of text about a single
|
|
108
|
+
* decision.
|
|
109
|
+
*/
|
|
110
|
+
export function assertPaymentMethodAllowed(items, productById, paymentMethod) {
|
|
111
|
+
if (!paymentMethod)
|
|
112
|
+
return;
|
|
113
|
+
/*
|
|
114
|
+
* 🛑 `admin_bypass` is exempt, deliberately. It exists so an admin can reach
|
|
115
|
+
* an order state without a real payment, is gated by a site-settings flag
|
|
116
|
+
* plus an admin role, and logs every use. Blocking it would make the one tool
|
|
117
|
+
* for testing these flows unable to test them.
|
|
118
|
+
*/
|
|
119
|
+
if (paymentMethod === "admin_bypass")
|
|
120
|
+
return;
|
|
121
|
+
const blocked = blockedMethodsForCart(items, productById);
|
|
122
|
+
const offender = blocked.get(paymentMethod);
|
|
123
|
+
if (!offender)
|
|
124
|
+
return;
|
|
125
|
+
/*
|
|
126
|
+
* The methods that remain, derived from the union rather than a second list —
|
|
127
|
+
* a seventh payment method must not quietly go unmentioned here.
|
|
128
|
+
*/
|
|
129
|
+
const allowed = CHECKOUT_PAYMENT_METHODS.filter((m) => m !== "admin_bypass" && !blocked.has(m)).map((m) => PAYMENT_METHOD_LABEL[m] ?? m);
|
|
130
|
+
throw Object.assign(new ValidationError(allowed.length > 0
|
|
131
|
+
? `${offender.message} Available instead: ${allowed.join(", ")}.`
|
|
132
|
+
: `${offender.message} Nothing in this cart's combination can be paid for — remove the item and buy it on its own.`), { code: "PAYMENT_METHOD_BLOCKED" });
|
|
133
|
+
}
|
|
@@ -10,15 +10,26 @@ import { PRIZE_DRAW_MAX_REVEALS_PER_ORDER } from "./_limits.js";
|
|
|
10
10
|
* "admin_bypass" stays usable for QA regardless.
|
|
11
11
|
*/
|
|
12
12
|
const PRIZE_DRAW_BLOCKED_PAYMENT_METHODS = ["cod", "cash", "emi"];
|
|
13
|
+
/**
|
|
14
|
+
* The refusal, kept VERBATIM when this check moved out of `preflightChecks`
|
|
15
|
+
* into `assertPaymentMethodAllowed`.
|
|
16
|
+
*
|
|
17
|
+
* 🛑 The gate can generate a correct sentence on its own, and a generated one
|
|
18
|
+
* would have been a regression here: this wording names the REASON (winner
|
|
19
|
+
* assignment waits on confirmed payment) rather than just the refusal, and the
|
|
20
|
+
* reason is the thing a buyer needs in order to pick a different method rather
|
|
21
|
+
* than abandon the entry.
|
|
22
|
+
*/
|
|
23
|
+
const PRIZE_DRAW_BLOCKED_PAYMENT_MESSAGE = "Prize-draw entries can only be paid by manual bank/UPI transfer or PhonePe — cash on delivery and EMI are not available for this listing type.";
|
|
13
24
|
export const prizeDrawRule = {
|
|
14
25
|
...DEFAULT_LISTING_RULE,
|
|
15
26
|
orderType: "prize-draw",
|
|
16
27
|
nonRefundable: true,
|
|
17
|
-
maxQuantityPerLine: 1,
|
|
18
28
|
canMergeWithSameProduct: false,
|
|
19
29
|
maxLinesPerOrder: PRIZE_DRAW_MAX_REVEALS_PER_ORDER,
|
|
20
30
|
refundPolicy: { full: false, partial: false, partialGranularity: "none" },
|
|
21
31
|
blockedPaymentMethods: PRIZE_DRAW_BLOCKED_PAYMENT_METHODS,
|
|
32
|
+
blockedPaymentMessage: PRIZE_DRAW_BLOCKED_PAYMENT_MESSAGE,
|
|
22
33
|
splitKey: (item) => `prize-draw:${item.itemId}`,
|
|
23
34
|
/**
|
|
24
35
|
* Slice a high-quantity prize-draw entry into chunks of
|
|
@@ -43,13 +54,23 @@ export const prizeDrawRule = {
|
|
|
43
54
|
}
|
|
44
55
|
return chunks;
|
|
45
56
|
},
|
|
46
|
-
preflightChecks: (pairs
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
57
|
+
preflightChecks: (pairs) => {
|
|
58
|
+
/*
|
|
59
|
+
* The payment-method check USED to live here and is now in
|
|
60
|
+
* `assertPaymentMethodAllowed`, which runs cart-wide before the
|
|
61
|
+
* transaction.
|
|
62
|
+
*
|
|
63
|
+
* 🛑 This is not a tidy-up. The copy here could only ever see
|
|
64
|
+
* single-member lines — `runSyncPreflight` skips a bundle or grouped line,
|
|
65
|
+
* and its online call site reduces each line to its FIRST member — so a
|
|
66
|
+
* prize-draw entry reachable through a grouped selection was never
|
|
67
|
+
* checked. Re-adding a copy here would be a second answer to one question
|
|
68
|
+
* (Root Cause #75), and the one that is easier to find is the one that
|
|
69
|
+
* cannot see every line.
|
|
70
|
+
*
|
|
71
|
+
* `blockedPaymentMethods` + `blockedPaymentMessage` on this rule are what
|
|
72
|
+
* the gate reads, so the wording is unchanged.
|
|
73
|
+
*/
|
|
53
74
|
for (const { item, product } of pairs) {
|
|
54
75
|
if (product.listingType !== "prize-draw")
|
|
55
76
|
continue;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spares listing rule — one component off a disassembled item, standard-like
|
|
3
|
+
* checkout.
|
|
4
|
+
*
|
|
5
|
+
* No bespoke behaviour: cart/order grouping, stock decrement and refund policy
|
|
6
|
+
* all follow the standard defaults, and `pluginFor()` carries everything that
|
|
7
|
+
* differs (badge, browse route, seller form fields).
|
|
8
|
+
*
|
|
9
|
+
* 🛑 `orderType: "standard"` is deliberate rather than lazy. A new `OrderType`
|
|
10
|
+
* member fans out into the order-status tabs, the order filters and the
|
|
11
|
+
* splitter's own keys — and buys nothing here, because a spare is fulfilled,
|
|
12
|
+
* refunded and reported exactly like any other physical item. A buyer looking
|
|
13
|
+
* at their orders wants "the attack ring I bought", not a separate tab for it.
|
|
14
|
+
*/
|
|
15
|
+
import type { ListingCheckoutRule } from "./types";
|
|
16
|
+
export declare const sparesRule: ListingCheckoutRule;
|
|
@@ -62,8 +62,6 @@ export interface ListingCheckoutRule {
|
|
|
62
62
|
* Set true for prize-draw entries.
|
|
63
63
|
*/
|
|
64
64
|
nonRefundable: boolean;
|
|
65
|
-
/** Hard qty cap per single cart line. Auction/offer/prize-draw-per-line = 1. */
|
|
66
|
-
maxQuantityPerLine: number;
|
|
67
65
|
/**
|
|
68
66
|
* When false the checkout pipeline issues one order per cart line (even when
|
|
69
67
|
* multiple lines share the same product). Auctions and offers set this to
|
|
@@ -83,8 +81,20 @@ export interface ListingCheckoutRule {
|
|
|
83
81
|
* all methods allowed. Prize-draw blocks cod/cash/emi — winner assignment
|
|
84
82
|
* depends on the order's payment actually being confirmed, which those
|
|
85
83
|
* deferred-payment methods don't guarantee.
|
|
84
|
+
*
|
|
85
|
+
* 🛑 Enforced by `assertPaymentMethodAllowed`, NOT by `runSyncPreflight`. A
|
|
86
|
+
* rule may only trust preflight for a single-member line; a type that can
|
|
87
|
+
* appear inside a bundle or a grouped selection is skipped there entirely.
|
|
88
|
+
* The gate runs over every member of every line, once, before the
|
|
89
|
+
* transaction.
|
|
86
90
|
*/
|
|
87
91
|
blockedPaymentMethods?: CheckoutPaymentMethod[];
|
|
92
|
+
/**
|
|
93
|
+
* The refusal, in this type's own words. Optional — the gate generates a
|
|
94
|
+
* correct sentence without it. Supply one when the REASON is worth saying,
|
|
95
|
+
* as prize-draw's does.
|
|
96
|
+
*/
|
|
97
|
+
blockedPaymentMessage?: string;
|
|
88
98
|
/**
|
|
89
99
|
* Return the grouping key used by the order splitter. Items with the same
|
|
90
100
|
* key land in the same OrderGroup and produce one order document.
|
|
@@ -150,4 +160,18 @@ export interface CategoryCheckoutRule {
|
|
|
150
160
|
cartEligible: boolean;
|
|
151
161
|
orderType: OrderType;
|
|
152
162
|
requiresShippingAddress: boolean;
|
|
163
|
+
/**
|
|
164
|
+
* Payment methods this category cannot be paid with.
|
|
165
|
+
*
|
|
166
|
+
* 🛑 NOT enforced by `runSyncPreflight`. That function skips multi-member
|
|
167
|
+
* lines by design, and a bundle is always one — so a value here would be set,
|
|
168
|
+
* reviewed, and never read. `assertPaymentMethodAllowed` is what honours it,
|
|
169
|
+
* and it runs cart-wide before the transaction.
|
|
170
|
+
*/
|
|
171
|
+
blockedPaymentMethods?: CheckoutPaymentMethod[];
|
|
172
|
+
/**
|
|
173
|
+
* The refusal, in this category's own words. Optional — the gate generates a
|
|
174
|
+
* correct sentence without it. Supply one when the REASON is worth saying.
|
|
175
|
+
*/
|
|
176
|
+
blockedPaymentMessage?: string;
|
|
153
177
|
}
|