@mohasinac/appkit 4.53.1 → 4.54.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/.build-stamp.json +3 -3
- package/dist/_internal/client/theme/ThemeProvider.js +15 -1
- package/dist/_internal/server/features/auth/capabilities.js +7 -5
- package/dist/_internal/server/features/categories/price-guidance-resolve.d.ts +66 -0
- package/dist/_internal/server/features/categories/price-guidance-resolve.js +138 -0
- package/dist/_internal/server/features/checkout/actions.d.ts +22 -6
- package/dist/_internal/server/features/checkout/actions.js +96 -51
- package/dist/_internal/server/features/checkout/index.d.ts +1 -1
- package/dist/_internal/server/features/checkout/index.js +1 -1
- package/dist/_internal/server/features/checkout/supplier-identity.js +28 -6
- package/dist/_internal/server/features/orders/adapters.js +1 -3
- package/dist/_internal/server/features/price-index/market.d.ts +57 -0
- package/dist/_internal/server/features/price-index/market.js +120 -0
- package/dist/_internal/server/features/products/list-public.d.ts +12 -0
- package/dist/_internal/server/features/products/list-public.js +10 -1
- package/dist/_internal/server/features/products/listing-tab-counts.d.ts +25 -1
- package/dist/_internal/server/features/products/listing-tab-counts.js +184 -10
- package/dist/_internal/server/features/search/index-build/sources.js +43 -2
- package/dist/_internal/server/features/site-settings/adapters.js +1 -1
- package/dist/_internal/server/features/stores/adapters.d.ts +1 -1
- package/dist/_internal/server/features/stores/adapters.js +0 -1
- package/dist/_internal/server/features/stores/tabs.d.ts +7 -2
- package/dist/_internal/server/features/stores/tabs.js +5 -3
- package/dist/_internal/server/jobs/core/analyticsAlertEvaluate.js +2 -5
- package/dist/_internal/server/jobs/core/jobRunners.js +0 -10
- package/dist/_internal/server/jobs/core/onOrderCreate.js +10 -104
- package/dist/_internal/server/jobs/core/onOrderStatusChange.d.ts +0 -2
- package/dist/_internal/server/jobs/core/onOrderStatusChange.js +0 -1
- package/dist/_internal/server/jobs/core/onScamReportCreate.js +0 -1
- package/dist/_internal/server/jobs/core/onScamReportRejected.js +0 -1
- package/dist/_internal/server/jobs/core/onScamReportVerified.js +0 -1
- package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +0 -1
- package/dist/_internal/server/jobs/core/pendingOrderTimeout.js +0 -1
- package/dist/_internal/server/notifications/channel-health.d.ts +7 -3
- package/dist/_internal/server/notifications/channel-health.js +2 -2
- package/dist/_internal/server/notifications/send-guard.d.ts +1 -1
- package/dist/_internal/server/notifications/send-guard.js +2 -4
- package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
- package/dist/_internal/shared/actions/action-registry.js +128 -28
- package/dist/_internal/shared/checkout/order-math.d.ts +1 -1
- package/dist/_internal/shared/checkout/order-math.js +1 -1
- package/dist/_internal/shared/features/categories/bundle-copy.d.ts +1 -1
- package/dist/_internal/shared/features/checkout/config.d.ts +0 -2
- package/dist/_internal/shared/features/checkout/config.js +0 -2
- package/dist/_internal/shared/features/messaging/config.d.ts +7 -5
- package/dist/_internal/shared/features/messaging/config.js +1 -4
- package/dist/_internal/shared/features/site-settings/fees.d.ts +0 -2
- package/dist/_internal/shared/features/site-settings/fees.js +0 -2
- package/dist/_internal/shared/features/site-settings/supplier-of-record.d.ts +56 -0
- package/dist/_internal/shared/features/site-settings/supplier-of-record.js +57 -0
- package/dist/_internal/shared/fees/calculator.d.ts +0 -8
- package/dist/_internal/shared/fees/calculator.js +0 -7
- package/dist/_internal/shared/listing-types/tiers.d.ts +94 -0
- package/dist/_internal/shared/listing-types/tiers.js +150 -0
- package/dist/_internal/shared/search/match.js +28 -2
- package/dist/cli/index.js +0 -2
- package/dist/client.d.ts +25 -4
- package/dist/client.js +36 -5
- package/dist/constants/api-endpoints.d.ts +28 -15
- package/dist/constants/api-endpoints.js +14 -8
- package/dist/constants/field-names.d.ts +1 -0
- package/dist/constants/field-names.js +1 -0
- package/dist/constants/notification-types.d.ts +1 -1
- package/dist/constants/notification-types.js +1 -1
- package/dist/core/integration-keys.d.ts +5 -5
- package/dist/core/integration-keys.js +21 -10
- package/dist/features/about/components/FeesView.js +0 -6
- package/dist/features/about/components/GuidesHubView.js +15 -2
- package/dist/features/account/components/NotificationPreferencesPanel.js +3 -4
- package/dist/features/account/components/UserOrdersView.js +26 -7
- package/dist/features/account/types/index.d.ts +0 -2
- package/dist/features/addresses/utils/postal-autofill.d.ts +39 -0
- package/dist/features/addresses/utils/postal-autofill.js +54 -0
- package/dist/features/admin/actions/notification-actions.d.ts +2 -8
- package/dist/features/admin/actions/notification-actions.js +9 -104
- package/dist/features/admin/components/AdminGuideHubView.js +1 -8
- package/dist/features/admin/components/AdminOrderEditorView.d.ts +1 -1
- package/dist/features/admin/components/AdminOrdersView.js +0 -2
- package/dist/features/admin/components/AdminSectionsView.js +3 -2
- package/dist/features/admin/components/AdminSiteSettingsView.js +22 -68
- package/dist/features/admin/components/AdminStoreEditorView.js +72 -34
- package/dist/features/admin/components/OwnerQuickActions.d.ts +29 -0
- package/dist/features/admin/components/OwnerQuickActions.js +142 -0
- package/dist/features/admin/components/sections/adminSectionsTypes.js +13 -4
- package/dist/features/admin/components/sections/icon-options.d.ts +21 -0
- package/dist/features/admin/components/sections/icon-options.js +23 -0
- package/dist/features/admin/components/sections/sectionTemplates.js +4 -1
- package/dist/features/admin/constants/site-settings-tabs.d.ts +7 -12
- package/dist/features/admin/constants/site-settings-tabs.js +6 -12
- package/dist/features/admin/repository/site-settings.repository.js +1 -1
- package/dist/features/admin/schemas/admin-editor-forms.d.ts +1 -1
- package/dist/features/admin/schemas/admin-editor-forms.js +4 -1
- package/dist/features/admin/schemas/admin-user-form.d.ts +0 -61
- package/dist/features/admin/schemas/admin-user-form.js +3 -44
- package/dist/features/admin/schemas/firestore.d.ts +28 -54
- package/dist/features/admin/schemas/firestore.js +40 -18
- package/dist/features/auctions/components/AuctionDetailPageView.js +12 -10
- package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +11 -1
- package/dist/features/auctions/components/MarketplaceAuctionCard.js +9 -2
- package/dist/features/auth/checkout-value-otp.d.ts +1 -1
- package/dist/features/auth/checkout-value-otp.js +1 -1
- package/dist/features/auth/permissions/constants.d.ts +29 -2
- package/dist/features/auth/permissions/constants.js +67 -1
- package/dist/features/blog/components/BlogFeaturedCard.d.ts +11 -1
- package/dist/features/blog/components/BlogFeaturedCard.js +9 -2
- package/dist/features/cart/components/CartDrawer.js +3 -2
- package/dist/features/cart/components/CartGroupLineRow.js +2 -1
- package/dist/features/cart/components/CartPriceBreakdown.d.ts +0 -2
- package/dist/features/cart/components/CartPriceBreakdown.js +1 -1
- package/dist/features/cart/components/StoreAddonsPicker.d.ts +2 -5
- package/dist/features/cart/components/StoreAddonsPicker.js +4 -5
- package/dist/features/cart/hooks/useAddToCart.js +10 -5
- package/dist/features/cart/repository/cart.repository.js +1 -2
- package/dist/features/cart/schemas/firestore.d.ts +1 -2
- package/dist/features/cart/utils/pending-ops.d.ts +11 -1
- package/dist/features/cart/utils/pending-ops.js +14 -2
- package/dist/features/categories/api/[id]/price-guidance/route.js +1 -24
- package/dist/features/categories/components/BrandDetailPageView.js +15 -6
- package/dist/features/categories/components/BrandDetailTabs.d.ts +7 -1
- package/dist/features/categories/components/BrandDetailTabs.js +18 -3
- package/dist/features/categories/components/BundleCollage.js +3 -2
- package/dist/features/categories/components/BundleDetailView.js +2 -1
- package/dist/features/categories/components/BundleItemsPicker.js +3 -4
- package/dist/features/categories/components/CategoryDetailPageView.js +19 -8
- package/dist/features/categories/components/CategoryDetailTabs.d.ts +7 -1
- package/dist/features/categories/components/CategoryDetailTabs.js +29 -7
- package/dist/features/categories/components/CategoryGrid.d.ts +11 -1
- package/dist/features/categories/components/CategoryGrid.js +9 -2
- package/dist/features/checkout/actions/checkout-value-otp-actions.d.ts +10 -5
- package/dist/features/checkout/actions/checkout-value-otp-actions.js +2 -88
- package/dist/features/classified/components/ClassifiedDetailPageView.js +12 -2
- package/dist/features/digital-codes/components/DigitalCodeDetailPageView.js +12 -2
- package/dist/features/events/components/EventCard.d.ts +11 -1
- package/dist/features/events/components/EventCard.js +9 -2
- package/dist/features/grouped/components/GroupedListingDetailView.js +3 -1
- package/dist/features/homepage/components/CTABannerSection.d.ts +3 -1
- package/dist/features/homepage/components/CTABannerSection.js +6 -3
- package/dist/features/homepage/components/HeroCarousel.js +8 -6
- package/dist/features/homepage/components/MarketplaceHomepageView.js +33 -7
- package/dist/features/homepage/components/SectionCarousel.js +13 -5
- package/dist/features/homepage/components/SecurityHighlightsSection.d.ts +8 -3
- package/dist/features/homepage/components/SecurityHighlightsSection.js +2 -2
- package/dist/features/homepage/components/StatsCounterSection.d.ts +9 -4
- package/dist/features/homepage/components/StatsCounterSection.js +2 -2
- package/dist/features/homepage/components/TestimonialsCarousel.js +1 -1
- package/dist/features/homepage/components/TrustFeaturesSection.d.ts +18 -4
- package/dist/features/homepage/components/TrustFeaturesSection.js +5 -5
- package/dist/features/homepage/components/WelcomeSection.d.ts +13 -2
- package/dist/features/homepage/components/WelcomeSection.js +3 -3
- package/dist/features/homepage/components/WhatsAppCommunitySection.d.ts +28 -0
- package/dist/features/homepage/components/WhatsAppCommunitySection.js +42 -6
- package/dist/features/homepage/components/WhatsAppGlyph.d.ts +20 -0
- package/dist/features/homepage/components/WhatsAppGlyph.js +20 -0
- package/dist/features/homepage/constants/hero-carousel-styles.d.ts +8 -6
- package/dist/features/homepage/constants/hero-carousel-styles.js +8 -6
- package/dist/features/homepage/constants/section-copy.d.ts +12 -10
- package/dist/features/homepage/constants/section-copy.js +28 -6
- package/dist/features/homepage/constants/stat-icons.d.ts +12 -0
- package/dist/features/homepage/constants/stat-icons.js +17 -0
- package/dist/features/homepage/constants/trust-icon-aliases.d.ts +8 -0
- package/dist/features/homepage/constants/trust-icon-aliases.js +75 -0
- package/dist/features/homepage/lib/section-defaults.d.ts +16 -1
- package/dist/features/homepage/lib/section-defaults.js +24 -4
- package/dist/features/homepage/lib/section-renderer.js +48 -8
- package/dist/features/homepage/schemas/firestore.d.ts +18 -1
- package/dist/features/layout/AppLayoutShell.js +2 -1
- package/dist/features/layout/BottomActions.d.ts +1 -0
- package/dist/features/layout/BottomActions.js +330 -0
- package/dist/features/layout/BottomChrome.d.ts +45 -0
- package/dist/features/layout/BottomChrome.js +5 -17
- package/dist/features/layout/SideActionDock.js +36 -13
- package/dist/features/layout/index.d.ts +2 -7
- package/dist/features/layout/index.js +7 -7
- package/dist/features/layout/useIsDesktop.d.ts +36 -0
- package/dist/features/layout/useIsDesktop.js +48 -0
- package/dist/features/live/components/LiveItemDetailPageView.js +12 -2
- package/dist/features/orders/actions/refund-actions.js +0 -1
- package/dist/features/orders/components/OrderAddonBadges.d.ts +1 -3
- package/dist/features/orders/components/OrderAddonBadges.js +3 -4
- package/dist/features/orders/components/OrderPaymentSummary.js +15 -2
- package/dist/features/orders/components/YourPurchaseStrip.d.ts +24 -0
- package/dist/features/orders/components/YourPurchaseStrip.js +77 -0
- package/dist/features/orders/components/index.d.ts +2 -1
- package/dist/features/orders/components/index.js +1 -1
- package/dist/features/orders/repository/orders.repository.d.ts +0 -8
- package/dist/features/orders/repository/orders.repository.js +0 -2
- package/dist/features/orders/schemas/firestore.d.ts +17 -9
- package/dist/features/orders/types/index.d.ts +2 -5
- package/dist/features/orders/utils/order-announcement-message.d.ts +18 -0
- package/dist/features/orders/utils/order-announcement-message.js +16 -0
- package/dist/features/orders/utils/payment-proof-message.d.ts +20 -0
- package/dist/features/orders/utils/payment-proof-message.js +17 -0
- package/dist/features/parts/components/PartDetailPageView.js +96 -1
- package/dist/features/parts/schemas/firestore.d.ts +247 -0
- package/dist/features/parts/schemas/firestore.js +6 -6
- package/dist/features/pre-orders/components/MarketplacePreorderCard.d.ts +11 -1
- package/dist/features/pre-orders/components/MarketplacePreorderCard.js +10 -3
- package/dist/features/pre-orders/components/PreOrderDetailPageView.js +12 -10
- package/dist/features/price-index/components/PriceIndexToolView.d.ts +21 -0
- package/dist/features/price-index/components/PriceIndexToolView.js +230 -27
- package/dist/features/price-index/lookup-target.d.ts +48 -0
- package/dist/features/price-index/lookup-target.js +107 -0
- package/dist/features/products/api/[id]/route.js +8 -1
- package/dist/features/products/api/route.js +16 -4
- package/dist/features/products/components/AvailabilityScopeHint.d.ts +22 -0
- package/dist/features/products/components/AvailabilityScopeHint.js +27 -0
- package/dist/features/products/components/CompareOverlay.d.ts +2 -1
- package/dist/features/products/components/CompareOverlay.js +2 -1
- package/dist/features/products/components/GroupSettingsPanel.js +2 -1
- package/dist/features/products/components/InteractiveProductCard.d.ts +7 -1
- package/dist/features/products/components/InteractiveProductCard.js +16 -4
- package/dist/features/products/components/MarketplaceBundleCard.d.ts +11 -1
- package/dist/features/products/components/MarketplaceBundleCard.js +9 -2
- package/dist/features/products/components/MarketplacePrizeDrawCard.d.ts +11 -1
- package/dist/features/products/components/MarketplacePrizeDrawCard.js +9 -2
- package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -1
- package/dist/features/products/components/ProductDetailPageView.js +34 -4
- package/dist/features/products/components/ProductGrid.d.ts +14 -1
- package/dist/features/products/components/ProductGrid.js +22 -5
- package/dist/features/products/components/ProductsIndexListing.js +2 -2
- package/dist/features/products/components/SublistingCarouselSection.js +2 -1
- package/dist/features/products/repository/products.repository.d.ts +1 -0
- package/dist/features/products/repository/products.repository.js +5 -1
- package/dist/features/products/utils/group-member-image.d.ts +9 -2
- package/dist/features/products/utils/group-member-image.js +2 -1
- package/dist/features/reviews/api/[id]/route.js +83 -23
- package/dist/features/reviews/components/PurchaseReviewAffordance.d.ts +6 -0
- package/dist/features/reviews/components/PurchaseReviewAffordance.js +42 -0
- package/dist/features/reviews/components/ReviewFormDrawer.d.ts +34 -0
- package/dist/features/reviews/components/ReviewFormDrawer.js +127 -0
- package/dist/features/reviews/components/index.d.ts +4 -0
- package/dist/features/reviews/components/index.js +2 -0
- package/dist/features/scams/schemas/index.d.ts +10 -10
- package/dist/features/search/action-index/settings-entries.js +0 -9
- package/dist/features/seller/actions/seller-actions.d.ts +1 -1
- package/dist/features/seller/actions/seller-actions.js +49 -3
- package/dist/features/seller/components/SellerPayoutSettingsView.js +30 -2
- package/dist/features/seller/components/SellerProductShell.d.ts +17 -1
- package/dist/features/seller/components/SellerProductsView.js +3 -2
- package/dist/features/seller/hooks/useStoreListingEntitlements.d.ts +8 -0
- package/dist/features/seller/hooks/useStoreListingEntitlements.js +70 -0
- package/dist/features/store-extensions/repository/store-extensions.repositories.d.ts +1 -6
- package/dist/features/store-extensions/repository/store-extensions.repositories.js +1 -10
- package/dist/features/store-extensions/schemas/firestore.d.ts +1 -17
- package/dist/features/store-extensions/schemas/firestore.js +0 -10
- package/dist/features/stores/components/InteractiveStoreCard.d.ts +11 -1
- package/dist/features/stores/components/InteractiveStoreCard.js +9 -2
- package/dist/features/stores/components/StoreAuctionsListing.js +2 -1
- package/dist/features/stores/components/StoreCapabilitiesGuideView.js +0 -1
- package/dist/features/stores/components/StoreGuideHubView.js +2 -8
- package/dist/features/stores/components/StoreSettingsGuideView.js +2 -6
- package/dist/features/stores/components/index.d.ts +0 -2
- package/dist/features/stores/components/index.js +0 -1
- package/dist/features/stores/repository/store.repository.d.ts +1 -26
- package/dist/features/stores/repository/store.repository.js +5 -60
- package/dist/features/stores/schemas/firestore.d.ts +6 -25
- package/dist/features/stores/schemas/firestore.js +6 -3
- package/dist/features/stores/schemas/index.d.ts +1 -87
- package/dist/features/stores/schemas/index.js +10 -15
- package/dist/features/tester/seed-data/authored/admin__site-system.js +0 -48
- package/dist/features/tester/seed-data/authored/buying__buying-checkout.js +0 -40
- package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.js +114 -2
- package/dist/features/tester/seed-data/authored/selling__quick-add-minimum-details.js +0 -16
- package/dist/features/tester/seed-data/authored/selling__seller-guide.js +1 -1
- package/dist/features/tester/seed-data/authored/selling__seller-marketing-extras.js +0 -79
- package/dist/features/tester/seed-data/authored/selling__seller-orders.js +1 -1
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +427 -69
- package/dist/index.d.ts +20 -32
- package/dist/index.js +34 -43
- package/dist/next/routing/route-map.d.ts +2 -8
- package/dist/next/routing/route-map.js +21 -4
- package/dist/providers/db-firebase/base.repository.d.ts +1 -1
- package/dist/providers/db-firebase/base.repository.js +1 -1
- package/dist/providers/payment-razorpay/index.d.ts +125 -0
- package/dist/providers/payment-razorpay/index.js +232 -0
- package/dist/providers/payment-razorpay/signature.d.ts +53 -0
- package/dist/providers/payment-razorpay/signature.js +71 -0
- package/dist/providers/shipping-shiprocket/index.d.ts +98 -0
- package/dist/providers/shipping-shiprocket/index.js +356 -0
- package/dist/providers.d.ts +3 -0
- package/dist/providers.js +3 -0
- package/dist/react/hooks/useCanSeePrices.d.ts +0 -27
- package/dist/react/hooks/useCanSeePrices.js +25 -0
- package/dist/repositories/index.d.ts +1 -1
- package/dist/repositories/index.js +1 -1
- package/dist/schemas/registry.d.ts +10 -115
- package/dist/schemas/registry.js +1 -2
- package/dist/security/pii-encrypt.js +1 -1
- package/dist/seed/_helpers/category-forest.js +27 -0
- package/dist/seed/_helpers/category-parts-glossary-map.js +1816 -86
- package/dist/seed/_helpers/category-parts.d.ts +1 -1
- package/dist/seed/_helpers/category-parts.js +13412 -3020
- package/dist/seed/carousel-slides-seed-data.js +47 -10
- package/dist/seed/categories-seed-data.js +48 -6
- package/dist/seed/faq-seed-data.js +2 -2
- package/dist/seed/homepage-sections-seed-data.js +286 -54
- package/dist/seed/index.d.ts +1 -1
- package/dist/seed/index.js +1 -1
- package/dist/seed/manifest.d.ts +1 -1
- package/dist/seed/manifest.js +1 -2
- package/dist/seed/model-composition-seed-data.js +6 -8
- package/dist/seed/part-glossary/chunk0.d.ts +9 -0
- package/dist/seed/part-glossary/chunk0.js +35448 -0
- package/dist/seed/part-glossary/chunk1.d.ts +9 -0
- package/dist/seed/part-glossary/chunk1.js +40494 -0
- package/dist/seed/part-glossary/chunk2.d.ts +9 -0
- package/dist/seed/part-glossary/chunk2.js +51242 -0
- package/dist/seed/part-glossary/chunk3.d.ts +9 -0
- package/dist/seed/part-glossary/chunk3.js +53337 -0
- package/dist/seed/part-glossary/chunk4.d.ts +9 -0
- package/dist/seed/part-glossary/chunk4.js +51454 -0
- package/dist/seed/part-glossary-seed-data.d.ts +1 -1
- package/dist/seed/part-glossary-seed-data.js +23 -47483
- package/dist/seed/products-beyblade-x-seed-data.js +36 -1
- package/dist/seed/site-settings-seed-data.js +34 -35
- package/dist/seed/store-extensions-seed-data.d.ts +1 -2
- package/dist/seed/store-extensions-seed-data.js +1 -23
- package/dist/seed/stores-seed-data.js +0 -1
- package/dist/server-entry.d.ts +1 -1
- package/dist/server-entry.js +1 -1
- package/dist/server.d.ts +10 -10
- package/dist/server.js +24 -22
- package/dist/styles.css +392 -43
- package/dist/tailwind-utilities.css +1 -1
- package/dist/tokens/themes/default-dark.js +1 -1
- package/dist/tokens/themes/default-light.js +2 -1
- package/dist/tokens/tokens.css +6 -2
- package/dist/ui/components/Button.d.ts +11 -0
- package/dist/ui/components/Button.js +11 -0
- package/dist/ui/components/Button.style.css +29 -0
- package/dist/ui/components/CarouselNav.d.ts +57 -0
- package/dist/ui/components/CarouselNav.js +25 -0
- package/dist/ui/components/CarouselNav.style.css +265 -0
- package/dist/ui/components/GatedPrice.js +30 -3
- package/dist/ui/components/GatedPrice.style.css +43 -40
- package/dist/ui/components/HorizontalScroller.d.ts +12 -1
- package/dist/ui/components/HorizontalScroller.js +43 -3
- package/dist/ui/components/ImageMosaic.d.ts +8 -1
- package/dist/ui/components/ImageMosaic.js +3 -2
- package/dist/ui/components/ImageMosaic.style.css +22 -0
- package/dist/ui/components/Layout.style.css +6 -0
- package/dist/ui/components/Semantic.d.ts +3 -2
- package/dist/ui/components/Semantic.js +1 -0
- package/dist/ui/components/Typography.d.ts +2 -0
- package/dist/ui/components/Typography.js +2 -0
- package/dist/ui/components/Typography.style.css +19 -0
- package/dist/ui/components/index.style.css +1 -0
- package/dist/ui/index.d.ts +3 -1
- package/dist/ui/index.js +4 -0
- package/package.json +3 -2
- package/scripts/seed-cli.mjs +133 -27
- package/dist/_internal/server/jobs/core/whatsappCatalogImport.d.ts +0 -27
- package/dist/_internal/server/jobs/core/whatsappCatalogImport.js +0 -172
- package/dist/_internal/server/jobs/core/whatsappNotify.d.ts +0 -35
- package/dist/_internal/server/jobs/core/whatsappNotify.js +0 -140
- package/dist/features/admin/components/AdminWhatsAppGuideView.d.ts +0 -2
- package/dist/features/admin/components/AdminWhatsAppGuideView.js +0 -35
- package/dist/features/orders/components/MarketplaceOrderCard.d.ts +0 -36
- package/dist/features/orders/components/MarketplaceOrderCard.js +0 -57
- package/dist/features/stores/components/StoreWhatsAppGuideView.d.ts +0 -3
- package/dist/features/stores/components/StoreWhatsAppGuideView.js +0 -12
- package/dist/features/whatsapp-bot/api/send-status/route.d.ts +0 -12
- package/dist/features/whatsapp-bot/api/send-status/route.js +0 -38
- package/dist/features/whatsapp-bot/api/webhook/route.d.ts +0 -12
- package/dist/features/whatsapp-bot/api/webhook/route.js +0 -43
- package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.d.ts +0 -6
- package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +0 -270
- package/dist/features/whatsapp-bot/components/WhatsAppChatButton.d.ts +0 -9
- package/dist/features/whatsapp-bot/components/WhatsAppChatButton.js +0 -7
- package/dist/features/whatsapp-bot/components/index.d.ts +0 -3
- package/dist/features/whatsapp-bot/components/index.js +0 -2
- package/dist/features/whatsapp-bot/helpers/payment-proof-message.d.ts +0 -14
- package/dist/features/whatsapp-bot/helpers/payment-proof-message.js +0 -17
- package/dist/features/whatsapp-bot/helpers/whatsapp.d.ts +0 -52
- package/dist/features/whatsapp-bot/helpers/whatsapp.js +0 -283
- package/dist/features/whatsapp-bot/index.d.ts +0 -3
- package/dist/features/whatsapp-bot/index.js +0 -3
- package/dist/features/whatsapp-bot/manifest.d.ts +0 -2
- package/dist/features/whatsapp-bot/manifest.js +0 -13
- package/dist/features/whatsapp-bot/messages/en.json +0 -7
- package/dist/features/whatsapp-bot/server.d.ts +0 -7
- package/dist/features/whatsapp-bot/server.js +0 -7
- package/dist/features/whatsapp-bot/types/index.d.ts +0 -126
- package/dist/features/whatsapp-bot/types/index.js +0 -1
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @mohasinac/payment-razorpay — Razorpay IPaymentProvider implementation
|
|
3
|
+
*
|
|
4
|
+
* Implements the `IPaymentProvider` contract using the official `razorpay`
|
|
5
|
+
* package. Accepts credentials via constructor — no Firestore or DB
|
|
6
|
+
* dependency (same shape as `payment-manual` and `payment-phonepe`).
|
|
7
|
+
*
|
|
8
|
+
* 🛑 This is a RESTORE, not the original file. The pre-2026-10 provider was
|
|
9
|
+
* deleted in "replace Razorpay with PhonePe Standard Checkout v2" and this
|
|
10
|
+
* one is deliberately NOT a revert of it. Three things changed, each because
|
|
11
|
+
* the old shape could not work against the current money path:
|
|
12
|
+
*
|
|
13
|
+
* 1. **`getOrder()` maps the real status.** The old implementation
|
|
14
|
+
* hardcoded `status: "created"` on every fetch. That was survivable
|
|
15
|
+
* when the Razorpay path verified a client-side signature and nothing
|
|
16
|
+
* else, but the current `verifyAndPlaceGatewayOrderAction` treats
|
|
17
|
+
* `getOrder().status === "paid"` as the authoritative proof of payment
|
|
18
|
+
* (PhonePe hands the browser nothing verifiable, so that is the only
|
|
19
|
+
* check it has). A provider that always answers "created" would make
|
|
20
|
+
* every Razorpay checkout fail verification after a successful charge —
|
|
21
|
+
* the buyer is debited and gets no order.
|
|
22
|
+
* 2. **`capturePayment()`/`refund()` are ORDER-keyed, tolerantly.** The
|
|
23
|
+
* rest of this codebase keys gateway lookups on one id — PhonePe's
|
|
24
|
+
* order-keyed `merchantOrderId` — and stores it as `order.paymentId`.
|
|
25
|
+
* Razorpay's refund API is payment-keyed (`pay_…`), so rather than
|
|
26
|
+
* forcing every caller to track a second id, both methods accept EITHER
|
|
27
|
+
* an `order_…` or a `pay_…` id and resolve the order's captured payment
|
|
28
|
+
* themselves. See `resolvePaymentId()`.
|
|
29
|
+
* 3. **The three `@deprecated` standalone helpers are gone.** The old file
|
|
30
|
+
* carried a second, credential-resolving API surface
|
|
31
|
+
* (`createRazorpayOrder`, `fetchRazorpayOrder`, `createRazorpayRefund`,
|
|
32
|
+
* …) that bypassed the provider registry entirely. Its own JSDoc said
|
|
33
|
+
* to use `getProviders().payment` instead, and every live caller now
|
|
34
|
+
* does. Restoring a bypass layer nothing needs would be reviving the
|
|
35
|
+
* exact duplication Root Cause #75 is about.
|
|
36
|
+
*
|
|
37
|
+
* Unlike PhonePe, Razorpay uses a client-side modal: `createOrder()` returns
|
|
38
|
+
* no `checkoutUrl`, and the browser opens Razorpay's `checkout.js` with the
|
|
39
|
+
* returned order id plus the PUBLISHABLE key id. The key id is handed to the
|
|
40
|
+
* client by `/api/payment/create-order`, never by this provider.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* registerProviders({
|
|
45
|
+
* payment: new RazorpayProvider({
|
|
46
|
+
* keyId: process.env.RAZORPAY_KEY_ID!,
|
|
47
|
+
* keySecret: process.env.RAZORPAY_KEY_SECRET!,
|
|
48
|
+
* webhookSecret: process.env.RAZORPAY_WEBHOOK_SECRET,
|
|
49
|
+
* }),
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
import type { JsonValue } from "@mohasinac/appkit";
|
|
54
|
+
import { IPaymentProvider } from "../../contracts";
|
|
55
|
+
import type { PaymentOrder, PaymentCapture, Refund } from "../../contracts";
|
|
56
|
+
export { verifyPaymentSignature, verifyWebhookSignature, type RazorpayPaymentResult, } from "./signature";
|
|
57
|
+
export interface RazorpayConfig {
|
|
58
|
+
/** Publishable key (`rzp_test_…` / `rzp_live_…`). Safe to expose to the browser. */
|
|
59
|
+
keyId: string;
|
|
60
|
+
/** Secret key. Server-only — never returned by any route. */
|
|
61
|
+
keySecret: string;
|
|
62
|
+
/** Webhook signing secret from the Razorpay dashboard's Webhooks tab. `verifyWebhook()` returns false without it. */
|
|
63
|
+
webhookSecret?: string;
|
|
64
|
+
}
|
|
65
|
+
export declare class RazorpayProvider extends IPaymentProvider {
|
|
66
|
+
readonly name = "razorpay";
|
|
67
|
+
private readonly razorpay;
|
|
68
|
+
private readonly webhookSecret?;
|
|
69
|
+
constructor(config: RazorpayConfig);
|
|
70
|
+
/**
|
|
71
|
+
* Creates a Razorpay order. `amount` is in PAISE — the smallest currency
|
|
72
|
+
* unit, which is what Razorpay's `amount` field means and what every
|
|
73
|
+
* caller in this codebase already passes (`rupeesToPaise(total)`).
|
|
74
|
+
*
|
|
75
|
+
* The returned `id` is Razorpay's own order id (`order_…`) and is the key
|
|
76
|
+
* every later lookup uses, so `gatewayOrderId` stays unset — the contract
|
|
77
|
+
* reserves that for gateways where the two ids differ. No `checkoutUrl`:
|
|
78
|
+
* Razorpay has no hosted page in this integration, the browser opens its
|
|
79
|
+
* modal instead.
|
|
80
|
+
*/
|
|
81
|
+
createOrder(amount: number, currency?: string, metadata?: Record<string, JsonValue>): Promise<PaymentOrder>;
|
|
82
|
+
/**
|
|
83
|
+
* Verifies a Razorpay webhook: HMAC-SHA256 hex over the RAW request body,
|
|
84
|
+
* compared against the `x-razorpay-signature` header.
|
|
85
|
+
*
|
|
86
|
+
* Fails closed when no webhook secret is configured — same shape as
|
|
87
|
+
* PhonePe's missing-credential behaviour. The caller must pass the raw
|
|
88
|
+
* body string, not a re-serialised object: `JSON.stringify(JSON.parse(b))`
|
|
89
|
+
* is not guaranteed to reproduce the bytes that were signed.
|
|
90
|
+
*/
|
|
91
|
+
verifyWebhook(payload: string, signature: string): boolean;
|
|
92
|
+
/**
|
|
93
|
+
* Resolves a `pay_…` id for either id shape.
|
|
94
|
+
*
|
|
95
|
+
* Given an `order_…` id, picks that order's captured payment (falling back
|
|
96
|
+
* to an authorized one, which is what a non-auto-capture flow leaves
|
|
97
|
+
* behind). Throws when the order has no such payment, because every caller
|
|
98
|
+
* — capture confirmation and refund alike — is meaningless without one.
|
|
99
|
+
*/
|
|
100
|
+
private resolvePaymentId;
|
|
101
|
+
/**
|
|
102
|
+
* Reports the state of the payment behind an order. Accepts our stored
|
|
103
|
+
* order id (`order_…`) or a payment id (`pay_…`) — see the class comment.
|
|
104
|
+
*
|
|
105
|
+
* Named `capturePayment` by the contract, but it does NOT capture: this
|
|
106
|
+
* integration creates orders with Razorpay's default auto-capture, so a
|
|
107
|
+
* successful payment is already captured by the time anything here runs.
|
|
108
|
+
* Issuing a second capture would be an error, not a no-op.
|
|
109
|
+
*/
|
|
110
|
+
capturePayment(orderId: string): Promise<PaymentCapture>;
|
|
111
|
+
/**
|
|
112
|
+
* Full or partial refund. `amount` is in paise; omit it to refund the whole
|
|
113
|
+
* payment. `paymentId` may be an `order_…` id — Razorpay refunds are
|
|
114
|
+
* payment-keyed but this codebase stores the order id, so it is resolved
|
|
115
|
+
* here rather than at ~6 call sites (see the class comment).
|
|
116
|
+
*/
|
|
117
|
+
refund(paymentId: string, amount?: number): Promise<Refund>;
|
|
118
|
+
/**
|
|
119
|
+
* Fetches an order and reports its REAL status. This is the authoritative
|
|
120
|
+
* "was this paid" check — `verifyAndPlaceGatewayOrderAction` gates order
|
|
121
|
+
* placement on `status === "paid"`, so the mapping here is load-bearing
|
|
122
|
+
* (see point 1 of the class comment).
|
|
123
|
+
*/
|
|
124
|
+
getOrder(orderId: string): Promise<PaymentOrder>;
|
|
125
|
+
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @mohasinac/payment-razorpay — Razorpay IPaymentProvider implementation
|
|
3
|
+
*
|
|
4
|
+
* Implements the `IPaymentProvider` contract using the official `razorpay`
|
|
5
|
+
* package. Accepts credentials via constructor — no Firestore or DB
|
|
6
|
+
* dependency (same shape as `payment-manual` and `payment-phonepe`).
|
|
7
|
+
*
|
|
8
|
+
* 🛑 This is a RESTORE, not the original file. The pre-2026-10 provider was
|
|
9
|
+
* deleted in "replace Razorpay with PhonePe Standard Checkout v2" and this
|
|
10
|
+
* one is deliberately NOT a revert of it. Three things changed, each because
|
|
11
|
+
* the old shape could not work against the current money path:
|
|
12
|
+
*
|
|
13
|
+
* 1. **`getOrder()` maps the real status.** The old implementation
|
|
14
|
+
* hardcoded `status: "created"` on every fetch. That was survivable
|
|
15
|
+
* when the Razorpay path verified a client-side signature and nothing
|
|
16
|
+
* else, but the current `verifyAndPlaceGatewayOrderAction` treats
|
|
17
|
+
* `getOrder().status === "paid"` as the authoritative proof of payment
|
|
18
|
+
* (PhonePe hands the browser nothing verifiable, so that is the only
|
|
19
|
+
* check it has). A provider that always answers "created" would make
|
|
20
|
+
* every Razorpay checkout fail verification after a successful charge —
|
|
21
|
+
* the buyer is debited and gets no order.
|
|
22
|
+
* 2. **`capturePayment()`/`refund()` are ORDER-keyed, tolerantly.** The
|
|
23
|
+
* rest of this codebase keys gateway lookups on one id — PhonePe's
|
|
24
|
+
* order-keyed `merchantOrderId` — and stores it as `order.paymentId`.
|
|
25
|
+
* Razorpay's refund API is payment-keyed (`pay_…`), so rather than
|
|
26
|
+
* forcing every caller to track a second id, both methods accept EITHER
|
|
27
|
+
* an `order_…` or a `pay_…` id and resolve the order's captured payment
|
|
28
|
+
* themselves. See `resolvePaymentId()`.
|
|
29
|
+
* 3. **The three `@deprecated` standalone helpers are gone.** The old file
|
|
30
|
+
* carried a second, credential-resolving API surface
|
|
31
|
+
* (`createRazorpayOrder`, `fetchRazorpayOrder`, `createRazorpayRefund`,
|
|
32
|
+
* …) that bypassed the provider registry entirely. Its own JSDoc said
|
|
33
|
+
* to use `getProviders().payment` instead, and every live caller now
|
|
34
|
+
* does. Restoring a bypass layer nothing needs would be reviving the
|
|
35
|
+
* exact duplication Root Cause #75 is about.
|
|
36
|
+
*
|
|
37
|
+
* Unlike PhonePe, Razorpay uses a client-side modal: `createOrder()` returns
|
|
38
|
+
* no `checkoutUrl`, and the browser opens Razorpay's `checkout.js` with the
|
|
39
|
+
* returned order id plus the PUBLISHABLE key id. The key id is handed to the
|
|
40
|
+
* client by `/api/payment/create-order`, never by this provider.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* registerProviders({
|
|
45
|
+
* payment: new RazorpayProvider({
|
|
46
|
+
* keyId: process.env.RAZORPAY_KEY_ID!,
|
|
47
|
+
* keySecret: process.env.RAZORPAY_KEY_SECRET!,
|
|
48
|
+
* webhookSecret: process.env.RAZORPAY_WEBHOOK_SECRET,
|
|
49
|
+
* }),
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
import Razorpay from "razorpay";
|
|
54
|
+
import { IPaymentProvider } from "../../contracts/index.js";
|
|
55
|
+
import { getDefaultCurrency } from "../../core/baseline-resolver.js";
|
|
56
|
+
import { verifyWebhookSignature } from "./signature.js";
|
|
57
|
+
export { verifyPaymentSignature, verifyWebhookSignature, } from "./signature.js";
|
|
58
|
+
/** Razorpay's own order status vocabulary → the contract's. */
|
|
59
|
+
function mapOrderStatus(status) {
|
|
60
|
+
switch (status) {
|
|
61
|
+
case "paid":
|
|
62
|
+
return "paid";
|
|
63
|
+
case "attempted":
|
|
64
|
+
return "attempted";
|
|
65
|
+
default:
|
|
66
|
+
return "created";
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Razorpay `notes` is a flat string map (≤15 keys, 256 chars per value), but
|
|
71
|
+
* `createOrder`'s `metadata` is `Record<string, JsonValue>` and the shared
|
|
72
|
+
* create-order route passes PhonePe-shaped keys (`uid`, `redirectUrl`) through
|
|
73
|
+
* it. Flatten what survives and drop what does not, rather than letting a
|
|
74
|
+
* nested object reach the API and 400 the whole checkout.
|
|
75
|
+
*/
|
|
76
|
+
function toNotes(metadata) {
|
|
77
|
+
if (!metadata)
|
|
78
|
+
return undefined;
|
|
79
|
+
const notes = {};
|
|
80
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
81
|
+
if (value === null || value === undefined)
|
|
82
|
+
continue;
|
|
83
|
+
if (typeof value === "object")
|
|
84
|
+
continue; // arrays/objects have no representation in notes
|
|
85
|
+
if (Object.keys(notes).length >= 15)
|
|
86
|
+
break;
|
|
87
|
+
notes[key] = String(value).slice(0, 256);
|
|
88
|
+
}
|
|
89
|
+
return Object.keys(notes).length > 0 ? notes : undefined;
|
|
90
|
+
}
|
|
91
|
+
// --- IPaymentProvider implementation ------------------------------------------
|
|
92
|
+
export class RazorpayProvider extends IPaymentProvider {
|
|
93
|
+
constructor(config) {
|
|
94
|
+
super();
|
|
95
|
+
this.name = "razorpay";
|
|
96
|
+
if (!config.keyId || !config.keySecret) {
|
|
97
|
+
throw new Error("RazorpayProvider requires keyId and keySecret. Configure them in Admin › Site Settings › Credentials, or set RAZORPAY_KEY_ID / RAZORPAY_KEY_SECRET.");
|
|
98
|
+
}
|
|
99
|
+
this.razorpay = new Razorpay({ key_id: config.keyId, key_secret: config.keySecret });
|
|
100
|
+
this.webhookSecret = config.webhookSecret;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Creates a Razorpay order. `amount` is in PAISE — the smallest currency
|
|
104
|
+
* unit, which is what Razorpay's `amount` field means and what every
|
|
105
|
+
* caller in this codebase already passes (`rupeesToPaise(total)`).
|
|
106
|
+
*
|
|
107
|
+
* The returned `id` is Razorpay's own order id (`order_…`) and is the key
|
|
108
|
+
* every later lookup uses, so `gatewayOrderId` stays unset — the contract
|
|
109
|
+
* reserves that for gateways where the two ids differ. No `checkoutUrl`:
|
|
110
|
+
* Razorpay has no hosted page in this integration, the browser opens its
|
|
111
|
+
* modal instead.
|
|
112
|
+
*/
|
|
113
|
+
async createOrder(amount, currency, metadata) {
|
|
114
|
+
const resolvedCurrency = currency ?? getDefaultCurrency();
|
|
115
|
+
const receipt = typeof metadata?.receipt === "string" ? metadata.receipt : undefined;
|
|
116
|
+
const order = await this.razorpay.orders.create({
|
|
117
|
+
amount,
|
|
118
|
+
currency: resolvedCurrency,
|
|
119
|
+
receipt,
|
|
120
|
+
notes: toNotes(metadata),
|
|
121
|
+
});
|
|
122
|
+
return {
|
|
123
|
+
id: String(order.id),
|
|
124
|
+
amount: Number(order.amount),
|
|
125
|
+
currency: String(order.currency),
|
|
126
|
+
status: mapOrderStatus(String(order.status)),
|
|
127
|
+
receipt: order.receipt ?? undefined,
|
|
128
|
+
metadata,
|
|
129
|
+
createdAt: new Date(Number(order.created_at) * 1000).toISOString(),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Verifies a Razorpay webhook: HMAC-SHA256 hex over the RAW request body,
|
|
134
|
+
* compared against the `x-razorpay-signature` header.
|
|
135
|
+
*
|
|
136
|
+
* Fails closed when no webhook secret is configured — same shape as
|
|
137
|
+
* PhonePe's missing-credential behaviour. The caller must pass the raw
|
|
138
|
+
* body string, not a re-serialised object: `JSON.stringify(JSON.parse(b))`
|
|
139
|
+
* is not guaranteed to reproduce the bytes that were signed.
|
|
140
|
+
*/
|
|
141
|
+
verifyWebhook(payload, signature) {
|
|
142
|
+
if (!this.webhookSecret)
|
|
143
|
+
return false;
|
|
144
|
+
return verifyWebhookSignature(payload, signature, this.webhookSecret);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Resolves a `pay_…` id for either id shape.
|
|
148
|
+
*
|
|
149
|
+
* Given an `order_…` id, picks that order's captured payment (falling back
|
|
150
|
+
* to an authorized one, which is what a non-auto-capture flow leaves
|
|
151
|
+
* behind). Throws when the order has no such payment, because every caller
|
|
152
|
+
* — capture confirmation and refund alike — is meaningless without one.
|
|
153
|
+
*/
|
|
154
|
+
async resolvePaymentId(id) {
|
|
155
|
+
if (!id.startsWith("order_"))
|
|
156
|
+
return id;
|
|
157
|
+
const { items } = await this.razorpay.orders.fetchPayments(id);
|
|
158
|
+
const payment = items.find((p) => p.status === "captured") ?? items.find((p) => p.status === "authorized");
|
|
159
|
+
if (!payment) {
|
|
160
|
+
throw new Error(`Razorpay order ${id} has no captured or authorized payment`);
|
|
161
|
+
}
|
|
162
|
+
return String(payment.id);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Reports the state of the payment behind an order. Accepts our stored
|
|
166
|
+
* order id (`order_…`) or a payment id (`pay_…`) — see the class comment.
|
|
167
|
+
*
|
|
168
|
+
* Named `capturePayment` by the contract, but it does NOT capture: this
|
|
169
|
+
* integration creates orders with Razorpay's default auto-capture, so a
|
|
170
|
+
* successful payment is already captured by the time anything here runs.
|
|
171
|
+
* Issuing a second capture would be an error, not a no-op.
|
|
172
|
+
*/
|
|
173
|
+
async capturePayment(orderId) {
|
|
174
|
+
const paymentId = await this.resolvePaymentId(orderId);
|
|
175
|
+
const payment = await this.razorpay.payments.fetch(paymentId);
|
|
176
|
+
return {
|
|
177
|
+
id: String(payment.id),
|
|
178
|
+
orderId: String(payment.order_id ?? orderId),
|
|
179
|
+
amount: Number(payment.amount),
|
|
180
|
+
currency: String(payment.currency),
|
|
181
|
+
status: payment.status === "captured" ? "captured" : "failed",
|
|
182
|
+
capturedAt: new Date().toISOString(),
|
|
183
|
+
transactionId: String(payment.id),
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Full or partial refund. `amount` is in paise; omit it to refund the whole
|
|
188
|
+
* payment. `paymentId` may be an `order_…` id — Razorpay refunds are
|
|
189
|
+
* payment-keyed but this codebase stores the order id, so it is resolved
|
|
190
|
+
* here rather than at ~6 call sites (see the class comment).
|
|
191
|
+
*/
|
|
192
|
+
async refund(paymentId, amount) {
|
|
193
|
+
const resolvedPaymentId = await this.resolvePaymentId(paymentId);
|
|
194
|
+
const result = await this.razorpay.payments.refund(resolvedPaymentId, amount === undefined ? {} : { amount });
|
|
195
|
+
return {
|
|
196
|
+
id: String(result.id),
|
|
197
|
+
paymentId: resolvedPaymentId,
|
|
198
|
+
amount: Number(result.amount),
|
|
199
|
+
currency: String(result.currency),
|
|
200
|
+
status: result.status === "processed"
|
|
201
|
+
? "processed"
|
|
202
|
+
: result.status === "failed"
|
|
203
|
+
? "failed"
|
|
204
|
+
: "pending",
|
|
205
|
+
createdAt: new Date(Number(result.created_at) * 1000).toISOString(),
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Fetches an order and reports its REAL status. This is the authoritative
|
|
210
|
+
* "was this paid" check — `verifyAndPlaceGatewayOrderAction` gates order
|
|
211
|
+
* placement on `status === "paid"`, so the mapping here is load-bearing
|
|
212
|
+
* (see point 1 of the class comment).
|
|
213
|
+
*/
|
|
214
|
+
async getOrder(orderId) {
|
|
215
|
+
const order = await this.razorpay.orders.fetch(orderId);
|
|
216
|
+
return {
|
|
217
|
+
id: String(order.id),
|
|
218
|
+
amount: Number(order.amount),
|
|
219
|
+
currency: String(order.currency),
|
|
220
|
+
status: mapOrderStatus(String(order.status)),
|
|
221
|
+
receipt: order.receipt ?? undefined,
|
|
222
|
+
createdAt: new Date(Number(order.created_at) * 1000).toISOString(),
|
|
223
|
+
/*
|
|
224
|
+
* `notes` round-trips whatever `createOrder` put there, which is how the
|
|
225
|
+
* WEBHOOK path (no buyer session) recovers the checkout intent — the
|
|
226
|
+
* same job PhonePe's `metaInfo` does. Without this the webhook could
|
|
227
|
+
* confirm a payment and then have no uid to place the order for.
|
|
228
|
+
*/
|
|
229
|
+
metadata: order.notes,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Razorpay signature verification — pure `node:crypto`, NO SDK import.
|
|
3
|
+
*
|
|
4
|
+
* 🛑 This is a separate module from `./index.ts` on purpose, and the split is
|
|
5
|
+
* load-bearing rather than tidiness. `_internal/server/features/checkout/
|
|
6
|
+
* actions.ts` needs `verifyPaymentSignature` on the buyer-present verify path,
|
|
7
|
+
* and importing it from the provider's `index.ts` would pull a static
|
|
8
|
+
* `import Razorpay from "razorpay"` into the checkout action's import graph —
|
|
9
|
+
* the whole SDK, its transitive deps and its own `node:` requires — for one
|
|
10
|
+
* HMAC comparison. Root Cause #24 is the same shape one layer down: a static
|
|
11
|
+
* top-level import is resolved before anything is tree-shaken, so "the symbol
|
|
12
|
+
* I use is cheap" does not make the module it lives in cheap.
|
|
13
|
+
*
|
|
14
|
+
* Keep this file free of SDK imports. `./index.ts` re-exports from here so
|
|
15
|
+
* the provider still has one public surface.
|
|
16
|
+
*/
|
|
17
|
+
/** The three fields Razorpay's `checkout.js` hands back on a successful payment. */
|
|
18
|
+
export interface RazorpayPaymentResult {
|
|
19
|
+
razorpay_order_id: string;
|
|
20
|
+
razorpay_payment_id: string;
|
|
21
|
+
razorpay_signature: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Compares two hex digests without leaking position through an early exit.
|
|
25
|
+
*
|
|
26
|
+
* `timingSafeEqual` throws on unequal buffer lengths, and a non-hex input
|
|
27
|
+
* silently produces a short buffer — both are "not equal", so both are
|
|
28
|
+
* caught rather than propagated. Returning false on malformed input is the
|
|
29
|
+
* fail-closed direction.
|
|
30
|
+
*/
|
|
31
|
+
export declare function hexEqual(expected: string, received: string): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Verifies the signature Razorpay's modal returns to the browser:
|
|
34
|
+
* HMAC-SHA256 over `{order_id}|{payment_id}`, keyed with the SECRET.
|
|
35
|
+
*
|
|
36
|
+
* 🛑 This proves the browser's callback was not forged or tampered with. It is
|
|
37
|
+
* NOT on its own proof that money moved — the digest is computable the moment
|
|
38
|
+
* an order id and a payment id exist, and both are visible to the client.
|
|
39
|
+
* `verifyAndPlaceGatewayOrderAction` therefore checks this AND re-fetches the
|
|
40
|
+
* order from Razorpay; this is the cheap guard, the fetch is the authority.
|
|
41
|
+
* Each alone has a failure mode: signature-only trusts a client-reported
|
|
42
|
+
* outcome, fetch-only accepts a replayed order id from another session.
|
|
43
|
+
*/
|
|
44
|
+
export declare function verifyPaymentSignature(params: RazorpayPaymentResult, keySecret: string): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Verifies a Razorpay webhook: HMAC-SHA256 hex over the RAW request body,
|
|
47
|
+
* compared against the `x-razorpay-signature` header.
|
|
48
|
+
*
|
|
49
|
+
* 🛑 The caller must pass the raw body STRING, not a re-serialised object.
|
|
50
|
+
* `JSON.stringify(JSON.parse(body))` is not guaranteed to reproduce the bytes
|
|
51
|
+
* that were signed — key order and whitespace both survive into the digest.
|
|
52
|
+
*/
|
|
53
|
+
export declare function verifyWebhookSignature(rawBody: string, signature: string, webhookSecret: string): boolean;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Razorpay signature verification — pure `node:crypto`, NO SDK import.
|
|
3
|
+
*
|
|
4
|
+
* 🛑 This is a separate module from `./index.ts` on purpose, and the split is
|
|
5
|
+
* load-bearing rather than tidiness. `_internal/server/features/checkout/
|
|
6
|
+
* actions.ts` needs `verifyPaymentSignature` on the buyer-present verify path,
|
|
7
|
+
* and importing it from the provider's `index.ts` would pull a static
|
|
8
|
+
* `import Razorpay from "razorpay"` into the checkout action's import graph —
|
|
9
|
+
* the whole SDK, its transitive deps and its own `node:` requires — for one
|
|
10
|
+
* HMAC comparison. Root Cause #24 is the same shape one layer down: a static
|
|
11
|
+
* top-level import is resolved before anything is tree-shaken, so "the symbol
|
|
12
|
+
* I use is cheap" does not make the module it lives in cheap.
|
|
13
|
+
*
|
|
14
|
+
* Keep this file free of SDK imports. `./index.ts` re-exports from here so
|
|
15
|
+
* the provider still has one public surface.
|
|
16
|
+
*/
|
|
17
|
+
import { createHmac, timingSafeEqual } from "crypto";
|
|
18
|
+
import { normalizeError } from "../../errors/normalize.js";
|
|
19
|
+
/**
|
|
20
|
+
* Compares two hex digests without leaking position through an early exit.
|
|
21
|
+
*
|
|
22
|
+
* `timingSafeEqual` throws on unequal buffer lengths, and a non-hex input
|
|
23
|
+
* silently produces a short buffer — both are "not equal", so both are
|
|
24
|
+
* caught rather than propagated. Returning false on malformed input is the
|
|
25
|
+
* fail-closed direction.
|
|
26
|
+
*/
|
|
27
|
+
export function hexEqual(expected, received) {
|
|
28
|
+
if (expected.length !== received.length)
|
|
29
|
+
return false;
|
|
30
|
+
try {
|
|
31
|
+
return timingSafeEqual(Buffer.from(expected, "hex"), Buffer.from(received, "hex"));
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
void normalizeError(err);
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Verifies the signature Razorpay's modal returns to the browser:
|
|
40
|
+
* HMAC-SHA256 over `{order_id}|{payment_id}`, keyed with the SECRET.
|
|
41
|
+
*
|
|
42
|
+
* 🛑 This proves the browser's callback was not forged or tampered with. It is
|
|
43
|
+
* NOT on its own proof that money moved — the digest is computable the moment
|
|
44
|
+
* an order id and a payment id exist, and both are visible to the client.
|
|
45
|
+
* `verifyAndPlaceGatewayOrderAction` therefore checks this AND re-fetches the
|
|
46
|
+
* order from Razorpay; this is the cheap guard, the fetch is the authority.
|
|
47
|
+
* Each alone has a failure mode: signature-only trusts a client-reported
|
|
48
|
+
* outcome, fetch-only accepts a replayed order id from another session.
|
|
49
|
+
*/
|
|
50
|
+
export function verifyPaymentSignature(params, keySecret) {
|
|
51
|
+
if (!keySecret)
|
|
52
|
+
return false;
|
|
53
|
+
const expected = createHmac("sha256", keySecret)
|
|
54
|
+
.update(`${params.razorpay_order_id}|${params.razorpay_payment_id}`)
|
|
55
|
+
.digest("hex");
|
|
56
|
+
return hexEqual(expected, params.razorpay_signature);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Verifies a Razorpay webhook: HMAC-SHA256 hex over the RAW request body,
|
|
60
|
+
* compared against the `x-razorpay-signature` header.
|
|
61
|
+
*
|
|
62
|
+
* 🛑 The caller must pass the raw body STRING, not a re-serialised object.
|
|
63
|
+
* `JSON.stringify(JSON.parse(body))` is not guaranteed to reproduce the bytes
|
|
64
|
+
* that were signed — key order and whitespace both survive into the digest.
|
|
65
|
+
*/
|
|
66
|
+
export function verifyWebhookSignature(rawBody, signature, webhookSecret) {
|
|
67
|
+
if (!webhookSecret)
|
|
68
|
+
return false;
|
|
69
|
+
const expected = createHmac("sha256", webhookSecret).update(rawBody).digest("hex");
|
|
70
|
+
return hexEqual(expected, signature);
|
|
71
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @mohasinac/shipping-shiprocket — IShippingProvider over Shiprocket's v1 API.
|
|
3
|
+
*
|
|
4
|
+
* ── Read this before trusting it ──────────────────────────────────────────
|
|
5
|
+
*
|
|
6
|
+
* ── What is verified, and what is not ────────────────────────────────────
|
|
7
|
+
*
|
|
8
|
+
* ✅ VERIFIED against the live API (2026-10-20, real API-user credentials):
|
|
9
|
+
* `POST /v1/external/auth/login` returns HTTP 200 with
|
|
10
|
+
* `{ company_id, created_at, email, first_name, id, last_name, token }`.
|
|
11
|
+
* The `token` field is present and non-empty, which is the only field
|
|
12
|
+
* `loginResponse` requires — the rest are ignored, as Zod ignores unknown
|
|
13
|
+
* keys by default.
|
|
14
|
+
*
|
|
15
|
+
* 🛑 NOT VERIFIED: every other endpoint. Order creation, AWB assignment,
|
|
16
|
+
* tracking, serviceability and label generation all MUTATE or bill against
|
|
17
|
+
* a real carrier account, so none was called. Their field names below are
|
|
18
|
+
* claims taken from the published docs, not facts read off a payload.
|
|
19
|
+
*
|
|
20
|
+
* That asymmetry is the reason every response is parsed through Zod rather
|
|
21
|
+
* than cast: an unverified contract that is wrong surfaces as a named error at
|
|
22
|
+
* the boundary, instead of as an `undefined` AWB written to an order and shown
|
|
23
|
+
* to a buyer as a tracking number that tracks nothing.
|
|
24
|
+
*
|
|
25
|
+
* ── Auth: why a dedicated API user, and why the token is cached ───────────
|
|
26
|
+
*
|
|
27
|
+
* Shiprocket's core v1 API has no long-lived key/secret. You POST credentials
|
|
28
|
+
* to `/v1/external/auth/login` and receive a bearer token valid for roughly
|
|
29
|
+
* ten days, then log in again.
|
|
30
|
+
*
|
|
31
|
+
* 🛑 Those credentials should be a DEDICATED API USER (Shiprocket dashboard →
|
|
32
|
+
* Settings → API → Configure), not the dashboard login. Using the dashboard
|
|
33
|
+
* account means the token dies whenever someone changes that password — a
|
|
34
|
+
* shipping integration that breaks on an unrelated admin action — and it hands
|
|
35
|
+
* full account scope to this process. The env var is named
|
|
36
|
+
* `SHIPROCKET_LOGIN_USER_EMAIL` rather than `LOGIN_ID` because the login payload
|
|
37
|
+
* field is `email`; a var called "login id" invites someone to put a username
|
|
38
|
+
* in it and get a 400 they cannot explain.
|
|
39
|
+
*
|
|
40
|
+
* 🛑 The token is cached in module state with its expiry. Logging in per
|
|
41
|
+
* request would mean two round trips for every shipment and would hit
|
|
42
|
+
* Shiprocket's auth rate limit under any real volume. A 401 mid-flight clears
|
|
43
|
+
* the cache and retries ONCE — exactly once, because a credential that is
|
|
44
|
+
* genuinely wrong must fail fast rather than loop.
|
|
45
|
+
*
|
|
46
|
+
* ── What is deliberately NOT here ────────────────────────────────────────
|
|
47
|
+
*
|
|
48
|
+
* Inbound webhooks. Shiprocket pushes status updates to a URL configured in
|
|
49
|
+
* its dashboard and authenticates them with an `x-api-key` header whose value
|
|
50
|
+
* you set there — a THIRD secret, and an inbound route rather than a provider
|
|
51
|
+
* method. `trackShipment` below polls instead, which is correct for a provider
|
|
52
|
+
* contract and wasteful as a status mechanism; the webhook is the better
|
|
53
|
+
* answer and belongs in its own route with its own verification.
|
|
54
|
+
*
|
|
55
|
+
* @tag domain:shipping
|
|
56
|
+
* @tag layer:providers
|
|
57
|
+
* @tag access:server-only
|
|
58
|
+
*/
|
|
59
|
+
import { IShippingProvider } from "../../contracts";
|
|
60
|
+
import type { CreateShipmentInput, Shipment, TrackingInfo, ServiceabilityResult } from "../../contracts";
|
|
61
|
+
export interface ShiprocketConfig {
|
|
62
|
+
/** The API user's email. See the header on why this is not a "login id". */
|
|
63
|
+
email: string;
|
|
64
|
+
password: string;
|
|
65
|
+
/** Shiprocket pickup-location nickname, as registered in their dashboard. */
|
|
66
|
+
pickupLocation?: string;
|
|
67
|
+
}
|
|
68
|
+
export declare class ShiprocketShippingProvider extends IShippingProvider {
|
|
69
|
+
private readonly config;
|
|
70
|
+
readonly name = "shiprocket";
|
|
71
|
+
private token;
|
|
72
|
+
private tokenExpiresAt;
|
|
73
|
+
constructor(config: ShiprocketConfig);
|
|
74
|
+
/**
|
|
75
|
+
* A bearer token, logging in only when the cached one is absent or stale.
|
|
76
|
+
*
|
|
77
|
+
* The 60-second safety margin matters: a token that expires mid-request
|
|
78
|
+
* produces a 401 the caller has to interpret, and shaving a minute off a
|
|
79
|
+
* ten-day lifetime costs nothing.
|
|
80
|
+
*/
|
|
81
|
+
private getToken;
|
|
82
|
+
/**
|
|
83
|
+
* One authenticated call, with a single re-auth on 401.
|
|
84
|
+
*
|
|
85
|
+
* 🛑 Exactly one retry. A token that expired early is worth one more attempt;
|
|
86
|
+
* a credential that is wrong must fail rather than loop, because a retry loop
|
|
87
|
+
* against an auth endpoint is how an integration gets rate-limited and then
|
|
88
|
+
* looks like an outage.
|
|
89
|
+
*/
|
|
90
|
+
private call;
|
|
91
|
+
/** Their order payload wants the address flattened across many keys. */
|
|
92
|
+
private addressFields;
|
|
93
|
+
createShipment(data: CreateShipmentInput): Promise<Shipment>;
|
|
94
|
+
trackShipment(trackingId: string): Promise<TrackingInfo>;
|
|
95
|
+
cancelShipment(shipmentId: string): Promise<void>;
|
|
96
|
+
checkServiceability(pincode: string, weight: number): Promise<ServiceabilityResult>;
|
|
97
|
+
generateLabel(shipmentId: string): Promise<ArrayBuffer>;
|
|
98
|
+
}
|