@mohasinac/appkit 4.10.0 → 4.11.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 (319) hide show
  1. package/dist/_internal/client/features/layout/DashboardLayoutClient.d.ts +6 -1
  2. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +4 -1
  3. package/dist/_internal/client/features/lottery/LotteryPullForm.d.ts +1 -1
  4. package/dist/_internal/client/features/lottery/LotteryPullForm.js +2 -2
  5. package/dist/_internal/server/features/admin/daily-digest-actions.d.ts +18 -0
  6. package/dist/_internal/server/features/admin/daily-digest-actions.js +37 -0
  7. package/dist/_internal/server/features/audit-log/actions.d.ts +25 -0
  8. package/dist/_internal/server/features/audit-log/actions.js +38 -0
  9. package/dist/_internal/server/features/brands/actions.js +0 -2
  10. package/dist/_internal/server/features/brands/og.d.ts +4 -1
  11. package/dist/_internal/server/features/brands/og.js +1 -1
  12. package/dist/_internal/server/features/grouped/data.d.ts +4 -0
  13. package/dist/_internal/server/features/grouped/data.js +24 -0
  14. package/dist/_internal/server/features/grouped/index.d.ts +1 -1
  15. package/dist/_internal/server/features/grouped/index.js +1 -1
  16. package/dist/_internal/server/features/orders/actions.js +9 -0
  17. package/dist/_internal/server/features/orders/adapters.js +25 -0
  18. package/dist/_internal/server/functions/scheduled.d.ts +3 -1
  19. package/dist/_internal/server/functions/scheduled.js +17 -1
  20. package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +40 -0
  21. package/dist/_internal/server/jobs/core/dailyStatusDigest.js +164 -0
  22. package/dist/_internal/server/jobs/core/hardBanCascade.js +11 -0
  23. package/dist/_internal/server/jobs/core/testerSandboxCleanup.d.ts +1 -0
  24. package/dist/_internal/server/jobs/core/testerSandboxCleanup.js +4 -1
  25. package/dist/_internal/server/jobs/core/testerSandboxRefresh.d.ts +12 -0
  26. package/dist/_internal/server/jobs/core/testerSandboxRefresh.js +85 -0
  27. package/dist/_internal/server/jobs/core/whatsappNotify.js +16 -0
  28. package/dist/_internal/server/jobs/handlers/dailyStatusDigest.d.ts +2 -0
  29. package/dist/_internal/server/jobs/handlers/dailyStatusDigest.js +4 -0
  30. package/dist/_internal/server/jobs/handlers/index.d.ts +2 -0
  31. package/dist/_internal/server/jobs/handlers/index.js +3 -0
  32. package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.d.ts +2 -0
  33. package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.js +2 -0
  34. package/dist/_internal/server/notifications/channel-health.d.ts +27 -0
  35. package/dist/_internal/server/notifications/channel-health.js +101 -0
  36. package/dist/_internal/shared/features/brands/schema.d.ts +0 -6
  37. package/dist/_internal/shared/features/brands/schema.js +0 -1
  38. package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +7 -0
  39. package/dist/_internal/shared/features/categories/bundle-schemas.js +3 -0
  40. package/dist/_internal/shared/features/orders/schema.d.ts +8 -8
  41. package/dist/client.d.ts +21 -6
  42. package/dist/client.js +13 -3
  43. package/dist/constants/api-endpoints.d.ts +6 -9
  44. package/dist/constants/api-endpoints.js +2 -3
  45. package/dist/contracts/client-auth.d.ts +3 -7
  46. package/dist/contracts/email.d.ts +1 -0
  47. package/dist/features/account/components/AddressForm.js +24 -2
  48. package/dist/features/account/components/BecomeSellerView.d.ts +1 -2
  49. package/dist/features/account/components/BecomeSellerView.js +1 -1
  50. package/dist/features/account/components/NotificationBell.js +1 -1
  51. package/dist/features/account/components/UserBidsView.d.ts +1 -0
  52. package/dist/features/account/components/UserBidsView.js +47 -0
  53. package/dist/features/account/components/UserOrdersView.d.ts +4 -11
  54. package/dist/features/account/components/UserOrdersView.js +54 -4
  55. package/dist/features/account/components/UserReturnsView.d.ts +4 -9
  56. package/dist/features/account/components/UserReturnsView.js +37 -3
  57. package/dist/features/account/components/index.d.ts +3 -2
  58. package/dist/features/account/components/index.js +1 -0
  59. package/dist/features/admin/actions/admin-actions.js +22 -0
  60. package/dist/features/admin/actions/admin-coupon-actions.js +10 -0
  61. package/dist/features/admin/actions/notification-actions.js +4 -3
  62. package/dist/features/admin/components/AdminAdsView.d.ts +2 -3
  63. package/dist/features/admin/components/AdminAdsView.js +86 -89
  64. package/dist/features/admin/components/AdminAllEventEntriesView.js +18 -3
  65. package/dist/features/admin/components/AdminAuditLogView.d.ts +11 -0
  66. package/dist/features/admin/components/AdminAuditLogView.js +95 -0
  67. package/dist/features/admin/components/AdminBlogEditorView.js +37 -3
  68. package/dist/features/admin/components/AdminBrandEditorView.js +10 -6
  69. package/dist/features/admin/components/AdminBundleEditorView.js +18 -2
  70. package/dist/features/admin/components/AdminCarouselEditorView.js +2 -2
  71. package/dist/features/admin/components/AdminCarouselGroupEditorView.js +2 -2
  72. package/dist/features/admin/components/AdminCartsView.js +34 -4
  73. package/dist/features/admin/components/AdminCategoryEditorView.js +5 -4
  74. package/dist/features/admin/components/AdminCouponEditorView.js +2 -2
  75. package/dist/features/admin/components/AdminFaqEditorView.js +2 -2
  76. package/dist/features/admin/components/AdminHistoryView.js +11 -1
  77. package/dist/features/admin/components/AdminNotificationsView.js +27 -1
  78. package/dist/features/admin/components/AdminOrderEditorView.d.ts +10 -1
  79. package/dist/features/admin/components/AdminOrderEditorView.js +4 -3
  80. package/dist/features/admin/components/AdminOrdersView.js +92 -24
  81. package/dist/features/admin/components/AdminPayoutMarkPaidModal.d.ts +7 -0
  82. package/dist/features/admin/components/AdminPayoutMarkPaidModal.js +47 -0
  83. package/dist/features/admin/components/AdminPayoutsView.js +15 -31
  84. package/dist/features/admin/components/AdminProductEditorView.js +26 -3
  85. package/dist/features/admin/components/AdminSiteSettingsView.js +20 -1
  86. package/dist/features/admin/components/AdminStoreAddressesView.js +22 -2
  87. package/dist/features/admin/components/AdminStoresView.js +7 -0
  88. package/dist/features/admin/components/AdminSublistingCategoryEditorView.js +2 -2
  89. package/dist/features/admin/components/AdminTesterChecklistItemEditorView.js +2 -2
  90. package/dist/features/admin/components/AdminUserEditorView.d.ts +2 -2
  91. package/dist/features/admin/components/AdminUserEditorView.js +4 -2
  92. package/dist/features/admin/components/AdminUsersView.js +1 -1
  93. package/dist/features/admin/components/AdminWishlistsView.js +14 -1
  94. package/dist/features/admin/components/DataListingView.d.ts +2 -2
  95. package/dist/features/admin/components/ViewAuditLogEntryModal.d.ts +19 -0
  96. package/dist/features/admin/components/ViewAuditLogEntryModal.js +22 -0
  97. package/dist/features/admin/components/ViewNotificationModal.d.ts +21 -0
  98. package/dist/features/admin/components/ViewNotificationModal.js +15 -0
  99. package/dist/features/admin/components/analytics/AdminPageViewsReportView.d.ts +4 -7
  100. package/dist/features/admin/components/analytics/AdminPageViewsReportView.js +56 -36
  101. package/dist/features/admin/components/index.d.ts +8 -1
  102. package/dist/features/admin/components/index.js +4 -0
  103. package/dist/features/admin/constants/filter-tabs.d.ts +49 -0
  104. package/dist/features/admin/constants/filter-tabs.js +27 -0
  105. package/dist/features/admin/hooks/useAdminListing.d.ts +6 -0
  106. package/dist/features/admin/hooks/useAdminListing.js +3 -1
  107. package/dist/features/admin/hooks/useAdminListingData.d.ts +9 -1
  108. package/dist/features/admin/hooks/useAdminListingData.js +9 -2
  109. package/dist/features/admin/repository/site-settings.repository.d.ts +5 -0
  110. package/dist/features/admin/schemas/firestore.d.ts +12 -0
  111. package/dist/features/analytics/types.d.ts +1 -1
  112. package/dist/features/analytics/types.js +8 -0
  113. package/dist/features/auctions/schemas/index.d.ts +5 -0
  114. package/dist/features/audit-log/repository/audit-log.repository.d.ts +45 -0
  115. package/dist/features/audit-log/repository/audit-log.repository.js +30 -0
  116. package/dist/features/audit-log/schemas/firestore.d.ts +59 -0
  117. package/dist/features/audit-log/schemas/firestore.js +35 -0
  118. package/dist/features/auth/actions/index.d.ts +0 -1
  119. package/dist/features/auth/actions/index.js +0 -1
  120. package/dist/features/auth/hooks/useAuth.d.ts +8 -35
  121. package/dist/features/auth/hooks/useAuth.js +21 -37
  122. package/dist/features/auth/permissions/constants.d.ts +1 -1
  123. package/dist/features/auth/permissions/constants.js +2 -0
  124. package/dist/features/blog/schemas/index.d.ts +32 -0
  125. package/dist/features/catalogue/components/AdminCatalogueApprovalsView.js +31 -3
  126. package/dist/features/catalogue/components/CatalogueItemEditorView.js +2 -1
  127. package/dist/features/categories/components/BrandDetailPageView.js +14 -12
  128. package/dist/features/categories/components/CategoryDetailPageView.js +7 -3
  129. package/dist/features/categories/components/CategoryHighlightsAndFaqSection.d.ts +14 -0
  130. package/dist/features/categories/components/CategoryHighlightsAndFaqSection.js +22 -0
  131. package/dist/features/categories/components/CategoryProductsView.d.ts +1 -5
  132. package/dist/features/categories/components/CategoryProductsView.js +1 -1
  133. package/dist/features/categories/components/CategorySelectorCreate.js +16 -2
  134. package/dist/features/categories/schemas/firestore.d.ts +19 -2
  135. package/dist/features/categories/schemas/index.d.ts +24 -3
  136. package/dist/features/categories/schemas/index.js +3 -1
  137. package/dist/features/categories/types/index.d.ts +7 -0
  138. package/dist/features/checkout/actions/checkout-value-otp-actions.d.ts +17 -3
  139. package/dist/features/checkout/actions/checkout-value-otp-actions.js +101 -22
  140. package/dist/features/contact/components/ContactForm.js +17 -4
  141. package/dist/features/contact/email.d.ts +1 -0
  142. package/dist/features/contact/email.js +3 -0
  143. package/dist/features/events/components/AdminEventEditorView.js +54 -2
  144. package/dist/features/events/components/AdminEventEntriesView.d.ts +2 -16
  145. package/dist/features/events/components/AdminEventEntriesView.js +56 -89
  146. package/dist/features/events/components/EventFormDrawer.js +5 -1
  147. package/dist/features/events/components/EventRaffleEntryForm.d.ts +1 -3
  148. package/dist/features/events/components/EventRaffleEntryForm.js +1 -1
  149. package/dist/features/events/schemas/index.d.ts +22 -0
  150. package/dist/features/grouped/repository/grouped-listings.repository.d.ts +4 -0
  151. package/dist/features/grouped/repository/grouped-listings.repository.js +18 -0
  152. package/dist/features/homepage/components/CharacterHotspotForm.js +202 -187
  153. package/dist/features/homepage/components/SectionCarousel.d.ts +1 -7
  154. package/dist/features/homepage/components/SectionCarousel.js +1 -1
  155. package/dist/features/layout/TitleBarLayout.d.ts +1 -1
  156. package/dist/features/layout/TitleBarLayout.js +3 -3
  157. package/dist/features/media/MediaImage.js +39 -3
  158. package/dist/features/media/types/index.d.ts +10 -0
  159. package/dist/features/media/types/index.js +1 -0
  160. package/dist/features/media/upload/MediaUploadField.d.ts +7 -1
  161. package/dist/features/media/upload/MediaUploadField.js +11 -7
  162. package/dist/features/media/upload/video-poster.d.ts +2 -0
  163. package/dist/features/media/upload/video-poster.js +16 -1
  164. package/dist/features/media/upload/video-poster.test.js +1 -1
  165. package/dist/features/orders/components/OrderStatusTimeline.d.ts +12 -0
  166. package/dist/features/orders/components/OrderStatusTimeline.js +55 -0
  167. package/dist/features/orders/components/index.d.ts +2 -0
  168. package/dist/features/orders/components/index.js +1 -0
  169. package/dist/features/orders/constants/payment-window.d.ts +25 -0
  170. package/dist/features/orders/constants/payment-window.js +25 -0
  171. package/dist/features/orders/repository/orders.repository.d.ts +32 -0
  172. package/dist/features/orders/repository/orders.repository.js +56 -0
  173. package/dist/features/orders/schemas/index.d.ts +24 -24
  174. package/dist/features/orders/types/index.d.ts +33 -0
  175. package/dist/features/pre-orders/schemas/index.d.ts +5 -0
  176. package/dist/features/products/components/BidHistory.js +9 -1
  177. package/dist/features/products/components/GroupSettingsPanel.js +25 -3
  178. package/dist/features/products/components/PrizeDrawDetailPageView.js +1 -1
  179. package/dist/features/products/components/PrizeDrawEntryActions.d.ts +1 -4
  180. package/dist/features/products/components/PrizeDrawEntryActions.js +1 -1
  181. package/dist/features/products/components/ProductDetailActions.d.ts +1 -2
  182. package/dist/features/products/components/ProductDetailActions.js +1 -1
  183. package/dist/features/products/components/ProductGrid.js +15 -1
  184. package/dist/features/products/constants/action-defs.d.ts +1 -0
  185. package/dist/features/products/constants/action-defs.js +1 -0
  186. package/dist/features/products/schemas/index.d.ts +5 -0
  187. package/dist/features/promotions/components/CouponsIndexListing.d.ts +1 -3
  188. package/dist/features/promotions/components/CouponsIndexListing.js +1 -1
  189. package/dist/features/search/components/SearchView.d.ts +1 -3
  190. package/dist/features/search/components/SearchView.js +1 -1
  191. package/dist/features/seller/components/QuickProductForm.js +2 -1
  192. package/dist/features/seller/components/SellerBidsView.js +66 -107
  193. package/dist/features/seller/components/SellerGoogleReviewsView.js +17 -1
  194. package/dist/features/seller/components/SellerOrdersView.d.ts +15 -3
  195. package/dist/features/seller/components/SellerOrdersView.js +134 -163
  196. package/dist/features/seller/components/SellerPayoutMethodsView.js +60 -48
  197. package/dist/features/seller/components/SellerPayoutSettingsView.js +69 -4
  198. package/dist/features/seller/components/SellerPayoutsView.d.ts +12 -0
  199. package/dist/features/seller/components/SellerPayoutsView.js +25 -5
  200. package/dist/features/seller/components/SellerProductShell.d.ts +10 -3
  201. package/dist/features/seller/components/SellerProductShell.js +89 -36
  202. package/dist/features/seller/components/SellerProductsFilterDrawer.d.ts +2 -7
  203. package/dist/features/seller/components/SellerProductsFilterDrawer.js +4 -4
  204. package/dist/features/seller/components/SellerProductsView.d.ts +2 -4
  205. package/dist/features/seller/components/SellerProductsView.js +131 -189
  206. package/dist/features/seller/components/SellerReviewsView.js +95 -133
  207. package/dist/features/seller/components/SellerShippingConfigsView.js +47 -67
  208. package/dist/features/seller/components/SellerShippingView.js +41 -4
  209. package/dist/features/seller/components/SellerStoreCategoriesView.js +51 -59
  210. package/dist/features/seller/components/SellerStorefrontView.d.ts +6 -1
  211. package/dist/features/seller/components/SellerStorefrontView.js +42 -5
  212. package/dist/features/seller/components/index.d.ts +2 -2
  213. package/dist/features/seller/components/index.js +2 -2
  214. package/dist/features/shell/FormShell.d.ts +24 -4
  215. package/dist/features/shell/FormShell.js +12 -6
  216. package/dist/features/shell/QuickFormDrawer.js +67 -12
  217. package/dist/features/shell/StepForm.d.ts +30 -1
  218. package/dist/features/shell/StepForm.js +47 -4
  219. package/dist/features/shell/index.d.ts +1 -1
  220. package/dist/features/shell/index.js +1 -1
  221. package/dist/features/shipments/components/AdminShipmentEditorView.js +2 -2
  222. package/dist/features/shipments/schemas/validation.d.ts +14 -4
  223. package/dist/features/tester/components/AdminTesterFeedbackListView.js +23 -2
  224. package/dist/features/tester/components/TesterChecklistStepRow.js +1 -1
  225. package/dist/features/tester/components/TesterHubView.js +3 -2
  226. package/dist/features/tester/seed-data/orders-tester-seed-data.js +9 -1
  227. package/dist/features/tester/seed-data/products-tester-seed-data.js +43 -32
  228. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +404 -15
  229. package/dist/index.d.ts +15 -3
  230. package/dist/index.js +22 -5
  231. package/dist/next/routing/route-map.d.ts +11 -0
  232. package/dist/next/routing/route-map.js +5 -0
  233. package/dist/providers/email-resend/provider.js +1 -0
  234. package/dist/providers/firebase-client/auth.d.ts +1 -0
  235. package/dist/providers/firebase-client/auth.js +7 -1
  236. package/dist/repositories/index.d.ts +1 -0
  237. package/dist/repositories/index.js +1 -0
  238. package/dist/schemas/registry.d.ts +61 -25
  239. package/dist/security/pii-mask.js +1 -1
  240. package/dist/seed/categories-seed-data.js +69 -0
  241. package/dist/seed/products-auctions-seed-data.js +11 -0
  242. package/dist/seed/products-standard-seed-data.js +93 -4
  243. package/dist/seed/site-settings-seed-data.js +13 -1
  244. package/dist/seed/store-extensions-seed-data.js +1 -1
  245. package/dist/server-entry.d.ts +2 -1
  246. package/dist/server-entry.js +20 -2
  247. package/dist/server.d.ts +7 -2
  248. package/dist/server.js +8 -3
  249. package/dist/styles.css +1 -1
  250. package/dist/tailwind-utilities.css +1 -1
  251. package/dist/ui/components/Form.d.ts +11 -2
  252. package/dist/ui/components/Form.js +4 -3
  253. package/dist/ui/components/FormField.d.ts +3 -1
  254. package/dist/ui/components/FormField.js +22 -4
  255. package/dist/ui/components/ListingLayout.d.ts +1 -2
  256. package/dist/ui/components/ListingLayout.js +1 -1
  257. package/dist/ui/components/RecordDetailModal.d.ts +68 -0
  258. package/dist/ui/components/RecordDetailModal.js +8 -0
  259. package/dist/ui/components/SlottedListingView.js +9 -1
  260. package/dist/ui/forms/FormErrorSummary.d.ts +25 -0
  261. package/dist/ui/forms/FormErrorSummary.js +37 -0
  262. package/dist/ui/forms/FormShell.d.ts +37 -2
  263. package/dist/ui/forms/FormShell.js +37 -7
  264. package/dist/ui/forms/FormShell.style.css +17 -0
  265. package/dist/ui/forms/index.d.ts +2 -0
  266. package/dist/ui/forms/index.js +1 -0
  267. package/dist/ui/index.d.ts +4 -0
  268. package/dist/ui/index.js +5 -0
  269. package/dist/utils/media-url.d.ts +3 -1
  270. package/dist/utils/media-url.js +20 -1
  271. package/dist/validation/schemas.d.ts +4 -4
  272. package/package.json +1 -1
  273. package/dist/_internal/client/features/classified/ClassifiedDetailView.d.ts +0 -9
  274. package/dist/_internal/client/features/classified/ClassifiedDetailView.js +0 -55
  275. package/dist/_internal/client/features/digital-code/DigitalCodeDetailView.d.ts +0 -18
  276. package/dist/_internal/client/features/digital-code/DigitalCodeDetailView.js +0 -21
  277. package/dist/_internal/client/features/live/LiveItemDetailView.d.ts +0 -9
  278. package/dist/_internal/client/features/live/LiveItemDetailView.js +0 -25
  279. package/dist/_internal/server/jobs/core/prizeRevealClose.d.ts +0 -2
  280. package/dist/_internal/server/jobs/core/prizeRevealClose.js +0 -28
  281. package/dist/_internal/server/jobs/core/prizeRevealExpiry.d.ts +0 -2
  282. package/dist/_internal/server/jobs/core/prizeRevealExpiry.js +0 -61
  283. package/dist/_internal/server/jobs/core/prizeRevealOpen.d.ts +0 -2
  284. package/dist/_internal/server/jobs/core/prizeRevealOpen.js +0 -68
  285. package/dist/_internal/server/jobs/core/prizeRevealReminder.d.ts +0 -2
  286. package/dist/_internal/server/jobs/core/prizeRevealReminder.js +0 -49
  287. package/dist/_internal/server/jobs/handlers/prizeRevealClose.d.ts +0 -2
  288. package/dist/_internal/server/jobs/handlers/prizeRevealClose.js +0 -2
  289. package/dist/_internal/server/jobs/handlers/prizeRevealExpiry.d.ts +0 -2
  290. package/dist/_internal/server/jobs/handlers/prizeRevealExpiry.js +0 -2
  291. package/dist/_internal/server/jobs/handlers/prizeRevealOpen.d.ts +0 -2
  292. package/dist/_internal/server/jobs/handlers/prizeRevealOpen.js +0 -2
  293. package/dist/_internal/server/jobs/handlers/prizeRevealReminder.d.ts +0 -2
  294. package/dist/_internal/server/jobs/handlers/prizeRevealReminder.js +0 -2
  295. package/dist/features/auth/consent-otp.d.ts +0 -57
  296. package/dist/features/auth/consent-otp.js +0 -127
  297. package/dist/features/cart/components/CheckoutOtpModal.d.ts +0 -15
  298. package/dist/features/cart/components/CheckoutOtpModal.js +0 -12
  299. package/dist/features/checkout/actions/checkout-actions.d.ts +0 -31
  300. package/dist/features/checkout/actions/checkout-actions.js +0 -124
  301. package/dist/features/classified/components/ClassifiedIndexListing.d.ts +0 -5
  302. package/dist/features/classified/components/ClassifiedIndexListing.js +0 -123
  303. package/dist/features/classified/components/ClassifiedListView.d.ts +0 -6
  304. package/dist/features/classified/components/ClassifiedListView.js +0 -44
  305. package/dist/features/digital-codes/components/DigitalCodesIndexListing.d.ts +0 -5
  306. package/dist/features/digital-codes/components/DigitalCodesIndexListing.js +0 -114
  307. package/dist/features/digital-codes/components/DigitalCodesListView.d.ts +0 -6
  308. package/dist/features/digital-codes/components/DigitalCodesListView.js +0 -38
  309. package/dist/features/live/components/LiveItemsIndexListing.d.ts +0 -5
  310. package/dist/features/live/components/LiveItemsIndexListing.js +0 -115
  311. package/dist/features/live/components/LiveItemsListView.d.ts +0 -6
  312. package/dist/features/live/components/LiveItemsListView.js +0 -44
  313. package/dist/features/seller/components/SellerTemplatesView.d.ts +0 -12
  314. package/dist/features/seller/components/SellerTemplatesView.js +0 -276
  315. package/dist/react/hooks/useVisibleItems.d.ts +0 -37
  316. package/dist/react/hooks/useVisibleItems.js +0 -59
  317. package/dist/ui/components/TabStrip.d.ts +0 -34
  318. package/dist/ui/components/TabStrip.js +0 -56
  319. package/dist/ui/components/TabStrip.style.css +0 -97
@@ -35,7 +35,12 @@ export interface DashboardLayoutClientProps {
35
35
  permissions?: string[] | null;
36
36
  /** Override active-link highlight. Defaults to usePathname(). */
37
37
  activeHref?: string;
38
- /** Responsive controls — currently only hideAt is honoured. */
38
+ /**
39
+ * Responsive controls — accepted for interface parity with the generic
40
+ * `SectionResponsive` shape used elsewhere, but not currently honoured by
41
+ * this component (no caller passes it today). Wire `hideAt`/`showAt`/
42
+ * `compactAt` to real chrome behaviour before relying on this prop.
43
+ */
39
44
  responsive?: SectionResponsive;
40
45
  /**
41
46
  * Cross-dashboard nav links shown in the sidebar footer. Plain hrefs
@@ -155,7 +155,10 @@ function DashboardBottomNav({ items, activeHref }) {
155
155
  const DEFAULT_CONTENT_PADDING_RIGHT = "px-[var(--appkit-space-5)] py-[var(--appkit-space-8)] lg:pl-14 lg:pr-6 xl:pl-16 xl:pr-10";
156
156
  const DEFAULT_CONTENT_PADDING_LEFT = "px-[var(--appkit-space-5)] py-[var(--appkit-space-8)] lg:pr-14 lg:pl-6 xl:pr-16 xl:pl-10";
157
157
  const DEFAULT_CONTENT_MAX_WIDTH = "max-w-screen-2xl";
158
- export function DashboardLayoutClient({ variant, groups, permissions, activeHref: explicitActiveHref, responsive: _responsive, crossNav, className, contentPadding, contentSurface, contentMaxWidth, lightBackground, darkBackground, children, }) {
158
+ export function DashboardLayoutClient({ variant, groups, permissions, activeHref: explicitActiveHref,
159
+ // audit-dead-underscore-prop-ok: accepted for interface parity, not yet
160
+ // wired — see the doc comment on `responsive` above; no caller passes it.
161
+ responsive: _responsive, crossNav, className, contentPadding, contentSurface, contentMaxWidth, lightBackground, darkBackground, children, }) {
159
162
  const pathname = usePathname();
160
163
  const activeHref = explicitActiveHref ?? pathname ?? "";
161
164
  const storageKey = `appkit:sidebar-open:${variant}`;
@@ -16,5 +16,5 @@ interface LotteryPullFormProps {
16
16
  * Submits TX ID + phone + payment time + item number.
17
17
  * On success, shows the user their lottery number and assigned prize slot.
18
18
  */
19
- export declare function LotteryPullForm({ sourceType, eventId, productId, totalSlots, maxPullsPerUser: _maxPullsPerUser, onSuccess, }: LotteryPullFormProps): React.JSX.Element;
19
+ export declare function LotteryPullForm({ sourceType, eventId, productId, totalSlots, maxPullsPerUser, onSuccess, }: LotteryPullFormProps): React.JSX.Element;
20
20
  export {};
@@ -10,7 +10,7 @@ import { apiClient } from "../../../../http";
10
10
  * Submits TX ID + phone + payment time + item number.
11
11
  * On success, shows the user their lottery number and assigned prize slot.
12
12
  */
13
- export function LotteryPullForm({ sourceType, eventId, productId, totalSlots, maxPullsPerUser: _maxPullsPerUser, onSuccess, }) {
13
+ export function LotteryPullForm({ sourceType, eventId, productId, totalSlots, maxPullsPerUser, onSuccess, }) {
14
14
  const [result, setResult] = useState(null);
15
15
  const [transactionId, setTransactionId] = useState("");
16
16
  const [paymentTime, setPaymentTime] = useState("");
@@ -39,7 +39,7 @@ export function LotteryPullForm({ sourceType, eventId, productId, totalSlots, ma
39
39
  if (result) {
40
40
  return (_jsxs(Stack, { gap: "sm", padding: "md", rounded: "2xl", surface: "success-surface", className: "border border-success/20", children: [_jsxs(Row, { align: "center", gap: "sm", children: [_jsx(Span, { layout: "inline-flex", color: "inverse", weight: "semibold", className: "bg-success text-[11px] tracking-wide", padding: "pill-sm", rounded: "full", transform: "uppercase", children: "Entry Confirmed" }), _jsxs(Heading, { level: 2, className: "text-success", size: "lg", weight: "bold", children: ["You're #", result.userLotteryNumber, "!"] })] }), _jsxs(Text, { className: "text-success", size: "sm", children: ["You've been assigned", " ", _jsxs(Span, { weight: "bold", children: ["Slot #", result.assignedPrizeSlotNumber] }), result.slotName ? ` — ${result.slotName}` : "", ". Good luck!"] })] }));
41
41
  }
42
- return (_jsx(Form, { onSubmit: (e) => e.preventDefault(), className: "space-y-4", children: ({ setFieldError, clearErrors }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, size: "lg", weight: "semibold", children: "Submit Your Entry" }), _jsx(Text, { size: "sm", color: "muted", children: "Enter your UPI Transaction ID and payment details to claim your slot." }), _jsx(FieldInput, { name: "transactionId", label: "Transaction ID (UPI Ref / Payment Ref)", placeholder: "e.g. 123456789012", required: true, value: transactionId, onChange: (v) => { setTransactionId(v); clearErrors(); } }), _jsx(FieldInput, { name: "paymentTime", label: "Payment Date & Time", type: "datetime-local", required: true, value: paymentTime, onChange: (v) => { setPaymentTime(v); clearErrors(); } }), _jsx(FieldInput, { name: "itemNumber", label: `Slot Number (1 – ${totalSlots})`, type: "number", placeholder: `Enter a number between 1 and ${totalSlots}`, required: true, value: itemNumber, onChange: (v) => { setItemNumber(v); clearErrors(); } }), _jsx(FieldInput, { name: "userPhone", label: "Your Phone Number", type: "tel", placeholder: "e.g. 9876543210", required: true, value: userPhone, onChange: (v) => { setUserPhone(v); clearErrors(); } }), _jsx(Button, { type: "submit", variant: "primary", isLoading: mutation.isPending, onClick: () => {
42
+ return (_jsx(Form, { onSubmit: (e) => e.preventDefault(), className: "space-y-4", children: ({ setFieldError, clearErrors }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, size: "lg", weight: "semibold", children: "Submit Your Entry" }), _jsxs(Text, { size: "sm", color: "muted", children: ["Enter your UPI Transaction ID and payment details to claim your slot.", " ", "You may enter up to ", maxPullsPerUser, " time", maxPullsPerUser === 1 ? "" : "s", "."] }), _jsx(FieldInput, { name: "transactionId", label: "Transaction ID (UPI Ref / Payment Ref)", placeholder: "e.g. 123456789012", required: true, value: transactionId, onChange: (v) => { setTransactionId(v); clearErrors(); } }), _jsx(FieldInput, { name: "paymentTime", label: "Payment Date & Time", type: "datetime-local", required: true, value: paymentTime, onChange: (v) => { setPaymentTime(v); clearErrors(); } }), _jsx(FieldInput, { name: "itemNumber", label: `Slot Number (1 – ${totalSlots})`, type: "number", placeholder: `Enter a number between 1 and ${totalSlots}`, required: true, value: itemNumber, onChange: (v) => { setItemNumber(v); clearErrors(); } }), _jsx(FieldInput, { name: "userPhone", label: "Your Phone Number", type: "tel", placeholder: "e.g. 9876543210", required: true, value: userPhone, onChange: (v) => { setUserPhone(v); clearErrors(); } }), _jsx(Button, { type: "submit", variant: "primary", isLoading: mutation.isPending, onClick: () => {
43
43
  clearErrors();
44
44
  const num = parseInt(itemNumber, 10);
45
45
  let valid = true;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Manual trigger for the daily status digest.
3
+ *
4
+ * The digest normally runs from the `dailyStatusDigest` scheduled Firebase
5
+ * Function (10:00 IST). Firebase has no "run on first deploy" trigger, so
6
+ * this exists to fire the exact same core function on demand — e.g. right
7
+ * after a fresh deploy, to confirm the whole chain works without waiting
8
+ * for the next morning. Both paths share one implementation; there is no
9
+ * second copy of the digest logic.
10
+ */
11
+ import { type DailyStatusDigestResult } from "../../jobs/core/dailyStatusDigest";
12
+ export declare function triggerDailyStatusDigest(): Promise<DailyStatusDigestResult>;
13
+ /**
14
+ * Fires the digest once per deployment version, from server startup.
15
+ * Safe to call on every cold start — `runDeploymentDigest` claims the
16
+ * version in a Firestore transaction and no-ops if it's already been sent.
17
+ */
18
+ export declare function triggerDeploymentDigest(version: string): Promise<DailyStatusDigestResult>;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Manual trigger for the daily status digest.
3
+ *
4
+ * The digest normally runs from the `dailyStatusDigest` scheduled Firebase
5
+ * Function (10:00 IST). Firebase has no "run on first deploy" trigger, so
6
+ * this exists to fire the exact same core function on demand — e.g. right
7
+ * after a fresh deploy, to confirm the whole chain works without waiting
8
+ * for the next morning. Both paths share one implementation; there is no
9
+ * second copy of the digest logic.
10
+ */
11
+ import { getAdminDb } from "../../../../providers/db-firebase";
12
+ import { serverLogger } from "../../../../monitoring";
13
+ import { runDailyStatusDigest, runDeploymentDigest, } from "../../jobs/core/dailyStatusDigest";
14
+ function buildManualJobContext(job) {
15
+ return {
16
+ job,
17
+ db: getAdminDb(),
18
+ logger: {
19
+ info: (message, meta) => serverLogger.info(message, meta),
20
+ warn: (message, meta) => serverLogger.warn(message, meta),
21
+ error: (message, err, meta) => serverLogger.error(message, { err, ...(meta ?? {}) }),
22
+ },
23
+ env: (key) => process.env[key],
24
+ now: new Date(),
25
+ };
26
+ }
27
+ export async function triggerDailyStatusDigest() {
28
+ return runDailyStatusDigest(buildManualJobContext("dailyStatusDigest:manual"));
29
+ }
30
+ /**
31
+ * Fires the digest once per deployment version, from server startup.
32
+ * Safe to call on every cold start — `runDeploymentDigest` claims the
33
+ * version in a Firestore transaction and no-ops if it's already been sent.
34
+ */
35
+ export async function triggerDeploymentDigest(version) {
36
+ return runDeploymentDigest(buildManualJobContext("dailyStatusDigest:deploy"), version);
37
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * recordAdminAction — the single write-site for the admin audit trail.
3
+ *
4
+ * MVP scope: instruments the highest-value already-privileged admin actions
5
+ * (bans, checkout bypass, coupon edits, payout mark-paid, store status
6
+ * changes, role changes) rather than sweeping every write path in the app —
7
+ * see CLAUDE.md's "Admin Audit Log" section for the full instrumented-action
8
+ * list and rationale.
9
+ *
10
+ * Callers should treat this as best-effort/non-blocking — a failure to write
11
+ * an audit entry must never fail the underlying privileged action itself.
12
+ */
13
+ import type { AdminAuditAction } from "../../../../features/audit-log/schemas/firestore";
14
+ import type { JsonValue } from "../../../../schemas/types";
15
+ export interface RecordAdminActionInput {
16
+ actorUid: string;
17
+ actorName?: string;
18
+ action: AdminAuditAction;
19
+ targetType: string;
20
+ targetId: string;
21
+ targetLabel?: string;
22
+ reason?: string;
23
+ metadata?: Record<string, JsonValue>;
24
+ }
25
+ export declare function recordAdminAction(input: RecordAdminActionInput): Promise<void>;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * recordAdminAction — the single write-site for the admin audit trail.
3
+ *
4
+ * MVP scope: instruments the highest-value already-privileged admin actions
5
+ * (bans, checkout bypass, coupon edits, payout mark-paid, store status
6
+ * changes, role changes) rather than sweeping every write path in the app —
7
+ * see CLAUDE.md's "Admin Audit Log" section for the full instrumented-action
8
+ * list and rationale.
9
+ *
10
+ * Callers should treat this as best-effort/non-blocking — a failure to write
11
+ * an audit entry must never fail the underlying privileged action itself.
12
+ */
13
+ import { adminAuditLogRepository } from "../../../../features/audit-log/repository/audit-log.repository";
14
+ import { normalizeError } from "../../../../errors/normalize";
15
+ import { serverLogger } from "../../../../monitoring";
16
+ export async function recordAdminAction(input) {
17
+ try {
18
+ await adminAuditLogRepository.create({
19
+ actorUid: input.actorUid,
20
+ actorName: input.actorName,
21
+ action: input.action,
22
+ targetType: input.targetType,
23
+ targetId: input.targetId,
24
+ targetLabel: input.targetLabel,
25
+ reason: input.reason,
26
+ metadata: input.metadata,
27
+ });
28
+ }
29
+ catch (err) {
30
+ const normalized = normalizeError(err);
31
+ serverLogger.warn("recordAdminAction failed (non-critical)", {
32
+ action: input.action,
33
+ targetType: input.targetType,
34
+ targetId: input.targetId,
35
+ error: normalized.message,
36
+ });
37
+ }
38
+ }
@@ -26,8 +26,6 @@ function brandInputToCategoryFields(input) {
26
26
  out.brandCountry = input.country;
27
27
  if (input.founded !== undefined)
28
28
  out.brandFounded = input.founded;
29
- if (input.bannerURL !== undefined)
30
- out.brandBannerImage = input.bannerURL;
31
29
  if (input.logoURL !== undefined) {
32
30
  out.display = { coverImage: input.logoURL, showInMenu: false, showInFooter: false };
33
31
  }
@@ -7,7 +7,10 @@ export interface BrandOgData {
7
7
  interface BrandDocLike {
8
8
  name?: string | null;
9
9
  description?: string | null;
10
- logoURL?: string | null;
10
+ /** CategoryDocument has no `logoURL` field the brand's image lives at `display.coverImage`, the same field the hero banner and generateMetadata's OG meta tag already use. */
11
+ display?: {
12
+ coverImage?: string | null;
13
+ } | null;
11
14
  }
12
15
  /** High-level OG renderer — accepts the raw brand document from `getBrandForDetail`. */
13
16
  export declare function renderBrandOg(doc: BrandDocLike | null | undefined, opts: {
@@ -7,7 +7,7 @@ export function renderBrandOg(doc, opts) {
7
7
  name,
8
8
  description: doc?.description?.slice(0, 120) ??
9
9
  `Shop authentic ${name} collectibles on ${opts.siteName}.`,
10
- logoUrl: resolveOgImageUrl(doc?.logoURL ?? null, opts.baseUrl),
10
+ logoUrl: resolveOgImageUrl(doc?.display?.coverImage ?? null, opts.baseUrl),
11
11
  }, opts.siteName);
12
12
  }
13
13
  export function renderBrandOgImage(data, siteName) {
@@ -30,6 +30,10 @@ export declare const getGroupsForProduct: (productId: string) => Promise<Grouped
30
30
  * to render directly as a public GroupedListingsCarousel section.
31
31
  */
32
32
  export declare const getGroupsWithItemsForProduct: (productId: string) => Promise<GroupedListingWithItems[]>;
33
+ /** Groups tagged to a category, hydrated with all member products — for the category detail page's GroupedListingsCarousel. */
34
+ export declare const getGroupsForCategory: (categorySlug: string) => Promise<GroupedListingWithItems[]>;
35
+ /** Groups tagged to a brand, hydrated with all member products — for the brand detail page's GroupedListingsCarousel. */
36
+ export declare const getGroupsForBrand: (brandSlug: string) => Promise<GroupedListingWithItems[]>;
33
37
  export interface SitemapGroupedListing {
34
38
  slug: string;
35
39
  updatedAt: Date;
@@ -132,6 +132,30 @@ export const getGroupsWithItemsForProduct = cache(async (productId) => {
132
132
  return { ...group, items: items.filter((p) => p !== null) };
133
133
  }));
134
134
  });
135
+ /** Groups tagged to a category, hydrated with all member products — for the category detail page's GroupedListingsCarousel. */
136
+ export const getGroupsForCategory = cache(async (categorySlug) => {
137
+ const groups = await groupedListingsRepository.findByCategorySlug(categorySlug).catch((err) => {
138
+ void normalizeError(err);
139
+ serverLogger.warn("grouped-data: getGroupsForCategory failed — returning empty", { categorySlug, error: err instanceof Error ? err.message : String(err) });
140
+ return [];
141
+ });
142
+ return Promise.all(groups.map(async (group) => {
143
+ const items = await Promise.all(group.productIds.map((id) => productRepository.findByIdOrSlug(id).catch(() => null)));
144
+ return { ...group, items: items.filter((p) => p !== null) };
145
+ }));
146
+ });
147
+ /** Groups tagged to a brand, hydrated with all member products — for the brand detail page's GroupedListingsCarousel. */
148
+ export const getGroupsForBrand = cache(async (brandSlug) => {
149
+ const groups = await groupedListingsRepository.findByBrandSlug(brandSlug).catch((err) => {
150
+ void normalizeError(err);
151
+ serverLogger.warn("grouped-data: getGroupsForBrand failed — returning empty", { brandSlug, error: err instanceof Error ? err.message : String(err) });
152
+ return [];
153
+ });
154
+ return Promise.all(groups.map(async (group) => {
155
+ const items = await Promise.all(group.productIds.map((id) => productRepository.findByIdOrSlug(id).catch(() => null)));
156
+ return { ...group, items: items.filter((p) => p !== null) };
157
+ }));
158
+ });
135
159
  export async function listSitemapGroupedListings() {
136
160
  try {
137
161
  const db = getAdminDb();
@@ -1,2 +1,2 @@
1
- export { getGroupedListingForDetail, getGroupedListingWithItems, listGroupedListings, listFeaturedGroupedListings, listSitemapGroupedListings, getGroupsForProduct, getGroupsWithItemsForProduct, type GroupedListingWithItems, type ListGroupedListingsParams, type SitemapGroupedListing, } from "./data";
1
+ export { getGroupedListingForDetail, getGroupedListingWithItems, listGroupedListings, listFeaturedGroupedListings, listSitemapGroupedListings, getGroupsForProduct, getGroupsWithItemsForProduct, getGroupsForCategory, getGroupsForBrand, type GroupedListingWithItems, type ListGroupedListingsParams, type SitemapGroupedListing, } from "./data";
2
2
  export { GROUPED_LISTINGS_PAGE_SIZE, GROUPED_LISTINGS_FEATURED_LIMIT, GROUPED_LISTINGS_SITEMAP_LIMIT, } from "../../../shared/features/grouped/config";
@@ -1,2 +1,2 @@
1
- export { getGroupedListingForDetail, getGroupedListingWithItems, listGroupedListings, listFeaturedGroupedListings, listSitemapGroupedListings, getGroupsForProduct, getGroupsWithItemsForProduct, } from "./data";
1
+ export { getGroupedListingForDetail, getGroupedListingWithItems, listGroupedListings, listFeaturedGroupedListings, listSitemapGroupedListings, getGroupsForProduct, getGroupsWithItemsForProduct, getGroupsForCategory, getGroupsForBrand, } from "./data";
2
2
  export { GROUPED_LISTINGS_PAGE_SIZE, GROUPED_LISTINGS_FEATURED_LIMIT, GROUPED_LISTINGS_SITEMAP_LIMIT, } from "../../../shared/features/grouped/config";
@@ -161,6 +161,15 @@ export async function attachPaymentProofAction(orderId, proof) {
161
161
  buyerFraudAgreementAcceptedAt: new Date(),
162
162
  buyerReportedUpiId: proof.buyerReportedUpiId,
163
163
  paymentUpiMismatch,
164
+ // A re-upload after `adminRequestProofReuploadAction` must clear the
165
+ // stale `reupload_requested` outcome. Both the 2-hour auto-approve
166
+ // sweep (`getUnreviewedProofPastDeadline`) and the admin
167
+ // "Awaiting verification" queue treat *any* set outcome as "already
168
+ // decided" — leaving it set meant a corrected proof was invisible to
169
+ // both: never auto-approved, never surfaced for manual review.
170
+ paymentReviewOutcome: null,
171
+ paymentReviewedBy: null,
172
+ paymentReviewedAt: null,
164
173
  });
165
174
  notifyAdminsOfPaymentProof({
166
175
  id: orderId,
@@ -1,3 +1,6 @@
1
+ function toIsoOrUndefined(value) {
2
+ return value instanceof Date ? value.toISOString() : undefined;
3
+ }
1
4
  export function orderDocumentToOrder(doc) {
2
5
  const items = doc.items?.length
3
6
  ? doc.items.map((item) => ({
@@ -55,10 +58,32 @@ export function orderDocumentToOrder(doc) {
55
58
  couponCode: doc.couponCode,
56
59
  trackingNumber: doc.trackingNumber,
57
60
  shippingCarrier: doc.shippingCarrier,
61
+ trackingUrl: doc.trackingUrl,
58
62
  notes: doc.notes,
63
+ orderDate: toIsoOrUndefined(doc.orderDate),
64
+ shippingDate: toIsoOrUndefined(doc.shippingDate),
65
+ deliveryDate: toIsoOrUndefined(doc.deliveryDate),
66
+ cancellationDate: toIsoOrUndefined(doc.cancellationDate),
59
67
  autoApproved: doc.autoApproved,
60
68
  disputeRaised: doc.disputeRaised,
61
69
  disputeStatus: doc.disputeStatus,
70
+ // Manual-payment (cash / UPI / EMI) passthrough. These were previously
71
+ // dropped here, which silently disabled the entire buyer proof-upload
72
+ // flow: `/user/orders/[id]/payment` branches on `paymentMethod` and so
73
+ // rendered "this order does not require manual payment upload" for every
74
+ // order, with no UPI ID and no countdown.
75
+ paymentMethod: doc.paymentMethod,
76
+ displayedUpiId: doc.displayedUpiId,
77
+ paymentDeadline: toIsoOrUndefined(doc.paymentDeadline),
78
+ paymentProofUrl: doc.paymentProofUrl,
79
+ paymentProofUploadedAt: toIsoOrUndefined(doc.paymentProofUploadedAt),
80
+ paymentTransactionId: doc.paymentTransactionId,
81
+ buyerReportedUpiId: doc.buyerReportedUpiId,
82
+ buyerMarkedPaid: doc.buyerMarkedPaid,
83
+ paymentUpiMismatch: doc.paymentUpiMismatch,
84
+ paymentReviewOutcome: doc.paymentReviewOutcome,
85
+ paymentReviewNote: doc.paymentReviewNote,
86
+ cancellationReason: doc.cancellationReason,
62
87
  createdAt: doc.createdAt instanceof Date
63
88
  ? doc.createdAt.toISOString()
64
89
  : String(doc.createdAt),
@@ -7,6 +7,7 @@ export declare const couponExpiry: import("./types").ScheduledFunctionDefinition
7
7
  export declare const offerExpiry: import("./types").ScheduledFunctionDefinition;
8
8
  export declare const productStatsSync: import("./types").ScheduledFunctionDefinition;
9
9
  export declare const revenueRollup: import("./types").ScheduledFunctionDefinition;
10
+ export declare const dailyStatusDigest: import("./types").ScheduledFunctionDefinition;
10
11
  export declare const dailyDataCleanup: import("./types").ScheduledFunctionDefinition;
11
12
  export declare const countersReconcile: import("./types").ScheduledFunctionDefinition;
12
13
  export declare const positionsReconcile: import("./types").ScheduledFunctionDefinition;
@@ -19,8 +20,9 @@ export declare const cleanupRtdbEvents: import("./types").ScheduledFunctionDefin
19
20
  export declare const mediaTmpCleanup: import("./types").ScheduledFunctionDefinition;
20
21
  export declare const draftPrune: import("./types").ScheduledFunctionDefinition;
21
22
  export declare const testerSandboxCleanup: import("./types").ScheduledFunctionDefinition;
23
+ export declare const testerSandboxRefresh: import("./types").ScheduledFunctionDefinition;
22
24
  export declare const prizeDrawExpiryReveal: import("./types").ScheduledFunctionDefinition;
23
25
  export declare const bundleStockSync: import("./types").ScheduledFunctionDefinition;
24
26
  export declare const emiInstallmentReminder: import("./types").ScheduledFunctionDefinition;
25
27
  export declare const catalogueImageStalenessReminder: import("./types").ScheduledFunctionDefinition;
26
- export declare const SCHEDULED_FUNCTIONS: readonly [import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition];
28
+ export declare const SCHEDULED_FUNCTIONS: readonly [import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition, import("./types").ScheduledFunctionDefinition];
@@ -1,6 +1,6 @@
1
1
  // Scheduled function definitions (Cloud Scheduler triggers).
2
2
  // Cron syntax accepts both Firebase shorthand and standard cron expressions.
3
- import { auctionSettlementHandler, autoPayoutEligibilityHandler, bundleStockSyncHandler, cartPruneHandler, cleanupRtdbEventsHandler, countersReconcileHandler, couponExpiryHandler, dailyDataCleanupHandler, draftPruneHandler, emiInstallmentReminderHandler, catalogueImageStalenessReminderHandler, mediaTmpCleanupHandler, notificationPruneHandler, offerExpiryHandler, payoutBatchHandler, paymentWindowTimeoutHandler, hardBanReinstatementHandler, paymentReviewAutoApproveHandler, pendingOrderTimeoutHandler, positionsReconcileHandler, prizeDrawExpiryRevealHandler, productStatsSyncHandler, revenueRollupHandler, weeklyPayoutEligibilityHandler, testerSandboxCleanupHandler, } from "../jobs/handlers";
3
+ import { auctionSettlementHandler, autoPayoutEligibilityHandler, bundleStockSyncHandler, cartPruneHandler, cleanupRtdbEventsHandler, countersReconcileHandler, couponExpiryHandler, dailyDataCleanupHandler, draftPruneHandler, emiInstallmentReminderHandler, catalogueImageStalenessReminderHandler, mediaTmpCleanupHandler, notificationPruneHandler, offerExpiryHandler, payoutBatchHandler, paymentWindowTimeoutHandler, hardBanReinstatementHandler, paymentReviewAutoApproveHandler, pendingOrderTimeoutHandler, positionsReconcileHandler, prizeDrawExpiryRevealHandler, productStatsSyncHandler, revenueRollupHandler, dailyStatusDigestHandler, weeklyPayoutEligibilityHandler, testerSandboxCleanupHandler, testerSandboxRefreshHandler, } from "../jobs/handlers";
4
4
  import { defineFunction } from "./define";
5
5
  const REGION = "asia-south1";
6
6
  const EVERY_5_MIN = "every 5 minutes";
@@ -67,6 +67,13 @@ export const revenueRollup = defineFunction({
67
67
  handler: revenueRollupHandler,
68
68
  options: { region: REGION, timeoutSeconds: 300, memory: "256MiB", maxInstances: 1 },
69
69
  });
70
+ export const dailyStatusDigest = defineFunction({
71
+ name: "dailyStatusDigest",
72
+ description: "Email the previous 24h order summary + platform status to the team every morning at 10:00 IST.",
73
+ trigger: { kind: "schedule", cron: "0 10 * * *", timeZone: "Asia/Kolkata" },
74
+ handler: dailyStatusDigestHandler,
75
+ options: { region: REGION, timeoutSeconds: 120, memory: "256MiB", maxInstances: 1 },
76
+ });
70
77
  export const dailyDataCleanup = defineFunction({
71
78
  name: "dailyDataCleanup",
72
79
  description: "Daily data cleanup (drafts, transient records) at 02:00 UTC.",
@@ -151,6 +158,13 @@ export const testerSandboxCleanup = defineFunction({
151
158
  handler: testerSandboxCleanupHandler,
152
159
  options: { region: REGION, timeoutSeconds: 300, memory: "256MiB", maxInstances: 1 },
153
160
  });
161
+ export const testerSandboxRefresh = defineFunction({
162
+ name: "testerSandboxRefresh",
163
+ description: "Revert live tester QA sandbox fixtures to their canonical seed shape and prune tester-created extras (every 4 hours).",
164
+ trigger: { kind: "schedule", cron: "0 */4 * * *", timeZone: "UTC" },
165
+ handler: testerSandboxRefreshHandler,
166
+ options: { region: REGION, timeoutSeconds: 300, memory: "256MiB", maxInstances: 1 },
167
+ });
154
168
  export const prizeDrawExpiryReveal = defineFunction({
155
169
  name: "prizeDrawExpiryReveal",
156
170
  description: "Assign winners for outstanding paid orders on scheduled-mode prize draws past their expiry, then close them (every 5 minutes).",
@@ -189,6 +203,7 @@ export const SCHEDULED_FUNCTIONS = [
189
203
  offerExpiry,
190
204
  productStatsSync,
191
205
  revenueRollup,
206
+ dailyStatusDigest,
192
207
  dailyDataCleanup,
193
208
  countersReconcile,
194
209
  positionsReconcile,
@@ -201,6 +216,7 @@ export const SCHEDULED_FUNCTIONS = [
201
216
  mediaTmpCleanup,
202
217
  draftPrune,
203
218
  testerSandboxCleanup,
219
+ testerSandboxRefresh,
204
220
  prizeDrawExpiryReveal,
205
221
  bundleStockSync,
206
222
  emiInstallmentReminder,
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Core: daily status digest email.
3
+ *
4
+ * Emails the previous 24h of order activity to the team every morning. The
5
+ * digest's arrival is itself the platform health signal — if it stops
6
+ * landing, something in the Firestore → Functions → Resend chain needs a
7
+ * look. Deliberately no separate error/exception tracking: there is no
8
+ * structured error-log collection to query, and building one just to fill
9
+ * this email would be scope no one asked for.
10
+ *
11
+ * Runs from a scheduled Firebase Function (not a Vercel route), so the
12
+ * unbounded-ish order scan below is safe against CLAUDE.md Rule #6's 10s
13
+ * sync ceiling — it has the Function's much larger budget.
14
+ */
15
+ import type { JobContext } from "../runtime/types";
16
+ export interface DailyStatusDigestSummary {
17
+ orderCount: number;
18
+ revenue: number;
19
+ statusBreakdown: Record<string, number>;
20
+ stuckPendingCount: number;
21
+ activeListingCount: number;
22
+ }
23
+ /** Gathers the last-24h numbers. Exported so the admin manual-trigger route can reuse it. */
24
+ export declare function collectDailyStatusSummary(): Promise<DailyStatusDigestSummary>;
25
+ export interface DailyStatusDigestResult {
26
+ sent: boolean;
27
+ reason?: string;
28
+ summary?: DailyStatusDigestSummary;
29
+ }
30
+ /**
31
+ * Sends the digest once per deployment version.
32
+ *
33
+ * Called from server startup. On Vercel that means EVERY lambda cold start,
34
+ * not once per deploy — so the version marker below is what makes this a
35
+ * per-deployment event rather than a per-cold-start email storm. The claim
36
+ * runs in a transaction because several cold starts can race on the first
37
+ * request after a deploy; exactly one wins and sends.
38
+ */
39
+ export declare function runDeploymentDigest(ctx: JobContext, version: string): Promise<DailyStatusDigestResult>;
40
+ export declare function runDailyStatusDigest(ctx: JobContext, version?: string): Promise<DailyStatusDigestResult>;
@@ -0,0 +1,164 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Core: daily status digest email.
4
+ *
5
+ * Emails the previous 24h of order activity to the team every morning. The
6
+ * digest's arrival is itself the platform health signal — if it stops
7
+ * landing, something in the Firestore → Functions → Resend chain needs a
8
+ * look. Deliberately no separate error/exception tracking: there is no
9
+ * structured error-log collection to query, and building one just to fill
10
+ * this email would be scope no one asked for.
11
+ *
12
+ * Runs from a scheduled Firebase Function (not a Vercel route), so the
13
+ * unbounded-ish order scan below is safe against CLAUDE.md Rule #6's 10s
14
+ * sync ceiling — it has the Function's much larger budget.
15
+ */
16
+ import { renderToStaticMarkup } from "react-dom/server";
17
+ import { getAdminDb } from "../../../../providers/db-firebase";
18
+ import { sendEmail } from "../../../../features/contact/email";
19
+ import { siteSettingsRepository } from "../../../../features/admin/repository/site-settings.repository";
20
+ import { ORDER_COLLECTION, OrderStatusValues } from "../../../../features/orders/schemas/firestore";
21
+ import { PRODUCT_COLLECTION, ProductStatusValues } from "../../../../features/products/schemas/firestore";
22
+ import { ORDER_FIELDS, PRODUCT_FIELDS } from "../../../../constants/field-names";
23
+ import { EmailBold, EmailContainer, EmailDivider, EmailDoc, EmailFooter, EmailHeader, EmailRow, } from "../../../../features/email/primitives";
24
+ import { normalizeError } from "../../../../errors/normalize";
25
+ const DAY_MS = 24 * 60 * 60 * 1000;
26
+ /** Statuses that shouldn't count toward revenue for the day. */
27
+ const NON_REVENUE_STATUSES = new Set([
28
+ OrderStatusValues.CANCELLED,
29
+ OrderStatusValues.REFUNDED,
30
+ ]);
31
+ function currency(amount) {
32
+ return `₹${amount.toLocaleString("en-IN", { maximumFractionDigits: 2 })}`;
33
+ }
34
+ /** One "Label: value" line. Uses only email primitives — email clients need
35
+ * inline-styled, table-based markup, which the Email* components provide. */
36
+ function StatLine({ label, value }) {
37
+ return (_jsxs(_Fragment, { children: [label, ": ", _jsx(EmailBold, { children: String(value) }), _jsx("br", {})] }));
38
+ }
39
+ /** Gathers the last-24h numbers. Exported so the admin manual-trigger route can reuse it. */
40
+ export async function collectDailyStatusSummary() {
41
+ const db = getAdminDb();
42
+ const since = new Date(Date.now() - DAY_MS);
43
+ const recentSnap = await db
44
+ .collection(ORDER_COLLECTION)
45
+ .where(ORDER_FIELDS.CREATED_AT, ">=", since)
46
+ .get();
47
+ let revenue = 0;
48
+ const statusBreakdown = {};
49
+ for (const doc of recentSnap.docs) {
50
+ const data = doc.data();
51
+ const status = data.status ?? "unknown";
52
+ statusBreakdown[status] = (statusBreakdown[status] ?? 0) + 1;
53
+ if (!NON_REVENUE_STATUSES.has(status)) {
54
+ revenue += Number(data.totalPrice ?? 0) || 0;
55
+ }
56
+ }
57
+ // Orders still sitting in PENDING beyond the 24h window — the one number
58
+ // here that signals something needs attention rather than just reporting
59
+ // volume.
60
+ const stuckSnap = await db
61
+ .collection(ORDER_COLLECTION)
62
+ .where(ORDER_FIELDS.STATUS, "==", OrderStatusValues.PENDING)
63
+ .where(ORDER_FIELDS.CREATED_AT, "<", since)
64
+ .count()
65
+ .get();
66
+ const activeSnap = await db
67
+ .collection(PRODUCT_COLLECTION)
68
+ .where(PRODUCT_FIELDS.STATUS, "==", ProductStatusValues.PUBLISHED)
69
+ .count()
70
+ .get();
71
+ return {
72
+ orderCount: recentSnap.size,
73
+ revenue,
74
+ statusBreakdown,
75
+ stuckPendingCount: stuckSnap.data().count,
76
+ activeListingCount: activeSnap.data().count,
77
+ };
78
+ }
79
+ function renderDigestHtml(summary, siteName, version) {
80
+ const statusRows = Object.entries(summary.statusBreakdown).sort(([a], [b]) => a.localeCompare(b));
81
+ const title = siteName ? `${siteName} — Daily Status` : "Daily Status";
82
+ return `<!DOCTYPE html>${renderToStaticMarkup(_jsx(EmailDoc, { title: title, children: _jsxs(EmailContainer, { children: [_jsx(EmailHeader, { brandName: siteName }), _jsxs(EmailRow, { children: [version
83
+ ? `Deployment ${version} is live. Activity for the last 24 hours.`
84
+ : "Activity for the last 24 hours.", _jsx("br", {}), _jsx("br", {}), _jsx(StatLine, { label: "Orders placed", value: summary.orderCount }), _jsx(StatLine, { label: "Revenue (excl. cancelled/refunded)", value: currency(summary.revenue) }), _jsx(StatLine, { label: "Active listings", value: summary.activeListingCount }), _jsx(StatLine, { label: "Pending > 24h (needs attention)", value: summary.stuckPendingCount })] }), _jsx(EmailDivider, {}), _jsxs(EmailRow, { children: [_jsx(EmailBold, { children: "Orders by status" }), _jsx("br", {}), _jsx("br", {}), statusRows.length === 0 ? ("No orders in this window.") : (statusRows.map(([status, count]) => (_jsx(StatLine, { label: status, value: count }, status))))] }), _jsx(EmailFooter, { copyright: `© ${new Date().getFullYear()}${siteName ? ` ${siteName}` : ""}. All rights reserved.` })] }) }))}`;
85
+ }
86
+ const DEPLOY_MARKER_COLLECTION = "system";
87
+ const DEPLOY_MARKER_DOC = "deployDigest";
88
+ /**
89
+ * Sends the digest once per deployment version.
90
+ *
91
+ * Called from server startup. On Vercel that means EVERY lambda cold start,
92
+ * not once per deploy — so the version marker below is what makes this a
93
+ * per-deployment event rather than a per-cold-start email storm. The claim
94
+ * runs in a transaction because several cold starts can race on the first
95
+ * request after a deploy; exactly one wins and sends.
96
+ */
97
+ export async function runDeploymentDigest(ctx, version) {
98
+ if (!version)
99
+ return { sent: false, reason: "no_version" };
100
+ const markerRef = getAdminDb().collection(DEPLOY_MARKER_COLLECTION).doc(DEPLOY_MARKER_DOC);
101
+ let claimed = false;
102
+ try {
103
+ await getAdminDb().runTransaction(async (tx) => {
104
+ const snap = await tx.get(markerRef);
105
+ const lastVersion = snap.data()?.lastVersion;
106
+ if (lastVersion === version)
107
+ return;
108
+ tx.set(markerRef, { lastVersion: version, sentAt: new Date() }, { merge: true });
109
+ claimed = true;
110
+ });
111
+ }
112
+ catch (err) {
113
+ void normalizeError(err);
114
+ ctx.logger.warn("deploymentDigest: could not claim version marker — skipping", { version });
115
+ return { sent: false, reason: "claim_failed" };
116
+ }
117
+ if (!claimed)
118
+ return { sent: false, reason: "already_sent_for_version" };
119
+ ctx.logger.info("deploymentDigest: claimed version, sending", { version });
120
+ return runDailyStatusDigest(ctx, version);
121
+ }
122
+ export async function runDailyStatusDigest(ctx, version) {
123
+ const settings = await siteSettingsRepository.getSingleton().catch((err) => {
124
+ void normalizeError(err);
125
+ return null;
126
+ });
127
+ const digestConfig = settings?.emailSettings?.dailyDigest;
128
+ if (digestConfig?.enabled !== true) {
129
+ ctx.logger.info("dailyStatusDigest: disabled in site settings — skipping");
130
+ return { sent: false, reason: "disabled" };
131
+ }
132
+ const recipients = (digestConfig.recipients ?? []).filter((r) => r.trim().length > 0);
133
+ if (recipients.length === 0) {
134
+ ctx.logger.warn("dailyStatusDigest: enabled but no recipients configured — skipping");
135
+ return { sent: false, reason: "no_recipients" };
136
+ }
137
+ const ccRecipients = (digestConfig.ccRecipients ?? []).filter((r) => r.trim().length > 0);
138
+ const summary = await collectDailyStatusSummary();
139
+ // No hardcoded brand fallback — appkit is consumer-agnostic; the site name
140
+ // comes from settings or the consumer's own env var.
141
+ const siteName = settings?.siteName?.trim() || process.env.NEXT_PUBLIC_SITE_NAME?.trim() || "";
142
+ const { error } = await sendEmail({
143
+ to: recipients,
144
+ // Spread rather than `cc: undefined` — SendEmailOptions has a
145
+ // Record<string, JsonValue> index signature that rejects undefined.
146
+ ...(ccRecipients.length > 0 ? { cc: ccRecipients } : {}),
147
+ subject: "Daily Status",
148
+ html: renderDigestHtml(summary, siteName, version),
149
+ text: (version ? `Deployment ${version} is live.\n\n` : "") +
150
+ `Orders placed: ${summary.orderCount}\n` +
151
+ `Revenue: ${currency(summary.revenue)}\n` +
152
+ `Active listings: ${summary.activeListingCount}\n` +
153
+ `Pending > 24h: ${summary.stuckPendingCount}`,
154
+ });
155
+ if (error) {
156
+ ctx.logger.error("dailyStatusDigest: send failed", { error: String(error) });
157
+ throw new Error(`Daily status digest send failed: ${String(error)}`);
158
+ }
159
+ ctx.logger.info("dailyStatusDigest: sent", {
160
+ recipients: recipients.length,
161
+ orderCount: summary.orderCount,
162
+ });
163
+ return { sent: true, summary };
164
+ }