@mohasinac/appkit 4.53.1 → 4.54.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (384) hide show
  1. package/dist/.build-stamp.json +3 -3
  2. package/dist/_internal/client/theme/ThemeProvider.js +15 -1
  3. package/dist/_internal/server/features/auth/capabilities.js +7 -5
  4. package/dist/_internal/server/features/categories/price-guidance-resolve.d.ts +66 -0
  5. package/dist/_internal/server/features/categories/price-guidance-resolve.js +138 -0
  6. package/dist/_internal/server/features/checkout/actions.d.ts +22 -6
  7. package/dist/_internal/server/features/checkout/actions.js +96 -51
  8. package/dist/_internal/server/features/checkout/index.d.ts +1 -1
  9. package/dist/_internal/server/features/checkout/index.js +1 -1
  10. package/dist/_internal/server/features/checkout/supplier-identity.js +28 -6
  11. package/dist/_internal/server/features/orders/adapters.js +1 -3
  12. package/dist/_internal/server/features/price-index/market.d.ts +57 -0
  13. package/dist/_internal/server/features/price-index/market.js +120 -0
  14. package/dist/_internal/server/features/products/list-public.d.ts +12 -0
  15. package/dist/_internal/server/features/products/list-public.js +10 -1
  16. package/dist/_internal/server/features/products/listing-tab-counts.d.ts +25 -1
  17. package/dist/_internal/server/features/products/listing-tab-counts.js +184 -10
  18. package/dist/_internal/server/features/search/index-build/sources.js +43 -2
  19. package/dist/_internal/server/features/site-settings/adapters.js +1 -1
  20. package/dist/_internal/server/features/stores/adapters.d.ts +1 -1
  21. package/dist/_internal/server/features/stores/adapters.js +0 -1
  22. package/dist/_internal/server/features/stores/tabs.d.ts +7 -2
  23. package/dist/_internal/server/features/stores/tabs.js +5 -3
  24. package/dist/_internal/server/jobs/core/analyticsAlertEvaluate.js +2 -5
  25. package/dist/_internal/server/jobs/core/jobRunners.js +0 -10
  26. package/dist/_internal/server/jobs/core/onOrderCreate.js +10 -104
  27. package/dist/_internal/server/jobs/core/onOrderStatusChange.d.ts +0 -2
  28. package/dist/_internal/server/jobs/core/onOrderStatusChange.js +0 -1
  29. package/dist/_internal/server/jobs/core/onScamReportCreate.js +0 -1
  30. package/dist/_internal/server/jobs/core/onScamReportRejected.js +0 -1
  31. package/dist/_internal/server/jobs/core/onScamReportVerified.js +0 -1
  32. package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +0 -1
  33. package/dist/_internal/server/jobs/core/pendingOrderTimeout.js +0 -1
  34. package/dist/_internal/server/notifications/channel-health.d.ts +7 -3
  35. package/dist/_internal/server/notifications/channel-health.js +2 -2
  36. package/dist/_internal/server/notifications/send-guard.d.ts +1 -1
  37. package/dist/_internal/server/notifications/send-guard.js +2 -4
  38. package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
  39. package/dist/_internal/shared/actions/action-registry.js +128 -28
  40. package/dist/_internal/shared/checkout/order-math.d.ts +1 -1
  41. package/dist/_internal/shared/checkout/order-math.js +1 -1
  42. package/dist/_internal/shared/features/categories/bundle-copy.d.ts +1 -1
  43. package/dist/_internal/shared/features/checkout/config.d.ts +0 -2
  44. package/dist/_internal/shared/features/checkout/config.js +0 -2
  45. package/dist/_internal/shared/features/messaging/config.d.ts +7 -5
  46. package/dist/_internal/shared/features/messaging/config.js +1 -4
  47. package/dist/_internal/shared/features/site-settings/fees.d.ts +0 -2
  48. package/dist/_internal/shared/features/site-settings/fees.js +0 -2
  49. package/dist/_internal/shared/features/site-settings/supplier-of-record.d.ts +56 -0
  50. package/dist/_internal/shared/features/site-settings/supplier-of-record.js +57 -0
  51. package/dist/_internal/shared/fees/calculator.d.ts +0 -8
  52. package/dist/_internal/shared/fees/calculator.js +0 -7
  53. package/dist/_internal/shared/listing-types/tiers.d.ts +94 -0
  54. package/dist/_internal/shared/listing-types/tiers.js +150 -0
  55. package/dist/_internal/shared/search/match.js +28 -2
  56. package/dist/cli/index.js +0 -2
  57. package/dist/client.d.ts +25 -4
  58. package/dist/client.js +36 -5
  59. package/dist/constants/api-endpoints.d.ts +28 -15
  60. package/dist/constants/api-endpoints.js +14 -8
  61. package/dist/constants/field-names.d.ts +1 -0
  62. package/dist/constants/field-names.js +1 -0
  63. package/dist/constants/notification-types.d.ts +1 -1
  64. package/dist/constants/notification-types.js +1 -1
  65. package/dist/core/integration-keys.d.ts +5 -5
  66. package/dist/core/integration-keys.js +21 -10
  67. package/dist/features/about/components/FeesView.js +0 -6
  68. package/dist/features/about/components/GuidesHubView.js +15 -2
  69. package/dist/features/account/components/NotificationPreferencesPanel.js +3 -4
  70. package/dist/features/account/components/UserOrdersView.js +26 -7
  71. package/dist/features/account/types/index.d.ts +0 -2
  72. package/dist/features/addresses/utils/postal-autofill.d.ts +39 -0
  73. package/dist/features/addresses/utils/postal-autofill.js +54 -0
  74. package/dist/features/admin/actions/notification-actions.d.ts +2 -8
  75. package/dist/features/admin/actions/notification-actions.js +9 -104
  76. package/dist/features/admin/components/AdminGuideHubView.js +1 -8
  77. package/dist/features/admin/components/AdminOrderEditorView.d.ts +1 -1
  78. package/dist/features/admin/components/AdminOrdersView.js +0 -2
  79. package/dist/features/admin/components/AdminSectionsView.js +3 -2
  80. package/dist/features/admin/components/AdminSiteSettingsView.js +22 -68
  81. package/dist/features/admin/components/AdminStoreEditorView.js +72 -34
  82. package/dist/features/admin/components/OwnerQuickActions.d.ts +29 -0
  83. package/dist/features/admin/components/OwnerQuickActions.js +142 -0
  84. package/dist/features/admin/components/sections/adminSectionsTypes.js +13 -4
  85. package/dist/features/admin/components/sections/icon-options.d.ts +21 -0
  86. package/dist/features/admin/components/sections/icon-options.js +23 -0
  87. package/dist/features/admin/components/sections/sectionTemplates.js +4 -1
  88. package/dist/features/admin/constants/site-settings-tabs.d.ts +7 -12
  89. package/dist/features/admin/constants/site-settings-tabs.js +6 -12
  90. package/dist/features/admin/repository/site-settings.repository.js +1 -1
  91. package/dist/features/admin/schemas/admin-editor-forms.d.ts +1 -1
  92. package/dist/features/admin/schemas/admin-editor-forms.js +4 -1
  93. package/dist/features/admin/schemas/admin-user-form.d.ts +0 -61
  94. package/dist/features/admin/schemas/admin-user-form.js +3 -44
  95. package/dist/features/admin/schemas/firestore.d.ts +28 -54
  96. package/dist/features/admin/schemas/firestore.js +40 -18
  97. package/dist/features/auctions/components/AuctionDetailPageView.js +12 -10
  98. package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +11 -1
  99. package/dist/features/auctions/components/MarketplaceAuctionCard.js +9 -2
  100. package/dist/features/auth/checkout-value-otp.d.ts +1 -1
  101. package/dist/features/auth/checkout-value-otp.js +1 -1
  102. package/dist/features/auth/permissions/constants.d.ts +29 -2
  103. package/dist/features/auth/permissions/constants.js +67 -1
  104. package/dist/features/blog/components/BlogFeaturedCard.d.ts +11 -1
  105. package/dist/features/blog/components/BlogFeaturedCard.js +9 -2
  106. package/dist/features/cart/components/CartDrawer.js +3 -2
  107. package/dist/features/cart/components/CartGroupLineRow.js +2 -1
  108. package/dist/features/cart/components/CartPriceBreakdown.d.ts +0 -2
  109. package/dist/features/cart/components/CartPriceBreakdown.js +1 -1
  110. package/dist/features/cart/components/StoreAddonsPicker.d.ts +2 -5
  111. package/dist/features/cart/components/StoreAddonsPicker.js +4 -5
  112. package/dist/features/cart/hooks/useAddToCart.js +10 -5
  113. package/dist/features/cart/repository/cart.repository.js +1 -2
  114. package/dist/features/cart/schemas/firestore.d.ts +1 -2
  115. package/dist/features/cart/utils/pending-ops.d.ts +11 -1
  116. package/dist/features/cart/utils/pending-ops.js +14 -2
  117. package/dist/features/categories/api/[id]/price-guidance/route.js +1 -24
  118. package/dist/features/categories/components/BrandDetailPageView.js +15 -6
  119. package/dist/features/categories/components/BrandDetailTabs.d.ts +7 -1
  120. package/dist/features/categories/components/BrandDetailTabs.js +18 -3
  121. package/dist/features/categories/components/BundleCollage.js +3 -2
  122. package/dist/features/categories/components/BundleDetailView.js +2 -1
  123. package/dist/features/categories/components/BundleItemsPicker.js +3 -4
  124. package/dist/features/categories/components/CategoryDetailPageView.js +19 -8
  125. package/dist/features/categories/components/CategoryDetailTabs.d.ts +7 -1
  126. package/dist/features/categories/components/CategoryDetailTabs.js +29 -7
  127. package/dist/features/categories/components/CategoryGrid.d.ts +11 -1
  128. package/dist/features/categories/components/CategoryGrid.js +9 -2
  129. package/dist/features/checkout/actions/checkout-value-otp-actions.d.ts +10 -5
  130. package/dist/features/checkout/actions/checkout-value-otp-actions.js +2 -88
  131. package/dist/features/classified/components/ClassifiedDetailPageView.js +12 -2
  132. package/dist/features/digital-codes/components/DigitalCodeDetailPageView.js +12 -2
  133. package/dist/features/events/components/EventCard.d.ts +11 -1
  134. package/dist/features/events/components/EventCard.js +9 -2
  135. package/dist/features/grouped/components/GroupedListingDetailView.js +3 -1
  136. package/dist/features/homepage/components/CTABannerSection.d.ts +3 -1
  137. package/dist/features/homepage/components/CTABannerSection.js +6 -3
  138. package/dist/features/homepage/components/HeroCarousel.js +8 -6
  139. package/dist/features/homepage/components/MarketplaceHomepageView.js +33 -7
  140. package/dist/features/homepage/components/SectionCarousel.js +13 -5
  141. package/dist/features/homepage/components/SecurityHighlightsSection.d.ts +8 -3
  142. package/dist/features/homepage/components/SecurityHighlightsSection.js +2 -2
  143. package/dist/features/homepage/components/StatsCounterSection.d.ts +9 -4
  144. package/dist/features/homepage/components/StatsCounterSection.js +2 -2
  145. package/dist/features/homepage/components/TestimonialsCarousel.js +1 -1
  146. package/dist/features/homepage/components/TrustFeaturesSection.d.ts +18 -4
  147. package/dist/features/homepage/components/TrustFeaturesSection.js +5 -5
  148. package/dist/features/homepage/components/WelcomeSection.d.ts +13 -2
  149. package/dist/features/homepage/components/WelcomeSection.js +3 -3
  150. package/dist/features/homepage/components/WhatsAppCommunitySection.d.ts +28 -0
  151. package/dist/features/homepage/components/WhatsAppCommunitySection.js +42 -6
  152. package/dist/features/homepage/components/WhatsAppGlyph.d.ts +20 -0
  153. package/dist/features/homepage/components/WhatsAppGlyph.js +20 -0
  154. package/dist/features/homepage/constants/hero-carousel-styles.d.ts +8 -6
  155. package/dist/features/homepage/constants/hero-carousel-styles.js +8 -6
  156. package/dist/features/homepage/constants/section-copy.d.ts +12 -10
  157. package/dist/features/homepage/constants/section-copy.js +28 -6
  158. package/dist/features/homepage/constants/stat-icons.d.ts +12 -0
  159. package/dist/features/homepage/constants/stat-icons.js +17 -0
  160. package/dist/features/homepage/constants/trust-icon-aliases.d.ts +8 -0
  161. package/dist/features/homepage/constants/trust-icon-aliases.js +75 -0
  162. package/dist/features/homepage/lib/section-defaults.d.ts +16 -1
  163. package/dist/features/homepage/lib/section-defaults.js +24 -4
  164. package/dist/features/homepage/lib/section-renderer.js +48 -8
  165. package/dist/features/homepage/schemas/firestore.d.ts +18 -1
  166. package/dist/features/layout/AppLayoutShell.js +2 -1
  167. package/dist/features/layout/BottomActions.d.ts +1 -0
  168. package/dist/features/layout/BottomActions.js +330 -0
  169. package/dist/features/layout/BottomChrome.d.ts +45 -0
  170. package/dist/features/layout/BottomChrome.js +5 -17
  171. package/dist/features/layout/SideActionDock.js +36 -13
  172. package/dist/features/layout/index.d.ts +2 -7
  173. package/dist/features/layout/index.js +7 -7
  174. package/dist/features/layout/useIsDesktop.d.ts +36 -0
  175. package/dist/features/layout/useIsDesktop.js +48 -0
  176. package/dist/features/live/components/LiveItemDetailPageView.js +12 -2
  177. package/dist/features/orders/actions/refund-actions.js +0 -1
  178. package/dist/features/orders/components/OrderAddonBadges.d.ts +1 -3
  179. package/dist/features/orders/components/OrderAddonBadges.js +3 -4
  180. package/dist/features/orders/components/OrderPaymentSummary.js +15 -2
  181. package/dist/features/orders/components/YourPurchaseStrip.d.ts +24 -0
  182. package/dist/features/orders/components/YourPurchaseStrip.js +77 -0
  183. package/dist/features/orders/components/index.d.ts +2 -1
  184. package/dist/features/orders/components/index.js +1 -1
  185. package/dist/features/orders/repository/orders.repository.d.ts +0 -8
  186. package/dist/features/orders/repository/orders.repository.js +0 -2
  187. package/dist/features/orders/schemas/firestore.d.ts +17 -9
  188. package/dist/features/orders/types/index.d.ts +2 -5
  189. package/dist/features/orders/utils/order-announcement-message.d.ts +18 -0
  190. package/dist/features/orders/utils/order-announcement-message.js +16 -0
  191. package/dist/features/orders/utils/payment-proof-message.d.ts +20 -0
  192. package/dist/features/orders/utils/payment-proof-message.js +17 -0
  193. package/dist/features/parts/components/PartDetailPageView.js +96 -1
  194. package/dist/features/parts/schemas/firestore.d.ts +247 -0
  195. package/dist/features/parts/schemas/firestore.js +6 -6
  196. package/dist/features/pre-orders/components/MarketplacePreorderCard.d.ts +11 -1
  197. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +10 -3
  198. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +12 -10
  199. package/dist/features/price-index/components/PriceIndexToolView.d.ts +21 -0
  200. package/dist/features/price-index/components/PriceIndexToolView.js +230 -27
  201. package/dist/features/price-index/lookup-target.d.ts +48 -0
  202. package/dist/features/price-index/lookup-target.js +107 -0
  203. package/dist/features/products/api/[id]/route.js +8 -1
  204. package/dist/features/products/api/route.js +16 -4
  205. package/dist/features/products/components/AvailabilityScopeHint.d.ts +22 -0
  206. package/dist/features/products/components/AvailabilityScopeHint.js +27 -0
  207. package/dist/features/products/components/CompareOverlay.d.ts +2 -1
  208. package/dist/features/products/components/CompareOverlay.js +2 -1
  209. package/dist/features/products/components/GroupSettingsPanel.js +2 -1
  210. package/dist/features/products/components/InteractiveProductCard.d.ts +7 -1
  211. package/dist/features/products/components/InteractiveProductCard.js +16 -4
  212. package/dist/features/products/components/MarketplaceBundleCard.d.ts +11 -1
  213. package/dist/features/products/components/MarketplaceBundleCard.js +9 -2
  214. package/dist/features/products/components/MarketplacePrizeDrawCard.d.ts +11 -1
  215. package/dist/features/products/components/MarketplacePrizeDrawCard.js +9 -2
  216. package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -1
  217. package/dist/features/products/components/ProductDetailPageView.js +34 -4
  218. package/dist/features/products/components/ProductGrid.d.ts +14 -1
  219. package/dist/features/products/components/ProductGrid.js +22 -5
  220. package/dist/features/products/components/ProductsIndexListing.js +2 -2
  221. package/dist/features/products/components/SublistingCarouselSection.js +2 -1
  222. package/dist/features/products/repository/products.repository.d.ts +1 -0
  223. package/dist/features/products/repository/products.repository.js +5 -1
  224. package/dist/features/products/utils/group-member-image.d.ts +9 -2
  225. package/dist/features/products/utils/group-member-image.js +2 -1
  226. package/dist/features/reviews/api/[id]/route.js +83 -23
  227. package/dist/features/reviews/components/PurchaseReviewAffordance.d.ts +6 -0
  228. package/dist/features/reviews/components/PurchaseReviewAffordance.js +42 -0
  229. package/dist/features/reviews/components/ReviewFormDrawer.d.ts +34 -0
  230. package/dist/features/reviews/components/ReviewFormDrawer.js +127 -0
  231. package/dist/features/reviews/components/index.d.ts +4 -0
  232. package/dist/features/reviews/components/index.js +2 -0
  233. package/dist/features/scams/schemas/index.d.ts +10 -10
  234. package/dist/features/search/action-index/settings-entries.js +0 -9
  235. package/dist/features/seller/actions/seller-actions.d.ts +1 -1
  236. package/dist/features/seller/actions/seller-actions.js +49 -3
  237. package/dist/features/seller/components/SellerPayoutSettingsView.js +30 -2
  238. package/dist/features/seller/components/SellerProductShell.d.ts +17 -1
  239. package/dist/features/seller/components/SellerProductsView.js +3 -2
  240. package/dist/features/seller/hooks/useStoreListingEntitlements.d.ts +8 -0
  241. package/dist/features/seller/hooks/useStoreListingEntitlements.js +70 -0
  242. package/dist/features/store-extensions/repository/store-extensions.repositories.d.ts +1 -6
  243. package/dist/features/store-extensions/repository/store-extensions.repositories.js +1 -10
  244. package/dist/features/store-extensions/schemas/firestore.d.ts +1 -17
  245. package/dist/features/store-extensions/schemas/firestore.js +0 -10
  246. package/dist/features/stores/components/InteractiveStoreCard.d.ts +11 -1
  247. package/dist/features/stores/components/InteractiveStoreCard.js +9 -2
  248. package/dist/features/stores/components/StoreAuctionsListing.js +2 -1
  249. package/dist/features/stores/components/StoreCapabilitiesGuideView.js +0 -1
  250. package/dist/features/stores/components/StoreGuideHubView.js +2 -8
  251. package/dist/features/stores/components/StoreSettingsGuideView.js +2 -6
  252. package/dist/features/stores/components/index.d.ts +0 -2
  253. package/dist/features/stores/components/index.js +0 -1
  254. package/dist/features/stores/repository/store.repository.d.ts +1 -26
  255. package/dist/features/stores/repository/store.repository.js +5 -60
  256. package/dist/features/stores/schemas/firestore.d.ts +6 -25
  257. package/dist/features/stores/schemas/firestore.js +6 -3
  258. package/dist/features/stores/schemas/index.d.ts +1 -87
  259. package/dist/features/stores/schemas/index.js +10 -15
  260. package/dist/features/tester/seed-data/authored/admin__site-system.js +0 -48
  261. package/dist/features/tester/seed-data/authored/buying__buying-checkout.js +0 -40
  262. package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.js +114 -2
  263. package/dist/features/tester/seed-data/authored/selling__quick-add-minimum-details.js +0 -16
  264. package/dist/features/tester/seed-data/authored/selling__seller-guide.js +1 -1
  265. package/dist/features/tester/seed-data/authored/selling__seller-marketing-extras.js +0 -79
  266. package/dist/features/tester/seed-data/authored/selling__seller-orders.js +1 -1
  267. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +427 -69
  268. package/dist/index.d.ts +20 -32
  269. package/dist/index.js +34 -43
  270. package/dist/next/routing/route-map.d.ts +2 -8
  271. package/dist/next/routing/route-map.js +21 -4
  272. package/dist/providers/db-firebase/base.repository.d.ts +1 -1
  273. package/dist/providers/db-firebase/base.repository.js +1 -1
  274. package/dist/providers/payment-razorpay/index.d.ts +125 -0
  275. package/dist/providers/payment-razorpay/index.js +232 -0
  276. package/dist/providers/payment-razorpay/signature.d.ts +53 -0
  277. package/dist/providers/payment-razorpay/signature.js +71 -0
  278. package/dist/providers/shipping-shiprocket/index.d.ts +98 -0
  279. package/dist/providers/shipping-shiprocket/index.js +356 -0
  280. package/dist/providers.d.ts +3 -0
  281. package/dist/providers.js +3 -0
  282. package/dist/react/hooks/useCanSeePrices.d.ts +0 -27
  283. package/dist/react/hooks/useCanSeePrices.js +25 -0
  284. package/dist/repositories/index.d.ts +1 -1
  285. package/dist/repositories/index.js +1 -1
  286. package/dist/schemas/registry.d.ts +10 -115
  287. package/dist/schemas/registry.js +1 -2
  288. package/dist/security/pii-encrypt.js +1 -1
  289. package/dist/seed/_helpers/category-forest.js +27 -0
  290. package/dist/seed/_helpers/category-parts-glossary-map.js +1816 -86
  291. package/dist/seed/_helpers/category-parts.d.ts +1 -1
  292. package/dist/seed/_helpers/category-parts.js +13412 -3020
  293. package/dist/seed/carousel-slides-seed-data.js +47 -10
  294. package/dist/seed/categories-seed-data.js +48 -6
  295. package/dist/seed/faq-seed-data.js +2 -2
  296. package/dist/seed/homepage-sections-seed-data.js +286 -54
  297. package/dist/seed/index.d.ts +1 -1
  298. package/dist/seed/index.js +1 -1
  299. package/dist/seed/manifest.d.ts +1 -1
  300. package/dist/seed/manifest.js +1 -2
  301. package/dist/seed/model-composition-seed-data.js +6 -8
  302. package/dist/seed/part-glossary/chunk0.d.ts +9 -0
  303. package/dist/seed/part-glossary/chunk0.js +35448 -0
  304. package/dist/seed/part-glossary/chunk1.d.ts +9 -0
  305. package/dist/seed/part-glossary/chunk1.js +40494 -0
  306. package/dist/seed/part-glossary/chunk2.d.ts +9 -0
  307. package/dist/seed/part-glossary/chunk2.js +51242 -0
  308. package/dist/seed/part-glossary/chunk3.d.ts +9 -0
  309. package/dist/seed/part-glossary/chunk3.js +53337 -0
  310. package/dist/seed/part-glossary/chunk4.d.ts +9 -0
  311. package/dist/seed/part-glossary/chunk4.js +51454 -0
  312. package/dist/seed/part-glossary-seed-data.d.ts +1 -1
  313. package/dist/seed/part-glossary-seed-data.js +23 -47483
  314. package/dist/seed/products-beyblade-x-seed-data.js +36 -1
  315. package/dist/seed/site-settings-seed-data.js +34 -35
  316. package/dist/seed/store-extensions-seed-data.d.ts +1 -2
  317. package/dist/seed/store-extensions-seed-data.js +1 -23
  318. package/dist/seed/stores-seed-data.js +0 -1
  319. package/dist/server-entry.d.ts +1 -1
  320. package/dist/server-entry.js +1 -1
  321. package/dist/server.d.ts +10 -10
  322. package/dist/server.js +24 -22
  323. package/dist/styles.css +392 -43
  324. package/dist/tailwind-utilities.css +1 -1
  325. package/dist/tokens/themes/default-dark.js +1 -1
  326. package/dist/tokens/themes/default-light.js +2 -1
  327. package/dist/tokens/tokens.css +6 -2
  328. package/dist/ui/components/Button.d.ts +11 -0
  329. package/dist/ui/components/Button.js +11 -0
  330. package/dist/ui/components/Button.style.css +29 -0
  331. package/dist/ui/components/CarouselNav.d.ts +57 -0
  332. package/dist/ui/components/CarouselNav.js +25 -0
  333. package/dist/ui/components/CarouselNav.style.css +265 -0
  334. package/dist/ui/components/GatedPrice.js +30 -3
  335. package/dist/ui/components/GatedPrice.style.css +43 -40
  336. package/dist/ui/components/HorizontalScroller.d.ts +12 -1
  337. package/dist/ui/components/HorizontalScroller.js +43 -3
  338. package/dist/ui/components/ImageMosaic.d.ts +8 -1
  339. package/dist/ui/components/ImageMosaic.js +3 -2
  340. package/dist/ui/components/ImageMosaic.style.css +22 -0
  341. package/dist/ui/components/Layout.style.css +6 -0
  342. package/dist/ui/components/Semantic.d.ts +3 -2
  343. package/dist/ui/components/Semantic.js +1 -0
  344. package/dist/ui/components/Typography.d.ts +2 -0
  345. package/dist/ui/components/Typography.js +2 -0
  346. package/dist/ui/components/Typography.style.css +19 -0
  347. package/dist/ui/components/index.style.css +1 -0
  348. package/dist/ui/index.d.ts +3 -1
  349. package/dist/ui/index.js +4 -0
  350. package/package.json +3 -2
  351. package/scripts/seed-cli.mjs +133 -27
  352. package/dist/_internal/server/jobs/core/whatsappCatalogImport.d.ts +0 -27
  353. package/dist/_internal/server/jobs/core/whatsappCatalogImport.js +0 -172
  354. package/dist/_internal/server/jobs/core/whatsappNotify.d.ts +0 -35
  355. package/dist/_internal/server/jobs/core/whatsappNotify.js +0 -140
  356. package/dist/features/admin/components/AdminWhatsAppGuideView.d.ts +0 -2
  357. package/dist/features/admin/components/AdminWhatsAppGuideView.js +0 -35
  358. package/dist/features/orders/components/MarketplaceOrderCard.d.ts +0 -36
  359. package/dist/features/orders/components/MarketplaceOrderCard.js +0 -57
  360. package/dist/features/stores/components/StoreWhatsAppGuideView.d.ts +0 -3
  361. package/dist/features/stores/components/StoreWhatsAppGuideView.js +0 -12
  362. package/dist/features/whatsapp-bot/api/send-status/route.d.ts +0 -12
  363. package/dist/features/whatsapp-bot/api/send-status/route.js +0 -38
  364. package/dist/features/whatsapp-bot/api/webhook/route.d.ts +0 -12
  365. package/dist/features/whatsapp-bot/api/webhook/route.js +0 -43
  366. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.d.ts +0 -6
  367. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +0 -270
  368. package/dist/features/whatsapp-bot/components/WhatsAppChatButton.d.ts +0 -9
  369. package/dist/features/whatsapp-bot/components/WhatsAppChatButton.js +0 -7
  370. package/dist/features/whatsapp-bot/components/index.d.ts +0 -3
  371. package/dist/features/whatsapp-bot/components/index.js +0 -2
  372. package/dist/features/whatsapp-bot/helpers/payment-proof-message.d.ts +0 -14
  373. package/dist/features/whatsapp-bot/helpers/payment-proof-message.js +0 -17
  374. package/dist/features/whatsapp-bot/helpers/whatsapp.d.ts +0 -52
  375. package/dist/features/whatsapp-bot/helpers/whatsapp.js +0 -283
  376. package/dist/features/whatsapp-bot/index.d.ts +0 -3
  377. package/dist/features/whatsapp-bot/index.js +0 -3
  378. package/dist/features/whatsapp-bot/manifest.d.ts +0 -2
  379. package/dist/features/whatsapp-bot/manifest.js +0 -13
  380. package/dist/features/whatsapp-bot/messages/en.json +0 -7
  381. package/dist/features/whatsapp-bot/server.d.ts +0 -7
  382. package/dist/features/whatsapp-bot/server.js +0 -7
  383. package/dist/features/whatsapp-bot/types/index.d.ts +0 -126
  384. package/dist/features/whatsapp-bot/types/index.js +0 -1
@@ -742,16 +742,6 @@ const rawTesterChecklistItems = [
742
742
  label: "Carts ≥ the admin-configured high-value OTP threshold (Site Settings → Shipping → \"High-value checkout OTP threshold\", default ₹5,000) prompt a \"Verify this order\" email OTP right before payment (except COD); carts below the threshold check out directly with no OTP step at all",
743
743
  description: "Root-caused 2026-08-20 — the OTP email send used to be fire-and-forget, so a Resend/API failure silently left the buyer stuck with no code and no error. Sending now surfaces a real error if the email genuinely fails to send, and the \"already sent, retry in N minutes\" rate-limit message is a clear sentence instead of a raw error code. Place a real order ≥ the threshold and confirm the code actually arrives by email (check spam too) — report the exact error text if it still doesn't.",
744
744
  },
745
- {
746
- key: "checkout-otp-whatsapp-option",
747
- label: "When the admin has WhatsApp OTP switched on, the high-value checkout verification step offers a \"Send via WhatsApp instead\" option — and email, not WhatsApp, is still what gets sent by default",
748
- description: "Added 2026-08-21. WhatsApp is deliberately opt-in for OTP: the code must arrive by email unless the buyer explicitly clicks the WhatsApp option. Requires Site Settings → Notifications → WhatsApp → \"WhatsApp OTP\" enabled AND real Meta Cloud API credentials saved, AND the selected delivery address having a phone number. Verify: (a) the default send is email; (b) the WhatsApp option only appears when all three conditions hold; (c) clicking it delivers the code to the address's phone and the on-screen text switches to the masked phone number; (d) the code from WhatsApp verifies successfully.",
749
- },
750
- {
751
- key: "checkout-otp-whatsapp-hidden-without-phone",
752
- label: "The \"Send via WhatsApp instead\" option is NOT offered when the selected delivery address has no phone number on it, even with WhatsApp OTP enabled",
753
- description: "Added 2026-08-21. The phone is resolved server-side from the selected address (never from anything the browser sends), so an address with no phone has nowhere to send the code. Select/create a delivery address with the phone field empty and confirm the WhatsApp option is absent rather than appearing and then failing.",
754
- },
755
745
  { key: "payment-method-selection", label: "Choosing between COD, UPI/manual, and PhonePe (when enabled) at checkout works" },
756
746
  { key: "payment-window-countdown", label: "Manual-payment orders show a 15-minute countdown timer on the payment page" },
757
747
  { key: "payment-proof-upload", label: "Uploading manual payment proof (screenshot, UTR, mark-as-paid + agreement checkboxes) works" },
@@ -777,7 +767,7 @@ const rawTesterChecklistItems = [
777
767
  },
778
768
  {
779
769
  key: "checkout-order-summary-full-breakdown",
780
- label: "The checkout Order Summary panel shows Shipping, COD handling fee (when COD is the likely method), the selected add-on fees (WhatsApp updates / gift wrap / shipment protection — only the ones checked), GST (when enabled), and Coupon discount as separate line items with icons before you pay — not just Subtotal and Total",
770
+ label: "The checkout Order Summary panel shows Shipping, COD handling fee (when COD is the likely method), the selected add-on fees (gift wrap / shipment protection — only the ones checked), GST (when enabled), and Coupon discount as separate line items with icons before you pay — not just Subtotal and Total",
781
771
  description: "Fixed 2026-08-20 — the Order Summary previously showed Total = Subtotal − coupon discount only; shipping and every fee were computed and charged server-side but never shown to the buyer beforehand. Reach the payment step with an address selected, toggle an add-on checkbox, and confirm the matching line appears in the summary a moment later and the Total updates to match — then confirm the same Total appears on the order confirmation page afterward.",
782
772
  href: "/checkout",
783
773
  },
@@ -1301,7 +1291,7 @@ const rawTesterChecklistItems = [
1301
1291
  },
1302
1292
  {
1303
1293
  key: "cart-breakdown-aggregate-only",
1304
- label: "The expanded breakdown shows ONE line per fee type (Shipping, WhatsApp updates, Gift wrap, Platform fee, GST…) with a \"(N stores)\" qualifier where a fee applies to several sellers — not a separate block per store",
1294
+ label: "The expanded breakdown shows ONE line per fee type (Shipping, Gift wrap, Platform fee, GST…) with a \"(N stores)\" qualifier where a fee applies to several sellers — not a separate block per store",
1305
1295
  description: "Per-store detail belongs on each seller card, not in this panel. Confirm the two don't duplicate each other.",
1306
1296
  href: "/cart",
1307
1297
  },
@@ -1329,8 +1319,8 @@ const rawTesterChecklistItems = [
1329
1319
  },
1330
1320
  {
1331
1321
  key: "cart-addons-per-store",
1332
- label: "Ticking \"WhatsApp order updates\" on ONE seller's card charges the fee once (₹10, not ₹20 on a two-seller cart) and shows it under that seller only",
1333
- description: "Requires Site Settings → Fees → WhatsApp notify fee enabled. Core regression guard: the selection used to be a single cart-wide checkbox while the fee was billed per seller, so one tick charged every store in the cart.",
1322
+ label: "Ticking \"Gift wrap\" on ONE seller's card charges the fee once (₹49, not ₹98 on a two-seller cart) and shows it under that seller only",
1323
+ description: "Requires Site Settings → Fees → gift wrap fee enabled. Core regression guard: the selection used to be a single cart-wide checkbox while the fee was billed per seller, so one tick charged every store in the cart.",
1334
1324
  href: "/cart",
1335
1325
  },
1336
1326
  {
@@ -1362,8 +1352,8 @@ const rawTesterChecklistItems = [
1362
1352
  },
1363
1353
  {
1364
1354
  key: "order-addon-icons-visible",
1365
- label: "An order that included add-ons shows icon chips for them (WhatsApp updates / Gift wrap / Protected) plus the coupon code, on the buyer's order page, the seller's order detail AND the admin order drawer",
1366
- description: "These are fulfilment instructions, not decoration: WhatsApp tells the notifier to message this buyer on status change, and gift wrap tells the packer to wrap the parcel. Check all three surfaces — they render from one shared component, so if one is missing something is unwired.",
1355
+ label: "An order that included add-ons shows icon chips for them (Gift wrap / Protected) plus the coupon code, on the buyer's order page, the seller's order detail AND the admin order drawer",
1356
+ description: "These are fulfilment instructions, not decoration: gift wrap tells the packer to wrap the parcel, and protection changes how a claim is handled. Check all three surfaces — they render from one shared component, so if one is missing something is unwired.",
1367
1357
  href: "/user/orders",
1368
1358
  },
1369
1359
  {
@@ -2491,7 +2481,7 @@ const rawTesterChecklistItems = [
2491
2481
  { key: "confirm-payment", label: "Approving a buyer's manual payment proof works" },
2492
2482
  { key: "request-reupload", label: "Requesting a proof re-upload (honest-mistake tier) clears the proof and extends the buyer's deadline" },
2493
2483
  { key: "reject-fraud", label: "Rejecting a proof as fraudulent cancels the order, restores stock, and bans the buyer's account for 7 days" },
2494
- { key: "whatsapp-admin-share", label: "Uploading payment proof pings the admin WhatsApp numbers, and the buyer's \"Share for review\" link opens with a pre-filled message" },
2484
+ { key: "whatsapp-admin-share", label: "Uploading payment proof records a staff notification, and the buyer's \"Share for review\" wa.me link opens with a pre-filled message" },
2495
2485
  { key: "mark-shipped", label: "Marking an order shipped with tracking info works" },
2496
2486
  { key: "tracking-visible", label: "Buyer sees updated tracking status after seller ships" },
2497
2487
  {
@@ -2581,7 +2571,7 @@ const rawTesterChecklistItems = [
2581
2571
  {
2582
2572
  key: "form-sections-save-unchanged",
2583
2573
  label: "Every migrated form still saves exactly the fields it saved before",
2584
- description: "W8 C3 moved 16 hand-rolled forms onto <SectionForm>. The risk is a field that renders but no longer reaches the payload. On each of these, change EVERY field, save, reload, and confirm each value came back: the admin order editor (status, tracking number, carrier, notes), the admin user editor (role, email verified, display name, phone, tester flags, admin notes, bio, location, website, four social links), WhatsApp settings, the seller order panel, and the ad settings panel. A field that silently reverts is the failure, and nothing errors when it happens.",
2574
+ description: "W8 C3 moved 16 hand-rolled forms onto <SectionForm>. The risk is a field that renders but no longer reaches the payload. On each of these, change EVERY field, save, reload, and confirm each value came back: the admin order editor (status, tracking number, carrier, notes), the admin user editor (role, email verified, display name, phone, tester flags, admin notes, bio, location, website, four social links), the seller order panel, and the ad settings panel. A field that silently reverts is the failure, and nothing errors when it happens.",
2585
2575
  href: "/admin/orders",
2586
2576
  },
2587
2577
  {
@@ -2801,7 +2791,7 @@ const rawTesterChecklistItems = [
2801
2791
  },
2802
2792
  {
2803
2793
  pageKey: "seller-marketing-extras",
2804
- pageLabel: "Seller Offers, Features, Google Reviews & WhatsApp Catalog",
2794
+ pageLabel: "Seller Offers, Features & Google Reviews",
2805
2795
  href: "/store/offers",
2806
2796
  cases: [
2807
2797
  {
@@ -2812,31 +2802,6 @@ const rawTesterChecklistItems = [
2812
2802
  },
2813
2803
  { key: "seller-features-crud", label: "Seller can create and edit product features", href: "/store/features" },
2814
2804
  { key: "seller-google-reviews-sync", label: "Google Reviews sync pulls in real reviews correctly", href: "/store/google-reviews" },
2815
- { key: "seller-whatsapp-catalog", label: "WhatsApp catalog import/push works", href: "/store/whatsapp" },
2816
- {
2817
- key: "seller-whatsapp-token-save",
2818
- label: "Saving a WhatsApp access token on the store succeeds and comes back masked — it must not error out",
2819
- description: "Added 2026-08-21. The store's WhatsApp access token is encrypted before storage by the same mechanism as the admin Integrations keys, and that mechanism was failing in production — so this save path was broken too, in a place nobody would think to check. Enter a throwaway token value, save, reload the page, and confirm you got a success toast and the field shows a masked value rather than an error or a blank field.",
2820
- href: "/store/whatsapp",
2821
- },
2822
- {
2823
- key: "seller-whatsapp-import-runs-in-background",
2824
- label: "\"Import from WhatsApp\" returns immediately and reports its result when the background job finishes — the page never hangs waiting on it",
2825
- description: "Changed 2026-08-22 — the import used to run inline and could time out on a large catalog, silently importing only the first 250 items. It now runs as a background job, so expect an immediate \"import started\" response and a result toast a few moments later.",
2826
- href: "/store/whatsapp",
2827
- },
2828
- {
2829
- key: "seller-whatsapp-import-skips-already-synced",
2830
- label: "Re-running \"Import from WhatsApp\" a second time imports nothing new — everything is reported as already synced",
2831
- description: "Items pushed from here carry their LetItRip slug, so a repeat import must not create duplicate draft products. Run it twice and compare the counts.",
2832
- href: "/store/whatsapp",
2833
- },
2834
- {
2835
- key: "seller-whatsapp-push-product-link-opens",
2836
- label: "A product pushed to the WhatsApp catalog links back to a working, full product URL — not a broken relative link",
2837
- description: "Fixed 2026-08-22 — the pushed link was a relative path Meta rejects. Open the item in your WhatsApp catalog and tap through to confirm it lands on the live product page.",
2838
- href: "/store/whatsapp",
2839
- },
2840
2805
  { key: "seller-reviews-response", label: "Seller can view and respond to product reviews", href: "/store/reviews" },
2841
2806
  ],
2842
2807
  },
@@ -2944,7 +2909,7 @@ const rawTesterChecklistItems = [
2944
2909
  },
2945
2910
  {
2946
2911
  pageKey: "quick-add-minimum-details",
2947
- pageLabel: "Quick add — the short form, and what WhatsApp shows",
2912
+ pageLabel: "Quick add — the short form",
2948
2913
  href: "/store/products/new",
2949
2914
  cases: [
2950
2915
  {
@@ -2957,11 +2922,6 @@ const rawTesterChecklistItems = [
2957
2922
  label: "The short form alone can publish a real, buyable listing",
2958
2923
  description: "If it cannot, it is a decoy: the seller fills it, is refused, and has to learn the long form anyway — having done the work twice.",
2959
2924
  },
2960
- {
2961
- key: "whatsapp-shows-the-same-fields",
2962
- label: "Everything WhatsApp shows was already asked for by the short form",
2963
- description: "The catalog push sends title, price, image, condition and stock. That is the quick form field set, which is why the short form is the right shape — a seller who fills only it has supplied everything a WhatsApp buyer will see.",
2964
- },
2965
2925
  {
2966
2926
  key: "advanced-flip-keeps-values",
2967
2927
  label: "Switching to the full form keeps everything already typed",
@@ -3301,6 +3261,18 @@ const rawTesterChecklistItems = [
3301
3261
  { key: "regional-code-reads-as-regional", label: "A Korean or Middle-East code names its region instead of coming back unrecorded" },
3302
3262
  { key: "series-window-names-the-production-run", label: "A derivable date names its Metal-series production window, or names none outside all four" },
3303
3263
  { key: "temporal-context-for-an-unmatched-code", label: "An unmatched code reports what else the tables record from the same month, framed as context not a match" },
3264
+ /* ── The model picker and the per-model code list (2026-10-20) ───
3265
+ * The reported bug: naming a bey the tool holds 33 recorded box
3266
+ * codes for produced "Nothing contradicts it, and nothing confirms
3267
+ * it either" and never mentioned them. Every case here compares the
3268
+ * answer against data the tool demonstrably has.
3269
+ */
3270
+ { key: "model-picker-finds-l-drago", label: "The model picker finds all three L-Dragos by partial name, and each shows how many box codes are on file" },
3271
+ { key: "picked-model-lists-its-box-codes", label: "Picking a model with no code returns the codes recorded for that exact bey, not a bare 'inconclusive'" },
3272
+ { key: "picked-model-plus-its-own-code", label: "A code recorded against the picked bey reads as agreement; one recorded against a different bey reads as weak support, not a mismatch" },
3273
+ { key: "missing-code-is-not-an-accusation", label: "A code absent from the picked model's list says 'unrecorded', never 'fake', and the verdict stays inconclusive" },
3274
+ { key: "working-out-is-collapsed-by-default", label: "The verdict is readable without expanding anything, and a concern auto-opens the working-out" },
3275
+ { key: "result-scrolls-into-view", label: "Submitting scrolls the verdict into view on a phone rather than leaving it below the fold" },
3304
3276
  ],
3305
3277
  },
3306
3278
  {
@@ -3538,7 +3510,7 @@ const rawTesterChecklistItems = [
3538
3510
  cases: [
3539
3511
  { key: "receive-notification", label: "In-app notifications appear for order/bid/message events", href: "/user/notifications" },
3540
3512
  { key: "mark-read", label: "Marking a notification as read works" },
3541
- { key: "notification-channel-prefs", label: "Per-channel notification preferences (in-app / email / WhatsApp) save and are respected" },
3513
+ { key: "notification-channel-prefs", label: "Per-channel notification preferences (in-app / email) save and are respected" },
3542
3514
  {
3543
3515
  key: "notification-type-sample",
3544
3516
  label: "A sample of notification types each trigger correctly end-to-end — and the bell-only ones produce NO email",
@@ -4562,7 +4534,7 @@ const rawTesterChecklistItems = [
4562
4534
  {
4563
4535
  key: "soft-ban-lift-notification-has-a-body",
4564
4536
  label: "Lifting a user's soft ban sends them a notification WITH a readable message, not just a title",
4565
- description: "Fixed 2026-08-31. BEFORE: the route wrote `body`, `entityId` and `entityType` behind an `as any` — none of which are fields on NotificationDocument (they are `message`, `relatedId`, `relatedType`) — so the bell showed a title and an EMPTY body, and the notification never reached email or WhatsApp. AFTER: as an admin, lift any soft ban on a test user from /admin/users, then open that user's bell. The row must show both the title AND the sentence naming which restriction was lifted, and it must be clickable.",
4537
+ description: "Fixed 2026-08-31. BEFORE: the route wrote `body`, `entityId` and `entityType` behind an `as any` — none of which are fields on NotificationDocument (they are `message`, `relatedId`, `relatedType`) — so the bell showed a title and an EMPTY body, and the notification never reached email. AFTER: as an admin, lift any soft ban on a test user from /admin/users, then open that user's bell. The row must show both the title AND the sentence naming which restriction was lifted, and it must be clickable.",
4566
4538
  href: "/admin/users",
4567
4539
  },
4568
4540
  {
@@ -6047,23 +6019,6 @@ const rawTesterChecklistItems = [
6047
6019
  description: "The toggle lives under the Shipping tab's \"Payment methods\" section (?tab=shipping), not a dedicated Payments tab. With it OFF, /checkout must not offer 'Pay Online (PhonePe)' — only manual UPI/cash and COD (whichever are separately enabled). Turn it ON, save, reload the settings page to confirm it's still ON, then open /checkout and confirm 'Pay Online (PhonePe)' now appears as a payment option.",
6048
6020
  href: "/admin/site",
6049
6021
  },
6050
- {
6051
- key: "whatsapp-credentials-persist",
6052
- label: "Site Settings → WhatsApp saves the Phone Number ID, Cloud API token, admin notify numbers, template language and all 6 template names — and they survive a reload",
6053
- description: "The token field is masked on reload (shows dots, not the raw value) — that is correct. Confirm by changing an unrelated field, saving again, and verifying the token still works rather than being overwritten with the mask.",
6054
- href: "/admin/site",
6055
- },
6056
- {
6057
- key: "whatsapp-channel-toggle-persists",
6058
- label: "Site Settings → Notifications: the WhatsApp channel enable toggle, minimum priority, and the checkout OTP switch all persist after save + reload",
6059
- href: "/admin/site",
6060
- },
6061
- {
6062
- key: "whatsapp-order-announcement-fires",
6063
- label: "Placing an order writes ONE admin notification and WhatsApps only the seller — never the admin number list",
6064
- description: "Rewritten 2026-09. BEFORE: every order WhatsApped every number in the admin notify list, the highest-volume staff blast in the codebase, and it was skipped entirely when Meta credentials were absent — so with no credentials an order produced no staff signal at all and no record that it hadn't. AFTER: place an order and confirm (a) an admin notification row appears for it (visible in the admin notifications inbox, and counted in the next daily digest) EVEN WITH NO META CREDENTIALS CONFIGURED; (b) no WhatsApp message reaches any admin number; (c) with credentials configured, the seller who owns the listing still receives their sale announcement — that one is a single message to one person about their own sale and is deliberately kept.",
6065
- href: "/admin/site",
6066
- },
6067
6022
  {
6068
6023
  key: "auction-bid-tiers-admin",
6069
6024
  label: "Admin can add, edit, and remove bid-increment tiers in Site Settings → Auction Config, and the changes persist after saving and reloading the page",
@@ -7235,6 +7190,409 @@ const rawTesterChecklistItems = [
7235
7190
  ],
7236
7191
  },
7237
7192
  ], { adminOnly: true }),
7193
+ /*
7194
+ * OWNER QUICK-ACTIONS, BUYER PURCHASE CONTEXT, AND THE ADVANCED-TYPE GATE.
7195
+ *
7196
+ * 🛑 Every case here is an explicit BEFORE -> AFTER, and that is not a
7197
+ * stylistic choice. Each defect these cover returned HTTP 200 with plausible
7198
+ * content: a form that saved nothing, a gate that permitted everything, a
7199
+ * review whose search tokens silently described its previous text. A case
7200
+ * reading "check the editor works" passes against all of them.
7201
+ *
7202
+ * The spares case is the proof. Before the fix, every /store/spares/new save
7203
+ * failed Zod validation because the schema's hand-written listingType enum
7204
+ * omitted the type — so a tester told to "check creating a spares listing
7205
+ * works" would answer no, with no idea what correct looked like.
7206
+ */
7207
+ ...group("owner-tools", "Owner tools & purchase context", [
7208
+ {
7209
+ pageKey: "listing-types",
7210
+ pageLabel: "Listing types & the advanced gate",
7211
+ href: "/store/products",
7212
+ cases: [
7213
+ {
7214
+ key: "spares-can-be-created",
7215
+ label: "A spares listing can be created at all",
7216
+ roles: ["seller"],
7217
+ startPage: "/store/spares/new",
7218
+ steps: [
7219
+ "Sign in as the seller who owns store-beyblade-arena.",
7220
+ "Open /store/spares/new and fill in a title, a price and a stock quantity.",
7221
+ "Save as draft, then publish.",
7222
+ "Open /spares and look for the listing.",
7223
+ ],
7224
+ inputs: { title: "QA Spare attack ring", price: 249, stockQuantity: 3 },
7225
+ expectedBehaviour: "productCreateSchema accepts listingType 'spares'. Its enum is DERIVED from ALL_LISTING_TYPES rather than hand-written, so a type in the union cannot be missing from the schema.",
7226
+ expectedUiState: "Both the autosave and the publish succeed, with no field error on listingType. The published row appears on /spares.",
7227
+ endResult: "BEFORE: every save failed validation — the hand-written enum omitted 'spares' while carrying a dead 'bundle' — so the type could not be created at all, even though its 21 pages, its nav entry and its browse page all existed. AFTER: it saves and appears.",
7228
+ },
7229
+ {
7230
+ key: "dead-bundle-type-rejected",
7231
+ label: "listingType 'bundle' is rejected rather than silently stored",
7232
+ roles: ["admin"],
7233
+ startPage: "/admin/products",
7234
+ steps: [
7235
+ "Sign in as admin@letitrip.in / TempPass123!.",
7236
+ "POST to /api/admin/products with a valid product body and listingType set to 'bundle'.",
7237
+ "Read the response status and body.",
7238
+ ],
7239
+ inputs: { listingType: "bundle" },
7240
+ expectedBehaviour: "'bundle' stopped being a listingType in SB-UNI-D — bundles are a categoryType on categories. The derived enum no longer accepts it.",
7241
+ expectedUiState: "A 400 naming listingType. No product is created.",
7242
+ endResult: "BEFORE: it passed validation and wrote a product that pluginFor, LISTING_KIND_ALIAS_MAP and isListingRowAvailable have no branch for — invisible on every surface and uneditable from any UI. AFTER: refused at the door.",
7243
+ },
7244
+ {
7245
+ key: "advanced-types-hidden-for-new-store",
7246
+ label: "A new store sees only Products, Spares and Auctions under Listings",
7247
+ roles: ["seller"],
7248
+ startPage: "/store",
7249
+ steps: [
7250
+ "Sign in as a seller whose store has no advanced_listing_types capability.",
7251
+ "Read every entry in the Listings group of the store sidebar.",
7252
+ "Type /store/live/new directly into the address bar.",
7253
+ ],
7254
+ expectedBehaviour: "The nav filter resolves the store's entitlements SERVER-side — capabilities is a private store field, so a client filter has nothing to read. The create shell refuses a type the store may not use.",
7255
+ expectedUiState: "The Listings group lists Products, Spares and Auctions and nothing else. /store/live/new renders a refusal naming the type and linking to store preferences, not a usable form.",
7256
+ expectedData: { listingNavItems: 3 },
7257
+ endResult: "BEFORE: all eleven entries showed and every per-type new page rendered a complete, usable form for any store. AFTER: three entries, and the advanced pages refuse.",
7258
+ },
7259
+ {
7260
+ key: "advanced-create-refused-server-side",
7261
+ label: "The API refuses an advanced type even when the form is bypassed",
7262
+ roles: ["seller"],
7263
+ startPage: "/store/products",
7264
+ steps: [
7265
+ "Sign in as a seller without the advanced_listing_types capability.",
7266
+ "Call the seller create-product action with listingType 'prize-draw'.",
7267
+ "Read the result.",
7268
+ ],
7269
+ inputs: { listingType: "prize-draw" },
7270
+ expectedBehaviour: "assertListingTypeAllowed runs inside createSellerProduct, where the store document is already loaded — so the refusal costs no extra read and cannot be skipped by calling a different entry point.",
7271
+ expectedUiState: "An authorization error naming the type. No listing is created.",
7272
+ endResult: "BEFORE: the only gate covered auction and pre-order, and it sat behind an if-store check that let a storeless caller through. AFTER: all seven advanced types refused, and a non-admin with no store is refused rather than waved past.",
7273
+ },
7274
+ {
7275
+ key: "cannot-patch-into-advanced-type",
7276
+ label: "A standard listing cannot be PATCHed into an advanced type",
7277
+ roles: ["seller"],
7278
+ startPage: "/store/products",
7279
+ steps: [
7280
+ "Sign in as a seller without the advanced_listing_types capability.",
7281
+ "Create a standard listing and note its id.",
7282
+ "Call the seller update action on it with listingType 'auction', then again with 'prize-draw'.",
7283
+ "Reload the listing and read its type.",
7284
+ ],
7285
+ expectedBehaviour: "The update gate fires on a CHANGE of type. 'auction' is a basic type so it is allowed; 'prize-draw' is advanced and is refused.",
7286
+ expectedUiState: "The prize-draw PATCH returns an authorization error. The listing's type is unchanged after a reload.",
7287
+ endResult: "BEFORE: sellerUpdateProduct had NO type check at all, so the create gate was bypassable in one request. AFTER: it is refused. 🛑 And editing an EXISTING advanced listing still works — the gate fires only on a change, because every per-type edit page re-sends its own type literal.",
7288
+ },
7289
+ {
7290
+ key: "advanced-optin-round-trips",
7291
+ label: "The advanced-types checkbox survives a reload",
7292
+ roles: ["seller"],
7293
+ startPage: "/store/payout-settings",
7294
+ steps: [
7295
+ "Sign in as a seller and open Payout & Preferences from the store sidebar.",
7296
+ "Tick 'Enable advanced listing types' and save.",
7297
+ "RELOAD the page and read the checkbox.",
7298
+ "Open the store sidebar and read the Listings group.",
7299
+ ],
7300
+ expectedBehaviour: "The flag is stored as the advanced_listing_types capability, MERGED into the array rather than replacing it, so admin-granted capabilities survive. The route echoes the saved value back.",
7301
+ expectedUiState: "After the reload the checkbox is still ticked and the Listings group now lists all ten types.",
7302
+ expectedData: { listingNavItems: 10 },
7303
+ endResult: "BEFORE: there was no such control, and /store/payout-settings had no nav entry at all — reachable only by typing the URL. AFTER: it is in the sidebar, and the value round-trips.",
7304
+ },
7305
+ {
7306
+ key: "optin-preserves-admin-capabilities",
7307
+ label: "Saving the seller checkbox does not revoke admin-granted capabilities",
7308
+ roles: ["admin", "seller"],
7309
+ startPage: "/admin/stores",
7310
+ steps: [
7311
+ "As admin, open the store editor for the seller's store and tick 'Verified Seller Badge'. Save.",
7312
+ "Sign in as that seller, open Payout & Preferences, tick 'Enable advanced listing types' and save.",
7313
+ "As admin again, reopen the store editor and read the capability list.",
7314
+ ],
7315
+ expectedBehaviour: "The seller's form owns ONE member of the capabilities array and touches only that member; everything else is read from the stored document and written back unchanged.",
7316
+ expectedUiState: "Verified Seller Badge is still ticked, alongside the new advanced_listing_types.",
7317
+ endResult: "A seller form whose write shape can EXPRESS state it does not own will eventually overwrite it (Root Cause #76). This is the case that proves it does not.",
7318
+ },
7319
+ ],
7320
+ },
7321
+ {
7322
+ pageKey: "owner-quick-actions",
7323
+ pageLabel: "Pencil, clone and bin on public pages",
7324
+ href: "/products",
7325
+ cases: [
7326
+ {
7327
+ key: "no-controls-for-guest",
7328
+ label: "A signed-out visitor sees no pencil, clone or bin anywhere",
7329
+ roles: ["guest"],
7330
+ startPage: "/products",
7331
+ steps: [
7332
+ "Open /products signed out and read a product card.",
7333
+ "Open a product detail page.",
7334
+ "Open /categories and a category page.",
7335
+ ],
7336
+ expectedBehaviour: "The toolbar renders nothing when there is no session, and nothing while the session is still resolving.",
7337
+ expectedUiState: "No edit, duplicate or delete control on any card or detail page.",
7338
+ endResult: "A visitor must never see an owner control, and must never see one flash in and out.",
7339
+ },
7340
+ {
7341
+ key: "no-flash-for-signed-in-owner",
7342
+ label: "The toolbar appears once, without flashing",
7343
+ roles: ["admin"],
7344
+ startPage: "/products",
7345
+ steps: [
7346
+ "Sign in as admin@letitrip.in / TempPass123!.",
7347
+ "HARD-reload /products and watch the first second of the page closely.",
7348
+ "Repeat twice more.",
7349
+ ],
7350
+ expectedBehaviour: "Public pages are ISR and read no session, so loading starts true on every hard load even for a signed-in user. The toolbar renders NOTHING until auth resolves.",
7351
+ expectedUiState: "The controls are absent, then appear once. They never appear, vanish and reappear.",
7352
+ endResult: "A two-state gate here would show nothing, then pop the toolbar in a few hundred ms after every single page load. Appearing late is invisible; flashing is a bug people report.",
7353
+ },
7354
+ {
7355
+ key: "pencil-opens-that-records-editor",
7356
+ label: "The pencil lands on that record's editor, not a list",
7357
+ roles: ["admin"],
7358
+ startPage: "/products",
7359
+ steps: [
7360
+ "Signed in as admin, open a product detail page and note the product title.",
7361
+ "Press the pencil.",
7362
+ "Read the page that opens.",
7363
+ ],
7364
+ expectedBehaviour: "The pencil navigates to that product's edit route.",
7365
+ expectedUiState: "The editor opens on the SAME product, with its title already filled in.",
7366
+ endResult: "BEFORE: there was no control at all — ZERO public detail views rendered any owner affordance — so fixing a typo meant going to the dashboard, finding the list and searching for the row.",
7367
+ },
7368
+ {
7369
+ key: "card-navigation-still-works",
7370
+ label: "A card with owner controls still navigates when clicked",
7371
+ roles: ["admin"],
7372
+ startPage: "/products",
7373
+ steps: [
7374
+ "Signed in as admin, open /products.",
7375
+ "Click a product card anywhere OTHER than the owner controls.",
7376
+ "Go back, then click the pencil on the same card.",
7377
+ ],
7378
+ expectedBehaviour: "The toolbar is rendered OUTSIDE the card's anchor. A button inside an anchor is invalid HTML that browsers resolve by closing the anchor early, which breaks the CARD's navigation.",
7379
+ expectedUiState: "Clicking the card opens the product. Clicking the pencil opens the editor. Neither does both.",
7380
+ endResult: "The card's own link must survive the toolbar being added to it.",
7381
+ },
7382
+ {
7383
+ key: "clone-is-admin-only",
7384
+ label: "A seller sees pencil and bin but NOT clone",
7385
+ roles: ["seller"],
7386
+ startPage: "/products",
7387
+ steps: [
7388
+ "Sign in as the seller who owns store-beyblade-arena.",
7389
+ "Open one of that store's product detail pages.",
7390
+ "Read the owner controls.",
7391
+ ],
7392
+ expectedBehaviour: "Clone is gated on useIsAdmin, not the owner check — useIsOwner returns true for the owner too, so reusing it would hand every seller a staff tool.",
7393
+ expectedUiState: "A pencil and a bin. No duplicate control.",
7394
+ endResult: "Clone is a staff tool; editing and deleting your own listing is ordinary.",
7395
+ },
7396
+ {
7397
+ key: "clone-creates-a-draft-copy",
7398
+ label: "Clone creates a (Copy) draft and opens its editor",
7399
+ roles: ["admin"],
7400
+ startPage: "/products",
7401
+ steps: [
7402
+ "Signed in as admin, open a product detail page and note its title, stock and whether it has bids.",
7403
+ "Press the duplicate control.",
7404
+ "Read the editor that opens: its title, its status, its bid count and its group membership.",
7405
+ "Go back to the original product page and read its title and status.",
7406
+ ],
7407
+ expectedBehaviour: "The duplicate endpoint strips identity (id/slug/barcodeId), analytics (viewCount/avgRating/reviewCount), auction bid state and group membership, titles the copy with a (Copy) suffix and forces status draft. It returns the new id so the UI can land on the copy.",
7408
+ expectedUiState: "The editor opens on a NEW record whose title ends in (Copy), status draft, no bids and no group. The original is untouched.",
7409
+ expectedData: { copyStatus: "draft", copyBidCount: 0 },
7410
+ endResult: "A duplicate must start standalone — silently joined to the source's group is how one edit changes two listings.",
7411
+ },
7412
+ {
7413
+ key: "bin-confirms-before-deleting",
7414
+ label: "The bin confirms, names the record, and cancelling changes nothing",
7415
+ roles: ["admin"],
7416
+ startPage: "/products",
7417
+ steps: [
7418
+ "Signed in as admin, open a product detail page and note its title.",
7419
+ "Press the bin and read the dialog.",
7420
+ "Press Cancel. Reload the page.",
7421
+ "Press the bin again and confirm.",
7422
+ "Try to open the same product URL.",
7423
+ ],
7424
+ expectedBehaviour: "The confirm copy comes from the ACTIONS registry, never inline, and names the record being deleted.",
7425
+ expectedUiState: "The dialog names the product. After Cancel the product is still there on reload. After confirming, the product URL no longer resolves.",
7426
+ endResult: "A destructive control on a PUBLIC page must state what it will destroy, and cancelling must be a true no-op.",
7427
+ },
7428
+ ],
7429
+ },
7430
+ {
7431
+ pageKey: "purchase-context",
7432
+ pageLabel: "Your order & your review on a product page",
7433
+ href: "/products",
7434
+ cases: [
7435
+ {
7436
+ key: "strip-links-to-your-order",
7437
+ label: "A buyer who ordered this item gets a Track link to that order",
7438
+ roles: ["buyer"],
7439
+ startPage: "/user/orders",
7440
+ steps: [
7441
+ "Sign in as a buyer with a seeded order and note the order id and one item in it.",
7442
+ "Open that item's product page.",
7443
+ "Read the strip above the reviews.",
7444
+ "Press Track.",
7445
+ ],
7446
+ expectedBehaviour: "The lookup scans the buyer's recent orders for one containing this product — items[] holds objects, so no Firestore query can match a nested productId.",
7447
+ expectedUiState: "The strip names the order date and its short reference, and Track lands on the track page for THAT order.",
7448
+ endResult: "BEFORE: no surface linked a product to the buyer's own order; the route was remember-you-bought-it, go to /user/orders, page through. 🛑 No price appears in the strip.",
7449
+ },
7450
+ {
7451
+ key: "older-than-window-says-so",
7452
+ label: "A purchase older than 90 days says so rather than denying it",
7453
+ roles: ["buyer"],
7454
+ startPage: "/products",
7455
+ steps: [
7456
+ "Sign in as a buyer and open a product page for an item they have NOT ordered in the last 90 days.",
7457
+ "Read the strip's wording exactly.",
7458
+ ],
7459
+ expectedBehaviour: "The order lookup is a bounded 90-day window, and the response carries windowDays so the UI can state the bound.",
7460
+ expectedUiState: "It reads 'No order for this item in the last 90 days' with a link to all orders. It does NOT read 'you haven't bought this'.",
7461
+ endResult: "🛑 A filtered empty result reported as an absolute zero is a lie the buyer cannot check — the same defect UserOrdersView carries a long comment about.",
7462
+ },
7463
+ {
7464
+ key: "write-then-edit-a-review",
7465
+ label: "A buyer can write a review and then edit it",
7466
+ roles: ["buyer"],
7467
+ startPage: "/products",
7468
+ steps: [
7469
+ "Sign in as a buyer with a delivered order and open one of its items.",
7470
+ "Press 'Write a review' in the strip, give 4 stars, a title and a comment, and save.",
7471
+ "RELOAD the product page and read the strip and the review list.",
7472
+ "Press 'Edit review', change the comment, and save.",
7473
+ "RELOAD again and read the review.",
7474
+ ],
7475
+ inputs: { rating: 4, title: "QA review purchase-context", comment: "First version." },
7476
+ expectedBehaviour: "One form component serves both the inline drawer and /user/reviews/[id]/edit, so the two cannot drift. An approved review edited by its author stays approved.",
7477
+ expectedUiState: "The strip shows 'Your review: 4/5' and the edited comment is the one displayed after the reload.",
7478
+ endResult: "BEFORE: there was NO review form anywhere in the application — useCreateReview had zero component consumers and ViewReviewModal is read-only. AFTER: a review can be written and changed.",
7479
+ },
7480
+ {
7481
+ key: "review-edit-keeps-search-and-images-honest",
7482
+ label: "Editing a review rebuilds its search tokens and its hasImages flag",
7483
+ roles: ["buyer"],
7484
+ startPage: "/user/reviews",
7485
+ steps: [
7486
+ "Sign in as a buyer with an existing review that has at least one image.",
7487
+ "Open /user/reviews and note the review's id.",
7488
+ "Edit the review, replacing a distinctive word in the comment with a new distinctive word, and save.",
7489
+ "Search the product's reviews for the OLD word, then for the NEW word.",
7490
+ "Read the review's stored hasImages against whether it still has images.",
7491
+ ],
7492
+ expectedBehaviour: "The PATCH goes through reviewRepository, so searchTxt is rebuilt and userName stays encrypted; hasImages is derived whenever images is sent.",
7493
+ expectedUiState: "Searching the NEW word finds the review. Searching the OLD word does not.",
7494
+ expectedData: { foundByNewWord: true, foundByOldWord: false },
7495
+ endResult: "BEFORE: the route wrote through a GENERIC repository, so the tokens still described the previous text — the review was findable only by what it used to say — and hasImages went stale.",
7496
+ },
7497
+ {
7498
+ key: "review-get-returns-a-name-not-ciphertext",
7499
+ label: "GET a review by id returns a display name, not enc:v1 ciphertext",
7500
+ roles: ["guest"],
7501
+ startPage: "/reviews",
7502
+ steps: [
7503
+ "Open /api/reviews/{id} for any seeded review.",
7504
+ "Read the userName field and look for a helpfulVoterIds field.",
7505
+ ],
7506
+ expectedBehaviour: "The read goes through reviewRepository, so mapDoc decrypts userName and strips helpfulVoterIds.",
7507
+ expectedUiState: "userName is a readable name. There is no helpfulVoterIds field in the response.",
7508
+ endResult: "BEFORE: the generic repository returned the document verbatim, so this public endpoint served the reviewer's name as raw enc:v1 ciphertext and published the list of everyone who had voted it helpful.",
7509
+ },
7510
+ ],
7511
+ },
7512
+ {
7513
+ pageKey: "order-journey",
7514
+ pageLabel: "Order tracking & search",
7515
+ href: "/user/orders",
7516
+ cases: [
7517
+ {
7518
+ key: "track-offered-before-shipping",
7519
+ label: "Track is offered on a pending order, not only a shipped one",
7520
+ roles: ["buyer"],
7521
+ startPage: "/user/orders",
7522
+ steps: [
7523
+ "Sign in as a buyer with orders in several statuses.",
7524
+ "Find an order that is pending, confirmed or processing.",
7525
+ "Read its row's actions.",
7526
+ "Press Track.",
7527
+ ],
7528
+ expectedBehaviour: "Every pre-delivery status offers Track. The timeline reads correctly for all of them — it shows the stages reached and the stages still ahead.",
7529
+ expectedUiState: "A Track action is present, and it opens the track page for that order.",
7530
+ endResult: "BEFORE: Track appeared only once an order was shipped, so a buyer waiting on a pending order — exactly when they most want to know — had no link at all.",
7531
+ },
7532
+ {
7533
+ key: "track-page-shows-the-parcel",
7534
+ label: "The track page shows items, address, carrier and onward links",
7535
+ roles: ["buyer"],
7536
+ startPage: "/user/orders",
7537
+ steps: [
7538
+ "Open the track page for an order with more than one item and a delivery address.",
7539
+ "Read everything on the page.",
7540
+ ],
7541
+ expectedBehaviour: "Items, the delivery address, the carrier and tracking number, and links to the detail page, the invoice and — once delivered — a return, all come from data already on the order.",
7542
+ expectedUiState: "Item thumbnails and titles with quantities, the delivery address, the short order reference, and the onward action buttons. No price anywhere.",
7543
+ endResult: "BEFORE: the page rendered a timeline and nothing else — a wiring gap, not a data gap. A buyer who wanted their invoice had to go back to the list and find the order again.",
7544
+ },
7545
+ {
7546
+ key: "search-orders-by-item-name",
7547
+ label: "Searching orders matches the item name, and a nonsense term returns the filtered message",
7548
+ roles: ["buyer"],
7549
+ startPage: "/user/orders",
7550
+ steps: [
7551
+ "Sign in as a buyer with several orders and note one item's title.",
7552
+ "Search /user/orders for a distinctive word from that title.",
7553
+ "Now search for 'zzzznope'.",
7554
+ "Read the empty-state wording exactly.",
7555
+ ],
7556
+ inputs: { nonsenseTerm: "zzzznope" },
7557
+ expectedBehaviour: "The in-memory filter matches the item TITLES as well as the order id, and a filtered empty result is reported as filtered.",
7558
+ expectedUiState: "The item word returns that order. 'zzzznope' returns 'No orders match your search or filters.' — NOT 'You haven't placed any orders yet.'",
7559
+ expectedData: { nonsenseResults: 0 },
7560
+ endResult: "BEFORE: the route matched the order id only, so a buyer searching for what they bought got nothing. 🛑 The nonsense control is the point — a real term returns plausible rows whether or not the filter works.",
7561
+ },
7562
+ {
7563
+ key: "invoice-supplier-from-business-block",
7564
+ label: "The invoice names the registered entity from the business block",
7565
+ roles: ["buyer", "admin"],
7566
+ startPage: "/user/orders",
7567
+ steps: [
7568
+ "Open the invoice for a recent order and read the supplier block — legal name, GSTIN, address.",
7569
+ "Compare them against appkit.config.js's business block.",
7570
+ "Download the PDF invoice for the SAME order and compare it line for line with the HTML one.",
7571
+ ],
7572
+ expectedBehaviour: "resolveSupplierIdentity's platform branch reads the injected business identity, and both renderers read the snapshot stamped on the order at creation.",
7573
+ expectedUiState: "The HTML and PDF invoices agree, and the supplier block matches the business block.",
7574
+ endResult: "BEFORE: it read siteSettings.gst, making the invoice path a sixth owner of the statutory identity — and the one that decides what a tax invoice says. 🛑 The snapshot is unchanged, so correcting a typo must NOT reissue historical invoices.",
7575
+ },
7576
+ {
7577
+ key: "user-reviews-list-is-paginated",
7578
+ label: "The user reviews endpoint returns a page, not everything ever written",
7579
+ roles: ["buyer"],
7580
+ startPage: "/user/reviews",
7581
+ steps: [
7582
+ "Sign in as a buyer with several reviews.",
7583
+ "Call /api/user/reviews and read the response keys.",
7584
+ "Call it again with pageSize=1 and read how many reviews come back.",
7585
+ "Call it with pageSize=5000.",
7586
+ ],
7587
+ inputs: { pageSize: 1, oversizedPageSize: 5000 },
7588
+ expectedBehaviour: "The endpoint pages, and clamps pageSize to Rule #6's ceiling of 50.",
7589
+ expectedUiState: "The response carries reviews, total, page, pageSize and totalPages. pageSize=1 returns one review. pageSize=5000 returns at most 50.",
7590
+ expectedData: { maxPageSize: 50 },
7591
+ endResult: "BEFORE: it returned every review the account had ever written, unbounded, in one response.",
7592
+ },
7593
+ ],
7594
+ },
7595
+ ]),
7238
7596
  ];
7239
7597
  const defaultPhases = assignDefaultPhases(rawTesterChecklistItems);
7240
7598
  export const testerChecklistSeedData = rawTesterChecklistItems.map((item, index) => ({