@mohasinac/appkit 3.8.1 → 3.9.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/live/LiveItemDetailView.js +2 -2
- package/dist/_internal/client/features/lottery/LotteryAdminEditView.d.ts +4 -4
- package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +8 -8
- package/dist/_internal/client/features/lottery/LotteryAdminSlotView.d.ts +1 -1
- package/dist/_internal/client/features/lottery/LotteryAdminSlotView.js +2 -2
- package/dist/_internal/server/features/bundles/actions.js +2 -2
- package/dist/_internal/server/features/bundles/og.d.ts +1 -1
- package/dist/_internal/server/features/bundles/og.js +4 -5
- package/dist/_internal/server/features/checkout/actions.js +57 -21
- package/dist/_internal/server/features/checkout/stock-restore.d.ts +19 -0
- package/dist/_internal/server/features/checkout/stock-restore.js +80 -0
- package/dist/_internal/server/features/checkout/upi-resolution.d.ts +11 -0
- package/dist/_internal/server/features/checkout/upi-resolution.js +28 -0
- package/dist/_internal/server/features/classified/og.js +1 -1
- package/dist/_internal/server/features/digital-code/og.js +1 -1
- package/dist/_internal/server/features/item-requests/og.d.ts +2 -2
- package/dist/_internal/server/features/item-requests/og.js +4 -5
- package/dist/_internal/server/features/live/og.js +1 -1
- package/dist/_internal/server/features/lottery/adapters.d.ts +2 -2
- package/dist/_internal/server/features/lottery/adapters.js +1 -1
- package/dist/_internal/server/features/orders/actions.d.ts +28 -0
- package/dist/_internal/server/features/orders/actions.js +239 -4
- package/dist/_internal/server/features/orders/adapters.js +3 -0
- package/dist/_internal/server/features/payments/data.js +3 -2
- package/dist/_internal/server/features/payouts/actions.d.ts +2 -2
- package/dist/_internal/server/features/payouts/actions.js +4 -3
- package/dist/_internal/server/features/pre-orders/service.d.ts +1 -1
- package/dist/_internal/server/features/pre-orders/service.js +3 -2
- package/dist/_internal/server/features/prize-draws/og.js +5 -5
- package/dist/_internal/server/features/products/og.js +1 -1
- package/dist/_internal/server/features/promotions/service.js +3 -1
- package/dist/_internal/server/features/refunds/actions.d.ts +2 -2
- package/dist/_internal/server/features/refunds/actions.js +7 -6
- package/dist/_internal/server/functions/firestore.js +1 -1
- package/dist/_internal/server/functions/scheduled.d.ts +4 -1
- package/dist/_internal/server/functions/scheduled.js +26 -2
- package/dist/_internal/server/jobs/core/emiInstallmentReminder.js +1 -1
- package/dist/_internal/server/jobs/core/hardBanCascade.d.ts +4 -0
- package/dist/_internal/server/jobs/core/hardBanCascade.js +15 -4
- package/dist/_internal/server/jobs/core/hardBanReinstatement.d.ts +16 -0
- package/dist/_internal/server/jobs/core/hardBanReinstatement.js +63 -0
- package/dist/_internal/server/jobs/core/jobRunners.js +3 -1
- package/dist/_internal/server/jobs/core/onScamReportCreate.js +1 -1
- package/dist/_internal/server/jobs/core/paymentReviewAutoApprove.d.ts +10 -0
- package/dist/_internal/server/jobs/core/paymentReviewAutoApprove.js +60 -0
- package/dist/_internal/server/jobs/core/paymentWindowTimeout.d.ts +15 -0
- package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +59 -0
- package/dist/_internal/server/jobs/core/pendingOrderTimeout.d.ts +7 -0
- package/dist/_internal/server/jobs/core/pendingOrderTimeout.js +32 -6
- package/dist/_internal/server/jobs/handlers/hardBanReinstatement.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/hardBanReinstatement.js +2 -0
- package/dist/_internal/server/jobs/handlers/index.d.ts +3 -0
- package/dist/_internal/server/jobs/handlers/index.js +3 -0
- package/dist/_internal/server/jobs/handlers/messages.d.ts +4 -0
- package/dist/_internal/server/jobs/handlers/messages.js +4 -0
- package/dist/_internal/server/jobs/handlers/onShipmentAllocationSync.d.ts +3 -3
- package/dist/_internal/server/jobs/handlers/onShipmentAllocationSync.js +12 -12
- package/dist/_internal/server/jobs/handlers/onShipmentItemWrite.d.ts +1 -1
- package/dist/_internal/server/jobs/handlers/onShipmentItemWrite.js +5 -5
- package/dist/_internal/server/jobs/handlers/paymentReviewAutoApprove.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/paymentReviewAutoApprove.js +2 -0
- package/dist/_internal/server/jobs/handlers/paymentWindowTimeout.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/paymentWindowTimeout.js +2 -0
- package/dist/_internal/shared/actions/action-registry.js +27 -0
- package/dist/_internal/shared/checkout/order-math.js +3 -2
- package/dist/_internal/shared/checkout/rules/_defaults.js +1 -0
- package/dist/_internal/shared/checkout/rules/preorder.rule.js +7 -0
- package/dist/_internal/shared/checkout/rules/prize-draw.rule.js +7 -0
- package/dist/_internal/shared/checkout/rules/types.d.ts +11 -0
- package/dist/_internal/shared/features/auctions/errors.js +1 -1
- package/dist/_internal/shared/features/categories/bundle-copy.d.ts +0 -1
- package/dist/_internal/shared/features/categories/bundle-copy.js +0 -1
- package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +6 -6
- package/dist/_internal/shared/features/categories/bundle-schemas.js +2 -2
- package/dist/_internal/shared/features/checkout/config.d.ts +3 -3
- package/dist/_internal/shared/features/checkout/config.js +3 -3
- package/dist/_internal/shared/features/emi/schedule.d.ts +6 -6
- package/dist/_internal/shared/features/emi/schedule.js +10 -9
- package/dist/_internal/shared/features/promotions/errors.js +1 -1
- package/dist/_internal/shared/fees/calculator.d.ts +5 -5
- package/dist/_internal/shared/fees/calculator.js +19 -19
- package/dist/client.d.ts +1 -1
- package/dist/client.js +1 -1
- package/dist/constants/api-endpoints.d.ts +9 -0
- package/dist/constants/api-endpoints.js +3 -0
- package/dist/constants/field-names.d.ts +4 -0
- package/dist/constants/field-names.js +4 -0
- package/dist/features/admin/components/AdminArtView.js +2 -2
- package/dist/features/admin/components/AdminBidsView.js +2 -2
- package/dist/features/admin/components/AdminBundleEditorView.d.ts +1 -1
- package/dist/features/admin/components/AdminBundleEditorView.js +8 -8
- package/dist/features/admin/components/AdminBundlesView.js +6 -6
- package/dist/features/admin/components/AdminClassifiedView.js +2 -2
- package/dist/features/admin/components/AdminDigitalCodesView.js +2 -2
- package/dist/features/admin/components/AdminLiveView.js +2 -2
- package/dist/features/admin/components/AdminOrderEditorView.d.ts +6 -1
- package/dist/features/admin/components/AdminOrderEditorView.js +45 -5
- package/dist/features/admin/components/AdminOrdersView.js +8 -3
- package/dist/features/admin/components/AdminPayoutsView.js +2 -2
- package/dist/features/admin/components/AdminPrizeDrawsView.js +2 -2
- package/dist/features/admin/components/AdminReturnRequestsView.js +2 -2
- package/dist/features/admin/components/AdminSiteSettingsView.js +11 -11
- package/dist/features/admin/components/AdminStickersView.js +2 -2
- package/dist/features/admin/components/AdminSupportTicketDetailView.js +1 -1
- package/dist/features/admin/hooks/useAdminListingData.d.ts +1 -1
- package/dist/features/admin/hooks/useAdminListingData.js +3 -2
- package/dist/features/admin/schemas/firestore.d.ts +9 -7
- package/dist/features/admin/schemas/firestore.js +4 -3
- package/dist/features/auctions/components/AuctionBidsTable.js +3 -3
- package/dist/features/auth/checkout-value-otp.d.ts +46 -0
- package/dist/features/auth/checkout-value-otp.js +73 -0
- package/dist/features/auth/repository/user.repository.d.ts +6 -0
- package/dist/features/auth/repository/user.repository.js +19 -0
- package/dist/features/auth/schemas/firestore.d.ts +10 -0
- package/dist/features/auth/schemas/firestore.js +2 -0
- package/dist/features/cart/actions/cart-actions.d.ts +1 -1
- package/dist/features/cart/actions/cart-actions.js +4 -4
- package/dist/features/cart/components/CartView.d.ts +2 -2
- package/dist/features/cart/components/ShippingPicker.d.ts +4 -4
- package/dist/features/cart/components/ShippingPicker.js +11 -11
- package/dist/features/cart/repository/cart.repository.d.ts +1 -1
- package/dist/features/cart/repository/cart.repository.js +2 -2
- package/dist/features/cart/schemas/firestore.d.ts +2 -2
- package/dist/features/catalogue/components/CatalogueItemEditorView.js +3 -3
- package/dist/features/catalogue/components/PublicCatalogueView.js +2 -2
- package/dist/features/catalogue/schemas/validation.js +1 -1
- package/dist/features/categories/components/BundleCollage.js +2 -2
- package/dist/features/categories/components/BundleDetailView.js +2 -2
- package/dist/features/categories/components/BundleItemsPicker.d.ts +1 -1
- package/dist/features/categories/components/BundleItemsPicker.js +2 -2
- package/dist/features/categories/components/CategoryBundlesListing.js +2 -2
- package/dist/features/categories/schemas/firestore.d.ts +1 -1
- package/dist/features/categories/schemas/index.d.ts +3 -3
- package/dist/features/categories/schemas/index.js +2 -2
- package/dist/features/checkout/actions/checkout-value-otp-actions.d.ts +16 -0
- package/dist/features/checkout/actions/checkout-value-otp-actions.js +83 -0
- package/dist/features/checkout/actions/index.d.ts +1 -0
- package/dist/features/checkout/actions/index.js +1 -0
- package/dist/features/checkout/schemas/firestore.d.ts +1 -1
- package/dist/features/classified/components/index.d.ts +0 -4
- package/dist/features/classified/components/index.js +0 -2
- package/dist/features/digital-codes/components/index.d.ts +0 -4
- package/dist/features/digital-codes/components/index.js +0 -2
- package/dist/features/events/schemas/index.d.ts +1 -1
- package/dist/features/events/schemas/index.js +1 -1
- package/dist/features/homepage/components/FeaturedBundlesSection.js +2 -2
- package/dist/features/live/components/index.d.ts +0 -4
- package/dist/features/live/components/index.js +0 -2
- package/dist/features/lottery/types/index.d.ts +3 -3
- package/dist/features/lottery/types/index.js +5 -5
- package/dist/features/orders/components/OrderPaymentSummary.js +2 -2
- package/dist/features/orders/components/OrderSiblingPayments.js +1 -1
- package/dist/features/orders/components/RefundHistoryTable.js +1 -1
- package/dist/features/orders/components/RefundRequestView.js +1 -1
- package/dist/features/orders/constants/payment-window.d.ts +10 -0
- package/dist/features/orders/constants/payment-window.js +10 -0
- package/dist/features/orders/repository/orders.repository.d.ts +25 -0
- package/dist/features/orders/repository/orders.repository.js +50 -1
- package/dist/features/orders/schemas/firestore.d.ts +50 -2
- package/dist/features/orders/schemas/index.d.ts +24 -24
- package/dist/features/orders/schemas/index.js +20 -20
- package/dist/features/orders/types/index.d.ts +4 -0
- package/dist/features/orders/utils/bundle-grouping.d.ts +1 -1
- package/dist/features/orders/utils/bundle-grouping.js +1 -1
- package/dist/features/payments/schemas/index.d.ts +10 -10
- package/dist/features/payments/schemas/index.js +9 -9
- package/dist/features/pre-orders/components/PreOrderDetailPageView.js +2 -2
- package/dist/features/products/components/ArtStickersListView.d.ts +7 -0
- package/dist/features/products/components/ArtStickersListView.js +57 -0
- package/dist/features/products/components/GroupSettingsPanel.js +1 -1
- package/dist/features/products/components/MakeOfferButton.js +3 -3
- package/dist/features/products/components/MarketplaceBundleCard.d.ts +1 -1
- package/dist/features/products/components/MarketplaceBundleCard.js +2 -2
- package/dist/features/products/components/PrizeDrawCollage.js +2 -2
- package/dist/features/products/components/PrizeDrawItemsEditor.js +2 -2
- package/dist/features/products/components/PrizeRevealModal.js +1 -1
- package/dist/features/products/components/ProductDetailPageView.js +2 -9
- package/dist/features/products/components/ProductForm.js +2 -2
- package/dist/features/products/components/ProductGrid.js +2 -2
- package/dist/features/products/components/ProductsIndexListing.d.ts +13 -1
- package/dist/features/products/components/ProductsIndexListing.js +7 -5
- package/dist/features/products/components/ProductsIndexPageView.js +6 -1
- package/dist/features/products/constants/listing-tabs.d.ts +42 -17
- package/dist/features/products/constants/listing-tabs.js +25 -6
- package/dist/features/products/schemas/catalog-product.d.ts +5 -5
- package/dist/features/products/schemas/catalog-product.js +1 -1
- package/dist/features/products/schemas/firestore.d.ts +5 -5
- package/dist/features/products/schemas/firestore.js +2 -2
- package/dist/features/products/types/index.d.ts +5 -2
- package/dist/features/promotions/components/CouponCard.js +2 -2
- package/dist/features/promotions/schemas/firestore.d.ts +2 -0
- package/dist/features/promotions/schemas/firestore.js +1 -0
- package/dist/features/promotions/schemas/index.d.ts +14 -14
- package/dist/features/promotions/schemas/index.js +6 -6
- package/dist/features/scams/components/ScamProfileView.js +3 -7
- package/dist/features/scams/components/ScamRegistryView.js +2 -6
- package/dist/features/scams/schemas/firestore.d.ts +1 -1
- package/dist/features/search/components/Search.d.ts +1 -1
- package/dist/features/seller/actions/offer-actions.js +1 -1
- package/dist/features/seller/components/PrintCenterView.js +2 -2
- package/dist/features/seller/components/QuickProductForm.js +5 -5
- package/dist/features/seller/components/SellerArtView.js +2 -2
- package/dist/features/seller/components/SellerAuctionsView.js +2 -2
- package/dist/features/seller/components/SellerBidsView.js +2 -2
- package/dist/features/seller/components/SellerBundlesView.js +6 -6
- package/dist/features/seller/components/SellerClassifiedView.js +2 -2
- package/dist/features/seller/components/SellerDigitalCodesView.js +2 -2
- package/dist/features/seller/components/SellerLiveView.js +2 -2
- package/dist/features/seller/components/SellerOffersView.js +2 -2
- package/dist/features/seller/components/SellerOrdersView.js +3 -3
- package/dist/features/seller/components/SellerPayoutRequestView.js +2 -2
- package/dist/features/seller/components/SellerPayoutSettingsView.js +2 -2
- package/dist/features/seller/components/SellerPayoutsView.js +2 -2
- package/dist/features/seller/components/SellerPreOrdersView.js +2 -2
- package/dist/features/seller/components/SellerPrizeDrawsView.js +2 -2
- package/dist/features/seller/components/SellerProductShell.js +8 -8
- package/dist/features/seller/components/SellerProductsView.js +1 -1
- package/dist/features/seller/components/SellerShippingView.js +6 -6
- package/dist/features/seller/components/SellerStickersView.js +2 -2
- package/dist/features/seller/hooks/useSellerListingData.d.ts +1 -1
- package/dist/features/seller/hooks/useSellerListingData.js +3 -2
- package/dist/features/shipments/components/AdminShipmentEditorView.js +10 -10
- package/dist/features/shipments/components/AdminShipmentLotItemsView.js +4 -4
- package/dist/features/shipments/components/AdminShipmentProjectionsView.js +5 -5
- package/dist/features/shipments/components/AdminShipmentsView.js +4 -4
- package/dist/features/shipments/repository/shipment-lots.repository.d.ts +2 -2
- package/dist/features/shipments/repository/shipment-lots.repository.js +8 -8
- package/dist/features/shipments/schemas/firestore.d.ts +21 -21
- package/dist/features/shipments/schemas/firestore.js +9 -9
- package/dist/features/shipments/schemas/validation.d.ts +30 -30
- package/dist/features/shipments/schemas/validation.js +6 -6
- package/dist/features/shipments/utils/cost-allocation.d.ts +5 -5
- package/dist/features/shipments/utils/cost-allocation.js +39 -38
- package/dist/features/store-extensions/schemas/firestore.d.ts +5 -5
- package/dist/features/stores/components/StoreDetailLayoutView.js +9 -13
- package/dist/features/stores/schemas/firestore.d.ts +7 -7
- package/dist/features/stores/schemas/index.d.ts +84 -84
- package/dist/features/stores/schemas/index.js +5 -5
- package/dist/features/tester/seed-data/categories-tester-seed-data.js +1 -1
- package/dist/features/tester/seed-data/products-tester-seed-data.js +6 -6
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +9 -2
- package/dist/features/whatsapp-bot/helpers/whatsapp.d.ts +8 -1
- package/dist/features/whatsapp-bot/helpers/whatsapp.js +13 -2
- package/dist/features/whatsapp-bot/types/index.d.ts +9 -1
- package/dist/index.d.ts +4 -7
- package/dist/index.js +9 -5
- package/dist/next/routing/route-map.d.ts +2 -0
- package/dist/next/routing/route-map.js +6 -0
- package/dist/schemas/firestore-helpers.d.ts +2 -2
- package/dist/schemas/firestore-helpers.js +2 -2
- package/dist/schemas/registry.d.ts +73 -73
- package/dist/security/index.d.ts +2 -1
- package/dist/security/index.js +5 -1
- package/dist/security/pii-encrypt.d.ts +2 -53
- package/dist/security/pii-encrypt.js +19 -100
- package/dist/security/pii-mask.d.ts +67 -0
- package/dist/security/pii-mask.js +100 -0
- package/dist/seed/bids-seed-data.js +6 -6
- package/dist/seed/blog-posts-seed-data.js +1 -0
- package/dist/seed/cart-seed-data.js +13 -13
- package/dist/seed/catalogue-seed-data.js +6 -6
- package/dist/seed/categories-seed-data.js +5 -5
- package/dist/seed/claimed-coupons-seed-data.js +3 -3
- package/dist/seed/coupons-seed-data.js +20 -20
- package/dist/seed/events-seed-data.js +27 -27
- package/dist/seed/factories/bid.factory.js +1 -1
- package/dist/seed/faq-seed-data.js +20 -1
- package/dist/seed/grouped-listings-seed-data.d.ts +2 -2
- package/dist/seed/grouped-listings-seed-data.js +3 -3
- package/dist/seed/offers-seed-data.js +19 -19
- package/dist/seed/orders-seed-data.js +29 -29
- package/dist/seed/payouts-seed-data.js +7 -7
- package/dist/seed/products-auctions-seed-data.js +6 -6
- package/dist/seed/products-preorders-seed-data.d.ts +2 -2
- package/dist/seed/products-preorders-seed-data.js +1 -1
- package/dist/seed/products-standard-seed-data.js +8 -8
- package/dist/seed/scammers-seed-data.js +2 -2
- package/dist/seed/shipments-seed-data.js +29 -29
- package/dist/seed/site-settings-seed-data.js +3 -2
- package/dist/seed/store-extensions-seed-data.js +8 -8
- package/dist/seed/stores-seed-data.js +37 -8
- package/dist/seed/users-seed-data.js +38 -1
- package/dist/server-entry.d.ts +1 -3
- package/dist/server-entry.js +1 -3
- package/dist/server.d.ts +2 -1
- package/dist/server.js +3 -1
- package/dist/ui/components/PriceDisplay.js +3 -12
- package/dist/utils/number.formatter.d.ts +2 -7
- package/dist/utils/number.formatter.js +3 -8
- package/package.json +1 -1
- package/scripts/seed-cli.mjs +17 -3
- package/dist/_internal/client/scaffolds/DashboardScaffold.d.ts +0 -34
- package/dist/_internal/client/scaffolds/DashboardScaffold.js +0 -26
- package/dist/_internal/client/theme/__tests__/ThemeProvider.test.d.ts +0 -1
- package/dist/_internal/client/theme/__tests__/ThemeProvider.test.js +0 -109
- package/dist/_internal/server/features/auctions/__tests__/service.test.d.ts +0 -1
- package/dist/_internal/server/features/auctions/__tests__/service.test.js +0 -140
- package/dist/_internal/server/features/checkout/__tests__/actions.test.d.ts +0 -1
- package/dist/_internal/server/features/checkout/__tests__/actions.test.js +0 -600
- package/dist/_internal/server/features/refunds/__tests__/actions.test.d.ts +0 -1
- package/dist/_internal/server/features/refunds/__tests__/actions.test.js +0 -263
- package/dist/_internal/server/jobs/core/__tests__/auctionSettlement.test.d.ts +0 -1
- package/dist/_internal/server/jobs/core/__tests__/auctionSettlement.test.js +0 -249
- package/dist/_internal/server/jobs/core/__tests__/couponExpiry.test.d.ts +0 -1
- package/dist/_internal/server/jobs/core/__tests__/couponExpiry.test.js +0 -65
- package/dist/_internal/server/jobs/core/__tests__/listingProcessor.test.d.ts +0 -1
- package/dist/_internal/server/jobs/core/__tests__/listingProcessor.test.js +0 -163
- package/dist/_internal/server/jobs/core/__tests__/mediaTmpCleanup.test.d.ts +0 -1
- package/dist/_internal/server/jobs/core/__tests__/mediaTmpCleanup.test.js +0 -115
- package/dist/_internal/server/jobs/core/__tests__/onBidPlaced.test.d.ts +0 -1
- package/dist/_internal/server/jobs/core/__tests__/onBidPlaced.test.js +0 -201
- package/dist/_internal/server/jobs/core/__tests__/onOrderCreate.test.d.ts +0 -1
- package/dist/_internal/server/jobs/core/__tests__/onOrderCreate.test.js +0 -169
- package/dist/_internal/server/jobs/core/__tests__/onOrderStatusChange.test.d.ts +0 -1
- package/dist/_internal/server/jobs/core/__tests__/onOrderStatusChange.test.js +0 -148
- package/dist/_internal/server/jobs/core/__tests__/onProductStockChange.test.d.ts +0 -1
- package/dist/_internal/server/jobs/core/__tests__/onProductStockChange.test.js +0 -210
- package/dist/_internal/server/jobs/core/__tests__/onReviewWrite.test.d.ts +0 -1
- package/dist/_internal/server/jobs/core/__tests__/onReviewWrite.test.js +0 -190
- package/dist/_internal/server/jobs/core/__tests__/onUserBanChange.test.d.ts +0 -1
- package/dist/_internal/server/jobs/core/__tests__/onUserBanChange.test.js +0 -161
- package/dist/_internal/server/jobs/core/__tests__/payoutBatch.test.d.ts +0 -1
- package/dist/_internal/server/jobs/core/__tests__/payoutBatch.test.js +0 -302
- package/dist/_internal/server/jobs/core/__tests__/pendingOrderTimeout.test.d.ts +0 -1
- package/dist/_internal/server/jobs/core/__tests__/pendingOrderTimeout.test.js +0 -96
- package/dist/_internal/server/jobs/core/__tests__/triggerEventRaffle.test.d.ts +0 -1
- package/dist/_internal/server/jobs/core/__tests__/triggerEventRaffle.test.js +0 -252
- package/dist/_internal/server/jobs/core/__tests__/wrapJobHandler.test.d.ts +0 -1
- package/dist/_internal/server/jobs/core/__tests__/wrapJobHandler.test.js +0 -129
- package/dist/_internal/server/jobs/core/onCatalogueSubmittedForApproval.d.ts +0 -15
- package/dist/_internal/server/jobs/core/onCatalogueSubmittedForApproval.js +0 -38
- package/dist/_internal/server/providers/index.d.ts +0 -11
- package/dist/_internal/server/providers/index.js +0 -11
- package/dist/_internal/server/providers/payment/razorpay-mock.d.ts +0 -52
- package/dist/_internal/server/providers/payment/razorpay-mock.js +0 -118
- package/dist/_internal/server/providers/resolve.d.ts +0 -36
- package/dist/_internal/server/providers/resolve.js +0 -31
- package/dist/_internal/server/providers/shipping/shiprocket-mock.d.ts +0 -29
- package/dist/_internal/server/providers/shipping/shiprocket-mock.js +0 -152
- package/dist/_internal/shared/types/__tests__/action-result.test.d.ts +0 -1
- package/dist/_internal/shared/types/__tests__/action-result.test.js +0 -65
- package/dist/errors/__tests__/error-mapping.test.d.ts +0 -1
- package/dist/errors/__tests__/error-mapping.test.js +0 -122
- package/dist/errors/__tests__/safe-read.test.d.ts +0 -1
- package/dist/errors/__tests__/safe-read.test.js +0 -39
- package/dist/features/addresses/repository/__tests__/addresses.repository.test.d.ts +0 -1
- package/dist/features/addresses/repository/__tests__/addresses.repository.test.js +0 -386
- package/dist/features/admin/components/AdminListingScaffold.d.ts +0 -41
- package/dist/features/admin/components/AdminListingScaffold.js +0 -68
- package/dist/features/admin/components/QuickActionsPanel.d.ts +0 -15
- package/dist/features/admin/components/QuickActionsPanel.js +0 -5
- package/dist/features/admin/repository/__tests__/notification.repository.test.d.ts +0 -1
- package/dist/features/admin/repository/__tests__/notification.repository.test.js +0 -356
- package/dist/features/admin/repository/__tests__/site-settings.repository.test.d.ts +0 -1
- package/dist/features/admin/repository/__tests__/site-settings.repository.test.js +0 -298
- package/dist/features/auctions/repository/__tests__/bid.repository.test.d.ts +0 -1
- package/dist/features/auctions/repository/__tests__/bid.repository.test.js +0 -290
- package/dist/features/auctions/repository/auctions.repository.d.ts +0 -12
- package/dist/features/auctions/repository/auctions.repository.js +0 -42
- package/dist/features/auth/repository/__tests__/session.repository.test.d.ts +0 -1
- package/dist/features/auth/repository/__tests__/session.repository.test.js +0 -310
- package/dist/features/auth/repository/__tests__/session.test.d.ts +0 -1
- package/dist/features/auth/repository/__tests__/session.test.js +0 -146
- package/dist/features/auth/repository/__tests__/sms-counter.repository.test.d.ts +0 -1
- package/dist/features/auth/repository/__tests__/sms-counter.repository.test.js +0 -171
- package/dist/features/auth/repository/__tests__/sms-counter.test.d.ts +0 -1
- package/dist/features/auth/repository/__tests__/sms-counter.test.js +0 -88
- package/dist/features/auth/repository/__tests__/token.repository.test.d.ts +0 -1
- package/dist/features/auth/repository/__tests__/token.repository.test.js +0 -260
- package/dist/features/auth/repository/__tests__/token.test.d.ts +0 -1
- package/dist/features/auth/repository/__tests__/token.test.js +0 -140
- package/dist/features/auth/repository/__tests__/user.repository.test.d.ts +0 -1
- package/dist/features/auth/repository/__tests__/user.repository.test.js +0 -352
- package/dist/features/auth/repository/__tests__/user.test.d.ts +0 -1
- package/dist/features/auth/repository/__tests__/user.test.js +0 -226
- package/dist/features/before-after/repository/before-after.repository.d.ts +0 -13
- package/dist/features/before-after/repository/before-after.repository.js +0 -36
- package/dist/features/before-after/server.d.ts +0 -6
- package/dist/features/before-after/server.js +0 -6
- package/dist/features/cart/repository/__tests__/cart.repository.test.d.ts +0 -1
- package/dist/features/cart/repository/__tests__/cart.repository.test.js +0 -371
- package/dist/features/categories/repository/__tests__/categories.repository.test.d.ts +0 -1
- package/dist/features/categories/repository/__tests__/categories.repository.test.js +0 -813
- package/dist/features/collections/repository/collections.repository.d.ts +0 -8
- package/dist/features/collections/repository/collections.repository.js +0 -16
- package/dist/features/collections/server.d.ts +0 -6
- package/dist/features/collections/server.js +0 -6
- package/dist/features/events/repository/__tests__/event.repository.test.d.ts +0 -1
- package/dist/features/events/repository/__tests__/event.repository.test.js +0 -299
- package/dist/features/faq/repository/__tests__/faqs.repository.test.d.ts +0 -1
- package/dist/features/faq/repository/__tests__/faqs.repository.test.js +0 -311
- package/dist/features/forms/Form.d.ts +0 -25
- package/dist/features/forms/Form.js +0 -37
- package/dist/features/history/repository/__tests__/user-history.repository.test.d.ts +0 -1
- package/dist/features/history/repository/__tests__/user-history.repository.test.js +0 -180
- package/dist/features/homepage/repository/__tests__/carousel.repository.test.d.ts +0 -1
- package/dist/features/homepage/repository/__tests__/carousel.repository.test.js +0 -182
- package/dist/features/homepage/repository/__tests__/homepage-sections.repository.test.d.ts +0 -1
- package/dist/features/homepage/repository/__tests__/homepage-sections.repository.test.js +0 -185
- package/dist/features/layout/ListingLayout.d.ts +0 -34
- package/dist/features/layout/ListingLayout.js +0 -103
- package/dist/features/messages/repository/__tests__/conversations.repository.test.d.ts +0 -1
- package/dist/features/messages/repository/__tests__/conversations.repository.test.js +0 -257
- package/dist/features/orders/repository/__tests__/orders.repository.test.d.ts +0 -1
- package/dist/features/orders/repository/__tests__/orders.repository.test.js +0 -211
- package/dist/features/payments/repository/__tests__/payout.repository.test.d.ts +0 -1
- package/dist/features/payments/repository/__tests__/payout.repository.test.js +0 -292
- package/dist/features/pre-orders/repository/preorders.repository.d.ts +0 -8
- package/dist/features/pre-orders/repository/preorders.repository.js +0 -25
- package/dist/features/products/repository/__tests__/product-features.repository.test.d.ts +0 -1
- package/dist/features/products/repository/__tests__/product-features.repository.test.js +0 -329
- package/dist/features/products/repository/__tests__/products.repository.test.d.ts +0 -1
- package/dist/features/products/repository/__tests__/products.repository.test.js +0 -607
- package/dist/features/promotions/repository/__tests__/claimed-coupons.repository.test.d.ts +0 -1
- package/dist/features/promotions/repository/__tests__/claimed-coupons.repository.test.js +0 -219
- package/dist/features/promotions/repository/__tests__/coupons.repository.test.d.ts +0 -1
- package/dist/features/promotions/repository/__tests__/coupons.repository.test.js +0 -480
- package/dist/features/promotions/repository/promotions.repository.d.ts +0 -14
- package/dist/features/promotions/repository/promotions.repository.js +0 -43
- package/dist/features/reviews/repository/__tests__/reviews.repository.test.d.ts +0 -1
- package/dist/features/reviews/repository/__tests__/reviews.repository.test.js +0 -327
- package/dist/features/scams/repository/__tests__/scammer.repository.test.d.ts +0 -1
- package/dist/features/scams/repository/__tests__/scammer.repository.test.js +0 -385
- package/dist/features/search/repository/__tests__/search.repository.test.d.ts +0 -1
- package/dist/features/search/repository/__tests__/search.repository.test.js +0 -369
- package/dist/features/seller/components/SellerStatCard.d.ts +0 -14
- package/dist/features/seller/components/SellerStatCard.js +0 -6
- package/dist/features/seller/components/seller-products-styles.d.ts +0 -7
- package/dist/features/seller/components/seller-products-styles.js +0 -14
- package/dist/features/seller/repository/__tests__/offer.repository.test.d.ts +0 -1
- package/dist/features/seller/repository/__tests__/offer.repository.test.js +0 -458
- package/dist/features/seller/repository/seller.repository.d.ts +0 -22
- package/dist/features/seller/repository/seller.repository.js +0 -72
- package/dist/features/site-settings/components/__tests__/ThemeManagerView.test.d.ts +0 -1
- package/dist/features/site-settings/components/__tests__/ThemeManagerView.test.js +0 -37
- package/dist/features/stores/repository/__tests__/store.repository.test.d.ts +0 -1
- package/dist/features/stores/repository/__tests__/store.repository.test.js +0 -261
- package/dist/features/stores/repository/stores.repository.d.ts +0 -11
- package/dist/features/stores/repository/stores.repository.js +0 -37
- package/dist/features/support/repository/__tests__/support.repository.test.d.ts +0 -1
- package/dist/features/support/repository/__tests__/support.repository.test.js +0 -312
- package/dist/features/wishlist/repository/__tests__/user-wishlist.repository.test.d.ts +0 -1
- package/dist/features/wishlist/repository/__tests__/user-wishlist.repository.test.js +0 -139
- package/dist/features/wishlist/repository/wishlist.repository.d.ts +0 -13
- package/dist/features/wishlist/repository/wishlist.repository.js +0 -31
- package/dist/providers/db-firebase/__tests__/filter-aliases.test.d.ts +0 -1
- package/dist/providers/db-firebase/__tests__/filter-aliases.test.js +0 -93
- package/dist/providers/shipping-shiprocket/index.d.ts +0 -297
- package/dist/providers/shipping-shiprocket/index.js +0 -194
- package/dist/providers/shipping-shiprocket/shiprocket-provider.d.ts +0 -45
- package/dist/providers/shipping-shiprocket/shiprocket-provider.js +0 -168
- package/dist/react/contexts/ThemeContext.d.ts +0 -13
- package/dist/react/contexts/ThemeContext.js +0 -64
- package/dist/schemas/webhooks/shiprocket.d.ts +0 -30
- package/dist/schemas/webhooks/shiprocket.js +0 -22
- package/dist/seed/actions/demo-seed-actions.d.ts +0 -42
- package/dist/seed/actions/demo-seed-actions.js +0 -36
- package/dist/seed/actions/index.d.ts +0 -1
- package/dist/seed/actions/index.js +0 -1
- package/dist/seed/sub-listings-seed-data.d.ts +0 -123
- package/dist/seed/sub-listings-seed-data.js +0 -447
- package/dist/seed/tester-checklist-seed-data.d.ts +0 -2
- package/dist/seed/tester-checklist-seed-data.js +0 -248
- package/dist/ui/components/DashboardStatsCard.d.ts +0 -15
- package/dist/ui/components/DashboardStatsCard.js +0 -27
- package/dist/ui/components/DashboardStatsCard.style.css +0 -68
- package/dist/ui/components/DynamicSelect.d.ts +0 -23
- package/dist/ui/components/DynamicSelect.js +0 -77
- package/dist/ui/components/DynamicSelect.style.css +0 -101
- package/dist/ui/components/InlineCreateSelect.d.ts +0 -48
- package/dist/ui/components/InlineCreateSelect.js +0 -75
- package/dist/ui/components/ListingViewShell.d.ts +0 -37
- package/dist/ui/components/ListingViewShell.js +0 -9
- package/dist/ui/components/PaginatedMultiSelect.d.ts +0 -28
- package/dist/ui/components/PaginatedMultiSelect.js +0 -141
- package/dist/ui/components/PaginatedMultiSelect.style.css +0 -272
- package/dist/ui/components/SectionTabs.d.ts +0 -19
- package/dist/ui/components/SectionTabs.js +0 -66
- package/dist/ui/components/SectionTabs.style.css +0 -164
- package/dist/ui/components/__tests__/BulkActionBar.test.d.ts +0 -1
- package/dist/ui/components/__tests__/BulkActionBar.test.js +0 -96
- package/dist/ui/components/__tests__/ListingToolbar.test.d.ts +0 -1
- package/dist/ui/components/__tests__/ListingToolbar.test.js +0 -125
- package/dist/ui/components/__tests__/new-primitives.test.d.ts +0 -1
- package/dist/ui/components/__tests__/new-primitives.test.js +0 -187
|
@@ -1,252 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from "vitest";
|
|
2
|
-
// No repository mocks needed — function uses ctx.db directly.
|
|
3
|
-
import { runTriggerEventRaffle } from "../triggerEventRaffle";
|
|
4
|
-
// ── Helpers ─────────────────────────────────────────────────────────────────
|
|
5
|
-
function makeCtx(dbOverrides = {}) {
|
|
6
|
-
return {
|
|
7
|
-
db: buildMockDb(dbOverrides),
|
|
8
|
-
now: new Date("2026-01-01T00:00:00Z"),
|
|
9
|
-
env: vi.fn().mockReturnValue(""),
|
|
10
|
-
logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Builds a mock Firestore db that:
|
|
15
|
-
* - eventSnap: resolved by the 'events' collection path
|
|
16
|
-
* - entriesSnap: resolved by the 'eventEntries' collection path
|
|
17
|
-
*/
|
|
18
|
-
function buildMockDb(overrides = {}) {
|
|
19
|
-
const { eventExists = true, eventData = {}, entriesDocs = [], updateFn = vi.fn().mockResolvedValue(undefined), } = overrides;
|
|
20
|
-
const mockUpdate = updateFn;
|
|
21
|
-
// Chain for event: db.collection("events").doc(id).get()
|
|
22
|
-
const eventSnap = { exists: eventExists, data: () => eventData };
|
|
23
|
-
const eventDocRef = { get: vi.fn().mockResolvedValue(eventSnap), update: mockUpdate };
|
|
24
|
-
const eventsCollection = { doc: vi.fn().mockReturnValue(eventDocRef) };
|
|
25
|
-
// Chain for entries: db.collection("eventEntries").where(...).where(...).get()
|
|
26
|
-
const entriesSnap = {
|
|
27
|
-
docs: entriesDocs,
|
|
28
|
-
size: entriesDocs.length,
|
|
29
|
-
};
|
|
30
|
-
const entriesQuery = {
|
|
31
|
-
where: vi.fn().mockReturnThis(),
|
|
32
|
-
get: vi.fn().mockResolvedValue(entriesSnap),
|
|
33
|
-
};
|
|
34
|
-
const entriesCollection = { where: vi.fn().mockReturnValue(entriesQuery) };
|
|
35
|
-
const db = {
|
|
36
|
-
collection: vi.fn((name) => {
|
|
37
|
-
if (name === "events")
|
|
38
|
-
return eventsCollection;
|
|
39
|
-
if (name === "eventEntries")
|
|
40
|
-
return entriesCollection;
|
|
41
|
-
return eventsCollection;
|
|
42
|
-
}),
|
|
43
|
-
mockUpdate, // expose for assertions
|
|
44
|
-
};
|
|
45
|
-
return db;
|
|
46
|
-
}
|
|
47
|
-
function makeEntry(overrides = {}) {
|
|
48
|
-
const { id = "entry-1", userId = "user-ravi", displayName = "Ravi Kumar", points = 0, createdAt = new Date() } = overrides;
|
|
49
|
-
return {
|
|
50
|
-
id,
|
|
51
|
-
data: () => ({ userId, userDisplayName: displayName, points, createdAt }),
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
const INPUT_BASE = { eventId: "event-summer-raffle" };
|
|
55
|
-
// ── Tests ────────────────────────────────────────────────────────────────────
|
|
56
|
-
describe("runTriggerEventRaffle — event not found", () => {
|
|
57
|
-
it("returns reason=event_not_found when event does not exist", async () => {
|
|
58
|
-
const ctx = makeCtx({ eventExists: false });
|
|
59
|
-
const result = await runTriggerEventRaffle(INPUT_BASE, ctx);
|
|
60
|
-
expect(result.reason).toBe("event_not_found");
|
|
61
|
-
expect(result.raffleEntryCount).toBe(0);
|
|
62
|
-
});
|
|
63
|
-
it("does NOT update eventRef when event not found", async () => {
|
|
64
|
-
const ctx = makeCtx({ eventExists: false });
|
|
65
|
-
await runTriggerEventRaffle(INPUT_BASE, ctx);
|
|
66
|
-
expect(ctx.db.mockUpdate).not.toHaveBeenCalled();
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
describe("runTriggerEventRaffle — already triggered (idempotency)", () => {
|
|
70
|
-
it("returns alreadyTriggered=true when winner already set", async () => {
|
|
71
|
-
const ctx = makeCtx({ eventData: { raffleWinnerUserId: "user-already-won" } });
|
|
72
|
-
const result = await runTriggerEventRaffle(INPUT_BASE, ctx);
|
|
73
|
-
expect(result.alreadyTriggered).toBe(true);
|
|
74
|
-
expect(result.raffleWinnerUserId).toBe("user-already-won");
|
|
75
|
-
});
|
|
76
|
-
it("does NOT query entries or update event when already triggered", async () => {
|
|
77
|
-
const ctx = makeCtx({ eventData: { raffleWinnerUserId: "user-already-won" } });
|
|
78
|
-
await runTriggerEventRaffle(INPUT_BASE, ctx);
|
|
79
|
-
expect(ctx.db.mockUpdate).not.toHaveBeenCalled();
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
describe("runTriggerEventRaffle — no eligible entries", () => {
|
|
83
|
-
it("returns reason=no_eligible_entries when no CONFIRMED entries exist", async () => {
|
|
84
|
-
const ctx = makeCtx({ entriesDocs: [] });
|
|
85
|
-
const result = await runTriggerEventRaffle(INPUT_BASE, ctx);
|
|
86
|
-
expect(result.reason).toBe("no_eligible_entries");
|
|
87
|
-
expect(result.raffleEntryCount).toBe(0);
|
|
88
|
-
});
|
|
89
|
-
it("does NOT update event when no entries", async () => {
|
|
90
|
-
const ctx = makeCtx({ entriesDocs: [] });
|
|
91
|
-
await runTriggerEventRaffle(INPUT_BASE, ctx);
|
|
92
|
-
expect(ctx.db.mockUpdate).not.toHaveBeenCalled();
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
describe("runTriggerEventRaffle — open_raffle (default)", () => {
|
|
96
|
-
it("all confirmed entries are in the pool", async () => {
|
|
97
|
-
const entries = [
|
|
98
|
-
makeEntry({ id: "e1", userId: "user-1" }),
|
|
99
|
-
makeEntry({ id: "e2", userId: "user-2" }),
|
|
100
|
-
makeEntry({ id: "e3", userId: "user-3" }),
|
|
101
|
-
];
|
|
102
|
-
const ctx = makeCtx({ eventData: { raffleType: "open_raffle" }, entriesDocs: entries });
|
|
103
|
-
const result = await runTriggerEventRaffle(INPUT_BASE, ctx);
|
|
104
|
-
expect(["user-1", "user-2", "user-3"]).toContain(result.raffleWinnerUserId);
|
|
105
|
-
});
|
|
106
|
-
it("winner fields written back to event doc", async () => {
|
|
107
|
-
const updateFn = vi.fn().mockResolvedValue(undefined);
|
|
108
|
-
const entries = [makeEntry({ id: "e1", userId: "user-ravi", displayName: "Ravi" })];
|
|
109
|
-
const ctx = makeCtx({ entriesDocs: entries, updateFn });
|
|
110
|
-
await runTriggerEventRaffle(INPUT_BASE, ctx);
|
|
111
|
-
expect(updateFn).toHaveBeenCalledWith(expect.objectContaining({
|
|
112
|
-
raffleWinnerUserId: "user-ravi",
|
|
113
|
-
raffleWinnerDisplayName: "Ravi",
|
|
114
|
-
raffleWinnerEntryId: "e1",
|
|
115
|
-
raffleEntryCount: 1,
|
|
116
|
-
}));
|
|
117
|
-
});
|
|
118
|
-
it("raffleTriggeredAt = ctx.now", async () => {
|
|
119
|
-
const updateFn = vi.fn().mockResolvedValue(undefined);
|
|
120
|
-
const now = new Date("2026-03-15T10:00:00Z");
|
|
121
|
-
const entries = [makeEntry({ id: "e1" })];
|
|
122
|
-
const ctx = makeCtx({ entriesDocs: entries, updateFn });
|
|
123
|
-
ctx.now = now;
|
|
124
|
-
await runTriggerEventRaffle(INPUT_BASE, ctx);
|
|
125
|
-
expect(updateFn).toHaveBeenCalledWith(expect.objectContaining({ raffleTriggeredAt: now }));
|
|
126
|
-
});
|
|
127
|
-
it("raffleEntryCount = total entries (not pool size)", async () => {
|
|
128
|
-
const updateFn = vi.fn().mockResolvedValue(undefined);
|
|
129
|
-
const entries = [
|
|
130
|
-
makeEntry({ id: "e1", userId: "user-1" }),
|
|
131
|
-
makeEntry({ id: "e2", userId: "user-2" }),
|
|
132
|
-
];
|
|
133
|
-
const ctx = makeCtx({ entriesDocs: entries, updateFn });
|
|
134
|
-
await runTriggerEventRaffle({ ...INPUT_BASE, raffleType: "open_raffle" }, ctx);
|
|
135
|
-
expect(updateFn).toHaveBeenCalledWith(expect.objectContaining({ raffleEntryCount: 2 }));
|
|
136
|
-
});
|
|
137
|
-
it("returns correct winner in result object", async () => {
|
|
138
|
-
const entries = [makeEntry({ id: "e1", userId: "user-only", displayName: "Only User" })];
|
|
139
|
-
const ctx = makeCtx({ entriesDocs: entries });
|
|
140
|
-
const result = await runTriggerEventRaffle(INPUT_BASE, ctx);
|
|
141
|
-
expect(result.raffleWinnerUserId).toBe("user-only");
|
|
142
|
-
expect(result.raffleWinnerDisplayName).toBe("Only User");
|
|
143
|
-
expect(result.raffleEntryCount).toBe(1);
|
|
144
|
-
});
|
|
145
|
-
});
|
|
146
|
-
describe("runTriggerEventRaffle — top_n_scorers", () => {
|
|
147
|
-
it("pool limited to top N by points descending", async () => {
|
|
148
|
-
const entries = [
|
|
149
|
-
makeEntry({ id: "e1", userId: "user-low", points: 10 }),
|
|
150
|
-
makeEntry({ id: "e2", userId: "user-high", points: 100 }),
|
|
151
|
-
makeEntry({ id: "e3", userId: "user-mid", points: 50 }),
|
|
152
|
-
];
|
|
153
|
-
const ctx = makeCtx({ entriesDocs: entries });
|
|
154
|
-
// topN=1 means only the highest scorer can win
|
|
155
|
-
const result = await runTriggerEventRaffle({ ...INPUT_BASE, raffleType: "top_n_scorers", topN: 1 }, ctx);
|
|
156
|
-
expect(result.raffleWinnerUserId).toBe("user-high");
|
|
157
|
-
});
|
|
158
|
-
it("topN=2: winner is either top-1 or top-2 scorer, NOT bottom scorer", async () => {
|
|
159
|
-
const entries = [
|
|
160
|
-
makeEntry({ id: "e1", userId: "user-bottom", points: 1 }),
|
|
161
|
-
makeEntry({ id: "e2", userId: "user-top", points: 100 }),
|
|
162
|
-
makeEntry({ id: "e3", userId: "user-second", points: 50 }),
|
|
163
|
-
];
|
|
164
|
-
const ctx = makeCtx({ entriesDocs: entries });
|
|
165
|
-
const result = await runTriggerEventRaffle({ ...INPUT_BASE, raffleType: "top_n_scorers", topN: 2 }, ctx);
|
|
166
|
-
expect(["user-top", "user-second"]).toContain(result.raffleWinnerUserId);
|
|
167
|
-
expect(result.raffleWinnerUserId).not.toBe("user-bottom");
|
|
168
|
-
});
|
|
169
|
-
it("topN=0 → entire pool used (topN disabled)", async () => {
|
|
170
|
-
const entries = [
|
|
171
|
-
makeEntry({ id: "e1", userId: "user-1", points: 10 }),
|
|
172
|
-
makeEntry({ id: "e2", userId: "user-2", points: 20 }),
|
|
173
|
-
];
|
|
174
|
-
const ctx = makeCtx({ entriesDocs: entries });
|
|
175
|
-
const result = await runTriggerEventRaffle({ ...INPUT_BASE, raffleType: "top_n_scorers", topN: 0 }, ctx);
|
|
176
|
-
expect(["user-1", "user-2"]).toContain(result.raffleWinnerUserId);
|
|
177
|
-
});
|
|
178
|
-
it("reads raffleTopN from event when topN not in input", async () => {
|
|
179
|
-
const entries = [
|
|
180
|
-
makeEntry({ id: "e1", userId: "user-low", points: 5 }),
|
|
181
|
-
makeEntry({ id: "e2", userId: "user-high", points: 999 }),
|
|
182
|
-
];
|
|
183
|
-
const ctx = makeCtx({
|
|
184
|
-
eventData: { raffleType: "top_n_scorers", raffleTopN: 1 },
|
|
185
|
-
entriesDocs: entries,
|
|
186
|
-
});
|
|
187
|
-
const result = await runTriggerEventRaffle(INPUT_BASE, ctx);
|
|
188
|
-
expect(result.raffleWinnerUserId).toBe("user-high");
|
|
189
|
-
});
|
|
190
|
-
});
|
|
191
|
-
describe("runTriggerEventRaffle — top_n_participants", () => {
|
|
192
|
-
it("pool limited to first N by createdAt ascending", async () => {
|
|
193
|
-
const t1 = new Date("2026-01-01");
|
|
194
|
-
const t2 = new Date("2026-01-02");
|
|
195
|
-
const t3 = new Date("2026-01-03");
|
|
196
|
-
const entries = [
|
|
197
|
-
makeEntry({ id: "e3", userId: "user-last", createdAt: t3 }),
|
|
198
|
-
makeEntry({ id: "e1", userId: "user-first", createdAt: t1 }),
|
|
199
|
-
makeEntry({ id: "e2", userId: "user-second", createdAt: t2 }),
|
|
200
|
-
];
|
|
201
|
-
const ctx = makeCtx({ entriesDocs: entries });
|
|
202
|
-
// topN=1 means only the earliest registrant wins
|
|
203
|
-
const result = await runTriggerEventRaffle({ ...INPUT_BASE, raffleType: "top_n_participants", topN: 1 }, ctx);
|
|
204
|
-
expect(result.raffleWinnerUserId).toBe("user-first");
|
|
205
|
-
});
|
|
206
|
-
it("handles Firestore Timestamp-like createdAt objects (via toDate)", async () => {
|
|
207
|
-
const entries = [
|
|
208
|
-
makeEntry({
|
|
209
|
-
id: "e1",
|
|
210
|
-
userId: "user-a",
|
|
211
|
-
createdAt: { toDate: () => new Date("2026-01-01") },
|
|
212
|
-
}),
|
|
213
|
-
makeEntry({
|
|
214
|
-
id: "e2",
|
|
215
|
-
userId: "user-b",
|
|
216
|
-
createdAt: { toDate: () => new Date("2026-01-02") },
|
|
217
|
-
}),
|
|
218
|
-
];
|
|
219
|
-
const ctx = makeCtx({ entriesDocs: entries });
|
|
220
|
-
const result = await runTriggerEventRaffle({ ...INPUT_BASE, raffleType: "top_n_participants", topN: 1 }, ctx);
|
|
221
|
-
expect(result.raffleWinnerUserId).toBe("user-a");
|
|
222
|
-
});
|
|
223
|
-
});
|
|
224
|
-
describe("runTriggerEventRaffle — input override precedence", () => {
|
|
225
|
-
it("input.raffleType overrides event.raffleType", async () => {
|
|
226
|
-
const entries = [
|
|
227
|
-
makeEntry({ id: "e1", userId: "user-low", points: 1 }),
|
|
228
|
-
makeEntry({ id: "e2", userId: "user-high", points: 999 }),
|
|
229
|
-
];
|
|
230
|
-
// Event says open_raffle, but input says top_n_scorers topN=1
|
|
231
|
-
const ctx = makeCtx({
|
|
232
|
-
eventData: { raffleType: "open_raffle" },
|
|
233
|
-
entriesDocs: entries,
|
|
234
|
-
});
|
|
235
|
-
const result = await runTriggerEventRaffle({ ...INPUT_BASE, raffleType: "top_n_scorers", topN: 1 }, ctx);
|
|
236
|
-
expect(result.raffleWinnerUserId).toBe("user-high");
|
|
237
|
-
});
|
|
238
|
-
it("input.topN overrides event.raffleTopN", async () => {
|
|
239
|
-
const entries = [
|
|
240
|
-
makeEntry({ id: "e1", userId: "user-low", points: 5 }),
|
|
241
|
-
makeEntry({ id: "e2", userId: "user-high", points: 100 }),
|
|
242
|
-
makeEntry({ id: "e3", userId: "user-mid", points: 50 }),
|
|
243
|
-
];
|
|
244
|
-
// Event says topN=3 (all), but input says topN=1 (only highest)
|
|
245
|
-
const ctx = makeCtx({
|
|
246
|
-
eventData: { raffleType: "top_n_scorers", raffleTopN: 3 },
|
|
247
|
-
entriesDocs: entries,
|
|
248
|
-
});
|
|
249
|
-
const result = await runTriggerEventRaffle({ ...INPUT_BASE, raffleType: "top_n_scorers", topN: 1 }, ctx);
|
|
250
|
-
expect(result.raffleWinnerUserId).toBe("user-high");
|
|
251
|
-
});
|
|
252
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
-
const { mockRecord, mockMapToHttpError } = vi.hoisted(() => ({
|
|
3
|
-
mockRecord: vi.fn().mockResolvedValue(undefined),
|
|
4
|
-
mockMapToHttpError: vi.fn().mockReturnValue({ code: 500, message: "Internal error" }),
|
|
5
|
-
}));
|
|
6
|
-
vi.mock("../../../../../features/server-errors/repository/server-errors.repository", () => ({
|
|
7
|
-
serverErrorsRepository: vi.fn(() => ({ record: mockRecord })),
|
|
8
|
-
}));
|
|
9
|
-
vi.mock("../../../../../errors/error-mapping", () => ({
|
|
10
|
-
mapToHttpError: mockMapToHttpError,
|
|
11
|
-
}));
|
|
12
|
-
import { wrapScheduleHandler, wrapTriggerHandler, wrapCallableHandler, wrapJobHandler, } from "../wrapJobHandler";
|
|
13
|
-
function makeCtx() {
|
|
14
|
-
return {
|
|
15
|
-
db: {},
|
|
16
|
-
now: new Date("2026-01-01"),
|
|
17
|
-
logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
beforeEach(() => {
|
|
21
|
-
vi.clearAllMocks();
|
|
22
|
-
mockRecord.mockResolvedValue(undefined);
|
|
23
|
-
mockMapToHttpError.mockReturnValue({ code: 500, message: "Internal error" });
|
|
24
|
-
});
|
|
25
|
-
// ── wrapScheduleHandler ──────────────────────────────────────────────────────
|
|
26
|
-
describe("wrapScheduleHandler", () => {
|
|
27
|
-
it("returns handler result when handler succeeds", async () => {
|
|
28
|
-
const handler = vi.fn().mockResolvedValue(undefined);
|
|
29
|
-
const wrapped = wrapScheduleHandler("my-job", handler);
|
|
30
|
-
await expect(wrapped(makeCtx())).resolves.toBeUndefined();
|
|
31
|
-
});
|
|
32
|
-
it("persists error to serverErrors when handler throws", async () => {
|
|
33
|
-
const handler = vi.fn().mockRejectedValue(new Error("job failed"));
|
|
34
|
-
const wrapped = wrapScheduleHandler("my-job", handler);
|
|
35
|
-
try {
|
|
36
|
-
await wrapped(makeCtx());
|
|
37
|
-
}
|
|
38
|
-
catch { /* expected */ }
|
|
39
|
-
expect(mockRecord).toHaveBeenCalledWith(expect.objectContaining({ source: "function", route: "my-job" }));
|
|
40
|
-
});
|
|
41
|
-
it("re-throws the original error after persisting", async () => {
|
|
42
|
-
const err = new Error("job failed");
|
|
43
|
-
const handler = vi.fn().mockRejectedValue(err);
|
|
44
|
-
const wrapped = wrapScheduleHandler("my-job", handler);
|
|
45
|
-
await expect(wrapped(makeCtx())).rejects.toThrow("job failed");
|
|
46
|
-
});
|
|
47
|
-
it("persist failure does NOT prevent re-throw", async () => {
|
|
48
|
-
const err = new Error("job failed");
|
|
49
|
-
mockRecord.mockRejectedValue(new Error("DB write failed"));
|
|
50
|
-
const handler = vi.fn().mockRejectedValue(err);
|
|
51
|
-
const wrapped = wrapScheduleHandler("my-job", handler);
|
|
52
|
-
await expect(wrapped(makeCtx())).rejects.toThrow("job failed");
|
|
53
|
-
});
|
|
54
|
-
it("calls mapToHttpError to normalise the error", async () => {
|
|
55
|
-
const err = new Error("Something broke");
|
|
56
|
-
const handler = vi.fn().mockRejectedValue(err);
|
|
57
|
-
const wrapped = wrapScheduleHandler("my-job", handler);
|
|
58
|
-
try {
|
|
59
|
-
await wrapped(makeCtx());
|
|
60
|
-
}
|
|
61
|
-
catch { /* expected */ }
|
|
62
|
-
expect(mockMapToHttpError).toHaveBeenCalledWith(err);
|
|
63
|
-
});
|
|
64
|
-
it("requestId includes handler name", async () => {
|
|
65
|
-
const handler = vi.fn().mockRejectedValue(new Error("oops"));
|
|
66
|
-
const wrapped = wrapScheduleHandler("audit-run", handler);
|
|
67
|
-
try {
|
|
68
|
-
await wrapped(makeCtx());
|
|
69
|
-
}
|
|
70
|
-
catch { /* expected */ }
|
|
71
|
-
const call = mockRecord.mock.calls[0][0];
|
|
72
|
-
expect(call.requestId).toMatch(/audit-run/);
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
// ── wrapTriggerHandler ───────────────────────────────────────────────────────
|
|
76
|
-
describe("wrapTriggerHandler", () => {
|
|
77
|
-
const mockEvent = { path: "test/doc1", params: {}, before: null, after: {} };
|
|
78
|
-
it("returns handler result when handler succeeds", async () => {
|
|
79
|
-
const handler = vi.fn().mockResolvedValue(undefined);
|
|
80
|
-
const wrapped = wrapTriggerHandler("trigger-fn", handler);
|
|
81
|
-
await expect(wrapped(mockEvent, makeCtx())).resolves.toBeUndefined();
|
|
82
|
-
});
|
|
83
|
-
it("persists error and re-throws when handler throws", async () => {
|
|
84
|
-
const err = new Error("trigger failed");
|
|
85
|
-
const handler = vi.fn().mockRejectedValue(err);
|
|
86
|
-
const wrapped = wrapTriggerHandler("trigger-fn", handler);
|
|
87
|
-
await expect(wrapped(mockEvent, makeCtx())).rejects.toThrow("trigger failed");
|
|
88
|
-
expect(mockRecord).toHaveBeenCalled();
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
// ── wrapCallableHandler ──────────────────────────────────────────────────────
|
|
92
|
-
describe("wrapCallableHandler", () => {
|
|
93
|
-
it("returns handler result when handler succeeds", async () => {
|
|
94
|
-
const handler = vi.fn().mockResolvedValue({ result: "ok" });
|
|
95
|
-
const wrapped = wrapCallableHandler("callable-fn", handler);
|
|
96
|
-
await expect(wrapped({}, makeCtx())).resolves.toEqual({ result: "ok" });
|
|
97
|
-
});
|
|
98
|
-
it("persists error and re-throws when handler throws", async () => {
|
|
99
|
-
const handler = vi.fn().mockRejectedValue(new Error("callable failed"));
|
|
100
|
-
const wrapped = wrapCallableHandler("callable-fn", handler);
|
|
101
|
-
await expect(wrapped({}, makeCtx())).rejects.toThrow("callable failed");
|
|
102
|
-
expect(mockRecord).toHaveBeenCalled();
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
// ── wrapJobHandler ───────────────────────────────────────────────────────────
|
|
106
|
-
describe("wrapJobHandler", () => {
|
|
107
|
-
it("returns handler result for a generic handler", async () => {
|
|
108
|
-
const handler = vi.fn().mockResolvedValue(42);
|
|
109
|
-
const wrapped = wrapJobHandler("generic-fn", handler);
|
|
110
|
-
await expect(wrapped()).resolves.toBe(42);
|
|
111
|
-
});
|
|
112
|
-
it("persists error with handler name and re-throws", async () => {
|
|
113
|
-
const handler = vi.fn().mockRejectedValue(new Error("generic failed"));
|
|
114
|
-
const wrapped = wrapJobHandler("generic-fn", handler);
|
|
115
|
-
await expect(wrapped()).rejects.toThrow("generic failed");
|
|
116
|
-
expect(mockRecord).toHaveBeenCalledWith(expect.objectContaining({ route: "generic-fn", source: "function" }));
|
|
117
|
-
});
|
|
118
|
-
it("extracts JobContext from last arg if it has .now", async () => {
|
|
119
|
-
const now = new Date("2026-06-15T12:00:00Z");
|
|
120
|
-
const handler = vi.fn().mockRejectedValue(new Error("err"));
|
|
121
|
-
const wrapped = wrapJobHandler("fn-with-ctx", handler);
|
|
122
|
-
try {
|
|
123
|
-
await wrapped({ now });
|
|
124
|
-
}
|
|
125
|
-
catch { /* expected */ }
|
|
126
|
-
const call = mockRecord.mock.calls[0][0];
|
|
127
|
-
expect(call.occurredAt).toBe(now.getTime());
|
|
128
|
-
});
|
|
129
|
-
});
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { JobContext } from "../runtime/types";
|
|
2
|
-
import type { CatalogueItemDocument } from "../../../../features/catalogue/schemas/firestore";
|
|
3
|
-
export interface CatalogueApprovalEvent {
|
|
4
|
-
itemId: string;
|
|
5
|
-
before: CatalogueItemDocument;
|
|
6
|
-
after: CatalogueItemDocument;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Fires when a catalogue item's `listingStatus` transitions to
|
|
10
|
-
* "pending_admin_approval" (a buyer's "Request to sell"). Notifies every
|
|
11
|
-
* admin so the approvals queue doesn't go unnoticed. Kept out of the
|
|
12
|
-
* synchronous submit action per Rule #6 — the buyer-facing request stays
|
|
13
|
-
* fast regardless of how many admins there are to fan out to.
|
|
14
|
-
*/
|
|
15
|
-
export declare function handleCatalogueSubmittedForApproval(event: CatalogueApprovalEvent, ctx: JobContext): Promise<void>;
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { userRepository } from "../../../../features/auth/repository/user.repository";
|
|
2
|
-
import { sendNotification } from "../../../../features/admin/actions/notification-actions";
|
|
3
|
-
import { normalizeError } from "../../../../errors/normalize";
|
|
4
|
-
/**
|
|
5
|
-
* Fires when a catalogue item's `listingStatus` transitions to
|
|
6
|
-
* "pending_admin_approval" (a buyer's "Request to sell"). Notifies every
|
|
7
|
-
* admin so the approvals queue doesn't go unnoticed. Kept out of the
|
|
8
|
-
* synchronous submit action per Rule #6 — the buyer-facing request stays
|
|
9
|
-
* fast regardless of how many admins there are to fan out to.
|
|
10
|
-
*/
|
|
11
|
-
export async function handleCatalogueSubmittedForApproval(event, ctx) {
|
|
12
|
-
const becamePending = event.before.listingStatus !== "pending_admin_approval" &&
|
|
13
|
-
event.after.listingStatus === "pending_admin_approval";
|
|
14
|
-
if (!becamePending)
|
|
15
|
-
return;
|
|
16
|
-
const admins = await userRepository.findByRole("admin");
|
|
17
|
-
for (const admin of admins) {
|
|
18
|
-
try {
|
|
19
|
-
await sendNotification({
|
|
20
|
-
userId: admin.uid,
|
|
21
|
-
type: "system",
|
|
22
|
-
priority: "normal",
|
|
23
|
-
title: "New catalogue listing request",
|
|
24
|
-
message: `"${event.after.title}" was submitted for approval to list under LetItRip Official.`,
|
|
25
|
-
actionUrl: "/admin/catalogue-approvals",
|
|
26
|
-
actionLabel: "Review request",
|
|
27
|
-
relatedId: event.itemId,
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
catch (err) {
|
|
31
|
-
void normalizeError(err);
|
|
32
|
-
ctx.logger.error("onCatalogueSubmittedForApproval: failed to notify admin", {
|
|
33
|
-
itemId: event.itemId,
|
|
34
|
-
adminUid: admin.uid,
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Public surface for the provider resolver + mocks.
|
|
3
|
-
*
|
|
4
|
-
* Real provider implementations remain in `appkit/src/providers/{payment-razorpay,payment-manual,shipping-manual}/`
|
|
5
|
-
* because they are independently consumable per-package. This barrel only
|
|
6
|
-
* exposes the resolver entry points and the in-process mock implementations
|
|
7
|
-
* Track H requires. Shipping has no mock — the manual shipping provider
|
|
8
|
-
* makes no external API calls, so there's nothing to mock.
|
|
9
|
-
*/
|
|
10
|
-
export { resolvePaymentProvider, type PaymentResolutionFactories, type ProviderResolutionContext, } from "./resolve";
|
|
11
|
-
export { MockRazorpayProvider, type MockWebhookEvent, type MockWebhookPayload, type WebhookSink, } from "./payment/razorpay-mock";
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Public surface for the provider resolver + mocks.
|
|
3
|
-
*
|
|
4
|
-
* Real provider implementations remain in `appkit/src/providers/{payment-razorpay,payment-manual,shipping-manual}/`
|
|
5
|
-
* because they are independently consumable per-package. This barrel only
|
|
6
|
-
* exposes the resolver entry points and the in-process mock implementations
|
|
7
|
-
* Track H requires. Shipping has no mock — the manual shipping provider
|
|
8
|
-
* makes no external API calls, so there's nothing to mock.
|
|
9
|
-
*/
|
|
10
|
-
export { resolvePaymentProvider, } from "./resolve";
|
|
11
|
-
export { MockRazorpayProvider, } from "./payment/razorpay-mock";
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `MockRazorpayProvider` — in-process mock implementing `IPaymentProvider`.
|
|
3
|
-
*
|
|
4
|
-
* Replaces the orphaned `/api/dev/mock-razorpay/**` HTTP routes (deleted in
|
|
5
|
-
* Track H). The mock behaviour is preserved bit-for-bit so checkout flows
|
|
6
|
-
* exercise identical wire shapes:
|
|
7
|
-
*
|
|
8
|
-
* - Order IDs prefix `order_mock_`, payment IDs `pay_mock_`, refund IDs
|
|
9
|
-
* `rfnd_mock_` — matches the previous route output exactly.
|
|
10
|
-
* - Webhook signatures use HMAC-SHA256 with the deterministic
|
|
11
|
-
* `MOCK_WEBHOOK_SECRET` so `verifyWebhook(raw, sig)` returns true for
|
|
12
|
-
* any signature the mock itself produced.
|
|
13
|
-
* - In-memory `Map<orderId, PaymentOrder>` survives per process. State is
|
|
14
|
-
* intentionally not persisted — tests reset between runs by recreating
|
|
15
|
-
* the provider instance.
|
|
16
|
-
*
|
|
17
|
-
* Mocks-only operations:
|
|
18
|
-
* - `emitWebhook(event)` synchronously fires a webhook payload through a
|
|
19
|
-
* consumer-supplied callback so end-to-end tests can drive a
|
|
20
|
-
* payment.captured / payment.failed / order.paid event without leaving
|
|
21
|
-
* the process. Registered via `setWebhookSink(fn)`.
|
|
22
|
-
*/
|
|
23
|
-
import { IPaymentProvider } from "../../../../contracts";
|
|
24
|
-
import type { PaymentCapture, PaymentOrder, Refund } from "../../../../contracts";
|
|
25
|
-
import type { JsonValue } from "../../../../schemas/types";
|
|
26
|
-
export type MockWebhookEvent = "payment.captured" | "payment.failed" | "order.paid";
|
|
27
|
-
export interface MockWebhookPayload {
|
|
28
|
-
readonly event: MockWebhookEvent;
|
|
29
|
-
readonly orderId: string;
|
|
30
|
-
readonly paymentId: string;
|
|
31
|
-
readonly amount: number;
|
|
32
|
-
readonly currency: string;
|
|
33
|
-
}
|
|
34
|
-
export type WebhookSink = (rawBody: string, signature: string, payload: MockWebhookPayload) => Promise<void> | void;
|
|
35
|
-
export declare class MockRazorpayProvider extends IPaymentProvider {
|
|
36
|
-
readonly name: "razorpay-mock";
|
|
37
|
-
private readonly orders;
|
|
38
|
-
private readonly captures;
|
|
39
|
-
private webhookSink;
|
|
40
|
-
setWebhookSink(sink: WebhookSink | null): void;
|
|
41
|
-
createOrder(amount: number, currency: string, metadata?: Record<string, JsonValue>): Promise<PaymentOrder>;
|
|
42
|
-
verifyWebhook(payload: string, signature: string): boolean;
|
|
43
|
-
capturePayment(orderId: string): Promise<PaymentCapture>;
|
|
44
|
-
refund(paymentId: string, amount?: number): Promise<Refund>;
|
|
45
|
-
getOrder(orderId: string): Promise<PaymentOrder>;
|
|
46
|
-
/**
|
|
47
|
-
* Mocks-only — fire a webhook event through the consumer-registered sink.
|
|
48
|
-
* Used by `/api/admin/dev/emit-payment-webhook` to drive end-to-end test
|
|
49
|
-
* flows. Throws if no sink is registered.
|
|
50
|
-
*/
|
|
51
|
-
emitWebhook(payload: MockWebhookPayload): Promise<void>;
|
|
52
|
-
}
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `MockRazorpayProvider` — in-process mock implementing `IPaymentProvider`.
|
|
3
|
-
*
|
|
4
|
-
* Replaces the orphaned `/api/dev/mock-razorpay/**` HTTP routes (deleted in
|
|
5
|
-
* Track H). The mock behaviour is preserved bit-for-bit so checkout flows
|
|
6
|
-
* exercise identical wire shapes:
|
|
7
|
-
*
|
|
8
|
-
* - Order IDs prefix `order_mock_`, payment IDs `pay_mock_`, refund IDs
|
|
9
|
-
* `rfnd_mock_` — matches the previous route output exactly.
|
|
10
|
-
* - Webhook signatures use HMAC-SHA256 with the deterministic
|
|
11
|
-
* `MOCK_WEBHOOK_SECRET` so `verifyWebhook(raw, sig)` returns true for
|
|
12
|
-
* any signature the mock itself produced.
|
|
13
|
-
* - In-memory `Map<orderId, PaymentOrder>` survives per process. State is
|
|
14
|
-
* intentionally not persisted — tests reset between runs by recreating
|
|
15
|
-
* the provider instance.
|
|
16
|
-
*
|
|
17
|
-
* Mocks-only operations:
|
|
18
|
-
* - `emitWebhook(event)` synchronously fires a webhook payload through a
|
|
19
|
-
* consumer-supplied callback so end-to-end tests can drive a
|
|
20
|
-
* payment.captured / payment.failed / order.paid event without leaving
|
|
21
|
-
* the process. Registered via `setWebhookSink(fn)`.
|
|
22
|
-
*/
|
|
23
|
-
import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
|
|
24
|
-
import { IPaymentProvider } from "../../../../contracts";
|
|
25
|
-
const MOCK_WEBHOOK_SECRET = "appkit-mock-razorpay-webhook-secret-v1";
|
|
26
|
-
export class MockRazorpayProvider extends IPaymentProvider {
|
|
27
|
-
constructor() {
|
|
28
|
-
super(...arguments);
|
|
29
|
-
this.name = "razorpay-mock";
|
|
30
|
-
this.orders = new Map();
|
|
31
|
-
this.captures = new Map();
|
|
32
|
-
this.webhookSink = null;
|
|
33
|
-
}
|
|
34
|
-
setWebhookSink(sink) {
|
|
35
|
-
this.webhookSink = sink;
|
|
36
|
-
}
|
|
37
|
-
async createOrder(amount, currency, metadata) {
|
|
38
|
-
const order = {
|
|
39
|
-
id: `order_mock_${randomBytes(8).toString("hex")}`,
|
|
40
|
-
amount,
|
|
41
|
-
currency,
|
|
42
|
-
status: "created",
|
|
43
|
-
receipt: `rcpt_mock_${Date.now()}`,
|
|
44
|
-
metadata,
|
|
45
|
-
createdAt: new Date().toISOString(),
|
|
46
|
-
};
|
|
47
|
-
this.orders.set(order.id, order);
|
|
48
|
-
return order;
|
|
49
|
-
}
|
|
50
|
-
verifyWebhook(payload, signature) {
|
|
51
|
-
if (signature.length !== 64)
|
|
52
|
-
return false;
|
|
53
|
-
const expected = createHmac("sha256", MOCK_WEBHOOK_SECRET)
|
|
54
|
-
.update(payload)
|
|
55
|
-
.digest("hex");
|
|
56
|
-
return timingSafeEqual(Buffer.from(expected, "hex"), Buffer.from(signature, "hex"));
|
|
57
|
-
}
|
|
58
|
-
async capturePayment(orderId) {
|
|
59
|
-
const order = this.orders.get(orderId);
|
|
60
|
-
if (!order) {
|
|
61
|
-
throw Object.assign(new Error(`Mock order not found: ${orderId}`), {
|
|
62
|
-
httpStatus: 404,
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
const capture = {
|
|
66
|
-
id: `pay_mock_${randomBytes(8).toString("hex")}`,
|
|
67
|
-
orderId,
|
|
68
|
-
amount: order.amount,
|
|
69
|
-
currency: order.currency,
|
|
70
|
-
status: "captured",
|
|
71
|
-
capturedAt: new Date().toISOString(),
|
|
72
|
-
};
|
|
73
|
-
this.captures.set(capture.id, capture);
|
|
74
|
-
this.orders.set(orderId, { ...order, status: "paid" });
|
|
75
|
-
return capture;
|
|
76
|
-
}
|
|
77
|
-
async refund(paymentId, amount) {
|
|
78
|
-
const capture = this.captures.get(paymentId);
|
|
79
|
-
const refund = {
|
|
80
|
-
id: `rfnd_mock_${randomBytes(8).toString("hex")}`,
|
|
81
|
-
paymentId,
|
|
82
|
-
amount: amount ?? capture?.amount ?? 0,
|
|
83
|
-
currency: capture?.currency ?? "INR",
|
|
84
|
-
status: "processed",
|
|
85
|
-
createdAt: new Date().toISOString(),
|
|
86
|
-
};
|
|
87
|
-
return refund;
|
|
88
|
-
}
|
|
89
|
-
async getOrder(orderId) {
|
|
90
|
-
const order = this.orders.get(orderId);
|
|
91
|
-
if (!order) {
|
|
92
|
-
throw Object.assign(new Error(`Mock order not found: ${orderId}`), {
|
|
93
|
-
httpStatus: 404,
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
return order;
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Mocks-only — fire a webhook event through the consumer-registered sink.
|
|
100
|
-
* Used by `/api/admin/dev/emit-payment-webhook` to drive end-to-end test
|
|
101
|
-
* flows. Throws if no sink is registered.
|
|
102
|
-
*/
|
|
103
|
-
async emitWebhook(payload) {
|
|
104
|
-
if (!this.webhookSink) {
|
|
105
|
-
throw new Error("MockRazorpayProvider.emitWebhook called with no webhook sink registered. " +
|
|
106
|
-
"Call provider.setWebhookSink(handler) at startup.");
|
|
107
|
-
}
|
|
108
|
-
const rawBody = JSON.stringify({
|
|
109
|
-
event: payload.event,
|
|
110
|
-
payload: {
|
|
111
|
-
order: { entity: { id: payload.orderId, amount: payload.amount, currency: payload.currency } },
|
|
112
|
-
payment: { entity: { id: payload.paymentId, amount: payload.amount, currency: payload.currency } },
|
|
113
|
-
},
|
|
114
|
-
});
|
|
115
|
-
const signature = createHmac("sha256", MOCK_WEBHOOK_SECRET).update(rawBody).digest("hex");
|
|
116
|
-
await this.webhookSink(rawBody, signature, payload);
|
|
117
|
-
}
|
|
118
|
-
}
|