@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,170 @@
1
+ import type { DocumentReference } from "firebase-admin/firestore";
2
+ import type { FirebaseSieveFields, FirebaseSieveResult, SieveModel } from "../../../providers/db-firebase";
3
+ import { BaseRepository } from "../../../providers/db-firebase";
4
+ import { type PaymentCaseDocument, type PaymentCaseKind, type PaymentCaseSeverity, type PaymentCaseStatus } from "../schemas/firestore";
5
+ export interface OpenCaseInput {
6
+ kind: PaymentCaseKind;
7
+ /** Identifies THE PROBLEM, not the observation — see `createPaymentCaseId`. */
8
+ subjectId: string;
9
+ severity: PaymentCaseSeverity;
10
+ title: string;
11
+ detail: string;
12
+ entityType: PaymentCaseDocument["entityType"];
13
+ entityId: string;
14
+ dueAt?: Date;
15
+ amountAtRisk?: number;
16
+ gatewayEventIds?: string[];
17
+ orderIds?: string[];
18
+ gatewayPaymentId?: string;
19
+ now?: Date;
20
+ }
21
+ export type OpenCaseResult = {
22
+ id: string;
23
+ /** `true` on first sight; `false` when an existing case was observed again. */
24
+ created: boolean;
25
+ };
26
+ export interface ResolveCaseInput {
27
+ /** `actioned` (a human did something) or `dismissed` (nothing was wrong). */
28
+ status: Extract<PaymentCaseStatus, "actioned" | "dismissed">;
29
+ /** Required, min 10 chars — see the 🛑 on `resolve`. */
30
+ resolution: string;
31
+ /**
32
+ * The admin uid. 🛑 There is no overload accepting `"system"`, and that
33
+ * absence is the enforcement — see `resolve`.
34
+ */
35
+ resolvedBy: string;
36
+ now?: Date;
37
+ }
38
+ export declare class PaymentCasesRepository extends BaseRepository<PaymentCaseDocument> {
39
+ static readonly SIEVE_FIELDS: FirebaseSieveFields;
40
+ constructor();
41
+ /**
42
+ * Open a case, or record another observation of one that already exists.
43
+ *
44
+ * 🛑 THIS IS WHAT MAKES IT SAFE TO RUN RECONCILERS ON A HOT CADENCE, and it
45
+ * is the reason the dedupe key is the document id. A reconciler that re-finds
46
+ * the same problem every 5 minutes for 30 days produces **one** case and
47
+ * **one** notification. Without that property the queue fills with duplicates
48
+ * of the same fact, an operator learns to ignore it, and the first real
49
+ * chargeback is lost in 8,000 rows of noise — which is a worse outcome than
50
+ * having no queue at all.
51
+ *
52
+ * On an existing case it increments `observedCount`, bumps `lastObservedAt`,
53
+ * and ESCALATES severity if the new observation is worse. It deliberately
54
+ * does not touch `title`, `detail`, `status`, `assignedTo` or `resolution` —
55
+ * a human may have edited those, and a sweep must not overwrite a human.
56
+ *
57
+ * 🛑 Severity escalates and never falls. A reconciler seeing a smaller
58
+ * manifestation of a known problem must not be able to quietly downgrade an
59
+ * `error` an operator has already been paged about.
60
+ */
61
+ openOrObserve(input: OpenCaseInput): Promise<OpenCaseResult>;
62
+ /**
63
+ * Resolve a case. **Humans only.**
64
+ *
65
+ * 🛑 A CASE IS NEVER AUTO-CLOSABLE, AND THAT IS ENFORCED BY THE ABSENCE OF A
66
+ * CODE PATH RATHER THAN BY A FLAG.
67
+ *
68
+ * There is no overload a job can call: `resolvedBy` is required, `"system"`
69
+ * is rejected at runtime, and `resolution` has a length floor. A rule
70
+ * enforced by a boolean can be flipped by whoever is in a hurry; a rule
71
+ * enforced by there being no function to call cannot.
72
+ *
73
+ * The reason this matters more than it looks: every case here is money, and
74
+ * the thing that closes a money case is a human understanding what happened.
75
+ * A sweep that closed its own cases would turn the queue into a log — and a
76
+ * log that scrolls is exactly what the 2026-10-21 incident had instead of a
77
+ * record.
78
+ *
79
+ * A reconciler that no longer sees the problem calls `markSelfHealed`.
80
+ */
81
+ resolve(id: string, input: ResolveCaseInput): Promise<void>;
82
+ /**
83
+ * A reconciler no longer observes the problem.
84
+ *
85
+ * 🛑 Writes `selfHealedAt` and NOTHING ELSE — the status stays whatever it
86
+ * was. "The symptom is gone" and "somebody understands why" are different
87
+ * facts, and conflating them on a money case is how a hand-refunded payment
88
+ * gets filed as fixed.
89
+ */
90
+ markSelfHealed(id: string, now?: Date): Promise<void>;
91
+ assign(id: string, assignedTo: string, now?: Date): Promise<void>;
92
+ /**
93
+ * Open + under-review, worst first, then most-recently-observed first.
94
+ *
95
+ * ## 🛑 `orderBy(SEVERITY)` IS THE BUG THIS FIXES — never put it back
96
+ *
97
+ * This read `.orderBy(SEVERITY, "desc").orderBy(LAST_OBSERVED_AT, "desc")`
98
+ * under the docstring "worst first". **It returned the opposite.** `severity`
99
+ * stores the STRINGS `error` / `warning` / `info`, and Firestore orders
100
+ * strings lexicographically — so `desc` yields **warning, info, error**, the
101
+ * most urgent cases last, in the one query whose whole job is to put them
102
+ * first. Nothing errored; the list was simply backwards.
103
+ *
104
+ * So the QUERY now selects its window by `lastObservedAt` — always written by
105
+ * `openOrObserve`, one index, no composite on an enum — and the ORDER is
106
+ * applied in memory from `PAYMENT_CASE_SEVERITY_RANK`, which already exists
107
+ * and is exact. A stored numeric rank would also work and is worse: a second
108
+ * representation of severity that can drift from the first.
109
+ *
110
+ * ## Why it SURVIVED, and what measuring corrected
111
+ *
112
+ * The order was wrong and harmless, because **neither consumer reads it** —
113
+ * `countActiveBySeverity` tallies and `activeGatewayEventIds` collects into a
114
+ * Set. Two of my own assumptions were false and are recorded so they are not
115
+ * re-assumed:
116
+ *
117
+ * · *"the digest reads this"* — it does NOT. `dailyStatusDigest` runs three
118
+ * `.count()` queries, one per severity, so it never ordered by severity
119
+ * and was correct throughout.
120
+ * · *"it has zero consumers, so delete it"* — it has TWO, both in this
121
+ * file. A grep for `listActive()` with empty parentheses missed
122
+ * `listActive(500)` twice, and deleting on that basis would have broken
123
+ * the digest's counts and the gateway-event retention exclusion.
124
+ *
125
+ * 🛑 The order DOES still matter to those two, via the WINDOW: at >500 active
126
+ * cases, a severity-ordered window filled with alphabetically-first
127
+ * `warning`s would have cut `error`s out of the count entirely. Theoretical
128
+ * at this volume, real in principle, and fixed by the same change.
129
+ *
130
+ * `/admin/money-cases` deliberately does NOT use this — `DataListingView`
131
+ * needs pagination, filters and a sort dropdown, so it goes through the Sieve
132
+ * `list()` below. That view's `sortOptions` carries the matching 🛑 about why
133
+ * it offers no severity sort: same arithmetic, found at the same time.
134
+ */
135
+ listActive(limit?: number): Promise<PaymentCaseDocument[]>;
136
+ /**
137
+ * Active cases whose external deadline falls inside `horizon`.
138
+ *
139
+ * 🛑 One equality (`status in`) and one inequality (`dueAt <=`), ordered by
140
+ * `dueAt` — the only shape Firestore serves without demanding the inequality
141
+ * field lead the sort (Root Cause #59).
142
+ *
143
+ * 🛑 A case with NO `dueAt` is structurally absent from this query, because a
144
+ * Firestore inequality excludes documents lacking the field (Root Cause
145
+ * #100). That is correct here and is worth stating so nobody "fixes" it: a
146
+ * case without a deadline cannot be nearly-overdue. It is NOT correct for
147
+ * `listActive`, which is why that one filters on `status` only.
148
+ */
149
+ listDueBefore(horizon: Date, limit?: number): Promise<PaymentCaseDocument[]>;
150
+ /**
151
+ * Counts by severity over active cases.
152
+ *
153
+ * 🛑 Its docstring said *"what the daily digest prints"* and that is FALSE,
154
+ * measured 2026-10-21: `dailyStatusDigest` runs its own three `.count()`
155
+ * aggregations against the collection directly — deliberately, because that
156
+ * file is reachable from the Functions bundle and avoids the repository. So
157
+ * this method currently has no caller, and the digest does not depend on it.
158
+ *
159
+ * Kept rather than deleted because `activeGatewayEventIds` beside it is live
160
+ * and shares `listActive`, so the pair earns its keep — but do not "wire the
161
+ * digest to it" on the strength of the old comment: three `.count()`s are
162
+ * cheaper than paging 500 documents to tally them.
163
+ */
164
+ countActiveBySeverity(): Promise<Record<PaymentCaseSeverity, number>>;
165
+ /** Every gateway-event id referenced by an ACTIVE case — the retention exclusion. */
166
+ activeGatewayEventIds(): Promise<Set<string>>;
167
+ listRefs(limit?: number): Promise<DocumentReference[]>;
168
+ list(model: SieveModel): Promise<FirebaseSieveResult<PaymentCaseDocument>>;
169
+ }
170
+ export declare function paymentCasesRepository(): PaymentCasesRepository;
@@ -0,0 +1,342 @@
1
+ import { BaseRepository, applySieveToFirestore, parseSieveDateValue, prepareForFirestore, } from "../../../providers/db-firebase/index.js";
2
+ import { normalizeError } from "../../../errors/normalize.js";
3
+ import { buildHistoryEntry } from "../../../_internal/shared/history/history.js";
4
+ import { PAYMENT_CASES_COLLECTION, PAYMENT_CASE_ACTIVE_STATUSES, PAYMENT_CASE_FIELDS, PAYMENT_CASE_RESOLUTION_MIN, PAYMENT_CASE_SEVERITY_RANK, createPaymentCaseId, } from "../schemas/firestore.js";
5
+ /** gRPC `ALREADY_EXISTS` — the one `.create()` failure meaning "we have it". */
6
+ const GRPC_ALREADY_EXISTS = 6;
7
+ function isAlreadyExists(err) {
8
+ if (typeof err !== "object" || err === null)
9
+ return false;
10
+ const code = err.code;
11
+ if (code === GRPC_ALREADY_EXISTS)
12
+ return true;
13
+ if (code === "already-exists" || code === "ALREADY_EXISTS")
14
+ return true;
15
+ const message = err.message;
16
+ return typeof message === "string" && message.includes("ALREADY_EXISTS");
17
+ }
18
+ export class PaymentCasesRepository extends BaseRepository {
19
+ constructor() {
20
+ super(PAYMENT_CASES_COLLECTION);
21
+ }
22
+ /**
23
+ * Open a case, or record another observation of one that already exists.
24
+ *
25
+ * 🛑 THIS IS WHAT MAKES IT SAFE TO RUN RECONCILERS ON A HOT CADENCE, and it
26
+ * is the reason the dedupe key is the document id. A reconciler that re-finds
27
+ * the same problem every 5 minutes for 30 days produces **one** case and
28
+ * **one** notification. Without that property the queue fills with duplicates
29
+ * of the same fact, an operator learns to ignore it, and the first real
30
+ * chargeback is lost in 8,000 rows of noise — which is a worse outcome than
31
+ * having no queue at all.
32
+ *
33
+ * On an existing case it increments `observedCount`, bumps `lastObservedAt`,
34
+ * and ESCALATES severity if the new observation is worse. It deliberately
35
+ * does not touch `title`, `detail`, `status`, `assignedTo` or `resolution` —
36
+ * a human may have edited those, and a sweep must not overwrite a human.
37
+ *
38
+ * 🛑 Severity escalates and never falls. A reconciler seeing a smaller
39
+ * manifestation of a known problem must not be able to quietly downgrade an
40
+ * `error` an operator has already been paged about.
41
+ */
42
+ async openOrObserve(input) {
43
+ const now = input.now ?? new Date();
44
+ const id = createPaymentCaseId(input.kind, input.subjectId);
45
+ const ref = this.getCollection().doc(id);
46
+ const doc = {
47
+ id,
48
+ kind: input.kind,
49
+ status: "open",
50
+ severity: input.severity,
51
+ title: input.title,
52
+ detail: input.detail,
53
+ entityType: input.entityType,
54
+ entityId: input.entityId,
55
+ dedupeKey: id,
56
+ observedCount: 1,
57
+ lastObservedAt: now,
58
+ ...(input.dueAt ? { dueAt: input.dueAt } : {}),
59
+ ...(typeof input.amountAtRisk === "number"
60
+ ? { amountAtRisk: input.amountAtRisk }
61
+ : {}),
62
+ ...(input.gatewayEventIds?.length ? { gatewayEventIds: input.gatewayEventIds } : {}),
63
+ ...(input.orderIds?.length ? { orderIds: input.orderIds } : {}),
64
+ ...(input.gatewayPaymentId ? { gatewayPaymentId: input.gatewayPaymentId } : {}),
65
+ statusHistory: [
66
+ buildHistoryEntry({
67
+ actor: { role: "system" },
68
+ trigger: `paymentCase:open:${input.kind}`,
69
+ changes: { status: { from: null, to: "open" } },
70
+ now,
71
+ }),
72
+ ],
73
+ createdAt: now,
74
+ updatedAt: now,
75
+ };
76
+ try {
77
+ await ref.create(prepareForFirestore(doc));
78
+ return { id, created: true };
79
+ }
80
+ catch (err) {
81
+ if (!isAlreadyExists(err)) {
82
+ void normalizeError(err);
83
+ throw err;
84
+ }
85
+ }
86
+ /*
87
+ * Already open. A transaction, because `observedCount` is a read-modify-
88
+ * write and two reconcilers can observe the same problem in the same tick —
89
+ * `FieldValue.increment` would handle the counter but not the conditional
90
+ * severity escalation, which needs the current value to compare.
91
+ */
92
+ try {
93
+ await this.db.runTransaction(async (tx) => {
94
+ const snap = await tx.get(ref);
95
+ if (!snap.exists)
96
+ return; // raced a delete; nothing to observe
97
+ const current = this.mapDoc(snap);
98
+ const escalate = PAYMENT_CASE_SEVERITY_RANK[input.severity] >
99
+ PAYMENT_CASE_SEVERITY_RANK[current.severity];
100
+ tx.update(ref, {
101
+ observedCount: (current.observedCount ?? 0) + 1,
102
+ lastObservedAt: now,
103
+ updatedAt: now,
104
+ ...(escalate ? { severity: input.severity } : {}),
105
+ /*
106
+ * A fresh observation clears `selfHealedAt`: the problem is back (or
107
+ * never left), so a stale "looks resolved" banner would actively
108
+ * mislead. Cleared with `null` rather than `undefined` because
109
+ * `prepareForFirestore` strips undefined, which would leave the old
110
+ * value in place — a delete that silently does nothing.
111
+ */
112
+ selfHealedAt: null,
113
+ });
114
+ });
115
+ }
116
+ catch (err) {
117
+ void normalizeError(err);
118
+ throw err;
119
+ }
120
+ return { id, created: false };
121
+ }
122
+ /**
123
+ * Resolve a case. **Humans only.**
124
+ *
125
+ * 🛑 A CASE IS NEVER AUTO-CLOSABLE, AND THAT IS ENFORCED BY THE ABSENCE OF A
126
+ * CODE PATH RATHER THAN BY A FLAG.
127
+ *
128
+ * There is no overload a job can call: `resolvedBy` is required, `"system"`
129
+ * is rejected at runtime, and `resolution` has a length floor. A rule
130
+ * enforced by a boolean can be flipped by whoever is in a hurry; a rule
131
+ * enforced by there being no function to call cannot.
132
+ *
133
+ * The reason this matters more than it looks: every case here is money, and
134
+ * the thing that closes a money case is a human understanding what happened.
135
+ * A sweep that closed its own cases would turn the queue into a log — and a
136
+ * log that scrolls is exactly what the 2026-10-21 incident had instead of a
137
+ * record.
138
+ *
139
+ * A reconciler that no longer sees the problem calls `markSelfHealed`.
140
+ */
141
+ async resolve(id, input) {
142
+ const resolution = input.resolution?.trim() ?? "";
143
+ if (resolution.length < PAYMENT_CASE_RESOLUTION_MIN) {
144
+ throw new Error(`A payment case resolution must be at least ${PAYMENT_CASE_RESOLUTION_MIN} characters — "${resolution}" says nothing a later reader can use`);
145
+ }
146
+ if (!input.resolvedBy || input.resolvedBy === "system") {
147
+ throw new Error("A payment case can only be resolved by a human: `resolvedBy` must be an admin uid, never 'system'");
148
+ }
149
+ const now = input.now ?? new Date();
150
+ const ref = this.getCollection().doc(id);
151
+ const existing = await this.findById(id);
152
+ await ref.update({
153
+ status: input.status,
154
+ resolution,
155
+ resolvedBy: input.resolvedBy,
156
+ resolvedAt: now,
157
+ updatedAt: now,
158
+ statusHistory: [
159
+ ...(existing?.statusHistory ?? []),
160
+ buildHistoryEntry({
161
+ actor: { role: "admin", uid: input.resolvedBy },
162
+ trigger: "paymentCase:resolve",
163
+ changes: { status: { from: existing?.status ?? null, to: input.status } },
164
+ reason: resolution,
165
+ now,
166
+ }),
167
+ ],
168
+ });
169
+ }
170
+ /**
171
+ * A reconciler no longer observes the problem.
172
+ *
173
+ * 🛑 Writes `selfHealedAt` and NOTHING ELSE — the status stays whatever it
174
+ * was. "The symptom is gone" and "somebody understands why" are different
175
+ * facts, and conflating them on a money case is how a hand-refunded payment
176
+ * gets filed as fixed.
177
+ */
178
+ async markSelfHealed(id, now = new Date()) {
179
+ try {
180
+ await this.getCollection().doc(id).update({ selfHealedAt: now, updatedAt: now });
181
+ }
182
+ catch (err) {
183
+ // A case deleted between the sweep's read and this write is not a fault.
184
+ void normalizeError(err);
185
+ }
186
+ }
187
+ async assign(id, assignedTo, now = new Date()) {
188
+ await this.getCollection()
189
+ .doc(id)
190
+ .update({ assignedTo, status: "under-review", updatedAt: now });
191
+ }
192
+ /**
193
+ * Open + under-review, worst first, then most-recently-observed first.
194
+ *
195
+ * ## 🛑 `orderBy(SEVERITY)` IS THE BUG THIS FIXES — never put it back
196
+ *
197
+ * This read `.orderBy(SEVERITY, "desc").orderBy(LAST_OBSERVED_AT, "desc")`
198
+ * under the docstring "worst first". **It returned the opposite.** `severity`
199
+ * stores the STRINGS `error` / `warning` / `info`, and Firestore orders
200
+ * strings lexicographically — so `desc` yields **warning, info, error**, the
201
+ * most urgent cases last, in the one query whose whole job is to put them
202
+ * first. Nothing errored; the list was simply backwards.
203
+ *
204
+ * So the QUERY now selects its window by `lastObservedAt` — always written by
205
+ * `openOrObserve`, one index, no composite on an enum — and the ORDER is
206
+ * applied in memory from `PAYMENT_CASE_SEVERITY_RANK`, which already exists
207
+ * and is exact. A stored numeric rank would also work and is worse: a second
208
+ * representation of severity that can drift from the first.
209
+ *
210
+ * ## Why it SURVIVED, and what measuring corrected
211
+ *
212
+ * The order was wrong and harmless, because **neither consumer reads it** —
213
+ * `countActiveBySeverity` tallies and `activeGatewayEventIds` collects into a
214
+ * Set. Two of my own assumptions were false and are recorded so they are not
215
+ * re-assumed:
216
+ *
217
+ * · *"the digest reads this"* — it does NOT. `dailyStatusDigest` runs three
218
+ * `.count()` queries, one per severity, so it never ordered by severity
219
+ * and was correct throughout.
220
+ * · *"it has zero consumers, so delete it"* — it has TWO, both in this
221
+ * file. A grep for `listActive()` with empty parentheses missed
222
+ * `listActive(500)` twice, and deleting on that basis would have broken
223
+ * the digest's counts and the gateway-event retention exclusion.
224
+ *
225
+ * 🛑 The order DOES still matter to those two, via the WINDOW: at >500 active
226
+ * cases, a severity-ordered window filled with alphabetically-first
227
+ * `warning`s would have cut `error`s out of the count entirely. Theoretical
228
+ * at this volume, real in principle, and fixed by the same change.
229
+ *
230
+ * `/admin/money-cases` deliberately does NOT use this — `DataListingView`
231
+ * needs pagination, filters and a sort dropdown, so it goes through the Sieve
232
+ * `list()` below. That view's `sortOptions` carries the matching 🛑 about why
233
+ * it offers no severity sort: same arithmetic, found at the same time.
234
+ */
235
+ async listActive(limit = 100) {
236
+ const snap = await this.getCollection()
237
+ .where(PAYMENT_CASE_FIELDS.STATUS, "in", [...PAYMENT_CASE_ACTIVE_STATUSES])
238
+ .orderBy(PAYMENT_CASE_FIELDS.LAST_OBSERVED_AT, "desc")
239
+ .limit(limit)
240
+ .get();
241
+ const rows = snap.docs.map((d) => this.mapDoc(d));
242
+ return rows.sort((a, b) => {
243
+ const bySeverity = (PAYMENT_CASE_SEVERITY_RANK[b.severity] ?? 0) -
244
+ (PAYMENT_CASE_SEVERITY_RANK[a.severity] ?? 0);
245
+ if (bySeverity !== 0)
246
+ return bySeverity;
247
+ return b.lastObservedAt.getTime() - a.lastObservedAt.getTime();
248
+ });
249
+ }
250
+ /**
251
+ * Active cases whose external deadline falls inside `horizon`.
252
+ *
253
+ * 🛑 One equality (`status in`) and one inequality (`dueAt <=`), ordered by
254
+ * `dueAt` — the only shape Firestore serves without demanding the inequality
255
+ * field lead the sort (Root Cause #59).
256
+ *
257
+ * 🛑 A case with NO `dueAt` is structurally absent from this query, because a
258
+ * Firestore inequality excludes documents lacking the field (Root Cause
259
+ * #100). That is correct here and is worth stating so nobody "fixes" it: a
260
+ * case without a deadline cannot be nearly-overdue. It is NOT correct for
261
+ * `listActive`, which is why that one filters on `status` only.
262
+ */
263
+ async listDueBefore(horizon, limit = 50) {
264
+ const snap = await this.getCollection()
265
+ .where(PAYMENT_CASE_FIELDS.STATUS, "in", [...PAYMENT_CASE_ACTIVE_STATUSES])
266
+ .where(PAYMENT_CASE_FIELDS.DUE_AT, "<=", horizon)
267
+ .orderBy(PAYMENT_CASE_FIELDS.DUE_AT, "asc")
268
+ .limit(limit)
269
+ .get();
270
+ return snap.docs.map((d) => this.mapDoc(d));
271
+ }
272
+ /**
273
+ * Counts by severity over active cases.
274
+ *
275
+ * 🛑 Its docstring said *"what the daily digest prints"* and that is FALSE,
276
+ * measured 2026-10-21: `dailyStatusDigest` runs its own three `.count()`
277
+ * aggregations against the collection directly — deliberately, because that
278
+ * file is reachable from the Functions bundle and avoids the repository. So
279
+ * this method currently has no caller, and the digest does not depend on it.
280
+ *
281
+ * Kept rather than deleted because `activeGatewayEventIds` beside it is live
282
+ * and shares `listActive`, so the pair earns its keep — but do not "wire the
283
+ * digest to it" on the strength of the old comment: three `.count()`s are
284
+ * cheaper than paging 500 documents to tally them.
285
+ */
286
+ async countActiveBySeverity() {
287
+ const rows = await this.listActive(500);
288
+ const out = { info: 0, warning: 0, error: 0 };
289
+ for (const row of rows)
290
+ out[row.severity] = (out[row.severity] ?? 0) + 1;
291
+ return out;
292
+ }
293
+ /** Every gateway-event id referenced by an ACTIVE case — the retention exclusion. */
294
+ async activeGatewayEventIds() {
295
+ const rows = await this.listActive(500);
296
+ const ids = new Set();
297
+ for (const row of rows)
298
+ for (const id of row.gatewayEventIds ?? [])
299
+ ids.add(id);
300
+ return ids;
301
+ }
302
+ async listRefs(limit = 500) {
303
+ const snap = await this.getCollection().limit(limit).get();
304
+ return snap.docs.map((d) => d.ref);
305
+ }
306
+ async list(model) {
307
+ return applySieveToFirestore({
308
+ baseQuery: this.getCollection(),
309
+ model,
310
+ fields: PaymentCasesRepository.SIEVE_FIELDS,
311
+ });
312
+ }
313
+ }
314
+ PaymentCasesRepository.SIEVE_FIELDS = {
315
+ kind: { canFilter: true, canSort: false },
316
+ status: { canFilter: true, canSort: false },
317
+ severity: { canFilter: true, canSort: true },
318
+ entityType: { canFilter: true, canSort: false },
319
+ entityId: { canFilter: true, canSort: false },
320
+ dedupeKey: { canFilter: true, canSort: false },
321
+ assignedTo: { canFilter: true, canSort: false },
322
+ observedCount: { canFilter: true, canSort: true },
323
+ amountAtRisk: { canFilter: true, canSort: true },
324
+ gatewayPaymentId: { canFilter: true, canSort: false },
325
+ /*
326
+ * Every date field needs `parseValue` — these are stored Timestamps and
327
+ * sievejs' default coercion leaves an ISO string as a string, which
328
+ * Firestore cannot compare to a Timestamp and so matches ZERO documents
329
+ * with no error (Root Cause #47).
330
+ */
331
+ dueAt: { canFilter: true, canSort: true, parseValue: parseSieveDateValue },
332
+ lastObservedAt: { canFilter: true, canSort: true, parseValue: parseSieveDateValue },
333
+ resolvedAt: { canFilter: true, canSort: true, parseValue: parseSieveDateValue },
334
+ selfHealedAt: { canFilter: true, canSort: true, parseValue: parseSieveDateValue },
335
+ createdAt: { canFilter: true, canSort: true, parseValue: parseSieveDateValue },
336
+ };
337
+ let cached = null;
338
+ export function paymentCasesRepository() {
339
+ if (!cached)
340
+ cached = new PaymentCasesRepository();
341
+ return cached;
342
+ }