@mohasinac/appkit 4.62.0 → 4.63.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (391) hide show
  1. package/dist/.build-stamp.json +3 -3
  2. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +8 -29
  3. package/dist/_internal/client/features/layout/filterNavItems.d.ts +28 -0
  4. package/dist/_internal/client/features/layout/filterNavItems.js +35 -0
  5. package/dist/_internal/server/features/ads/booking.d.ts +118 -0
  6. package/dist/_internal/server/features/ads/booking.js +326 -0
  7. package/dist/_internal/server/features/checkout/actions.d.ts +129 -9
  8. package/dist/_internal/server/features/checkout/actions.js +850 -79
  9. package/dist/_internal/server/features/checkout/expand-order-items.d.ts +1 -2
  10. package/dist/_internal/server/features/checkout/expand-order-items.js +32 -0
  11. package/dist/_internal/server/features/checkout/freeze-parts.d.ts +50 -0
  12. package/dist/_internal/server/features/checkout/freeze-parts.js +94 -0
  13. package/dist/_internal/server/features/checkout/value-otp-gate.d.ts +55 -0
  14. package/dist/_internal/server/features/checkout/value-otp-gate.js +60 -0
  15. package/dist/_internal/server/features/dashboard/attention.d.ts +128 -0
  16. package/dist/_internal/server/features/dashboard/attention.js +183 -0
  17. package/dist/_internal/server/features/dashboard/data.d.ts +47 -0
  18. package/dist/_internal/server/features/dashboard/data.js +82 -0
  19. package/dist/_internal/server/features/inventory/reservations.d.ts +99 -0
  20. package/dist/_internal/server/features/inventory/reservations.js +273 -0
  21. package/dist/_internal/server/features/invoicing/allocate.d.ts +63 -0
  22. package/dist/_internal/server/features/invoicing/allocate.js +162 -0
  23. package/dist/_internal/server/features/invoicing/credit-note.d.ts +57 -0
  24. package/dist/_internal/server/features/invoicing/credit-note.js +126 -0
  25. package/dist/_internal/server/features/invoicing/gstr1.d.ts +74 -0
  26. package/dist/_internal/server/features/invoicing/gstr1.js +251 -0
  27. package/dist/_internal/server/features/invoicing/issue.d.ts +96 -0
  28. package/dist/_internal/server/features/invoicing/issue.js +202 -0
  29. package/dist/_internal/server/features/offers/destinations.d.ts +40 -0
  30. package/dist/_internal/server/features/offers/destinations.js +65 -0
  31. package/dist/_internal/server/features/orders/actions.d.ts +8 -1
  32. package/dist/_internal/server/features/orders/actions.js +81 -8
  33. package/dist/_internal/server/features/orders/adapters.js +54 -0
  34. package/dist/_internal/server/features/orders/amend-delivery.d.ts +56 -0
  35. package/dist/_internal/server/features/orders/amend-delivery.js +124 -0
  36. package/dist/_internal/server/features/orders/balance.d.ts +89 -0
  37. package/dist/_internal/server/features/orders/balance.js +256 -0
  38. package/dist/_internal/server/features/orders/cancellation-refund.d.ts +15 -9
  39. package/dist/_internal/server/features/orders/cancellation-refund.js +15 -9
  40. package/dist/_internal/server/features/points/award.js +46 -4
  41. package/dist/_internal/server/features/pricing/actions.d.ts +58 -0
  42. package/dist/_internal/server/features/pricing/actions.js +144 -0
  43. package/dist/_internal/server/features/refunds/actions.js +26 -0
  44. package/dist/_internal/server/features/shipping/book-split.d.ts +86 -0
  45. package/dist/_internal/server/features/shipping/book-split.js +130 -0
  46. package/dist/_internal/server/features/shipping/book.d.ts +61 -0
  47. package/dist/_internal/server/features/shipping/book.js +176 -0
  48. package/dist/_internal/server/features/shipping/courier-block.d.ts +69 -0
  49. package/dist/_internal/server/features/shipping/courier-block.js +264 -0
  50. package/dist/_internal/server/features/site-settings/adapters.d.ts +2 -2
  51. package/dist/_internal/server/features/site-settings/adapters.js +29 -0
  52. package/dist/_internal/server/features/stores/adapters.d.ts +2 -2
  53. package/dist/_internal/server/features/stores/adapters.js +65 -0
  54. package/dist/_internal/server/functions/scheduled.d.ts +2 -1
  55. package/dist/_internal/server/functions/scheduled.js +95 -2
  56. package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +11 -2
  57. package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +4 -0
  58. package/dist/_internal/server/jobs/core/dailyStatusDigest.js +19 -2
  59. package/dist/_internal/server/jobs/core/index.d.ts +2 -1
  60. package/dist/_internal/server/jobs/core/index.js +2 -1
  61. package/dist/_internal/server/jobs/core/jobRunners.js +45 -0
  62. package/dist/_internal/server/jobs/core/onJobCreated.d.ts +30 -7
  63. package/dist/_internal/server/jobs/core/onJobCreated.js +78 -45
  64. package/dist/_internal/server/jobs/core/onOrderStatusChange.d.ts +7 -0
  65. package/dist/_internal/server/jobs/core/onOrderStatusChange.js +65 -0
  66. package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +33 -0
  67. package/dist/_internal/server/jobs/core/reservationExpiry.d.ts +17 -0
  68. package/dist/_internal/server/jobs/core/reservationExpiry.js +40 -0
  69. package/dist/_internal/server/jobs/core/runJobOnce.d.ts +48 -0
  70. package/dist/_internal/server/jobs/core/runJobOnce.js +195 -0
  71. package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +25 -2
  72. package/dist/_internal/server/jobs/handlers/index.d.ts +1 -0
  73. package/dist/_internal/server/jobs/handlers/index.js +1 -0
  74. package/dist/_internal/server/jobs/handlers/onOrderStatusChange.js +17 -0
  75. package/dist/_internal/server/jobs/handlers/reservationExpiry.d.ts +2 -0
  76. package/dist/_internal/server/jobs/handlers/reservationExpiry.js +2 -0
  77. package/dist/_internal/server/notifications/channel-health.d.ts +26 -3
  78. package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
  79. package/dist/_internal/shared/actions/action-registry.js +296 -0
  80. package/dist/_internal/shared/checkout/coupon-discount.d.ts +43 -1
  81. package/dist/_internal/shared/checkout/coupon-discount.js +26 -1
  82. package/dist/_internal/shared/checkout/order-math.d.ts +174 -0
  83. package/dist/_internal/shared/checkout/order-math.js +159 -0
  84. package/dist/_internal/shared/checkout/refundable-base.d.ts +25 -0
  85. package/dist/_internal/shared/checkout/refundable-base.js +13 -1
  86. package/dist/_internal/shared/checkout/rules/index.d.ts +1 -1
  87. package/dist/_internal/shared/checkout/rules/index.js +1 -1
  88. package/dist/_internal/shared/checkout/rules/payment-gate.d.ts +18 -0
  89. package/dist/_internal/shared/checkout/rules/payment-gate.js +25 -0
  90. package/dist/_internal/shared/checkout/split.d.ts +75 -0
  91. package/dist/_internal/shared/checkout/split.js +120 -0
  92. package/dist/_internal/shared/content/disclaimers.d.ts +88 -0
  93. package/dist/_internal/shared/content/disclaimers.js +217 -0
  94. package/dist/_internal/shared/content/published-values.d.ts +93 -0
  95. package/dist/_internal/shared/content/published-values.js +206 -0
  96. package/dist/_internal/shared/features/admin/integrations.d.ts +139 -0
  97. package/dist/_internal/shared/features/admin/integrations.js +263 -0
  98. package/dist/_internal/shared/features/dashboard/hub-sections.d.ts +72 -0
  99. package/dist/_internal/shared/features/dashboard/hub-sections.js +75 -0
  100. package/dist/_internal/shared/features/emi/choice.d.ts +98 -0
  101. package/dist/_internal/shared/features/emi/choice.js +69 -0
  102. package/dist/_internal/shared/features/emi/group.d.ts +84 -0
  103. package/dist/_internal/shared/features/emi/group.js +126 -0
  104. package/dist/_internal/shared/features/ledger/posting.d.ts +107 -0
  105. package/dist/_internal/shared/features/ledger/posting.js +165 -0
  106. package/dist/_internal/shared/features/ledger/reports.d.ts +76 -0
  107. package/dist/_internal/shared/features/ledger/reports.js +127 -0
  108. package/dist/_internal/shared/features/ledger/rules.d.ts +170 -0
  109. package/dist/_internal/shared/features/ledger/rules.js +221 -0
  110. package/dist/_internal/shared/features/offers/coordination.d.ts +122 -0
  111. package/dist/_internal/shared/features/offers/coordination.js +80 -0
  112. package/dist/_internal/shared/features/orders/delivery-snapshot.d.ts +114 -0
  113. package/dist/_internal/shared/features/orders/delivery-snapshot.js +116 -0
  114. package/dist/_internal/shared/features/orders/dispute-reasons.d.ts +113 -0
  115. package/dist/_internal/shared/features/orders/dispute-reasons.js +181 -0
  116. package/dist/_internal/shared/features/orders/refund-copy.d.ts +1 -1
  117. package/dist/_internal/shared/features/orders/refund-copy.js +18 -1
  118. package/dist/_internal/shared/features/payouts/pay-period.d.ts +91 -0
  119. package/dist/_internal/shared/features/payouts/pay-period.js +104 -0
  120. package/dist/_internal/shared/features/points/accepts.d.ts +29 -0
  121. package/dist/_internal/shared/features/points/accepts.js +49 -0
  122. package/dist/_internal/shared/features/pricing/rate-registry.d.ts +150 -0
  123. package/dist/_internal/shared/features/pricing/rate-registry.js +246 -0
  124. package/dist/_internal/shared/features/shipping/parcel.d.ts +123 -0
  125. package/dist/_internal/shared/features/shipping/parcel.js +139 -0
  126. package/dist/_internal/shared/features/shipping/shared-purchase.d.ts +91 -0
  127. package/dist/_internal/shared/features/shipping/shared-purchase.js +108 -0
  128. package/dist/_internal/shared/features/site-settings/fees.d.ts +16 -8
  129. package/dist/_internal/shared/features/site-settings/fees.js +12 -8
  130. package/dist/_internal/shared/features/site-settings/types.d.ts +11 -0
  131. package/dist/_internal/shared/fees/calculator.d.ts +33 -1
  132. package/dist/_internal/shared/fees/calculator.js +32 -2
  133. package/dist/_internal/shared/fees/explain.d.ts +81 -0
  134. package/dist/_internal/shared/fees/explain.js +101 -0
  135. package/dist/_internal/shared/history/index.d.ts +1 -1
  136. package/dist/_internal/shared/history/index.js +1 -1
  137. package/dist/_internal/shared/history/types.d.ts +7 -1
  138. package/dist/_internal/shared/history/types.js +25 -0
  139. package/dist/client.d.ts +21 -0
  140. package/dist/client.js +43 -0
  141. package/dist/constants/api-endpoints.d.ts +114 -0
  142. package/dist/constants/api-endpoints.js +55 -0
  143. package/dist/constants/field-names.d.ts +42 -0
  144. package/dist/constants/field-names.js +52 -0
  145. package/dist/contracts/index.d.ts +1 -1
  146. package/dist/contracts/shipping.d.ts +45 -0
  147. package/dist/contracts/shipping.js +15 -0
  148. package/dist/features/about/components/AboutView.js +1 -1
  149. package/dist/features/account/components/BuyerAuctionsGuideView.js +4 -1
  150. package/dist/features/account/components/UserOrdersView.js +47 -35
  151. package/dist/features/admin/components/AdminCouponEditorView.js +17 -0
  152. package/dist/features/admin/components/AdminIntegrationsView.d.ts +55 -0
  153. package/dist/features/admin/components/AdminIntegrationsView.js +74 -0
  154. package/dist/features/admin/components/AdminInvoicingView.d.ts +2 -0
  155. package/dist/features/admin/components/AdminInvoicingView.js +65 -0
  156. package/dist/features/admin/components/AdminOrderEditorView.d.ts +33 -1
  157. package/dist/features/admin/components/AdminOrderEditorView.js +81 -3
  158. package/dist/features/admin/components/AdminOrdersGuideView.js +23 -2
  159. package/dist/features/admin/components/AdminOrdersView.js +86 -5
  160. package/dist/features/admin/components/OwnerQuickActions.js +24 -2
  161. package/dist/features/admin/constants/filter-tabs.d.ts +6 -0
  162. package/dist/features/admin/constants/filter-tabs.js +6 -0
  163. package/dist/features/admin/constants/site-settings-tabs.d.ts +1 -1
  164. package/dist/features/admin/hooks/useAdminListingData.js +16 -0
  165. package/dist/features/admin/schemas/admin-user-form.d.ts +2 -2
  166. package/dist/features/admin/schemas/firestore.d.ts +62 -0
  167. package/dist/features/admin/schemas/firestore.js +5 -0
  168. package/dist/features/ads/schemas/booking-write.d.ts +120 -0
  169. package/dist/features/ads/schemas/booking-write.js +75 -0
  170. package/dist/features/ads/schemas/creative-form.d.ts +18 -0
  171. package/dist/features/ads/schemas/creative-form.js +51 -0
  172. package/dist/features/ads/schemas/firestore.d.ts +140 -0
  173. package/dist/features/ads/schemas/firestore.js +109 -0
  174. package/dist/features/auctions/repository/bid.repository.js +3 -1
  175. package/dist/features/audit-log/schemas/firestore.d.ts +140 -0
  176. package/dist/features/audit-log/schemas/firestore.js +89 -0
  177. package/dist/features/auth/actions/profile-actions.d.ts +69 -1
  178. package/dist/features/auth/actions/profile-actions.js +62 -1
  179. package/dist/features/auth/permissions/constants.js +13 -0
  180. package/dist/features/auth/schemas/firestore.d.ts +16 -2
  181. package/dist/features/auth/schemas/firestore.js +2 -1
  182. package/dist/features/blog/actions/blog-actions.d.ts +6 -0
  183. package/dist/features/blog/actions/blog-actions.js +17 -2
  184. package/dist/features/blog/api/route.js +4 -1
  185. package/dist/features/blog/columns/index.js +5 -0
  186. package/dist/features/blog/components/BlogIndexPageView.js +2 -1
  187. package/dist/features/blog/repository/blog.repository.d.ts +4 -0
  188. package/dist/features/blog/repository/blog.repository.js +5 -0
  189. package/dist/features/blog/schemas/blog-form.d.ts +3 -0
  190. package/dist/features/blog/schemas/blog-form.js +1 -0
  191. package/dist/features/blog/schemas/firestore.d.ts +38 -1
  192. package/dist/features/blog/schemas/firestore.js +23 -0
  193. package/dist/features/blog/schemas/index.d.ts +6 -0
  194. package/dist/features/blog/schemas/index.js +2 -0
  195. package/dist/features/blog/types/index.d.ts +2 -0
  196. package/dist/features/cart/components/CartPriceBreakdown.d.ts +25 -1
  197. package/dist/features/cart/components/CartPriceBreakdown.js +29 -6
  198. package/dist/features/cart/components/PointsTenderPicker.d.ts +61 -0
  199. package/dist/features/cart/components/PointsTenderPicker.js +15 -0
  200. package/dist/features/cart/components/StoreAddonsPicker.js +2 -1
  201. package/dist/features/cart/components/index.d.ts +2 -0
  202. package/dist/features/cart/components/index.js +1 -0
  203. package/dist/features/cart/repository/cart.repository.d.ts +33 -0
  204. package/dist/features/cart/repository/cart.repository.js +47 -0
  205. package/dist/features/cart/schemas/firestore.d.ts +116 -0
  206. package/dist/features/contact/email.d.ts +27 -10
  207. package/dist/features/contact/email.js +20 -3
  208. package/dist/features/dashboard/components/DashboardHubView.d.ts +83 -0
  209. package/dist/features/dashboard/components/DashboardHubView.js +56 -0
  210. package/dist/features/dashboard/components/DashboardSectionsClient.d.ts +23 -0
  211. package/dist/features/dashboard/components/DashboardSectionsClient.js +66 -0
  212. package/dist/features/dispute-reasons/components/AdminDisputeReasonsView.d.ts +55 -0
  213. package/dist/features/dispute-reasons/components/AdminDisputeReasonsView.js +175 -0
  214. package/dist/features/dispute-reasons/repository/dispute-reasons.repository.d.ts +62 -0
  215. package/dist/features/dispute-reasons/repository/dispute-reasons.repository.js +108 -0
  216. package/dist/features/dispute-reasons/schemas/firestore.d.ts +62 -0
  217. package/dist/features/dispute-reasons/schemas/firestore.js +40 -0
  218. package/dist/features/events/components/EventSaleBanner.js +1 -1
  219. package/dist/features/faq/components/FAQAccordion.d.ts +13 -1
  220. package/dist/features/faq/components/FAQAccordion.js +29 -4
  221. package/dist/features/faq/components/FAQPageContent.js +2 -2
  222. package/dist/features/gateway-events/schemas/index.d.ts +2 -2
  223. package/dist/features/homepage/schemas/index.d.ts +8 -8
  224. package/dist/features/inventory/schemas/stock-reservation.d.ts +114 -0
  225. package/dist/features/inventory/schemas/stock-reservation.js +103 -0
  226. package/dist/features/invoicing/schemas/firestore.d.ts +112 -0
  227. package/dist/features/invoicing/schemas/firestore.js +45 -0
  228. package/dist/features/invoicing/utils/financial-year.d.ts +43 -0
  229. package/dist/features/invoicing/utils/financial-year.js +53 -0
  230. package/dist/features/jobs/actions/enqueue-job.js +18 -1
  231. package/dist/features/jobs/repository/jobs.repository.d.ts +62 -1
  232. package/dist/features/jobs/repository/jobs.repository.js +84 -1
  233. package/dist/features/jobs/schemas/firestore.d.ts +80 -0
  234. package/dist/features/jobs/schemas/firestore.js +37 -0
  235. package/dist/features/layout/AppLayoutShell.d.ts +9 -1
  236. package/dist/features/layout/AppLayoutShell.js +12 -4
  237. package/dist/features/layout/BottomActions.js +2 -1
  238. package/dist/features/layout/BottomNavbar.d.ts +10 -2
  239. package/dist/features/layout/SideActionDock.js +52 -2
  240. package/dist/features/layout/TitleBarLayout.js +13 -4
  241. package/dist/features/layout/TitleBarLayout.style.css +59 -0
  242. package/dist/features/layout/useCtaReveal.d.ts +16 -1
  243. package/dist/features/layout/useCtaReveal.js +17 -26
  244. package/dist/features/ledger/repository/journal.repository.d.ts +110 -0
  245. package/dist/features/ledger/repository/journal.repository.js +312 -0
  246. package/dist/features/ledger/schemas/expenses.d.ts +87 -0
  247. package/dist/features/ledger/schemas/expenses.js +27 -0
  248. package/dist/features/ledger/schemas/firestore.d.ts +183 -0
  249. package/dist/features/ledger/schemas/firestore.js +69 -0
  250. package/dist/features/lottery/schemas/zod.d.ts +6 -6
  251. package/dist/features/media/MediaImage.js +22 -1
  252. package/dist/features/media/upload/ImageUpload.js +1 -1
  253. package/dist/features/obligations/constants/policies.js +24 -1
  254. package/dist/features/orders/components/BalancePaymentPanel.d.ts +12 -0
  255. package/dist/features/orders/components/BalancePaymentPanel.js +94 -0
  256. package/dist/features/orders/components/OrderPaymentSummary.js +10 -1
  257. package/dist/features/orders/components/OrderProvenanceCard.d.ts +8 -0
  258. package/dist/features/orders/components/OrderProvenanceCard.js +185 -0
  259. package/dist/features/orders/components/RaiseDisputeForm.d.ts +14 -0
  260. package/dist/features/orders/components/RaiseDisputeForm.js +119 -0
  261. package/dist/features/orders/components/RefundRequestView.js +19 -1
  262. package/dist/features/orders/components/index.d.ts +4 -0
  263. package/dist/features/orders/components/index.js +2 -0
  264. package/dist/features/orders/constants/order-lane-tabs.d.ts +69 -0
  265. package/dist/features/orders/constants/order-lane-tabs.js +88 -0
  266. package/dist/features/orders/repository/orders.repository.d.ts +85 -1
  267. package/dist/features/orders/repository/orders.repository.js +205 -6
  268. package/dist/features/orders/schemas/balance.d.ts +40 -0
  269. package/dist/features/orders/schemas/balance.js +47 -0
  270. package/dist/features/orders/schemas/firestore.d.ts +398 -1
  271. package/dist/features/orders/schemas/firestore.js +43 -0
  272. package/dist/features/orders/schemas/index.d.ts +56 -8
  273. package/dist/features/orders/schemas/index.js +12 -0
  274. package/dist/features/orders/types/index.d.ts +47 -0
  275. package/dist/features/orders/utils/courier-block.d.ts +25 -0
  276. package/dist/features/orders/utils/courier-block.js +23 -0
  277. package/dist/features/payment-cases/schemas/firestore.d.ts +26 -1
  278. package/dist/features/payment-cases/schemas/firestore.js +1 -0
  279. package/dist/features/payments/repository/payout.repository.js +3 -2
  280. package/dist/features/payments/schemas/firestore.d.ts +92 -1
  281. package/dist/features/payments/schemas/firestore.js +23 -0
  282. package/dist/features/pricing/components/AdminPricingView.d.ts +13 -0
  283. package/dist/features/pricing/components/AdminPricingView.js +157 -0
  284. package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -2
  285. package/dist/features/products/components/ProductDetailPageView.d.ts +17 -1
  286. package/dist/features/products/components/ProductDetailPageView.js +2 -2
  287. package/dist/features/products/schemas/firestore.d.ts +26 -1
  288. package/dist/features/products/schemas/firestore.js +2 -0
  289. package/dist/features/products/schemas/index.d.ts +2 -2
  290. package/dist/features/products/schemas/product-features.validators.d.ts +10 -10
  291. package/dist/features/promotions/actions/coupon-stacking.d.ts +30 -3
  292. package/dist/features/promotions/actions/coupon-stacking.js +21 -2
  293. package/dist/features/promotions/components/CouponCard.js +13 -0
  294. package/dist/features/promotions/constants/coupon-help.d.ts +2 -2
  295. package/dist/features/promotions/constants/coupon-help.js +9 -1
  296. package/dist/features/promotions/schemas/firestore.d.ts +24 -0
  297. package/dist/features/promotions/schemas/firestore.js +4 -0
  298. package/dist/features/promotions/types/index.d.ts +19 -1
  299. package/dist/features/reviews/repository/reviews.repository.d.ts +14 -0
  300. package/dist/features/reviews/repository/reviews.repository.js +16 -0
  301. package/dist/features/scams/components/ScamProfileView.js +2 -2
  302. package/dist/features/scams/components/ScamRegistryView.js +2 -2
  303. package/dist/features/scams/repository/scammer.repository.js +2 -1
  304. package/dist/features/scams/schemas/firestore.d.ts +2 -1
  305. package/dist/features/scams/schemas/firestore.js +2 -1
  306. package/dist/features/search/action-index/tab-entries.js +1 -1
  307. package/dist/features/seller/actions/offer-actions.js +56 -0
  308. package/dist/features/seller/actions/seller-actions.d.ts +1 -1
  309. package/dist/features/seller/actions/seller-actions.js +37 -3
  310. package/dist/features/seller/components/DispatchForm.d.ts +11 -0
  311. package/dist/features/seller/components/DispatchForm.js +190 -0
  312. package/dist/features/seller/components/SellerOrdersView.js +221 -27
  313. package/dist/features/seller/components/index.d.ts +1 -0
  314. package/dist/features/seller/components/index.js +1 -0
  315. package/dist/features/seller/hooks/useSellerListingData.js +25 -0
  316. package/dist/features/seller/repository/offer.repository.js +4 -3
  317. package/dist/features/seller/schemas/firestore.d.ts +23 -2
  318. package/dist/features/seller/schemas/firestore.js +3 -2
  319. package/dist/features/seller/schemas/index.d.ts +4 -4
  320. package/dist/features/seller/schemas/order-forms.d.ts +61 -4
  321. package/dist/features/seller/schemas/order-forms.js +41 -8
  322. package/dist/features/shipments/schemas/firestore.d.ts +25 -0
  323. package/dist/features/shipments/schemas/validation.d.ts +4 -4
  324. package/dist/features/shipping-boxes/repository/shipping-boxes.repository.d.ts +82 -0
  325. package/dist/features/shipping-boxes/repository/shipping-boxes.repository.js +145 -0
  326. package/dist/features/shipping-boxes/schemas/firestore.d.ts +80 -0
  327. package/dist/features/shipping-boxes/schemas/firestore.js +53 -0
  328. package/dist/features/store-extensions/schemas/report-create-form.d.ts +2 -2
  329. package/dist/features/store-extensions/schemas/shipping-config-form.d.ts +2 -2
  330. package/dist/features/stores/components/StoreOrdersGuideView.js +6 -1
  331. package/dist/features/stores/repository/store.repository.d.ts +18 -0
  332. package/dist/features/stores/repository/store.repository.js +27 -1
  333. package/dist/features/stores/schemas/firestore.d.ts +112 -0
  334. package/dist/features/stores/schemas/firestore.js +20 -0
  335. package/dist/features/stores/schemas/index.d.ts +6 -6
  336. package/dist/features/stores/types/index.d.ts +19 -0
  337. package/dist/features/support/repository/support.repository.js +72 -6
  338. package/dist/features/support/schemas/firestore.d.ts +17 -0
  339. package/dist/features/support/schemas/index.d.ts +8 -8
  340. package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +1 -1
  341. package/dist/index.d.ts +11 -1
  342. package/dist/index.js +33 -1
  343. package/dist/next/routing/route-map.d.ts +112 -0
  344. package/dist/next/routing/route-map.js +63 -0
  345. package/dist/providers/shipping-shiprocket/index.d.ts +27 -1
  346. package/dist/providers/shipping-shiprocket/index.js +84 -1
  347. package/dist/react/contexts/SessionContext.d.ts +17 -1
  348. package/dist/schemas/registry.d.ts +69 -34
  349. package/dist/schemas/sieve.d.ts +2 -2
  350. package/dist/security/pii-schemas.d.ts +1 -1
  351. package/dist/security/pii-schemas.js +45 -0
  352. package/dist/server-entry.d.ts +2 -2
  353. package/dist/server-entry.js +8 -1
  354. package/dist/server.d.ts +36 -1
  355. package/dist/server.js +183 -1
  356. package/dist/styles.css +412 -80
  357. package/dist/tailwind-utilities.css +1 -1
  358. package/dist/tokens/themes/default-dark.js +1 -0
  359. package/dist/tokens/themes/default-light.js +1 -0
  360. package/dist/tokens/themes/required.d.ts +1 -1
  361. package/dist/tokens/themes/required.js +1 -0
  362. package/dist/tokens/tokens.css +15 -0
  363. package/dist/ui/components/Button.d.ts +10 -1
  364. package/dist/ui/components/Button.js +25 -3
  365. package/dist/ui/components/Chart.d.ts +63 -0
  366. package/dist/ui/components/Chart.js +169 -0
  367. package/dist/ui/components/Chart.style.css +214 -0
  368. package/dist/ui/components/Disclaimer.d.ts +19 -0
  369. package/dist/ui/components/Disclaimer.js +83 -0
  370. package/dist/ui/components/OverflowRow.js +54 -2
  371. package/dist/ui/components/OverflowRow.style.css +38 -0
  372. package/dist/ui/components/RichTextEditor.js +99 -8
  373. package/dist/ui/components/chart-spec.d.ts +68 -0
  374. package/dist/ui/components/chart-spec.js +140 -0
  375. package/dist/ui/components/index.style.css +1 -0
  376. package/dist/ui/components/surface-tokens.d.ts +1 -1
  377. package/dist/ui/components/surface-tokens.js +9 -0
  378. package/dist/ui/components/tabs-overflow.js +64 -11
  379. package/dist/ui/components/toolbar-collapse.d.ts +13 -0
  380. package/dist/ui/components/toolbar-collapse.js +10 -1
  381. package/dist/ui/index.d.ts +8 -0
  382. package/dist/ui/index.js +9 -0
  383. package/dist/ui/rich-text/RichText.d.ts +10 -1
  384. package/dist/ui/rich-text/RichText.js +33 -2
  385. package/dist/ui/rich-text/RichText.style.css +83 -79
  386. package/dist/ui/rich-text/RichTextRenderer.d.ts +30 -1
  387. package/dist/ui/rich-text/RichTextRenderer.js +34 -2
  388. package/dist/ui/rich-text/chart-blocks.d.ts +62 -0
  389. package/dist/ui/rich-text/chart-blocks.js +87 -0
  390. package/package.json +1 -1
  391. package/scripts/seed-cli.mjs +1834 -1822
@@ -1,5 +1,10 @@
1
+ import { normalizeError } from "../../../../errors/normalize.js";
1
2
  import { decryptPii } from "../../../../security/index.js";
2
3
  import { sendNotification } from "../../../../features/admin/actions/notification-actions.js";
4
+ import { orderRepository } from "../../../../features/orders/repository/orders.repository.js";
5
+ /* Phase 7 — numbering only; the PDF renderer lives in `functions/` because
6
+ * `pdfkit` must not enter appkit's module graph. */
7
+ import { allocateSeriesNumber } from "../../features/invoicing/allocate.js";
3
8
  import { ORDER_MESSAGES } from "../handlers/messages.js";
4
9
  const STATUS_CONFIG = {
5
10
  confirmed: {
@@ -31,6 +36,66 @@ export async function handleOrderStatusChange(input, ctx) {
31
36
  const { orderId, before, after } = input;
32
37
  if (!before || !after)
33
38
  return;
39
+ /*
40
+ * ── PHASE 7: number the invoice on the PAYMENT transition ─────────────────
41
+ *
42
+ * 🛑 PLACED FIRST, before the `status`-unchanged early return. That return
43
+ * is correct for the notification work below it, and it is also why this
44
+ * cannot go after it: `paymentStatus: pending → paid` frequently happens
45
+ * with NO change to `status` at all (a COD order verified by an admin, a
46
+ * manual proof approved), so appending this below would have numbered only
47
+ * the minority of paid orders whose status happened to move in the same
48
+ * write. That is Root Cause #27's sweep-coverage trap, and R1 in
49
+ * `paymentWindowTimeout` had to be placed the same way for the same reason.
50
+ *
51
+ * 🛑 Extending THIS trigger rather than adding a second one on `orders`.
52
+ * A second Firestore trigger on the same collection wakes for every write
53
+ * and returns — which is how `onShipmentDeleted` burned a million
54
+ * invocations a day sitting correctly-guarded beside a neighbour's loop
55
+ * (Root Cause #92). The sticker-trace definitions carry the same 🛑.
56
+ *
57
+ * 🛑 And it is numbering ONLY — no PDF. `pdfkit` is a Functions dependency
58
+ * and must not enter appkit's module graph; the bytes are rendered once,
59
+ * lazily, by the serve route and stored from there. Numbering is the half
60
+ * that must be immediate and transactional, because it is the half that
61
+ * cannot be corrected: a number cannot be withdrawn without leaving a gap.
62
+ */
63
+ const becamePaid = before.paymentStatus !== "paid" && after.paymentStatus === "paid";
64
+ if (becamePaid && !after.invoiceNumber) {
65
+ try {
66
+ const allocation = await allocateSeriesNumber({
67
+ kind: "invoice",
68
+ subjectId: orderId,
69
+ orderId,
70
+ });
71
+ /*
72
+ * Only writes when THIS call allocated. A re-entry that found an
73
+ * existing claim skips the write entirely, which keeps a re-fired
74
+ * trigger from touching the order at all — the write that would
75
+ * otherwise re-fire this very trigger.
76
+ */
77
+ if (allocation.allocated) {
78
+ await orderRepository.update(orderId, {
79
+ invoiceNumber: allocation.number,
80
+ invoiceIssuedAt: new Date(),
81
+ });
82
+ ctx.logger.info(`Invoice ${allocation.number} allocated`, { orderId });
83
+ }
84
+ }
85
+ catch (error) {
86
+ /*
87
+ * Logged and swallowed, so a numbering failure cannot suppress the
88
+ * buyer's order notification below. The order stays un-invoiced, which
89
+ * is a visible, retryable state — the next write that touches
90
+ * `paymentStatus` re-attempts, and the serve route can allocate on
91
+ * demand. Throwing here would also make the Firestore trigger retry the
92
+ * whole handler, re-sending the notification.
93
+ */
94
+ ctx.logger.error("Invoice allocation failed", normalizeError(error), {
95
+ orderId,
96
+ });
97
+ }
98
+ }
34
99
  if (before.status === after.status)
35
100
  return;
36
101
  const newStatus = after.status;
@@ -6,6 +6,9 @@ import { OrderStatusValues } from "../../../../features/orders/schemas/firestore
6
6
  import { PAYMENT_WINDOW_EXPIRED_REASON } from "../../../../features/orders/constants/payment-window.js";
7
7
  import { ORDER_MESSAGES } from "../handlers/messages.js";
8
8
  import { reconcileStuckGatewayEvents } from "./paymentReconcile.js";
9
+ /* Phase 8 — the job retry sweep. Folded in here rather than given its own
10
+ * Scheduler job; see its own docstring and the 🛑 at the call site. */
11
+ import { runDueJobRetries } from "./onJobCreated.js";
9
12
  /**
10
13
  * 15-minute payment window sweep — cancels + restocks any `upi_manual`/
11
14
  * `cash`/`emi` order still `pending`/`pending` with no proof uploaded past
@@ -53,6 +56,36 @@ export async function runPaymentWindowTimeout(ctx) {
53
56
  err,
54
57
  });
55
58
  }
59
+ /*
60
+ * ── Phase 8 rides along too: job retries whose backoff has elapsed ────────
61
+ *
62
+ * Same two reasons as R1 above, and the same placement rule: **FIRST, before
63
+ * the early return**. A retry is a `pending` job document with a future
64
+ * `nextAttemptAt`, and nothing else in the system will ever run it — the
65
+ * create trigger deliberately defers to this sweep, because creating the
66
+ * retry document fires that trigger instantly and would collapse the backoff
67
+ * to zero.
68
+ *
69
+ * So if this call sat after the early return, a retry would run only on a
70
+ * tick that happened to have an expired payment window — which is the
71
+ * minority — and a job scheduled on a quiet afternoon could wait hours.
72
+ * Root Cause #27 again, now with a second mechanism depending on it.
73
+ *
74
+ * Never throws, for the same reason R1 does not: a stuck job must not stop
75
+ * the payment-window cancellations this function exists for.
76
+ */
77
+ try {
78
+ const retries = await runDueJobRetries(ctx);
79
+ if (retries.ran > 0) {
80
+ ctx.logger.info("Phase 8: ran due job retries", { ...retries });
81
+ }
82
+ }
83
+ catch (err) {
84
+ void normalizeError(err);
85
+ ctx.logger.error("job retry sweep failed inside paymentWindowTimeout — continuing", {
86
+ err,
87
+ });
88
+ }
56
89
  ctx.logger.info("Scanning orders past their 15-minute payment deadline");
57
90
  const expired = await orderRepository.getExpiredPaymentDeadlines();
58
91
  if (expired.length === 0) {
@@ -0,0 +1,17 @@
1
+ import type { JobContext } from "../runtime/types";
2
+ /**
3
+ * Return expired stock holds to the shelf.
4
+ *
5
+ * 🛑 This sweep is the ONLY thing that bounds a leaked hold. Everything else
6
+ * that ends a reservation is an action somebody takes — a release, a
7
+ * consume — and the entire reason `expiresAt` exists is that nobody takes
8
+ * those when they close the tab. Without this job a hold is permanent, and a
9
+ * permanent hold is indistinguishable from stock the seller no longer has.
10
+ *
11
+ * 🛑 Runs every 15 minutes, which is the real resolution of a TTL. The
12
+ * default hold is 72 hours, so the cadence does not need to be tight — but a
13
+ * daily sweep would make the worst case "expires at 09:01, returns tomorrow",
14
+ * and a buyer told an item is sold out for 24 hours after it stopped being
15
+ * held is the failure this exists to prevent.
16
+ */
17
+ export declare function runReservationExpiry(ctx: JobContext): Promise<void>;
@@ -0,0 +1,40 @@
1
+ import { expireDueReservations } from "../../features/inventory/reservations.js";
2
+ import { normalizeError } from "../../../../errors/normalize.js";
3
+ /**
4
+ * Return expired stock holds to the shelf.
5
+ *
6
+ * 🛑 This sweep is the ONLY thing that bounds a leaked hold. Everything else
7
+ * that ends a reservation is an action somebody takes — a release, a
8
+ * consume — and the entire reason `expiresAt` exists is that nobody takes
9
+ * those when they close the tab. Without this job a hold is permanent, and a
10
+ * permanent hold is indistinguishable from stock the seller no longer has.
11
+ *
12
+ * 🛑 Runs every 15 minutes, which is the real resolution of a TTL. The
13
+ * default hold is 72 hours, so the cadence does not need to be tight — but a
14
+ * daily sweep would make the worst case "expires at 09:01, returns tomorrow",
15
+ * and a buyer told an item is sold out for 24 hours after it stopped being
16
+ * held is the failure this exists to prevent.
17
+ */
18
+ export async function runReservationExpiry(ctx) {
19
+ ctx.logger.info("Starting stock-reservation expiry sweep");
20
+ let result;
21
+ try {
22
+ result = await expireDueReservations();
23
+ }
24
+ catch (err) {
25
+ const normalized = normalizeError(err);
26
+ ctx.logger.error("Reservation expiry sweep failed", { message: normalized.message });
27
+ throw err;
28
+ }
29
+ /*
30
+ * `truncated` is logged rather than swallowed, and is the signal that the
31
+ * bound was reached: a run that hits its cap left real holds in place, and
32
+ * reading "expired 200" as "all done" is the same mistake a truncated
33
+ * recount invites (Root Cause #102).
34
+ */
35
+ ctx.logger.info("Reservation expiry sweep complete", {
36
+ scanned: result.scanned,
37
+ expired: result.expired,
38
+ truncated: result.truncated,
39
+ });
40
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Run ONE attempt of a job, and decide what happens next (Phase 8).
3
+ *
4
+ * ## 🛑 ONE dispatch path, shared by the trigger and the retry sweep
5
+ *
6
+ * `handleJobCreated` is the `jobs/{jobId}` create trigger; `runDueJobRetries`
7
+ * is the sweep that picks up scheduled retries. Both call THIS, so there is
8
+ * exactly one place that knows how to run a job, classify its failure and
9
+ * schedule the next attempt. Two dispatch paths would drift the first time one
10
+ * of them learned something — which is the shape of every defect in this
11
+ * plan's § "Recurrent Root Cause Patterns" that begins "a fix applied to the
12
+ * route but never back-ported".
13
+ *
14
+ * ## 🛑 A retry is a NEW DOCUMENT
15
+ *
16
+ * `onJobCreated` fires on CREATE. Re-running a job by flipping its status back
17
+ * to `pending` would never wake the trigger, so the job would sit `pending`
18
+ * forever looking scheduled — a stall that reads as "queued". So a retry is a
19
+ * fresh `jobs` document carrying `attempt + 1`, `parentJobId` and a
20
+ * `nextAttemptAt`, and the sweep is what runs it when due.
21
+ *
22
+ * ## What is retryable
23
+ *
24
+ * `mapToHttpError(err).status >= 500`. Reused rather than invented: that
25
+ * function already encodes "is this our fault or the caller's" for every error
26
+ * class in the codebase, and a second classification would answer differently
27
+ * the first time either changed.
28
+ *
29
+ * A 4xx is terminal IMMEDIATELY — no backoff, no attempts burned. A validation
30
+ * failure does not become valid by waiting, and retrying it three times over
31
+ * 35 minutes just delays the case by 35 minutes.
32
+ */
33
+ import { type JobDocument } from "../../../../features/jobs/schemas/firestore";
34
+ import type { JobContext } from "../runtime/types";
35
+ export interface RunJobOnceInput {
36
+ jobId: string;
37
+ job: JobDocument;
38
+ }
39
+ /**
40
+ * Run one attempt. Marks the job done, schedules a retry, or declares it dead.
41
+ *
42
+ * Never throws: a job's failure is recorded on the job, and letting it escape
43
+ * would make the Firebase trigger retry the whole handler — a second,
44
+ * uncontrolled retry mechanism layered under this one, which is precisely the
45
+ * doubling that cost 55 sessions in Root Cause #91 (`run.mjs`'s internal retry
46
+ * multiplying the pool's).
47
+ */
48
+ export declare function runJobOnce(input: RunJobOnceInput, ctx: JobContext): Promise<void>;
@@ -0,0 +1,195 @@
1
+ /**
2
+ * Run ONE attempt of a job, and decide what happens next (Phase 8).
3
+ *
4
+ * ## 🛑 ONE dispatch path, shared by the trigger and the retry sweep
5
+ *
6
+ * `handleJobCreated` is the `jobs/{jobId}` create trigger; `runDueJobRetries`
7
+ * is the sweep that picks up scheduled retries. Both call THIS, so there is
8
+ * exactly one place that knows how to run a job, classify its failure and
9
+ * schedule the next attempt. Two dispatch paths would drift the first time one
10
+ * of them learned something — which is the shape of every defect in this
11
+ * plan's § "Recurrent Root Cause Patterns" that begins "a fix applied to the
12
+ * route but never back-ported".
13
+ *
14
+ * ## 🛑 A retry is a NEW DOCUMENT
15
+ *
16
+ * `onJobCreated` fires on CREATE. Re-running a job by flipping its status back
17
+ * to `pending` would never wake the trigger, so the job would sit `pending`
18
+ * forever looking scheduled — a stall that reads as "queued". So a retry is a
19
+ * fresh `jobs` document carrying `attempt + 1`, `parentJobId` and a
20
+ * `nextAttemptAt`, and the sweep is what runs it when due.
21
+ *
22
+ * ## What is retryable
23
+ *
24
+ * `mapToHttpError(err).status >= 500`. Reused rather than invented: that
25
+ * function already encodes "is this our fault or the caller's" for every error
26
+ * class in the codebase, and a second classification would answer differently
27
+ * the first time either changed.
28
+ *
29
+ * A 4xx is terminal IMMEDIATELY — no backoff, no attempts burned. A validation
30
+ * failure does not become valid by waiting, and retrying it three times over
31
+ * 35 minutes just delays the case by 35 minutes.
32
+ */
33
+ import { normalizeError } from "../../../../errors/normalize.js";
34
+ import { mapToHttpError } from "../../../../errors/error-mapping.js";
35
+ import { jobsRepository } from "../../../../repositories/index.js";
36
+ import { paymentCasesRepository } from "../../../../features/payment-cases/repository/payment-cases.repository.js";
37
+ import { getAdminRealtimeDb } from "../../../../providers/db-firebase/index.js";
38
+ import { RTDB_PATHS } from "../../../../providers/db-firebase/rtdb-paths.js";
39
+ import { JOB_BACKOFF_MS, JOB_MAX_ATTEMPTS, } from "../../../../features/jobs/schemas/firestore.js";
40
+ import { JOB_RUNNERS } from "./jobRunners.js";
41
+ async function pingBulkEvent(jobId, payload, ctx) {
42
+ try {
43
+ await getAdminRealtimeDb()
44
+ .ref(`${RTDB_PATHS.BULK_EVENTS}/${jobId}`)
45
+ .set({ ...payload, updatedAt: Date.now() });
46
+ }
47
+ catch (err) {
48
+ void normalizeError(err);
49
+ ctx.logger.warn("runJobOnce: RTDB ping failed (non-fatal)", {
50
+ jobId,
51
+ error: err instanceof Error ? err.message : String(err),
52
+ });
53
+ }
54
+ }
55
+ /**
56
+ * The delay before the next attempt.
57
+ *
58
+ * 🛑 Clamped to the LAST element rather than indexing past the end. An
59
+ * out-of-range index yields `undefined`, `new Date(Date.now() + undefined)` is
60
+ * `Invalid Date`, and the sweep's `nextAttemptAt <= now` comparison is false
61
+ * for an invalid date forever — so the retry would be scheduled and never run.
62
+ * A stall that looks like a queue is the exact failure this phase removes.
63
+ */
64
+ function backoffFor(attempt) {
65
+ const idx = Math.max(0, Math.min(attempt - 1, JOB_BACKOFF_MS.length - 1));
66
+ return JOB_BACKOFF_MS[idx];
67
+ }
68
+ /**
69
+ * Run one attempt. Marks the job done, schedules a retry, or declares it dead.
70
+ *
71
+ * Never throws: a job's failure is recorded on the job, and letting it escape
72
+ * would make the Firebase trigger retry the whole handler — a second,
73
+ * uncontrolled retry mechanism layered under this one, which is precisely the
74
+ * doubling that cost 55 sessions in Root Cause #91 (`run.mjs`'s internal retry
75
+ * multiplying the pool's).
76
+ */
77
+ export async function runJobOnce(input, ctx) {
78
+ const { jobId, job } = input;
79
+ const attempt = job.attempt ?? 1;
80
+ const maxAttempts = job.maxAttempts ?? JOB_MAX_ATTEMPTS;
81
+ await jobsRepository.markProcessing(jobId);
82
+ const runner = JOB_RUNNERS[job.jobType];
83
+ if (!runner) {
84
+ /*
85
+ * 🛑 Terminal immediately, and DEAD rather than failed. An unregistered
86
+ * jobType cannot become registered by waiting, and the thing that would
87
+ * fix it is a deploy — so this is the clearest possible case for a human,
88
+ * not a retry. It is also the failure mode of the seed-loader registry
89
+ * (Root Cause #90): a missing map entry whose symptom is silence.
90
+ */
91
+ const error = `No runner registered for jobType: ${job.jobType}`;
92
+ await jobsRepository.markDead(jobId, error);
93
+ await pingBulkEvent(jobId, { status: "failed", action: job.jobType, error }, ctx);
94
+ await openDeadJobCase(jobId, job, error, ctx);
95
+ ctx.logger.error("runJobOnce: unregistered jobType", null, { jobId, jobType: job.jobType });
96
+ return;
97
+ }
98
+ try {
99
+ const result = await runner(job.payload, ctx);
100
+ await jobsRepository.markDone(jobId, result);
101
+ await pingBulkEvent(jobId, { status: "success", action: job.jobType, ...result }, ctx);
102
+ ctx.logger.info("runJobOnce: job complete", {
103
+ jobId,
104
+ jobType: job.jobType,
105
+ attempt,
106
+ summary: result.summary,
107
+ });
108
+ return;
109
+ }
110
+ catch (err) {
111
+ void normalizeError(err);
112
+ const message = err instanceof Error ? err.message : String(err);
113
+ /*
114
+ * 🛑 `mapToHttpError` rather than a bespoke test. It already decides "ours
115
+ * or theirs" for every error class here, so a 5xx is a transient fault
116
+ * worth retrying and a 4xx is a permanent one that will fail identically
117
+ * in five minutes.
118
+ */
119
+ const status = mapToHttpError(err).status;
120
+ const retryable = status >= 500;
121
+ const attemptsLeft = attempt < maxAttempts;
122
+ if (retryable && attemptsLeft) {
123
+ const nextAttemptAt = new Date(Date.now() + backoffFor(attempt));
124
+ /*
125
+ * 🛑 The NEW document is created BEFORE this one is marked failed. The
126
+ * reverse ordering leaves a window where the job reads as failed with no
127
+ * retry scheduled — and if the process dies in that window, nothing
128
+ * retries and nothing says so. This way the worst case is a scheduled
129
+ * retry whose parent still reads `processing`, which the sweep handles
130
+ * and a human can see.
131
+ */
132
+ const retryId = await jobsRepository.createRetry(jobId, job, {
133
+ attempt: attempt + 1,
134
+ maxAttempts,
135
+ nextAttemptAt,
136
+ });
137
+ await jobsRepository.markFailed(jobId, message);
138
+ /*
139
+ * The client is told "retrying", not "failed". `useBulkEvent` watches
140
+ * for a terminal state, and reporting failure here would stop a progress
141
+ * UI on a job that is still going.
142
+ */
143
+ await pingBulkEvent(jobId, { status: "retrying", action: job.jobType, error: message, retryJobId: retryId }, ctx);
144
+ ctx.logger.warn("runJobOnce: attempt failed, retry scheduled", {
145
+ jobId,
146
+ retryId,
147
+ jobType: job.jobType,
148
+ attempt,
149
+ status,
150
+ nextAttemptAt: nextAttemptAt.toISOString(),
151
+ });
152
+ return;
153
+ }
154
+ await jobsRepository.markDead(jobId, message);
155
+ await pingBulkEvent(jobId, { status: "failed", action: job.jobType, error: message }, ctx);
156
+ await openDeadJobCase(jobId, job, message, ctx);
157
+ ctx.logger.error("runJobOnce: job DEAD", err, {
158
+ jobId,
159
+ jobType: job.jobType,
160
+ attempt,
161
+ status,
162
+ reason: retryable ? "attempts exhausted" : "permanent failure",
163
+ });
164
+ }
165
+ }
166
+ /**
167
+ * A dead job is a case, not a log line.
168
+ *
169
+ * 🛑 Keyed on the ORIGINAL job id (`parentJobId ?? jobId`), so three exhausted
170
+ * attempts of one job produce ONE case rather than three. `openOrObserve`
171
+ * increments its own counter — the property that makes it safe to open a case
172
+ * from a hot path at all.
173
+ *
174
+ * Best-effort: a job is already dead by this point, and failing to file the
175
+ * case must not turn that into a thrown error from a trigger.
176
+ */
177
+ async function openDeadJobCase(jobId, job, error, ctx) {
178
+ const subjectId = job.parentJobId ?? jobId;
179
+ try {
180
+ await paymentCasesRepository().openOrObserve({
181
+ kind: "dead_job",
182
+ subjectId,
183
+ severity: "error",
184
+ entityType: "job",
185
+ entityId: subjectId,
186
+ title: `Job ${job.jobType} gave up after ${job.attempt ?? 1} attempt(s)`,
187
+ detail: `The last error was: ${error}. ` +
188
+ `Requested by ${job.requestedBy}. The job document holds the payload.`,
189
+ });
190
+ }
191
+ catch (err) {
192
+ void normalizeError(err);
193
+ ctx.logger.error("runJobOnce: could not open dead_job case", err, { jobId });
194
+ }
195
+ }
@@ -8,7 +8,7 @@ import { getDefaultCurrency } from "../../../../core/index.js";
8
8
  import { computePayoutDeduction } from "../../../shared/fees/calculator.js";
9
9
  import { payoutCutoff } from "../../../shared/fees/payout-hold.js";
10
10
  import { PROTECTION_CLAIM_WINDOW_HOURS } from "../../../shared/features/shipping/protections.js";
11
- import { ordersTaxableValue, ordersShippingReimbursement, } from "../../../shared/checkout/order-math.js";
11
+ import { ordersTaxableValue, ordersShippingReimbursement, ordersPointsBorneByStore, } from "../../../shared/checkout/order-math.js";
12
12
  export async function runWeeklyPayoutEligibility(ctx) {
13
13
  // `FEATURE_PAYOUTS` gate deleted 2026-10-19 — see `autoPayoutEligibility.ts`.
14
14
  const siteSettings = await siteSettingsRepository.getSingleton();
@@ -33,8 +33,21 @@ export async function runWeeklyPayoutEligibility(ctx) {
33
33
  holdSource: hold.source,
34
34
  cutoff: cutoff.toISOString(),
35
35
  });
36
+ /*
37
+ * 🛑 Resolved BEFORE the sweep, not per group.
38
+ *
39
+ * The widened query needs the whole set up front — the grouping by store
40
+ * happens after the rows come back, so a per-group lookup would arrive too
41
+ * late to have admitted the shipped rows in the first place. One bounded
42
+ * read against a hand-granted flag.
43
+ */
44
+ const trustedStoreIds = await storeRepository.findTrustedStoreIds();
45
+ if (trustedStoreIds.size > 0) {
46
+ ctx.logger.info(`${trustedStoreIds.size} trusted store(s) — their SHIPPED orders are eligible without waiting for delivery`, { trustedStoreCount: trustedStoreIds.size });
47
+ }
36
48
  const eligible = await orderRepository.getEligibleAutomatic(cutoff, {
37
49
  onWarn: (m, meta) => ctx.logger.warn(m, meta),
50
+ trustedStoreIds,
38
51
  });
39
52
  if (eligible.length === 0) {
40
53
  ctx.logger.info("No eligible delivered orders found");
@@ -75,7 +88,15 @@ export async function runWeeklyPayoutEligibility(ctx) {
75
88
  * `{ id, data }` wrappers, and passing the wrapper would read every field
76
89
  * as undefined and silently reimburse zero.
77
90
  */
78
- ordersShippingReimbursement(orders.map((o) => o.data)));
91
+ ordersShippingReimbursement(orders.map((o) => o.data)),
92
+ /*
93
+ * D46/D47 — the store-funded points, both ends. Must match
94
+ * `autoPayoutEligibility` exactly, for the reason stated above
95
+ * `grossAmount`: the weekly run and the automatic one pay the same orders,
96
+ * and a term present in one and absent in the other is a seller paid two
97
+ * different amounts depending on which job got there first.
98
+ */
99
+ ordersPointsBorneByStore(orders.map((o) => o.data)));
79
100
  /*
80
101
  * 🛑 REVEALED before building a payout — see the identical note in
81
102
  * `autoPayoutEligibility.ts`. `findById` is ciphertext-by-default and
@@ -85,6 +106,8 @@ export async function runWeeklyPayoutEligibility(ctx) {
85
106
  */
86
107
  const sellerPlain = userRepository.revealUser(seller);
87
108
  const payoutInput = {
109
+ /* Every row this job writes settles a SELLER liability. */
110
+ payeeType: "store",
88
111
  storeId,
89
112
  // `displayName` is plaintext by D1; the email fallback must be revealed.
90
113
  sellerName: (seller.displayName ?? sellerPlain.email ?? store.ownerId),
@@ -9,6 +9,7 @@
9
9
  */
10
10
  export { couponExpiryHandler } from "./couponExpiry";
11
11
  export { offerExpiryHandler } from "./offerExpiry";
12
+ export { reservationExpiryHandler } from "./reservationExpiry";
12
13
  export { cartPruneHandler } from "./cartPrune";
13
14
  export { notificationPruneHandler } from "./notificationPrune";
14
15
  export { dailyDataCleanupHandler } from "./dailyDataCleanup";
@@ -9,6 +9,7 @@
9
9
  */
10
10
  export { couponExpiryHandler } from "./couponExpiry.js";
11
11
  export { offerExpiryHandler } from "./offerExpiry.js";
12
+ export { reservationExpiryHandler } from "./reservationExpiry.js";
12
13
  export { cartPruneHandler } from "./cartPrune.js";
13
14
  export { notificationPruneHandler } from "./notificationPrune.js";
14
15
  export { dailyDataCleanupHandler } from "./dailyDataCleanup.js";
@@ -1,4 +1,21 @@
1
1
  import { handleOrderStatusChange, } from "../core/onOrderStatusChange.js";
2
+ /*
3
+ * 🛑 Bound as **`documentUpdated`**, which is what Phase 7's numbering needs
4
+ * and is already what this function uses — verified rather than assumed.
5
+ *
6
+ * `paymentStatus: pending → paid` is frequently the ONLY field that moves on a
7
+ * COD or manual order, and `documentUpdated` fires on any update, so the
8
+ * handler sees it. `documentCreated` would miss every one of them, and
9
+ * `documentWritten` would add nothing except a wake-up on create, where an
10
+ * order is `pending` and there is nothing to number.
11
+ *
12
+ * 🛑 What makes a write-back from this handler safe is the allocation claim:
13
+ * it updates `orders` only when IT allocated, so the re-fire caused by its own
14
+ * write finds the claim taken and writes nothing. That is the guard Root Cause
15
+ * #92's 12M-invocation loop lacked — there the no-op check compared Firestore
16
+ * maps with `JSON.stringify`, which is key-order sensitive and could never
17
+ * match, so every invocation wrote and every write re-triggered.
18
+ */
2
19
  export const onOrderStatusChangeHandler = async (event, ctx) => {
3
20
  await handleOrderStatusChange({ orderId: event.params.orderId, before: event.before, after: event.after }, ctx);
4
21
  };
@@ -0,0 +1,2 @@
1
+ import type { ScheduleHandler } from "../runtime/types";
2
+ export declare const reservationExpiryHandler: ScheduleHandler;
@@ -0,0 +1,2 @@
1
+ import { runReservationExpiry } from "../core/reservationExpiry.js";
2
+ export const reservationExpiryHandler = runReservationExpiry;
@@ -10,10 +10,33 @@
10
10
  * its own outcome decides whether the circuit re-closes or re-opens.
11
11
  */
12
12
  /**
13
- * Email is the only outbound channel with a transport. "whatsapp" was the
14
- * other arm until 2026-10-20, when the Cloud API integration was removed.
13
+ * Email is the only outbound *notification* channel with a transport.
14
+ * "whatsapp" was the other arm until 2026-10-20, when the Cloud API
15
+ * integration was removed.
16
+ *
17
+ * ## 🛑 Phase 8 widened this to the RECONCILERS' reads — and only those
18
+ *
19
+ * `razorpay_read` and `shiprocket_read` name the one placement where "stop
20
+ * hammering a dead API" is the right behaviour. Two placements are **actively
21
+ * harmful** and must never be added:
22
+ *
23
+ * 1. **NOT the webhook ingest path.** An open breaker converts a transient
24
+ * blip into a DROPPED money event — and dropping is precisely what a
25
+ * breaker does. The ingest path's whole job is to persist first and ack
26
+ * honestly so the gateway retries; a breaker there would ack a 5xx we never
27
+ * recorded.
28
+ *
29
+ * 2. **NOT around `payment.refund()`.** A refund POST that timed out may have
30
+ * SUCCEEDED, so retrying it issues two refunds — and the idempotency claim
31
+ * does not help, because it is the same call with the same key making a
32
+ * second network attempt. The two-phase reserve/settle exists so a human
33
+ * can resolve that by reading the gateway, not so a breaker can guess.
34
+ *
35
+ * The names carry `_read` for exactly that reason: a reader is idempotent, so
36
+ * backing off costs only freshness. Anything that moves money is not a reader
37
+ * and does not belong in this union.
15
38
  */
16
- export type NotificationChannel = "email";
39
+ export type NotificationChannel = "email" | "razorpay_read" | "shiprocket_read";
17
40
  /**
18
41
  * Returns false only when the circuit is open and still within its cooldown
19
42
  * window. Any other state (closed, or open-but-cooldown-elapsed) is treated
@@ -29,7 +29,7 @@ import type { IconKey } from "../../../ui/icons/icon-registry";
29
29
  /** What KIND of action — drives default UI affordance (link vs button vs danger). */
30
30
  export type ActionKind = "primary" | "secondary" | "danger" | "ghost" | "link" | "chip";
31
31
  /** Resource bucket — keyed top-level in the ACTIONS tree. */
32
- export type ActionResource = "PRODUCT" | "AUCTION" | "PRE_ORDER" | "PRIZE_DRAW" | "DIGITAL_CODE" | "BUNDLE" | "GROUP" | "CATEGORY" | "BRAND" | "PART" | "BEY" | "FAQ" | "SUBLISTING" | "STORE" | "BLOG" | "EVENT" | "REVIEW" | "SHIPMENT" | "CATALOGUE" | "USER" | "SELLER" | "ADMIN" | "CART" | "CHECKOUT" | "NAV" | "MEDIA" | "SUPPORT" | "LOTTERY" | "TESTER";
32
+ export type ActionResource = "PRODUCT" | "AUCTION" | "PRE_ORDER" | "PRIZE_DRAW" | "DIGITAL_CODE" | "BUNDLE" | "GROUP" | "CATEGORY" | "BRAND" | "ADS" | "PART" | "BEY" | "FAQ" | "SUBLISTING" | "STORE" | "BLOG" | "EVENT" | "REVIEW" | "SHIPMENT" | "CATALOGUE" | "USER" | "SELLER" | "ADMIN" | "CART" | "CHECKOUT" | "NAV" | "MEDIA" | "SUPPORT" | "LOTTERY" | "TESTER";
33
33
  /** Confirmation modal config — when set, <Button action={...}> opens
34
34
  * a confirm dialog before firing the actual handler. */
35
35
  export interface ActionConfirmation {