@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
@@ -53,7 +53,24 @@ export function resolveSupplierIdentity(store, settings) {
53
53
  * A seller with a GSTIN and no legal name is a data gap worth seeing as a
54
54
  * blank on the invoice, not one worth papering over with the wrong name.
55
55
  */
56
- if (sellerGstin) {
56
+ /*
57
+ * 🛑 G8 — `&& settings?.gst?.enabled`, added 2026-10-21.
58
+ *
59
+ * This branch returned on the GSTIN ALONE while the platform branch below
60
+ * was correctly gated on `gst.enabled`. So with GST disabled, a seller who
61
+ * happens to have a GSTIN still got it stamped onto the order — producing a
62
+ * document that LOOKS like a tax invoice, names a registration, and carries
63
+ * **no tax at all**, because the whole GST computation is skipped when the
64
+ * flag is off (`previewCheckoutPricing` and `createOrderForGroup` both gate
65
+ * their `sumGroupGst` call on it).
66
+ *
67
+ * An invoice asserting a GSTIN with zero tax on it is worse than a plain
68
+ * invoice: it implies a taxable supply was made and nil tax was due. The two
69
+ * branches now agree that `gst.enabled` is the switch for whether this is a
70
+ * tax document at all — which is what that flag already means everywhere
71
+ * else, and what the platform branch's own comment below says.
72
+ */
73
+ if (sellerGstin && settings?.gst?.enabled) {
57
74
  return {
58
75
  gstin: sellerGstin,
59
76
  legalName: trimmed(store?.legalName),
@@ -0,0 +1,10 @@
1
+ /**
2
+ * gateway-events — server surface.
3
+ *
4
+ * 🛑 A barrel for ONE feature's public surface, not a convenience re-export
5
+ * hub (Root Cause #18). Three symbols, all consumed by the webhook route; the
6
+ * repository is imported directly by anything that queries, because a
7
+ * reconciler has no business pulling the redactor into its graph.
8
+ */
9
+ export { ingestGatewayEvent, settleGatewayEvent, statusForDispatch, resolveDuplicateDelivery, type IngestGatewayEventInput, type SettleGatewayEventInput, type DuplicateAction, type DuplicateResolution, } from "./ingest";
10
+ export { redactGatewayPayload, type RedactResult } from "./redact";
@@ -0,0 +1,10 @@
1
+ /**
2
+ * gateway-events — server surface.
3
+ *
4
+ * 🛑 A barrel for ONE feature's public surface, not a convenience re-export
5
+ * hub (Root Cause #18). Three symbols, all consumed by the webhook route; the
6
+ * repository is imported directly by anything that queries, because a
7
+ * reconciler has no business pulling the redactor into its graph.
8
+ */
9
+ export { ingestGatewayEvent, settleGatewayEvent, statusForDispatch, resolveDuplicateDelivery, } from "./ingest.js";
10
+ export { redactGatewayPayload } from "./redact.js";
@@ -0,0 +1,127 @@
1
+ /**
2
+ * The gateway-event inbox: persist, then act, then ack.
3
+ *
4
+ * ## The ordering, and why it is this way round
5
+ *
6
+ * ```
7
+ * verify signature ← already done by the route, see below
8
+ * parse + normalise
9
+ * ingestGatewayEvent() ← 1 write: persist AND claim, atomically
10
+ * dispatch ← place the order / signal RTDB / nothing
11
+ * settleGatewayEvent() ← 1 write: the outcome
12
+ * ack
13
+ * ```
14
+ *
15
+ * Total cost: 2 writes, 0 reads for a new event; 1 failed create for a
16
+ * duplicate. ~80 ms against the route's 60,000 ms budget.
17
+ *
18
+ * 🛑 **Ingest MUST sit below the signature check**, and the webhook route
19
+ * carries a comment saying so at the rejection branch. An unauthenticated
20
+ * caller who can create Firestore documents by POSTing garbage is a write-quota
21
+ * denial-of-service with no authentication at all — on the one route in the
22
+ * application that accepts requests with no session. Persist after
23
+ * authentication, never before.
24
+ *
25
+ * ## What a crash leaves behind
26
+ *
27
+ * A row with `status: "received"` and a lease that expires in 120 s. That is
28
+ * the entire point: the 2026-10-21 incident left *nothing*, so there was no
29
+ * artefact to reconcile against and the first signal was a customer asking
30
+ * where their order was. Phase 4's R1 sweep queries exactly that shape every
31
+ * 5 minutes.
32
+ */
33
+ import { type GatewayEventClaimResult } from "../../../../features/gateway-events/repository/gateway-events.repository";
34
+ import { type GatewayEventKind, type GatewayEventStatus } from "../../../../features/gateway-events/schemas/firestore";
35
+ export interface IngestGatewayEventInput {
36
+ /** `payment.name` — the provider that signed this delivery. */
37
+ gateway: string;
38
+ /** The raw request body, verbatim — the same string the signature covered. */
39
+ rawBody: string;
40
+ /** The parsed body. Passed in rather than re-parsed, so there is one parse. */
41
+ body: unknown;
42
+ /** The gateway's own event string, e.g. `order.paid`. */
43
+ rawEvent: string;
44
+ kind: GatewayEventKind;
45
+ providerEventId?: string;
46
+ gatewayOrderId?: string;
47
+ gatewayPaymentId?: string;
48
+ /** Decimal rupees. Convert at the provider boundary, never here. */
49
+ amount?: number;
50
+ now?: Date;
51
+ }
52
+ /**
53
+ * Persist and claim.
54
+ *
55
+ * 🛑 **Throws** when the write fails for any reason other than "already
56
+ * exists". The caller must answer **503** in that case — per the route's ack
57
+ * contract, we hold no record, so the only honest response is "send it again".
58
+ * Catching this and acking 200 loses the event, which is the failure this
59
+ * module exists to prevent.
60
+ */
61
+ export declare function ingestGatewayEvent(input: IngestGatewayEventInput): Promise<GatewayEventClaimResult>;
62
+ /**
63
+ * What to do about a delivery we have seen before.
64
+ *
65
+ * 🛑 THIS BRANCH EXISTS BECAUSE NAIVE DEDUPE WOULD HAVE BROKEN THE D4 FIX, and
66
+ * the interaction is not obvious until you trace the two mechanisms together.
67
+ *
68
+ * Phase 0 made a transient placement failure answer **500**, specifically so
69
+ * the gateway's own retry schedule becomes the safety net for a
70
+ * captured-but-unplaced payment. Razorpay then redelivers **the same event
71
+ * id**. So if "we already have a row for this id" meant "ack 200 and do
72
+ * nothing", the retry we deliberately asked for would be swallowed by the
73
+ * inbox — and a captured payment with no order would go back to being
74
+ * unrecoverable. The inbox would have made things *worse* than no inbox.
75
+ *
76
+ * So a duplicate is resolved by reading its row — the one read the write-
77
+ * amplification budget allows for this path — and the answer depends on where
78
+ * that row got to:
79
+ *
80
+ * | existing row | action | why |
81
+ * |---|---|---|
82
+ * | `processed` / `ignored` / `conflict` | **ack** | done; nothing a retry can add |
83
+ * | `failed` + `terminal: true` | **ack** | a retry cannot help; a human must look |
84
+ * | `failed` without `terminal` | **redispatch** | transient — this IS the retry we asked for |
85
+ * | `received`/`processing`, lease LIVE | **ack** | another worker has it; a 5xx would thundering-herd one order |
86
+ * | `received`/`processing`, lease LAPSED | **redispatch** | the previous worker died mid-flight |
87
+ * | row missing (raced its own deletion) | **redispatch** | treat as new rather than lose it |
88
+ */
89
+ export type DuplicateAction = "ack" | "redispatch";
90
+ export interface DuplicateResolution {
91
+ action: DuplicateAction;
92
+ /** Attempts recorded so far — the caller renews the lease with this. */
93
+ attempts: number;
94
+ status?: GatewayEventStatus;
95
+ }
96
+ export declare function resolveDuplicateDelivery(id: string, now?: Date): Promise<DuplicateResolution>;
97
+ export interface SettleGatewayEventInput {
98
+ status: GatewayEventStatus;
99
+ orderIds?: string[];
100
+ lastError?: string;
101
+ terminal?: boolean;
102
+ now?: Date;
103
+ }
104
+ /**
105
+ * Record the outcome. Never throws — by this point the event is durable and the
106
+ * work is done, so a bookkeeping failure must not become a 5xx that makes the
107
+ * gateway redeliver an event we processed successfully. The row is left
108
+ * `received` with a lapsing lease, which the stuck-event sweep handles.
109
+ */
110
+ export declare function settleGatewayEvent(id: string, input: SettleGatewayEventInput): Promise<void>;
111
+ /**
112
+ * Translate a dispatch outcome into an inbox status.
113
+ *
114
+ * Kept here rather than inlined at the route so the mapping is stated once and
115
+ * both halves of the ack contract — the HTTP status the gateway sees and the
116
+ * row an operator reads — are derived from the same decision. Two hand-rolled
117
+ * copies of this would be Root Cause #75's shape on the observability axis:
118
+ * the row would say `processed` while the route answered 500.
119
+ */
120
+ export declare function statusForDispatch(outcome: {
121
+ handled: boolean;
122
+ succeeded: boolean;
123
+ retryable: boolean;
124
+ }): {
125
+ status: GatewayEventStatus;
126
+ terminal?: boolean;
127
+ };
@@ -0,0 +1,188 @@
1
+ /**
2
+ * The gateway-event inbox: persist, then act, then ack.
3
+ *
4
+ * ## The ordering, and why it is this way round
5
+ *
6
+ * ```
7
+ * verify signature ← already done by the route, see below
8
+ * parse + normalise
9
+ * ingestGatewayEvent() ← 1 write: persist AND claim, atomically
10
+ * dispatch ← place the order / signal RTDB / nothing
11
+ * settleGatewayEvent() ← 1 write: the outcome
12
+ * ack
13
+ * ```
14
+ *
15
+ * Total cost: 2 writes, 0 reads for a new event; 1 failed create for a
16
+ * duplicate. ~80 ms against the route's 60,000 ms budget.
17
+ *
18
+ * 🛑 **Ingest MUST sit below the signature check**, and the webhook route
19
+ * carries a comment saying so at the rejection branch. An unauthenticated
20
+ * caller who can create Firestore documents by POSTing garbage is a write-quota
21
+ * denial-of-service with no authentication at all — on the one route in the
22
+ * application that accepts requests with no session. Persist after
23
+ * authentication, never before.
24
+ *
25
+ * ## What a crash leaves behind
26
+ *
27
+ * A row with `status: "received"` and a lease that expires in 120 s. That is
28
+ * the entire point: the 2026-10-21 incident left *nothing*, so there was no
29
+ * artefact to reconcile against and the first signal was a customer asking
30
+ * where their order was. Phase 4's R1 sweep queries exactly that shape every
31
+ * 5 minutes.
32
+ */
33
+ /*
34
+ * 🛑 `"crypto"`, NOT `"node:crypto"` — Root Cause #24. A top-level
35
+ * `node:`-prefixed import in any file reachable from `index.ts` or `client.ts`
36
+ * through ANY re-export chain hard-fails the Turbopack production build with
37
+ * `the chunking context (unknown) does not support external modules`, on every
38
+ * page, in production only. `next dev` tolerates it, so the mistake ships.
39
+ *
40
+ * This file is server-only today and so would probably survive the prefixed
41
+ * form — but "probably, today" is how that bug arrived the first time, and the
42
+ * bare specifier costs nothing. `refunds/actions.ts` uses the same spelling for
43
+ * the same reason.
44
+ */
45
+ import { createHash } from "crypto";
46
+ import { normalizeError } from "../../../../errors/normalize.js";
47
+ import { serverLogger } from "../../../../monitoring/index.js";
48
+ import { gatewayEventsRepository, } from "../../../../features/gateway-events/repository/gateway-events.repository.js";
49
+ import { GATEWAY_EVENT_MAX_ATTEMPTS, } from "../../../../features/gateway-events/schemas/firestore.js";
50
+ import { redactGatewayPayload } from "./redact.js";
51
+ /**
52
+ * Persist and claim.
53
+ *
54
+ * 🛑 **Throws** when the write fails for any reason other than "already
55
+ * exists". The caller must answer **503** in that case — per the route's ack
56
+ * contract, we hold no record, so the only honest response is "send it again".
57
+ * Catching this and acking 200 loses the event, which is the failure this
58
+ * module exists to prevent.
59
+ */
60
+ export async function ingestGatewayEvent(input) {
61
+ const bodySha256 = createHash("sha256").update(input.rawBody).digest("hex");
62
+ const { payload, truncated } = redactGatewayPayload(input.body);
63
+ const result = await gatewayEventsRepository().claim({
64
+ gateway: input.gateway,
65
+ rawEvent: input.rawEvent,
66
+ kind: input.kind,
67
+ bodySha256,
68
+ ...(input.providerEventId ? { providerEventId: input.providerEventId } : {}),
69
+ ...(input.gatewayOrderId ? { gatewayOrderId: input.gatewayOrderId } : {}),
70
+ ...(input.gatewayPaymentId ? { gatewayPaymentId: input.gatewayPaymentId } : {}),
71
+ ...(typeof input.amount === "number" ? { amount: input.amount } : {}),
72
+ payload,
73
+ ...(truncated ? { payloadTruncated: true } : {}),
74
+ ...(input.now ? { now: input.now } : {}),
75
+ });
76
+ if (!result.claimed) {
77
+ /*
78
+ * A redelivery, or a second event carrying an identical body. Logged at
79
+ * `info` because it is NORMAL traffic and not a fault — Razorpay's own
80
+ * Resend button produces it, and so does any at-least-once delivery
81
+ * schedule. The absence of a second row IS the feature working.
82
+ */
83
+ serverLogger.info("gatewayEvents: duplicate delivery — already have it", {
84
+ id: result.id,
85
+ rawEvent: input.rawEvent,
86
+ });
87
+ }
88
+ return result;
89
+ }
90
+ export async function resolveDuplicateDelivery(id, now = new Date()) {
91
+ const existing = await gatewayEventsRepository().findById(id);
92
+ if (!existing) {
93
+ /*
94
+ * The id exists (the create failed) but the row does not — a race with the
95
+ * retention sweep, or a delete between the two calls. Fail toward DOING THE
96
+ * WORK: re-dispatching an already-processed event is idempotent downstream
97
+ * (the placement claim makes it a no-op), whereas acking an event we have
98
+ * no record of is the loss this collection exists to prevent.
99
+ */
100
+ return { action: "redispatch", attempts: 1 };
101
+ }
102
+ if (existing.status === "processed" ||
103
+ existing.status === "ignored" ||
104
+ existing.status === "conflict") {
105
+ return { action: "ack", attempts: existing.attempts, status: existing.status };
106
+ }
107
+ if (existing.status === "failed") {
108
+ return {
109
+ action: existing.terminal === true ? "ack" : "redispatch",
110
+ attempts: existing.attempts,
111
+ status: existing.status,
112
+ };
113
+ }
114
+ // received | processing — decided by the lease, not by the status.
115
+ const leaseLive = existing.leaseExpiresAt.getTime() > now.getTime();
116
+ if (leaseLive) {
117
+ return { action: "ack", attempts: existing.attempts, status: existing.status };
118
+ }
119
+ if (existing.attempts >= GATEWAY_EVENT_MAX_ATTEMPTS) {
120
+ /*
121
+ * Budget exhausted. Ack rather than loop forever — the row is `received`
122
+ * with a lapsed lease and a maxed attempt count, which is exactly the shape
123
+ * Phase 4's R1 sweep escalates into a case.
124
+ */
125
+ return { action: "ack", attempts: existing.attempts, status: existing.status };
126
+ }
127
+ /*
128
+ * Taking over a dead worker's claim, so renew the lease HERE rather than
129
+ * leaving it to the caller.
130
+ *
131
+ * 🛑 This is not a lock and does not pretend to be: `renewLease` is a plain
132
+ * update, so two redeliveries arriving in the same instant can both read a
133
+ * lapsed lease and both decide to dispatch. Narrowing that window is worth
134
+ * one write; closing it would need a transaction, and a transaction here
135
+ * would buy nothing — the thing that actually makes a double dispatch safe is
136
+ * the placement claim in `verifyAndPlaceGatewayOrderAction`, which is
137
+ * at-most-once on the gateway order id and turns the second attempt into a
138
+ * no-op. Two guards for one hazard, and the downstream one is the real one.
139
+ */
140
+ try {
141
+ await gatewayEventsRepository().renewLease(id, existing.attempts, now);
142
+ }
143
+ catch (err) {
144
+ /*
145
+ * Could not renew. Dispatch anyway: the alternative is dropping a retry we
146
+ * explicitly asked the gateway for, and the row is already durable so the
147
+ * sweep can still find it. The lease is an optimisation, not a correctness
148
+ * boundary.
149
+ */
150
+ void normalizeError(err);
151
+ serverLogger.warn("gatewayEvents: lease renewal failed — dispatching regardless", { id });
152
+ }
153
+ return { action: "redispatch", attempts: existing.attempts, status: existing.status };
154
+ }
155
+ /**
156
+ * Record the outcome. Never throws — by this point the event is durable and the
157
+ * work is done, so a bookkeeping failure must not become a 5xx that makes the
158
+ * gateway redeliver an event we processed successfully. The row is left
159
+ * `received` with a lapsing lease, which the stuck-event sweep handles.
160
+ */
161
+ export async function settleGatewayEvent(id, input) {
162
+ try {
163
+ await gatewayEventsRepository().settle(id, input);
164
+ }
165
+ catch (err) {
166
+ void normalizeError(err);
167
+ serverLogger.warn("gatewayEvents: settle failed — the stuck-event sweep will retry", {
168
+ id,
169
+ err,
170
+ });
171
+ }
172
+ }
173
+ /**
174
+ * Translate a dispatch outcome into an inbox status.
175
+ *
176
+ * Kept here rather than inlined at the route so the mapping is stated once and
177
+ * both halves of the ack contract — the HTTP status the gateway sees and the
178
+ * row an operator reads — are derived from the same decision. Two hand-rolled
179
+ * copies of this would be Root Cause #75's shape on the observability axis:
180
+ * the row would say `processed` while the route answered 500.
181
+ */
182
+ export function statusForDispatch(outcome) {
183
+ if (!outcome.handled)
184
+ return { status: "ignored" };
185
+ if (outcome.succeeded)
186
+ return { status: "processed" };
187
+ return { status: "failed", terminal: !outcome.retryable };
188
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Redact a gateway webhook body down to something safe to keep for 90 days.
3
+ *
4
+ * ## Why the raw body is never stored
5
+ *
6
+ * A Razorpay payment entity carries the buyer's `email`, `contact`,
7
+ * `card.last4`, `vpa` and `bank` — so persisting the body verbatim would make
8
+ * `gatewayEvents` a **new PII store**, with a 90-day retention, no encryption,
9
+ * and an admin table rendering it. That is a worse outcome than the problem the
10
+ * inbox solves.
11
+ *
12
+ * The integrity guarantee does not depend on keeping the body: `bodySha256` is
13
+ * computed over the verbatim bytes before redaction, so "is this the same event
14
+ * the gateway signed" stays answerable regardless of what the projection drops.
15
+ *
16
+ * ## Deny-list, and why that is defensible HERE specifically
17
+ *
18
+ * 🛑 Root Cause #70 is the incident where a deny-list projection published
19
+ * every field nobody thought to delete, and § "Public Data Projections" draws
20
+ * the rule: **a document field is private until someone names it public.** This
21
+ * redactor is a deny-list, which looks like the same mistake. It is not, for
22
+ * two reasons worth stating rather than assuming:
23
+ *
24
+ * 1. **The shape is THEIRS, not ours.** An allow-list requires enumerating
25
+ * every field a gateway might send, across providers and across their
26
+ * future API versions. A field we failed to anticipate would be *dropped*,
27
+ * and the whole value of this row is being able to read a payload we did
28
+ * not expect — that is what makes an unhandled event diagnosable. An
29
+ * allow-list here optimises for the case that never needs diagnosing.
30
+ * 2. **The output is never published.** It reaches one admin maintenance
31
+ * table behind `admin:maintenance:view-server-errors`. The field that got
32
+ * away in #70 went to an *unauthenticated, edge-cached* public endpoint.
33
+ *
34
+ * The deny-list is therefore keyed on *categories of sensitive data* rather
35
+ * than on one provider's field names, and it matches **recursively on the key
36
+ * at every depth** — so `payload.payment.entity.card.last4` is caught by the
37
+ * `card` key without anyone having written that path down.
38
+ */
39
+ import type { FirestoreDocument } from "../../../../schemas/types";
40
+ /**
41
+ * `vpa` appears as a bare key AND embedded in strings like
42
+ * `"someone@okhdfcbank"`. The key test catches the former; nothing here tries
43
+ * to catch the latter, and that is a deliberate limit rather than an oversight:
44
+ * a value-scanning redactor over arbitrary provider JSON produces false
45
+ * positives on ids that merely contain "@", and a redactor that mangles the
46
+ * diagnostic data is worse than one with a documented edge.
47
+ *
48
+ * What covers the gap is that the *keys* carrying an address — `email`,
49
+ * `contact`, `vpa` — are all denied, so a value only survives if the gateway
50
+ * put a contact detail under a key none of us anticipated.
51
+ */
52
+ export interface RedactResult {
53
+ payload: FirestoreDocument;
54
+ truncated: boolean;
55
+ }
56
+ /**
57
+ * Redact, then cap.
58
+ *
59
+ * 🛑 The cap is applied by MEASURING the serialised result and, if it is over
60
+ * budget, replacing it with a marker rather than by slicing the JSON string.
61
+ * A sliced JSON string is not JSON — it would be stored as a truncated blob
62
+ * that no reader can parse, which is a field that looks present and is
63
+ * unusable. A marker plus `payloadTruncated: true` tells the reader exactly
64
+ * what happened, and `bodySha256` still proves what arrived.
65
+ */
66
+ export declare function redactGatewayPayload(body: unknown): RedactResult;
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Redact a gateway webhook body down to something safe to keep for 90 days.
3
+ *
4
+ * ## Why the raw body is never stored
5
+ *
6
+ * A Razorpay payment entity carries the buyer's `email`, `contact`,
7
+ * `card.last4`, `vpa` and `bank` — so persisting the body verbatim would make
8
+ * `gatewayEvents` a **new PII store**, with a 90-day retention, no encryption,
9
+ * and an admin table rendering it. That is a worse outcome than the problem the
10
+ * inbox solves.
11
+ *
12
+ * The integrity guarantee does not depend on keeping the body: `bodySha256` is
13
+ * computed over the verbatim bytes before redaction, so "is this the same event
14
+ * the gateway signed" stays answerable regardless of what the projection drops.
15
+ *
16
+ * ## Deny-list, and why that is defensible HERE specifically
17
+ *
18
+ * 🛑 Root Cause #70 is the incident where a deny-list projection published
19
+ * every field nobody thought to delete, and § "Public Data Projections" draws
20
+ * the rule: **a document field is private until someone names it public.** This
21
+ * redactor is a deny-list, which looks like the same mistake. It is not, for
22
+ * two reasons worth stating rather than assuming:
23
+ *
24
+ * 1. **The shape is THEIRS, not ours.** An allow-list requires enumerating
25
+ * every field a gateway might send, across providers and across their
26
+ * future API versions. A field we failed to anticipate would be *dropped*,
27
+ * and the whole value of this row is being able to read a payload we did
28
+ * not expect — that is what makes an unhandled event diagnosable. An
29
+ * allow-list here optimises for the case that never needs diagnosing.
30
+ * 2. **The output is never published.** It reaches one admin maintenance
31
+ * table behind `admin:maintenance:view-server-errors`. The field that got
32
+ * away in #70 went to an *unauthenticated, edge-cached* public endpoint.
33
+ *
34
+ * The deny-list is therefore keyed on *categories of sensitive data* rather
35
+ * than on one provider's field names, and it matches **recursively on the key
36
+ * at every depth** — so `payload.payment.entity.card.last4` is caught by the
37
+ * `card` key without anyone having written that path down.
38
+ */
39
+ import { GATEWAY_EVENT_PAYLOAD_MAX_BYTES } from "../../../../features/gateway-events/schemas/firestore.js";
40
+ /**
41
+ * Keys dropped wherever they appear, at any depth.
42
+ *
43
+ * Grouped by why, because "it looked sensitive" is not a maintainable reason
44
+ * and the next person needs to know whether to extend the list:
45
+ *
46
+ * - **direct identifiers** — reach a person without any other data
47
+ * - **instrument data** — card/UPI/bank details; `last4` is nested under `card`
48
+ * and so is covered by the parent key
49
+ * - **our own passthrough** — `notes` and `metaInfo` are where WE pack
50
+ * `uid`/`addressId`/`outOfStockPolicy` at create-order time, so they are the
51
+ * one category that is sensitive *because of what we put there*
52
+ * - **credentials** — anything token-shaped, which should never be in a webhook
53
+ * body but costs nothing to exclude
54
+ */
55
+ const DENY_KEYS = new Set([
56
+ // direct identifiers
57
+ "email",
58
+ "contact",
59
+ "phone",
60
+ "phone_number",
61
+ "phoneNumber",
62
+ "mobile",
63
+ "name",
64
+ "customer_id",
65
+ "customerId",
66
+ "address",
67
+ "billing_address",
68
+ "shipping_address",
69
+ // instrument data
70
+ "card",
71
+ "card_id",
72
+ "vpa",
73
+ "bank_account",
74
+ "bankAccount",
75
+ "account_number",
76
+ "accountNumber",
77
+ "ifsc",
78
+ "upi",
79
+ "wallet",
80
+ // our own passthrough channel
81
+ "notes",
82
+ "metaInfo",
83
+ "udf1",
84
+ "udf2",
85
+ "udf3",
86
+ "udf4",
87
+ "udf5",
88
+ // credentials
89
+ "token",
90
+ "access_token",
91
+ "accessToken",
92
+ "refresh_token",
93
+ "secret",
94
+ "signature",
95
+ "password",
96
+ ]);
97
+ function redactValue(value) {
98
+ if (value === null || value === undefined)
99
+ return value;
100
+ if (value instanceof Date)
101
+ return value;
102
+ if (typeof value !== "object")
103
+ return value;
104
+ if (Array.isArray(value))
105
+ return value.map(redactValue);
106
+ const out = {};
107
+ for (const [key, child] of Object.entries(value)) {
108
+ if (DENY_KEYS.has(key))
109
+ continue;
110
+ out[key] = redactValue(child);
111
+ }
112
+ return out;
113
+ }
114
+ /**
115
+ * Redact, then cap.
116
+ *
117
+ * 🛑 The cap is applied by MEASURING the serialised result and, if it is over
118
+ * budget, replacing it with a marker rather than by slicing the JSON string.
119
+ * A sliced JSON string is not JSON — it would be stored as a truncated blob
120
+ * that no reader can parse, which is a field that looks present and is
121
+ * unusable. A marker plus `payloadTruncated: true` tells the reader exactly
122
+ * what happened, and `bodySha256` still proves what arrived.
123
+ */
124
+ export function redactGatewayPayload(body) {
125
+ if (typeof body !== "object" || body === null || Array.isArray(body)) {
126
+ return { payload: {}, truncated: false };
127
+ }
128
+ const redacted = redactValue(body);
129
+ let serialisedLength;
130
+ try {
131
+ serialisedLength = JSON.stringify(redacted)?.length ?? 0;
132
+ }
133
+ catch {
134
+ /*
135
+ * A circular structure cannot come from `JSON.parse`, which is the only
136
+ * producer here — but this function is exported and a future caller could
137
+ * hand it something else. Failing to a marker keeps the row writable.
138
+ */
139
+ return { payload: { redactionFailed: true }, truncated: true };
140
+ }
141
+ if (serialisedLength > GATEWAY_EVENT_PAYLOAD_MAX_BYTES) {
142
+ return {
143
+ payload: {
144
+ omitted: "payload exceeded the size budget after redaction",
145
+ approximateBytes: serialisedLength,
146
+ },
147
+ truncated: true,
148
+ };
149
+ }
150
+ return { payload: redacted, truncated: false };
151
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Grievance intake — a record, a clock, and a place in the queue.
3
+ *
4
+ * ## What was wrong (D18)
5
+ *
6
+ * There was **no intake at all**: no form, no route, no API endpoint. The
7
+ * public `/grievance` page's only instruction was a `mailto:` to the generic
8
+ * support address, so nothing recorded a grievance, timestamped it, or tracked
9
+ * any statutory clock. `/report` is for scam and entity reports, not money.
10
+ *
11
+ * ## What this builds, and what it deliberately does NOT
12
+ *
13
+ * Built: the record, the acknowledgement timestamp, the resolution deadline,
14
+ * the structured disputed amount, and a `paymentCases` row so the deadline sits
15
+ * in the one queue an operator already reads.
16
+ *
17
+ * 🛑 **NOT built: anything published.** The Consumer Protection (E-Commerce)
18
+ * Rules 2020 require a NAMED individual as grievance officer, and this project
19
+ * publishes the business name with designation "Support" and the same generic
20
+ * support email — so there is no escalation tier (D17). It also publishes no
21
+ * timeline anywhere.
22
+ *
23
+ * I am not asserting the statutory periods from memory, and the reason is
24
+ * asymmetric: **a published timeline we then miss is worse than the present
25
+ * silence.** So the clock runs against `GRIEVANCE_PERIODS`, whose defaults are
26
+ * deliberately shorter than any plausible statutory period — firing early is
27
+ * harmless, firing late is the thing the regime punishes — and the public page
28
+ * stays untouched until the owner supplies the officer and the real numbers.
29
+ */
30
+ import { type ActionResult } from "../../../shared/types/action-result";
31
+ export interface FileGrievanceInput {
32
+ subject: string;
33
+ detail: string;
34
+ /** The order it concerns, when it concerns one. */
35
+ orderId?: string;
36
+ /** Decimal rupees in dispute. Structured so the queue can sort by it. */
37
+ disputedAmount?: number;
38
+ }
39
+ /**
40
+ * File a grievance.
41
+ *
42
+ * 🛑 The acknowledgement is stamped at intake, SYNCHRONOUSLY, and that is the
43
+ * one thing here that must not be best-effort. An acknowledgement timestamp is
44
+ * the evidence that we received the complaint on the day we say we did; writing
45
+ * it fire-and-forget would mean the clock's start could silently fail to
46
+ * record, and a clock whose start is unknown cannot be shown to have been met.
47
+ *
48
+ * The `paymentCases` row IS best-effort, because it is a convenience surface —
49
+ * losing it costs visibility, not evidence.
50
+ */
51
+ export declare function fileGrievanceAction(input: FileGrievanceInput): Promise<ActionResult<{
52
+ ticketId: string;
53
+ dueAt: string;
54
+ }>>;
55
+ /**
56
+ * Stamp the first human response.
57
+ *
58
+ * 🛑 Separate from the ticket's ordinary reply path on purpose: it is
59
+ * write-once (`!existing.firstResponseAt`), so a second reply cannot move the
60
+ * metric forward and make a slow first response look fast. The same
61
+ * write-once discipline `resolvedAt` already uses.
62
+ */
63
+ export declare function recordGrievanceFirstResponseAction(ticketId: string): Promise<ActionResult<void>>;