@mohasinac/appkit 4.53.0 → 4.53.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (500) hide show
  1. package/dist/.build-stamp.json +3 -3
  2. package/dist/_internal/client/scaffolds/AppShell.js +1 -1
  3. package/dist/_internal/server/features/auctions/og.d.ts +3 -1
  4. package/dist/_internal/server/features/auctions/og.js +3 -1
  5. package/dist/_internal/server/features/bundles/actions.js +1 -1
  6. package/dist/_internal/server/features/business-documents/download.d.ts +41 -0
  7. package/dist/_internal/server/features/business-documents/download.js +91 -0
  8. package/dist/_internal/server/features/categories/adapters.d.ts +1 -1
  9. package/dist/_internal/server/features/categories/adapters.js +10 -0
  10. package/dist/_internal/server/features/checkout/actions.d.ts +14 -0
  11. package/dist/_internal/server/features/checkout/actions.js +106 -12
  12. package/dist/_internal/server/features/checkout/bundle-expansion.js +17 -0
  13. package/dist/_internal/server/features/checkout/data.d.ts +22 -0
  14. package/dist/_internal/server/features/checkout/group-rule-revalidation.d.ts +34 -0
  15. package/dist/_internal/server/features/checkout/group-rule-revalidation.js +124 -0
  16. package/dist/_internal/server/features/checkout/supplier-identity.d.ts +55 -0
  17. package/dist/_internal/server/features/checkout/supplier-identity.js +81 -0
  18. package/dist/_internal/server/features/classified/metadata.js +1 -1
  19. package/dist/_internal/server/features/classified/og.d.ts +3 -1
  20. package/dist/_internal/server/features/classified/og.js +3 -1
  21. package/dist/_internal/server/features/digital-code/metadata.js +1 -1
  22. package/dist/_internal/server/features/digital-code/og.d.ts +3 -1
  23. package/dist/_internal/server/features/digital-code/og.js +3 -1
  24. package/dist/_internal/server/features/digital-code/pool.d.ts +19 -4
  25. package/dist/_internal/server/features/digital-code/pool.js +19 -4
  26. package/dist/_internal/server/features/live/metadata.js +1 -1
  27. package/dist/_internal/server/features/live/og.d.ts +3 -1
  28. package/dist/_internal/server/features/live/og.js +3 -1
  29. package/dist/_internal/server/features/messages/actions.js +1 -1
  30. package/dist/_internal/server/features/parts/og.js +1 -1
  31. package/dist/_internal/server/features/pre-orders/og.d.ts +3 -1
  32. package/dist/_internal/server/features/pre-orders/og.js +3 -1
  33. package/dist/_internal/server/features/price-index/search.d.ts +18 -0
  34. package/dist/_internal/server/features/price-index/search.js +47 -7
  35. package/dist/_internal/server/features/prize-draws/og.d.ts +3 -1
  36. package/dist/_internal/server/features/prize-draws/og.js +3 -1
  37. package/dist/_internal/server/features/products/group-members.d.ts +26 -0
  38. package/dist/_internal/server/features/products/group-members.js +7 -1
  39. package/dist/_internal/server/features/products/og.d.ts +3 -1
  40. package/dist/_internal/server/features/products/og.js +3 -1
  41. package/dist/_internal/server/features/search/scoped-sources.d.ts +26 -0
  42. package/dist/_internal/server/features/search/scoped-sources.js +252 -0
  43. package/dist/_internal/server/features/search/search-everything.d.ts +57 -0
  44. package/dist/_internal/server/features/search/search-everything.js +70 -20
  45. package/dist/_internal/server/features/seo/sitemap.js +6 -0
  46. package/dist/_internal/server/features/shared/listing-adapters.js +4 -2
  47. package/dist/_internal/server/features/sticker-trace/adapters.d.ts +11 -0
  48. package/dist/_internal/server/features/sticker-trace/adapters.js +1 -0
  49. package/dist/_internal/server/features/sticker-trace/promote-to-listings.d.ts +26 -0
  50. package/dist/_internal/server/features/sticker-trace/promote-to-listings.js +264 -0
  51. package/dist/_internal/server/features/sticker-trace/sheet-actions.d.ts +3 -1
  52. package/dist/_internal/server/features/sticker-trace/sheet-actions.js +32 -0
  53. package/dist/_internal/server/features/sticker-trace/storage.d.ts +20 -1
  54. package/dist/_internal/server/features/sticker-trace/storage.js +20 -1
  55. package/dist/_internal/server/features/stores/adapters.d.ts +1 -1
  56. package/dist/_internal/server/features/stores/adapters.js +16 -0
  57. package/dist/_internal/server/features/stores/index.d.ts +1 -0
  58. package/dist/_internal/server/features/stores/index.js +1 -0
  59. package/dist/_internal/server/features/stores/tabs.d.ts +25 -0
  60. package/dist/_internal/server/features/stores/tabs.js +122 -0
  61. package/dist/_internal/shared/checkout/rules/_defaults.js +0 -2
  62. package/dist/_internal/shared/checkout/rules/_limits.d.ts +14 -1
  63. package/dist/_internal/shared/checkout/rules/_limits.js +14 -1
  64. package/dist/_internal/shared/checkout/rules/_registry.js +2 -0
  65. package/dist/_internal/shared/checkout/rules/auction.rule.js +9 -1
  66. package/dist/_internal/shared/checkout/rules/bundle.rule.js +13 -0
  67. package/dist/_internal/shared/checkout/rules/index.d.ts +2 -0
  68. package/dist/_internal/shared/checkout/rules/index.js +9 -0
  69. package/dist/_internal/shared/checkout/rules/offer.rule.js +0 -1
  70. package/dist/_internal/shared/checkout/rules/payment-gate.d.ts +26 -0
  71. package/dist/_internal/shared/checkout/rules/payment-gate.js +133 -0
  72. package/dist/_internal/shared/checkout/rules/prize-draw.rule.js +29 -8
  73. package/dist/_internal/shared/checkout/rules/spares.rule.d.ts +16 -0
  74. package/dist/_internal/shared/checkout/rules/spares.rule.js +5 -0
  75. package/dist/_internal/shared/checkout/rules/types.d.ts +26 -2
  76. package/dist/_internal/shared/config/schema.d.ts +122 -0
  77. package/dist/_internal/shared/features/cart/schema.js +3 -2
  78. package/dist/_internal/shared/features/products/group-rules.d.ts +75 -0
  79. package/dist/_internal/shared/features/products/group-rules.js +142 -0
  80. package/dist/_internal/shared/listing-types/_registry.d.ts +24 -0
  81. package/dist/_internal/shared/listing-types/_registry.js +39 -1
  82. package/dist/_internal/shared/listing-types/art/config.d.ts +1 -0
  83. package/dist/_internal/shared/listing-types/art/config.js +2 -0
  84. package/dist/_internal/shared/listing-types/auction/config.d.ts +1 -0
  85. package/dist/_internal/shared/listing-types/auction/config.js +2 -0
  86. package/dist/_internal/shared/listing-types/availability.js +48 -0
  87. package/dist/_internal/shared/listing-types/capabilities.js +19 -0
  88. package/dist/_internal/shared/listing-types/classified/config.d.ts +1 -0
  89. package/dist/_internal/shared/listing-types/classified/config.js +2 -0
  90. package/dist/_internal/shared/listing-types/digital-code/config.d.ts +1 -0
  91. package/dist/_internal/shared/listing-types/digital-code/config.js +2 -0
  92. package/dist/_internal/shared/listing-types/feature-flags.js +1 -0
  93. package/dist/_internal/shared/listing-types/live/config.d.ts +1 -0
  94. package/dist/_internal/shared/listing-types/live/config.js +2 -0
  95. package/dist/_internal/shared/listing-types/pre-order/config.d.ts +1 -0
  96. package/dist/_internal/shared/listing-types/pre-order/config.js +2 -0
  97. package/dist/_internal/shared/listing-types/prize-draw/config.d.ts +1 -0
  98. package/dist/_internal/shared/listing-types/prize-draw/config.js +2 -0
  99. package/dist/_internal/shared/listing-types/spares/config.d.ts +74 -0
  100. package/dist/_internal/shared/listing-types/spares/config.js +60 -0
  101. package/dist/_internal/shared/listing-types/spares/ctas.d.ts +1 -0
  102. package/dist/_internal/shared/listing-types/spares/ctas.js +4 -0
  103. package/dist/_internal/shared/listing-types/spares/og.js +1 -0
  104. package/dist/_internal/shared/listing-types/spares/schema.d.ts +2 -0
  105. package/dist/_internal/shared/listing-types/spares/schema.js +3 -0
  106. package/dist/_internal/shared/listing-types/spares/seed-factory.d.ts +1 -0
  107. package/dist/_internal/shared/listing-types/spares/seed-factory.js +1 -0
  108. package/dist/_internal/shared/listing-types/standard/config.d.ts +1 -0
  109. package/dist/_internal/shared/listing-types/standard/config.js +2 -0
  110. package/dist/_internal/shared/listing-types/stickers/config.d.ts +1 -0
  111. package/dist/_internal/shared/listing-types/stickers/config.js +2 -0
  112. package/dist/_internal/shared/search/match.d.ts +11 -0
  113. package/dist/_internal/shared/search/match.js +2 -1
  114. package/dist/_internal/shared/search/to-groups.d.ts +52 -0
  115. package/dist/_internal/shared/search/to-groups.js +141 -0
  116. package/dist/client.d.ts +8 -2
  117. package/dist/client.js +4 -1
  118. package/dist/constants/api-endpoints.d.ts +39 -15
  119. package/dist/constants/api-endpoints.js +28 -5
  120. package/dist/constants/cache-invalidation.js +3 -1
  121. package/dist/constants/field-names.d.ts +6 -0
  122. package/dist/constants/field-names.js +6 -0
  123. package/dist/features/about/components/PolicyPageView.d.ts +22 -2
  124. package/dist/features/about/components/PolicyPageView.js +14 -2
  125. package/dist/features/about/components/PublicProfileView.js +2 -1
  126. package/dist/features/about/components/ShippingPolicyView.js +42 -2
  127. package/dist/features/account/components/NotificationBell.js +1 -1
  128. package/dist/features/account/hooks/useProfileStats.js +5 -1
  129. package/dist/features/addresses/repository/addresses.repository.d.ts +16 -0
  130. package/dist/features/addresses/repository/addresses.repository.js +21 -0
  131. package/dist/features/admin/actions/admin-actions.js +16 -1
  132. package/dist/features/admin/components/AdminCategoryEditorView.js +19 -2
  133. package/dist/features/admin/components/AdminNavigationView.js +1 -1
  134. package/dist/features/admin/components/AdminPageHeader.js +1 -1
  135. package/dist/features/admin/components/AdminProductEditorView.js +17 -2
  136. package/dist/features/admin/components/AdminSidebar.js +1 -1
  137. package/dist/features/admin/components/AdminSiteSettingsView.js +39 -8
  138. package/dist/features/admin/components/AdminSparesView.d.ts +12 -0
  139. package/dist/features/admin/components/AdminSparesView.js +30 -0
  140. package/dist/features/admin/components/AdminUsersView.js +9 -7
  141. package/dist/features/admin/components/index.d.ts +2 -0
  142. package/dist/features/admin/components/index.js +1 -0
  143. package/dist/features/admin/components/sections/adminSectionsTypes.js +7 -0
  144. package/dist/features/admin/constants/filter-tabs.d.ts +3 -0
  145. package/dist/features/admin/constants/filter-tabs.js +1 -0
  146. package/dist/features/admin/schemas/firestore.d.ts +26 -2
  147. package/dist/features/auctions/components/AuctionDetailPageView.js +4 -11
  148. package/dist/features/auth/repository/user.repository.d.ts +13 -0
  149. package/dist/features/auth/repository/user.repository.js +28 -0
  150. package/dist/features/auth/schemas/firestore.d.ts +2 -0
  151. package/dist/features/auth/schemas/firestore.js +2 -0
  152. package/dist/features/business-documents/repository/business-documents.repository.d.ts +58 -0
  153. package/dist/features/business-documents/repository/business-documents.repository.js +54 -0
  154. package/dist/features/business-documents/schemas/firestore.d.ts +105 -0
  155. package/dist/features/business-documents/schemas/firestore.js +75 -0
  156. package/dist/features/cart/actions/cart-actions.js +83 -6
  157. package/dist/features/cart/repository/cart.repository.js +32 -4
  158. package/dist/features/cart/schemas/firestore.d.ts +20 -0
  159. package/dist/features/cart/schemas/index.d.ts +2 -2
  160. package/dist/features/catalogue/components/PublicCatalogueItemDetailView.js +1 -1
  161. package/dist/features/categories/api/[id]/price-guidance/route.d.ts +42 -0
  162. package/dist/features/categories/api/[id]/price-guidance/route.js +113 -0
  163. package/dist/features/categories/components/BrandDetailPageView.js +19 -3
  164. package/dist/features/categories/components/BrandDetailTabs.js +10 -0
  165. package/dist/features/categories/components/CategoriesIndexListing.js +23 -8
  166. package/dist/features/categories/components/CategoryDetailPageView.js +141 -14
  167. package/dist/features/categories/components/CategoryDetailTabs.js +12 -0
  168. package/dist/features/categories/components/CategoryGrid.js +10 -1
  169. package/dist/features/categories/components/PriceGuidanceHint.d.ts +29 -0
  170. package/dist/features/categories/components/PriceGuidanceHint.js +61 -0
  171. package/dist/features/categories/components/SubcategoryCardRow.d.ts +27 -0
  172. package/dist/features/categories/components/SubcategoryCardRow.js +98 -0
  173. package/dist/features/categories/constants/category-tabs.d.ts +20 -25
  174. package/dist/features/categories/constants/category-tabs.js +22 -39
  175. package/dist/features/categories/repository/categories.repository.d.ts +12 -0
  176. package/dist/features/categories/repository/categories.repository.js +20 -0
  177. package/dist/features/categories/schemas/firestore.d.ts +22 -1
  178. package/dist/features/categories/schemas/firestore.js +10 -0
  179. package/dist/features/categories/schemas/index.d.ts +6 -0
  180. package/dist/features/categories/schemas/index.js +2 -0
  181. package/dist/features/categories/types/index.d.ts +8 -0
  182. package/dist/features/categories/utils/taxonomy-visual.d.ts +16 -3
  183. package/dist/features/categories/utils/taxonomy-visual.js +26 -10
  184. package/dist/features/classified/components/ClassifiedDetailPageView.js +4 -9
  185. package/dist/features/contact/components/ContactPageView.d.ts +33 -1
  186. package/dist/features/contact/components/ContactPageView.js +58 -28
  187. package/dist/features/digital-codes/components/DigitalCodeDetailPageView.js +4 -9
  188. package/dist/features/grouped/components/GroupedListingDetailView.js +9 -1
  189. package/dist/features/grouped/schemas/firestore.d.ts +5 -0
  190. package/dist/features/homepage/actions/homepage-section-actions.d.ts +3 -3
  191. package/dist/features/homepage/components/CollectionCardsSection.d.ts +28 -6
  192. package/dist/features/homepage/components/CollectionCardsSection.js +43 -8
  193. package/dist/features/homepage/components/HowItWorksSection.d.ts +23 -6
  194. package/dist/features/homepage/components/HowItWorksSection.js +4 -4
  195. package/dist/features/homepage/components/PromoGrid.d.ts +31 -2
  196. package/dist/features/homepage/components/PromoGrid.js +12 -3
  197. package/dist/features/homepage/components/TestimonialsCarousel.d.ts +34 -2
  198. package/dist/features/homepage/components/TestimonialsCarousel.js +1 -1
  199. package/dist/features/homepage/components/index.d.ts +0 -20
  200. package/dist/features/homepage/components/index.js +0 -11
  201. package/dist/features/homepage/index.d.ts +0 -2
  202. package/dist/features/homepage/index.js +0 -2
  203. package/dist/features/homepage/lib/section-renderer.d.ts +9 -0
  204. package/dist/features/homepage/lib/section-renderer.js +202 -58
  205. package/dist/features/homepage/repository/homepage-sections.repository.d.ts +35 -3
  206. package/dist/features/homepage/repository/homepage-sections.repository.js +58 -8
  207. package/dist/features/homepage/schemas/firestore.d.ts +106 -3
  208. package/dist/features/homepage/schemas/firestore.js +32 -2
  209. package/dist/features/homepage/schemas/index.d.ts +36 -7
  210. package/dist/features/homepage/schemas/index.js +39 -27
  211. package/dist/features/homepage/server.d.ts +0 -3
  212. package/dist/features/homepage/server.js +0 -3
  213. package/dist/features/homepage/types/index.d.ts +0 -47
  214. package/dist/features/homepage/types/index.js +49 -0
  215. package/dist/features/layout/AppLayoutShell.js +1 -1
  216. package/dist/features/layout/BottomNavItem.js +1 -1
  217. package/dist/features/layout/BottomSheet.js +1 -1
  218. package/dist/features/layout/TitleBarLayout.js +1 -1
  219. package/dist/features/live/components/LiveItemDetailPageView.js +4 -9
  220. package/dist/features/media/hooks/useMedia.js +17 -0
  221. package/dist/features/media/repository/media-assets.repository.d.ts +46 -0
  222. package/dist/features/media/repository/media-assets.repository.js +31 -0
  223. package/dist/features/media/trust-signals.d.ts +85 -0
  224. package/dist/features/media/trust-signals.js +126 -0
  225. package/dist/features/parts/components/PartDetailPageView.d.ts +14 -1
  226. package/dist/features/parts/components/PartDetailPageView.js +2 -2
  227. package/dist/features/parts/components/PartsIndexPageView.d.ts +11 -2
  228. package/dist/features/parts/components/PartsIndexPageView.js +2 -2
  229. package/dist/features/parts/components/PartsSearchBox.d.ts +9 -0
  230. package/dist/features/parts/components/PartsSearchBox.js +57 -0
  231. package/dist/features/parts/schemas/firestore.d.ts +149 -3
  232. package/dist/features/parts/schemas/firestore.js +184 -0
  233. package/dist/features/payments/repository/payout.repository.d.ts +15 -0
  234. package/dist/features/payments/repository/payout.repository.js +21 -0
  235. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +4 -11
  236. package/dist/features/pre-orders/components/PreOrdersIndexListing.js +1 -1
  237. package/dist/features/price-index/components/PriceIndexToolView.d.ts +3 -1
  238. package/dist/features/price-index/components/PriceIndexToolView.js +92 -13
  239. package/dist/features/products/components/CompareOverlay.d.ts +18 -1
  240. package/dist/features/products/components/CompareOverlay.js +21 -2
  241. package/dist/features/products/components/CustomSectionTabContent.d.ts +31 -0
  242. package/dist/features/products/components/CustomSectionTabContent.js +29 -3
  243. package/dist/features/products/components/GroupMemberPicker.d.ts +19 -1
  244. package/dist/features/products/components/GroupMemberPicker.js +46 -8
  245. package/dist/features/products/components/GroupSettingsPanel.d.ts +11 -1
  246. package/dist/features/products/components/GroupSettingsPanel.js +91 -3
  247. package/dist/features/products/components/PrizeDrawDetailPageView.js +1 -1
  248. package/dist/features/products/components/PrizeDrawEntryActions.d.ts +15 -1
  249. package/dist/features/products/components/PrizeDrawEntryActions.js +70 -8
  250. package/dist/features/products/components/ProductDetailPageView.js +74 -15
  251. package/dist/features/products/components/ProductForm.d.ts +13 -1
  252. package/dist/features/products/components/ProductForm.js +16 -2
  253. package/dist/features/products/components/ProductsIndexListing.d.ts +16 -1
  254. package/dist/features/products/components/ProductsIndexListing.js +3 -3
  255. package/dist/features/products/components/ShowGroupSection.js +15 -2
  256. package/dist/features/products/components/SparesListView.d.ts +7 -0
  257. package/dist/features/products/components/SparesListView.js +39 -0
  258. package/dist/features/products/constants/action-defs.d.ts +1 -0
  259. package/dist/features/products/constants/action-defs.js +1 -0
  260. package/dist/features/products/repository/products.repository.d.ts +98 -0
  261. package/dist/features/products/repository/products.repository.js +235 -17
  262. package/dist/features/products/schemas/firestore.d.ts +97 -4
  263. package/dist/features/products/schemas/firestore.js +104 -0
  264. package/dist/features/products/schemas/index.d.ts +10 -19
  265. package/dist/features/products/schemas/index.js +23 -6
  266. package/dist/features/products/types/index.d.ts +45 -1
  267. package/dist/features/products/utils/group-member-image.d.ts +39 -0
  268. package/dist/features/products/utils/group-member-image.js +3 -0
  269. package/dist/features/products/utils/listing-badge-variant.js +4 -0
  270. package/dist/features/reviews/components/ReviewsList.js +1 -1
  271. package/dist/features/scams/components/ScamProfileView.js +1 -1
  272. package/dist/features/search/components/EntityTypeahead.d.ts +44 -0
  273. package/dist/features/search/components/EntityTypeahead.js +92 -0
  274. package/dist/features/search/components/Search.d.ts +12 -1
  275. package/dist/features/search/components/Search.js +47 -3
  276. package/dist/features/search/components/SearchFacetRail.d.ts +11 -0
  277. package/dist/features/search/components/SearchFacetRail.js +92 -0
  278. package/dist/features/search/components/SearchResultsClient.d.ts +33 -0
  279. package/dist/features/search/components/SearchResultsClient.js +103 -0
  280. package/dist/features/search/components/SearchResultsPageView.d.ts +15 -1
  281. package/dist/features/search/components/SearchResultsPageView.js +2 -2
  282. package/dist/features/search/components/index.d.ts +0 -6
  283. package/dist/features/search/components/index.js +0 -3
  284. package/dist/features/search/hooks/useNavSuggestions.d.ts +13 -0
  285. package/dist/features/search/hooks/useScopedSearch.d.ts +34 -0
  286. package/dist/features/search/hooks/useScopedSearch.js +114 -0
  287. package/dist/features/search/hooks/useSiteSearch.d.ts +26 -0
  288. package/dist/features/search/hooks/useSiteSearch.js +149 -0
  289. package/dist/features/search/index.d.ts +0 -4
  290. package/dist/features/search/index.js +0 -4
  291. package/dist/features/search/manifest.d.ts +12 -0
  292. package/dist/features/search/manifest.js +17 -2
  293. package/dist/features/search/server.d.ts +0 -3
  294. package/dist/features/search/server.js +0 -3
  295. package/dist/features/seller/components/SellerListingTypeView.d.ts +1 -1
  296. package/dist/features/seller/components/SellerListingTypeView.js +20 -0
  297. package/dist/features/seller/components/SellerPayoutSettingsView.js +35 -14
  298. package/dist/features/seller/components/SellerProductShell.d.ts +1 -1
  299. package/dist/features/seller/components/SellerProductShell.js +2 -1
  300. package/dist/features/seller/components/SellerSidebar.js +1 -1
  301. package/dist/features/seller/components/SellerSparesView.d.ts +17 -0
  302. package/dist/features/seller/components/SellerSparesView.js +6 -0
  303. package/dist/features/seller/components/index.d.ts +2 -0
  304. package/dist/features/seller/components/index.js +1 -0
  305. package/dist/features/shell/CommandPalette.js +1 -1
  306. package/dist/features/sticker-trace/schemas/firestore.d.ts +19 -0
  307. package/dist/features/stores/components/StoreDetailLayoutView.d.ts +1 -1
  308. package/dist/features/stores/components/StoreDetailLayoutView.js +7 -82
  309. package/dist/features/stores/components/StoreHeader.js +1 -2
  310. package/dist/features/stores/components/StoreSparesPageView.d.ts +27 -0
  311. package/dist/features/stores/components/StoreSparesPageView.js +48 -0
  312. package/dist/features/stores/schemas/firestore.d.ts +19 -0
  313. package/dist/features/tester/seed-data/authored/buying__spares-and-groups.d.ts +2 -0
  314. package/dist/features/tester/seed-data/authored/buying__spares-and-groups.js +96 -0
  315. package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.d.ts +2 -0
  316. package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.js +280 -45
  317. package/dist/features/tester/seed-data/authored/content-discovery__category-tabs-franchise-bundles.js +54 -32
  318. package/dist/features/tester/seed-data/authored/content-discovery__parts-database.js +3 -2
  319. package/dist/features/tester/seed-data/authored/content-discovery__price-index-and-compare.d.ts +2 -0
  320. package/dist/features/tester/seed-data/authored/content-discovery__price-index-and-compare.js +73 -0
  321. package/dist/features/tester/seed-data/authored/content-discovery__site-wide-index.d.ts +2 -0
  322. package/dist/features/tester/seed-data/authored/content-discovery__site-wide-index.js +340 -0
  323. package/dist/features/tester/seed-data/authored/index.js +16 -0
  324. package/dist/features/tester/seed-data/authored/search-and-nav__header-search.d.ts +1 -0
  325. package/dist/features/tester/seed-data/authored/search-and-nav__header-search.js +57 -0
  326. package/dist/features/tester/seed-data/authored/selling__spares-and-group-editing.d.ts +2 -0
  327. package/dist/features/tester/seed-data/authored/selling__spares-and-group-editing.js +77 -0
  328. package/dist/features/tester/seed-data/authored/tools__sticker-promote-to-listings.d.ts +2 -0
  329. package/dist/features/tester/seed-data/authored/tools__sticker-promote-to-listings.js +58 -0
  330. package/dist/features/tester/seed-data/authored/tools__sticker-tracer.js +5 -4
  331. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +372 -18
  332. package/dist/index.d.ts +17 -57
  333. package/dist/index.js +35 -96
  334. package/dist/next/routing/route-map.d.ts +42 -1
  335. package/dist/next/routing/route-map.js +45 -0
  336. package/dist/providers/db-firebase/base.repository.d.ts +22 -0
  337. package/dist/providers/db-firebase/base.repository.js +36 -0
  338. package/dist/schemas/registry.d.ts +15 -6
  339. package/dist/security/blind-index-tokens.d.ts +54 -0
  340. package/dist/security/blind-index-tokens.js +152 -0
  341. package/dist/security/index.d.ts +1 -1
  342. package/dist/security/index.js +1 -1
  343. package/dist/security/settings-encryption.d.ts +35 -0
  344. package/dist/security/settings-encryption.js +91 -0
  345. package/dist/seed/_helpers/brand-rows.js +38 -14
  346. package/dist/seed/_helpers/category-forest.js +73 -7
  347. package/dist/seed/_helpers/category-images-generated.d.ts +25 -6
  348. package/dist/seed/_helpers/category-images-generated.js +81 -6
  349. package/dist/seed/_helpers/category-models.d.ts +1 -1
  350. package/dist/seed/_helpers/category-models.js +7 -1
  351. package/dist/seed/_helpers/category-parts-glossary-map.js +8 -0
  352. package/dist/seed/_helpers/category-parts.d.ts +1 -1
  353. package/dist/seed/_helpers/category-parts.js +50 -2
  354. package/dist/seed/_helpers/character-features.d.ts +1 -1
  355. package/dist/seed/_helpers/character-features.js +2 -1
  356. package/dist/seed/_helpers/franchise-rows.js +10 -2
  357. package/dist/seed/_helpers/media.d.ts +47 -0
  358. package/dist/seed/_helpers/media.js +34 -0
  359. package/dist/seed/authenticity-knowledge-seed-data.d.ts +49 -5
  360. package/dist/seed/authenticity-knowledge-seed-data.js +10001 -549
  361. package/dist/seed/categories-seed-data.js +124 -20
  362. package/dist/seed/grouped-listings-seed-data.js +16 -0
  363. package/dist/seed/homepage-sections-seed-data.js +94 -5
  364. package/dist/seed/index.d.ts +2 -3
  365. package/dist/seed/index.js +2 -2
  366. package/dist/seed/manifest.js +3 -0
  367. package/dist/seed/media-assets-seed-data.d.ts +1 -1
  368. package/dist/seed/media-assets-seed-data.js +746 -196
  369. package/dist/seed/model-composition-seed-data.js +122 -6
  370. package/dist/seed/part-glossary-seed-data.d.ts +1 -1
  371. package/dist/seed/part-glossary-seed-data.js +37219 -463
  372. package/dist/seed/products-art-seed-data.js +7 -18
  373. package/dist/seed/products-auctions-seed-data.js +56 -47
  374. package/dist/seed/products-beyblade-x-seed-data.d.ts +2 -0
  375. package/dist/seed/products-beyblade-x-seed-data.js +441 -0
  376. package/dist/seed/products-catalogue-seed-data.d.ts +5 -5
  377. package/dist/seed/products-catalogue-seed-data.js +1500 -1240
  378. package/dist/seed/products-classifieds-seed-data.js +9 -27
  379. package/dist/seed/products-digital-codes-seed-data.js +9 -18
  380. package/dist/seed/products-live-items-seed-data.js +5 -13
  381. package/dist/seed/products-preorders-seed-data.js +67 -33
  382. package/dist/seed/products-prize-draws-seed-data.js +8 -17
  383. package/dist/seed/products-spares-seed-data.d.ts +2 -0
  384. package/dist/seed/products-spares-seed-data.js +368 -0
  385. package/dist/seed/products-standard-seed-data.js +39 -126
  386. package/dist/seed/products-stickers-seed-data.js +59 -15
  387. package/dist/seed/site-settings-seed-data.js +8 -0
  388. package/dist/seo/json-ld.d.ts +25 -0
  389. package/dist/seo/json-ld.js +28 -0
  390. package/dist/server-entry.d.ts +3 -1
  391. package/dist/server-entry.js +2 -2
  392. package/dist/server.d.ts +9 -9
  393. package/dist/server.js +27 -25
  394. package/dist/styles.css +202 -1
  395. package/dist/tailwind-input.css +31 -17
  396. package/dist/tailwind-utilities.css +1 -1
  397. package/dist/ui/components/Accordion.js +1 -1
  398. package/dist/ui/components/Breadcrumb.js +1 -1
  399. package/dist/ui/components/DetailPageGallery.js +0 -2
  400. package/dist/ui/components/DetailPageHero.js +0 -1
  401. package/dist/ui/components/DetailPageTabs.js +1 -1
  402. package/dist/ui/components/Divider.js +3 -3
  403. package/dist/ui/components/GatedPrice.js +5 -1
  404. package/dist/ui/components/HorizontalScroller.js +1 -1
  405. package/dist/ui/components/ListingLayout.js +3 -3
  406. package/dist/ui/components/MediaTabs.style.css +81 -0
  407. package/dist/ui/components/Pagination.js +1 -1
  408. package/dist/ui/components/PendingValue.d.ts +45 -0
  409. package/dist/ui/components/PendingValue.js +7 -0
  410. package/dist/ui/components/Radio.style.css +119 -0
  411. package/dist/ui/components/RatingDisplay.js +2 -2
  412. package/dist/ui/components/SettingsSection.js +0 -2
  413. package/dist/ui/components/SiteLogo.js +3 -0
  414. package/dist/ui/components/SiteMark.js +3 -0
  415. package/dist/ui/components/SortDropdown.js +1 -1
  416. package/dist/ui/components/SpecTable.d.ts +58 -0
  417. package/dist/ui/components/SpecTable.js +8 -0
  418. package/dist/ui/components/StarRating.js +1 -3
  419. package/dist/ui/components/SummaryCard.js +1 -1
  420. package/dist/ui/components/index.style.css +1 -0
  421. package/dist/ui/icons/icon-registry.d.ts +1 -0
  422. package/dist/ui/icons/icon-registry.js +9 -1
  423. package/dist/ui/index.d.ts +4 -0
  424. package/dist/ui/index.js +2 -0
  425. package/dist/utils/search-txt-query.d.ts +12 -0
  426. package/dist/utils/search-txt-query.js +12 -0
  427. package/package.json +1 -1
  428. package/scripts/dedupe-peer-deps.mjs +18 -0
  429. package/scripts/seed-cli.mjs +135 -26
  430. package/scripts/verify-css-build.mjs +118 -37
  431. package/dist/_internal/server/features/search/actions.d.ts +0 -7
  432. package/dist/_internal/server/features/search/actions.js +0 -21
  433. package/dist/_internal/server/features/search/data.d.ts +0 -15
  434. package/dist/_internal/server/features/search/data.js +0 -18
  435. package/dist/_internal/server/features/search/index.d.ts +0 -3
  436. package/dist/_internal/server/features/search/index.js +0 -2
  437. package/dist/features/homepage/api/[id]/route.d.ts +0 -23
  438. package/dist/features/homepage/api/[id]/route.js +0 -103
  439. package/dist/features/homepage/api/route.d.ts +0 -14
  440. package/dist/features/homepage/api/route.js +0 -140
  441. package/dist/features/homepage/api/sections/[id]/route.d.ts +0 -26
  442. package/dist/features/homepage/api/sections/[id]/route.js +0 -95
  443. package/dist/features/homepage/api/sections/route.d.ts +0 -13
  444. package/dist/features/homepage/api/sections/route.js +0 -82
  445. package/dist/features/homepage/components/AdvertisementBanner.d.ts +0 -14
  446. package/dist/features/homepage/components/AdvertisementBanner.js +0 -35
  447. package/dist/features/homepage/components/BeforeAfterCard.d.ts +0 -9
  448. package/dist/features/homepage/components/BeforeAfterCard.js +0 -73
  449. package/dist/features/homepage/components/FeaturedResultsSection.d.ts +0 -17
  450. package/dist/features/homepage/components/FeaturedResultsSection.js +0 -17
  451. package/dist/features/homepage/components/HeroBanner.d.ts +0 -7
  452. package/dist/features/homepage/components/HeroBanner.js +0 -43
  453. package/dist/features/homepage/components/HeroSection.d.ts +0 -7
  454. package/dist/features/homepage/components/HeroSection.js +0 -6
  455. package/dist/features/homepage/components/HomepageSkeleton.d.ts +0 -2
  456. package/dist/features/homepage/components/HomepageSkeleton.js +0 -21
  457. package/dist/features/homepage/components/HomepageView.d.ts +0 -25
  458. package/dist/features/homepage/components/HomepageView.js +0 -5
  459. package/dist/features/homepage/components/NewsletterBanner.d.ts +0 -23
  460. package/dist/features/homepage/components/NewsletterBanner.js +0 -37
  461. package/dist/features/homepage/components/SiteFeaturesSection.d.ts +0 -14
  462. package/dist/features/homepage/components/SiteFeaturesSection.js +0 -11
  463. package/dist/features/homepage/components/TrustBadges.d.ts +0 -6
  464. package/dist/features/homepage/components/TrustBadges.js +0 -46
  465. package/dist/features/homepage/components/TrustIndicatorsSection.d.ts +0 -12
  466. package/dist/features/homepage/components/TrustIndicatorsSection.js +0 -11
  467. package/dist/features/homepage/hooks/useHomepage.d.ts +0 -11
  468. package/dist/features/homepage/hooks/useHomepage.js +0 -17
  469. package/dist/features/homepage/hooks/useHomepageSections.d.ts +0 -2
  470. package/dist/features/homepage/hooks/useHomepageSections.js +0 -10
  471. package/dist/features/homepage/repository/homepage.repository.d.ts +0 -11
  472. package/dist/features/homepage/repository/homepage.repository.js +0 -25
  473. package/dist/features/search/actions/index.d.ts +0 -1
  474. package/dist/features/search/actions/index.js +0 -1
  475. package/dist/features/search/actions/search-actions.d.ts +0 -18
  476. package/dist/features/search/actions/search-actions.js +0 -43
  477. package/dist/features/search/api/route.d.ts +0 -22
  478. package/dist/features/search/api/route.js +0 -128
  479. package/dist/features/search/columns/index.d.ts +0 -17
  480. package/dist/features/search/columns/index.js +0 -49
  481. package/dist/features/search/components/SearchFiltersRow.d.ts +0 -22
  482. package/dist/features/search/components/SearchFiltersRow.js +0 -21
  483. package/dist/features/search/components/SearchResultsSection.d.ts +0 -53
  484. package/dist/features/search/components/SearchResultsSection.js +0 -35
  485. package/dist/features/search/components/SearchView.d.ts +0 -27
  486. package/dist/features/search/components/SearchView.js +0 -8
  487. package/dist/features/search/hooks/useSearch.d.ts +0 -21
  488. package/dist/features/search/hooks/useSearch.js +0 -33
  489. package/dist/features/search/repository/search.repository.d.ts +0 -14
  490. package/dist/features/search/repository/search.repository.js +0 -59
  491. package/dist/features/search/schemas/index.d.ts +0 -70
  492. package/dist/features/search/schemas/index.js +0 -36
  493. package/dist/features/search/types/index.d.ts +0 -48
  494. package/dist/features/stores/components/StoreScopedSearch.d.ts +0 -17
  495. package/dist/features/stores/components/StoreScopedSearch.js +0 -27
  496. package/dist/seed/defaults/homepage-sections.d.ts +0 -2
  497. package/dist/seed/defaults/homepage-sections.js +0 -60
  498. package/dist/seed/factories/homepage-section.factory.d.ts +0 -10
  499. package/dist/seed/factories/homepage-section.factory.js +0 -13
  500. /package/dist/{features/search/types/index.js → _internal/shared/listing-types/spares/og.d.ts} +0 -0
@@ -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
- maxQuantityPerLine: 1,
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, paymentMethod) => {
47
- if (paymentMethod && PRIZE_DRAW_BLOCKED_PAYMENT_METHODS.includes(paymentMethod)) {
48
- const hasPrizeDraw = pairs.some((p) => p.product.listingType === "prize-draw");
49
- if (hasPrizeDraw) {
50
- throw Object.assign(new ValidationError("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."), { code: "PRIZE_DRAW_PAYMENT_METHOD_BLOCKED" });
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;
@@ -0,0 +1,5 @@
1
+ import { DEFAULT_LISTING_RULE } from "./_defaults.js";
2
+ export const sparesRule = {
3
+ ...DEFAULT_LISTING_RULE,
4
+ orderType: "standard",
5
+ };
@@ -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
  }
@@ -119,6 +119,120 @@ export interface AppkitSeoConfig {
119
119
  /** BCP 47 locale tag for OG/schema.org, e.g. "en-IN" */
120
120
  locale?: string;
121
121
  }
122
+ /**
123
+ * A value the business has not decided yet.
124
+ *
125
+ * 🛑 `null`, deliberately, rather than `undefined` or an empty string. All
126
+ * three would render the same blank space, and only this one is distinguishable
127
+ * from "the key is missing" at a glance in the config file — which matters
128
+ * because every field typed this way appears on a page whose purpose is legal
129
+ * disclosure. A renderer is expected to show a visible `[to be confirmed]`
130
+ * marker (`<PendingValue>`), never an empty gap, so that an unfilled statutory
131
+ * field is obvious to whoever looks at the page rather than reading as absent.
132
+ */
133
+ export type PendingString = string | null;
134
+ /** Registered postal address of the legal entity. */
135
+ export interface AppkitBusinessAddress {
136
+ line1: string;
137
+ line2?: string;
138
+ city: string;
139
+ state: string;
140
+ /**
141
+ * GST state code, e.g. "27" for Maharashtra.
142
+ *
143
+ * 🛑 Must match the first two digits of `AppkitBusinessConfig.gstin`, and is
144
+ * an INPUT to the intra- vs inter-state supply decision that picks CGST+SGST
145
+ * over IGST. Wrong here means wrong tax on every invoice.
146
+ */
147
+ stateCode: string;
148
+ postalCode: string;
149
+ country: string;
150
+ }
151
+ export interface AppkitBusinessSupport {
152
+ email?: PendingString;
153
+ phone?: PendingString;
154
+ /** WhatsApp number with country code, digits only, e.g. "918919665811". */
155
+ whatsapp?: PendingString;
156
+ /** Human-readable, e.g. "Mon-Sat, 10:00-19:00 IST". */
157
+ hours?: PendingString;
158
+ }
159
+ /**
160
+ * Grievance officer. A mandatory published disclosure for an Indian
161
+ * e-commerce platform under the Consumer Protection (E-Commerce) Rules 2020
162
+ * and the IT Rules 2021 — name, designation and a working contact.
163
+ */
164
+ export interface AppkitBusinessGrievance {
165
+ name?: PendingString;
166
+ designation?: PendingString;
167
+ email?: PendingString;
168
+ phone?: PendingString;
169
+ }
170
+ /**
171
+ * Published policy terms, as PROSE rather than numbers.
172
+ *
173
+ * "2-3 business days" carries its own unit; a bare `3` forces every renderer
174
+ * to re-invent one, and they will not agree.
175
+ */
176
+ export interface AppkitBusinessPolicy {
177
+ processingTime?: PendingString;
178
+ deliveryEstimate?: PendingString;
179
+ shippingCharges?: PendingString;
180
+ cancellationWindow?: PendingString;
181
+ returnWindow?: PendingString;
182
+ refundTimeline?: PendingString;
183
+ }
184
+ /** Where buyers paying by bank transfer or UPI send money. */
185
+ export interface AppkitBusinessBank {
186
+ name?: PendingString;
187
+ accountName?: PendingString;
188
+ /**
189
+ * Home branch, e.g. "Koramangala, Bangalore". Buyer-facing and NOT private:
190
+ * it identifies a public bank location, carries no account identifier, and
191
+ * some transfer forms still ask for it. Contrast `accountNumber`/`ifsc`
192
+ * below, which do identify the account and are withheld.
193
+ */
194
+ branchName?: PendingString;
195
+ /** 🛑 PRIVATE. Never on the public GET /api/site-settings. */
196
+ accountNumber?: PendingString;
197
+ /** 🛑 PRIVATE. Never on the public GET /api/site-settings. */
198
+ ifsc?: PendingString;
199
+ /** UPI Virtual Payment Address, e.g. "name@bank". Buyer-facing. */
200
+ upiVpa?: PendingString;
201
+ /**
202
+ * Root-relative path to the payment QR image.
203
+ *
204
+ * 🛑 A STATIC asset under public/, never a `/media/<slug>`. The media proxy
205
+ * composites a watermark onto every image it serves and has no skip
206
+ * mechanism, and a mark over a QR can corrupt enough modules to break the
207
+ * scan. `resolveMediaUrl` returns a relative path untouched, which is what
208
+ * makes a static path safe here.
209
+ */
210
+ qrImagePath?: string;
211
+ }
212
+ /**
213
+ * Statutory identity of the legal entity behind the site.
214
+ *
215
+ * This is the ONE owner of these facts. They are published by law, so none of
216
+ * it is secret and all of it belongs in a committed, reviewable file; the
217
+ * corresponding `BUSINESS_*` env vars exist to override per deployment.
218
+ */
219
+ export interface AppkitBusinessConfig {
220
+ /** Registered legal name, e.g. "Let It Rip India". */
221
+ legalName: string;
222
+ /** Proprietor / authorised signatory. */
223
+ proprietor?: string;
224
+ /** e.g. "Sole proprietorship", "Private limited company". */
225
+ structure?: string;
226
+ /** 15-character GSTIN. Validate with `isValidGstin` — shape AND checksum. */
227
+ gstin?: PendingString;
228
+ /** Udyam (MSME) registration number. */
229
+ udyamNumber?: PendingString;
230
+ registeredAddress?: AppkitBusinessAddress;
231
+ support?: AppkitBusinessSupport;
232
+ grievance?: AppkitBusinessGrievance;
233
+ policy?: AppkitBusinessPolicy;
234
+ bank?: AppkitBusinessBank;
235
+ }
122
236
  export interface AppkitI18nConfig {
123
237
  /** next-intl localePrefix strategy (default: "never") */
124
238
  localePrefix?: "never" | "always" | "as-needed";
@@ -146,6 +260,14 @@ export interface AppkitConfig {
146
260
  locales?: string[];
147
261
  /** Brand identity — name, social URLs, taglines */
148
262
  brand?: AppkitBrandConfig;
263
+ /**
264
+ * Statutory identity of the legal entity — legal name, GSTIN, registered
265
+ * address, support channels, grievance officer, published policy terms.
266
+ *
267
+ * Distinct from `brand`, which is how the site PRESENTS itself. "LetItRip"
268
+ * is the brand; "Let It Rip India" is the entity that issues the invoice.
269
+ */
270
+ business?: AppkitBusinessConfig;
149
271
  /** SEO defaults — siteUrl, defaultTitle, OG image, Twitter handle */
150
272
  seo?: AppkitSeoConfig;
151
273
  /** i18n / next-intl routing options */
@@ -1,3 +1,4 @@
1
+ import { STANDARD_MAX_QTY_PER_LINE } from "../../checkout/rules/_limits.js";
1
2
  import { z } from "zod";
2
3
  const cartItemBaseSchema = z.object({
3
4
  productId: z.string().min(1),
@@ -7,7 +8,7 @@ const cartItemBaseSchema = z.object({
7
8
  currency: z.string().default("INR"),
8
9
  storeId: z.string(),
9
10
  storeName: z.string().default(""),
10
- quantity: z.number().int().min(1).max(99).default(1),
11
+ quantity: z.number().int().min(1).max(STANDARD_MAX_QTY_PER_LINE).default(1),
11
12
  // SB1-G Phase 4 — canonical listing-kind snapshot.
12
13
  // SB-UNI-D — "bundle" removed from the listing-kind enum.
13
14
  /*
@@ -41,7 +42,7 @@ const cartItemBaseSchema = z.object({
41
42
  export const addToCartSchema = cartItemBaseSchema;
42
43
  export const updateCartItemSchema = z.object({
43
44
  productId: z.string().min(1),
44
- quantity: z.number().int().min(1).max(99),
45
+ quantity: z.number().int().min(1).max(STANDARD_MAX_QTY_PER_LINE),
45
46
  });
46
47
  export const removeFromCartSchema = z.object({
47
48
  productId: z.string().min(1),
@@ -0,0 +1,75 @@
1
+ /**
2
+ * What a seller or admin may constrain about a self-assembled selection.
3
+ *
4
+ * 🛑 These are limits on the SELECTION, never on stock. Stock is independent
5
+ * per listing (there is no pool and no bill of materials) — a spare attack ring
6
+ * is one object the seller happens to have. These answer "what counts as a
7
+ * valid mix", which is a merchandising decision.
8
+ */
9
+ export interface GroupRules {
10
+ /** Fewest DISTINCT members a valid selection may contain. */
11
+ groupMinMembers?: number;
12
+ /** Most distinct members. */
13
+ groupMaxMembers?: number;
14
+ /** Ceiling on units of any ONE member, independent of the line total. */
15
+ groupMaxUnitsPerMember?: number;
16
+ /** Product ids that must be present for the selection to be valid. */
17
+ groupRequiredMemberIds?: string[];
18
+ /**
19
+ * Percentage off the selection's subtotal, 0–100.
20
+ *
21
+ * 🛑 Carried here but NOT applied here, and that separation is deliberate.
22
+ * The discount has to land inside the repository's private `deriveLinePrice`,
23
+ * which runs on every `groupMembers` write and feeds
24
+ * `expandCartLineToOrderRows`' per-member GST proration via
25
+ * `allocateAcrossMembers`. Applying it in a second place is how the cart
26
+ * total comes to disagree with the invoice (Root Cause #75), so this module
27
+ * only ever REPORTS the figure.
28
+ */
29
+ groupDiscountPercent?: number;
30
+ }
31
+ export declare const EMPTY_GROUP_RULES: GroupRules;
32
+ /** Whichever document the rules were read off. */
33
+ export type GroupRuleSource = "product-group" | "grouped-listing";
34
+ /**
35
+ * Read the rules off either home.
36
+ *
37
+ * Structurally typed on purpose: a product group's rules live on the PARENT
38
+ * product document and a grouped listing's on its own, and both are just
39
+ * objects carrying these optional keys. Taking `ProductDocument |
40
+ * GroupedListingDocument` here would drag two feature schemas into a shared
41
+ * module for no gain — and this module is imported by a client component.
42
+ */
43
+ export declare function readGroupRules(doc: Partial<GroupRules> | null | undefined): GroupRules;
44
+ export interface GroupRuleViolation {
45
+ code: "GROUP_TOO_FEW_MEMBERS" | "GROUP_TOO_MANY_MEMBERS" | "GROUP_MEMBER_QTY_EXCEEDED" | "GROUP_REQUIRED_MEMBER_MISSING";
46
+ /** Buyer-facing, already specific. Never a raw field name. */
47
+ message: string;
48
+ }
49
+ /** One chosen member: which product, and how many of it. */
50
+ export interface GroupSelectionEntry {
51
+ productId: string;
52
+ quantity: number;
53
+ /** For the message. Falls back to the id when the caller has no title. */
54
+ title?: string;
55
+ }
56
+ /**
57
+ * Check a selection against the rules.
58
+ *
59
+ * Returns ALL violations rather than the first, because a picker shows them
60
+ * together and fixing one at a time is a worse experience than seeing the set.
61
+ * The server throws on the first; that is the caller's choice, not this
62
+ * function's.
63
+ *
64
+ * Entries at quantity 0 are ignored — the picker's stepper has `min={0}` and
65
+ * zero means "not chosen", so counting them would make an untouched member
66
+ * count toward `groupMinMembers`.
67
+ */
68
+ export declare function checkGroupRules(rules: GroupRules, selection: readonly GroupSelectionEntry[]): GroupRuleViolation[];
69
+ /**
70
+ * The rules in words, for the picker's header.
71
+ *
72
+ * Returns an empty array when nothing is restricted, so the caller renders
73
+ * nothing rather than an empty box saying "Rules:".
74
+ */
75
+ export declare function describeGroupRules(rules: GroupRules): string[];