@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.
- package/dist/_internal/client/features/lottery/LotteryAdminEditView.d.ts +42 -0
- package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +86 -0
- package/dist/_internal/client/features/lottery/LotteryAdminSlotView.d.ts +14 -0
- package/dist/_internal/client/features/lottery/LotteryAdminSlotView.js +46 -0
- package/dist/_internal/client/features/lottery/LotteryDetailView.d.ts +28 -0
- package/dist/_internal/client/features/lottery/LotteryDetailView.js +17 -0
- package/dist/_internal/client/features/lottery/LotteryEntriesView.d.ts +23 -0
- package/dist/_internal/client/features/lottery/LotteryEntriesView.js +58 -0
- package/dist/_internal/client/features/lottery/LotteryListView.d.ts +21 -0
- package/dist/_internal/client/features/lottery/LotteryListView.js +25 -0
- package/dist/_internal/client/features/lottery/LotteryPullForm.d.ts +19 -0
- package/dist/_internal/client/features/lottery/LotteryPullForm.js +65 -0
- package/dist/_internal/client/features/lottery/LotterySlotGrid.d.ts +13 -0
- package/dist/_internal/client/features/lottery/LotterySlotGrid.js +21 -0
- package/dist/_internal/client/features/lottery/PrizeDrawLotteryDetailView.d.ts +28 -0
- package/dist/_internal/client/features/lottery/PrizeDrawLotteryDetailView.js +18 -0
- package/dist/_internal/server/features/auctions/__tests__/service.test.d.ts +1 -0
- package/dist/_internal/server/features/auctions/__tests__/service.test.js +140 -0
- package/dist/_internal/server/features/auctions/data.d.ts +2 -4
- package/dist/_internal/server/features/auctions/data.js +3 -9
- package/dist/_internal/server/features/checkout/__tests__/actions.test.d.ts +1 -0
- package/dist/_internal/server/features/checkout/__tests__/actions.test.js +600 -0
- package/dist/_internal/server/features/classified/adapters.d.ts +2 -15
- package/dist/_internal/server/features/classified/adapters.js +2 -17
- package/dist/_internal/server/features/classified/data.d.ts +1 -6
- package/dist/_internal/server/features/classified/data.js +2 -10
- package/dist/_internal/server/features/digital-code/adapters.d.ts +2 -15
- package/dist/_internal/server/features/digital-code/adapters.js +2 -17
- package/dist/_internal/server/features/digital-code/data.d.ts +1 -6
- package/dist/_internal/server/features/digital-code/data.js +2 -10
- package/dist/_internal/server/features/live/adapters.d.ts +2 -15
- package/dist/_internal/server/features/live/adapters.js +2 -17
- package/dist/_internal/server/features/live/data.d.ts +1 -6
- package/dist/_internal/server/features/live/data.js +2 -10
- package/dist/_internal/server/features/lottery/actions.d.ts +43 -0
- package/dist/_internal/server/features/lottery/actions.js +243 -0
- package/dist/_internal/server/features/lottery/adapters.d.ts +9 -0
- package/dist/_internal/server/features/lottery/adapters.js +21 -0
- package/dist/_internal/server/features/lottery/data.d.ts +20 -0
- package/dist/_internal/server/features/lottery/data.js +41 -0
- package/dist/_internal/server/features/lottery/metadata.d.ts +6 -0
- package/dist/_internal/server/features/lottery/metadata.js +31 -0
- package/dist/_internal/server/features/pre-orders/data.d.ts +2 -4
- package/dist/_internal/server/features/pre-orders/data.js +3 -9
- package/dist/_internal/server/features/prize-draws/actions.d.ts +2 -0
- package/dist/_internal/server/features/prize-draws/actions.js +22 -0
- package/dist/_internal/server/features/prize-draws/data.d.ts +1 -17
- package/dist/_internal/server/features/prize-draws/data.js +2 -20
- package/dist/_internal/server/features/prize-draws/index.d.ts +3 -1
- package/dist/_internal/server/features/prize-draws/index.js +2 -0
- package/dist/_internal/server/features/prize-draws/service.d.ts +3 -0
- package/dist/_internal/server/features/prize-draws/service.js +19 -0
- package/dist/_internal/server/features/refunds/__tests__/actions.test.d.ts +1 -0
- package/dist/_internal/server/features/refunds/__tests__/actions.test.js +263 -0
- package/dist/_internal/server/features/shared/listing-adapters.d.ts +19 -0
- package/dist/_internal/server/features/shared/listing-adapters.js +20 -0
- package/dist/_internal/server/features/shared/listing-data-factory.d.ts +9 -0
- package/dist/_internal/server/features/shared/listing-data-factory.js +33 -0
- package/dist/_internal/server/features/stores/data.d.ts +3 -14
- package/dist/_internal/server/features/stores/data.js +6 -44
- package/dist/_internal/server/jobs/core/__tests__/auctionSettlement.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/auctionSettlement.test.js +249 -0
- package/dist/_internal/server/jobs/core/__tests__/onBidPlaced.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/onBidPlaced.test.js +201 -0
- package/dist/_internal/server/jobs/core/__tests__/onOrderCreate.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/onOrderCreate.test.js +169 -0
- package/dist/_internal/server/jobs/core/__tests__/onOrderStatusChange.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/onOrderStatusChange.test.js +148 -0
- package/dist/_internal/server/jobs/core/__tests__/onProductStockChange.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/onProductStockChange.test.js +210 -0
- package/dist/_internal/server/jobs/core/__tests__/onReviewWrite.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/onReviewWrite.test.js +190 -0
- package/dist/_internal/server/jobs/core/__tests__/onUserBanChange.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/onUserBanChange.test.js +161 -0
- package/dist/_internal/server/jobs/core/__tests__/payoutBatch.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/payoutBatch.test.js +302 -0
- package/dist/_internal/server/jobs/core/__tests__/triggerEventRaffle.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/triggerEventRaffle.test.js +252 -0
- package/dist/_internal/server/jobs/core/__tests__/wrapJobHandler.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/wrapJobHandler.test.js +129 -0
- package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
- package/dist/_internal/shared/actions/action-registry.js +46 -0
- package/dist/_internal/shared/features/cart/schema.d.ts +8 -8
- package/dist/_internal/shared/features/cart/schema.js +3 -0
- package/dist/_internal/shared/features/products/schema.d.ts +8 -8
- package/dist/_internal/shared/listing-types/_registry.js +2 -0
- package/dist/_internal/shared/listing-types/auction/schema.d.ts +3 -1
- package/dist/_internal/shared/listing-types/auction/schema.js +7 -1
- package/dist/_internal/shared/listing-types/classified/schema.d.ts +2 -1
- package/dist/_internal/shared/listing-types/classified/schema.js +3 -1
- package/dist/_internal/shared/listing-types/digital-code/schema.d.ts +3 -1
- package/dist/_internal/shared/listing-types/digital-code/schema.js +7 -1
- package/dist/_internal/shared/listing-types/live/schema.d.ts +2 -1
- package/dist/_internal/shared/listing-types/live/schema.js +3 -1
- package/dist/_internal/shared/listing-types/pre-order/schema.d.ts +3 -1
- package/dist/_internal/shared/listing-types/pre-order/schema.js +7 -1
- package/dist/_internal/shared/listing-types/prize-draw/schema.d.ts +3 -1
- package/dist/_internal/shared/listing-types/prize-draw/schema.js +13 -1
- package/dist/_internal/shared/listing-types/standard/schema.d.ts +2 -1
- package/dist/_internal/shared/listing-types/standard/schema.js +4 -1
- package/dist/_internal/shared/types/base-document.d.ts +15 -0
- package/dist/_internal/shared/types/base-document.js +1 -0
- package/dist/_internal/shared/types/index.d.ts +2 -0
- package/dist/_internal/shared/types/index.js +1 -0
- package/dist/client.d.ts +13 -4
- package/dist/client.js +11 -2
- package/dist/constants/api-endpoints.d.ts +12 -0
- package/dist/constants/api-endpoints.js +4 -0
- package/dist/constants/field-names.d.ts +5 -1
- package/dist/constants/field-names.js +5 -1
- package/dist/features/addresses/repository/__tests__/addresses.repository.test.d.ts +1 -0
- package/dist/features/addresses/repository/__tests__/addresses.repository.test.js +386 -0
- package/dist/features/addresses/schemas/firestore.d.ts +2 -4
- package/dist/features/admin/api/bids/route.d.ts +2 -2
- package/dist/features/admin/api/coupons/route.d.ts +2 -2
- package/dist/features/admin/api/products/route.d.ts +2 -2
- package/dist/features/admin/api/reviews/route.d.ts +2 -2
- package/dist/features/admin/components/AdminFulfillmentView.d.ts +6 -0
- package/dist/features/admin/components/AdminFulfillmentView.js +107 -0
- package/dist/features/admin/components/AdminProductEditorView.js +21 -9
- package/dist/features/admin/components/AdminProductsView.js +3 -0
- package/dist/features/admin/components/DataListingView.d.ts +1 -0
- package/dist/features/admin/components/index.d.ts +2 -0
- package/dist/features/admin/components/index.js +1 -0
- package/dist/features/admin/repository/__tests__/notification.repository.test.d.ts +1 -0
- package/dist/features/admin/repository/__tests__/notification.repository.test.js +356 -0
- package/dist/features/admin/repository/__tests__/site-settings.repository.test.d.ts +1 -0
- package/dist/features/admin/repository/__tests__/site-settings.repository.test.js +298 -0
- package/dist/features/admin/schemas/firestore.d.ts +3 -8
- package/dist/features/auctions/repository/__tests__/bid.repository.test.d.ts +1 -0
- package/dist/features/auctions/repository/__tests__/bid.repository.test.js +290 -0
- package/dist/features/auctions/schemas/firestore.d.ts +2 -4
- package/dist/features/auctions/schemas/index.d.ts +2 -2
- package/dist/features/auth/api/route.d.ts +2 -2
- package/dist/features/auth/repository/__tests__/session.repository.test.d.ts +1 -0
- package/dist/features/auth/repository/__tests__/session.repository.test.js +310 -0
- package/dist/features/auth/repository/__tests__/session.test.d.ts +1 -0
- package/dist/features/auth/repository/__tests__/session.test.js +146 -0
- package/dist/features/auth/repository/__tests__/sms-counter.repository.test.d.ts +1 -0
- package/dist/features/auth/repository/__tests__/sms-counter.repository.test.js +171 -0
- package/dist/features/auth/repository/__tests__/sms-counter.test.d.ts +1 -0
- package/dist/features/auth/repository/__tests__/sms-counter.test.js +88 -0
- package/dist/features/auth/repository/__tests__/token.repository.test.d.ts +1 -0
- package/dist/features/auth/repository/__tests__/token.repository.test.js +260 -0
- package/dist/features/auth/repository/__tests__/token.test.d.ts +1 -0
- package/dist/features/auth/repository/__tests__/token.test.js +140 -0
- package/dist/features/auth/repository/__tests__/user.repository.test.d.ts +1 -0
- package/dist/features/auth/repository/__tests__/user.repository.test.js +352 -0
- package/dist/features/auth/repository/__tests__/user.test.d.ts +1 -0
- package/dist/features/auth/repository/__tests__/user.test.js +226 -0
- package/dist/features/auth/repository/session.repository.js +10 -1
- package/dist/features/before-after/schemas/index.d.ts +2 -2
- package/dist/features/blog/schemas/firestore.d.ts +2 -4
- package/dist/features/blog/schemas/index.d.ts +4 -4
- package/dist/features/cart/repository/__tests__/cart.repository.test.d.ts +1 -0
- package/dist/features/cart/repository/__tests__/cart.repository.test.js +371 -0
- package/dist/features/cart/repository/cart.repository.js +2 -2
- package/dist/features/cart/schemas/firestore.d.ts +2 -4
- package/dist/features/categories/api/[id]/route.d.ts +4 -4
- package/dist/features/categories/api/route.d.ts +2 -2
- package/dist/features/categories/repository/__tests__/categories.repository.test.d.ts +1 -0
- package/dist/features/categories/repository/__tests__/categories.repository.test.js +813 -0
- package/dist/features/categories/schemas/firestore.d.ts +2 -4
- package/dist/features/categories/schemas/index.d.ts +4 -4
- package/dist/features/events/components/EventCard.js +1 -0
- package/dist/features/events/repository/__tests__/event.repository.test.d.ts +1 -0
- package/dist/features/events/repository/__tests__/event.repository.test.js +299 -0
- package/dist/features/events/schemas/firestore.d.ts +5 -4
- package/dist/features/events/schemas/index.d.ts +836 -16
- package/dist/features/events/schemas/index.js +80 -1
- package/dist/features/events/types/index.d.ts +4 -1
- package/dist/features/faq/repository/__tests__/faqs.repository.test.d.ts +1 -0
- package/dist/features/faq/repository/__tests__/faqs.repository.test.js +311 -0
- package/dist/features/faq/schemas/firestore.d.ts +2 -4
- package/dist/features/faq/schemas/index.d.ts +2 -2
- package/dist/features/grouped/schemas/index.d.ts +2 -2
- package/dist/features/history/repository/__tests__/user-history.repository.test.d.ts +1 -0
- package/dist/features/history/repository/__tests__/user-history.repository.test.js +180 -0
- package/dist/features/homepage/api/[id]/route.d.ts +4 -4
- package/dist/features/homepage/api/carousel/[id]/route.d.ts +4 -4
- package/dist/features/homepage/api/carousel/route.d.ts +2 -2
- package/dist/features/homepage/api/route.d.ts +2 -2
- package/dist/features/homepage/repository/__tests__/carousel.repository.test.d.ts +1 -0
- package/dist/features/homepage/repository/__tests__/carousel.repository.test.js +182 -0
- package/dist/features/homepage/repository/__tests__/homepage-sections.repository.test.d.ts +1 -0
- package/dist/features/homepage/repository/__tests__/homepage-sections.repository.test.js +185 -0
- package/dist/features/homepage/schemas/firestore.d.ts +4 -12
- package/dist/features/homepage/schemas/index.d.ts +2 -2
- package/dist/features/lottery/repository/lottery-entry.repository.d.ts +33 -0
- package/dist/features/lottery/repository/lottery-entry.repository.js +130 -0
- package/dist/features/lottery/schemas/firestore.d.ts +49 -0
- package/dist/features/lottery/schemas/firestore.js +25 -0
- package/dist/features/lottery/schemas/zod.d.ts +113 -0
- package/dist/features/lottery/schemas/zod.js +39 -0
- package/dist/features/lottery/types/index.d.ts +67 -0
- package/dist/features/lottery/types/index.js +55 -0
- package/dist/features/messages/repository/__tests__/conversations.repository.test.d.ts +1 -0
- package/dist/features/messages/repository/__tests__/conversations.repository.test.js +257 -0
- package/dist/features/messages/schemas/firestore.d.ts +2 -4
- package/dist/features/messages/schemas/index.d.ts +2 -2
- package/dist/features/orders/repository/__tests__/orders.repository.test.d.ts +1 -0
- package/dist/features/orders/repository/__tests__/orders.repository.test.js +211 -0
- package/dist/features/orders/repository/orders.repository.d.ts +5 -0
- package/dist/features/orders/repository/orders.repository.js +26 -0
- package/dist/features/orders/schemas/firestore.d.ts +9 -5
- package/dist/features/orders/schemas/firestore.js +3 -0
- package/dist/features/payments/repository/__tests__/payout.repository.test.d.ts +1 -0
- package/dist/features/payments/repository/__tests__/payout.repository.test.js +292 -0
- package/dist/features/payments/schemas/firestore.d.ts +2 -4
- package/dist/features/pre-orders/schemas/index.d.ts +2 -2
- package/dist/features/products/api/[id]/route.d.ts +4 -4
- package/dist/features/products/api/route.d.ts +2 -2
- package/dist/features/products/constants/action-defs.d.ts +16 -0
- package/dist/features/products/constants/action-defs.js +16 -0
- package/dist/features/products/constants/listing-tabs.d.ts +48 -0
- package/dist/features/products/constants/listing-tabs.js +12 -0
- package/dist/features/products/repository/__tests__/product-features.repository.test.d.ts +1 -0
- package/dist/features/products/repository/__tests__/product-features.repository.test.js +329 -0
- package/dist/features/products/repository/__tests__/products.repository.test.d.ts +1 -0
- package/dist/features/products/repository/__tests__/products.repository.test.js +607 -0
- package/dist/features/products/repository/products.repository.d.ts +37 -0
- package/dist/features/products/repository/products.repository.js +28 -1
- package/dist/features/products/schemas/firestore.d.ts +23 -7
- package/dist/features/products/schemas/firestore.js +2 -0
- package/dist/features/products/schemas/index.d.ts +18 -18
- package/dist/features/products/schemas/index.js +4 -2
- package/dist/features/products/types/index.d.ts +3 -1
- package/dist/features/promotions/repository/__tests__/claimed-coupons.repository.test.d.ts +1 -0
- package/dist/features/promotions/repository/__tests__/claimed-coupons.repository.test.js +219 -0
- package/dist/features/promotions/repository/__tests__/coupons.repository.test.d.ts +1 -0
- package/dist/features/promotions/repository/__tests__/coupons.repository.test.js +480 -0
- package/dist/features/promotions/schemas/firestore.d.ts +2 -4
- package/dist/features/promotions/schemas/index.d.ts +4 -4
- package/dist/features/reviews/api/[id]/route.d.ts +4 -4
- package/dist/features/reviews/api/route.d.ts +2 -2
- package/dist/features/reviews/repository/__tests__/reviews.repository.test.d.ts +1 -0
- package/dist/features/reviews/repository/__tests__/reviews.repository.test.js +327 -0
- package/dist/features/reviews/schemas/firestore.d.ts +2 -4
- package/dist/features/reviews/schemas/index.d.ts +2 -2
- package/dist/features/scams/repository/__tests__/scammer.repository.test.d.ts +1 -0
- package/dist/features/scams/repository/__tests__/scammer.repository.test.js +385 -0
- package/dist/features/scams/schemas/firestore.d.ts +2 -4
- package/dist/features/scams/schemas/index.d.ts +4 -4
- package/dist/features/search/repository/__tests__/search.repository.test.d.ts +1 -0
- package/dist/features/search/repository/__tests__/search.repository.test.js +369 -0
- package/dist/features/search/schemas/index.d.ts +2 -2
- package/dist/features/seller/api/coupons/route.d.ts +2 -2
- package/dist/features/seller/api/offers/route.d.ts +2 -2
- package/dist/features/seller/api/products/route.d.ts +2 -2
- package/dist/features/seller/api/store/route.d.ts +2 -2
- package/dist/features/seller/components/BarcodeField.d.ts +17 -0
- package/dist/features/seller/components/BarcodeField.js +30 -0
- package/dist/features/seller/components/FulfillmentView.d.ts +5 -0
- package/dist/features/seller/components/FulfillmentView.js +120 -0
- package/dist/features/seller/components/PrintCenterView.d.ts +3 -1
- package/dist/features/seller/components/PrintCenterView.js +52 -4
- package/dist/features/seller/components/SellerProductShell.d.ts +2 -0
- package/dist/features/seller/components/SellerProductShell.js +2 -1
- package/dist/features/seller/components/index.d.ts +4 -0
- package/dist/features/seller/components/index.js +2 -0
- package/dist/features/seller/repository/__tests__/offer.repository.test.d.ts +1 -0
- package/dist/features/seller/repository/__tests__/offer.repository.test.js +458 -0
- package/dist/features/seller/schemas/index.d.ts +2 -2
- package/dist/features/store-extensions/schemas/firestore.d.ts +12 -44
- package/dist/features/stores/components/StoreClassifiedsListing.d.ts +5 -0
- package/dist/features/stores/components/StoreClassifiedsListing.js +48 -0
- package/dist/features/stores/components/StoreClassifiedsPageView.d.ts +4 -0
- package/dist/features/stores/components/StoreClassifiedsPageView.js +20 -0
- package/dist/features/stores/components/StoreDetailLayoutView.js +23 -2
- package/dist/features/stores/components/StoreDigitalCodesListing.d.ts +5 -0
- package/dist/features/stores/components/StoreDigitalCodesListing.js +48 -0
- package/dist/features/stores/components/StoreDigitalCodesPageView.d.ts +4 -0
- package/dist/features/stores/components/StoreDigitalCodesPageView.js +20 -0
- package/dist/features/stores/components/StoreLiveItemsListing.d.ts +5 -0
- package/dist/features/stores/components/StoreLiveItemsListing.js +48 -0
- package/dist/features/stores/components/StoreLiveItemsPageView.d.ts +4 -0
- package/dist/features/stores/components/StoreLiveItemsPageView.js +20 -0
- package/dist/features/stores/components/index.d.ts +9 -0
- package/dist/features/stores/components/index.js +3 -0
- package/dist/features/stores/repository/__tests__/store.repository.test.d.ts +1 -0
- package/dist/features/stores/repository/__tests__/store.repository.test.js +261 -0
- package/dist/features/stores/schemas/firestore.d.ts +2 -4
- package/dist/features/stores/schemas/index.d.ts +4 -4
- package/dist/features/support/repository/__tests__/support.repository.test.d.ts +1 -0
- package/dist/features/support/repository/__tests__/support.repository.test.js +312 -0
- package/dist/features/support/schemas/firestore.d.ts +2 -4
- package/dist/features/support/schemas/index.d.ts +2 -2
- package/dist/features/wishlist/repository/__tests__/user-wishlist.repository.test.d.ts +1 -0
- package/dist/features/wishlist/repository/__tests__/user-wishlist.repository.test.js +139 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +17 -0
- package/dist/next/api/routeHandler.d.ts +1 -1
- package/dist/next/routing/route-map.d.ts +24 -0
- package/dist/next/routing/route-map.js +11 -0
- package/dist/repositories/index.d.ts +1 -0
- package/dist/repositories/index.js +2 -0
- package/dist/schemas/registry.d.ts +24 -24
- package/dist/security/index.d.ts +1 -1
- package/dist/security/index.js +1 -1
- package/dist/security/pii-schemas.d.ts +2 -0
- package/dist/security/pii-schemas.js +6 -0
- package/dist/seed/actions/demo-seed-actions.d.ts +1 -1
- package/dist/seed/events-seed-data.js +85 -2
- package/dist/seed/grouped-listings-seed-data.d.ts +5 -2
- package/dist/seed/index.d.ts +1 -0
- package/dist/seed/index.js +1 -0
- package/dist/seed/lottery-entries-seed-data.d.ts +2 -0
- package/dist/seed/lottery-entries-seed-data.js +108 -0
- package/dist/seed/manifest.js +1 -0
- package/dist/seed/products-preorders-seed-data.d.ts +5 -2
- package/dist/seed/products-standard-seed-data.js +8 -0
- package/dist/server-entry.d.ts +3 -0
- package/dist/server-entry.js +3 -0
- package/dist/server.d.ts +10 -4
- package/dist/server.js +6 -0
- package/dist/styles.css +1 -1
- package/dist/tailwind-utilities.css +1 -1
- package/dist/utils/id-generators.d.ts +8 -0
- package/dist/utils/id-generators.js +14 -0
- 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", "
|
|
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" | "
|
|
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" | "
|
|
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" | "
|
|
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" | "
|
|
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", "
|
|
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" | "
|
|
567
|
-
condition?: "new" | "used" | "refurbished" | "
|
|
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" | "
|
|
581
|
-
condition?: "new" | "used" | "refurbished" | "
|
|
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", "
|
|
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", "
|
|
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 @@
|
|
|
1
|
+
export {};
|
|
@@ -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
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|