@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
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Booking a parcel through the platform's own carrier account — Part 1′.
3
+ *
4
+ * ## 🛑 Why this could not be built until Part 14
5
+ *
6
+ * `CreateShipmentInput` needs a structured `{name, phone, addressLine1, city,
7
+ * state, pincode, country}` for BOTH ends. Until the delivery snapshot landed
8
+ * the order carried `shippingAddress?: string` — flat free text with no
9
+ * pincode and no phone — and the only way to produce a party from it was to
10
+ * parse prose. The `placeOfSupply` comment already refuses that for tax, and
11
+ * the same argument holds here: a mis-parsed pincode is a parcel that goes to
12
+ * the wrong city, except nothing errors and the label prints fine.
13
+ *
14
+ * `deliveryPartyFor(order)` now returns exactly that shape, or `null` when a
15
+ * required field is missing — which is the only honest answer for an order
16
+ * placed before the snapshot existed.
17
+ *
18
+ * ## 🛑 `platformBookedShipment` is the flag this writes
19
+ *
20
+ * `order-math.ts` gates shipping reimbursement on it
21
+ * (`if (order.platformBookedShipment === true) return 0`) and
22
+ * `quote.ts:241` records that it has had **ZERO writers** — so the
23
+ * reimbursement rule has been reading a flag nothing sets. This is its
24
+ * writer, which is why the booking and the dispatch form are one unit of
25
+ * work and why the form must not ship first: a "Book through us" button with
26
+ * no booking behind it is a control the server refuses.
27
+ */
28
+ import { getProviders } from "../../../../contracts/registry.js";
29
+ import { orderRepository } from "../../../../features/orders/repository/orders.repository.js";
30
+ import { storeRepository } from "../../../../features/stores/repository/store.repository.js";
31
+ import { addressesRepository } from "../../../../features/addresses/repository/addresses.repository.js";
32
+ import { deliveryPartyFor } from "../../../shared/features/orders/delivery-snapshot.js";
33
+ import { revealPii } from "../../../../security/pii-accessors.js";
34
+ import { ORDER_PII_FIELDS } from "../../../../security/pii-schemas.js";
35
+ import { ValidationError } from "../../../../errors/validation-error.js";
36
+ import { NotFoundError } from "../../../../errors/not-found-error.js";
37
+ import { normalizeError } from "../../../../errors/normalize.js";
38
+ import { serverLogger } from "../../../../monitoring/server-logger.js";
39
+ /**
40
+ * Book one parcel.
41
+ *
42
+ * ## 🛑 The wallet is checked BEFORE the booking, and a failure is a 409
43
+ *
44
+ * A carrier account with no balance rejects the booking — but some providers
45
+ * accept it and then silently fail to hand over, which produces a tracking id
46
+ * that never moves. Checking first turns "the parcel vanished" into "top up
47
+ * the account", and the 409 is deliberate: the request is well-formed and the
48
+ * seller is not confused, the world is simply not ready.
49
+ *
50
+ * 🛑 `getWalletBalance` is NOT abstract on `IShippingProvider` — manual
51
+ * shipping has no wallet, so a provider that does not implement it returns
52
+ * undefined and the check is SKIPPED rather than failing. A missing balance
53
+ * must never block a manual dispatch.
54
+ */
55
+ export async function bookShipment(input) {
56
+ const order = (await orderRepository.findById(input.orderId));
57
+ if (!order)
58
+ throw new NotFoundError("Order not found.");
59
+ if (order.trackingNumber) {
60
+ /*
61
+ * 409, not 400. Double-booking is the expensive mistake here — two
62
+ * parcels, two charges, one of them never collected — and it is easy to
63
+ * cause by refreshing a form.
64
+ */
65
+ throw new ValidationError("This order already has a shipment.", {
66
+ orderId: `Already booked as ${order.trackingNumber}.`,
67
+ });
68
+ }
69
+ /*
70
+ * 🛑 DECRYPTED first. `OrderDocument`'s delivery name, phone and address
71
+ * lines are `Encrypted<string>` (ciphertext-by-default), and `Encrypted<T>`
72
+ * is deliberately assignable to nothing that wants a plain `string` — which
73
+ * is what made this a compile error rather than a courier label printed
74
+ * with `enc:v1:…` on it.
75
+ *
76
+ * A courier booking is the one place the plaintext is genuinely required:
77
+ * the carrier has to deliver to a real person at a real door. Masked would
78
+ * be the wrong default HERE and the right one almost everywhere else, which
79
+ * is why the two accessors are separately named.
80
+ */
81
+ const delivery = deliveryPartyFor(revealPii(order, ORDER_PII_FIELDS));
82
+ if (!delivery) {
83
+ /*
84
+ * An order placed before the delivery snapshot existed. Refused, loudly,
85
+ * rather than guessed at — see the module header on parsing prose.
86
+ */
87
+ throw new ValidationError("This order has no structured delivery address, so it cannot be booked automatically.", { orderId: "Placed before structured addresses; dispatch it manually." });
88
+ }
89
+ const pickupDoc = await addressesRepository.findById(input.pickupAddressId);
90
+ const store = order.storeId ? await storeRepository.findBySlug(order.storeId) : null;
91
+ /*
92
+ * 🛑 The pickup address must belong to the ORDER'S STORE. Checking only
93
+ * that it exists would let one seller's parcel be collected from another
94
+ * seller's premises — the same class of hole `assertOwnedAddresses` closes
95
+ * for coordinated purchases, and it is reachable here by id alone.
96
+ */
97
+ if (!pickupDoc ||
98
+ pickupDoc.ownerType !== "store" ||
99
+ !store ||
100
+ pickupDoc.ownerId !== store.id) {
101
+ throw new ValidationError("That pickup address is not available for this store.", {
102
+ pickupAddressId: "Pick one of this store's own addresses.",
103
+ });
104
+ }
105
+ const pickupPlain = addressesRepository.revealAddress(pickupDoc);
106
+ const pickup = {
107
+ name: String(pickupPlain.fullName ?? store.storeName ?? ""),
108
+ phone: String(pickupPlain.phone ?? ""),
109
+ addressLine1: String(pickupPlain.addressLine1 ?? ""),
110
+ ...(pickupPlain.addressLine2 ? { addressLine2: String(pickupPlain.addressLine2) } : {}),
111
+ city: pickupPlain.city ?? "",
112
+ state: pickupPlain.state ?? "",
113
+ pincode: pickupPlain.postalCode ?? "",
114
+ country: pickupPlain.country ?? "",
115
+ };
116
+ /*
117
+ * 🛑 `getProviders().shipping` is OPTIONAL on the registry, and refusing
118
+ * here is the honest handling. `providers.config.ts` always registers one
119
+ * today, so this is unreachable in this app — but a non-null assertion
120
+ * would turn the day somebody ships a build without it into a
121
+ * `Cannot read properties of undefined` at the moment money is involved,
122
+ * instead of a sentence a seller can act on.
123
+ */
124
+ const provider = getProviders().shipping;
125
+ if (!provider) {
126
+ throw new ValidationError("No shipping provider is configured.", {
127
+ orderId: "Automatic booking is unavailable — dispatch this order manually.",
128
+ });
129
+ }
130
+ /*
131
+ * 🛑 `WalletBalance` is a THREE-state union and collapsing it is the whole
132
+ * hazard the contract's own header describes. Only `{known: true, amount: 0}`
133
+ * is a decision to skip. `{known: false}` means either "no wallet exists"
134
+ * (manual shipping) or "could not read it right now" — and refusing on an
135
+ * unreadable balance would fail every dispatch on a transient blip.
136
+ *
137
+ * An earlier draft of this function tested `typeof balance === "number"`,
138
+ * which is never true against this contract: the guard was dead, so a
139
+ * genuinely empty wallet would have been booked into anyway.
140
+ */
141
+ const balance = await provider.getWalletBalance().catch((err) => {
142
+ void normalizeError(err);
143
+ serverLogger.warn("bookShipment: wallet balance unavailable", { orderId: input.orderId });
144
+ return { known: false, supported: true };
145
+ });
146
+ if (balance.known && balance.amount <= 0) {
147
+ throw new ValidationError("The courier account has no balance, so the booking was not attempted.", { orderId: "Top up the carrier wallet and try again." });
148
+ }
149
+ const payload = {
150
+ orderId: input.orderId,
151
+ dimensions: input.dimensions,
152
+ pickup,
153
+ delivery,
154
+ ...(order.paymentMethod === "cod"
155
+ ? { isCod: true, codAmount: order.codRemainingAmount ?? order.totalPrice }
156
+ : {}),
157
+ };
158
+ const shipment = await provider.createShipment(payload);
159
+ /*
160
+ * 🛑 `platformBookedShipment: true` is the WHOLE POINT of this function.
161
+ *
162
+ * `order-math.ts` already gates shipping reimbursement on it and nothing
163
+ * has ever set it. Writing the tracking id without it would book the parcel
164
+ * AND reimburse the seller for postage the platform just paid.
165
+ */
166
+ await orderRepository.update(input.orderId, {
167
+ trackingNumber: shipment.trackingId,
168
+ ...(shipment.courier ? { carrier: shipment.courier } : {}),
169
+ platformBookedShipment: true,
170
+ });
171
+ return {
172
+ trackingId: shipment.trackingId,
173
+ ...(shipment.courier ? { courier: shipment.courier } : {}),
174
+ ...(shipment.estimatedDelivery ? { estimatedDelivery: shipment.estimatedDelivery } : {}),
175
+ };
176
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Raising and clearing a courier block, and telling the ADMIN about it.
3
+ *
4
+ * ## The problem this exists for
5
+ *
6
+ * Shiprocket is PREPAID and has no recharge API, so topping up the courier
7
+ * wallet is irreducibly a human action. If the platform books couriers, an
8
+ * empty wallet silently stops dispatch on orders buyers have already paid for.
9
+ *
10
+ * ## The two rules
11
+ *
12
+ * 1. 🛑 **The order is never auto-cancelled over it.** `seller-dispatch`'s
13
+ * `precondition` carries `!hasOpenCourierBlock(o)`, so its 2-business-day
14
+ * `onDue: "act"` clock PAUSES while blocked instead of cancelling the order
15
+ * and refunding the buyer with the seller blamed for our funding state.
16
+ *
17
+ * 2. 🛑 **The admin alert is deduped on the WALLET, never on the order.** Fifty
18
+ * blocked orders are ONE problem with one fix. The daily email ceiling
19
+ * applies to staff mail too (`send-guard.ts:92` — the kill switch spares
20
+ * staff, the ceiling does not), so fifty per-order emails would spend the
21
+ * whole 80/day budget saying the same thing fifty times and leave the
22
+ * operator blind to everything else.
23
+ */
24
+ import type { OrderDocument } from "../../../../features/orders/schemas/firestore";
25
+ import type { WalletBalance } from "../../../../contracts";
26
+ /**
27
+ * ## 🛑 What is HERE and what deliberately is not
28
+ *
29
+ * Shipped: the wallet THRESHOLD check and the whole admin-alert path, driven by
30
+ * the daily digest. That is a real producer today and needs nothing new — and
31
+ * it is the better signal anyway: reacting only to failures means the first
32
+ * warning is always a buyer's order already stuck.
33
+ *
34
+ * NOT shipped: raising a block on a specific order. That belongs with the
35
+ * booking path, and nothing platform-books yet (`createShipment` has zero
36
+ * callers). A `raiseCourierBlock` with no producer is the speculative-infra
37
+ * pattern, so it lands when the caller does.
38
+ *
39
+ * `OrderDocument.courierBlock` and `seller-dispatch`'s
40
+ * `!hasOpenCourierBlock(o)` guard ARE already in place, and that ordering is
41
+ * deliberate: a safety property must exist BEFORE the thing it guards against,
42
+ * or the very first block auto-cancels a paid order. Inert today, correct the
43
+ * moment anything writes the field.
44
+ */
45
+ /** Why we could not book. Mirrors `OrderDocument.courierBlock.reason`. */
46
+ export type CourierBlockReason = NonNullable<OrderDocument["courierBlock"]>["reason"];
47
+ export interface CourierWalletCheck {
48
+ /** `null` when the provider has no wallet, or we could not read it. */
49
+ balance: number | null;
50
+ low: boolean;
51
+ alerted: boolean;
52
+ reason?: string;
53
+ }
54
+ /**
55
+ * Read the courier wallet and, if it is running low, alert the admin ONCE.
56
+ *
57
+ * Called from `dailyStatusDigest` — 🛑 deliberately NOT a new scheduled
58
+ * function. Cloud Scheduler bills per registered job and this is one read a
59
+ * day; the same reasoning that put the ledger reconciler inside
60
+ * `dailyDataCleanup`.
61
+ *
62
+ * Never throws: a wallet read is diagnostics, and a digest that fails because
63
+ * one provider was unreachable stops reporting the fifteen things that were
64
+ * fine.
65
+ */
66
+ export declare function checkCourierWalletAndAlert(provider: {
67
+ name: string;
68
+ getWalletBalance: () => Promise<WalletBalance>;
69
+ } | undefined): Promise<CourierWalletCheck>;
@@ -0,0 +1,264 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Raising and clearing a courier block, and telling the ADMIN about it.
4
+ *
5
+ * ## The problem this exists for
6
+ *
7
+ * Shiprocket is PREPAID and has no recharge API, so topping up the courier
8
+ * wallet is irreducibly a human action. If the platform books couriers, an
9
+ * empty wallet silently stops dispatch on orders buyers have already paid for.
10
+ *
11
+ * ## The two rules
12
+ *
13
+ * 1. 🛑 **The order is never auto-cancelled over it.** `seller-dispatch`'s
14
+ * `precondition` carries `!hasOpenCourierBlock(o)`, so its 2-business-day
15
+ * `onDue: "act"` clock PAUSES while blocked instead of cancelling the order
16
+ * and refunding the buyer with the seller blamed for our funding state.
17
+ *
18
+ * 2. 🛑 **The admin alert is deduped on the WALLET, never on the order.** Fifty
19
+ * blocked orders are ONE problem with one fix. The daily email ceiling
20
+ * applies to staff mail too (`send-guard.ts:92` — the kill switch spares
21
+ * staff, the ceiling does not), so fifty per-order emails would spend the
22
+ * whole 80/day budget saying the same thing fifty times and leave the
23
+ * operator blind to everything else.
24
+ */
25
+ import { Fragment } from "react";
26
+ import { renderToStaticMarkup } from "react-dom/server";
27
+ import { EmailContainer, EmailDoc, EmailRow, } from "../../../../features/email/primitives.js";
28
+ import { paymentCasesRepository } from "../../../../features/payment-cases/repository/payment-cases.repository.js";
29
+ // `adminNotificationsRepository` lives behind the repositories barrel — the
30
+ // same import the two existing staff-signal call sites use.
31
+ import { adminNotificationsRepository } from "../../../../repositories/index.js";
32
+ import { siteSettingsRepository } from "../../../../features/admin/repository/site-settings.repository.js";
33
+ import { normalizeError } from "../../../../errors/normalize.js";
34
+ import { serverLogger } from "../../../../monitoring/server-logger.js";
35
+ import { sendEmail } from "../../../../features/contact/email.js";
36
+ /**
37
+ * The dedupe key: the PROVIDER, not the order.
38
+ *
39
+ * One string, so a hundred stuck orders collapse into one case whose
40
+ * `observedCount` is the number of orders waiting — which is also the only
41
+ * number an operator actually needs in order to decide how urgently to top up.
42
+ */
43
+ function walletCaseKey(provider) {
44
+ return `courier-wallet:${provider}`;
45
+ }
46
+ /**
47
+ * How many shipments' worth of balance counts as "low".
48
+ *
49
+ * 🛑 Expressed in SHIPMENTS, not rupees. A ₹500 floor is meaningless without
50
+ * knowing what a booking costs, and the question an operator is really asking
51
+ * is "how many more parcels can I send before this stops". Four is roughly a
52
+ * day's slack at this volume, which is the point: the alert should arrive while
53
+ * topping up is still routine.
54
+ *
55
+ * `TYPICAL_BOOKING_COST` is an ESTIMATE and is labelled one — the real figure
56
+ * per parcel comes from `checkServiceability` and varies by weight and
57
+ * destination. It only has to be the right order of magnitude to make the
58
+ * warning land before the wallet is actually empty.
59
+ */
60
+ const LOW_BALANCE_SHIPMENTS = 4;
61
+ const TYPICAL_BOOKING_COST = 80;
62
+ /**
63
+ * Read the courier wallet and, if it is running low, alert the admin ONCE.
64
+ *
65
+ * Called from `dailyStatusDigest` — 🛑 deliberately NOT a new scheduled
66
+ * function. Cloud Scheduler bills per registered job and this is one read a
67
+ * day; the same reasoning that put the ledger reconciler inside
68
+ * `dailyDataCleanup`.
69
+ *
70
+ * Never throws: a wallet read is diagnostics, and a digest that fails because
71
+ * one provider was unreachable stops reporting the fifteen things that were
72
+ * fine.
73
+ */
74
+ export async function checkCourierWalletAndAlert(
75
+ /*
76
+ * 🛑 Accepts `undefined` rather than being handed a cast.
77
+ * `ProviderRegistry.shipping` is declared optional, and although
78
+ * `providers.config.ts` always populates it, that is a runtime guarantee the
79
+ * TYPE does not make — and `as IShippingProvider` would silence the one
80
+ * signal that the registry was never initialised.
81
+ */
82
+ provider) {
83
+ if (!provider) {
84
+ return { balance: null, low: false, alerted: false, reason: "no shipping provider" };
85
+ }
86
+ let balance;
87
+ try {
88
+ balance = await provider.getWalletBalance();
89
+ }
90
+ catch (err) {
91
+ const e = normalizeError(err);
92
+ return { balance: null, low: false, alerted: false, reason: e.message };
93
+ }
94
+ if (!balance.known) {
95
+ /*
96
+ * 🛑 No alert, and no "balance 0" either. An unreadable balance is not a
97
+ * low balance — alerting on it would page an operator every time the
98
+ * network hiccupped, and they would learn to ignore the one that mattered.
99
+ * The reason is returned so the digest can SAY it was unreadable.
100
+ */
101
+ return {
102
+ balance: null,
103
+ low: false,
104
+ alerted: false,
105
+ reason: balance.supported ? (balance.reason ?? "unreadable") : "no wallet",
106
+ };
107
+ }
108
+ const low = balance.amount < LOW_BALANCE_SHIPMENTS * TYPICAL_BOOKING_COST;
109
+ if (!low)
110
+ return { balance: balance.amount, low: false, alerted: false };
111
+ const alerted = await alertAdminOnce({
112
+ provider: provider.name,
113
+ reason: "insufficient_funds",
114
+ detail: `balance ${balance.amount}`,
115
+ }).catch((err) => {
116
+ const e = normalizeError(err);
117
+ serverLogger.error("courier-wallet: admin alert failed", {
118
+ provider: provider.name,
119
+ error: e.message,
120
+ });
121
+ return false;
122
+ });
123
+ return { balance: balance.amount, low: true, alerted };
124
+ }
125
+ /**
126
+ * One case, one in-app alert, one email — per WALLET, per unresolved episode.
127
+ *
128
+ * `openOrObserve` is what makes this idempotent: a second blocked order raises
129
+ * `observedCount` on the existing case rather than opening a new one, and the
130
+ * email is only sent when a case was actually OPENED.
131
+ */
132
+ async function alertAdminOnce(input) {
133
+ const { provider, reason, detail } = input;
134
+ const key = walletCaseKey(provider);
135
+ const title = reason === "insufficient_funds"
136
+ ? `Courier wallet needs a top-up (${provider})`
137
+ : `Courier booking failing (${provider})`;
138
+ const result = await paymentCasesRepository().openOrObserve({
139
+ kind: "courier_unavailable",
140
+ /*
141
+ * 🛑 `subjectId` identifies THE PROBLEM, not the observation — the
142
+ * repository's own words, and here the problem is the wallet. Passing the
143
+ * order id would open one case per stuck order, which is the exact noise
144
+ * `openOrObserve` exists to prevent ("an operator learns to ignore it, and
145
+ * the first real chargeback is lost in 8,000 rows").
146
+ */
147
+ subjectId: key,
148
+ severity: "error",
149
+ title,
150
+ detail: reason === "insufficient_funds"
151
+ ? `Bookings are failing for lack of funds. Paid orders are waiting and are NOT being auto-cancelled. Top up the ${provider} wallet, then retry from the order.`
152
+ : `Bookings are failing (${reason}). Paid orders are waiting and are NOT being auto-cancelled.${detail ? ` Upstream: ${detail.slice(0, 200)}` : ""}`,
153
+ /*
154
+ * The entity is the STORE-agnostic provider, so `entityType: "store"` would
155
+ * be a lie and `"order"` would re-key it to one order. `"job"` is the
156
+ * closest honest member of that union: this is a piece of our own
157
+ * machinery failing, not one record being wrong.
158
+ */
159
+ entityType: "job",
160
+ entityId: key,
161
+ });
162
+ /*
163
+ * 🛑 Only on a NEWLY CREATED case. This is the whole dedupe: an already-open
164
+ * episode has already been emailed, and re-sending it daily — or once per
165
+ * blocked order, once booking is wired — is the budget bug this function
166
+ * exists to avoid. The daily ceiling applies to staff mail too.
167
+ */
168
+ if (!result.created)
169
+ return false;
170
+ // One durable staff row the admin inbox reads and the digest counts —
171
+ // `audienceUserIds: []` is the "staff signal is a record, not a blast"
172
+ // pattern, rather than N personal notifications.
173
+ await adminNotificationsRepository
174
+ .create({
175
+ /*
176
+ * No cast. The fields are the real `AdminNotificationDocument` ones —
177
+ * `category`, not `type` — because a cast here would silence every other
178
+ * field's check too, which is how the `as never` on the older catalogue
179
+ * handler hid a wrong `createdAt` (CLAUDE.md § Notifications).
180
+ */
181
+ category: "system",
182
+ severity: "error",
183
+ title,
184
+ body: `${title}. Paid orders are waiting; none will be auto-cancelled while this is open.`,
185
+ isRead: false,
186
+ entityType: "job",
187
+ entityId: key,
188
+ audienceUserIds: [],
189
+ })
190
+ .catch((err) => {
191
+ void normalizeError(err);
192
+ });
193
+ await emailStaff({ title, provider, reason });
194
+ return true;
195
+ }
196
+ /**
197
+ * The staff email.
198
+ *
199
+ * 🛑 `feature` is a NAMED FLOW, not a `NotificationType`, and that is a
200
+ * deliberate correction to the plan this came from.
201
+ *
202
+ * `SendGuardContext.feature` is documented as "a notification type, or a named
203
+ * non-notification flow (`daily_digest`, `checkout_otp`, `payout_summary`)",
204
+ * and this is the second kind. A `NotificationType` is addressed to a USER and
205
+ * carries preferences, templates and an audience — none of which make sense
206
+ * here: nobody can opt out of "the courier wallet is empty", and there is no
207
+ * user it belongs to. Adding one would have meant four compile-checked map
208
+ * entries describing a notification nobody receives.
209
+ *
210
+ * `audience: "staff"` is load-bearing: the admin kill switch suppresses
211
+ * user-facing mail only, so switching customer email off must not stop the
212
+ * operator finding out that paid orders have stopped moving.
213
+ */
214
+ async function emailStaff(input) {
215
+ const settings = await siteSettingsRepository.getSingleton().catch((err) => {
216
+ void normalizeError(err);
217
+ return null;
218
+ });
219
+ // Same recipient list the daily digest uses — one place to configure "who
220
+ // hears about operational problems".
221
+ const recipients = (settings?.emailSettings?.dailyDigest?.recipients ?? []).filter((r) => r.trim().length > 0);
222
+ if (recipients.length === 0) {
223
+ serverLogger.warn("courier-block: no staff recipients configured — case raised, no email", {
224
+ provider: input.provider,
225
+ });
226
+ return;
227
+ }
228
+ const body = input.reason === "insufficient_funds"
229
+ ? `Courier bookings are failing for lack of funds on the ${input.provider} wallet.\n\nPaid orders are waiting. They are NOT being auto-cancelled — the dispatch clock is paused while this is open.\n\nTop up the wallet, then retry from the order or the money-cases queue.`
230
+ : `Courier bookings are failing on ${input.provider} (${input.reason}).\n\nPaid orders are waiting. They are NOT being auto-cancelled — the dispatch clock is paused while this is open.`;
231
+ const { error } = await sendEmail({
232
+ to: recipients,
233
+ subject: input.title,
234
+ /*
235
+ * Composed from the Email primitives rather than hand-built HTML.
236
+ *
237
+ * The old line string-replaced `\n\n` into `</p><p>`, which produces
238
+ * markup no email client was ever tested against and which
239
+ * `audit-email-raw-html` blocks for that reason. `EmailDoc` renders the
240
+ * table-based, inline-styled structure clients actually honour, and the
241
+ * paragraph split now happens on the DATA before it reaches the markup.
242
+ */
243
+ html: renderStaffAlertEmail(input.title, body),
244
+ text: body,
245
+ }, { channel: "email", feature: "courier_wallet_low", audience: "staff" });
246
+ if (error) {
247
+ serverLogger.error("courier-block: staff email failed", {
248
+ provider: input.provider,
249
+ error: String(error),
250
+ });
251
+ }
252
+ }
253
+ /**
254
+ * The staff courier-block alert, as an email document.
255
+ *
256
+ * Kept local to this file rather than exported: it is one alert with one
257
+ * shape, and a shared "generic staff alert" helper would invite the next
258
+ * caller to pass admin-editable text through it — which is how an email
259
+ * template becomes an injection surface. The body here is built entirely from
260
+ * our own constants and the provider/reason enums.
261
+ */
262
+ function renderStaffAlertEmail(title, body) {
263
+ return `<!DOCTYPE html>${renderToStaticMarkup(_jsx(EmailDoc, { title: title, children: _jsx(EmailContainer, { children: _jsx(EmailRow, { children: body.split("\n\n").map((para, i) => (_jsxs(Fragment, { children: [i > 0 ? _jsx("br", {}) : null, i > 0 ? _jsx("br", {}) : null, para.split("\n").map((line, j) => (_jsxs(Fragment, { children: [j > 0 ? _jsx("br", {}) : null, line] }, j)))] }, i))) }) }) }))}`;
264
+ }
@@ -37,9 +37,9 @@ import type { PublicSiteSettings } from "../../../shared/features/site-settings/
37
37
  * was traced to a call site; anything without one belongs in the private list,
38
38
  * because an unused public field is pure attack surface.
39
39
  */
40
- export declare const PUBLIC_SITE_SETTINGS_FIELDS: readonly ["contact", "payment", "listings", "notificationChannels", "announcementBar", "navConfig", "actionConfig", "background", "watermark", "disabledRoutes", "chat", "search"];
40
+ export declare const PUBLIC_SITE_SETTINGS_FIELDS: readonly ["contact", "payment", "listings", "notificationChannels", "announcementBar", "support", "navConfig", "actionConfig", "background", "watermark", "disabledRoutes", "chat", "search"];
41
41
  /** Everything else, with the reason it stays server-side. */
42
- export declare const PRIVATE_SITE_SETTINGS_FIELDS: readonly ["id", "createdAt", "updatedAt", "credentials", "emailSettings", "legalPages", "commissions", "emi", "gst", "laborRate", "adSettings", "integrations", "platformLimits", "auctionConfig", "siteName", "tagline", "motto", "logo", "favicon", "seo", "socialLinks", "features", "shipping", "returns", "faq", "aboutContent", "navbarConfig", "footerConfig", "theme", "featuredResults", "messaging"];
42
+ export declare const PRIVATE_SITE_SETTINGS_FIELDS: readonly ["rateChanges", "id", "createdAt", "updatedAt", "credentials", "emailSettings", "legalPages", "commissions", "emi", "gst", "laborRate", "adSettings", "integrations", "platformLimits", "auctionConfig", "siteName", "tagline", "motto", "logo", "favicon", "seo", "socialLinks", "features", "shipping", "returns", "faq", "aboutContent", "navbarConfig", "footerConfig", "theme", "featuredResults", "messaging"];
43
43
  export interface ToPublicSiteSettingsOptions {
44
44
  /**
45
45
  * The resolved marker → wordmark → text watermark chain. Injected because
@@ -9,6 +9,18 @@ export const PUBLIC_SITE_SETTINGS_FIELDS = [
9
9
  "listings", // useListingTypeFlags — narrowed to listings.listingTypes; categoryTypes has no client reader
10
10
  "notificationChannels", // NotificationPreferencesPanel reads the per-channel toggles
11
11
  "announcementBar", // the homepage banner (AdminSiteSettingsView edits it)
12
+ /*
13
+ * `support.enabled` — a REAL client reader, which is the bar this list sets:
14
+ * `getUserNavGroups` filters the buyer's support nav entry on it, and
15
+ * `UserLayoutClient` is a client component.
16
+ *
17
+ * 🛑 Publishing it is also harmless by inspection, and that is worth stating
18
+ * rather than assuming: the group holds exactly one boolean, and "is support
19
+ * reachable" is a fact a buyer discovers by looking at the page anyway. If a
20
+ * second field is ever added here, triage it separately — the group being
21
+ * public does not make its future members public.
22
+ */
23
+ "support",
12
24
  "navConfig", // NavbarWithSettings, DashboardLayoutClient
13
25
  "actionConfig", // useAuthGate
14
26
  "background", // DashboardLayoutClient (background.light / .dark)
@@ -54,6 +66,20 @@ export const PUBLIC_SITE_SETTINGS_FIELDS = [
54
66
  ];
55
67
  /** Everything else, with the reason it stays server-side. */
56
68
  export const PRIVATE_SITE_SETTINGS_FIELDS = [
69
+ /*
70
+ * 🛑 `rateChanges` — the rate-change log behind /admin/pricing.
71
+ *
72
+ * Every entry names an internal rate, who moved it and why. The WHY is the
73
+ * worst of it: a reason reads "undercutting X" or "margin too thin on
74
+ * bundles", which is commercial strategy typed by an admin who was told it
75
+ * was an internal note.
76
+ *
77
+ * Half the rates are already private (`gatewayFeePercent`,
78
+ * `payoutHoldDays`, `minPayoutAmount`), so publishing their history would
79
+ * also publish the values themselves — the current figure is the newest
80
+ * entry's `newValue`.
81
+ */
82
+ "rateChanges",
57
83
  "id", // singleton bookkeeping
58
84
  "createdAt", // bookkeeping
59
85
  "updatedAt", // bookkeeping
@@ -114,6 +140,9 @@ export function toPublicSiteSettings(doc, opts) {
114
140
  },
115
141
  notificationChannels: doc.notificationChannels,
116
142
  announcementBar: doc.announcementBar,
143
+ // Narrowed to the one boolean a client reads, not the group by reference —
144
+ // so a field added to `support` later is not published by accident.
145
+ support: doc.support ? { enabled: doc.support.enabled !== false } : undefined,
117
146
  navConfig: doc.navConfig,
118
147
  actionConfig: doc.actionConfig,
119
148
  background: doc.background,
@@ -25,9 +25,9 @@ import type { StoreDetail, StoreListItem } from "../../../../features/stores/typ
25
25
  * Document fields that may reach an unauthenticated client. Keep in sync with
26
26
  * the object literals below — the audit asserts both directions.
27
27
  */
28
- export declare const PUBLIC_STORE_FIELDS: readonly ["id", "storeSlug", "ownerId", "storeName", "storeDescription", "storeCategory", "storeLogoURL", "storeBannerURL", "status", "isPublic", "stats", "bio", "location", "website", "socialLinks", "returnPolicy", "shippingPolicy", "isVacationMode", "vacationMessage", "supportsShippingProtection", "supportsSaleProtection", "createdAt"];
28
+ export declare const PUBLIC_STORE_FIELDS: readonly ["id", "storeSlug", "ownerId", "storeName", "storeDescription", "storeCategory", "storeLogoURL", "storeBannerURL", "status", "isPublic", "stats", "bio", "location", "website", "socialLinks", "returnPolicy", "shippingPolicy", "isVacationMode", "vacationMessage", "supportsShippingProtection", "supportsSaleProtection", "allowSharedPurchase", "sharedPurchaseHandlingFee", "sharedPurchaseExtraShippingPerDestination", "createdAt"];
29
29
  /** Everything else, with the reason it stays server-side. */
30
- export declare const PRIVATE_STORE_FIELDS: readonly ["searchTxt", "updatedAt", "adminNotes", "statusHistory", "statusHistoryTruncated", "isVerified", "suspensionReason", "capabilities", "customCommissionRate", "googleReviews", "shippingConfig", "emiEnabled", "pricesIncludeGst", "shippingPricing", "returnsDirectToSeller", "isFeatured", "vacationReturnDate", "isTestData", "testDataExpiresAt", "gstin", "legalName", "registeredAddress"];
30
+ export declare const PRIVATE_STORE_FIELDS: readonly ["trustedSeller", "acceptsPoints", "searchTxt", "updatedAt", "adminNotes", "statusHistory", "statusHistoryTruncated", "isVerified", "suspensionReason", "capabilities", "customCommissionRate", "googleReviews", "shippingConfig", "emiEnabled", "pricesIncludeGst", "shippingPricing", "returnsDirectToSeller", "isFeatured", "vacationReturnDate", "isTestData", "testDataExpiresAt", "gstin", "legalName", "registeredAddress"];
31
31
  /**
32
32
  * Accepted input: a `StoreDocument` (the common case) or a loosely-typed
33
33
  * Firestore row. The legacy top-level counters below predate `stats` and are