@mohasinac/appkit 4.30.18 → 4.31.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 (557) hide show
  1. package/dist/_internal/client/features/digital-code/CodeRevealPanel.js +5 -2
  2. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +3 -3
  3. package/dist/_internal/client/features/layout/useSidebarSearch.d.ts +21 -5
  4. package/dist/_internal/client/features/layout/useSidebarSearch.js +27 -6
  5. package/dist/_internal/client/features/lottery/LotteryAdminEditView.d.ts +23 -3
  6. package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +106 -86
  7. package/dist/_internal/client/features/lottery/LotteryPullForm.d.ts +16 -5
  8. package/dist/_internal/client/features/lottery/LotteryPullForm.js +65 -40
  9. package/dist/_internal/client/features/maintenance/views/AnalysisRunnerView.js +5 -2
  10. package/dist/_internal/client/features/maintenance/views/CloudLogsListView.js +11 -3
  11. package/dist/_internal/client/hand-mode/HandModeProvider.js +2 -0
  12. package/dist/_internal/server/features/auctions/actions.js +14 -3
  13. package/dist/_internal/server/features/auctions/service.js +1 -1
  14. package/dist/_internal/server/features/auth/permissions.d.ts +2 -0
  15. package/dist/_internal/server/features/auth/permissions.js +3 -2
  16. package/dist/_internal/server/features/blog/data.js +2 -2
  17. package/dist/_internal/server/features/blog/service.js +3 -3
  18. package/dist/_internal/server/features/brands/data.js +1 -1
  19. package/dist/_internal/server/features/brands/service.js +3 -3
  20. package/dist/_internal/server/features/bundles/actions.js +6 -1
  21. package/dist/_internal/server/features/bundles/data.js +21 -4
  22. package/dist/_internal/server/features/cart/data.js +3 -1
  23. package/dist/_internal/server/features/cart/service.js +13 -2
  24. package/dist/_internal/server/features/categories/data.js +26 -6
  25. package/dist/_internal/server/features/classified/index.d.ts +0 -1
  26. package/dist/_internal/server/features/classified/index.js +0 -1
  27. package/dist/_internal/server/features/digital-code/index.d.ts +0 -1
  28. package/dist/_internal/server/features/digital-code/index.js +0 -1
  29. package/dist/_internal/server/features/events/actions.js +17 -4
  30. package/dist/_internal/server/features/events/data.js +1 -1
  31. package/dist/_internal/server/features/events/service.js +1 -1
  32. package/dist/_internal/server/features/grouped/data.js +7 -2
  33. package/dist/_internal/server/features/item-requests/data.js +1 -1
  34. package/dist/_internal/server/features/live/index.d.ts +0 -1
  35. package/dist/_internal/server/features/live/index.js +0 -1
  36. package/dist/_internal/server/features/lottery/actions.js +2 -2
  37. package/dist/_internal/server/features/lottery/data.js +1 -1
  38. package/dist/_internal/server/features/orders/actions.js +7 -7
  39. package/dist/_internal/server/features/orders/data.d.ts +1 -1
  40. package/dist/_internal/server/features/orders/data.js +14 -2
  41. package/dist/_internal/server/features/orders/service.js +1 -1
  42. package/dist/_internal/server/features/pre-orders/service.js +1 -1
  43. package/dist/_internal/server/features/prize-draws/actions.js +1 -1
  44. package/dist/_internal/server/features/products/data.js +21 -6
  45. package/dist/_internal/server/features/products/list-public.d.ts +9 -0
  46. package/dist/_internal/server/features/products/list-public.js +95 -7
  47. package/dist/_internal/server/features/products/service.js +1 -1
  48. package/dist/_internal/server/features/promotions/actions.js +1 -1
  49. package/dist/_internal/server/features/promotions/data.js +1 -1
  50. package/dist/_internal/server/features/promotions/service.js +1 -1
  51. package/dist/_internal/server/features/reviews/data.d.ts +1 -1
  52. package/dist/_internal/server/features/reviews/data.js +6 -1
  53. package/dist/_internal/server/features/reviews/og-data.js +1 -1
  54. package/dist/_internal/server/features/shared/listing-data-factory.js +7 -2
  55. package/dist/_internal/server/features/site-settings/adapters.d.ts +2 -2
  56. package/dist/_internal/server/features/site-settings/adapters.js +8 -5
  57. package/dist/_internal/server/features/stores/data.js +1 -1
  58. package/dist/_internal/server/features/sublisting-categories/data.js +1 -1
  59. package/dist/_internal/server/features/tester/visibility.d.ts +2 -1
  60. package/dist/_internal/server/features/tester/visibility.js +2 -2
  61. package/dist/_internal/server/functions/scheduled.d.ts +3 -1
  62. package/dist/_internal/server/functions/scheduled.js +27 -1
  63. package/dist/_internal/server/jobs/core/auctionSettlement.js +6 -1
  64. package/dist/_internal/server/jobs/core/hardBanCascade.js +4 -0
  65. package/dist/_internal/server/jobs/core/index.d.ts +2 -0
  66. package/dist/_internal/server/jobs/core/index.js +2 -0
  67. package/dist/_internal/server/jobs/core/onOrderStatusChange.js +7 -15
  68. package/dist/_internal/server/jobs/core/pageViewPrune.d.ts +10 -0
  69. package/dist/_internal/server/jobs/core/pageViewPrune.js +44 -0
  70. package/dist/_internal/server/jobs/core/pageViewRollup.d.ts +2 -0
  71. package/dist/_internal/server/jobs/core/pageViewRollup.js +87 -0
  72. package/dist/_internal/server/jobs/core/revenueRollup.js +7 -1
  73. package/dist/_internal/server/jobs/handlers/index.d.ts +2 -0
  74. package/dist/_internal/server/jobs/handlers/index.js +2 -0
  75. package/dist/_internal/server/jobs/handlers/pageViewPrune.d.ts +2 -0
  76. package/dist/_internal/server/jobs/handlers/pageViewPrune.js +2 -0
  77. package/dist/_internal/server/jobs/handlers/pageViewRollup.d.ts +2 -0
  78. package/dist/_internal/server/jobs/handlers/pageViewRollup.js +2 -0
  79. package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
  80. package/dist/_internal/shared/actions/action-registry.js +69 -22
  81. package/dist/_internal/shared/checkout/rules/classified.rule.d.ts +9 -4
  82. package/dist/_internal/shared/checkout/rules/classified.rule.js +7 -2
  83. package/dist/_internal/shared/features/layout/matchesNavQuery.d.ts +14 -0
  84. package/dist/_internal/shared/features/layout/matchesNavQuery.js +72 -0
  85. package/dist/_internal/shared/features/layout/types.d.ts +37 -1
  86. package/dist/_internal/shared/features/layout/types.js +19 -1
  87. package/dist/_internal/shared/features/notifications/action-url.d.ts +9 -1
  88. package/dist/_internal/shared/features/notifications/action-url.js +47 -0
  89. package/dist/_internal/shared/features/offers/config.d.ts +65 -0
  90. package/dist/_internal/shared/features/offers/config.js +73 -2
  91. package/dist/_internal/shared/features/orders/schema.d.ts +19 -1
  92. package/dist/_internal/shared/features/orders/schema.js +22 -2
  93. package/dist/_internal/shared/features/site-settings/types.d.ts +12 -3
  94. package/dist/_internal/shared/listing-types/capabilities.d.ts +8 -2
  95. package/dist/_internal/shared/listing-types/capabilities.js +6 -1
  96. package/dist/_internal/shared/listing-types/classified/ctas.js +6 -1
  97. package/dist/_internal/shared/listing-types/feature-flags.d.ts +10 -5
  98. package/dist/_internal/shared/listing-types/feature-flags.js +11 -6
  99. package/dist/client/api/useApiQuery.js +17 -6
  100. package/dist/client.d.ts +38 -20
  101. package/dist/client.js +39 -14
  102. package/dist/configs/next.js +10 -2
  103. package/dist/constants/api-endpoints.d.ts +18 -54
  104. package/dist/constants/api-endpoints.js +6 -26
  105. package/dist/constants/field-names.d.ts +6 -24
  106. package/dist/constants/field-names.js +10 -27
  107. package/dist/constants/geo/countries.d.ts +50 -0
  108. package/dist/constants/geo/countries.js +129 -0
  109. package/dist/constants/geo/subdivisions.d.ts +13 -0
  110. package/dist/constants/geo/subdivisions.js +104 -0
  111. package/dist/constants/index.d.ts +2 -2
  112. package/dist/constants/index.js +2 -2
  113. package/dist/constants/table-keys.d.ts +24 -0
  114. package/dist/constants/table-keys.js +28 -0
  115. package/dist/contracts/client-realtime.d.ts +6 -0
  116. package/dist/contracts/extend.d.ts +0 -9
  117. package/dist/contracts/index.d.ts +1 -1
  118. package/dist/contracts/realtime-session.d.ts +12 -12
  119. package/dist/contracts/realtime-session.js +79 -77
  120. package/dist/core/browser.d.ts +1 -1
  121. package/dist/core/browser.js +1 -1
  122. package/dist/core/index.d.ts +1 -1
  123. package/dist/core/index.js +1 -1
  124. package/dist/core/site-config.d.ts +0 -3
  125. package/dist/core/site-config.js +0 -3
  126. package/dist/errors/index.d.ts +1 -1
  127. package/dist/errors/index.js +1 -1
  128. package/dist/errors/messages.d.ts +0 -8
  129. package/dist/errors/messages.js +0 -9
  130. package/dist/features/about/components/DeveloperView.js +7 -2
  131. package/dist/features/about/components/PolicyPageView.js +9 -1
  132. package/dist/features/about/components/PublicProfileView.js +23 -5
  133. package/dist/features/about/schemas/index.d.ts +8 -8
  134. package/dist/features/account/components/AddressFilters.js +32 -11
  135. package/dist/features/account/components/AddressForm.d.ts +26 -25
  136. package/dist/features/account/components/AddressForm.js +81 -103
  137. package/dist/features/account/components/AddressesIndexListing.js +8 -4
  138. package/dist/features/account/components/NotificationBell.js +4 -3
  139. package/dist/features/account/components/NotificationPreferencesPanel.js +1 -1
  140. package/dist/features/account/components/UserOffersPanel.js +1 -1
  141. package/dist/features/account/components/UserSidebar.d.ts +3 -4
  142. package/dist/features/account/components/UserSupportView.js +89 -58
  143. package/dist/features/account/components/index.d.ts +1 -7
  144. package/dist/features/account/components/index.js +0 -3
  145. package/dist/features/account/hooks/useAddresses.d.ts +4 -3
  146. package/dist/features/account/hooks/useAddresses.js +4 -6
  147. package/dist/features/account/hooks/useCollapsedSections.d.ts +51 -10
  148. package/dist/features/account/hooks/useCollapsedSections.js +211 -38
  149. package/dist/features/account/hooks/useProfile.d.ts +8 -0
  150. package/dist/features/account/index.d.ts +0 -3
  151. package/dist/features/account/index.js +0 -3
  152. package/dist/features/account/schemas/index.d.ts +0 -92
  153. package/dist/features/account/schemas/index.js +42 -20
  154. package/dist/features/addresses/components/AddressLocationFields.d.ts +13 -0
  155. package/dist/features/addresses/components/AddressLocationFields.js +41 -0
  156. package/dist/features/addresses/hooks/usePostalLookup.d.ts +17 -0
  157. package/dist/features/addresses/hooks/usePostalLookup.js +133 -0
  158. package/dist/features/addresses/schemas/address-form.d.ts +423 -0
  159. package/dist/features/addresses/schemas/address-form.js +212 -0
  160. package/dist/features/addresses/schemas/index.d.ts +1 -0
  161. package/dist/features/addresses/schemas/index.js +8 -0
  162. package/dist/features/admin/actions/admin-read-actions.d.ts +1 -1
  163. package/dist/features/admin/actions/index.d.ts +0 -1
  164. package/dist/features/admin/actions/index.js +0 -1
  165. package/dist/features/admin/actions/notification-actions.js +1 -41
  166. package/dist/features/admin/components/AdminActionIndexView.d.ts +32 -0
  167. package/dist/features/admin/components/AdminActionIndexView.js +128 -0
  168. package/dist/features/admin/components/AdminAdEditorView.js +159 -163
  169. package/dist/features/admin/components/AdminAddressEditorView.js +97 -55
  170. package/dist/features/admin/components/AdminBrandEditorView.d.ts +15 -0
  171. package/dist/features/admin/components/AdminBrandEditorView.js +113 -77
  172. package/dist/features/admin/components/AdminBundleEditorView.d.ts +19 -9
  173. package/dist/features/admin/components/AdminBundleEditorView.js +136 -168
  174. package/dist/features/admin/components/AdminCategoryEditorView.js +120 -43
  175. package/dist/features/admin/components/AdminCouponEditorView.js +145 -109
  176. package/dist/features/admin/components/AdminEmployeeEditorView.js +125 -56
  177. package/dist/features/admin/components/AdminFaqEditorView.js +112 -58
  178. package/dist/features/admin/components/AdminFeatureEditorView.js +108 -68
  179. package/dist/features/admin/components/AdminFulfillmentView.js +5 -2
  180. package/dist/features/admin/components/AdminMediaView.js +3 -3
  181. package/dist/features/admin/components/AdminNavEditorView.js +69 -44
  182. package/dist/features/admin/components/AdminOrderEditorView.js +47 -10
  183. package/dist/features/admin/components/AdminPrizeDrawsView.js +16 -2
  184. package/dist/features/admin/components/AdminSidebar.d.ts +11 -7
  185. package/dist/features/admin/components/AdminSiteSettingsView.js +37 -37
  186. package/dist/features/admin/components/AdminStoreEditorView.js +75 -52
  187. package/dist/features/admin/components/AdminSublistingCategoryEditorView.js +71 -30
  188. package/dist/features/admin/components/AdminTesterChecklistItemEditorView.js +95 -65
  189. package/dist/features/admin/components/BrandQuickCreateForm.d.ts +10 -0
  190. package/dist/features/admin/components/BrandQuickCreateForm.js +49 -26
  191. package/dist/features/admin/components/CategoryQuickCreateForm.d.ts +11 -0
  192. package/dist/features/admin/components/CategoryQuickCreateForm.js +48 -26
  193. package/dist/features/admin/components/index.d.ts +2 -2
  194. package/dist/features/admin/components/index.js +1 -1
  195. package/dist/features/admin/constants/site-settings-tabs.d.ts +120 -0
  196. package/dist/features/admin/constants/site-settings-tabs.js +152 -0
  197. package/dist/features/admin/index.d.ts +0 -3
  198. package/dist/features/admin/index.js +0 -2
  199. package/dist/features/admin/repository/analytics-rollup.repository.d.ts +35 -0
  200. package/dist/features/admin/repository/analytics-rollup.repository.js +30 -0
  201. package/dist/features/admin/schemas/admin-editor-forms.d.ts +56 -57
  202. package/dist/features/admin/schemas/admin-editor-forms.js +97 -54
  203. package/dist/features/admin/schemas/admin-ops-forms.d.ts +57 -5
  204. package/dist/features/admin/schemas/admin-ops-forms.js +104 -20
  205. package/dist/features/admin/schemas/admin-user-form.js +7 -0
  206. package/dist/features/admin/schemas/firestore.d.ts +48 -95
  207. package/dist/features/admin/schemas/firestore.js +15 -151
  208. package/dist/features/admin/schemas/nav-item-form.js +9 -2
  209. package/dist/features/admin/server.d.ts +0 -4
  210. package/dist/features/admin/server.js +0 -2
  211. package/dist/features/admin/types/index.d.ts +0 -7
  212. package/dist/features/analytics/repository/page-views.repository.d.ts +14 -0
  213. package/dist/features/analytics/repository/page-views.repository.js +24 -0
  214. package/dist/features/analytics/types.d.ts +1 -1
  215. package/dist/features/analytics/types.js +13 -0
  216. package/dist/features/auctions/components/AuctionDetailPageView.js +6 -2
  217. package/dist/features/auctions/components/MarketplaceAuctionCard.js +3 -1
  218. package/dist/features/auth/actions/index.d.ts +0 -1
  219. package/dist/features/auth/actions/index.js +0 -1
  220. package/dist/features/auth/actions/profile-actions.js +4 -3
  221. package/dist/features/auth/actions/realtime-token-actions.js +1 -12
  222. package/dist/features/auth/auth-helpers.js +5 -7
  223. package/dist/features/auth/components/ForgotPasswordView.js +1 -1
  224. package/dist/features/auth/components/Guards.js +2 -1
  225. package/dist/features/auth/components/LoginForm.d.ts +0 -2
  226. package/dist/features/auth/components/LoginForm.js +2 -4
  227. package/dist/features/auth/components/RegisterForm.js +62 -19
  228. package/dist/features/auth/components/ResetPasswordView.js +1 -1
  229. package/dist/features/auth/hooks/useAuth.js +3 -0
  230. package/dist/features/auth/permissions/constants.d.ts +27 -1
  231. package/dist/features/auth/role-predicates.d.ts +75 -7
  232. package/dist/features/auth/role-predicates.js +28 -2
  233. package/dist/features/auth/schemas/firestore.d.ts +22 -0
  234. package/dist/features/auth/schemas/index.d.ts +1 -1
  235. package/dist/features/auth/schemas/index.js +44 -8
  236. package/dist/features/auth/types/index.d.ts +14 -1
  237. package/dist/features/blog/api/route.js +10 -2
  238. package/dist/features/blog/components/BlogIndexListing.js +1 -1
  239. package/dist/features/blog/hooks/useBlog.js +2 -2
  240. package/dist/features/blog/repository/blog.repository.js +3 -1
  241. package/dist/features/blog/schemas/index.d.ts +4 -0
  242. package/dist/features/blog/schemas/index.js +2 -0
  243. package/dist/features/blog/types/index.d.ts +1 -1
  244. package/dist/features/cart/actions/cart-actions.js +13 -4
  245. package/dist/features/cart/utils/pending-ops.js +1 -1
  246. package/dist/features/catalogue/components/CatalogueItemEditorView.d.ts +22 -0
  247. package/dist/features/catalogue/components/CatalogueItemEditorView.js +112 -52
  248. package/dist/features/catalogue/schemas/validation.d.ts +4 -4
  249. package/dist/features/catalogue/schemas/validation.js +47 -10
  250. package/dist/features/categories/components/BrandDetailPageView.js +28 -12
  251. package/dist/features/categories/components/CategoryDetailPageView.js +37 -20
  252. package/dist/features/categories/repository/categories.repository.js +3 -1
  253. package/dist/features/categories/schemas/bundle-form.d.ts +142 -0
  254. package/dist/features/categories/schemas/bundle-form.js +149 -0
  255. package/dist/features/checkout/actions/checkout-value-otp-actions.js +10 -1
  256. package/dist/features/classified/components/ClassifiedContactSellerPanel.js +1 -1
  257. package/dist/features/classified/components/ClassifiedDetailPageView.d.ts +5 -4
  258. package/dist/features/classified/components/ClassifiedDetailPageView.js +47 -18
  259. package/dist/features/consultation/components/ConsultationForm.js +1 -1
  260. package/dist/features/consultation/schemas/index.js +34 -10
  261. package/dist/features/corporate/schemas/index.js +36 -15
  262. package/dist/features/digital-codes/components/DigitalCodeDetailPageView.js +4 -1
  263. package/dist/features/events/components/EventBanner.js +5 -2
  264. package/dist/features/events/components/EventOfferCard.js +3 -1
  265. package/dist/features/events/components/EventPollWidget.js +1 -1
  266. package/dist/features/events/components/SpinWheelView.js +3 -2
  267. package/dist/features/filters/FilterPanel.js +3 -3
  268. package/dist/features/filters/RangeFilter.d.ts +10 -0
  269. package/dist/features/filters/RangeFilter.js +41 -4
  270. package/dist/features/grouped/components/GroupedListingEditorView.js +2 -1
  271. package/dist/features/history/hooks/useHistory.js +29 -27
  272. package/dist/features/homepage/components/AdSlot.js +3 -1
  273. package/dist/features/homepage/components/GoogleReviewsSection.js +8 -2
  274. package/dist/features/homepage/components/MarketplaceHomepageView.js +58 -15
  275. package/dist/features/homepage/components/SocialFeedSection.js +4 -1
  276. package/dist/features/homepage/hooks/useBlogArticles.js +1 -1
  277. package/dist/features/homepage/lib/live-stats.js +8 -1
  278. package/dist/features/homepage/repository/carousel.repository.js +2 -1
  279. package/dist/features/layout/BottomActions.js +84 -11
  280. package/dist/features/layout/BottomActionsContext.d.ts +1 -6
  281. package/dist/features/layout/BottomActionsContext.js +1 -1
  282. package/dist/features/layout/hooks/useBottomActions.js +2 -2
  283. package/dist/features/layout/hooks/useFormBottomActions.d.ts +12 -1
  284. package/dist/features/layout/hooks/useFormBottomActions.js +12 -6
  285. package/dist/features/live/components/LiveItemDetailPageView.js +4 -1
  286. package/dist/features/lottery/schemas/config-write.d.ts +9 -5
  287. package/dist/features/lottery/schemas/config-write.js +69 -9
  288. package/dist/features/media/finalize.js +3 -1
  289. package/dist/features/media/modals/ImageEditor.js +1 -1
  290. package/dist/features/media/modals/VideoThumbnailSelector.js +5 -2
  291. package/dist/features/media/modals/VideoTrimModal.js +5 -2
  292. package/dist/features/media/upload/MediaUploadField.js +2 -2
  293. package/dist/features/messages/hooks/useConversation.js +18 -4
  294. package/dist/features/messages/hooks/useConversations.js +25 -8
  295. package/dist/features/orders/components/RefundRequestView.js +5 -2
  296. package/dist/features/orders/schemas/buyer-forms.d.ts +6 -3
  297. package/dist/features/orders/schemas/buyer-forms.js +31 -3
  298. package/dist/features/orders/schemas/index.d.ts +2 -2
  299. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +3 -1
  300. package/dist/features/pre-orders/components/PreOrderActionsClient.js +1 -1
  301. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +4 -1
  302. package/dist/features/products/components/GroupSettingsPanel.js +3 -1
  303. package/dist/features/products/components/MakeOfferButton.d.ts +13 -2
  304. package/dist/features/products/components/MakeOfferButton.js +33 -11
  305. package/dist/features/products/components/PrizeDrawDetailPageView.js +4 -1
  306. package/dist/features/products/components/ProductDetailActions.js +0 -1
  307. package/dist/features/products/components/ProductDetailPageView.d.ts +7 -3
  308. package/dist/features/products/components/ProductDetailPageView.js +16 -7
  309. package/dist/features/products/components/ShareButton.js +3 -1
  310. package/dist/features/products/constants/action-defs.d.ts +1 -2
  311. package/dist/features/products/constants/action-defs.js +40 -43
  312. package/dist/features/products/repository/loadProductFeatures.js +10 -2
  313. package/dist/features/products/repository/products.repository.d.ts +5 -1
  314. package/dist/features/products/repository/products.repository.js +25 -2
  315. package/dist/features/products/schemas/firestore.d.ts +7 -3
  316. package/dist/features/products/schemas/product-features.validators.js +3 -0
  317. package/dist/features/promotions/components/CouponCard.js +11 -8
  318. package/dist/features/reviews/actions/review-actions.js +8 -1
  319. package/dist/features/reviews/components/ReviewDetailPageView.js +13 -3
  320. package/dist/features/reviews/components/ReviewDetailShell.js +3 -1
  321. package/dist/features/scams/actions/scam-actions.d.ts +9 -1
  322. package/dist/features/scams/actions/scam-actions.js +52 -12
  323. package/dist/features/scams/components/SellerTrustBadge.d.ts +1 -1
  324. package/dist/features/scams/components/SellerTrustBadge.js +13 -0
  325. package/dist/features/scams/repository/scammer.repository.js +2 -1
  326. package/dist/features/scams/schemas/firestore.d.ts +15 -1
  327. package/dist/features/scams/schemas/report-form.d.ts +5 -5
  328. package/dist/features/scams/schemas/report-form.js +18 -3
  329. package/dist/features/search/action-index/derive.d.ts +49 -0
  330. package/dist/features/search/action-index/derive.js +121 -0
  331. package/dist/features/search/action-index/repository.d.ts +42 -0
  332. package/dist/features/search/action-index/repository.js +100 -0
  333. package/dist/features/search/action-index/settings-entries.d.ts +41 -0
  334. package/dist/features/search/action-index/settings-entries.js +268 -0
  335. package/dist/features/search/action-index/types.d.ts +81 -0
  336. package/dist/features/search/action-index/types.js +102 -0
  337. package/dist/features/search/action-index/validate-entry.d.ts +34 -0
  338. package/dist/features/search/action-index/validate-entry.js +114 -0
  339. package/dist/features/search/hooks/useNavSuggestions.d.ts +5 -1
  340. package/dist/features/search/hooks/useNavSuggestions.js +23 -3
  341. package/dist/features/search/repository/search.repository.js +3 -1
  342. package/dist/features/seller/actions/offer-actions.js +43 -19
  343. package/dist/features/seller/actions/seller-actions.js +29 -5
  344. package/dist/features/seller/components/CategoryChipPicker.d.ts +9 -0
  345. package/dist/features/seller/components/CategoryChipPicker.js +12 -0
  346. package/dist/features/seller/components/FulfillmentView.js +5 -2
  347. package/dist/features/seller/components/PhysicalLocationModal.js +1 -1
  348. package/dist/features/seller/components/PrintCenterView.js +3 -1
  349. package/dist/features/seller/components/SellerAddressesView.js +5 -1
  350. package/dist/features/seller/components/SellerAnalyticsAlertsView.js +83 -43
  351. package/dist/features/seller/components/SellerArtView.d.ts +14 -7
  352. package/dist/features/seller/components/SellerArtView.js +4 -119
  353. package/dist/features/seller/components/SellerBidsView.js +1 -1
  354. package/dist/features/seller/components/SellerClassifiedView.d.ts +14 -7
  355. package/dist/features/seller/components/SellerClassifiedView.js +4 -124
  356. package/dist/features/seller/components/SellerCouponEditorView.d.ts +22 -1
  357. package/dist/features/seller/components/SellerCouponEditorView.js +91 -45
  358. package/dist/features/seller/components/SellerCouponsView.js +1 -1
  359. package/dist/features/seller/components/SellerDigitalCodesView.d.ts +14 -7
  360. package/dist/features/seller/components/SellerDigitalCodesView.js +4 -126
  361. package/dist/features/seller/components/SellerGoogleReviewsView.js +2 -2
  362. package/dist/features/seller/components/SellerListingTypeView.d.ts +66 -0
  363. package/dist/features/seller/components/SellerListingTypeView.js +277 -0
  364. package/dist/features/seller/components/SellerLiveView.d.ts +14 -7
  365. package/dist/features/seller/components/SellerLiveView.js +4 -126
  366. package/dist/features/seller/components/SellerOrdersView.js +3 -3
  367. package/dist/features/seller/components/SellerPayoutMethodsView.js +2 -2
  368. package/dist/features/seller/components/SellerProductShell.d.ts +5 -0
  369. package/dist/features/seller/components/SellerProductShell.js +15 -5
  370. package/dist/features/seller/components/SellerProductsView.js +24 -10
  371. package/dist/features/seller/components/SellerReviewsView.js +47 -16
  372. package/dist/features/seller/components/SellerShippingConfigsView.js +5 -4
  373. package/dist/features/seller/components/SellerSidebar.d.ts +3 -6
  374. package/dist/features/seller/components/SellerStickersView.d.ts +14 -7
  375. package/dist/features/seller/components/SellerStickersView.js +4 -119
  376. package/dist/features/seller/components/SellerStoreCategoriesView.js +3 -2
  377. package/dist/features/seller/components/SellerSupportView.d.ts +31 -0
  378. package/dist/features/seller/components/SellerSupportView.js +100 -0
  379. package/dist/features/seller/components/index.d.ts +4 -8
  380. package/dist/features/seller/components/index.js +2 -4
  381. package/dist/features/seller/index.d.ts +0 -1
  382. package/dist/features/seller/index.js +0 -1
  383. package/dist/features/seller/schemas/coupon-form.d.ts +214 -0
  384. package/dist/features/seller/schemas/coupon-form.js +155 -23
  385. package/dist/features/seller/schemas/offer-forms.d.ts +16 -7
  386. package/dist/features/seller/schemas/offer-forms.js +28 -12
  387. package/dist/features/shell/FormShell.js +2 -2
  388. package/dist/features/shell/QuickFormDrawer.js +2 -2
  389. package/dist/features/shell/SectionForm.d.ts +19 -1
  390. package/dist/features/shell/SectionForm.js +104 -17
  391. package/dist/features/shell/build-sections.d.ts +23 -0
  392. package/dist/features/shell/build-sections.js +106 -8
  393. package/dist/features/shell/field-ui-meta.d.ts +44 -0
  394. package/dist/features/shell/field-ui-meta.js +14 -7
  395. package/dist/features/shell/form-sections.d.ts +46 -0
  396. package/dist/features/shell/form-sections.js +114 -0
  397. package/dist/features/shipments/components/AdminShipmentEditorView.js +87 -64
  398. package/dist/features/shipments/schemas/validation.d.ts +2 -2
  399. package/dist/features/shipments/schemas/validation.js +44 -13
  400. package/dist/features/store-extensions/schemas/custom-role-form.js +6 -2
  401. package/dist/features/store-extensions/schemas/listing-template-form.d.ts +7 -7
  402. package/dist/features/store-extensions/schemas/payout-method-form.js +14 -0
  403. package/dist/features/stores/actions/store-query-actions.js +3 -2
  404. package/dist/features/stores/api/[storeSlug]/auctions/route.js +3 -1
  405. package/dist/features/stores/api/[storeSlug]/products/route.js +3 -1
  406. package/dist/features/stores/components/StoreDetailLayoutView.d.ts +1 -1
  407. package/dist/features/stores/components/StoreDetailLayoutView.js +12 -3
  408. package/dist/features/support/repository/support.repository.d.ts +21 -0
  409. package/dist/features/support/repository/support.repository.js +63 -0
  410. package/dist/features/support/schemas/firestore.d.ts +27 -2
  411. package/dist/features/support/schemas/firestore.js +2 -0
  412. package/dist/features/support/schemas/ticket-create-form.js +7 -0
  413. package/dist/features/tester/schemas/checklist-item-form.d.ts +43 -0
  414. package/dist/features/tester/schemas/checklist-item-form.js +109 -0
  415. package/dist/features/tester/seed-data/blog-tester-seed-data.js +2 -2
  416. package/dist/features/tester/seed-data/categories-tester-seed-data.js +2 -2
  417. package/dist/features/tester/seed-data/events-tester-seed-data.js +5 -5
  418. package/dist/features/tester/seed-data/orders-tester-seed-data.js +2 -2
  419. package/dist/features/tester/seed-data/products-tester-seed-data.js +48 -49
  420. package/dist/features/tester/seed-data/stores-tester-seed-data.js +3 -3
  421. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +291 -30
  422. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +51 -14
  423. package/dist/features/wishlist/hooks/useWishlistToggle.js +8 -1
  424. package/dist/http/api-handler.js +2 -1
  425. package/dist/index.d.ts +25 -104
  426. package/dist/index.js +38 -143
  427. package/dist/jobs.d.ts +1 -1
  428. package/dist/jobs.js +1 -1
  429. package/dist/monitoring/browser.d.ts +0 -2
  430. package/dist/monitoring/browser.js +12 -1
  431. package/dist/monitoring/index.d.ts +0 -2
  432. package/dist/monitoring/index.js +0 -1
  433. package/dist/next/api/routeHandler.js +9 -4
  434. package/dist/next/index.d.ts +1 -2
  435. package/dist/next/index.js +0 -1
  436. package/dist/next/middleware/index.d.ts +0 -2
  437. package/dist/next/middleware/index.js +0 -1
  438. package/dist/next/routing/route-map.d.ts +8 -7
  439. package/dist/next/routing/route-map.js +10 -3
  440. package/dist/providers/auth-firebase/session.js +3 -1
  441. package/dist/providers/db-firebase/admin-app-lite.js +8 -8
  442. package/dist/providers/db-firebase/admin.js +27 -13
  443. package/dist/providers/db-firebase/browser-stub.d.ts +1 -11
  444. package/dist/providers/db-firebase/browser-stub.js +6 -11
  445. package/dist/providers/db-firebase/index.d.ts +0 -1
  446. package/dist/providers/db-firebase/index.js +0 -1
  447. package/dist/providers/db-firebase/rtdb-paths.d.ts +15 -6
  448. package/dist/providers/db-firebase/rtdb-paths.js +15 -6
  449. package/dist/providers/db-firebase/rtdb-url.d.ts +27 -0
  450. package/dist/providers/db-firebase/rtdb-url.js +50 -0
  451. package/dist/providers/db-firebase/sieve.d.ts +22 -0
  452. package/dist/providers/firebase-client/realtime.d.ts +20 -0
  453. package/dist/providers/firebase-client/realtime.js +34 -1
  454. package/dist/providers.d.ts +1 -1
  455. package/dist/providers.js +1 -1
  456. package/dist/react/hooks/use-action-dispatch.js +8 -2
  457. package/dist/react/hooks/useFormStatePreservation.js +3 -1
  458. package/dist/react/hooks/useListingTypeFlags.d.ts +1 -1
  459. package/dist/react/hooks/useListingTypeFlags.js +1 -1
  460. package/dist/react/hooks/usePendingFilters.js +5 -3
  461. package/dist/react/hooks/usePendingTable.js +15 -3
  462. package/dist/react/hooks/useRealtimeEvent.js +20 -9
  463. package/dist/repositories/index.d.ts +0 -1
  464. package/dist/repositories/index.js +0 -1
  465. package/dist/schemas/registry.d.ts +197 -232
  466. package/dist/schemas/registry.js +5 -6
  467. package/dist/schemas/webhooks/razorpay.d.ts +50 -50
  468. package/dist/security/authorization.d.ts +9 -0
  469. package/dist/security/authorization.js +16 -2
  470. package/dist/security/browser.d.ts +1 -3
  471. package/dist/security/browser.js +5 -2
  472. package/dist/security/index.d.ts +1 -3
  473. package/dist/security/index.js +19 -2
  474. package/dist/security/pii-encrypt.js +16 -0
  475. package/dist/security/pii-schemas.d.ts +0 -14
  476. package/dist/security/pii-schemas.js +7 -15
  477. package/dist/seed/_helpers/category-forest.js +2 -2
  478. package/dist/seed/_helpers/media.d.ts +19 -0
  479. package/dist/seed/_helpers/media.js +75 -0
  480. package/dist/seed/blog-posts-seed-data.js +17 -17
  481. package/dist/seed/carousel-slides-seed-data.js +7 -7
  482. package/dist/seed/cart-seed-data.js +13 -13
  483. package/dist/seed/categories-seed-data.js +10 -10
  484. package/dist/seed/events-seed-data.js +24 -24
  485. package/dist/seed/factories/product.factory.js +4 -4
  486. package/dist/seed/factories/store.factory.js +3 -3
  487. package/dist/seed/factories/user.factory.js +2 -2
  488. package/dist/seed/grouped-listings-seed-data.js +11 -11
  489. package/dist/seed/homepage-sections-seed-data.js +2 -2
  490. package/dist/seed/index.d.ts +0 -1
  491. package/dist/seed/index.js +0 -1
  492. package/dist/seed/manifest.d.ts +1 -1
  493. package/dist/seed/manifest.js +0 -5
  494. package/dist/seed/notifications-seed-data.js +20 -1
  495. package/dist/seed/orders-seed-data.js +2 -2
  496. package/dist/seed/products-art-seed-data.js +16 -16
  497. package/dist/seed/products-auctions-seed-data.js +34 -34
  498. package/dist/seed/products-classifieds-seed-data.js +35 -37
  499. package/dist/seed/products-digital-codes-seed-data.js +20 -20
  500. package/dist/seed/products-live-items-seed-data.js +11 -11
  501. package/dist/seed/products-preorders-seed-data.js +13 -13
  502. package/dist/seed/products-prize-draws-seed-data.js +43 -43
  503. package/dist/seed/products-standard-seed-data.js +54 -54
  504. package/dist/seed/products-stickers-seed-data.js +15 -15
  505. package/dist/seed/reviews-seed-data.js +4 -4
  506. package/dist/seed/scammers-seed-data.js +3 -3
  507. package/dist/seed/site-settings-seed-data.js +11 -24
  508. package/dist/seed/store-extensions-seed-data.js +10 -10
  509. package/dist/seed/stores-seed-data.js +11 -11
  510. package/dist/seed/support-tickets-seed-data.d.ts +14 -0
  511. package/dist/seed/support-tickets-seed-data.js +20 -1
  512. package/dist/seed/users-seed-data.js +20 -20
  513. package/dist/server-entry.d.ts +0 -1
  514. package/dist/server-entry.js +0 -1
  515. package/dist/server.d.ts +9 -6
  516. package/dist/server.js +7 -13
  517. package/dist/styles.css +248 -68
  518. package/dist/tailwind-utilities.css +1 -1
  519. package/dist/tokens/themes/default-dark.js +2 -2
  520. package/dist/tokens/themes/default-light.js +2 -2
  521. package/dist/tokens/tokens.css +24 -4
  522. package/dist/ui/components/ActionRow.d.ts +50 -0
  523. package/dist/ui/components/ActionRow.js +53 -0
  524. package/dist/ui/components/ActionRow.style.css +145 -0
  525. package/dist/ui/components/Drawer.d.ts +10 -0
  526. package/dist/ui/components/Drawer.js +2 -1
  527. package/dist/ui/components/FilterDrawer.js +4 -1
  528. package/dist/ui/components/FilterDrawer.style.css +6 -12
  529. package/dist/ui/components/FormActionBar.js +14 -1
  530. package/dist/ui/components/FormActionBar.style.css +12 -11
  531. package/dist/ui/components/ListingLayout.js +8 -1
  532. package/dist/ui/components/ListingLayout.style.css +6 -13
  533. package/dist/ui/components/Modal.d.ts +15 -1
  534. package/dist/ui/components/Modal.js +17 -3
  535. package/dist/ui/components/QuickCreateModal.js +2 -2
  536. package/dist/ui/components/QuickCreateModal.style.css +78 -84
  537. package/dist/ui/components/RecordDetailModal.js +2 -2
  538. package/dist/ui/components/SideDrawer.d.ts +8 -0
  539. package/dist/ui/components/SideDrawer.js +2 -1
  540. package/dist/ui/components/SideDrawer.style.css +6 -3
  541. package/dist/ui/components/SideModal.d.ts +11 -1
  542. package/dist/ui/components/SideModal.js +3 -2
  543. package/dist/ui/components/SideModal.style.css +14 -0
  544. package/dist/ui/components/Typography.style.css +33 -24
  545. package/dist/ui/components/index.style.css +1 -0
  546. package/dist/ui/components/toolbar-collapse.js +1 -2
  547. package/dist/ui/forms/FormShell.style.css +260 -311
  548. package/dist/ui/index.d.ts +2 -0
  549. package/dist/ui/index.js +1 -0
  550. package/dist/utils/index.d.ts +0 -1
  551. package/dist/utils/index.js +0 -1
  552. package/dist/validation/index.d.ts +1 -1
  553. package/dist/validation/index.js +1 -1
  554. package/dist/validation/schemas.d.ts +0 -19
  555. package/dist/validation/schemas.js +8 -19
  556. package/package.json +1 -1
  557. package/scripts/seed-cli.mjs +3 -6
@@ -54,6 +54,8 @@ export function HandModeProvider({ initialHand, children }) {
54
54
  }
55
55
  }
56
56
  catch (_err) {
57
+ // localStorage unavailable (private-browse) — fall through to the value
58
+ // readHandPreference() already resolved; there is no preference to honour.
57
59
  void normalizeError(_err);
58
60
  }
59
61
  return stored;
@@ -1,5 +1,6 @@
1
1
  "use server";
2
2
  import { wrapAction } from "@mohasinac/appkit/server";
3
+ import { safeRead } from "../../../../errors/safe-read";
3
4
  import { bidRepository, productRepository, userRepository, siteSettingsRepository } from "../../../../repositories";
4
5
  import { requireRoleUser } from "../../../../providers/auth-firebase/helpers";
5
6
  import { placeBidActionSchema } from "../../../shared/features/auctions/schema";
@@ -16,10 +17,20 @@ export async function placeBidAction(input) {
16
17
  assertNotAuctionOwner(product, user.uid);
17
18
  const settings = await siteSettingsRepository.getSingleton();
18
19
  assertBidAmount(product, amount, settings.auctionConfig?.bidIncrementTiers ?? []);
19
- const profile = await userRepository.findById(user.uid).catch(() => null);
20
+ const profile = await safeRead(() => userRepository.findById(user.uid), {
21
+ route: "auction:placeBid",
22
+ key: "auctions.placeBid.bidderProfile",
23
+ fallback: null,
24
+ });
20
25
  const userName = profile?.displayName ?? user.name ?? "Anonymous";
21
- // Mark all current bids for this auction as outbid, then set new winning bid
22
- await bidRepository.setWinningBid("__placeholder__", auctionId).catch(() => null);
26
+ // (Removed: a `setWinningBid("__placeholder__", auctionId)` call whose
27
+ // rejection was swallowed. It accomplished NOTHING. setWinningBid builds a
28
+ // single batch — mark every bid for the product `outbid`, then update the
29
+ // winning bid's own doc — and `__placeholder__` is not a real bid id, so
30
+ // `batch.commit()` always threw and DISCARDED the whole batch, outbid
31
+ // marking included. It cost a full-collection query and an exception per
32
+ // bid placed, and the real `setWinningBid(bid.id, …)` below already marks
33
+ // every other bid for this product as outbid.)
23
34
  const bid = await bidRepository.create({
24
35
  productId: auctionId,
25
36
  productTitle: product.title ?? auctionId,
@@ -4,7 +4,7 @@ import { AuctionNotFoundError, AuctionEndedError, BidTooLowError, BidOnOwnAuctio
4
4
  import { AUCTION_SNIPING_WINDOW_SECONDS, AUCTION_DEFAULT_EXTENSION_MINUTES, resolveMinBid, } from "../../../shared/features/auctions/config";
5
5
  /** Assert an auction exists, is published, and is still active. Returns the product. */
6
6
  export async function assertAuctionActive(auctionId) {
7
- const product = await productRepository.findByIdOrSlug(auctionId).catch(() => null);
7
+ const product = await productRepository.findByIdOrSlug(auctionId);
8
8
  if (!product || !isAuctionListing(product))
9
9
  throw new AuctionNotFoundError(auctionId);
10
10
  const endDate = product.auctionEndDate instanceof Date
@@ -26,6 +26,8 @@ export declare function checkAnyPermission(resolved: ResolvedPermissions, requir
26
26
  type GetUser = () => Promise<{
27
27
  uid: string;
28
28
  role: string;
29
+ permissions?: readonly string[] | null;
30
+ /** @deprecated Legacy tester flags; still read during the migration window. */
29
31
  isTester?: boolean;
30
32
  canTestAdmin?: boolean;
31
33
  } | null>;
@@ -60,8 +60,9 @@ export function makeAdminSectionLayout(permission, opts) {
60
60
  redirect(opts.loginPath ?? String(ROUTES.AUTH.LOGIN));
61
61
  return null;
62
62
  }
63
- // admin role, or a tester explicitly flagged to test admin areas
64
- // (isTester && canTestAdmin), passes without a permission check
63
+ // Admin role, or a tester cleared for admin surfaces (the `tester` role
64
+ // plus `tester:admin-surfaces`, or the legacy isTester/canTestAdmin pair),
65
+ // passes without a permission check.
65
66
  if (isEffectiveAdminUser(user))
66
67
  return children;
67
68
  // non-employee non-admin roles have no business in /admin
@@ -1,8 +1,8 @@
1
1
  import { cache } from "react";
2
2
  import { blogRepository } from "../../../../repositories";
3
3
  export const getBlogPostForDetail = cache(async (slug) => {
4
- return (await blogRepository.findBySlug(slug).catch(() => undefined)) ?? null;
4
+ return (await blogRepository.findBySlug(slug)) ?? null;
5
5
  });
6
6
  export const getBlogPostById = cache(async (id) => {
7
- return (await blogRepository.findById(id).catch(() => undefined)) ?? null;
7
+ return (await blogRepository.findById(id)) ?? null;
8
8
  });
@@ -1,14 +1,14 @@
1
1
  import { blogRepository } from "../../../../repositories";
2
2
  import { BlogPostNotFoundError, BlogSlugConflictError } from "../../../shared/features/blog/errors";
3
3
  export async function assertBlogPostExists(slugOrId) {
4
- const post = await blogRepository.findBySlug(slugOrId).catch(() => null)
5
- ?? await blogRepository.findById(slugOrId).catch(() => null);
4
+ const post = await blogRepository.findBySlug(slugOrId)
5
+ ?? await blogRepository.findById(slugOrId);
6
6
  if (!post)
7
7
  throw new BlogPostNotFoundError(slugOrId);
8
8
  return post;
9
9
  }
10
10
  export async function assertBlogSlugUnique(slug) {
11
- const existing = await blogRepository.findBySlug(slug).catch(() => null);
11
+ const existing = await blogRepository.findBySlug(slug);
12
12
  if (existing)
13
13
  throw new BlogSlugConflictError(slug);
14
14
  }
@@ -6,7 +6,7 @@ import { categoriesRepository } from "../../../../repositories";
6
6
  * `BrandDetailPageView` consume the same `CategoryDocument` shape.
7
7
  */
8
8
  export const getBrandForDetail = cache(async (slug) => {
9
- return categoriesRepository.findBySlugAndType(slug, "brand").catch(() => null);
9
+ return categoriesRepository.findBySlugAndType(slug, "brand");
10
10
  });
11
11
  /**
12
12
  * @deprecated Identical to getBrandForDetail after SB-UNI-C. Kept as an
@@ -1,14 +1,14 @@
1
1
  import { categoriesRepository } from "../../../../repositories";
2
2
  import { BrandNotFoundError, BrandSlugConflictError } from "../../../shared/features/brands/errors";
3
3
  export async function assertBrandExists(slugOrId) {
4
- const brand = (await categoriesRepository.findBySlugAndType(slugOrId, "brand").catch(() => null)) ??
5
- (await categoriesRepository.findById(slugOrId).catch(() => null));
4
+ const brand = (await categoriesRepository.findBySlugAndType(slugOrId, "brand")) ??
5
+ (await categoriesRepository.findById(slugOrId));
6
6
  if (!brand || brand.categoryType !== "brand")
7
7
  throw new BrandNotFoundError(slugOrId);
8
8
  return brand;
9
9
  }
10
10
  export async function assertBrandSlugUnique(slug) {
11
- const existing = await categoriesRepository.findBySlugAndType(slug, "brand").catch(() => null);
11
+ const existing = await categoriesRepository.findBySlugAndType(slug, "brand");
12
12
  if (existing)
13
13
  throw new BrandSlugConflictError(slug);
14
14
  }
@@ -13,6 +13,7 @@
13
13
  * helpers can fan out stock decrements to member products.
14
14
  */
15
15
  import { NotFoundError, ValidationError } from "../../../../errors";
16
+ import { safeRead } from "../../../../errors/safe-read";
16
17
  import { categoriesRepository } from "../../../../repositories";
17
18
  import { cartRepository } from "../../../../features/cart/repository/cart.repository";
18
19
  import { assertCanAddNewItems } from "../../../../features/cart/actions/cart-actions";
@@ -55,7 +56,11 @@ quantity = 1) {
55
56
  // treating that as a stock quantity would silently change how much a
56
57
  // prize-draw member decrements, which the stock fan-out has never done.
57
58
  const memberIds = bundle.bundleProductIds ?? [];
58
- const memberDocs = await Promise.all(memberIds.map((id) => productRepository.findById(id).catch(() => null)));
59
+ const memberDocs = await Promise.all(memberIds.map((id) => safeRead(() => productRepository.findById(id), {
60
+ route: "/bundles",
61
+ key: "bundles.addBundleToCart.member",
62
+ fallback: null,
63
+ })));
59
64
  const groupMembers = memberDocs
60
65
  .filter((p) => p !== null)
61
66
  .map((p) => ({
@@ -8,6 +8,7 @@
8
8
  import { cache } from "react";
9
9
  import { categoriesRepository } from "../../../../repositories";
10
10
  import { productRepository } from "../../../../repositories";
11
+ import { safeRead } from "../../../../errors/safe-read";
11
12
  /**
12
13
  * Fetch a single bundle by slug for the public detail page. Returns null
13
14
  * when the slug is empty or no matching `categoryType:"bundle"` row exists.
@@ -43,7 +44,11 @@ export const listBundleMembers = cache(async (bundle, _opts) => {
43
44
  const ids = resolveBundleMemberIds(bundle);
44
45
  if (ids.length === 0)
45
46
  return [];
46
- const results = await Promise.all(ids.map((id) => productRepository.findById(id).catch(() => null)));
47
+ const results = await Promise.all(ids.map((id) => safeRead(() => productRepository.findById(id), {
48
+ route: "/bundles",
49
+ key: "bundles.listBundleMembers.member",
50
+ fallback: null,
51
+ })));
47
52
  return results.filter((p) => p !== null);
48
53
  });
49
54
  /**
@@ -58,7 +63,11 @@ export const listBundleMembers = cache(async (bundle, _opts) => {
58
63
  export async function resolveBundleOriginalTotal(productIds) {
59
64
  if (productIds.length === 0)
60
65
  return undefined;
61
- const results = await Promise.all(productIds.map((id) => productRepository.findById(id).catch(() => null)));
66
+ const results = await Promise.all(productIds.map((id) => safeRead(() => productRepository.findById(id), {
67
+ route: "/bundles",
68
+ key: "bundles.resolveBundleOriginalTotal.member",
69
+ fallback: null,
70
+ })));
62
71
  const prices = [];
63
72
  for (const p of results) {
64
73
  if (!p || typeof p.price !== "number")
@@ -89,7 +98,11 @@ export async function resolveBundleOriginalTotal(productIds) {
89
98
  export async function findBundleMemberStores(productIds) {
90
99
  if (productIds.length === 0)
91
100
  return [];
92
- const results = await Promise.all(productIds.map((id) => productRepository.findById(id).catch(() => null)));
101
+ const results = await Promise.all(productIds.map((id) => safeRead(() => productRepository.findById(id), {
102
+ route: "/bundles",
103
+ key: "bundles.findBundleMemberStores.member",
104
+ fallback: null,
105
+ })));
93
106
  const stores = new Set();
94
107
  for (const p of results) {
95
108
  // An unresolvable member says nothing about seller spread — the price
@@ -118,7 +131,11 @@ export async function findBundleMemberStores(productIds) {
118
131
  export async function resolveBundleCategorySlugs(productIds) {
119
132
  if (productIds.length === 0)
120
133
  return [];
121
- const results = await Promise.all(productIds.map((id) => productRepository.findById(id).catch(() => null)));
134
+ const results = await Promise.all(productIds.map((id) => safeRead(() => productRepository.findById(id), {
135
+ route: "/bundles",
136
+ key: "bundles.resolveBundleCategorySlugs.member",
137
+ fallback: null,
138
+ })));
122
139
  const slugs = new Set();
123
140
  for (const p of results) {
124
141
  for (const slug of p?.categorySlugs ?? [])
@@ -1,5 +1,7 @@
1
1
  import { cache } from "react";
2
2
  import { cartRepository } from "../../../../repositories";
3
3
  export const getCartForUser = cache(async (userId) => {
4
- return (await cartRepository.findByUserId(userId).catch(() => undefined)) ?? null;
4
+ // No catch: this cart IS the page. Degrading a Firestore failure to null
5
+ // renders an EMPTY CART to someone whose cart is full — money path.
6
+ return (await cartRepository.findByUserId(userId)) ?? null;
5
7
  });
@@ -1,8 +1,13 @@
1
1
  import { cartRepository } from "../../../../repositories";
2
2
  import { CART_MAX_ITEMS } from "../../../shared/features/cart/config";
3
3
  import { CartFullError, CartQuantityError } from "../../../shared/features/cart/errors";
4
+ import { normalizeError } from "../../../../errors/normalize";
5
+ import { serverLogger } from "../../../../monitoring/server-logger";
4
6
  export async function assertCartCapacity(userId, addingQty) {
5
- const cart = await cartRepository.findByUserId(userId).catch(() => null);
7
+ // No catch. Swallowing to null made `currentItemCount` 0, so a Firestore
8
+ // failure silently DISABLED the cart cap and let the add through — a guard
9
+ // that fails open. A throw is caught by the action envelope and recorded.
10
+ const cart = await cartRepository.findByUserId(userId);
6
11
  const currentItemCount = cart ? (cart.items ?? []).length : 0;
7
12
  if (currentItemCount + addingQty > CART_MAX_ITEMS) {
8
13
  throw new CartFullError(CART_MAX_ITEMS);
@@ -20,6 +25,12 @@ export async function upsertCartItem(userId, item) {
20
25
  }
21
26
  export async function mergeGuestItems(userId, guestItems) {
22
27
  for (const item of guestItems) {
23
- await cartRepository.addItem(userId, item).catch(() => null);
28
+ // A WRITE, not a read — safeRead does not apply. Guest-merge is
29
+ // best-effort per item so one bad line cannot lose the whole cart, but a
30
+ // dropped item must be visible rather than silent.
31
+ await cartRepository.addItem(userId, item).catch((err) => {
32
+ void normalizeError(err);
33
+ serverLogger.warn("cart.mergeGuestCart: item dropped", { userId, err });
34
+ });
24
35
  }
25
36
  }
@@ -1,17 +1,33 @@
1
1
  "use server";
2
2
  import { cache } from "react";
3
3
  import { categoriesRepository } from "../../../../repositories";
4
+ import { safeRead } from "../../../../errors/safe-read";
4
5
  import { CATEGORIES_FEATURED_LIMIT, CATEGORIES_MENU_LIMIT, CATEGORIES_SITEMAP_LIMIT } from "../../../shared/features/categories/config";
5
6
  /** Full category document by slug — deduped per request via React.cache(). */
6
7
  export const getCategoryForDetail = cache(async (slug) => {
7
- const category = (await categoriesRepository.getCategoryBySlug(slug).catch(() => undefined)) ?? null;
8
- if (category)
9
- void categoriesRepository.incrementViewCount(category.id);
10
- return category;
8
+ /*
9
+ * 🛑 No view-count write here — deleted 2026-08-31.
10
+ *
11
+ * This fired `incrementViewCount` on every render, which was two defects at
12
+ * once. It is a Firestore WRITE on the render path (Rule #6), and product
13
+ * and category detail were being counted TWICE by two systems that key
14
+ * differently: this one on the document by id, and the client
15
+ * `PageViewTracker` into `pageViews` by slug. They can never reconcile —
16
+ * they disagree on bots, on prefetch, and on JS-disabled clients — so the
17
+ * two numbers were guaranteed to drift and neither could be trusted.
18
+ *
19
+ * `pageViews` is the single counter now. `viewCount` on the document stays
20
+ * for historical rows; nothing increments it.
21
+ */
22
+ return (await categoriesRepository.getCategoryBySlug(slug)) ?? null;
11
23
  });
12
24
  /** Flat list of all categories at tier 1 (roots) — for nav/sitemap. */
13
25
  export const listRootCategories = cache(async () => {
14
- return categoriesRepository.getCategoriesByTier(1).catch(() => []);
26
+ return safeRead(() => categoriesRepository.getCategoriesByTier(1), {
27
+ route: "/categories",
28
+ key: "categories.listRootCategories",
29
+ fallback: [],
30
+ });
15
31
  });
16
32
  /** Featured categories for homepage display (showOnHomepage: true). */
17
33
  export const listFeaturedCategories = cache(async () => {
@@ -29,7 +45,11 @@ export const listMenuCategories = cache(async () => {
29
45
  });
30
46
  /** Full category tree rooted at a given rootId — for sidebar navigation. */
31
47
  export const getCategoryTree = cache(async (rootId) => {
32
- return categoriesRepository.buildTree(rootId).catch(() => []);
48
+ return safeRead(() => categoriesRepository.buildTree(rootId), {
49
+ route: "/categories",
50
+ key: "categories.getCategoryTree",
51
+ fallback: [],
52
+ });
33
53
  });
34
54
  /** Flat category list for sitemap generation. */
35
55
  export const listSitemapCategories = cache(async () => {
@@ -1,5 +1,4 @@
1
1
  export * from "./data";
2
- export * from "./actions";
3
2
  export * from "./adapters";
4
3
  export * from "./metadata";
5
4
  export * from "./og";
@@ -1,5 +1,4 @@
1
1
  export * from "./data";
2
- export * from "./actions";
3
2
  export * from "./adapters";
4
3
  export * from "./metadata";
5
4
  export * from "./og";
@@ -1,5 +1,4 @@
1
1
  export * from "./data";
2
2
  export * from "./adapters";
3
- export * from "./actions";
4
3
  export * from "./metadata";
5
4
  export * from "./og";
@@ -1,5 +1,4 @@
1
1
  export * from "./data";
2
2
  export * from "./adapters";
3
- export * from "./actions";
4
3
  export * from "./metadata";
5
4
  export * from "./og";
@@ -6,6 +6,8 @@ import { eventInputSchema, eventUpdateSchema, registerForEventSchema } from "../
6
6
  import { assertEventActive } from "./service";
7
7
  import { AlreadyRegisteredError, EventNotFoundError } from "../../../shared/features/events/errors";
8
8
  import { ValidationError } from "../../../shared/errors/index";
9
+ import { normalizeError } from "../../../../errors/normalize";
10
+ import { serverLogger } from "../../../../monitoring/server-logger";
9
11
  export async function createEventAction(input) {
10
12
  return wrapAction(async () => {
11
13
  const user = await requireRoleUser(["admin", "moderator"]);
@@ -23,7 +25,7 @@ export async function createEventAction(input) {
23
25
  export async function updateEventAction(eventId, input) {
24
26
  return wrapAction(async () => {
25
27
  await requireRoleUser(["admin", "moderator"]);
26
- const event = await eventRepository.findById(eventId).catch(() => null);
28
+ const event = await eventRepository.findById(eventId);
27
29
  if (!event)
28
30
  throw new EventNotFoundError(eventId);
29
31
  const parsed = eventUpdateSchema.safeParse(input);
@@ -52,15 +54,26 @@ export async function registerForEventAction(input) {
52
54
  reviewStatus: "pending",
53
55
  submittedAt: new Date(),
54
56
  });
55
- // Increment entry count
56
- await eventRepository.incrementTotalEntries(eventId).catch(() => null);
57
+ // Increment entry count. The entry document is already written and is the
58
+ // authoritative record, so a failed counter bump must not fail the
59
+ // registration — but it leaves `stats.totalEntries` under-reporting, and
60
+ // the capacity check in assertEventActive reads that mirror, so it has to
61
+ // be visible to an operator rather than dropped (Root Cause #42).
62
+ await eventRepository.incrementTotalEntries(eventId).catch((err) => {
63
+ void normalizeError(err);
64
+ serverLogger.warn("events: incrementTotalEntries failed — stats.totalEntries is now stale", {
65
+ eventId,
66
+ error: err instanceof Error ? err.message : String(err),
67
+ });
68
+ return null;
69
+ });
57
70
  return entry;
58
71
  });
59
72
  }
60
73
  export async function cancelEventRegistrationAction(entryId) {
61
74
  return wrapAction(async () => {
62
75
  const user = await requireRoleUser(["buyer", "seller", "admin"]);
63
- const entry = await eventEntryRepository.findById(entryId).catch(() => null);
76
+ const entry = await eventEntryRepository.findById(entryId);
64
77
  if (!entry || entry.userId !== user.uid) {
65
78
  throw new ValidationError("Registration not found or does not belong to you");
66
79
  }
@@ -1,5 +1,5 @@
1
1
  import { cache } from "react";
2
2
  import { eventRepository } from "../../../../repositories";
3
3
  export const getEventForDetail = cache(async (id) => {
4
- return eventRepository.findById(id).catch(() => null);
4
+ return eventRepository.findById(id);
5
5
  });
@@ -1,7 +1,7 @@
1
1
  import { eventRepository } from "../../../../repositories";
2
2
  import { EventNotFoundError, EventNotActiveError, EventEndedError, EventFullError, } from "../../../shared/features/events/errors";
3
3
  export async function assertEventActive(eventId) {
4
- const event = await eventRepository.findById(eventId).catch(() => null);
4
+ const event = await eventRepository.findById(eventId);
5
5
  if (!event)
6
6
  throw new EventNotFoundError(eventId);
7
7
  const status = event.status;
@@ -1,6 +1,7 @@
1
1
  import { cache } from "react";
2
2
  import { getAdminDb } from "../../../../providers/db-firebase";
3
3
  import { normalizeError } from "../../../../errors/normalize";
4
+ import { safeRead } from "../../../../errors/safe-read";
4
5
  import { serverLogger } from "../../../../monitoring/server-logger";
5
6
  import { GROUPED_LISTINGS_COLLECTION, } from "../../../../features/grouped/schemas/firestore";
6
7
  import { productRepository, groupedListingsRepository } from "../../../../repositories";
@@ -70,7 +71,7 @@ export const getGroupedListingWithItems = cache(async (slug) => {
70
71
  return null;
71
72
  const items = [];
72
73
  for (const productId of doc.productIds) {
73
- const product = await productRepository.findByIdOrSlug(productId).catch(() => null);
74
+ const product = await safeRead(() => productRepository.findByIdOrSlug(productId), { route: "/groups", key: "grouped.getGroupedListingWithItems.member", fallback: null });
74
75
  if (product)
75
76
  items.push(product);
76
77
  }
@@ -128,7 +129,11 @@ export const getGroupsWithItemsForProduct = cache(async (productId) => {
128
129
  const groups = await getGroupsForProduct(productId);
129
130
  return Promise.all(groups.map(async (group) => {
130
131
  const otherIds = group.productIds.filter((id) => id !== productId);
131
- const items = await Promise.all(otherIds.map((id) => productRepository.findByIdOrSlug(id).catch(() => null)));
132
+ const items = await Promise.all(otherIds.map((id) => safeRead(() => productRepository.findByIdOrSlug(id), {
133
+ route: "/products",
134
+ key: "grouped.getGroupsWithItemsForProduct.member",
135
+ fallback: null,
136
+ })));
132
137
  return { ...group, items: items.filter((p) => p !== null) };
133
138
  }));
134
139
  });
@@ -16,5 +16,5 @@ export const getItemRequestForDetail = cache(async (id, _opts) => {
16
16
  void _opts;
17
17
  if (!id)
18
18
  return null;
19
- return (await itemRequestsRepository.findById(id).catch(() => null)) ?? null;
19
+ return (await itemRequestsRepository.findById(id)) ?? null;
20
20
  });
@@ -1,5 +1,4 @@
1
1
  export * from "./data";
2
2
  export * from "./adapters";
3
- export * from "./actions";
4
3
  export * from "./metadata";
5
4
  export * from "./og";
@@ -1,5 +1,4 @@
1
1
  export * from "./data";
2
2
  export * from "./adapters";
3
- export * from "./actions";
4
3
  export * from "./metadata";
5
4
  export * from "./og";
@@ -39,7 +39,7 @@ export async function submitLotteryPullAction(input) {
39
39
  // Load the event/product to get the lotteryConfig
40
40
  let lotteryConfig;
41
41
  if (data.sourceType === "event") {
42
- const event = await eventRepository.findById(sourceId).catch(() => null);
42
+ const event = await eventRepository.findById(sourceId);
43
43
  if (!event || event.type !== "lottery") {
44
44
  throw new LotteryError("LOTTERY_WINDOW_CLOSED", "Lottery event not found or not of type lottery.");
45
45
  }
@@ -52,7 +52,7 @@ export async function submitLotteryPullAction(input) {
52
52
  lotteryConfig = event.lotteryConfig;
53
53
  }
54
54
  else {
55
- const product = await productRepository.findById(sourceId).catch(() => null);
55
+ const product = await productRepository.findById(sourceId);
56
56
  if (!product || product.listingType !== "prize-draw") {
57
57
  throw new LotteryError("LOTTERY_WINDOW_CLOSED", "Prize-draw product not found.");
58
58
  }
@@ -4,7 +4,7 @@ import { lotteryEntryRepository } from "../../../../features/lottery/repository/
4
4
  import { toClientLotteryConfig } from "./adapters";
5
5
  /** Fetch a lottery-type event with price/weight stripped for client use. */
6
6
  export const getLotteryEventCached = cache(async (id) => {
7
- const event = await eventRepository.findById(id).catch(() => null);
7
+ const event = await eventRepository.findById(id);
8
8
  if (!event || event.type !== "lottery")
9
9
  return null;
10
10
  return {
@@ -53,7 +53,7 @@ export async function updateOrderStatusAction(input) {
53
53
  const parsed = updateOrderStatusSchema.safeParse(input);
54
54
  if (!parsed.success)
55
55
  throw new ValidationError(parsed.error.issues[0]?.message ?? "Invalid input");
56
- const order = await orderRepository.findById(parsed.data.orderId).catch(() => null);
56
+ const order = await orderRepository.findById(parsed.data.orderId);
57
57
  if (!order)
58
58
  throw new OrderNotFoundError(parsed.data.orderId);
59
59
  if (!isAdminUser(user) && order.storeId !== user.uid) {
@@ -126,7 +126,7 @@ function notifyAdminsOfPaymentProof(order) {
126
126
  export async function attachPaymentProofAction(orderId, proof) {
127
127
  return wrapAction(async () => {
128
128
  const user = await requireRoleUser(["buyer", "seller", "admin"]);
129
- const order = await orderRepository.findById(orderId).catch(() => null);
129
+ const order = await orderRepository.findById(orderId);
130
130
  if (!order)
131
131
  throw new OrderNotFoundError(orderId);
132
132
  if (!isAdminUser(user) && order.userId !== user.uid)
@@ -187,7 +187,7 @@ export async function adminVerifyPaymentAction(orderId) {
187
187
  if (!isAdminUser(user) && !isModeratorUser(user)) {
188
188
  throw new ValidationError("Only admin or moderator can verify payments");
189
189
  }
190
- const order = await orderRepository.findById(orderId).catch(() => null);
190
+ const order = await orderRepository.findById(orderId);
191
191
  if (!order)
192
192
  throw new OrderNotFoundError(orderId);
193
193
  if (order.paymentStatus === "paid")
@@ -226,7 +226,7 @@ export async function adminRequestProofReuploadAction(orderId, note) {
226
226
  }
227
227
  if (!note.trim())
228
228
  throw new ValidationError(REASON_REQUIRED_MSG);
229
- const order = await orderRepository.findById(orderId).catch(() => null);
229
+ const order = await orderRepository.findById(orderId);
230
230
  if (!order)
231
231
  throw new OrderNotFoundError(orderId);
232
232
  if (order.paymentStatus === "paid") {
@@ -275,7 +275,7 @@ export async function adminRejectPaymentAsFraudAction(orderId, note) {
275
275
  }
276
276
  if (!note.trim())
277
277
  throw new ValidationError(REASON_REQUIRED_MSG);
278
- const order = await orderRepository.findById(orderId).catch(() => null);
278
+ const order = await orderRepository.findById(orderId);
279
279
  if (!order)
280
280
  throw new OrderNotFoundError(orderId);
281
281
  if (order.paymentStatus === "paid") {
@@ -317,13 +317,13 @@ export async function raiseOrderDisputeAction(orderId, reason) {
317
317
  const user = await requireRoleUser(["buyer", "seller", "admin"]);
318
318
  if (!reason.trim())
319
319
  throw new ValidationError(REASON_REQUIRED_MSG);
320
- const order = await orderRepository.findById(orderId).catch(() => null);
320
+ const order = await orderRepository.findById(orderId);
321
321
  if (!order)
322
322
  throw new OrderNotFoundError(orderId);
323
323
  const isBuyer = order.userId === user.uid;
324
324
  let isSeller = false;
325
325
  if (!isBuyer && !isAdminUser(user) && !isModeratorUser(user) && order.storeId) {
326
- const store = await storeRepository.findById(order.storeId).catch(() => null);
326
+ const store = await storeRepository.findById(order.storeId);
327
327
  isSeller = store?.ownerId === user.uid;
328
328
  }
329
329
  if (!isBuyer && !isSeller && !isAdminUser(user) && !isModeratorUser(user)) {
@@ -7,4 +7,4 @@ export declare const getOrdersForBuyer: (userId: string, page?: number, pageSize
7
7
  totalPages: number;
8
8
  hasMore: boolean;
9
9
  }>;
10
- export declare const getRecentOrdersForBuyer: (userId: string) => Promise<never[] | import("../../../..").OrderDocument[]>;
10
+ export declare const getRecentOrdersForBuyer: (userId: string) => Promise<import("../../../..").OrderDocument[]>;
@@ -1,7 +1,12 @@
1
1
  import { cache } from "react";
2
2
  import { orderRepository } from "../../../../repositories";
3
+ import { safeRead } from "../../../../errors/safe-read";
3
4
  export const getOrderForDetail = cache(async (orderId) => {
4
- return (await orderRepository.findById(orderId).catch(() => undefined)) ?? null;
5
+ // No catch: this order IS the page. Swallowing a Firestore failure to null
6
+ // renders "order not found" for a datastore outage — the caller cannot tell
7
+ // the two apart, which is Root Cause #59 on the money path. A throw reaches
8
+ // the route/error boundary and is now recorded.
9
+ return (await orderRepository.findById(orderId)) ?? null;
5
10
  });
6
11
  export const getOrdersForBuyer = cache(async (userId, page = 1, pageSize = 20) => {
7
12
  return orderRepository.listForUser(userId, { page, pageSize }).catch(() => ({
@@ -14,5 +19,12 @@ export const getOrdersForBuyer = cache(async (userId, page = 1, pageSize = 20) =
14
19
  }));
15
20
  });
16
21
  export const getRecentOrdersForBuyer = cache(async (userId) => {
17
- return orderRepository.findRecentByUser(userId).catch(() => []);
22
+ // Optional: a recent-orders rail. Degrading to empty is right, but it must
23
+ // be VISIBLE — safeRead records a DEGRADED_READ row instead of returning a
24
+ // value indistinguishable from "no recent orders".
25
+ return safeRead(() => orderRepository.findRecentByUser(userId), {
26
+ route: "/user/orders",
27
+ key: "orders.findRecentByUser",
28
+ fallback: [],
29
+ });
18
30
  });
@@ -2,7 +2,7 @@ import { orderRepository } from "../../../../repositories";
2
2
  import { OrderNotFoundError, OrderCancelError, OrderOwnershipError, OrderReturnWindowError, } from "../../../shared/features/orders/errors";
3
3
  import { ORDER_CANCELLABLE_STATUSES, ORDER_RETURN_WINDOW_MS, } from "../../../shared/features/orders/config";
4
4
  export async function assertOrderOwnership(orderId, userId) {
5
- const order = await orderRepository.findById(orderId).catch(() => null);
5
+ const order = await orderRepository.findById(orderId);
6
6
  if (!order)
7
7
  throw new OrderNotFoundError(orderId);
8
8
  if (order.userId !== userId)
@@ -4,7 +4,7 @@ import { roundRupees } from "../../../../utils/number.formatter";
4
4
  import { PreOrderNotFoundError, PreOrderSoldOutError, PreOrderNotOpenError, } from "../../../shared/features/pre-orders/errors";
5
5
  /** Assert a pre-order exists, is published, and has remaining capacity. */
6
6
  export async function assertPreOrderAvailable(preOrderId, requestedQty = 1) {
7
- const product = await productRepository.findByIdOrSlug(preOrderId).catch(() => null);
7
+ const product = await productRepository.findByIdOrSlug(preOrderId);
8
8
  if (!product || !isPreOrderListing(product))
9
9
  throw new PreOrderNotFoundError(preOrderId);
10
10
  if (product.status !== "published")
@@ -9,7 +9,7 @@ export async function enterPrizeDrawAction(input) {
9
9
  const { prizeDrawId } = input;
10
10
  if (!prizeDrawId)
11
11
  throw new Error("prizeDrawId is required.");
12
- const product = await productRepository.findByIdOrSlug(prizeDrawId).catch(() => null);
12
+ const product = await productRepository.findByIdOrSlug(prizeDrawId);
13
13
  if (!product)
14
14
  throw new Error("Prize draw not found.");
15
15
  assertPrizeDrawOpen(product);