@mohasinac/appkit 4.59.0 → 4.60.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (532) hide show
  1. package/dist/.build-stamp.json +3 -3
  2. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +62 -5
  3. package/dist/_internal/client/features/maintenance/views/MaintenanceDashboardView.js +2 -2
  4. package/dist/_internal/server/features/brands/actions.js +78 -4
  5. package/dist/_internal/server/features/checkout/actions.d.ts +36 -13
  6. package/dist/_internal/server/features/checkout/actions.js +668 -183
  7. package/dist/_internal/server/features/checkout/supplier-identity.js +18 -1
  8. package/dist/_internal/server/features/gateway-events/index.d.ts +10 -0
  9. package/dist/_internal/server/features/gateway-events/index.js +10 -0
  10. package/dist/_internal/server/features/gateway-events/ingest.d.ts +127 -0
  11. package/dist/_internal/server/features/gateway-events/ingest.js +188 -0
  12. package/dist/_internal/server/features/gateway-events/redact.d.ts +66 -0
  13. package/dist/_internal/server/features/gateway-events/redact.js +151 -0
  14. package/dist/_internal/server/features/grievance/actions.d.ts +63 -0
  15. package/dist/_internal/server/features/grievance/actions.js +173 -0
  16. package/dist/_internal/server/features/grievance/index.d.ts +8 -0
  17. package/dist/_internal/server/features/grievance/index.js +8 -0
  18. package/dist/_internal/server/features/grouped/data.js +28 -3
  19. package/dist/_internal/server/features/lottery/actions.js +99 -4
  20. package/dist/_internal/server/features/order-completion/actions.d.ts +92 -0
  21. package/dist/_internal/server/features/order-completion/actions.js +336 -0
  22. package/dist/_internal/server/features/order-completion/index.d.ts +7 -0
  23. package/dist/_internal/server/features/order-completion/index.js +7 -0
  24. package/dist/_internal/server/features/orders/actions.d.ts +13 -0
  25. package/dist/_internal/server/features/orders/actions.js +56 -2
  26. package/dist/_internal/server/features/orders/adapters.d.ts +20 -2
  27. package/dist/_internal/server/features/orders/adapters.js +44 -0
  28. package/dist/_internal/server/features/orders/cancellation-refund.d.ts +116 -0
  29. package/dist/_internal/server/features/orders/cancellation-refund.js +466 -0
  30. package/dist/_internal/server/features/orders/index.d.ts +2 -1
  31. package/dist/_internal/server/features/orders/index.js +1 -1
  32. package/dist/_internal/server/features/orders/service.d.ts +60 -0
  33. package/dist/_internal/server/features/orders/service.js +74 -0
  34. package/dist/_internal/server/features/payment-cases/disputes.d.ts +76 -0
  35. package/dist/_internal/server/features/payment-cases/disputes.js +241 -0
  36. package/dist/_internal/server/features/payment-cases/index.d.ts +9 -0
  37. package/dist/_internal/server/features/payment-cases/index.js +9 -0
  38. package/dist/_internal/server/features/payouts/actions.d.ts +28 -3
  39. package/dist/_internal/server/features/payouts/actions.js +84 -10
  40. package/dist/_internal/server/features/points/adjust.d.ts +61 -0
  41. package/dist/_internal/server/features/points/adjust.js +121 -0
  42. package/dist/_internal/server/features/points/award.d.ts +65 -0
  43. package/dist/_internal/server/features/points/award.js +145 -0
  44. package/dist/_internal/server/features/price-index/market.d.ts +33 -0
  45. package/dist/_internal/server/features/price-index/market.js +54 -1
  46. package/dist/_internal/server/features/products/data.js +40 -22
  47. package/dist/_internal/server/features/protection-claims/actions.d.ts +72 -0
  48. package/dist/_internal/server/features/protection-claims/actions.js +228 -0
  49. package/dist/_internal/server/features/protection-claims/index.d.ts +8 -0
  50. package/dist/_internal/server/features/protection-claims/index.js +8 -0
  51. package/dist/_internal/server/features/refunds/actions.d.ts +20 -0
  52. package/dist/_internal/server/features/refunds/actions.js +259 -17
  53. package/dist/_internal/server/features/refunds/capacity.d.ts +29 -0
  54. package/dist/_internal/server/features/refunds/capacity.js +37 -0
  55. package/dist/_internal/server/features/reviews/actions.js +3 -2
  56. package/dist/_internal/server/features/search/index-build/sources.js +20 -1
  57. package/dist/_internal/server/features/shipping/reconcile.d.ts +10 -1
  58. package/dist/_internal/server/features/shipping/reconcile.js +34 -3
  59. package/dist/_internal/server/features/shipping/reimbursement.d.ts +117 -0
  60. package/dist/_internal/server/features/shipping/reimbursement.js +223 -0
  61. package/dist/_internal/server/features/stores/tabs.d.ts +19 -4
  62. package/dist/_internal/server/features/stores/tabs.js +24 -4
  63. package/dist/_internal/server/functions/https.d.ts +31 -1
  64. package/dist/_internal/server/functions/https.js +52 -1
  65. package/dist/_internal/server/functions/scheduled.d.ts +72 -1
  66. package/dist/_internal/server/functions/scheduled.js +124 -1
  67. package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +62 -16
  68. package/dist/_internal/server/jobs/core/boxRollupReconcile.d.ts +46 -0
  69. package/dist/_internal/server/jobs/core/boxRollupReconcile.js +142 -0
  70. package/dist/_internal/server/jobs/core/dailyDataCleanup.js +149 -1
  71. package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +14 -0
  72. package/dist/_internal/server/jobs/core/dailyStatusDigest.js +79 -1
  73. package/dist/_internal/server/jobs/core/index.d.ts +2 -0
  74. package/dist/_internal/server/jobs/core/index.js +2 -0
  75. package/dist/_internal/server/jobs/core/marketPriceRollup.d.ts +64 -0
  76. package/dist/_internal/server/jobs/core/marketPriceRollup.js +153 -0
  77. package/dist/_internal/server/jobs/core/obligationSweep.d.ts +36 -0
  78. package/dist/_internal/server/jobs/core/obligationSweep.js +503 -0
  79. package/dist/_internal/server/jobs/core/paymentReconcile.d.ts +79 -0
  80. package/dist/_internal/server/jobs/core/paymentReconcile.js +614 -0
  81. package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +34 -0
  82. package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +35 -4
  83. package/dist/_internal/server/jobs/handlers/boxRollupReconcile.d.ts +2 -0
  84. package/dist/_internal/server/jobs/handlers/boxRollupReconcile.js +15 -0
  85. package/dist/_internal/server/jobs/handlers/countersReconcileNow.d.ts +65 -0
  86. package/dist/_internal/server/jobs/handlers/countersReconcileNow.js +89 -0
  87. package/dist/_internal/server/jobs/handlers/index.d.ts +5 -0
  88. package/dist/_internal/server/jobs/handlers/index.js +5 -0
  89. package/dist/_internal/server/jobs/handlers/marketPriceRollup.d.ts +2 -0
  90. package/dist/_internal/server/jobs/handlers/marketPriceRollup.js +2 -0
  91. package/dist/_internal/server/jobs/handlers/obligationSweep.d.ts +2 -0
  92. package/dist/_internal/server/jobs/handlers/obligationSweep.js +15 -0
  93. package/dist/_internal/server/jobs/handlers/onShipmentAllocationSync.js +30 -1
  94. package/dist/_internal/server/jobs/handlers/paymentReconcile.d.ts +2 -0
  95. package/dist/_internal/server/jobs/handlers/paymentReconcile.js +6 -0
  96. package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
  97. package/dist/_internal/shared/actions/action-registry.js +71 -0
  98. package/dist/_internal/shared/checkout/coupon-discount.d.ts +73 -0
  99. package/dist/_internal/shared/checkout/coupon-discount.js +103 -0
  100. package/dist/_internal/shared/checkout/lanes.d.ts +42 -0
  101. package/dist/_internal/shared/checkout/lanes.js +46 -0
  102. package/dist/_internal/shared/checkout/order-math.d.ts +149 -1
  103. package/dist/_internal/shared/checkout/order-math.js +251 -3
  104. package/dist/_internal/shared/checkout/refundable-base.d.ts +116 -0
  105. package/dist/_internal/shared/checkout/refundable-base.js +122 -0
  106. package/dist/_internal/shared/features/auctions/config.d.ts +14 -1
  107. package/dist/_internal/shared/features/auctions/config.js +30 -1
  108. package/dist/_internal/shared/features/brands/schema.d.ts +42 -0
  109. package/dist/_internal/shared/features/brands/schema.js +18 -0
  110. package/dist/_internal/shared/features/orders/refund-copy.d.ts +22 -0
  111. package/dist/_internal/shared/features/orders/refund-copy.js +34 -0
  112. package/dist/_internal/shared/features/print/label-profiles.d.ts +198 -0
  113. package/dist/_internal/shared/features/print/label-profiles.js +350 -0
  114. package/dist/_internal/shared/features/products/to-product-item.js +33 -5
  115. package/dist/_internal/shared/fees/calculator.d.ts +31 -2
  116. package/dist/_internal/shared/fees/calculator.js +103 -5
  117. package/dist/_internal/shared/fees/india-states.d.ts +195 -0
  118. package/dist/_internal/shared/fees/india-states.js +190 -0
  119. package/dist/_internal/shared/fees/payout-hold.d.ts +80 -0
  120. package/dist/_internal/shared/fees/payout-hold.js +74 -0
  121. package/dist/_internal/shared/obligations/deadlines.d.ts +94 -0
  122. package/dist/_internal/shared/obligations/deadlines.js +155 -0
  123. package/dist/_internal/shared/shipping/quote.d.ts +96 -0
  124. package/dist/_internal/shared/shipping/quote.js +67 -0
  125. package/dist/_internal/shared/time/business-days.d.ts +91 -0
  126. package/dist/_internal/shared/time/business-days.js +185 -0
  127. package/dist/cli/index.js +0 -2
  128. package/dist/client.d.ts +10 -4
  129. package/dist/client.js +29 -3
  130. package/dist/configs/tailwind.d.ts +0 -12
  131. package/dist/configs/tailwind.js +28 -15
  132. package/dist/constants/api-endpoints.d.ts +51 -9
  133. package/dist/constants/api-endpoints.js +23 -7
  134. package/dist/constants/index.d.ts +1 -1
  135. package/dist/constants/index.js +1 -1
  136. package/dist/contracts/index.d.ts +1 -1
  137. package/dist/contracts/payment.d.ts +131 -0
  138. package/dist/features/about/components/AboutView.js +1 -1
  139. package/dist/features/about/components/DeveloperView.js +5 -2
  140. package/dist/features/about/components/FAQPageView.js +2 -1
  141. package/dist/features/about/components/FeesView.js +2 -1
  142. package/dist/features/about/components/HelpPageView.js +2 -1
  143. package/dist/features/about/components/HowAuctionsWorkView.js +2 -1
  144. package/dist/features/about/components/HowCheckoutWorksView.js +2 -1
  145. package/dist/features/about/components/HowEmiWorksView.js +2 -1
  146. package/dist/features/about/components/HowOffersWorkView.js +2 -1
  147. package/dist/features/about/components/HowOrdersWorkView.js +2 -1
  148. package/dist/features/about/components/HowPayoutsWorkView.js +2 -1
  149. package/dist/features/about/components/HowPreOrdersWorkView.js +2 -1
  150. package/dist/features/about/components/HowReviewsWorkView.js +2 -1
  151. package/dist/features/about/components/PolicyPageView.js +2 -1
  152. package/dist/features/about/components/ProseHero.d.ts +73 -0
  153. package/dist/features/about/components/ProseHero.js +18 -0
  154. package/dist/features/about/components/SecurityPrivacyView.js +2 -1
  155. package/dist/features/about/components/ShippingPolicyView.js +2 -1
  156. package/dist/features/about/components/TrackOrderView.js +2 -1
  157. package/dist/features/about/components/UnauthorizedView.js +1 -1
  158. package/dist/features/about/index.d.ts +2 -0
  159. package/dist/features/about/index.js +5 -0
  160. package/dist/features/account/actions/address-actions.d.ts +26 -2
  161. package/dist/features/account/actions/address-actions.js +25 -1
  162. package/dist/features/account/components/BuyerShoppingGuideView.js +1 -1
  163. package/dist/features/account/components/NotificationPreferencesPanel.js +1 -1
  164. package/dist/features/account/components/UserOrdersView.js +17 -0
  165. package/dist/features/account/components/UserSidebar.js +1 -1
  166. package/dist/features/account/hooks/useNotifications.js +29 -0
  167. package/dist/features/admin/actions/admin-coupon-actions.js +36 -0
  168. package/dist/features/admin/components/AdminBeysView.js +2 -2
  169. package/dist/features/admin/components/AdminBlogEditorView.js +2 -2
  170. package/dist/features/admin/components/AdminBrandEditorView.js +32 -2
  171. package/dist/features/admin/components/AdminBundleEditorView.js +1 -1
  172. package/dist/features/admin/components/AdminCarouselEditorView.js +1 -1
  173. package/dist/features/admin/components/AdminCategoriesView.js +1 -1
  174. package/dist/features/admin/components/AdminCategoryEditorView.js +73 -17
  175. package/dist/features/admin/components/AdminContactEditorView.js +1 -1
  176. package/dist/features/admin/components/AdminCouponEditorView.js +26 -1
  177. package/dist/features/admin/components/AdminFaqEditorView.js +1 -1
  178. package/dist/features/admin/components/AdminFaqsView.js +2 -2
  179. package/dist/features/admin/components/AdminGatewayEventsView.d.ts +54 -0
  180. package/dist/features/admin/components/AdminGatewayEventsView.js +209 -0
  181. package/dist/features/admin/components/AdminGuideHubView.js +1 -1
  182. package/dist/features/admin/components/AdminMoneyCasesView.d.ts +60 -0
  183. package/dist/features/admin/components/AdminMoneyCasesView.js +287 -0
  184. package/dist/features/admin/components/AdminPartsView.js +2 -2
  185. package/dist/features/admin/components/AdminProductsView.js +75 -4
  186. package/dist/features/admin/components/AdminSidebar.js +2 -2
  187. package/dist/features/admin/components/AdminSiteSettingsView.js +65 -7
  188. package/dist/features/admin/components/AdminSublistingCategoriesView.js +2 -0
  189. package/dist/features/admin/components/AdminSupportTicketDetailView.js +1 -1
  190. package/dist/features/admin/components/AdminSupportTicketsView.js +2 -2
  191. package/dist/features/admin/components/AdminTesterChecklistView.js +2 -2
  192. package/dist/features/admin/components/AdminUsersView.js +72 -1
  193. package/dist/features/admin/components/AdminViewCards.d.ts +3 -1
  194. package/dist/features/admin/components/AdminViewCards.js +4 -4
  195. package/dist/features/admin/components/DataListingView.d.ts +28 -0
  196. package/dist/features/admin/components/DataListingView.js +175 -14
  197. package/dist/features/admin/components/DataTable.d.ts +12 -1
  198. package/dist/features/admin/components/DataTable.js +3 -3
  199. package/dist/features/admin/components/OwnerQuickActions.d.ts +1 -1
  200. package/dist/features/admin/components/OwnerQuickActions.js +60 -2
  201. package/dist/features/admin/components/RecordOwnerQuickActions.d.ts +1 -1
  202. package/dist/features/admin/components/RecordOwnerQuickActions.js +61 -14
  203. package/dist/features/admin/components/analytics/AdminStatCard.d.ts +35 -1
  204. package/dist/features/admin/components/analytics/AdminStatCard.js +77 -2
  205. package/dist/features/admin/components/index.d.ts +4 -0
  206. package/dist/features/admin/components/index.js +6 -0
  207. package/dist/features/admin/constants/filter-tabs.d.ts +156 -0
  208. package/dist/features/admin/constants/filter-tabs.js +106 -0
  209. package/dist/features/admin/repository/site-settings.repository.d.ts +22 -0
  210. package/dist/features/admin/repository/site-settings.repository.js +82 -1
  211. package/dist/features/admin/schemas/admin-editor-forms.d.ts +21 -0
  212. package/dist/features/admin/schemas/admin-editor-forms.js +44 -0
  213. package/dist/features/admin/schemas/firestore.js +5 -1
  214. package/dist/features/admin/schemas/site-settings-form.js +30 -1
  215. package/dist/features/auctions/actions/bid-actions.js +13 -1
  216. package/dist/features/auctions/components/AuctionBottomActions.js +2 -2
  217. package/dist/features/auctions/components/AuctionDetailPageView.js +3 -1
  218. package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +11 -0
  219. package/dist/features/auctions/components/MarketplaceAuctionCard.js +5 -3
  220. package/dist/features/auctions/components/PlaceBidFormClient.d.ts +8 -1
  221. package/dist/features/auctions/components/PlaceBidFormClient.js +2 -2
  222. package/dist/features/audit-log/schemas/firestore.d.ts +28 -0
  223. package/dist/features/audit-log/schemas/firestore.js +14 -0
  224. package/dist/features/auth/permissions/constants.d.ts +17 -1
  225. package/dist/features/auth/permissions/constants.js +18 -0
  226. package/dist/features/blog/components/BlogPostView.js +1 -1
  227. package/dist/features/catalogue/components/AdminCatalogueApprovalsView.js +1 -1
  228. package/dist/features/categories/api/[id]/description-template/route.js +107 -1
  229. package/dist/features/categories/components/BrandDetailPageView.js +2 -2
  230. package/dist/features/categories/components/BreadcrumbTrail.js +7 -1
  231. package/dist/features/categories/components/BundleDetailView.js +1 -1
  232. package/dist/features/categories/components/CategoryDetailPageView.js +2 -2
  233. package/dist/features/categories/components/CategoryForm.js +12 -1
  234. package/dist/features/categories/components/CategoryTemplatePicker.js +38 -5
  235. package/dist/features/categories/repository/market-price-index.repository.d.ts +123 -0
  236. package/dist/features/categories/repository/market-price-index.repository.js +105 -0
  237. package/dist/features/categories/repository/price-observation.repository.d.ts +166 -0
  238. package/dist/features/categories/repository/price-observation.repository.js +132 -0
  239. package/dist/features/events/components/EventSaleBanner.js +1 -1
  240. package/dist/features/events/components/EventStatusBadge.js +1 -1
  241. package/dist/features/faq/components/FAQAccordion.js +2 -1
  242. package/dist/features/faq/components/FAQCategorySidebar.js +2 -2
  243. package/dist/features/faq/components/FAQHelpfulButtons.js +4 -4
  244. package/dist/features/faq/components/RelatedFAQs.js +1 -1
  245. package/dist/features/filters/FilterFacetSection.js +1 -1
  246. package/dist/features/filters/SwitchFilter.js +1 -1
  247. package/dist/features/gateway-events/repository/gateway-events.repository.d.ts +117 -0
  248. package/dist/features/gateway-events/repository/gateway-events.repository.js +274 -0
  249. package/dist/features/gateway-events/schemas/firestore.d.ts +217 -0
  250. package/dist/features/gateway-events/schemas/firestore.js +125 -0
  251. package/dist/features/gateway-events/schemas/index.d.ts +81 -0
  252. package/dist/features/gateway-events/schemas/index.js +79 -0
  253. package/dist/features/grouped/components/GroupedListingDetailView.js +1 -1
  254. package/dist/features/homepage/components/AnnouncementBar.js +37 -1
  255. package/dist/features/homepage/components/AnnouncementBar.style.css +30 -0
  256. package/dist/features/homepage/components/BrandsSection.js +1 -1
  257. package/dist/features/homepage/components/CTABannerSection.js +1 -1
  258. package/dist/features/homepage/components/FeaturedBundlesSection.js +14 -24
  259. package/dist/features/homepage/components/HeroCarousel.js +2 -2
  260. package/dist/features/homepage/components/SocialPostCard.js +1 -1
  261. package/dist/features/inventory/components/AdminMoveLedgerView.d.ts +7 -0
  262. package/dist/features/inventory/components/AdminMoveLedgerView.js +157 -0
  263. package/dist/features/inventory/components/AdminStorageBoxesView.d.ts +11 -0
  264. package/dist/features/inventory/components/AdminStorageBoxesView.js +168 -0
  265. package/dist/features/inventory/components/ReceiveStationView.d.ts +39 -0
  266. package/dist/features/inventory/components/ReceiveStationView.js +413 -0
  267. package/dist/features/inventory/components/operator-message.d.ts +29 -0
  268. package/dist/features/inventory/components/operator-message.js +41 -0
  269. package/dist/features/inventory/index.d.ts +13 -0
  270. package/dist/features/inventory/index.js +28 -0
  271. package/dist/features/inventory/repository/inventory-movements.repository.d.ts +97 -0
  272. package/dist/features/inventory/repository/inventory-movements.repository.js +186 -0
  273. package/dist/features/inventory/repository/inventory-placements.repository.d.ts +179 -0
  274. package/dist/features/inventory/repository/inventory-placements.repository.js +345 -0
  275. package/dist/features/inventory/repository/storage-boxes.repository.d.ts +83 -0
  276. package/dist/features/inventory/repository/storage-boxes.repository.js +127 -0
  277. package/dist/features/inventory/schemas/firestore.d.ts +197 -0
  278. package/dist/features/inventory/schemas/firestore.js +159 -0
  279. package/dist/features/layout/AppLayoutShell.d.ts +12 -1
  280. package/dist/features/layout/AppLayoutShell.js +25 -12
  281. package/dist/features/layout/AutoBreadcrumbs.js +162 -3
  282. package/dist/features/layout/AutoBreadcrumbs.style.css +45 -0
  283. package/dist/features/layout/BottomNavbar.d.ts +1 -1
  284. package/dist/features/layout/BottomNavbar.js +2 -2
  285. package/dist/features/media/MediaAvatar.js +1 -1
  286. package/dist/features/media/MediaImage.d.ts +24 -4
  287. package/dist/features/media/MediaImage.js +44 -4
  288. package/dist/features/media/MediaLightbox.js +1 -1
  289. package/dist/features/media/modals/ImageCropModal.js +1 -1
  290. package/dist/features/media/modals/ImageEditor.js +1 -1
  291. package/dist/features/media/upload/MediaUploadField.js +91 -3
  292. package/dist/features/obligations/constants/policies.d.ts +92 -0
  293. package/dist/features/obligations/constants/policies.js +378 -0
  294. package/dist/features/obligations/repository/obligations.repository.d.ts +68 -0
  295. package/dist/features/obligations/repository/obligations.repository.js +158 -0
  296. package/dist/features/obligations/schemas/firestore.d.ts +160 -0
  297. package/dist/features/obligations/schemas/firestore.js +87 -0
  298. package/dist/features/orders/actions/order-actions.d.ts +43 -4
  299. package/dist/features/orders/actions/order-actions.js +60 -3
  300. package/dist/features/orders/actions/refund-actions.js +70 -10
  301. package/dist/features/orders/components/OrderCompletionPanel.d.ts +27 -0
  302. package/dist/features/orders/components/OrderCompletionPanel.js +192 -0
  303. package/dist/features/orders/components/OrdersList.js +2 -2
  304. package/dist/features/orders/components/RefundHistoryTable.js +3 -1
  305. package/dist/features/orders/components/index.d.ts +2 -0
  306. package/dist/features/orders/components/index.js +6 -0
  307. package/dist/features/orders/constants/transitions.d.ts +59 -0
  308. package/dist/features/orders/constants/transitions.js +104 -0
  309. package/dist/features/orders/repository/orders.repository.d.ts +109 -6
  310. package/dist/features/orders/repository/orders.repository.js +464 -21
  311. package/dist/features/orders/schemas/firestore.d.ts +270 -0
  312. package/dist/features/orders/schemas/firestore.js +24 -0
  313. package/dist/features/orders/schemas/index.d.ts +61 -0
  314. package/dist/features/orders/schemas/index.js +22 -0
  315. package/dist/features/orders/types/index.d.ts +79 -0
  316. package/dist/features/parts/components/PartsIndexPageView.js +8 -1
  317. package/dist/features/payment-cases/repository/payment-cases.repository.d.ts +170 -0
  318. package/dist/features/payment-cases/repository/payment-cases.repository.js +342 -0
  319. package/dist/features/payment-cases/schemas/firestore.d.ts +229 -0
  320. package/dist/features/payment-cases/schemas/firestore.js +105 -0
  321. package/dist/features/payment-cases/schemas/resolve-form.d.ts +97 -0
  322. package/dist/features/payment-cases/schemas/resolve-form.js +114 -0
  323. package/dist/features/payments/repository/payout.repository.d.ts +0 -1
  324. package/dist/features/payments/repository/payout.repository.js +0 -1
  325. package/dist/features/points/repository/points.repository.d.ts +122 -0
  326. package/dist/features/points/repository/points.repository.js +304 -1
  327. package/dist/features/points/schemas/adjust-form.d.ts +58 -0
  328. package/dist/features/points/schemas/adjust-form.js +63 -0
  329. package/dist/features/points/schemas/firestore.d.ts +108 -1
  330. package/dist/features/points/schemas/firestore.js +84 -0
  331. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +3 -3
  332. package/dist/features/pre-orders/components/PreOrderBadge.js +1 -1
  333. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +1 -1
  334. package/dist/features/price-index/components/PriceIndexToolView.d.ts +23 -4
  335. package/dist/features/price-index/components/PriceIndexToolView.js +71 -6
  336. package/dist/features/price-index/market-stats.d.ts +82 -0
  337. package/dist/features/price-index/market-stats.js +230 -0
  338. package/dist/features/print/components/BoxLabelPrintView.d.ts +25 -0
  339. package/dist/features/print/components/BoxLabelPrintView.js +66 -0
  340. package/dist/features/print/components/LabelProfilePicker.d.ts +13 -0
  341. package/dist/features/print/components/LabelProfilePicker.js +38 -0
  342. package/dist/features/print/components/labels.d.ts +117 -0
  343. package/dist/features/print/components/labels.js +258 -0
  344. package/dist/features/print/components/labels.style.css +46 -0
  345. package/dist/features/print/index.d.ts +6 -0
  346. package/dist/features/print/index.js +16 -0
  347. package/dist/features/products/columns/productTableColumns.js +5 -4
  348. package/dist/features/products/components/MarketplaceBundleCard.js +2 -2
  349. package/dist/features/products/components/MarketplacePrizeDrawCard.js +6 -6
  350. package/dist/features/products/components/PrizeDrawCollage.js +1 -1
  351. package/dist/features/products/components/PrizeDrawItemsEditor.js +1 -1
  352. package/dist/features/products/components/PrizeRevealModal.js +2 -2
  353. package/dist/features/products/components/ProductDetailPageView.js +18 -4
  354. package/dist/features/products/components/ProductForm.js +34 -23
  355. package/dist/features/products/components/ProductGrid.js +86 -62
  356. package/dist/features/products/constants/card-badges.d.ts +97 -0
  357. package/dist/features/products/constants/card-badges.js +100 -0
  358. package/dist/features/products/repository/products.repository.js +34 -1
  359. package/dist/features/products/schemas/firestore.d.ts +46 -3
  360. package/dist/features/products/schemas/firestore.js +21 -0
  361. package/dist/features/promotions/components/PromotionsView.js +1 -1
  362. package/dist/features/promotions/repository/claimed-coupons.repository.d.ts +32 -0
  363. package/dist/features/promotions/repository/claimed-coupons.repository.js +58 -0
  364. package/dist/features/promotions/schemas/firestore.js +30 -3
  365. package/dist/features/promotions/schemas/index.d.ts +6 -6
  366. package/dist/features/protection-claims/repository/protection-claims.repository.d.ts +54 -0
  367. package/dist/features/protection-claims/repository/protection-claims.repository.js +174 -0
  368. package/dist/features/protection-claims/schemas/firestore.d.ts +168 -0
  369. package/dist/features/protection-claims/schemas/firestore.js +130 -0
  370. package/dist/features/reviews/actions/review-actions.js +3 -2
  371. package/dist/features/reviews/components/ReviewModal.js +1 -1
  372. package/dist/features/reviews/components/ReviewsList.js +1 -1
  373. package/dist/features/reviews/schemas/firestore.d.ts +20 -1
  374. package/dist/features/scams/constants/scam-types.d.ts +2 -0
  375. package/dist/features/scams/constants/scam-types.js +18 -0
  376. package/dist/features/scams/schemas/report-form.d.ts +3 -3
  377. package/dist/features/scams/schemas/report-form.js +26 -1
  378. package/dist/features/search/components/Search.js +9 -9
  379. package/dist/features/search/components/SearchResultsClient.js +18 -3
  380. package/dist/features/search/components/SearchResultsPageView.d.ts +1 -6
  381. package/dist/features/search/components/SearchResultsPageView.js +2 -2
  382. package/dist/features/seller/actions/offer-actions.js +16 -1
  383. package/dist/features/seller/actions/seller-actions.js +14 -3
  384. package/dist/features/seller/components/CategoryInlineSelect.js +75 -11
  385. package/dist/features/seller/components/PrintCenterView.d.ts +5 -0
  386. package/dist/features/seller/components/PrintCenterView.js +41 -30
  387. package/dist/features/seller/components/SellerOrdersView.js +1 -1
  388. package/dist/features/seller/components/SellerPayoutRequestView.js +16 -5
  389. package/dist/features/seller/components/SellerPayoutSettingsView.js +1 -1
  390. package/dist/features/seller/components/SellerProductShell.d.ts +16 -0
  391. package/dist/features/seller/components/SellerProductShell.js +123 -13
  392. package/dist/features/seller/components/SellerReviewsView.js +4 -2
  393. package/dist/features/seller/components/SellerSidebar.js +1 -1
  394. package/dist/features/seller/schemas/coupon-form.d.ts +26 -0
  395. package/dist/features/seller/schemas/coupon-form.js +27 -0
  396. package/dist/features/seller/schemas/product-form.d.ts +3 -0
  397. package/dist/features/seller/schemas/product-form.js +5 -0
  398. package/dist/features/shell/FormShell.js +2 -2
  399. package/dist/features/shell/QuickFormDrawer.js +14 -0
  400. package/dist/features/shell/SectionForm.d.ts +19 -0
  401. package/dist/features/shell/SectionForm.js +133 -9
  402. package/dist/features/shell/SectionForm.style.css +54 -0
  403. package/dist/features/shipments/components/AdminShipmentsView.js +16 -1
  404. package/dist/features/shipments/repository/shipment-items.repository.d.ts +9 -0
  405. package/dist/features/shipments/repository/shipment-items.repository.js +14 -0
  406. package/dist/features/site-settings/components/ActionPermissionsManager.js +1 -1
  407. package/dist/features/sticker-trace/components/StickerCommitPanel.js +1 -1
  408. package/dist/features/store-extensions/schemas/report-review-form.d.ts +8 -8
  409. package/dist/features/stores/components/StoreGuideHubView.js +1 -1
  410. package/dist/features/stores/components/StoreHeader.js +1 -1
  411. package/dist/features/support/schemas/firestore.d.ts +73 -2
  412. package/dist/features/support/schemas/firestore.js +59 -0
  413. package/dist/index.d.ts +16 -24
  414. package/dist/index.js +38 -47
  415. package/dist/next/ErrorBoundary.js +1 -1
  416. package/dist/next/routing/route-map.d.ts +24 -0
  417. package/dist/next/routing/route-map.js +40 -0
  418. package/dist/providers/payment-manual/index.d.ts +15 -1
  419. package/dist/providers/payment-manual/index.js +37 -0
  420. package/dist/providers/payment-phonepe/index.d.ts +14 -1
  421. package/dist/providers/payment-phonepe/index.js +36 -0
  422. package/dist/providers/payment-razorpay/index.d.ts +44 -1
  423. package/dist/providers/payment-razorpay/index.js +99 -0
  424. package/dist/providers/shipping-shiprocket/index.d.ts +18 -0
  425. package/dist/providers/shipping-shiprocket/index.js +18 -0
  426. package/dist/schemas/registry.d.ts +44 -11
  427. package/dist/server-entry.d.ts +2 -0
  428. package/dist/server-entry.js +27 -0
  429. package/dist/server.d.ts +43 -0
  430. package/dist/server.js +98 -0
  431. package/dist/styles.css +418 -149
  432. package/dist/tailwind-utilities.css +1 -1
  433. package/dist/tokens/themes/default-dark.js +15 -12
  434. package/dist/tokens/themes/default-light.js +14 -11
  435. package/dist/tokens/tokens.css +106 -23
  436. package/dist/ui/DataTable.style.css +4 -4
  437. package/dist/ui/columns/cell-renderers.d.ts +20 -0
  438. package/dist/ui/columns/cell-renderers.js +26 -1
  439. package/dist/ui/columns/index.d.ts +1 -1
  440. package/dist/ui/columns/index.js +4 -1
  441. package/dist/ui/components/Badge.style.css +1 -1
  442. package/dist/ui/components/Breadcrumb.js +19 -1
  443. package/dist/ui/components/BulkActionBar.style.css +4 -4
  444. package/dist/ui/components/Button.style.css +1 -1
  445. package/dist/ui/components/Checkbox.style.css +1 -1
  446. package/dist/ui/components/FallbackShell.js +1 -1
  447. package/dist/ui/components/Form.d.ts +14 -1
  448. package/dist/ui/components/Form.js +2 -2
  449. package/dist/ui/components/FormField.js +18 -4
  450. package/dist/ui/components/FormField.style.css +43 -3
  451. package/dist/ui/components/GatedPrice.style.css +1 -1
  452. package/dist/ui/components/IconButton.style.css +1 -1
  453. package/dist/ui/components/Input.js +22 -1
  454. package/dist/ui/components/Input.style.css +38 -22
  455. package/dist/ui/components/ListingFilterDrawer.js +1 -1
  456. package/dist/ui/components/ListingToolbar.js +1 -1
  457. package/dist/ui/components/PaginatedSelect.js +0 -0
  458. package/dist/ui/components/Radio.style.css +1 -1
  459. package/dist/ui/components/Repeater.d.ts +53 -0
  460. package/dist/ui/components/Repeater.js +7 -0
  461. package/dist/ui/components/RichTextEditor.d.ts +20 -1
  462. package/dist/ui/components/RichTextEditor.js +23 -2
  463. package/dist/ui/components/Select.style.css +7 -21
  464. package/dist/ui/components/Semantic.js +27 -3
  465. package/dist/ui/components/TagInput.style.css +4 -9
  466. package/dist/ui/components/Textarea.style.css +4 -18
  467. package/dist/ui/components/Toggle.style.css +1 -1
  468. package/dist/ui/components/Typography.d.ts +3 -3
  469. package/dist/ui/components/Typography.js +15 -15
  470. package/dist/ui/components/ViewToggle.style.css +4 -4
  471. package/dist/ui/forms/AddAnotherToggle.d.ts +16 -0
  472. package/dist/ui/forms/AddAnotherToggle.js +56 -0
  473. package/dist/ui/forms/ColorPickerField.js +15 -2
  474. package/dist/ui/forms/FieldCheckbox.js +15 -2
  475. package/dist/ui/forms/FieldInput.d.ts +22 -1
  476. package/dist/ui/forms/FieldInput.js +19 -5
  477. package/dist/ui/forms/FieldLabel.d.ts +35 -0
  478. package/dist/ui/forms/FieldLabel.js +70 -0
  479. package/dist/ui/forms/FieldSelect.d.ts +4 -1
  480. package/dist/ui/forms/FieldSelect.js +27 -5
  481. package/dist/ui/forms/FieldTextarea.d.ts +4 -1
  482. package/dist/ui/forms/FieldTextarea.js +22 -5
  483. package/dist/ui/forms/FormShell.d.ts +17 -1
  484. package/dist/ui/forms/FormShell.js +36 -2
  485. package/dist/ui/forms/FormShell.style.css +41 -33
  486. package/dist/ui/forms/index.d.ts +5 -1
  487. package/dist/ui/forms/index.js +2 -0
  488. package/dist/ui/icons/icon-registry.d.ts +1 -0
  489. package/dist/ui/icons/icon-registry.js +17 -1
  490. package/dist/utils/id-generators.d.ts +80 -0
  491. package/dist/utils/id-generators.js +93 -0
  492. package/dist/utils/search-txt-builders.d.ts +12 -0
  493. package/dist/utils/search-txt-builders.js +17 -0
  494. package/package.json +1 -1
  495. package/scripts/seed-cli.mjs +106 -5
  496. package/dist/features/loyalty/api/admin/loyalty/grant/route.d.ts +0 -12
  497. package/dist/features/loyalty/api/admin/loyalty/grant/route.js +0 -38
  498. package/dist/features/loyalty/api/balance/route.d.ts +0 -12
  499. package/dist/features/loyalty/api/balance/route.js +0 -41
  500. package/dist/features/loyalty/api/earn/route.d.ts +0 -12
  501. package/dist/features/loyalty/api/earn/route.js +0 -38
  502. package/dist/features/loyalty/api/history/route.d.ts +0 -12
  503. package/dist/features/loyalty/api/history/route.js +0 -58
  504. package/dist/features/loyalty/api/redeem/route.d.ts +0 -12
  505. package/dist/features/loyalty/api/redeem/route.js +0 -38
  506. package/dist/features/loyalty/columns/index.d.ts +0 -17
  507. package/dist/features/loyalty/columns/index.js +0 -40
  508. package/dist/features/loyalty/components/CoinsDisplay.d.ts +0 -12
  509. package/dist/features/loyalty/components/CoinsDisplay.js +0 -10
  510. package/dist/features/loyalty/components/index.d.ts +0 -1
  511. package/dist/features/loyalty/components/index.js +0 -1
  512. package/dist/features/loyalty/hooks/useLoyaltyBalance.d.ts +0 -4
  513. package/dist/features/loyalty/hooks/useLoyaltyBalance.js +0 -25
  514. package/dist/features/loyalty/index.d.ts +0 -6
  515. package/dist/features/loyalty/index.js +0 -6
  516. package/dist/features/loyalty/manifest.d.ts +0 -2
  517. package/dist/features/loyalty/manifest.js +0 -16
  518. package/dist/features/loyalty/messages/en.json +0 -19
  519. package/dist/features/loyalty/repository/loyalty.repository.d.ts +0 -8
  520. package/dist/features/loyalty/repository/loyalty.repository.js +0 -22
  521. package/dist/features/loyalty/schemas/index.d.ts +0 -85
  522. package/dist/features/loyalty/schemas/index.js +0 -40
  523. package/dist/features/loyalty/server.d.ts +0 -6
  524. package/dist/features/loyalty/server.js +0 -6
  525. package/dist/features/loyalty/types/index.d.ts +0 -31
  526. package/dist/features/loyalty/types/index.js +0 -1
  527. package/dist/features/loyalty/types/loyalty-config.d.ts +0 -7
  528. package/dist/features/loyalty/types/loyalty-config.js +0 -1
  529. package/dist/features/loyalty/types/loyalty-math.d.ts +0 -9
  530. package/dist/features/loyalty/types/loyalty-math.js +0 -27
  531. package/dist/features/products/components/ProductOwnerQuickActions.d.ts +0 -11
  532. package/dist/features/products/components/ProductOwnerQuickActions.js +0 -120
@@ -0,0 +1,121 @@
1
+ import { pointsRepository } from "../../../../features/points/repository/points.repository.js";
2
+ import { pointsExpiryFrom } from "../../../../features/points/schemas/firestore.js";
3
+ import { AdminAuditActionValues } from "../../../../features/audit-log/schemas/firestore.js";
4
+ import { recordAdminAction } from "../audit-log/actions.js";
5
+ import { sendNotification } from "../../../../features/admin/actions/notification-actions.js";
6
+ import { normalizeError } from "../../../../errors/normalize.js";
7
+ import { serverLogger } from "../../../../monitoring/index.js";
8
+ /**
9
+ * `admin_adjustment`'s first HUMAN writer.
10
+ *
11
+ * ## Why this is the last piece of D48 rather than the first
12
+ *
13
+ * `admin_adjustment` and `redemption_reversal` were both fully specified —
14
+ * signed-amount invariant, mandatory `adminReason`, the lot — and had **zero
15
+ * writers**. The reversal got one when cancellation was built. This is the
16
+ * other, and it was left until last on purpose: it is the only path by which a
17
+ * human can create spendable money from nothing, so it should not have existed
18
+ * before the ledger could expire a batch, consume FIFO, reverse a spend and
19
+ * reconcile against its own mirror. All four now do.
20
+ *
21
+ * ## 🛑 The one writer it must NOT be confused with
22
+ *
23
+ * `expireLapsedBatches` also appends `admin_adjustment`, with
24
+ * `actorUid: "system:points-expiry"`, and its docstring calls that **the one
25
+ * place a system actor may write an adjustment** — because expiry is a rule
26
+ * with a date attached rather than a discretionary decision.
27
+ *
28
+ * So this function takes a REAL `actorUid` and never that sentinel. Reusing it
29
+ * would make a human's decision indistinguishable from a scheduled rule in the
30
+ * one record that exists to tell them apart.
31
+ *
32
+ * ## Credits expire; debits and the reason do not
33
+ *
34
+ * A positive adjustment gets `pointsExpiryFrom(now)` like any other credit — an
35
+ * admin-granted goodwill credit is not more permanent than an earned one, and
36
+ * leaving `expiresAt` absent would mean NEVER EXPIRES, quietly making this the
37
+ * one way to mint a perpetual balance.
38
+ *
39
+ * A negative adjustment passes nothing, matching every other spend: there is
40
+ * nothing left to expire.
41
+ *
42
+ * ## Two records, deliberately
43
+ *
44
+ * The ledger entry answers "why does this account have 53 points". The
45
+ * `adminAuditLog` row answers "what have admins done lately". The second is the
46
+ * one you need when the account is not yet suspected, which is why a feature
47
+ * that already records `actorUid` on the entry still writes both.
48
+ *
49
+ * ## The buyer is told
50
+ *
51
+ * A balance that changes with no explanation is indistinguishable from a bug,
52
+ * and the buyer is the only party who cannot query the ledger. `description` is
53
+ * the buyer-facing line and is already mandatory in the schema; the
54
+ * notification carries it. `adminReason` is NOT sent — it is written for the
55
+ * next admin and may name an internal case.
56
+ *
57
+ * Best-effort: a notification that fails must not undo an applied adjustment,
58
+ * because the money has already moved and the ledger is the record that
59
+ * matters.
60
+ */
61
+ export async function adjustUserPoints(input, actor) {
62
+ /*
63
+ * 🛑 No validation here, on purpose. `pointsAdjustFormSchema` is parsed at
64
+ * the route and `isPointsEntryWellFormed` is re-checked inside
65
+ * `append()` — which THROWS rather than writing a row it knows is
66
+ * malformed. A third copy of the rule here is the sixth-hand-rolled-copy
67
+ * shape (Root Cause #75); what this function owns is the side effects.
68
+ */
69
+ const isCredit = input.amount > 0;
70
+ const { entryId, balance } = await pointsRepository.append({
71
+ userId: input.userId,
72
+ kind: "admin_adjustment",
73
+ amount: input.amount,
74
+ description: input.description,
75
+ adminReason: input.adminReason,
76
+ actorUid: actor.uid,
77
+ ...(isCredit ? { expiresAt: pointsExpiryFrom(new Date()) } : {}),
78
+ });
79
+ serverLogger.info("adjustUserPoints", {
80
+ actorUid: actor.uid,
81
+ userId: input.userId,
82
+ amount: input.amount,
83
+ balance,
84
+ entryId,
85
+ });
86
+ void recordAdminAction({
87
+ actorUid: actor.uid,
88
+ actorName: actor.name,
89
+ action: AdminAuditActionValues.POINTS_ADJUST,
90
+ targetType: "user",
91
+ targetId: input.userId,
92
+ reason: input.adminReason,
93
+ metadata: { amount: input.amount, balanceAfter: balance, entryId },
94
+ });
95
+ await sendNotification({
96
+ userId: input.userId,
97
+ type: "account_action",
98
+ /*
99
+ * `account_action` is email-ELIGIBLE, which is correct here: a balance that
100
+ * changed is money news, and the buyer is the one party who cannot query
101
+ * the ledger to find out why.
102
+ *
103
+ * 🛑 And the type is right rather than convenient — `account_action` means
104
+ * "something was done TO your account by us", which is exactly this. It was
105
+ * split away from support-ticket and scam-report activity precisely so a
106
+ * type-level email decision could distinguish them.
107
+ */
108
+ priority: "normal",
109
+ title: isCredit ? "Points added to your account" : "Points removed from your account",
110
+ message: input.description,
111
+ relatedType: "user",
112
+ relatedId: input.userId,
113
+ }).catch((err) => {
114
+ void normalizeError(err);
115
+ serverLogger.warn("adjustUserPoints: buyer notification failed (adjustment stands)", {
116
+ userId: input.userId,
117
+ entryId,
118
+ });
119
+ });
120
+ return { entryId, balance };
121
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Award purchase points on a COMPLETED order — the owner's rule, made real.
3
+ *
4
+ * ## Why this had to wait for completion to exist
5
+ *
6
+ * *"Points only get issued on successful purchases after buyer put reviews,
7
+ * then only, if no review no points, that marks the complete order; they are
8
+ * also assigned if the user [raises] no issues or updates after 7 days of
9
+ * delivery."* Then: *"auto assigned after 7 days of delivery, when order is
10
+ * marked complete; if review is given and order marked complete by the buyer
11
+ * before — immediate disburse."*
12
+ *
13
+ * So the trigger is completion, and completion has TWO writers — the buyer's
14
+ * fast path and the 7-day `order-complete` sweep — converging on one fact,
15
+ * `completedAt`.
16
+ *
17
+ * ## 🛑 `pointsAwardedAt` IS the idempotency key, and it cannot be added later
18
+ *
19
+ * `pointsLedger` is append-only. An append does not deduplicate itself, and
20
+ * `pointsRepository.append` takes no key — so two completion triggers firing
21
+ * on one order would credit twice, **permanently, with no way to net it off.**
22
+ * That is why the award was deliberately NOT written when the completion fact
23
+ * was (the sweep's own comment says so): writing the expensive half of a
24
+ * feature before its key exists is how an append-only ledger acquires a double
25
+ * credit nobody can remove.
26
+ *
27
+ * The pattern is copied from `reconcileOrderShipping`, which faced exactly this
28
+ * and solved it without a transaction: it writes `order.shippingReconciliation`
29
+ * in the same step as the credit, precisely so that field can be the key.
30
+ *
31
+ * ## The base is post-discount GOODS
32
+ *
33
+ * Not the order total. "5% of what you paid" read literally includes shipping
34
+ * and the platform fee, so we would issue points against postage handed to a
35
+ * courier. And it excludes the points tender itself, or points breed points.
36
+ *
37
+ * `orderTaxableValue` is reused rather than a fresh sum: it is already the
38
+ * post-discount, per-line, tax-backed-out goods figure, and it is already the
39
+ * payout base — so the number the seller is paid on and the number they fund
40
+ * points on are the same number, which is the property that makes the
41
+ * seller-funded model explicable to them.
42
+ *
43
+ * ## 🛑 The STORE bears it
44
+ *
45
+ * Owner: *"so stores bear it"*, framed as *"like a sale discount for getting a
46
+ * repeat customer."* So it is a DEDUCTION TERM in the payout, never a
47
+ * clawback — and that works only because of an ordering guarantee worth
48
+ * stating: `payout-release` is `blockedBy: ["order-complete"]`, so the gate
49
+ * opens BECAUSE the order completed, and completion is the same event that
50
+ * issues the points. The award is therefore always strictly before the payout
51
+ * is computed, by construction rather than by timing luck.
52
+ */
53
+ import type { OrderDocument } from "../../../../features/orders/schemas/firestore";
54
+ export interface AwardPurchasePointsResult {
55
+ awarded: number;
56
+ skipped?: "already-awarded" | "not-complete" | "no-buyer" | "nothing-earnable";
57
+ }
58
+ /**
59
+ * Award points for one completed order. Safe to call from both triggers.
60
+ *
61
+ * Takes the order rather than an id when the caller already holds one — both
62
+ * completion paths do, and re-reading it would pay a Firestore read to learn
63
+ * what the caller just wrote.
64
+ */
65
+ export declare function awardPurchasePoints(order: OrderDocument): Promise<AwardPurchasePointsResult>;
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Award purchase points on a COMPLETED order — the owner's rule, made real.
3
+ *
4
+ * ## Why this had to wait for completion to exist
5
+ *
6
+ * *"Points only get issued on successful purchases after buyer put reviews,
7
+ * then only, if no review no points, that marks the complete order; they are
8
+ * also assigned if the user [raises] no issues or updates after 7 days of
9
+ * delivery."* Then: *"auto assigned after 7 days of delivery, when order is
10
+ * marked complete; if review is given and order marked complete by the buyer
11
+ * before — immediate disburse."*
12
+ *
13
+ * So the trigger is completion, and completion has TWO writers — the buyer's
14
+ * fast path and the 7-day `order-complete` sweep — converging on one fact,
15
+ * `completedAt`.
16
+ *
17
+ * ## 🛑 `pointsAwardedAt` IS the idempotency key, and it cannot be added later
18
+ *
19
+ * `pointsLedger` is append-only. An append does not deduplicate itself, and
20
+ * `pointsRepository.append` takes no key — so two completion triggers firing
21
+ * on one order would credit twice, **permanently, with no way to net it off.**
22
+ * That is why the award was deliberately NOT written when the completion fact
23
+ * was (the sweep's own comment says so): writing the expensive half of a
24
+ * feature before its key exists is how an append-only ledger acquires a double
25
+ * credit nobody can remove.
26
+ *
27
+ * The pattern is copied from `reconcileOrderShipping`, which faced exactly this
28
+ * and solved it without a transaction: it writes `order.shippingReconciliation`
29
+ * in the same step as the credit, precisely so that field can be the key.
30
+ *
31
+ * ## The base is post-discount GOODS
32
+ *
33
+ * Not the order total. "5% of what you paid" read literally includes shipping
34
+ * and the platform fee, so we would issue points against postage handed to a
35
+ * courier. And it excludes the points tender itself, or points breed points.
36
+ *
37
+ * `orderTaxableValue` is reused rather than a fresh sum: it is already the
38
+ * post-discount, per-line, tax-backed-out goods figure, and it is already the
39
+ * payout base — so the number the seller is paid on and the number they fund
40
+ * points on are the same number, which is the property that makes the
41
+ * seller-funded model explicable to them.
42
+ *
43
+ * ## 🛑 The STORE bears it
44
+ *
45
+ * Owner: *"so stores bear it"*, framed as *"like a sale discount for getting a
46
+ * repeat customer."* So it is a DEDUCTION TERM in the payout, never a
47
+ * clawback — and that works only because of an ordering guarantee worth
48
+ * stating: `payout-release` is `blockedBy: ["order-complete"]`, so the gate
49
+ * opens BECAUSE the order completed, and completion is the same event that
50
+ * issues the points. The award is therefore always strictly before the payout
51
+ * is computed, by construction rather than by timing luck.
52
+ */
53
+ import { orderRepository } from "../../../../features/orders/repository/orders.repository.js";
54
+ import { pointsRepository } from "../../../../features/points/repository/points.repository.js";
55
+ import { POINTS_EARN_PERCENT, pointsExpiryFrom, } from "../../../../features/points/schemas/firestore.js";
56
+ import { orderTaxableValue } from "../../../shared/checkout/order-math.js";
57
+ import { normalizeError } from "../../../../errors/normalize.js";
58
+ import { serverLogger } from "../../../../monitoring/index.js";
59
+ function roundPoints(value) {
60
+ return Math.round(value * 100) / 100;
61
+ }
62
+ /**
63
+ * Award points for one completed order. Safe to call from both triggers.
64
+ *
65
+ * Takes the order rather than an id when the caller already holds one — both
66
+ * completion paths do, and re-reading it would pay a Firestore read to learn
67
+ * what the caller just wrote.
68
+ */
69
+ export async function awardPurchasePoints(order) {
70
+ /*
71
+ * The key. Checked first and checked again by the caller's own write
72
+ * ordering — a double call is the NORMAL case here, not an edge: the buyer
73
+ * completes early and the 7-day sweep later finds the order already
74
+ * complete, or a retried action runs twice.
75
+ */
76
+ if (order.pointsAwardedAt) {
77
+ return { awarded: 0, skipped: "already-awarded" };
78
+ }
79
+ if (!order.completedAt) {
80
+ /*
81
+ * Refused rather than treated as an implicit completion. The award is a
82
+ * consequence of a fact somebody recorded; inferring the fact from the
83
+ * award's own call site would let any caller mint points by asking.
84
+ */
85
+ return { awarded: 0, skipped: "not-complete" };
86
+ }
87
+ if (!order.userId) {
88
+ serverLogger.error("purchase points: completed order has no buyer", {
89
+ orderId: order.id,
90
+ });
91
+ return { awarded: 0, skipped: "no-buyer" };
92
+ }
93
+ const goods = orderTaxableValue(order);
94
+ const amount = roundPoints((goods * POINTS_EARN_PERCENT) / 100);
95
+ if (amount <= 0) {
96
+ /*
97
+ * A fully-cancelled or zero-value order. Marked as awarded anyway below so
98
+ * the sweep stops revisiting it — "we looked and there was nothing to
99
+ * give" is a decision, and leaving it unmarked would re-read this order on
100
+ * every tick forever.
101
+ */
102
+ await orderRepository
103
+ .update(order.id, { pointsAwardedAt: new Date() })
104
+ .catch((err) => {
105
+ void normalizeError(err);
106
+ });
107
+ return { awarded: 0, skipped: "nothing-earnable" };
108
+ }
109
+ const now = new Date();
110
+ await pointsRepository.append({
111
+ userId: order.userId,
112
+ kind: "purchase_earn",
113
+ amount,
114
+ orderId: order.id,
115
+ /*
116
+ * Names the base and the rate, because "47 points" alone is unexplainable
117
+ * later — and written once rather than re-derived, so it stays true of this
118
+ * moment even if the order is edited afterwards.
119
+ */
120
+ description: `${POINTS_EARN_PERCENT}% back on ${order.id}: ₹${goods.toFixed(2)} of items.`,
121
+ expiresAt: pointsExpiryFrom(now),
122
+ });
123
+ /*
124
+ * 🛑 The key is written AFTER the credit, and that ordering is deliberate.
125
+ *
126
+ * A crash between them leaves a credited buyer and an order that looks
127
+ * unawarded — so the next trigger credits a second time. That is the lesser
128
+ * evil, and the same choice `reconcileOrderShipping` documents: the reverse
129
+ * ordering would mark the order done and then fail to pay, which is money a
130
+ * buyer was promised and silently never got. An extra credit is visible in
131
+ * the ledger and reversible by an `admin_adjustment`; a missing one is
132
+ * invisible to everybody.
133
+ */
134
+ await orderRepository.update(order.id, {
135
+ pointsAwardedAt: now,
136
+ pointsAwarded: amount,
137
+ });
138
+ serverLogger.info("purchase points awarded", {
139
+ orderId: order.id,
140
+ userId: order.userId,
141
+ goods,
142
+ amount,
143
+ });
144
+ return { awarded: amount };
145
+ }
@@ -1,4 +1,14 @@
1
1
  import { PRICE_GUIDANCE_TAX_BASIS } from "../../../shared/features/categories/price-guidance";
2
+ /**
3
+ * Where a row's figures came from, and therefore what may be claimed for them.
4
+ *
5
+ * 🛑 This is not decoration and a renderer that drops it will overclaim. A
6
+ * `computed` row is a mode over dated sightings of THIS leaf and may be
7
+ * labelled "most common price, last 6 months". A `seeded` row is the 2026-10
8
+ * crawl's median for an entire GENERATION, frozen at one date — calling that
9
+ * "most common" or "recent" would be false in both halves.
10
+ */
11
+ export type PriceIndexMarketOrigin = "computed" | "seeded";
2
12
  export interface PriceIndexMarketRow {
3
13
  categoryId: string;
4
14
  /**
@@ -16,6 +26,29 @@ export interface PriceIndexMarketRow {
16
26
  p75?: number;
17
27
  sampleSize?: number;
18
28
  asOf?: string;
29
+ origin: PriceIndexMarketOrigin;
30
+ /**
31
+ * The price sightings cluster on. `computed` rows only.
32
+ *
33
+ * 🛑 Optional even there: absent means no price bucket held two or more
34
+ * sightings, so there is no cluster and the renderer must fall back to
35
+ * `median` under a different label rather than printing a lone sighting as
36
+ * though it were a consensus.
37
+ */
38
+ mode?: number;
39
+ modeCount?: number;
40
+ /** Observed low/high over the window below. `computed` rows only. */
41
+ low?: number;
42
+ high?: number;
43
+ /**
44
+ * 🛑 FALSE means `low`/`high`/`mode` describe ALL TIME — the six-month window
45
+ * held too little to stand alone. The renderer must relabel; a stale figure
46
+ * is indistinguishable from a current one once printed.
47
+ */
48
+ basedOnRecent?: boolean;
49
+ windowDays?: number;
50
+ /** Newest sighting behind a `computed` row. Not the rollup time. */
51
+ lastSeenAt?: string;
19
52
  /**
20
53
  * The share of competitor listings at this level that are SOLD OUT (0.85,
21
54
  * measured across the five largest catalogues).
@@ -55,6 +55,7 @@
55
55
  */
56
56
  import { resolveInheritedGuidanceMany } from "../categories/price-guidance-resolve.js";
57
57
  import { PRICE_GUIDANCE_TAX_BASIS } from "../../../shared/features/categories/price-guidance.js";
58
+ import { marketPriceIndexRepository } from "../../../../features/categories/repository/market-price-index.repository.js";
58
59
  import { PRICE_INDEX_SEARCH_LIMIT } from "./search.js";
59
60
  /**
60
61
  * Market bands for the leaves the client already resolved.
@@ -72,9 +73,60 @@ export async function getPriceIndexMarketForIds(rawIds) {
72
73
  const ids = [...new Set(rawIds.filter((id) => typeof id === "string" && id.length > 0))].slice(0, PRICE_INDEX_SEARCH_LIMIT);
73
74
  if (ids.length === 0)
74
75
  return [];
75
- const guidanceById = await resolveInheritedGuidanceMany(ids);
76
+ /*
77
+ * Both halves in parallel. The computed read is one `getAll`, the seeded one
78
+ * is two batched reads — three round trips total against Rule #6's budget,
79
+ * and sequencing them would make it three in series for no benefit since
80
+ * neither depends on the other.
81
+ */
82
+ const [guidanceById, computedById] = await Promise.all([
83
+ resolveInheritedGuidanceMany(ids),
84
+ marketPriceIndexRepository.getManyForLeaves(ids),
85
+ ]);
76
86
  const rows = [];
77
87
  for (const id of ids) {
88
+ /*
89
+ * 🛑 A COMPUTED band for this exact leaf outranks any seeded one.
90
+ *
91
+ * The seeded band is a crawl median for a whole generation, so every model
92
+ * in an era carries the same number — which is how Dragoon MS and Strata
93
+ * Dragoon MS, different beys with different markets, both reported ₹3,999.
94
+ * A computed band is dated sightings of THIS leaf. Where both exist the
95
+ * specific measurement wins; where only the generation band exists it still
96
+ * shows, labelled as the generation's.
97
+ *
98
+ * 🛑 Looked up for the LEAF ONLY, deliberately. Computed bands do not walk
99
+ * the ancestor chain: observations are recorded against the thing that was
100
+ * actually priced, so an era-level row would be evidence about the era and
101
+ * inheriting it down to a model would re-create the exact conflation this
102
+ * precedence exists to end. The seeded band remains the inherited fallback,
103
+ * and it says so on the card.
104
+ */
105
+ const computed = computedById.get(id)?.byKind?.ask;
106
+ if (computed) {
107
+ rows.push({
108
+ categoryId: id,
109
+ origin: "computed",
110
+ median: computed.median,
111
+ ...(computed.mode === undefined
112
+ ? {}
113
+ : { mode: computed.mode, modeCount: computed.modeCount }),
114
+ low: computed.low,
115
+ high: computed.high,
116
+ sampleSize: computed.sampleSize,
117
+ basedOnRecent: computed.basedOnRecent,
118
+ windowDays: computed.windowDays,
119
+ ...(toIso(computed.lastSeenAt) ? { lastSeenAt: toIso(computed.lastSeenAt) } : {}),
120
+ /*
121
+ * A computed band is this leaf's own measurement by construction — it
122
+ * is keyed on the leaf id and never inherited — so `inherited` is
123
+ * false and no `via*` attribution applies.
124
+ */
125
+ inherited: false,
126
+ taxBasis: PRICE_GUIDANCE_TAX_BASIS,
127
+ });
128
+ continue;
129
+ }
78
130
  const resolved = guidanceById.get(id);
79
131
  const market = resolved?.guidance.market;
80
132
  // No band anywhere up the chain. Omitted, never zeroed.
@@ -82,6 +134,7 @@ export async function getPriceIndexMarketForIds(rawIds) {
82
134
  continue;
83
135
  rows.push({
84
136
  categoryId: id,
137
+ origin: "seeded",
85
138
  median: market.median,
86
139
  ...(market.p25 === undefined ? {} : { p25: market.p25 }),
87
140
  ...(market.p75 === undefined ? {} : { p75: market.p75 }),
@@ -14,6 +14,9 @@ import { PRODUCT_COLLECTION } from "../../../../features/products/schemas/firest
14
14
  import { PRODUCTS_SITEMAP_LIMIT } from "../../../shared/features/products/config.js";
15
15
  import { isListingRowAvailable } from "../../../shared/listing-types/_registry.js";
16
16
  import { isPubliclyVisible } from "../../../shared/listing-types/availability.js";
17
+ import { isListingTypeEnabled } from "../../../shared/listing-types/feature-flags.js";
18
+ import { normalizeListingType } from "../../../../features/products/utils/listing-type.js";
19
+ import { getSiteSettingsSafe } from "../site-settings/safe-settings.js";
17
20
  import { PRODUCT_FIELDS } from "../../../../constants/field-names.js";
18
21
  import { SIEVE_OP, sieveAnd, sieveFilter, sortBy } from "../../../../utils/sieve-builder.js";
19
22
  import { REVIEW_FIELDS } from "../../../../constants/field-names.js";
@@ -163,7 +166,17 @@ export async function listSitemapProducts() {
163
166
  .select("slug", "id", "updatedAt", "listingType")
164
167
  .limit(PRODUCTS_SITEMAP_LIMIT)
165
168
  .get();
166
- return snapshot.docs.map((doc) => {
169
+ /*
170
+ * 🛑 A disabled listing type must not be advertised to search engines.
171
+ * This is the furthest-reaching surface of the lot: a sitemap entry
172
+ * survives the admin toggle, gets crawled, and lands a visitor on a type
173
+ * the site has switched off. Filtered in memory rather than in the query
174
+ * because the enabled set is a settings map, not a Firestore field.
175
+ */
176
+ const settings = await getSiteSettingsSafe();
177
+ return snapshot.docs
178
+ .filter((doc) => isListingTypeEnabled(normalizeListingType(doc.data()), settings))
179
+ .map((doc) => {
167
180
  const data = doc.data();
168
181
  const rawListingType = data.listingType;
169
182
  const listingType = rawListingType === "auction" ||
@@ -190,25 +203,21 @@ export async function listSitemapProducts() {
190
203
  // ---------------------------------------------------------------------------
191
204
  const RELATED_QUERY_PAGE_SIZE = 9;
192
205
  const RELATED_DISPLAY_LIMIT = 8;
193
- /** Firestore doc → card-grid shape. Shared by every related/similar-items carousel. */
194
- /**
195
- * Excludes the current product, anything not publicly visible, and anything
196
- * no longer available — ended auctions, closed prize-draws, filled pre-orders,
197
- * depleted code pools, sold-out stock.
198
- *
199
- * This used to be a private `isValidRelatedItem` here, and it was the only
200
- * per-type availability predicate in the codebase — which meant it was also
201
- * the only place three bugs could hide: it read `codesAvailable` at the top
202
- * level when the schema nests it under `digitalCode.codesAvailable` (so that
203
- * branch never fired), it excluded `status` values ("sold", "out_of_stock",
204
- * "discontinued") that are not members of the real `ProductStatus` union, and
205
- * it had no branch at all for classified / live / art / stickers. It now
206
- * shares one definition with the listing query and the homepage.
207
- */
208
- function toRelatedItems(docs, currentProductId) {
206
+ function toRelatedItems(docs, currentProductId, settings) {
209
207
  const now = new Date();
210
208
  return docs
211
- .filter((r) => r.id !== currentProductId && isPubliclyVisible(r) && isListingRowAvailable(r, now))
209
+ .filter((r) => r.id !== currentProductId &&
210
+ isPubliclyVisible(r) &&
211
+ /*
212
+ * 🛑 A DISABLED listing type must not appear here. Related items are
213
+ * pure DISCOVERY — unlike a won auction sitting in the cart, nothing
214
+ * here is an obligation the buyer already holds, so there is no reason
215
+ * to surface a type the admin has switched off. Without this an
216
+ * auction card rendered on every related carousel with auctions
217
+ * disabled, and it was reachable by clicking it.
218
+ */
219
+ isListingTypeEnabled(normalizeListingType(r), settings) &&
220
+ isListingRowAvailable(r, now))
212
221
  .slice(0, RELATED_DISPLAY_LIMIT)
213
222
  .map(toProductItem);
214
223
  }
@@ -256,10 +265,19 @@ export const computeRelatedItems = cache(async (product) => {
256
265
  .catch(() => [])
257
266
  : Promise.resolve([]),
258
267
  ]);
268
+ /*
269
+ * Fetched AFTER the four queries rather than inside the Promise.all: it is
270
+ * a cached single-doc read, and keeping it out of the fan-out keeps the
271
+ * four product queries parallel. `getSiteSettingsSafe` returns null on
272
+ * failure, and `isListingTypeEnabled` reads a missing flag as ENABLED — so
273
+ * a settings read that fails shows everything rather than hiding the page,
274
+ * which is the right failure direction for a discovery surface.
275
+ */
276
+ const settings = await getSiteSettingsSafe();
259
277
  return {
260
- relatedItems: toRelatedItems(sameCategoryDocs, currentProductId),
261
- relatedByBrand: toRelatedItems(sameBrandDocs, currentProductId),
262
- relatedByTags: toRelatedItems(tagOverlapDocs, currentProductId),
263
- relatedByStore: toRelatedItems(sameStoreDocs, currentProductId),
278
+ relatedItems: toRelatedItems(sameCategoryDocs, currentProductId, settings),
279
+ relatedByBrand: toRelatedItems(sameBrandDocs, currentProductId, settings),
280
+ relatedByTags: toRelatedItems(tagOverlapDocs, currentProductId, settings),
281
+ relatedByStore: toRelatedItems(sameStoreDocs, currentProductId, settings),
264
282
  };
265
283
  });
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Filing and adjudicating a protection claim — the first callers
3
+ * `protectionAvailability()` and `adjudicateClaim()` have ever had.
4
+ *
5
+ * ## What was wrong (D11)
6
+ *
7
+ * We charge 2% (min ₹30) shipment protection and 3% (min ₹49) sale protection
8
+ * at four money sites. The decision logic, the custody state machine, the
9
+ * window constants and the order fields all existed with **zero callers**, and
10
+ * the refund path did not know the add-on existed. A FAQ promised *"we pursue
11
+ * the courier and refund you"* and *"refunded no questions asked"*.
12
+ *
13
+ * ## The two gates, and why both are server-side
14
+ *
15
+ * 1. **Did the buyer actually buy this cover?** Read off the ORDER's own
16
+ * `shipmentProtectionFee` / `saleProtectionFee` — the amount charged — not
17
+ * off the live store or the live settings. A seller must not be able to
18
+ * withdraw cover after the sale, which is the same snapshot reasoning
19
+ * `finalSale` uses on the refund path.
20
+ * 2. **Is the window still open?** The `claim-shipping` / `claim-sale`
21
+ * obligations, derived from `deliveryDate` through
22
+ * `PROTECTION_CLAIM_WINDOW_HOURS` (48h / 168h). One definition, shared with
23
+ * the sweep that closes the window and earns the premium.
24
+ */
25
+ import { type ActionResult } from "../../../shared/types/action-result";
26
+ import { type ProtectionClaimDocument, type ProtectionClaimReason } from "../../../../features/protection-claims/schemas/firestore";
27
+ import { adjudicateClaim, type ClaimFinding } from "../../../shared/features/shipping/protections";
28
+ import { deadlinesFor } from "../../../shared/obligations/deadlines";
29
+ export interface FileProtectionClaimInput {
30
+ orderId: string;
31
+ reason: ProtectionClaimReason;
32
+ detail: string;
33
+ itemIds?: string[];
34
+ evidenceUrls?: string[];
35
+ }
36
+ /**
37
+ * File a claim as the buyer.
38
+ *
39
+ * 🛑 The COVER KIND is derived from the reason, never taken from the caller.
40
+ * `REASON_TO_KIND` maps transit failures to shipment cover and item failures
41
+ * to sale cover — because letting the buyer pick would let them file a
42
+ * non-delivery against the 7-day sale window after the 48-hour transit window
43
+ * had closed, which is the window rule defeated by a dropdown.
44
+ */
45
+ export declare function fileProtectionClaimAction(input: FileProtectionClaimInput): Promise<ActionResult<{
46
+ claimId: string;
47
+ }>>;
48
+ /**
49
+ * Adjudicate as an admin or moderator.
50
+ *
51
+ * 🛑 THE FINDING DECIDES WHO PAYS, NEVER WHETHER A PROTECTED BUYER IS
52
+ * REFUNDED. `adjudicateClaim` encodes that and this action does not
53
+ * second-guess it: on protected cover a `change-of-mind` finding STILL refunds
54
+ * the buyer and moves the cost to the platform, raising a report — because the
55
+ * promise sold was unconditional, and the only honest enforcement against
56
+ * repeat abuse is withdrawing FUTURE eligibility, not denying this claim.
57
+ *
58
+ * 🛑 It records the decision and does NOT move money. The refund is
59
+ * `processRefundAction`'s job, with its own idempotency key — and keeping them
60
+ * apart means a claim that adjudicated but failed to refund leaves an `upheld`
61
+ * claim with no `refundId`, which is a findable state rather than a lost one.
62
+ */
63
+ export declare function adjudicateProtectionClaimAction(claimId: string, finding: ClaimFinding): Promise<ActionResult<{
64
+ outcome: ReturnType<typeof adjudicateClaim>;
65
+ }>>;
66
+ /** A buyer's own claims, for their order detail page. */
67
+ export declare function getMyProtectionClaimsAction(): Promise<ActionResult<ProtectionClaimDocument[]>>;
68
+ /** Whether this order can be claimed against right now, for rendering the CTA. */
69
+ export declare function canClaimProtection(order: Parameters<typeof deadlinesFor>[0], kind: "shipping" | "sale"): Promise<{
70
+ can: boolean;
71
+ reason?: string;
72
+ }>;