@mohasinac/appkit 3.0.4 → 3.1.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 (320) hide show
  1. package/dist/_internal/client/features/lottery/LotteryAdminEditView.d.ts +42 -0
  2. package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +86 -0
  3. package/dist/_internal/client/features/lottery/LotteryAdminSlotView.d.ts +14 -0
  4. package/dist/_internal/client/features/lottery/LotteryAdminSlotView.js +46 -0
  5. package/dist/_internal/client/features/lottery/LotteryDetailView.d.ts +28 -0
  6. package/dist/_internal/client/features/lottery/LotteryDetailView.js +17 -0
  7. package/dist/_internal/client/features/lottery/LotteryEntriesView.d.ts +23 -0
  8. package/dist/_internal/client/features/lottery/LotteryEntriesView.js +58 -0
  9. package/dist/_internal/client/features/lottery/LotteryListView.d.ts +21 -0
  10. package/dist/_internal/client/features/lottery/LotteryListView.js +25 -0
  11. package/dist/_internal/client/features/lottery/LotteryPullForm.d.ts +19 -0
  12. package/dist/_internal/client/features/lottery/LotteryPullForm.js +65 -0
  13. package/dist/_internal/client/features/lottery/LotterySlotGrid.d.ts +13 -0
  14. package/dist/_internal/client/features/lottery/LotterySlotGrid.js +21 -0
  15. package/dist/_internal/client/features/lottery/PrizeDrawLotteryDetailView.d.ts +28 -0
  16. package/dist/_internal/client/features/lottery/PrizeDrawLotteryDetailView.js +18 -0
  17. package/dist/_internal/server/features/auctions/__tests__/service.test.d.ts +1 -0
  18. package/dist/_internal/server/features/auctions/__tests__/service.test.js +140 -0
  19. package/dist/_internal/server/features/auctions/data.d.ts +2 -4
  20. package/dist/_internal/server/features/auctions/data.js +3 -9
  21. package/dist/_internal/server/features/checkout/__tests__/actions.test.d.ts +1 -0
  22. package/dist/_internal/server/features/checkout/__tests__/actions.test.js +600 -0
  23. package/dist/_internal/server/features/classified/adapters.d.ts +2 -15
  24. package/dist/_internal/server/features/classified/adapters.js +2 -17
  25. package/dist/_internal/server/features/classified/data.d.ts +1 -6
  26. package/dist/_internal/server/features/classified/data.js +2 -10
  27. package/dist/_internal/server/features/digital-code/adapters.d.ts +2 -15
  28. package/dist/_internal/server/features/digital-code/adapters.js +2 -17
  29. package/dist/_internal/server/features/digital-code/data.d.ts +1 -6
  30. package/dist/_internal/server/features/digital-code/data.js +2 -10
  31. package/dist/_internal/server/features/live/adapters.d.ts +2 -15
  32. package/dist/_internal/server/features/live/adapters.js +2 -17
  33. package/dist/_internal/server/features/live/data.d.ts +1 -6
  34. package/dist/_internal/server/features/live/data.js +2 -10
  35. package/dist/_internal/server/features/lottery/actions.d.ts +43 -0
  36. package/dist/_internal/server/features/lottery/actions.js +243 -0
  37. package/dist/_internal/server/features/lottery/adapters.d.ts +9 -0
  38. package/dist/_internal/server/features/lottery/adapters.js +21 -0
  39. package/dist/_internal/server/features/lottery/data.d.ts +20 -0
  40. package/dist/_internal/server/features/lottery/data.js +41 -0
  41. package/dist/_internal/server/features/lottery/metadata.d.ts +6 -0
  42. package/dist/_internal/server/features/lottery/metadata.js +31 -0
  43. package/dist/_internal/server/features/pre-orders/data.d.ts +2 -4
  44. package/dist/_internal/server/features/pre-orders/data.js +3 -9
  45. package/dist/_internal/server/features/prize-draws/actions.d.ts +2 -0
  46. package/dist/_internal/server/features/prize-draws/actions.js +22 -0
  47. package/dist/_internal/server/features/prize-draws/data.d.ts +1 -17
  48. package/dist/_internal/server/features/prize-draws/data.js +2 -20
  49. package/dist/_internal/server/features/prize-draws/index.d.ts +3 -1
  50. package/dist/_internal/server/features/prize-draws/index.js +2 -0
  51. package/dist/_internal/server/features/prize-draws/service.d.ts +3 -0
  52. package/dist/_internal/server/features/prize-draws/service.js +19 -0
  53. package/dist/_internal/server/features/refunds/__tests__/actions.test.d.ts +1 -0
  54. package/dist/_internal/server/features/refunds/__tests__/actions.test.js +263 -0
  55. package/dist/_internal/server/features/shared/listing-adapters.d.ts +19 -0
  56. package/dist/_internal/server/features/shared/listing-adapters.js +20 -0
  57. package/dist/_internal/server/features/shared/listing-data-factory.d.ts +9 -0
  58. package/dist/_internal/server/features/shared/listing-data-factory.js +33 -0
  59. package/dist/_internal/server/features/stores/data.d.ts +3 -14
  60. package/dist/_internal/server/features/stores/data.js +6 -44
  61. package/dist/_internal/server/jobs/core/__tests__/auctionSettlement.test.d.ts +1 -0
  62. package/dist/_internal/server/jobs/core/__tests__/auctionSettlement.test.js +249 -0
  63. package/dist/_internal/server/jobs/core/__tests__/onBidPlaced.test.d.ts +1 -0
  64. package/dist/_internal/server/jobs/core/__tests__/onBidPlaced.test.js +201 -0
  65. package/dist/_internal/server/jobs/core/__tests__/onOrderCreate.test.d.ts +1 -0
  66. package/dist/_internal/server/jobs/core/__tests__/onOrderCreate.test.js +169 -0
  67. package/dist/_internal/server/jobs/core/__tests__/onOrderStatusChange.test.d.ts +1 -0
  68. package/dist/_internal/server/jobs/core/__tests__/onOrderStatusChange.test.js +148 -0
  69. package/dist/_internal/server/jobs/core/__tests__/onProductStockChange.test.d.ts +1 -0
  70. package/dist/_internal/server/jobs/core/__tests__/onProductStockChange.test.js +210 -0
  71. package/dist/_internal/server/jobs/core/__tests__/onReviewWrite.test.d.ts +1 -0
  72. package/dist/_internal/server/jobs/core/__tests__/onReviewWrite.test.js +190 -0
  73. package/dist/_internal/server/jobs/core/__tests__/onUserBanChange.test.d.ts +1 -0
  74. package/dist/_internal/server/jobs/core/__tests__/onUserBanChange.test.js +161 -0
  75. package/dist/_internal/server/jobs/core/__tests__/payoutBatch.test.d.ts +1 -0
  76. package/dist/_internal/server/jobs/core/__tests__/payoutBatch.test.js +302 -0
  77. package/dist/_internal/server/jobs/core/__tests__/triggerEventRaffle.test.d.ts +1 -0
  78. package/dist/_internal/server/jobs/core/__tests__/triggerEventRaffle.test.js +252 -0
  79. package/dist/_internal/server/jobs/core/__tests__/wrapJobHandler.test.d.ts +1 -0
  80. package/dist/_internal/server/jobs/core/__tests__/wrapJobHandler.test.js +129 -0
  81. package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
  82. package/dist/_internal/shared/actions/action-registry.js +46 -0
  83. package/dist/_internal/shared/features/cart/schema.d.ts +8 -8
  84. package/dist/_internal/shared/features/cart/schema.js +3 -0
  85. package/dist/_internal/shared/features/products/schema.d.ts +8 -8
  86. package/dist/_internal/shared/listing-types/_registry.js +2 -0
  87. package/dist/_internal/shared/listing-types/auction/schema.d.ts +3 -1
  88. package/dist/_internal/shared/listing-types/auction/schema.js +7 -1
  89. package/dist/_internal/shared/listing-types/classified/schema.d.ts +2 -1
  90. package/dist/_internal/shared/listing-types/classified/schema.js +3 -1
  91. package/dist/_internal/shared/listing-types/digital-code/schema.d.ts +3 -1
  92. package/dist/_internal/shared/listing-types/digital-code/schema.js +7 -1
  93. package/dist/_internal/shared/listing-types/live/schema.d.ts +2 -1
  94. package/dist/_internal/shared/listing-types/live/schema.js +3 -1
  95. package/dist/_internal/shared/listing-types/pre-order/schema.d.ts +3 -1
  96. package/dist/_internal/shared/listing-types/pre-order/schema.js +7 -1
  97. package/dist/_internal/shared/listing-types/prize-draw/schema.d.ts +3 -1
  98. package/dist/_internal/shared/listing-types/prize-draw/schema.js +13 -1
  99. package/dist/_internal/shared/listing-types/standard/schema.d.ts +2 -1
  100. package/dist/_internal/shared/listing-types/standard/schema.js +4 -1
  101. package/dist/_internal/shared/types/base-document.d.ts +15 -0
  102. package/dist/_internal/shared/types/base-document.js +1 -0
  103. package/dist/_internal/shared/types/index.d.ts +2 -0
  104. package/dist/_internal/shared/types/index.js +1 -0
  105. package/dist/client.d.ts +13 -4
  106. package/dist/client.js +11 -2
  107. package/dist/constants/api-endpoints.d.ts +12 -0
  108. package/dist/constants/api-endpoints.js +4 -0
  109. package/dist/constants/field-names.d.ts +5 -1
  110. package/dist/constants/field-names.js +5 -1
  111. package/dist/features/addresses/repository/__tests__/addresses.repository.test.d.ts +1 -0
  112. package/dist/features/addresses/repository/__tests__/addresses.repository.test.js +386 -0
  113. package/dist/features/addresses/schemas/firestore.d.ts +2 -4
  114. package/dist/features/admin/api/bids/route.d.ts +2 -2
  115. package/dist/features/admin/api/coupons/route.d.ts +2 -2
  116. package/dist/features/admin/api/products/route.d.ts +2 -2
  117. package/dist/features/admin/api/reviews/route.d.ts +2 -2
  118. package/dist/features/admin/components/AdminFulfillmentView.d.ts +6 -0
  119. package/dist/features/admin/components/AdminFulfillmentView.js +107 -0
  120. package/dist/features/admin/components/AdminProductEditorView.js +21 -9
  121. package/dist/features/admin/components/AdminProductsView.js +3 -0
  122. package/dist/features/admin/components/DataListingView.d.ts +1 -0
  123. package/dist/features/admin/components/index.d.ts +2 -0
  124. package/dist/features/admin/components/index.js +1 -0
  125. package/dist/features/admin/repository/__tests__/notification.repository.test.d.ts +1 -0
  126. package/dist/features/admin/repository/__tests__/notification.repository.test.js +356 -0
  127. package/dist/features/admin/repository/__tests__/site-settings.repository.test.d.ts +1 -0
  128. package/dist/features/admin/repository/__tests__/site-settings.repository.test.js +298 -0
  129. package/dist/features/admin/schemas/firestore.d.ts +3 -8
  130. package/dist/features/auctions/repository/__tests__/bid.repository.test.d.ts +1 -0
  131. package/dist/features/auctions/repository/__tests__/bid.repository.test.js +290 -0
  132. package/dist/features/auctions/schemas/firestore.d.ts +2 -4
  133. package/dist/features/auctions/schemas/index.d.ts +2 -2
  134. package/dist/features/auth/api/route.d.ts +2 -2
  135. package/dist/features/auth/repository/__tests__/session.repository.test.d.ts +1 -0
  136. package/dist/features/auth/repository/__tests__/session.repository.test.js +310 -0
  137. package/dist/features/auth/repository/__tests__/session.test.d.ts +1 -0
  138. package/dist/features/auth/repository/__tests__/session.test.js +146 -0
  139. package/dist/features/auth/repository/__tests__/sms-counter.repository.test.d.ts +1 -0
  140. package/dist/features/auth/repository/__tests__/sms-counter.repository.test.js +171 -0
  141. package/dist/features/auth/repository/__tests__/sms-counter.test.d.ts +1 -0
  142. package/dist/features/auth/repository/__tests__/sms-counter.test.js +88 -0
  143. package/dist/features/auth/repository/__tests__/token.repository.test.d.ts +1 -0
  144. package/dist/features/auth/repository/__tests__/token.repository.test.js +260 -0
  145. package/dist/features/auth/repository/__tests__/token.test.d.ts +1 -0
  146. package/dist/features/auth/repository/__tests__/token.test.js +140 -0
  147. package/dist/features/auth/repository/__tests__/user.repository.test.d.ts +1 -0
  148. package/dist/features/auth/repository/__tests__/user.repository.test.js +352 -0
  149. package/dist/features/auth/repository/__tests__/user.test.d.ts +1 -0
  150. package/dist/features/auth/repository/__tests__/user.test.js +226 -0
  151. package/dist/features/auth/repository/session.repository.js +10 -1
  152. package/dist/features/before-after/schemas/index.d.ts +2 -2
  153. package/dist/features/blog/schemas/firestore.d.ts +2 -4
  154. package/dist/features/blog/schemas/index.d.ts +4 -4
  155. package/dist/features/cart/repository/__tests__/cart.repository.test.d.ts +1 -0
  156. package/dist/features/cart/repository/__tests__/cart.repository.test.js +371 -0
  157. package/dist/features/cart/repository/cart.repository.js +2 -2
  158. package/dist/features/cart/schemas/firestore.d.ts +2 -4
  159. package/dist/features/categories/api/[id]/route.d.ts +4 -4
  160. package/dist/features/categories/api/route.d.ts +2 -2
  161. package/dist/features/categories/repository/__tests__/categories.repository.test.d.ts +1 -0
  162. package/dist/features/categories/repository/__tests__/categories.repository.test.js +813 -0
  163. package/dist/features/categories/schemas/firestore.d.ts +2 -4
  164. package/dist/features/categories/schemas/index.d.ts +4 -4
  165. package/dist/features/events/components/EventCard.js +1 -0
  166. package/dist/features/events/repository/__tests__/event.repository.test.d.ts +1 -0
  167. package/dist/features/events/repository/__tests__/event.repository.test.js +299 -0
  168. package/dist/features/events/schemas/firestore.d.ts +5 -4
  169. package/dist/features/events/schemas/index.d.ts +836 -16
  170. package/dist/features/events/schemas/index.js +80 -1
  171. package/dist/features/events/types/index.d.ts +4 -1
  172. package/dist/features/faq/repository/__tests__/faqs.repository.test.d.ts +1 -0
  173. package/dist/features/faq/repository/__tests__/faqs.repository.test.js +311 -0
  174. package/dist/features/faq/schemas/firestore.d.ts +2 -4
  175. package/dist/features/faq/schemas/index.d.ts +2 -2
  176. package/dist/features/grouped/schemas/index.d.ts +2 -2
  177. package/dist/features/history/repository/__tests__/user-history.repository.test.d.ts +1 -0
  178. package/dist/features/history/repository/__tests__/user-history.repository.test.js +180 -0
  179. package/dist/features/homepage/api/[id]/route.d.ts +4 -4
  180. package/dist/features/homepage/api/carousel/[id]/route.d.ts +4 -4
  181. package/dist/features/homepage/api/carousel/route.d.ts +2 -2
  182. package/dist/features/homepage/api/route.d.ts +2 -2
  183. package/dist/features/homepage/repository/__tests__/carousel.repository.test.d.ts +1 -0
  184. package/dist/features/homepage/repository/__tests__/carousel.repository.test.js +182 -0
  185. package/dist/features/homepage/repository/__tests__/homepage-sections.repository.test.d.ts +1 -0
  186. package/dist/features/homepage/repository/__tests__/homepage-sections.repository.test.js +185 -0
  187. package/dist/features/homepage/schemas/firestore.d.ts +4 -12
  188. package/dist/features/homepage/schemas/index.d.ts +2 -2
  189. package/dist/features/lottery/repository/lottery-entry.repository.d.ts +33 -0
  190. package/dist/features/lottery/repository/lottery-entry.repository.js +130 -0
  191. package/dist/features/lottery/schemas/firestore.d.ts +49 -0
  192. package/dist/features/lottery/schemas/firestore.js +25 -0
  193. package/dist/features/lottery/schemas/zod.d.ts +113 -0
  194. package/dist/features/lottery/schemas/zod.js +39 -0
  195. package/dist/features/lottery/types/index.d.ts +67 -0
  196. package/dist/features/lottery/types/index.js +55 -0
  197. package/dist/features/messages/repository/__tests__/conversations.repository.test.d.ts +1 -0
  198. package/dist/features/messages/repository/__tests__/conversations.repository.test.js +257 -0
  199. package/dist/features/messages/schemas/firestore.d.ts +2 -4
  200. package/dist/features/messages/schemas/index.d.ts +2 -2
  201. package/dist/features/orders/repository/__tests__/orders.repository.test.d.ts +1 -0
  202. package/dist/features/orders/repository/__tests__/orders.repository.test.js +211 -0
  203. package/dist/features/orders/repository/orders.repository.d.ts +5 -0
  204. package/dist/features/orders/repository/orders.repository.js +26 -0
  205. package/dist/features/orders/schemas/firestore.d.ts +9 -5
  206. package/dist/features/orders/schemas/firestore.js +3 -0
  207. package/dist/features/payments/repository/__tests__/payout.repository.test.d.ts +1 -0
  208. package/dist/features/payments/repository/__tests__/payout.repository.test.js +292 -0
  209. package/dist/features/payments/schemas/firestore.d.ts +2 -4
  210. package/dist/features/pre-orders/schemas/index.d.ts +2 -2
  211. package/dist/features/products/api/[id]/route.d.ts +4 -4
  212. package/dist/features/products/api/route.d.ts +2 -2
  213. package/dist/features/products/constants/action-defs.d.ts +16 -0
  214. package/dist/features/products/constants/action-defs.js +16 -0
  215. package/dist/features/products/constants/listing-tabs.d.ts +48 -0
  216. package/dist/features/products/constants/listing-tabs.js +12 -0
  217. package/dist/features/products/repository/__tests__/product-features.repository.test.d.ts +1 -0
  218. package/dist/features/products/repository/__tests__/product-features.repository.test.js +329 -0
  219. package/dist/features/products/repository/__tests__/products.repository.test.d.ts +1 -0
  220. package/dist/features/products/repository/__tests__/products.repository.test.js +607 -0
  221. package/dist/features/products/repository/products.repository.d.ts +37 -0
  222. package/dist/features/products/repository/products.repository.js +28 -1
  223. package/dist/features/products/schemas/firestore.d.ts +23 -7
  224. package/dist/features/products/schemas/firestore.js +2 -0
  225. package/dist/features/products/schemas/index.d.ts +18 -18
  226. package/dist/features/products/schemas/index.js +4 -2
  227. package/dist/features/products/types/index.d.ts +3 -1
  228. package/dist/features/promotions/repository/__tests__/claimed-coupons.repository.test.d.ts +1 -0
  229. package/dist/features/promotions/repository/__tests__/claimed-coupons.repository.test.js +219 -0
  230. package/dist/features/promotions/repository/__tests__/coupons.repository.test.d.ts +1 -0
  231. package/dist/features/promotions/repository/__tests__/coupons.repository.test.js +480 -0
  232. package/dist/features/promotions/schemas/firestore.d.ts +2 -4
  233. package/dist/features/promotions/schemas/index.d.ts +4 -4
  234. package/dist/features/reviews/api/[id]/route.d.ts +4 -4
  235. package/dist/features/reviews/api/route.d.ts +2 -2
  236. package/dist/features/reviews/repository/__tests__/reviews.repository.test.d.ts +1 -0
  237. package/dist/features/reviews/repository/__tests__/reviews.repository.test.js +327 -0
  238. package/dist/features/reviews/schemas/firestore.d.ts +2 -4
  239. package/dist/features/reviews/schemas/index.d.ts +2 -2
  240. package/dist/features/scams/repository/__tests__/scammer.repository.test.d.ts +1 -0
  241. package/dist/features/scams/repository/__tests__/scammer.repository.test.js +385 -0
  242. package/dist/features/scams/schemas/firestore.d.ts +2 -4
  243. package/dist/features/scams/schemas/index.d.ts +4 -4
  244. package/dist/features/search/repository/__tests__/search.repository.test.d.ts +1 -0
  245. package/dist/features/search/repository/__tests__/search.repository.test.js +369 -0
  246. package/dist/features/search/schemas/index.d.ts +2 -2
  247. package/dist/features/seller/api/coupons/route.d.ts +2 -2
  248. package/dist/features/seller/api/offers/route.d.ts +2 -2
  249. package/dist/features/seller/api/products/route.d.ts +2 -2
  250. package/dist/features/seller/api/store/route.d.ts +2 -2
  251. package/dist/features/seller/components/BarcodeField.d.ts +17 -0
  252. package/dist/features/seller/components/BarcodeField.js +30 -0
  253. package/dist/features/seller/components/FulfillmentView.d.ts +5 -0
  254. package/dist/features/seller/components/FulfillmentView.js +120 -0
  255. package/dist/features/seller/components/PrintCenterView.d.ts +3 -1
  256. package/dist/features/seller/components/PrintCenterView.js +52 -4
  257. package/dist/features/seller/components/SellerProductShell.d.ts +2 -0
  258. package/dist/features/seller/components/SellerProductShell.js +2 -1
  259. package/dist/features/seller/components/index.d.ts +4 -0
  260. package/dist/features/seller/components/index.js +2 -0
  261. package/dist/features/seller/repository/__tests__/offer.repository.test.d.ts +1 -0
  262. package/dist/features/seller/repository/__tests__/offer.repository.test.js +458 -0
  263. package/dist/features/seller/schemas/index.d.ts +2 -2
  264. package/dist/features/store-extensions/schemas/firestore.d.ts +12 -44
  265. package/dist/features/stores/components/StoreClassifiedsListing.d.ts +5 -0
  266. package/dist/features/stores/components/StoreClassifiedsListing.js +48 -0
  267. package/dist/features/stores/components/StoreClassifiedsPageView.d.ts +4 -0
  268. package/dist/features/stores/components/StoreClassifiedsPageView.js +20 -0
  269. package/dist/features/stores/components/StoreDetailLayoutView.js +23 -2
  270. package/dist/features/stores/components/StoreDigitalCodesListing.d.ts +5 -0
  271. package/dist/features/stores/components/StoreDigitalCodesListing.js +48 -0
  272. package/dist/features/stores/components/StoreDigitalCodesPageView.d.ts +4 -0
  273. package/dist/features/stores/components/StoreDigitalCodesPageView.js +20 -0
  274. package/dist/features/stores/components/StoreLiveItemsListing.d.ts +5 -0
  275. package/dist/features/stores/components/StoreLiveItemsListing.js +48 -0
  276. package/dist/features/stores/components/StoreLiveItemsPageView.d.ts +4 -0
  277. package/dist/features/stores/components/StoreLiveItemsPageView.js +20 -0
  278. package/dist/features/stores/components/index.d.ts +9 -0
  279. package/dist/features/stores/components/index.js +3 -0
  280. package/dist/features/stores/repository/__tests__/store.repository.test.d.ts +1 -0
  281. package/dist/features/stores/repository/__tests__/store.repository.test.js +261 -0
  282. package/dist/features/stores/schemas/firestore.d.ts +2 -4
  283. package/dist/features/stores/schemas/index.d.ts +4 -4
  284. package/dist/features/support/repository/__tests__/support.repository.test.d.ts +1 -0
  285. package/dist/features/support/repository/__tests__/support.repository.test.js +312 -0
  286. package/dist/features/support/schemas/firestore.d.ts +2 -4
  287. package/dist/features/support/schemas/index.d.ts +2 -2
  288. package/dist/features/wishlist/repository/__tests__/user-wishlist.repository.test.d.ts +1 -0
  289. package/dist/features/wishlist/repository/__tests__/user-wishlist.repository.test.js +139 -0
  290. package/dist/index.d.ts +14 -0
  291. package/dist/index.js +17 -0
  292. package/dist/next/api/routeHandler.d.ts +1 -1
  293. package/dist/next/routing/route-map.d.ts +24 -0
  294. package/dist/next/routing/route-map.js +11 -0
  295. package/dist/repositories/index.d.ts +1 -0
  296. package/dist/repositories/index.js +2 -0
  297. package/dist/schemas/registry.d.ts +24 -24
  298. package/dist/security/index.d.ts +1 -1
  299. package/dist/security/index.js +1 -1
  300. package/dist/security/pii-schemas.d.ts +2 -0
  301. package/dist/security/pii-schemas.js +6 -0
  302. package/dist/seed/actions/demo-seed-actions.d.ts +1 -1
  303. package/dist/seed/events-seed-data.js +85 -2
  304. package/dist/seed/grouped-listings-seed-data.d.ts +5 -2
  305. package/dist/seed/index.d.ts +1 -0
  306. package/dist/seed/index.js +1 -0
  307. package/dist/seed/lottery-entries-seed-data.d.ts +2 -0
  308. package/dist/seed/lottery-entries-seed-data.js +108 -0
  309. package/dist/seed/manifest.js +1 -0
  310. package/dist/seed/products-preorders-seed-data.d.ts +5 -2
  311. package/dist/seed/products-standard-seed-data.js +8 -0
  312. package/dist/server-entry.d.ts +3 -0
  313. package/dist/server-entry.js +3 -0
  314. package/dist/server.d.ts +10 -4
  315. package/dist/server.js +6 -0
  316. package/dist/styles.css +1 -1
  317. package/dist/tailwind-utilities.css +1 -1
  318. package/dist/utils/id-generators.d.ts +8 -0
  319. package/dist/utils/id-generators.js +14 -0
  320. package/package.json +2 -1
@@ -0,0 +1,261 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ import { makeMockDb, makeSnap, makeQuerySnap } from "../../../../../tests/helpers/mock-firestore";
3
+ import { DatabaseError } from "../../../../errors";
4
+ const { db, mockDocRef, mockCollection, mockQuery, mockBatch } = makeMockDb();
5
+ vi.mock("../../../../providers/db-firebase/admin", () => ({
6
+ getAdminDb: () => db,
7
+ }));
8
+ vi.mock("../../../../providers/db-firebase", async (importOriginal) => {
9
+ const actual = await importOriginal();
10
+ return {
11
+ ...actual,
12
+ prepareForFirestore: (d) => d,
13
+ };
14
+ });
15
+ vi.mock("../../../../security/settings-encryption", () => ({
16
+ encryptSecret: (v) => `enc:${v}`,
17
+ decryptSecret: (v) => v.replace(/^enc:/, ""),
18
+ }));
19
+ vi.mock("../../../../errors/normalize", () => ({
20
+ normalizeError: vi.fn(),
21
+ }));
22
+ import { StoreRepository } from "../store.repository";
23
+ const repo = new StoreRepository();
24
+ function makeStoreDoc(overrides = {}) {
25
+ return {
26
+ id: "store-test",
27
+ storeSlug: "store-test",
28
+ ownerId: "uid-seller-1",
29
+ storeName: "Test Store",
30
+ status: "active",
31
+ isPublic: true,
32
+ isVerified: false,
33
+ createdAt: new Date(),
34
+ updatedAt: new Date(),
35
+ stats: { totalProducts: 0, itemsSold: 0, totalReviews: 0, averageRating: 0 },
36
+ ...overrides,
37
+ };
38
+ }
39
+ function makeCreateInput(overrides = {}) {
40
+ return {
41
+ storeSlug: "store-test",
42
+ ownerId: "uid-seller-1",
43
+ storeName: "Test Store",
44
+ status: "pending",
45
+ isPublic: false,
46
+ ...overrides,
47
+ };
48
+ }
49
+ beforeEach(() => {
50
+ vi.clearAllMocks();
51
+ db.collection.mockReturnValue(mockCollection);
52
+ mockCollection.doc.mockReturnValue(mockDocRef);
53
+ mockCollection.where.mockReturnValue(mockQuery);
54
+ mockQuery.where.mockReturnValue(mockQuery);
55
+ mockQuery.orderBy.mockReturnValue(mockQuery);
56
+ mockQuery.limit.mockReturnValue(mockQuery);
57
+ mockQuery.get.mockResolvedValue(makeQuerySnap([]));
58
+ mockDocRef.get.mockResolvedValue(makeSnap(null));
59
+ mockDocRef.create.mockResolvedValue(undefined);
60
+ mockDocRef.set.mockResolvedValue(undefined);
61
+ mockDocRef.update.mockResolvedValue(undefined);
62
+ mockDocRef.delete.mockResolvedValue(undefined);
63
+ db.batch.mockReturnValue(mockBatch);
64
+ });
65
+ // ---------------------------------------------------------------------------
66
+ // create
67
+ // ---------------------------------------------------------------------------
68
+ describe("StoreRepository.create", () => {
69
+ it("throws when storeSlug equals ownerId", async () => {
70
+ const input = makeCreateInput({ storeSlug: "uid-same", ownerId: "uid-same" });
71
+ await expect(repo.create(input)).rejects.toThrow(DatabaseError);
72
+ });
73
+ it("creates document using .create() semantics (not .set())", async () => {
74
+ await repo.create(makeCreateInput());
75
+ expect(mockDocRef.create).toHaveBeenCalledOnce();
76
+ expect(mockDocRef.set).not.toHaveBeenCalled();
77
+ });
78
+ it("sets document ID to storeSlug", async () => {
79
+ await repo.create(makeCreateInput({ storeSlug: "store-pokemon-palace" }));
80
+ expect(mockCollection.doc).toHaveBeenCalledWith("store-pokemon-palace");
81
+ });
82
+ it("throws DatabaseError(slug already taken) when .create() fails with gRPC code 6", async () => {
83
+ const grpcAlreadyExists = Object.assign(new Error("ALREADY_EXISTS"), { code: 6 });
84
+ mockDocRef.create.mockRejectedValue(grpcAlreadyExists);
85
+ await expect(repo.create(makeCreateInput({ storeSlug: "store-taken" }))).rejects.toThrow(DatabaseError);
86
+ });
87
+ it("re-throws non-ALREADY_EXISTS errors as-is", async () => {
88
+ const networkErr = new Error("NETWORK_FAILURE");
89
+ mockDocRef.create.mockRejectedValue(networkErr);
90
+ await expect(repo.create(makeCreateInput())).rejects.toThrow("NETWORK_FAILURE");
91
+ });
92
+ it("returns the store document with id=storeSlug", async () => {
93
+ const result = await repo.create(makeCreateInput({ storeSlug: "store-abc" }));
94
+ expect(result.id).toBe("store-abc");
95
+ expect(result.storeSlug).toBe("store-abc");
96
+ });
97
+ it("encrypts whatsappConfig.accessToken before writing", async () => {
98
+ const input = makeCreateInput({
99
+ whatsappConfig: { accessToken: "secret-token", phoneNumberId: "ph-1", businessId: "biz-1" },
100
+ });
101
+ await repo.create(input);
102
+ const callArg = mockDocRef.create.mock.calls[0][0];
103
+ const config = callArg.whatsappConfig;
104
+ expect(config.accessToken).toBe("enc:secret-token");
105
+ });
106
+ });
107
+ // ---------------------------------------------------------------------------
108
+ // isSlugAvailable
109
+ // ---------------------------------------------------------------------------
110
+ describe("StoreRepository.isSlugAvailable", () => {
111
+ it("returns true when no document exists for that slug", async () => {
112
+ mockDocRef.get.mockResolvedValue(makeSnap(null));
113
+ const result = await repo.isSlugAvailable("store-new");
114
+ expect(result).toBe(true);
115
+ });
116
+ it("returns false when a document exists for that slug", async () => {
117
+ const store = makeStoreDoc();
118
+ mockDocRef.get.mockResolvedValue(makeSnap(store, "store-test"));
119
+ const result = await repo.isSlugAvailable("store-test");
120
+ expect(result).toBe(false);
121
+ });
122
+ });
123
+ // ---------------------------------------------------------------------------
124
+ // findByOwnerId
125
+ // ---------------------------------------------------------------------------
126
+ describe("StoreRepository.findByOwnerId", () => {
127
+ it("returns store when found", async () => {
128
+ const store = makeStoreDoc();
129
+ mockQuery.get.mockResolvedValue(makeQuerySnap([{ id: store.id, data: store }]));
130
+ const result = await repo.findByOwnerId("uid-seller-1");
131
+ expect(result).not.toBeNull();
132
+ });
133
+ it("queries by ownerId field", async () => {
134
+ mockQuery.get.mockResolvedValue(makeQuerySnap([]));
135
+ await repo.findByOwnerId("uid-seller-1");
136
+ expect(mockCollection.where).toHaveBeenCalledWith("ownerId", "==", "uid-seller-1");
137
+ });
138
+ it("returns null when no store matches", async () => {
139
+ mockQuery.get.mockResolvedValue(makeQuerySnap([]));
140
+ const result = await repo.findByOwnerId("uid-nobody");
141
+ expect(result).toBeNull();
142
+ });
143
+ });
144
+ // ---------------------------------------------------------------------------
145
+ // setStatus
146
+ // ---------------------------------------------------------------------------
147
+ describe("StoreRepository.setStatus", () => {
148
+ it("status=active → sets isPublic: true", async () => {
149
+ const store = makeStoreDoc({ status: "pending", isPublic: false });
150
+ mockDocRef.get.mockResolvedValue(makeSnap(store, "store-test"));
151
+ await repo.setStatus("store-test", "active");
152
+ expect(mockDocRef.update).toHaveBeenCalledWith(expect.objectContaining({ status: "active", isPublic: true }));
153
+ });
154
+ it("status=suspended → sets isPublic: false", async () => {
155
+ const store = makeStoreDoc({ status: "active", isPublic: true });
156
+ mockDocRef.get.mockResolvedValue(makeSnap(store, "store-test"));
157
+ await repo.setStatus("store-test", "suspended");
158
+ expect(mockDocRef.update).toHaveBeenCalledWith(expect.objectContaining({ status: "suspended", isPublic: false }));
159
+ });
160
+ it("status=pending → sets isPublic: false", async () => {
161
+ const store = makeStoreDoc({ status: "active", isPublic: true });
162
+ mockDocRef.get.mockResolvedValue(makeSnap(store, "store-test"));
163
+ await repo.setStatus("store-test", "pending");
164
+ expect(mockDocRef.update).toHaveBeenCalledWith(expect.objectContaining({ status: "pending", isPublic: false }));
165
+ });
166
+ it("status=rejected → sets isPublic: false", async () => {
167
+ const store = makeStoreDoc({ status: "active", isPublic: true });
168
+ mockDocRef.get.mockResolvedValue(makeSnap(store, "store-test"));
169
+ await repo.setStatus("store-test", "rejected");
170
+ expect(mockDocRef.update).toHaveBeenCalledWith(expect.objectContaining({ isPublic: false }));
171
+ });
172
+ });
173
+ // ---------------------------------------------------------------------------
174
+ // incrementTotalProducts
175
+ // ---------------------------------------------------------------------------
176
+ describe("StoreRepository.incrementTotalProducts", () => {
177
+ it("calls update with increment on stats.totalProducts", async () => {
178
+ await repo.incrementTotalProducts("store-1", 1);
179
+ expect(mockDocRef.update).toHaveBeenCalledWith(expect.objectContaining({ "stats.totalProducts": expect.anything() }));
180
+ });
181
+ it("no-op when storeId is empty string", async () => {
182
+ await repo.incrementTotalProducts("", 1);
183
+ expect(mockDocRef.update).not.toHaveBeenCalled();
184
+ });
185
+ it("accepts negative delta (decrement)", async () => {
186
+ await repo.incrementTotalProducts("store-1", -1);
187
+ expect(mockDocRef.update).toHaveBeenCalledOnce();
188
+ });
189
+ });
190
+ // ---------------------------------------------------------------------------
191
+ // updateReviewStats
192
+ // ---------------------------------------------------------------------------
193
+ describe("StoreRepository.updateReviewStats", () => {
194
+ it("updates totalReviews and averageRating on the store doc", async () => {
195
+ await repo.updateReviewStats("store-1", 10, 4.5);
196
+ expect(mockDocRef.update).toHaveBeenCalledWith(expect.objectContaining({
197
+ "stats.totalReviews": 10,
198
+ "stats.averageRating": 4.5,
199
+ }));
200
+ });
201
+ it("no-op when storeId is empty string", async () => {
202
+ await repo.updateReviewStats("", 10, 4.5);
203
+ expect(mockDocRef.update).not.toHaveBeenCalled();
204
+ });
205
+ });
206
+ // ---------------------------------------------------------------------------
207
+ // changeSlug
208
+ // ---------------------------------------------------------------------------
209
+ describe("StoreRepository.changeSlug", () => {
210
+ it("throws when currentSlug === newSlug", async () => {
211
+ await expect(repo.changeSlug("store-same", "store-same")).rejects.toThrow(DatabaseError);
212
+ });
213
+ it("throws when newSlug is empty", async () => {
214
+ await expect(repo.changeSlug("store-old", "")).rejects.toThrow(DatabaseError);
215
+ });
216
+ it("throws when newSlug contains invalid characters (uppercase)", async () => {
217
+ await expect(repo.changeSlug("store-old", "Store-BAD")).rejects.toThrow(DatabaseError);
218
+ });
219
+ it("throws when current store is not found", async () => {
220
+ mockDocRef.get.mockResolvedValue(makeSnap(null));
221
+ await expect(repo.changeSlug("store-ghost", "store-new")).rejects.toThrow(DatabaseError);
222
+ });
223
+ it("throws when newSlug is already taken", async () => {
224
+ const currentStore = makeStoreDoc({ storeSlug: "store-old" });
225
+ const takenStore = makeStoreDoc({ storeSlug: "store-taken", id: "store-taken" });
226
+ mockDocRef.get
227
+ .mockResolvedValueOnce(makeSnap(currentStore, "store-old")) // findById(currentSlug)
228
+ .mockResolvedValueOnce(makeSnap(takenStore, "store-taken")); // isSlugAvailable check
229
+ await expect(repo.changeSlug("store-old", "store-taken")).rejects.toThrow(DatabaseError);
230
+ });
231
+ it("atomically creates new doc and deletes old doc in one batch", async () => {
232
+ const currentStore = makeStoreDoc({ storeSlug: "store-old" });
233
+ mockDocRef.get
234
+ .mockResolvedValueOnce(makeSnap(currentStore, "store-old")) // findById(currentSlug)
235
+ .mockResolvedValueOnce(makeSnap(null)); // isSlugAvailable(newSlug) → available
236
+ await repo.changeSlug("store-old", "store-new");
237
+ expect(mockBatch.create).toHaveBeenCalledOnce();
238
+ expect(mockBatch.delete).toHaveBeenCalledOnce();
239
+ expect(mockBatch.commit).toHaveBeenCalledOnce();
240
+ });
241
+ it("returns result with id=newSlug and storeSlug=newSlug", async () => {
242
+ const currentStore = makeStoreDoc({ storeSlug: "store-old" });
243
+ mockDocRef.get
244
+ .mockResolvedValueOnce(makeSnap(currentStore, "store-old"))
245
+ .mockResolvedValueOnce(makeSnap(null));
246
+ const result = await repo.changeSlug("store-old", "store-new");
247
+ expect(result.id).toBe("store-new");
248
+ expect(result.storeSlug).toBe("store-new");
249
+ });
250
+ it("creates new doc at newSlug path, deletes old doc at currentSlug path", async () => {
251
+ const currentStore = makeStoreDoc({ storeSlug: "store-old" });
252
+ mockDocRef.get
253
+ .mockResolvedValueOnce(makeSnap(currentStore, "store-old"))
254
+ .mockResolvedValueOnce(makeSnap(null));
255
+ await repo.changeSlug("store-old", "store-new");
256
+ // doc() was called for newSlug and currentSlug
257
+ const docCalls = mockCollection.doc.mock.calls.map((c) => c[0]);
258
+ expect(docCalls).toContain("store-new");
259
+ expect(docCalls).toContain("store-old");
260
+ });
261
+ });
@@ -5,6 +5,7 @@
5
5
  * and helpers for the stores feature.
6
6
  */
7
7
  import type { StoreCapability } from "../../auth/permissions/constants";
8
+ import type { BaseDocument } from "../../../_internal/shared/types/base-document";
8
9
  export type ShippingProviderType = "shiprocket" | "self-courier" | "store-pickup" | "custom";
9
10
  export interface ShippingProviderConfig {
10
11
  /** Stable slug — never changes after creation. */
@@ -46,8 +47,7 @@ export declare const StoreStatusValues: {
46
47
  readonly REJECTED: "rejected";
47
48
  };
48
49
  export type StoreStatus = (typeof StoreStatusValues)[keyof typeof StoreStatusValues];
49
- export interface StoreDocument {
50
- id: string;
50
+ export interface StoreDocument extends BaseDocument {
51
51
  storeSlug: string;
52
52
  ownerId: string;
53
53
  storeName: string;
@@ -123,8 +123,6 @@ export interface StoreDocument {
123
123
  /** When the seller first connected their account */
124
124
  connectedAt?: Date;
125
125
  };
126
- createdAt: Date;
127
- updatedAt: Date;
128
126
  }
129
127
  export type { StoreCapability } from "../../auth/permissions/constants";
130
128
  export declare const STORE_COLLECTION: "stores";
@@ -405,8 +405,8 @@ export declare const storeFirestoreSchema: z.ZodObject<{
405
405
  createdAt: string | Date | z.objectOutputType<{
406
406
  toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
407
407
  }, z.ZodTypeAny, "passthrough">;
408
- id: string;
409
408
  storeName: string;
409
+ id: string;
410
410
  updatedAt: string | Date | z.objectOutputType<{
411
411
  toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
412
412
  }, z.ZodTypeAny, "passthrough">;
@@ -489,8 +489,8 @@ export declare const storeFirestoreSchema: z.ZodObject<{
489
489
  createdAt: string | Date | z.objectInputType<{
490
490
  toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
491
491
  }, z.ZodTypeAny, "passthrough">;
492
- id: string;
493
492
  storeName: string;
493
+ id: string;
494
494
  updatedAt: string | Date | z.objectInputType<{
495
495
  toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
496
496
  }, z.ZodTypeAny, "passthrough">;
@@ -603,8 +603,8 @@ export declare const storeListItemSchema: z.ZodObject<{
603
603
  createdAt: z.ZodOptional<z.ZodString>;
604
604
  }, "strip", z.ZodTypeAny, {
605
605
  status: string;
606
- id: string;
607
606
  storeName: string;
607
+ id: string;
608
608
  isPublic: boolean;
609
609
  storeSlug: string;
610
610
  ownerId: string;
@@ -619,8 +619,8 @@ export declare const storeListItemSchema: z.ZodObject<{
619
619
  averageRating?: number | undefined;
620
620
  }, {
621
621
  status: string;
622
- id: string;
623
622
  storeName: string;
623
+ id: string;
624
624
  isPublic: boolean;
625
625
  storeSlug: string;
626
626
  ownerId: string;
@@ -0,0 +1,312 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ import { makeMockDb, makeSnap, makeQuerySnap } from "../../../../../tests/helpers/mock-firestore";
3
+ const { db, mockDocRef, mockCollection, mockQuery } = makeMockDb();
4
+ vi.mock("../../../../providers/db-firebase/admin", () => ({
5
+ getAdminDb: () => db,
6
+ }));
7
+ vi.mock("../../../../providers/db-firebase", async (importOriginal) => {
8
+ const actual = await importOriginal();
9
+ return {
10
+ ...actual,
11
+ prepareForFirestore: (d) => d,
12
+ firebaseFieldOps: {
13
+ arrayUnion: (...args) => args,
14
+ arrayRemove: (...args) => args,
15
+ increment: (n) => n,
16
+ serverTimestamp: () => new Date(),
17
+ delete: () => null,
18
+ },
19
+ };
20
+ });
21
+ vi.mock("../../../../errors/normalize", () => ({
22
+ normalizeError: vi.fn(),
23
+ }));
24
+ vi.mock("../../../../monitoring", () => ({
25
+ serverLogger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() },
26
+ }));
27
+ import { SupportRepository } from "../support.repository";
28
+ import { ACTIVE_TICKET_STATUSES } from "../../schemas/firestore";
29
+ const repo = new SupportRepository();
30
+ function makeTicketDoc(overrides = {}) {
31
+ return {
32
+ id: "ticket-order-issue-ravi-20260627",
33
+ userId: "user-ravi",
34
+ userEmail: "ravi@test.com",
35
+ userDisplayName: "Ravi Kumar",
36
+ category: "order_issue",
37
+ subject: "My order is missing",
38
+ description: "I placed an order but never received it.",
39
+ orderId: "order-3-20260601-abc123",
40
+ status: "open",
41
+ priority: "normal",
42
+ messages: [],
43
+ createdAt: new Date(),
44
+ updatedAt: new Date(),
45
+ ...overrides,
46
+ };
47
+ }
48
+ function makeMessage(overrides = {}) {
49
+ return {
50
+ id: "msg-1",
51
+ authorId: "user-ravi",
52
+ authorRole: "user",
53
+ body: "I need help with my order.",
54
+ createdAt: new Date(),
55
+ ...overrides,
56
+ };
57
+ }
58
+ beforeEach(() => {
59
+ vi.clearAllMocks();
60
+ db.collection.mockReturnValue(mockCollection);
61
+ mockCollection.doc.mockReturnValue(mockDocRef);
62
+ mockCollection.where.mockReturnValue(mockQuery);
63
+ mockCollection.add = vi.fn().mockResolvedValue({ id: "new-ticket-id", get: vi.fn().mockResolvedValue(makeSnap(makeTicketDoc(), "new-ticket-id")) });
64
+ mockQuery.where.mockReturnValue(mockQuery);
65
+ mockQuery.orderBy.mockReturnValue(mockQuery);
66
+ mockQuery.limit.mockReturnValue(mockQuery);
67
+ mockQuery.select = vi.fn().mockReturnValue(mockQuery);
68
+ mockQuery.get.mockResolvedValue(makeQuerySnap([]));
69
+ mockDocRef.get.mockResolvedValue(makeSnap(makeTicketDoc(), "ticket-1"));
70
+ mockDocRef.set.mockResolvedValue(undefined);
71
+ mockDocRef.update.mockResolvedValue(undefined);
72
+ });
73
+ // ---------------------------------------------------------------------------
74
+ // createTicket
75
+ // ---------------------------------------------------------------------------
76
+ describe("SupportRepository.createTicket", () => {
77
+ it("sets status: open on new tickets", async () => {
78
+ const input = {
79
+ userId: "user-ravi",
80
+ userEmail: "ravi@test.com",
81
+ userDisplayName: "Ravi Kumar",
82
+ category: "order_issue",
83
+ subject: "Missing order",
84
+ description: "Order never arrived.",
85
+ };
86
+ await repo.createTicket(input);
87
+ // create() calls collection.add (BaseRepository.create uses add for auto-ID)
88
+ const addArg = mockCollection.add.mock.calls[0][0];
89
+ expect(addArg.status).toBe("open");
90
+ });
91
+ it("sets priority: normal by default", async () => {
92
+ await repo.createTicket({
93
+ userId: "user-ravi",
94
+ userEmail: "ravi@test.com",
95
+ userDisplayName: "Ravi Kumar",
96
+ category: "general",
97
+ subject: "Question",
98
+ description: "I have a question.",
99
+ });
100
+ const addArg = mockCollection.add.mock.calls[0][0];
101
+ expect(addArg.priority).toBe("normal");
102
+ });
103
+ it("initialises messages: [] on new ticket", async () => {
104
+ await repo.createTicket({
105
+ userId: "user-ravi",
106
+ userEmail: "ravi@test.com",
107
+ userDisplayName: "Ravi Kumar",
108
+ category: "general",
109
+ subject: "Question",
110
+ description: "I have a question.",
111
+ });
112
+ const addArg = mockCollection.add.mock.calls[0][0];
113
+ expect(addArg.messages).toEqual([]);
114
+ });
115
+ it("stores orderId when provided", async () => {
116
+ await repo.createTicket({
117
+ userId: "user-ravi",
118
+ userEmail: "ravi@test.com",
119
+ userDisplayName: "Ravi Kumar",
120
+ category: "order_issue",
121
+ subject: "Order missing",
122
+ description: "My order is gone.",
123
+ orderId: "order-3-20260601-abc123",
124
+ });
125
+ const addArg = mockCollection.add.mock.calls[0][0];
126
+ expect(addArg.orderId).toBe("order-3-20260601-abc123");
127
+ });
128
+ it("sets createdAt and updatedAt timestamps", async () => {
129
+ await repo.createTicket({
130
+ userId: "user-ravi",
131
+ userEmail: "ravi@test.com",
132
+ userDisplayName: "Ravi Kumar",
133
+ category: "general",
134
+ subject: "Q",
135
+ description: "D",
136
+ });
137
+ const addArg = mockCollection.add.mock.calls[0][0];
138
+ expect(addArg.createdAt).toBeInstanceOf(Date);
139
+ expect(addArg.updatedAt).toBeInstanceOf(Date);
140
+ });
141
+ });
142
+ // ---------------------------------------------------------------------------
143
+ // countActiveTickets
144
+ // ---------------------------------------------------------------------------
145
+ describe("SupportRepository.countActiveTickets", () => {
146
+ it("runs a query per ACTIVE_TICKET_STATUS in parallel", async () => {
147
+ mockQuery.get.mockResolvedValue({ empty: true, size: 0, docs: [] });
148
+ await repo.countActiveTickets("user-ravi");
149
+ // One query per active status
150
+ expect(mockQuery.get).toHaveBeenCalledTimes(ACTIVE_TICKET_STATUSES.length);
151
+ });
152
+ it("returns sum of sizes across all active status queries", async () => {
153
+ // Each of the 3 queries returns size=2 → total should be 6
154
+ mockQuery.get.mockResolvedValue({ empty: false, size: 2, docs: [] });
155
+ const count = await repo.countActiveTickets("user-ravi");
156
+ expect(count).toBe(ACTIVE_TICKET_STATUSES.length * 2);
157
+ });
158
+ it("returns 0 when no active tickets", async () => {
159
+ mockQuery.get.mockResolvedValue({ empty: true, size: 0, docs: [] });
160
+ const count = await repo.countActiveTickets("user-nobody");
161
+ expect(count).toBe(0);
162
+ });
163
+ it("queries by userId on each sub-query", async () => {
164
+ mockQuery.get.mockResolvedValue({ empty: true, size: 0, docs: [] });
165
+ await repo.countActiveTickets("user-specific");
166
+ expect(mockCollection.where).toHaveBeenCalledWith(expect.stringContaining("userId"), "==", "user-specific");
167
+ });
168
+ it("uses select() stub reads (minimal cost)", async () => {
169
+ mockQuery.get.mockResolvedValue({ empty: true, size: 0, docs: [] });
170
+ await repo.countActiveTickets("user-ravi");
171
+ expect(mockQuery.select).toHaveBeenCalled();
172
+ });
173
+ });
174
+ // ---------------------------------------------------------------------------
175
+ // getActiveCategoryTicket
176
+ // ---------------------------------------------------------------------------
177
+ describe("SupportRepository.getActiveCategoryTicket", () => {
178
+ it("returns existing ticket for userId + category with status waiting_on_user", async () => {
179
+ const ticket = makeTicketDoc({ status: "waiting_on_user", category: "order_issue" });
180
+ mockQuery.get.mockResolvedValue({
181
+ empty: false,
182
+ size: 1,
183
+ docs: [makeSnap(ticket, ticket.id)],
184
+ });
185
+ const result = await repo.getActiveCategoryTicket("user-ravi", "order_issue");
186
+ expect(result).not.toBeNull();
187
+ expect(result?.category).toBe("order_issue");
188
+ });
189
+ it("returns null when no matching ticket found", async () => {
190
+ mockQuery.get.mockResolvedValue({ empty: true, size: 0, docs: [] });
191
+ const result = await repo.getActiveCategoryTicket("user-ravi", "general");
192
+ expect(result).toBeNull();
193
+ });
194
+ it("queries specifically for status == waiting_on_user", async () => {
195
+ mockQuery.get.mockResolvedValue({ empty: true, size: 0, docs: [] });
196
+ await repo.getActiveCategoryTicket("user-ravi", "billing_payment");
197
+ expect(mockQuery.where).toHaveBeenCalledWith(expect.stringContaining("status"), "==", "waiting_on_user");
198
+ });
199
+ it("queries by userId and category", async () => {
200
+ mockQuery.get.mockResolvedValue({ empty: true, size: 0, docs: [] });
201
+ await repo.getActiveCategoryTicket("user-xyz", "account");
202
+ expect(mockCollection.where).toHaveBeenCalledWith(expect.stringContaining("userId"), "==", "user-xyz");
203
+ expect(mockQuery.where).toHaveBeenCalledWith(expect.stringContaining("category"), "==", "account");
204
+ });
205
+ it("uses limit(1) to avoid scanning all tickets", async () => {
206
+ mockQuery.get.mockResolvedValue({ empty: true, size: 0, docs: [] });
207
+ await repo.getActiveCategoryTicket("user-ravi", "general");
208
+ expect(mockQuery.limit).toHaveBeenCalledWith(1);
209
+ });
210
+ });
211
+ // ---------------------------------------------------------------------------
212
+ // addMessage
213
+ // ---------------------------------------------------------------------------
214
+ describe("SupportRepository.addMessage", () => {
215
+ it("appends message using arrayUnion (does not overwrite messages array)", async () => {
216
+ const message = makeMessage();
217
+ await repo.addMessage("ticket-1", message);
218
+ const updateArg = mockDocRef.update.mock.calls[0][0];
219
+ // arrayUnion mock returns its arguments as an array
220
+ expect(updateArg.messages).toBeDefined();
221
+ });
222
+ it("updates updatedAt timestamp on message add", async () => {
223
+ await repo.addMessage("ticket-1", makeMessage());
224
+ const updateArg = mockDocRef.update.mock.calls[0][0];
225
+ expect(updateArg.updatedAt).toBeInstanceOf(Date);
226
+ });
227
+ it("sets newStatus when provided", async () => {
228
+ await repo.addMessage("ticket-1", makeMessage(), "in_progress");
229
+ const updateArg = mockDocRef.update.mock.calls[0][0];
230
+ expect(updateArg.status).toBe("in_progress");
231
+ });
232
+ it("does NOT set status field when newStatus not provided", async () => {
233
+ await repo.addMessage("ticket-1", makeMessage());
234
+ const updateArg = mockDocRef.update.mock.calls[0][0];
235
+ expect(Object.keys(updateArg)).not.toContain("status");
236
+ });
237
+ it("calls doc(ticketId).update — not collection.add", async () => {
238
+ await repo.addMessage("ticket-1", makeMessage());
239
+ expect(mockCollection.doc).toHaveBeenCalledWith("ticket-1");
240
+ expect(mockDocRef.update).toHaveBeenCalledOnce();
241
+ });
242
+ });
243
+ // ---------------------------------------------------------------------------
244
+ // assignTicket
245
+ // ---------------------------------------------------------------------------
246
+ describe("SupportRepository.assignTicket", () => {
247
+ it("sets assignedTo field", async () => {
248
+ await repo.assignTicket("ticket-1", "employee-uid-1", "Support Agent");
249
+ expect(mockDocRef.update).toHaveBeenCalledWith(expect.objectContaining({ assignedTo: "employee-uid-1" }));
250
+ });
251
+ it("sets assignedToName field", async () => {
252
+ await repo.assignTicket("ticket-1", "emp-1", "Alice Support");
253
+ expect(mockDocRef.update).toHaveBeenCalledWith(expect.objectContaining({ assignedToName: "Alice Support" }));
254
+ });
255
+ it("sets updatedAt timestamp", async () => {
256
+ await repo.assignTicket("ticket-1", "emp-1", "Agent");
257
+ expect(mockDocRef.update).toHaveBeenCalledWith(expect.objectContaining({ updatedAt: expect.any(Date) }));
258
+ });
259
+ });
260
+ // ---------------------------------------------------------------------------
261
+ // updateTicketStatus
262
+ // ---------------------------------------------------------------------------
263
+ describe("SupportRepository.updateTicketStatus", () => {
264
+ it("applies provided status update", async () => {
265
+ await repo.updateTicketStatus("ticket-1", { status: "resolved" });
266
+ expect(mockDocRef.update).toHaveBeenCalledWith(expect.objectContaining({ status: "resolved" }));
267
+ });
268
+ it("sets updatedAt on every status change", async () => {
269
+ await repo.updateTicketStatus("ticket-1", { status: "closed" });
270
+ expect(mockDocRef.update).toHaveBeenCalledWith(expect.objectContaining({ updatedAt: expect.any(Date) }));
271
+ });
272
+ it("stores resolvedAt when provided", async () => {
273
+ const resolvedAt = new Date();
274
+ await repo.updateTicketStatus("ticket-1", { status: "resolved", resolvedAt });
275
+ expect(mockDocRef.update).toHaveBeenCalledWith(expect.objectContaining({ resolvedAt }));
276
+ });
277
+ it("stores priority update when provided", async () => {
278
+ await repo.updateTicketStatus("ticket-1", { priority: "high" });
279
+ expect(mockDocRef.update).toHaveBeenCalledWith(expect.objectContaining({ priority: "high" }));
280
+ });
281
+ });
282
+ // ---------------------------------------------------------------------------
283
+ // getActiveOrderTicket
284
+ // ---------------------------------------------------------------------------
285
+ describe("SupportRepository.getActiveOrderTicket", () => {
286
+ it("returns ticket matching userId + orderId with active status", async () => {
287
+ const ticket = makeTicketDoc({ status: "open", orderId: "order-1" });
288
+ mockQuery.get.mockResolvedValue({
289
+ empty: false,
290
+ size: 1,
291
+ docs: [{ id: ticket.id, data: () => ticket }],
292
+ });
293
+ const result = await repo.getActiveOrderTicket("user-ravi", "order-1");
294
+ expect(result).not.toBeNull();
295
+ expect(result?.orderId).toBe("order-1");
296
+ });
297
+ it("returns null when no active order ticket exists", async () => {
298
+ mockQuery.get.mockResolvedValue({ empty: true, size: 0, docs: [] });
299
+ const result = await repo.getActiveOrderTicket("user-ravi", "order-nonexistent");
300
+ expect(result).toBeNull();
301
+ });
302
+ it("queries status in ACTIVE_TICKET_STATUSES", async () => {
303
+ mockQuery.get.mockResolvedValue({ empty: true, size: 0, docs: [] });
304
+ await repo.getActiveOrderTicket("user-ravi", "order-1");
305
+ expect(mockQuery.where).toHaveBeenCalledWith(expect.stringContaining("status"), "in", ACTIVE_TICKET_STATUSES);
306
+ });
307
+ it("uses limit(1)", async () => {
308
+ mockQuery.get.mockResolvedValue({ empty: true, size: 0, docs: [] });
309
+ await repo.getActiveOrderTicket("user-ravi", "order-1");
310
+ expect(mockQuery.limit).toHaveBeenCalledWith(1);
311
+ });
312
+ });
@@ -14,6 +14,7 @@
14
14
  * - No creation if user has create_support_tickets soft ban
15
15
  * - No new ticket in the same category while existing one is waiting_on_user
16
16
  */
17
+ import type { BaseDocument } from "../../../_internal/shared/types/base-document";
17
18
  export declare const TicketCategoryValues: {
18
19
  readonly ORDER_ISSUE: "order_issue";
19
20
  readonly BILLING_PAYMENT: "billing_payment";
@@ -70,8 +71,7 @@ export interface TicketRelatedParties {
70
71
  productId?: string;
71
72
  bidId?: string;
72
73
  }
73
- export interface SupportTicketDocument {
74
- id: string;
74
+ export interface SupportTicketDocument extends BaseDocument {
75
75
  userId: string;
76
76
  /** Denormalized — for admin table display. */
77
77
  userEmail: string;
@@ -103,8 +103,6 @@ export interface SupportTicketDocument {
103
103
  messages: TicketMessage[];
104
104
  resolvedAt?: Date;
105
105
  closedAt?: Date;
106
- createdAt: Date;
107
- updatedAt: Date;
108
106
  }
109
107
  export type SupportTicketCreateInput = Pick<SupportTicketDocument, "userId" | "userEmail" | "userDisplayName" | "category" | "subject" | "description" | "orderId">;
110
108
  export type SupportTicketUpdateInput = Partial<Pick<SupportTicketDocument, "status" | "priority" | "assignedTo" | "assignedToName" | "internalNotes" | "resolvedAt" | "closedAt" | "relatedParties">>;