@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
@@ -1,7 +1,11 @@
1
1
  import { sessionRepository, tokenRepository } from "../../../../repositories/index.js";
2
+ import { gatewayEventsRepository } from "../../../../features/gateway-events/repository/gateway-events.repository.js";
3
+ import { pointsRepository } from "../../../../features/points/repository/points.repository.js";
4
+ import { paymentCasesRepository } from "../../../../features/payment-cases/repository/payment-cases.repository.js";
5
+ import { normalizeError } from "../../../../errors/normalize.js";
2
6
  import { batchDelete } from "../handlers/_helpers.js";
3
7
  export async function runDailyDataCleanup(ctx) {
4
- ctx.logger.info("Starting daily data cleanup (sessions + tokens)");
8
+ ctx.logger.info("Starting daily data cleanup (sessions + tokens + gateway events)");
5
9
  const sessionRefs = await sessionRepository.getExpiredRefs(ctx.now);
6
10
  const sessionsDeleted = await batchDelete(ctx, sessionRefs);
7
11
  ctx.logger.info("Session cleanup complete", { deleted: sessionsDeleted });
@@ -13,8 +17,152 @@ export async function runDailyDataCleanup(ctx) {
13
17
  emailVerificationDeleted: emailDeleted,
14
18
  passwordResetDeleted: pwDeleted,
15
19
  });
20
+ /*
21
+ * ── gatewayEvents retention, 90 days ──────────────────────────────────────
22
+ *
23
+ * Folded in here rather than given its own scheduled function, deliberately:
24
+ * Cloud Scheduler bills **per registered job** (3 free, 28 already
25
+ * registered), so a new job for one `where(expiresAt <).limit(500)` query is
26
+ * ~$0.10/month for work that fits in a slot that already runs daily and
27
+ * already does exactly this shape for sessions and tokens.
28
+ *
29
+ * 🛑 Bounded at 500 per run, which is `getExpiredRefs`' own limit. At the
30
+ * expected ~100 events/day that is five days of backlog capacity, so the
31
+ * bound can only bite after a sustained ingest spike — and in that case the
32
+ * right response is to look at why, not to widen a sweep until it times out.
33
+ * The count is logged for exactly that reason.
34
+ *
35
+ * 🛑 It does NOT exclude rows referenced by an open `paymentCases` row yet —
36
+ * Phase 3 builds that collection and this is where the exclusion goes. Until
37
+ * then nothing references a gateway event, so there is nothing to protect;
38
+ * leaving a TODO-shaped comment here instead of a filter is honest, and the
39
+ * retention window (90d) is longer than any case should stay open.
40
+ */
41
+ const eventRefs = await gatewayEventsRepository().getExpiredRefs(ctx.now);
42
+ const eventsDeleted = await batchDelete(ctx, eventRefs);
43
+ ctx.logger.info("Gateway event cleanup complete", {
44
+ deleted: eventsDeleted,
45
+ hitLimit: eventRefs.length === 500,
46
+ });
47
+ /*
48
+ * ── Points expiry (Phase P, decision 4) ─────────────────────────────────
49
+ *
50
+ * Folded into THIS job rather than registered as its own, which is the same
51
+ * reasoning the 90-day gateway-event sweep above follows: Cloud Scheduler
52
+ * bills per REGISTERED JOB (~$0.10/month each, 3 free, 28 already live), and
53
+ * expiry is a once-a-day question whose answer does not need its own cadence.
54
+ *
55
+ * 🛑 It is not a cleanup in the delete sense, and that is why it comes last
56
+ * and is logged separately. The other three blocks remove rows nobody needs;
57
+ * this one DEBITS A BUYER by writing an adjustment entry. Burying that count
58
+ * inside "cleanup complete" would make a line of real money read as
59
+ * housekeeping.
60
+ *
61
+ * Bounded per run, and saturation is reported — at 200 expiries in one day
62
+ * there are more waiting, which is a fact about the programme's size rather
63
+ * than an error, but it must not look like the whole number.
64
+ */
65
+ let pointsExpired = { examined: 0, expired: 0, points: 0 };
66
+ try {
67
+ pointsExpired = await pointsRepository.expireLapsedBatches(ctx.now);
68
+ if (pointsExpired.expired > 0) {
69
+ ctx.logger.info("Points expiry complete", { ...pointsExpired });
70
+ }
71
+ if (pointsExpired.examined === 200) {
72
+ ctx.logger.warn("Points expiry hit its page limit — more batches are due than were processed");
73
+ }
74
+ }
75
+ catch (err) {
76
+ void normalizeError(err);
77
+ /*
78
+ * Never fails the cleanup. An unexpired batch stays spendable for another
79
+ * day, which costs us a day of liability and costs the buyer nothing —
80
+ * strictly the safe direction, and the next run picks it up because the
81
+ * query is driven by `expiresAt` rather than by a cursor.
82
+ */
83
+ ctx.logger.error("Points expiry failed — batches stay spendable for now");
84
+ }
85
+ /*
86
+ * ── Points ledger ↔ mirror reconciliation (D49) ─────────────────────────
87
+ *
88
+ * `sumLedger`'s own docstring has promised this job since the ledger was
89
+ * written — "to let a reconciliation job prove the two agree" — and nobody
90
+ * wrote it, so `users/{uid}.pointsBalance` could diverge from the entries
91
+ * indefinitely with nothing reporting it. Root Cause #102 one domain over.
92
+ *
93
+ * Folded in here rather than registered as its own scheduled function, the
94
+ * same reasoning as the two blocks above: Cloud Scheduler bills per
95
+ * REGISTERED JOB and "do the two agree" is a once-a-day question. The count
96
+ * is 33 and adding a 34th for one comparison is ~$0.10/month for work that
97
+ * fits in a slot already running.
98
+ *
99
+ * 🛑 It runs AFTER expiry, deliberately. Expiry writes adjustment entries and
100
+ * moves the mirror; reconciling first would measure a state expiry is about
101
+ * to change and could report drift that resolves itself seconds later.
102
+ *
103
+ * 🛑 Every drift opens a `ledger_drift` case even though the mirror is
104
+ * repaired on the spot. Repair without a report is self-healing that hides
105
+ * the write path which broke it — and `openOrObserve` is keyed on the user,
106
+ * so a persistently broken writer is ONE case with a rising `observedCount`
107
+ * rather than a fresh row every night.
108
+ */
109
+ let ledgerDrift = 0;
110
+ try {
111
+ const recon = await pointsRepository.reconcileLedgerMirror();
112
+ ledgerDrift = recon.drifted.length;
113
+ for (const d of recon.drifted) {
114
+ ctx.logger.error("points mirror disagreed with the ledger — repaired", {
115
+ userId: d.userId,
116
+ mirror: d.mirror,
117
+ ledger: d.ledger,
118
+ });
119
+ await paymentCasesRepository()
120
+ .openOrObserve({
121
+ kind: "ledger_drift",
122
+ severity: "warning",
123
+ subjectId: d.userId,
124
+ title: "Points balance disagreed with the ledger",
125
+ detail: `The mirror on users/${d.userId} read ${d.mirror} while the ledger sums to ` +
126
+ `${d.ledger}. The mirror has been repaired to the ledger, which is ` +
127
+ `authoritative. A repeat means a write path is losing entries.`,
128
+ entityType: "user",
129
+ entityId: d.userId,
130
+ now: ctx.now,
131
+ })
132
+ /*
133
+ * Best-effort: a case that cannot be filed must not fail the cleanup,
134
+ * because the repair has already happened and is the part the buyer
135
+ * feels. The logger line above is the fallback record.
136
+ */
137
+ .catch((caseErr) => {
138
+ void normalizeError(caseErr);
139
+ ctx.logger.error("could not open a ledger_drift case", { userId: d.userId });
140
+ });
141
+ }
142
+ if (recon.initialised > 0) {
143
+ // Not a fault — `getBalance` already falls back to summing the ledger.
144
+ ctx.logger.info("points mirrors initialised", { count: recon.initialised });
145
+ }
146
+ if (recon.saturated) {
147
+ ctx.logger.warn("points reconciliation hit its page limit — more users are unchecked than were checked");
148
+ }
149
+ }
150
+ catch (err) {
151
+ void normalizeError(err);
152
+ /*
153
+ * Never fails the cleanup. An unreconciled mirror is a read that may be
154
+ * wrong by whatever the drift is, which the next run catches; failing the
155
+ * job would also skip nothing useful, since every block above has already
156
+ * run.
157
+ */
158
+ ctx.logger.error("points reconciliation failed — mirrors unverified this run");
159
+ }
16
160
  ctx.logger.info("Daily data cleanup complete", {
17
161
  sessionsDeleted,
18
162
  tokensDeleted: emailDeleted + pwDeleted,
163
+ gatewayEventsDeleted: eventsDeleted,
164
+ pointsBatchesExpired: pointsExpired.expired,
165
+ pointsExpired: pointsExpired.points,
166
+ pointsLedgerDrift: ledgerDrift,
19
167
  });
20
168
  }
@@ -44,6 +44,20 @@ export interface DailyStatusDigestSummary {
44
44
  /** Privileged admin actions recorded in 24h — replaces the per-save settings email. */
45
45
  adminActionCount: number;
46
46
  unreadAdminNotificationCount: number;
47
+ /** Active (open + under-review) `paymentCases`, by severity. */
48
+ paymentCasesError: number;
49
+ paymentCasesWarning: number;
50
+ paymentCasesInfo: number;
51
+ /**
52
+ * The soonest external deadline across active cases, or null.
53
+ *
54
+ * 🛑 Not "oldest case" and not a count: a deadline is the only thing in this
55
+ * digest that gets WORSE on its own, so it is the one figure worth printing
56
+ * as a date rather than a number.
57
+ */
58
+ nearestCaseDueAt: Date | null;
59
+ /** Gateway events that never reached a terminal status — the inbox backlog. */
60
+ unprocessedGatewayEventCount: number;
47
61
  }
48
62
  /** Gathers the last-24h numbers. Exported so the admin manual-trigger route can reuse it. */
49
63
  export declare function collectDailyStatusSummary(): Promise<DailyStatusDigestSummary>;
@@ -27,6 +27,15 @@ import { SUPPORT_TICKET_COLLECTION, SUPPORT_TICKET_FIELDS, TicketStatusValues, }
27
27
  import { SCAMMER_COLLECTION, SCAMMER_FIELDS } from "../../../../features/scams/schemas/firestore.js";
28
28
  import { ADMIN_AUDIT_LOG_COLLECTION } from "../../../../features/audit-log/schemas/firestore.js";
29
29
  import { ADMIN_NOTIFICATIONS_COLLECTION } from "../../../../features/store-extensions/schemas/rbac.js";
30
+ /*
31
+ * Schema modules only — constants and types, no repository. This file is
32
+ * reachable from the Functions bundle and already queries nine collections
33
+ * through `getAdminDb()` directly; importing two repositories for four
34
+ * `count()` calls would widen that graph for nothing. Same reasoning as the
35
+ * `CountableQuery` structural type below.
36
+ */
37
+ import { PAYMENT_CASES_COLLECTION, PAYMENT_CASE_ACTIVE_STATUSES, PAYMENT_CASE_FIELDS, } from "../../../../features/payment-cases/schemas/firestore.js";
38
+ import { GATEWAY_EVENTS_COLLECTION, GATEWAY_EVENT_FIELDS, } from "../../../../features/gateway-events/schemas/firestore.js";
30
39
  import { EmailBold, EmailContainer, EmailDivider, EmailDoc, EmailFooter, EmailHeader, EmailLink, EmailRow, } from "../../../../features/email/primitives.js";
31
40
  import { normalizeError } from "../../../../errors/normalize.js";
32
41
  const DAY_MS = 24 * 60 * 60 * 1000;
@@ -137,6 +146,63 @@ export async function collectDailyStatusSummary() {
137
146
  safeCount(db.collection(ADMIN_AUDIT_LOG_COLLECTION).where(CREATED_AT, ">=", since)),
138
147
  safeCount(db.collection(ADMIN_NOTIFICATIONS_COLLECTION).where(IS_READ, "==", false)),
139
148
  ]);
149
+ /*
150
+ * ── MONEY AT RISK ─────────────────────────────────────────────────────────
151
+ *
152
+ * Three counts and one date. Deliberately NOT through
153
+ * `paymentCasesRepository`: this file is reachable from the Functions bundle,
154
+ * and the digest already talks to `getAdminDb()` directly for its other nine
155
+ * collections. Pulling a repository in here for three `count()` calls would
156
+ * widen the bundle's graph for no gain — the same reasoning the file's own
157
+ * `CountableQuery` comment gives for not importing a firebase-admin type.
158
+ *
159
+ * 🛑 Every one goes through `safeCount`, which returns 0 on failure. That is
160
+ * right for a digest and wrong almost anywhere else: a missing composite
161
+ * index must not stop the OTHER eleven sections being delivered, and a stuck
162
+ * zero beside live numbers reads as "that one broke". It is also why the
163
+ * nearest-deadline query below swallows and returns null rather than
164
+ * throwing.
165
+ */
166
+ const [paymentCasesError, paymentCasesWarning, paymentCasesInfo, unprocessedGatewayEventCount] = await Promise.all([
167
+ safeCount(db
168
+ .collection(PAYMENT_CASES_COLLECTION)
169
+ .where(PAYMENT_CASE_FIELDS.STATUS, "in", [...PAYMENT_CASE_ACTIVE_STATUSES])
170
+ .where(PAYMENT_CASE_FIELDS.SEVERITY, "==", "error")),
171
+ safeCount(db
172
+ .collection(PAYMENT_CASES_COLLECTION)
173
+ .where(PAYMENT_CASE_FIELDS.STATUS, "in", [...PAYMENT_CASE_ACTIVE_STATUSES])
174
+ .where(PAYMENT_CASE_FIELDS.SEVERITY, "==", "warning")),
175
+ safeCount(db
176
+ .collection(PAYMENT_CASES_COLLECTION)
177
+ .where(PAYMENT_CASE_FIELDS.STATUS, "in", [...PAYMENT_CASE_ACTIVE_STATUSES])
178
+ .where(PAYMENT_CASE_FIELDS.SEVERITY, "==", "info")),
179
+ safeCount(db
180
+ .collection(GATEWAY_EVENTS_COLLECTION)
181
+ .where(GATEWAY_EVENT_FIELDS.STATUS, "in", ["received", "processing", "failed"])),
182
+ ]);
183
+ /*
184
+ * The soonest external deadline. One document, ordered — and note it can only
185
+ * see cases that HAVE a `dueAt`, because a Firestore inequality excludes
186
+ * documents lacking the field (Root Cause #100). Correct here: a case with no
187
+ * deadline has nothing to be nearest about.
188
+ */
189
+ let nearestCaseDueAt = null;
190
+ try {
191
+ const dueSnap = await db
192
+ .collection(PAYMENT_CASES_COLLECTION)
193
+ .where(PAYMENT_CASE_FIELDS.STATUS, "in", [...PAYMENT_CASE_ACTIVE_STATUSES])
194
+ .orderBy(PAYMENT_CASE_FIELDS.DUE_AT, "asc")
195
+ .limit(1)
196
+ .get();
197
+ const raw = dueSnap.docs[0]?.get(PAYMENT_CASE_FIELDS.DUE_AT);
198
+ if (raw instanceof Date)
199
+ nearestCaseDueAt = raw;
200
+ else if (raw && typeof raw.toDate === "function")
201
+ nearestCaseDueAt = raw.toDate();
202
+ }
203
+ catch (err) {
204
+ void normalizeError(err);
205
+ }
140
206
  /*
141
207
  * `contactSubmissions` carries NO PII encryption — name, email, subject and
142
208
  * message are stored in plaintext (see `ContactSubmissionDocument`). That is
@@ -174,6 +240,11 @@ export async function collectDailyStatusSummary() {
174
240
  newSubscriberCount,
175
241
  adminActionCount,
176
242
  unreadAdminNotificationCount,
243
+ paymentCasesError,
244
+ paymentCasesWarning,
245
+ paymentCasesInfo,
246
+ nearestCaseDueAt,
247
+ unprocessedGatewayEventCount,
177
248
  };
178
249
  }
179
250
  function renderDigestHtml(summary, siteName, version) {
@@ -183,7 +254,7 @@ function renderDigestHtml(summary, siteName, version) {
183
254
  ? `Deployment ${version} is live. Activity for the last 24 hours.`
184
255
  : "Activity for the last 24 hours.", _jsx("br", {}), _jsx("br", {}), _jsx(StatLine, { label: "Orders placed", value: summary.orderCount }), _jsx(StatLine, { label: "Revenue (excl. cancelled/refunded)", value: currency(summary.revenue) }), _jsx(StatLine, { label: "Active listings", value: summary.activeListingCount }), _jsx(StatLine, { label: "Pending > 24h (needs attention)", value: summary.stuckPendingCount })] }), _jsx(EmailDivider, {}), _jsxs(EmailRow, { children: [_jsx(EmailBold, { children: "Orders by status" }), _jsx("br", {}), _jsx("br", {}), statusRows.length === 0 ? ("No orders in this window.") : (statusRows.map(([status, count]) => (_jsx(StatLine, { label: status, value: count }, status))))] }), _jsx(EmailDivider, {}), _jsxs(EmailRow, { children: [_jsx(EmailBold, { children: "Inbox" }), _jsx("br", {}), _jsx("br", {}), _jsx(StatLine, { label: "New contact messages", value: summary.contactTotal }), _jsx(StatLine, { label: "New support tickets", value: summary.newTicketCount }), _jsx(StatLine, { label: "Tickets open / in progress / waiting on user", value: `${summary.ticketsOpen} / ${summary.ticketsInProgress} / ${summary.ticketsWaitingOnUser}` }), _jsx(StatLine, { label: "Unread admin notifications", value: summary.unreadAdminNotificationCount })] }), summary.contactMessages.length > 0 ? (_jsxs(EmailRow, { children: [_jsx(EmailBold, { children: "Contact messages" }), _jsx("br", {}), _jsx("br", {}), summary.contactMessages.map((m) => (_jsxs(Fragment, { children: [_jsx(EmailBold, { children: m.subject }), _jsx("br", {}), m.name, " \u2014", " ", _jsxs(EmailLink, { href: `mailto:${m.email}?subject=${encodeURIComponent(`Re: ${m.subject}`)}`, children: ["Reply to ", m.email] }), _jsx("br", {}), m.excerpt, _jsx("br", {}), _jsx("br", {})] }, m.id))), summary.contactTotal > summary.contactMessages.length
185
256
  ? `…and ${summary.contactTotal - summary.contactMessages.length} more in /admin/contact.`
186
- : null] })) : null, _jsx(EmailDivider, {}), _jsxs(EmailRow, { children: [_jsx(EmailBold, { children: "Needs attention" }), _jsx("br", {}), _jsx("br", {}), _jsx(StatLine, { label: "Manual payments pending", value: summary.manualPaymentPendingCount }), _jsx(StatLine, { label: "New scam reports", value: summary.newScamReportCount }), _jsx(StatLine, { label: "New newsletter subscribers", value: summary.newSubscriberCount }), _jsx(StatLine, { label: "Admin actions logged", value: summary.adminActionCount })] }), _jsx(EmailFooter, { copyright: `© ${new Date().getFullYear()}${siteName ? ` ${siteName}` : ""}. All rights reserved.` })] }) }))}`;
257
+ : null] })) : null, _jsx(EmailDivider, {}), _jsxs(EmailRow, { children: [_jsx(EmailBold, { children: "Needs attention" }), _jsx("br", {}), _jsx("br", {}), _jsx(StatLine, { label: "Manual payments pending", value: summary.manualPaymentPendingCount }), _jsx(StatLine, { label: "New scam reports", value: summary.newScamReportCount }), _jsx(StatLine, { label: "New newsletter subscribers", value: summary.newSubscriberCount }), _jsx(StatLine, { label: "Admin actions logged", value: summary.adminActionCount })] }), _jsx(EmailDivider, {}), _jsxs(EmailRow, { children: [_jsx(EmailBold, { children: "Money at risk" }), _jsx("br", {}), _jsx("br", {}), _jsx(StatLine, { label: "Open cases \u2014 urgent", value: summary.paymentCasesError }), _jsx(StatLine, { label: "Open cases \u2014 warning", value: summary.paymentCasesWarning }), _jsx(StatLine, { label: "Open cases \u2014 info", value: summary.paymentCasesInfo }), _jsx(StatLine, { label: "Nearest external deadline", value: summary.nearestCaseDueAt ? summary.nearestCaseDueAt.toISOString() : "none" }), _jsx(StatLine, { label: "Unfinished gateway events", value: summary.unprocessedGatewayEventCount })] }), _jsx(EmailFooter, { copyright: `© ${new Date().getFullYear()}${siteName ? ` ${siteName}` : ""}. All rights reserved.` })] }) }))}`;
187
258
  }
188
259
  /**
189
260
  * The plain-text twin of `renderDigestHtml`.
@@ -211,6 +282,13 @@ function renderDigestText(summary, version) {
211
282
  }
212
283
  }
213
284
  lines.push("", "NEEDS ATTENTION", `Manual payments pending: ${summary.manualPaymentPendingCount}`, `New scam reports: ${summary.newScamReportCount}`, `New newsletter subscribers: ${summary.newSubscriberCount}`, `Admin actions logged: ${summary.adminActionCount}`);
285
+ /*
286
+ * The text twin of the HTML "Money at risk" section — this is the pairing
287
+ * the docstring above exists to enforce. Same five figures, same order, and
288
+ * the same unconditional rendering, because a mail client showing the text
289
+ * part must not get a digest missing the one block with a deadline in it.
290
+ */
291
+ lines.push("", "MONEY AT RISK", `Open cases — urgent: ${summary.paymentCasesError}`, `Open cases — warning: ${summary.paymentCasesWarning}`, `Open cases — info: ${summary.paymentCasesInfo}`, `Nearest external deadline: ${summary.nearestCaseDueAt ? summary.nearestCaseDueAt.toISOString() : "none"}`, `Unfinished gateway events: ${summary.unprocessedGatewayEventCount}`);
214
292
  return lines.join("\n");
215
293
  }
216
294
  const DEPLOY_MARKER_COLLECTION = "system";
@@ -19,6 +19,8 @@ export { runCleanupRtdbEvents } from "./cleanupRtdbEvents";
19
19
  export { runMediaTmpCleanup } from "./mediaTmpCleanup";
20
20
  export { runPendingOrderTimeout } from "./pendingOrderTimeout";
21
21
  export { runCountersReconcile } from "./countersReconcile";
22
+ export { runPaymentReconcile, reconcileStuckGatewayEvents } from "./paymentReconcile";
23
+ export { runObligationSweep } from "./obligationSweep";
22
24
  export { runBundleStockSync } from "./bundleStockSync";
23
25
  export { runAutoPayoutEligibility } from "./autoPayoutEligibility";
24
26
  export { runProductStatsSync } from "./productStatsSync";
@@ -20,6 +20,8 @@ export { runCleanupRtdbEvents } from "./cleanupRtdbEvents.js";
20
20
  export { runMediaTmpCleanup } from "./mediaTmpCleanup.js";
21
21
  export { runPendingOrderTimeout } from "./pendingOrderTimeout.js";
22
22
  export { runCountersReconcile } from "./countersReconcile.js";
23
+ export { runPaymentReconcile, reconcileStuckGatewayEvents } from "./paymentReconcile.js";
24
+ export { runObligationSweep } from "./obligationSweep.js";
23
25
  export { runBundleStockSync } from "./bundleStockSync.js";
24
26
  export { runAutoPayoutEligibility } from "./autoPayoutEligibility.js";
25
27
  export { runProductStatsSync } from "./productStatsSync.js";
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Core: the ASKING-price index — what a thing is currently going for, per leaf.
3
+ *
4
+ * ## Why this exists
5
+ *
6
+ * The price tool's market half was a single crawl, summarised to
7
+ * p25/median/p75 per GENERATION and frozen at one `asOf` date. Three things
8
+ * followed from that shape, none of which was fixable in the renderer:
9
+ *
10
+ * · **Every model in an era showed the same number.** Dragoon MS and Strata
11
+ * Dragoon MS are different beys with different markets, and both reported
12
+ * ₹3,999 because both inherited the Hard Metal System band.
13
+ * · **Whole eras showed nothing.** Engine Gear was never crawled, so Dragoon
14
+ * G and Dranzer G — two of the better-known tops in the line — resolved to
15
+ * no band at any ancestor and rendered an empty card.
16
+ * · **Nothing could age.** One date for the entire dataset means a figure
17
+ * measured last October reads exactly like one measured yesterday.
18
+ *
19
+ * This job replaces the summary with a derivation over dated rows, so the
20
+ * window is a parameter rather than a property of the data.
21
+ *
22
+ * ## 🛑 What it writes, and what it must never touch
23
+ *
24
+ * Writes `marketPriceIndex/{leafId}` ONLY. It does not write `categories`
25
+ * (Root Cause #92's self-triggering write, plus an ISR drop per row) and it
26
+ * does not write `priceIndex`, which is the SOLD half and belongs to
27
+ * `priceIndexRollup`. The seeded `CategoryPriceGuidance.market` band is left
28
+ * exactly as seeded and is outranked at read time, never overwritten — a bad
29
+ * import must not be able to erase the only evidence ~60 leaves have.
30
+ *
31
+ * ## 🛑 Enumerates LEAVES, not observations
32
+ *
33
+ * Root Cause #102: a reconciler that tallies from the events that exist rather
34
+ * than the entities that exist can only ever add, so a leaf whose last
35
+ * observation was retracted keeps a band forever. The leaf list is built first,
36
+ * and a leaf that no longer clears `MIN_BAND_OBSERVATIONS` has its band
37
+ * CLEARED rather than skipped.
38
+ *
39
+ * ## Why daily and never live
40
+ *
41
+ * Same answer as the sold half: a live index would scan observations per
42
+ * request, which is the unbounded-per-request pattern that paused this project
43
+ * on Hobby caps. One pre-computed read per row, with the window and the
44
+ * last-seen date travelling beside the figures.
45
+ *
46
+ * @tag domain:price-index
47
+ * @tag layer:job
48
+ * @tag pattern:rollup
49
+ * @tag access:server-only
50
+ * @tag consumers:scheduled.marketPriceRollup
51
+ * @tag sideEffects:writes marketPriceIndex
52
+ */
53
+ import type { JobContext } from "../runtime/types";
54
+ /**
55
+ * 🛑 Returns `void`, and the counts go to the LOG rather than to a caller.
56
+ *
57
+ * `ScheduleHandler` is `(ctx) => Promise<void>`, and matching it exactly is
58
+ * what lets `marketPriceRollupHandler` be a bare alias instead of a wrapper
59
+ * that discards a value — the same shape `priceIndexRollup` already has. A
60
+ * result object with no reader would also be speculative infrastructure: the
61
+ * only consumer today is an operator reading the run log, and
62
+ * `ctx.logger.info` is what they read.
63
+ */
64
+ export declare function runMarketPriceRollup(ctx: JobContext): Promise<void>;
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Core: the ASKING-price index — what a thing is currently going for, per leaf.
3
+ *
4
+ * ## Why this exists
5
+ *
6
+ * The price tool's market half was a single crawl, summarised to
7
+ * p25/median/p75 per GENERATION and frozen at one `asOf` date. Three things
8
+ * followed from that shape, none of which was fixable in the renderer:
9
+ *
10
+ * · **Every model in an era showed the same number.** Dragoon MS and Strata
11
+ * Dragoon MS are different beys with different markets, and both reported
12
+ * ₹3,999 because both inherited the Hard Metal System band.
13
+ * · **Whole eras showed nothing.** Engine Gear was never crawled, so Dragoon
14
+ * G and Dranzer G — two of the better-known tops in the line — resolved to
15
+ * no band at any ancestor and rendered an empty card.
16
+ * · **Nothing could age.** One date for the entire dataset means a figure
17
+ * measured last October reads exactly like one measured yesterday.
18
+ *
19
+ * This job replaces the summary with a derivation over dated rows, so the
20
+ * window is a parameter rather than a property of the data.
21
+ *
22
+ * ## 🛑 What it writes, and what it must never touch
23
+ *
24
+ * Writes `marketPriceIndex/{leafId}` ONLY. It does not write `categories`
25
+ * (Root Cause #92's self-triggering write, plus an ISR drop per row) and it
26
+ * does not write `priceIndex`, which is the SOLD half and belongs to
27
+ * `priceIndexRollup`. The seeded `CategoryPriceGuidance.market` band is left
28
+ * exactly as seeded and is outranked at read time, never overwritten — a bad
29
+ * import must not be able to erase the only evidence ~60 leaves have.
30
+ *
31
+ * ## 🛑 Enumerates LEAVES, not observations
32
+ *
33
+ * Root Cause #102: a reconciler that tallies from the events that exist rather
34
+ * than the entities that exist can only ever add, so a leaf whose last
35
+ * observation was retracted keeps a band forever. The leaf list is built first,
36
+ * and a leaf that no longer clears `MIN_BAND_OBSERVATIONS` has its band
37
+ * CLEARED rather than skipped.
38
+ *
39
+ * ## Why daily and never live
40
+ *
41
+ * Same answer as the sold half: a live index would scan observations per
42
+ * request, which is the unbounded-per-request pattern that paused this project
43
+ * on Hobby caps. One pre-computed read per row, with the window and the
44
+ * last-seen date travelling beside the figures.
45
+ *
46
+ * @tag domain:price-index
47
+ * @tag layer:job
48
+ * @tag pattern:rollup
49
+ * @tag access:server-only
50
+ * @tag consumers:scheduled.marketPriceRollup
51
+ * @tag sideEffects:writes marketPriceIndex
52
+ */
53
+ import { marketPriceIndexRepository, } from "../../../../features/categories/repository/market-price-index.repository.js";
54
+ import { priceObservationRepository, } from "../../../../features/categories/repository/price-observation.repository.js";
55
+ import { computeMarketStats, MIN_BAND_OBSERVATIONS, RECENT_WINDOW_DAYS, } from "../../../../features/price-index/market-stats.js";
56
+ /**
57
+ * Firestore `Timestamp` | `Date` | ISO string -> `Date`.
58
+ *
59
+ * `mapDoc` hands back whatever the driver produced, and a `Timestamp` has no
60
+ * `getTime`. `computeMarketStats` filters on `instanceof Date`, so an
61
+ * unconverted value would be silently DROPPED from the sample set rather than
62
+ * throwing — a band quietly computed over fewer rows than it had.
63
+ */
64
+ function toDate(v) {
65
+ if (v instanceof Date)
66
+ return Number.isNaN(v.getTime()) ? null : v;
67
+ if (typeof v === "string") {
68
+ const d = new Date(v);
69
+ return Number.isNaN(d.getTime()) ? null : d;
70
+ }
71
+ const t = v;
72
+ if (t && typeof t.toDate === "function") {
73
+ const d = t.toDate();
74
+ return Number.isNaN(d.getTime()) ? null : d;
75
+ }
76
+ return null;
77
+ }
78
+ /**
79
+ * 🛑 Ask and sale are grouped SEPARATELY, never pooled.
80
+ *
81
+ * `price-bands.md`'s governing rule — *"a sold-out row proves the item is
82
+ * GONE, not that it sold at that price"*, against 76–93% of crawled listings
83
+ * being sold out. Pooling them would produce a figure describing neither event,
84
+ * and the pooling would be undetectable afterwards because the result is a
85
+ * number either way.
86
+ */
87
+ function groupByKind(rows) {
88
+ const out = new Map();
89
+ for (const row of rows) {
90
+ const seenAt = toDate(row.seenAt);
91
+ if (!seenAt)
92
+ continue;
93
+ if (!Number.isFinite(row.amount) || row.amount <= 0)
94
+ continue;
95
+ const kind = row.kind === "sale" ? "sale" : "ask";
96
+ const bucket = out.get(kind) ?? [];
97
+ bucket.push({ amount: row.amount, seenAt });
98
+ out.set(kind, bucket);
99
+ }
100
+ return out;
101
+ }
102
+ /**
103
+ * 🛑 Returns `void`, and the counts go to the LOG rather than to a caller.
104
+ *
105
+ * `ScheduleHandler` is `(ctx) => Promise<void>`, and matching it exactly is
106
+ * what lets `marketPriceRollupHandler` be a bare alias instead of a wrapper
107
+ * that discards a value — the same shape `priceIndexRollup` already has. A
108
+ * result object with no reader would also be speculative infrastructure: the
109
+ * only consumer today is an operator reading the run log, and
110
+ * `ctx.logger.info` is what they read.
111
+ */
112
+ export async function runMarketPriceRollup(ctx) {
113
+ const now = new Date();
114
+ const leafIds = await priceObservationRepository.listLeafIdsWithObservations();
115
+ let written = 0;
116
+ let cleared = 0;
117
+ let counted = 0;
118
+ for (const leafId of leafIds) {
119
+ const rows = await priceObservationRepository.findForLeaf(leafId);
120
+ counted += rows.length;
121
+ const byKind = {};
122
+ for (const [kind, samples] of groupByKind(rows)) {
123
+ const stats = computeMarketStats(samples, now);
124
+ // `null` means the kind did not clear MIN_BAND_OBSERVATIONS. Omitted,
125
+ // never zeroed — a ₹0 band renders as a real price meaning "worthless".
126
+ if (!stats)
127
+ continue;
128
+ byKind[kind] = stats;
129
+ }
130
+ if (Object.keys(byKind).length === 0) {
131
+ /*
132
+ * 🛑 CLEARED, not skipped. This is the retraction path: a leaf whose
133
+ * observations were removed, or which dropped below the threshold, must
134
+ * stop publishing. Skipping would leave the last computed band standing
135
+ * on evidence that no longer exists — and it would look identical to a
136
+ * freshly computed one.
137
+ */
138
+ await marketPriceIndexRepository.clearForLeaf(leafId);
139
+ cleared += 1;
140
+ continue;
141
+ }
142
+ await marketPriceIndexRepository.setForLeaf(leafId, byKind);
143
+ written += 1;
144
+ }
145
+ ctx.logger.info("marketPriceRollup: complete", {
146
+ leavesScanned: leafIds.length,
147
+ leavesWritten: written,
148
+ leavesCleared: cleared,
149
+ observationsCounted: counted,
150
+ recentWindowDays: RECENT_WINDOW_DAYS,
151
+ minObservations: MIN_BAND_OBSERVATIONS,
152
+ });
153
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * `obligationSweep` — one job for every deadline in the order lifecycle.
3
+ *
4
+ * ## The shape, and why it is one query
5
+ *
6
+ * Open obligations past due, oldest first, bounded. For each: **re-read the
7
+ * subject**, re-evaluate the policy's `precondition`, check `blockedBy`, then
8
+ * either act or open a case.
9
+ *
10
+ * 🛑 THE RE-READ IS THE DESIGN. `obligations` is a due-date index, not truth.
11
+ * A row saying "cancel this at 15:00" is a hint; the order saying "I was paid
12
+ * at 14:58" is the fact, and the fact wins — the row closes `superseded` and
13
+ * nothing happens. Without that step this collection would be a stored mirror
14
+ * of derived state, which is Root Cause #42's shape and would eventually
15
+ * cancel a paid order.
16
+ *
17
+ * ## Scheduler cost: it goes DOWN
18
+ *
19
+ * One new job at every 5 minutes. Three existing jobs —
20
+ * `paymentWindowTimeout`, `pendingOrderTimeout` and `paymentReviewAutoApprove`
21
+ * — are superseded by policy rows and are retired in Phase 8, so the registered
22
+ * count goes **28 → 29 → 27** while roughly twenty scenarios gain coverage.
23
+ * Scheduler bills per registered job, so that is a real saving, not a wash.
24
+ *
25
+ * One query per tick, empty when idle; about a dozen writes per order lifetime.
26
+ */
27
+ import type { JobContext } from "../runtime/types";
28
+ export interface ObligationSweepResult {
29
+ due: number;
30
+ acted: number;
31
+ escalated: number;
32
+ superseded: number;
33
+ blocked: number;
34
+ failed: number;
35
+ }
36
+ export declare function runObligationSweep(ctx: JobContext): Promise<ObligationSweepResult>;