@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
@@ -3,7 +3,7 @@ import { increment, serverTimestamp } from "../../../contracts/field-ops";
3
3
  import { DatabaseError } from "../../../errors";
4
4
  import { BaseRepository, prepareForFirestore, } from "../../../providers/db-firebase";
5
5
  import { cacheManager } from "../../../core";
6
- import { generateUniqueId, slugify, buildSearchTokens, tokenizeQuery } from "../../../utils";
6
+ import { generateUniqueId, slugify, buildSearchTokens, tokenizeQuery, generateBarcodeId } from "../../../utils";
7
7
  import { PRODUCT_COLLECTION, ProductStatusValues, } from "../schemas";
8
8
  import { PRODUCT_FIELDS } from "../../../constants/field-names";
9
9
  /**
@@ -20,11 +20,17 @@ const SIEVE_CLAUSE_LT_AUCTION = `${PRODUCT_FIELDS.LISTING_TYPE}==${LISTING_TYPE_
20
20
  const SIEVE_CLAUSE_LT_PREORDER = `${PRODUCT_FIELDS.LISTING_TYPE}==${LISTING_TYPE_VALUES.PRE_ORDER}`;
21
21
  const SIEVE_CLAUSE_LT_STANDARD = `${PRODUCT_FIELDS.LISTING_TYPE}==${LISTING_TYPE_VALUES.STANDARD}`;
22
22
  const SIEVE_CLAUSE_LT_PRIZE_DRAW = `${PRODUCT_FIELDS.LISTING_TYPE}==${LISTING_TYPE_VALUES.PRIZE_DRAW}`;
23
+ const SIEVE_CLAUSE_LT_CLASSIFIED = `${PRODUCT_FIELDS.LISTING_TYPE}==${LISTING_TYPE_VALUES.CLASSIFIED}`;
24
+ const SIEVE_CLAUSE_LT_DIGITAL_CODE = `${PRODUCT_FIELDS.LISTING_TYPE}==${LISTING_TYPE_VALUES.DIGITAL_CODE}`;
25
+ const SIEVE_CLAUSE_LT_LIVE = `${PRODUCT_FIELDS.LISTING_TYPE}==${LISTING_TYPE_VALUES.LIVE}`;
23
26
  const LISTING_KIND_ALIAS_MAP = {
24
27
  standard: LISTING_TYPE_VALUES.STANDARD,
25
28
  auction: LISTING_TYPE_VALUES.AUCTION,
26
29
  "pre-order": LISTING_TYPE_VALUES.PRE_ORDER,
27
30
  "prize-draw": LISTING_TYPE_VALUES.PRIZE_DRAW,
31
+ classified: LISTING_TYPE_VALUES.CLASSIFIED,
32
+ "digital-code": LISTING_TYPE_VALUES.DIGITAL_CODE,
33
+ live: LISTING_TYPE_VALUES.LIVE,
28
34
  // Legacy → canonical.
29
35
  product: LISTING_TYPE_VALUES.STANDARD,
30
36
  preorder: LISTING_TYPE_VALUES.PRE_ORDER,
@@ -105,8 +111,10 @@ export class ProductRepository extends BaseRepository {
105
111
  return false;
106
112
  }
107
113
  });
114
+ const barcodeId = input.barcodeId ?? await generateBarcodeId(id);
108
115
  const productData = {
109
116
  ...input,
117
+ barcodeId,
110
118
  slug: id,
111
119
  availableQuantity: input.stockQuantity,
112
120
  searchTokens: buildProductSearchTokens(input),
@@ -136,6 +144,10 @@ export class ProductRepository extends BaseRepository {
136
144
  .get();
137
145
  return snap.docs.map((d) => this.mapDoc(d));
138
146
  }
147
+ async findByBarcodeId(barcodeId) {
148
+ const docs = await this.findBy("barcodeId", barcodeId);
149
+ return docs[0] ?? null;
150
+ }
139
151
  async findBySlug(slug) {
140
152
  const key = this.cacheKeyBySlug(slug);
141
153
  const cached = cacheManager.get(key);
@@ -486,6 +498,15 @@ ProductRepository.SIEVE_FIELDS = {
486
498
  currency: { canFilter: true, canSort: false },
487
499
  freeShipping: { canFilter: true, canSort: false },
488
500
  searchTokens: { canFilter: true, canSort: false },
501
+ "classified.meetupArea": { canFilter: true, canSort: false },
502
+ "classified.acceptsShipping": { canFilter: true, canSort: false },
503
+ "classified.negotiable": { canFilter: true, canSort: false },
504
+ "digitalCode.codeDeliveryMethod": { canFilter: true, canSort: false },
505
+ "digitalCode.codesAvailable": { canFilter: true, canSort: true },
506
+ "liveItem.species": { canFilter: true, canSort: false },
507
+ "liveItem.sex": { canFilter: true, canSort: false },
508
+ "liveItem.jurisdictionAllowed": { canFilter: true, canSort: false },
509
+ "liveItem.cites": { canFilter: true, canSort: false },
489
510
  };
490
511
  /**
491
512
  * Virtual filter aliases — callers can pass `f=listingType==auction` for
@@ -540,6 +561,12 @@ ProductRepository.FILTER_ALIASES = {
540
561
  return [SIEVE_CLAUSE_PUBLISHED, SIEVE_CLAUSE_LT_PREORDER].join(",");
541
562
  case "publicPrizeDraws":
542
563
  return [SIEVE_CLAUSE_PUBLISHED, SIEVE_CLAUSE_LT_PRIZE_DRAW].join(",");
564
+ case "publicClassifieds":
565
+ return [SIEVE_CLAUSE_PUBLISHED, SIEVE_CLAUSE_LT_CLASSIFIED].join(",");
566
+ case "publicDigitalCodes":
567
+ return [SIEVE_CLAUSE_PUBLISHED, SIEVE_CLAUSE_LT_DIGITAL_CODE].join(",");
568
+ case "publicLive":
569
+ return [SIEVE_CLAUSE_PUBLISHED, SIEVE_CLAUSE_LT_LIVE].join(",");
543
570
  case "published":
544
571
  return SIEVE_CLAUSE_PUBLISHED;
545
572
  default:
@@ -3,6 +3,8 @@
3
3
  */
4
4
  import { type GenerateProductIdInput, type GenerateAuctionIdInput, type GeneratePreOrderIdInput } from "../../../utils/id-generators";
5
5
  import type { ProductStatus, ListingType } from "../types";
6
+ import type { BaseDocument } from "../../../_internal/shared/types/base-document";
7
+ import type { LotteryConfig } from "../../lottery/types";
6
8
  export interface ProductVideoField {
7
9
  url: string;
8
10
  thumbnailUrl: string;
@@ -103,8 +105,7 @@ export interface ProductLiveItemMeta {
103
105
  /** CITES permit number (Appendix I/II species). */
104
106
  cites?: string;
105
107
  }
106
- export interface ProductDocument {
107
- id: string;
108
+ export interface ProductDocument extends BaseDocument {
108
109
  title: string;
109
110
  description: string;
110
111
  slug?: string;
@@ -142,7 +143,7 @@ export interface ProductDocument {
142
143
  features?: string[];
143
144
  shippingInfo?: string;
144
145
  returnPolicy?: string;
145
- condition?: "new" | "used" | "refurbished" | "broken" | "graded";
146
+ condition?: "new" | "like_new" | "good" | "fair" | "poor" | "used" | "refurbished" | "broken" | "graded";
146
147
  insurance?: boolean;
147
148
  insuranceCost?: number;
148
149
  shippingPaidBy?: "seller" | "buyer";
@@ -236,6 +237,17 @@ export interface ProductDocument {
236
237
  prizeRevealDeadlineDays?: number;
237
238
  /** Public proof-of-fairness file (commit-reveal scheme). */
238
239
  prizeGithubFileUrl?: string;
240
+ /**
241
+ * Draw mode for prize-draw listings.
242
+ * "reveal" = classic buyer-reveal flow (default, backward-compat).
243
+ * "lottery" = user self-pull with weighted random slot assignment.
244
+ */
245
+ prizeDrawMode?: "reveal" | "lottery";
246
+ /**
247
+ * Full lottery config. Only set when prizeDrawMode === "lottery".
248
+ * Includes server-only price/weight fields — stripped by adapter before any client response.
249
+ */
250
+ lotteryConfig?: LotteryConfig;
239
251
  /**
240
252
  * Optional per-item shipping constraints. When absent the store's
241
253
  * shippingConfig applies unchanged.
@@ -264,9 +276,11 @@ export interface ProductDocument {
264
276
  shelf: string;
265
277
  bin: string;
266
278
  };
279
+ /** Scannable barcode identifier linking this listing to a physical stickered item.
280
+ * Auto-generated as `LIR-{8-char-hex}` on product creation when not supplied.
281
+ * Override by scanning a pre-printed sticker during the create/edit flow. */
282
+ barcodeId?: string;
267
283
  searchTokens?: string[];
268
- createdAt: Date;
269
- updatedAt: Date;
270
284
  }
271
285
  /**
272
286
  * Single prize within a prize-draw listing. A draw can have between 3 and 16
@@ -284,6 +298,8 @@ export interface PrizeDrawItem {
284
298
  };
285
299
  condition: string;
286
300
  estimatedValue?: number;
301
+ /** Per-slot price in paise for lottery mode. Lower price = higher weight = higher chance. */
302
+ prizeSlotPrice?: number;
287
303
  isWon: boolean;
288
304
  }
289
305
  /** Runtime-accessible product status values — use instead of bare string literals. */
@@ -294,10 +310,10 @@ export declare const ProductStatusValues: {
294
310
  readonly ARCHIVED: "archived";
295
311
  };
296
312
  export declare const PRODUCT_COLLECTION: "products";
297
- export declare const PRODUCT_INDEXED_FIELDS: readonly ["storeId", "status", "category", "featured", "listingType", "isPromoted", "isOnSale", "isSold", "searchTokens", "createdAt"];
313
+ export declare const PRODUCT_INDEXED_FIELDS: readonly ["storeId", "status", "category", "featured", "listingType", "isPromoted", "isOnSale", "isSold", "searchTokens", "createdAt", "barcodeId"];
298
314
  export declare const DEFAULT_PRODUCT_DATA: Partial<ProductDocument>;
299
315
  export declare const PRODUCT_PUBLIC_FIELDS: readonly ["id", "title", "description", "category", "subcategory", "brand", "price", "currency", "stockQuantity", "availableQuantity", "images", "status", "storeName", "featured", "tags", "specifications", "features", "shippingInfo", "returnPolicy", "listingType", "auctionEndDate", "startingBid", "currentBid", "bidCount", "reservePrice", "buyNowPrice", "minBidIncrement", "autoExtendable", "auctionExtensionMinutes", "auctionShippingPaidBy", "buyItNowPriceInPaise", "bidsHaveStarted", "grading", "card", "classified", "digitalCode", "liveItem", "catalogProductId", "preOrderDeliveryDate", "preOrderDepositPercent", "preOrderDepositAmount", "preOrderMaxQuantity", "preOrderCurrentCount", "preOrderProductionStatus", "preOrderCancellable", "condition", "insurance", "insuranceCost", "shippingPaidBy", "isPromoted", "isOnSale", "isSold", "slug", "seoTitle", "seoDescription", "seoKeywords", "viewCount", "customFields", "customSections", "sublistingCategoryId", "groupId", "isGroupParent", "groupParentSlug", "groupChildSlugs", "groupTitle", "createdAt"];
300
- export declare const PRODUCT_UPDATABLE_FIELDS: readonly ["title", "description", "category", "subcategory", "brand", "price", "stockQuantity", "images", "status", "tags", "specifications", "features", "shippingInfo", "returnPolicy", "pickupAddressId", "condition", "insurance", "shippingPaidBy", "autoExtendable", "auctionExtensionMinutes", "auctionShippingPaidBy", "reservePrice", "buyNowPrice", "minBidIncrement", "buyItNowPriceInPaise", "bidsHaveStarted", "grading", "card", "classified", "digitalCode", "liveItem", "catalogProductId", "listingType", "preOrderDeliveryDate", "preOrderDepositPercent", "preOrderDepositAmount", "preOrderMaxQuantity", "preOrderProductionStatus", "preOrderCancellable", "isOnSale", "isSold", "seoTitle", "seoDescription", "seoKeywords", "customFields", "customSections", "sublistingCategoryId", "groupId", "isGroupParent", "groupParentSlug", "groupChildSlugs", "groupTitle"];
316
+ export declare const PRODUCT_UPDATABLE_FIELDS: readonly ["title", "description", "category", "subcategory", "brand", "price", "stockQuantity", "images", "status", "tags", "specifications", "features", "shippingInfo", "returnPolicy", "pickupAddressId", "condition", "insurance", "shippingPaidBy", "autoExtendable", "auctionExtensionMinutes", "auctionShippingPaidBy", "reservePrice", "buyNowPrice", "minBidIncrement", "buyItNowPriceInPaise", "bidsHaveStarted", "grading", "card", "classified", "digitalCode", "liveItem", "catalogProductId", "listingType", "preOrderDeliveryDate", "preOrderDepositPercent", "preOrderDepositAmount", "preOrderMaxQuantity", "preOrderProductionStatus", "preOrderCancellable", "isOnSale", "isSold", "seoTitle", "seoDescription", "seoKeywords", "customFields", "customSections", "sublistingCategoryId", "groupId", "isGroupParent", "groupParentSlug", "groupChildSlugs", "groupTitle", "barcodeId"];
301
317
  export type ProductCreateInput = Omit<ProductDocument, "id" | "createdAt" | "updatedAt" | "availableQuantity" | "bidCount" | "currentBid" | "auctionOriginalEndDate">;
302
318
  export type ProductUpdateInput = Partial<Pick<ProductDocument, (typeof PRODUCT_UPDATABLE_FIELDS)[number]>>;
303
319
  export type ProductAdminUpdateInput = Partial<Omit<ProductDocument, "id" | "createdAt">>;
@@ -23,6 +23,7 @@ export const PRODUCT_INDEXED_FIELDS = [
23
23
  "isSold",
24
24
  "searchTokens",
25
25
  "createdAt",
26
+ "barcodeId",
26
27
  ];
27
28
  export const DEFAULT_PRODUCT_DATA = {
28
29
  status: "draft",
@@ -173,6 +174,7 @@ export const PRODUCT_UPDATABLE_FIELDS = [
173
174
  "groupParentSlug",
174
175
  "groupChildSlugs",
175
176
  "groupTitle",
177
+ "barcodeId",
176
178
  ];
177
179
  // ── SB-UNI-N 2026-05-15 — Digital-code pool subcollection ───────────────────
178
180
  // Codes live at `products/{productId}/codes/{codeId}` — seller-only write,
@@ -92,8 +92,8 @@ export declare const productItemSchema: z.ZodObject<{
92
92
  categorySlug: z.ZodOptional<z.ZodString>;
93
93
  sellerAvatar: z.ZodOptional<z.ZodString>;
94
94
  status: z.ZodEnum<["draft", "published", "in_review", "archived"]>;
95
- condition: z.ZodOptional<z.ZodEnum<["new", "like_new", "good", "fair", "poor", "used", "refurbished", "broken"]>>;
96
- listingType: z.ZodOptional<z.ZodEnum<["standard", "auction", "pre-order", "prize-draw", "bundle"]>>;
95
+ condition: z.ZodOptional<z.ZodEnum<["new", "like_new", "good", "fair", "poor", "used", "refurbished", "broken", "graded"]>>;
96
+ listingType: z.ZodOptional<z.ZodEnum<["standard", "auction", "pre-order", "prize-draw", "classified", "digital-code", "live"]>>;
97
97
  maxPerUser: z.ZodOptional<z.ZodNumber>;
98
98
  partOfBundleIds: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
99
99
  partOfBundleTitles: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
@@ -263,8 +263,8 @@ export declare const productItemSchema: z.ZodObject<{
263
263
  unit?: string | undefined;
264
264
  }>, "many">>;
265
265
  }, "strip", z.ZodTypeAny, {
266
- id: string;
267
266
  title: string;
267
+ id: string;
268
268
  text?: string | undefined;
269
269
  fields?: {
270
270
  value: string;
@@ -273,8 +273,8 @@ export declare const productItemSchema: z.ZodObject<{
273
273
  unit?: string | undefined;
274
274
  }[] | undefined;
275
275
  }, {
276
- id: string;
277
276
  title: string;
277
+ id: string;
278
278
  text?: string | undefined;
279
279
  fields?: {
280
280
  value: string;
@@ -285,9 +285,9 @@ export declare const productItemSchema: z.ZodObject<{
285
285
  }>, "many">>;
286
286
  }, "strip", z.ZodTypeAny, {
287
287
  status: "draft" | "published" | "archived" | "in_review";
288
- id: string;
289
288
  title: string;
290
289
  price: number;
290
+ id: string;
291
291
  currency?: string | undefined;
292
292
  video?: {
293
293
  url: string;
@@ -296,7 +296,7 @@ export declare const productItemSchema: z.ZodObject<{
296
296
  storeId?: string | undefined;
297
297
  category?: string | undefined;
298
298
  featured?: boolean | undefined;
299
- listingType?: "standard" | "auction" | "pre-order" | "prize-draw" | "bundle" | undefined;
299
+ listingType?: "standard" | "auction" | "pre-order" | "prize-draw" | "classified" | "digital-code" | "live" | undefined;
300
300
  isPromoted?: boolean | undefined;
301
301
  createdAt?: string | undefined;
302
302
  description?: string | undefined;
@@ -316,7 +316,7 @@ export declare const productItemSchema: z.ZodObject<{
316
316
  features?: string[] | undefined;
317
317
  shippingInfo?: string | undefined;
318
318
  returnPolicy?: string | undefined;
319
- condition?: "new" | "used" | "refurbished" | "broken" | "like_new" | "good" | "fair" | "poor" | undefined;
319
+ condition?: "new" | "used" | "refurbished" | "like_new" | "good" | "fair" | "poor" | "broken" | "graded" | undefined;
320
320
  insurance?: boolean | undefined;
321
321
  insuranceCost?: number | undefined;
322
322
  shippingPaidBy?: "seller" | "buyer" | undefined;
@@ -356,8 +356,8 @@ export declare const productItemSchema: z.ZodObject<{
356
356
  unit?: string | undefined;
357
357
  }[] | undefined;
358
358
  customSections?: {
359
- id: string;
360
359
  title: string;
360
+ id: string;
361
361
  text?: string | undefined;
362
362
  fields?: {
363
363
  value: string;
@@ -414,9 +414,9 @@ export declare const productItemSchema: z.ZodObject<{
414
414
  publishedAt?: string | undefined;
415
415
  }, {
416
416
  status: "draft" | "published" | "archived" | "in_review";
417
- id: string;
418
417
  title: string;
419
418
  price: number;
419
+ id: string;
420
420
  currency?: string | undefined;
421
421
  video?: {
422
422
  url: string;
@@ -425,7 +425,7 @@ export declare const productItemSchema: z.ZodObject<{
425
425
  storeId?: string | undefined;
426
426
  category?: string | undefined;
427
427
  featured?: boolean | undefined;
428
- listingType?: "standard" | "auction" | "pre-order" | "prize-draw" | "bundle" | undefined;
428
+ listingType?: "standard" | "auction" | "pre-order" | "prize-draw" | "classified" | "digital-code" | "live" | undefined;
429
429
  isPromoted?: boolean | undefined;
430
430
  createdAt?: string | undefined;
431
431
  description?: string | undefined;
@@ -445,7 +445,7 @@ export declare const productItemSchema: z.ZodObject<{
445
445
  features?: string[] | undefined;
446
446
  shippingInfo?: string | undefined;
447
447
  returnPolicy?: string | undefined;
448
- condition?: "new" | "used" | "refurbished" | "broken" | "like_new" | "good" | "fair" | "poor" | undefined;
448
+ condition?: "new" | "used" | "refurbished" | "like_new" | "good" | "fair" | "poor" | "broken" | "graded" | undefined;
449
449
  insurance?: boolean | undefined;
450
450
  insuranceCost?: number | undefined;
451
451
  shippingPaidBy?: "seller" | "buyer" | undefined;
@@ -485,8 +485,8 @@ export declare const productItemSchema: z.ZodObject<{
485
485
  unit?: string | undefined;
486
486
  }[] | undefined;
487
487
  customSections?: {
488
- id: string;
489
488
  title: string;
489
+ id: string;
490
490
  text?: string | undefined;
491
491
  fields?: {
492
492
  value: string;
@@ -547,11 +547,11 @@ export declare const productListParamsSchema: z.ZodObject<{
547
547
  q: z.ZodOptional<z.ZodString>;
548
548
  category: z.ZodOptional<z.ZodString>;
549
549
  status: z.ZodOptional<z.ZodEnum<["draft", "published", "in_review", "archived"]>>;
550
- condition: z.ZodOptional<z.ZodEnum<["new", "like_new", "good", "fair", "poor", "used", "refurbished", "broken"]>>;
550
+ condition: z.ZodOptional<z.ZodEnum<["new", "like_new", "good", "fair", "poor", "used", "refurbished", "broken", "graded"]>>;
551
551
  minPrice: z.ZodOptional<z.ZodNumber>;
552
552
  maxPrice: z.ZodOptional<z.ZodNumber>;
553
553
  inStock: z.ZodOptional<z.ZodBoolean>;
554
- listingType: z.ZodOptional<z.ZodEnum<["standard", "auction", "pre-order", "prize-draw", "bundle"]>>;
554
+ listingType: z.ZodOptional<z.ZodEnum<["standard", "auction", "pre-order", "prize-draw", "classified", "digital-code", "live"]>>;
555
555
  storeId: z.ZodOptional<z.ZodString>;
556
556
  sort: z.ZodOptional<z.ZodString>;
557
557
  page: z.ZodOptional<z.ZodNumber>;
@@ -563,8 +563,8 @@ export declare const productListParamsSchema: z.ZodObject<{
563
563
  storeId?: string | undefined;
564
564
  category?: string | undefined;
565
565
  featured?: boolean | undefined;
566
- listingType?: "standard" | "auction" | "pre-order" | "prize-draw" | "bundle" | undefined;
567
- condition?: "new" | "used" | "refurbished" | "broken" | "like_new" | "good" | "fair" | "poor" | undefined;
566
+ listingType?: "standard" | "auction" | "pre-order" | "prize-draw" | "classified" | "digital-code" | "live" | undefined;
567
+ condition?: "new" | "used" | "refurbished" | "like_new" | "good" | "fair" | "poor" | "broken" | "graded" | undefined;
568
568
  page?: number | undefined;
569
569
  q?: string | undefined;
570
570
  perPage?: number | undefined;
@@ -577,8 +577,8 @@ export declare const productListParamsSchema: z.ZodObject<{
577
577
  storeId?: string | undefined;
578
578
  category?: string | undefined;
579
579
  featured?: boolean | undefined;
580
- listingType?: "standard" | "auction" | "pre-order" | "prize-draw" | "bundle" | undefined;
581
- condition?: "new" | "used" | "refurbished" | "broken" | "like_new" | "good" | "fair" | "poor" | undefined;
580
+ listingType?: "standard" | "auction" | "pre-order" | "prize-draw" | "classified" | "digital-code" | "live" | undefined;
581
+ condition?: "new" | "used" | "refurbished" | "like_new" | "good" | "fair" | "poor" | "broken" | "graded" | undefined;
582
582
  page?: number | undefined;
583
583
  q?: string | undefined;
584
584
  perPage?: number | undefined;
@@ -64,11 +64,12 @@ export const productItemSchema = z.object({
64
64
  "used",
65
65
  "refurbished",
66
66
  "broken",
67
+ "graded",
67
68
  ])
68
69
  .optional(),
69
70
  // SB1-G Phase 4 — canonical discriminator (legacy `isAuction`/`isPreOrder` booleans removed).
70
71
  listingType: z
71
- .enum(["standard", "auction", "pre-order", "prize-draw", "bundle"])
72
+ .enum(["standard", "auction", "pre-order", "prize-draw", "classified", "digital-code", "live"])
72
73
  .optional(),
73
74
  // SB1-C — prize-draw + bundle fields. All optional.
74
75
  maxPerUser: z.number().int().positive().optional(),
@@ -205,13 +206,14 @@ export const productListParamsSchema = z.object({
205
206
  "used",
206
207
  "refurbished",
207
208
  "broken",
209
+ "graded",
208
210
  ])
209
211
  .optional(),
210
212
  minPrice: z.coerce.number().optional(),
211
213
  maxPrice: z.coerce.number().optional(),
212
214
  inStock: z.coerce.boolean().optional(),
213
215
  listingType: z
214
- .enum(["standard", "auction", "pre-order", "prize-draw", "bundle"])
216
+ .enum(["standard", "auction", "pre-order", "prize-draw", "classified", "digital-code", "live"])
215
217
  .optional(),
216
218
  storeId: z.string().optional(),
217
219
  sort: z.string().optional(),
@@ -2,7 +2,7 @@ import type { MediaField } from "../../media/types/index";
2
2
  import type { CustomField, CustomSection } from "../schemas/firestore";
3
3
  export type { CustomField, CustomSection } from "../schemas/firestore";
4
4
  export type ProductStatus = "draft" | "published" | "in_review" | "archived";
5
- export type ProductCondition = "new" | "like_new" | "good" | "fair" | "poor" | "used" | "refurbished" | "broken";
5
+ export type ProductCondition = "new" | "like_new" | "good" | "fair" | "poor" | "used" | "refurbished" | "broken" | "graded";
6
6
  /**
7
7
  * Canonical listing-kind discriminator (SB1-G Phase 4).
8
8
  *
@@ -149,6 +149,8 @@ export interface ProductItem {
149
149
  shelf: string;
150
150
  bin: string;
151
151
  };
152
+ /** Scannable barcode ID linking this listing to a physical stickered item. */
153
+ barcodeId?: string;
152
154
  }
153
155
  export interface ProductListResponse {
154
156
  items: ProductItem[];
@@ -0,0 +1,219 @@
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
+ };
13
+ });
14
+ vi.mock("../../../../errors/normalize", () => ({
15
+ normalizeError: vi.fn(),
16
+ }));
17
+ import { ClaimedCouponsRepository } from "../claimed-coupons.repository";
18
+ import { createClaimedCouponId } from "../../schemas";
19
+ const repo = new ClaimedCouponsRepository();
20
+ function makeClaimInput(overrides = {}) {
21
+ return {
22
+ userId: "user-yugi",
23
+ couponId: "coupon-welcome10",
24
+ couponCode: "welcome10",
25
+ source: "manual",
26
+ couponSnapshot: {
27
+ name: "10% Off Coupon",
28
+ type: "percentage",
29
+ scope: "admin",
30
+ discount: { value: 10, maxDiscount: 0, minPurchase: 0 },
31
+ restrictions: { firstTimeUserOnly: false, combineWithSellerCoupons: true },
32
+ },
33
+ expiresAt: null,
34
+ ...overrides,
35
+ };
36
+ }
37
+ function makeClaimDoc(userId = "user-yugi", code = "WELCOME10") {
38
+ return {
39
+ id: createClaimedCouponId(userId, code),
40
+ userId,
41
+ couponId: "coupon-welcome10",
42
+ couponCode: code,
43
+ source: "manual",
44
+ status: "active",
45
+ expiresAt: null,
46
+ claimedAt: new Date(),
47
+ updatedAt: new Date(),
48
+ couponSnapshot: {},
49
+ };
50
+ }
51
+ beforeEach(() => {
52
+ vi.clearAllMocks();
53
+ db.collection.mockReturnValue(mockCollection);
54
+ mockCollection.doc.mockReturnValue(mockDocRef);
55
+ mockCollection.where.mockReturnValue(mockQuery);
56
+ mockQuery.where.mockReturnValue(mockQuery);
57
+ mockQuery.get.mockResolvedValue(makeQuerySnap([]));
58
+ mockDocRef.get.mockResolvedValue(makeSnap(null));
59
+ mockDocRef.set.mockResolvedValue(undefined);
60
+ mockDocRef.update.mockResolvedValue(undefined);
61
+ });
62
+ // ---------------------------------------------------------------------------
63
+ // findByUserAndCode
64
+ // ---------------------------------------------------------------------------
65
+ describe("ClaimedCouponsRepository.findByUserAndCode", () => {
66
+ it("existing claim → returns document", async () => {
67
+ const doc = makeClaimDoc();
68
+ mockDocRef.get.mockResolvedValue(makeSnap(doc, doc.id));
69
+ const result = await repo.findByUserAndCode("user-yugi", "WELCOME10");
70
+ expect(result).not.toBeNull();
71
+ expect(result.couponCode).toBe("WELCOME10");
72
+ });
73
+ it("no claim → returns null", async () => {
74
+ mockDocRef.get.mockResolvedValue(makeSnap(null));
75
+ const result = await repo.findByUserAndCode("user-yugi", "NOTFOUND");
76
+ expect(result).toBeNull();
77
+ });
78
+ it("uses deterministic ID based on userId + couponCode", async () => {
79
+ mockDocRef.get.mockResolvedValue(makeSnap(null));
80
+ await repo.findByUserAndCode("user-yugi", "WELCOME10");
81
+ const expectedId = createClaimedCouponId("user-yugi", "WELCOME10");
82
+ expect(mockCollection.doc).toHaveBeenCalledWith(expectedId);
83
+ });
84
+ });
85
+ // ---------------------------------------------------------------------------
86
+ // claim
87
+ // ---------------------------------------------------------------------------
88
+ describe("ClaimedCouponsRepository.claim", () => {
89
+ it("first call → creates record with status: active", async () => {
90
+ mockDocRef.get.mockResolvedValue(makeSnap(null));
91
+ const result = await repo.claim(makeClaimInput());
92
+ expect(result.status).toBe("active");
93
+ expect(mockDocRef.set).toHaveBeenCalledOnce();
94
+ });
95
+ it("second call for same user + code → returns existing record (idempotent)", async () => {
96
+ const existingDoc = makeClaimDoc();
97
+ mockDocRef.get.mockResolvedValue(makeSnap(existingDoc, existingDoc.id));
98
+ const result = await repo.claim(makeClaimInput());
99
+ expect(mockDocRef.set).not.toHaveBeenCalled();
100
+ expect(result.id).toBe(existingDoc.id);
101
+ });
102
+ it("couponCode normalized to uppercase on create", async () => {
103
+ mockDocRef.get.mockResolvedValue(makeSnap(null));
104
+ const result = await repo.claim(makeClaimInput({ couponCode: "welcome10" }));
105
+ expect(result.couponCode).toBe("WELCOME10");
106
+ });
107
+ it("expiresAt stored as provided (null case)", async () => {
108
+ mockDocRef.get.mockResolvedValue(makeSnap(null));
109
+ const result = await repo.claim(makeClaimInput({ expiresAt: null }));
110
+ expect(result.expiresAt).toBeNull();
111
+ });
112
+ it("expiresAt stored as provided (date case)", async () => {
113
+ const exp = new Date(Date.now() + 86400000);
114
+ mockDocRef.get.mockResolvedValue(makeSnap(null));
115
+ const result = await repo.claim(makeClaimInput({ expiresAt: exp }));
116
+ expect(result.expiresAt).toEqual(exp);
117
+ });
118
+ it("uses createClaimedCouponId for the document ID", async () => {
119
+ mockDocRef.get.mockResolvedValue(makeSnap(null));
120
+ await repo.claim(makeClaimInput({ userId: "user-yugi", couponCode: "SAVE20" }));
121
+ const expectedId = createClaimedCouponId("user-yugi", "SAVE20");
122
+ expect(mockCollection.doc).toHaveBeenCalledWith(expectedId);
123
+ });
124
+ });
125
+ // ---------------------------------------------------------------------------
126
+ // listForUser
127
+ // ---------------------------------------------------------------------------
128
+ describe("ClaimedCouponsRepository.listForUser", () => {
129
+ it("queries by userId field", async () => {
130
+ mockQuery.get.mockResolvedValue(makeQuerySnap([]));
131
+ await repo.listForUser("user-yugi");
132
+ expect(mockCollection.where).toHaveBeenCalledWith("userId", "==", "user-yugi");
133
+ });
134
+ it("valid coupon (not expired) → returned without mutation", async () => {
135
+ const futureDate = new Date(Date.now() + 86400000);
136
+ const doc = { ...makeClaimDoc(), status: "active", expiresAt: futureDate };
137
+ mockQuery.get.mockResolvedValue(makeQuerySnap([{ id: doc.id, data: doc }]));
138
+ const results = await repo.listForUser("user-yugi");
139
+ expect(results[0].status).toBe("active");
140
+ expect(mockDocRef.update).not.toHaveBeenCalled();
141
+ });
142
+ it("active coupon with no expiresAt → not lazily expired", async () => {
143
+ const doc = { ...makeClaimDoc(), status: "active", expiresAt: null };
144
+ mockQuery.get.mockResolvedValue(makeQuerySnap([{ id: doc.id, data: doc }]));
145
+ const results = await repo.listForUser("user-yugi");
146
+ expect(results[0].status).toBe("active");
147
+ expect(mockDocRef.update).not.toHaveBeenCalled();
148
+ });
149
+ it("expired coupon found on read → lazy-flips status to expired in returned item", async () => {
150
+ const pastDate = new Date(Date.now() - 86400000);
151
+ const doc = { ...makeClaimDoc(), status: "active", expiresAt: pastDate };
152
+ mockQuery.get.mockResolvedValue(makeQuerySnap([{ id: doc.id, data: doc }]));
153
+ const results = await repo.listForUser("user-yugi");
154
+ expect(results[0].status).toBe("expired");
155
+ });
156
+ it("expired coupon → best-effort write-back update called (fire-and-forget)", async () => {
157
+ const pastDate = new Date(Date.now() - 86400000);
158
+ const doc = { ...makeClaimDoc(), status: "active", expiresAt: pastDate };
159
+ mockQuery.get.mockResolvedValue(makeQuerySnap([{ id: doc.id, data: doc }]));
160
+ await repo.listForUser("user-yugi");
161
+ // Allow the fire-and-forget to complete
162
+ await new Promise((r) => setTimeout(r, 10));
163
+ expect(mockDocRef.update).toHaveBeenCalledWith(expect.objectContaining({ status: "expired" }));
164
+ });
165
+ it("already-expired coupon → no write-back (only active transitions)", async () => {
166
+ const pastDate = new Date(Date.now() - 86400000);
167
+ const doc = { ...makeClaimDoc(), status: "expired", expiresAt: pastDate };
168
+ mockQuery.get.mockResolvedValue(makeQuerySnap([{ id: doc.id, data: doc }]));
169
+ await repo.listForUser("user-yugi");
170
+ await new Promise((r) => setTimeout(r, 10));
171
+ expect(mockDocRef.update).not.toHaveBeenCalled();
172
+ });
173
+ it("empty list → returns []", async () => {
174
+ mockQuery.get.mockResolvedValue(makeQuerySnap([]));
175
+ const results = await repo.listForUser("user-nobody");
176
+ expect(results).toHaveLength(0);
177
+ });
178
+ });
179
+ // ---------------------------------------------------------------------------
180
+ // markUsed
181
+ // ---------------------------------------------------------------------------
182
+ describe("ClaimedCouponsRepository.markUsed", () => {
183
+ it("sets status: used on the claim document", async () => {
184
+ await repo.markUsed("user-yugi", "WELCOME10", "order-1-20260101-abc");
185
+ expect(mockDocRef.update).toHaveBeenCalledWith(expect.objectContaining({ status: "used" }));
186
+ });
187
+ it("stores usedOrderId on the claim", async () => {
188
+ await repo.markUsed("user-yugi", "WELCOME10", "order-1-20260101-abc");
189
+ expect(mockDocRef.update).toHaveBeenCalledWith(expect.objectContaining({ usedOrderId: "order-1-20260101-abc" }));
190
+ });
191
+ it("sets usedAt timestamp", async () => {
192
+ await repo.markUsed("user-yugi", "WELCOME10", "order-x");
193
+ expect(mockDocRef.update).toHaveBeenCalledWith(expect.objectContaining({ usedAt: expect.any(Date) }));
194
+ });
195
+ it("uses the correct document ID (userId + code)", async () => {
196
+ await repo.markUsed("user-yugi", "WELCOME10", "order-x");
197
+ const expectedId = createClaimedCouponId("user-yugi", "WELCOME10");
198
+ expect(mockCollection.doc).toHaveBeenCalledWith(expectedId);
199
+ });
200
+ });
201
+ // ---------------------------------------------------------------------------
202
+ // softRemove
203
+ // ---------------------------------------------------------------------------
204
+ describe("ClaimedCouponsRepository.softRemove", () => {
205
+ it("sets status: expired (audit trail preserved, no delete)", async () => {
206
+ await repo.softRemove("user-yugi", "WELCOME10");
207
+ expect(mockDocRef.update).toHaveBeenCalledWith(expect.objectContaining({ status: "expired" }));
208
+ expect(mockDocRef.delete).not.toHaveBeenCalled();
209
+ });
210
+ it("does NOT call delete on the document", async () => {
211
+ await repo.softRemove("user-yugi", "SAVE20");
212
+ expect(mockDocRef.delete).not.toHaveBeenCalled();
213
+ });
214
+ it("uses the correct document ID (userId + code)", async () => {
215
+ await repo.softRemove("user-yugi", "SAVE20");
216
+ const expectedId = createClaimedCouponId("user-yugi", "SAVE20");
217
+ expect(mockCollection.doc).toHaveBeenCalledWith(expectedId);
218
+ });
219
+ });