@mohasinac/appkit 4.62.0 → 4.63.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/features/layout/DashboardLayoutClient.js +8 -29
- package/dist/_internal/client/features/layout/filterNavItems.d.ts +28 -0
- package/dist/_internal/client/features/layout/filterNavItems.js +35 -0
- package/dist/_internal/server/features/ads/booking.d.ts +118 -0
- package/dist/_internal/server/features/ads/booking.js +326 -0
- package/dist/_internal/server/features/checkout/actions.d.ts +129 -9
- package/dist/_internal/server/features/checkout/actions.js +850 -79
- package/dist/_internal/server/features/checkout/expand-order-items.d.ts +1 -2
- package/dist/_internal/server/features/checkout/expand-order-items.js +32 -0
- package/dist/_internal/server/features/checkout/freeze-parts.d.ts +50 -0
- package/dist/_internal/server/features/checkout/freeze-parts.js +94 -0
- package/dist/_internal/server/features/checkout/value-otp-gate.d.ts +55 -0
- package/dist/_internal/server/features/checkout/value-otp-gate.js +60 -0
- package/dist/_internal/server/features/dashboard/attention.d.ts +128 -0
- package/dist/_internal/server/features/dashboard/attention.js +183 -0
- package/dist/_internal/server/features/dashboard/data.d.ts +47 -0
- package/dist/_internal/server/features/dashboard/data.js +82 -0
- package/dist/_internal/server/features/inventory/reservations.d.ts +99 -0
- package/dist/_internal/server/features/inventory/reservations.js +273 -0
- package/dist/_internal/server/features/invoicing/allocate.d.ts +63 -0
- package/dist/_internal/server/features/invoicing/allocate.js +162 -0
- package/dist/_internal/server/features/invoicing/credit-note.d.ts +57 -0
- package/dist/_internal/server/features/invoicing/credit-note.js +126 -0
- package/dist/_internal/server/features/invoicing/gstr1.d.ts +74 -0
- package/dist/_internal/server/features/invoicing/gstr1.js +251 -0
- package/dist/_internal/server/features/invoicing/issue.d.ts +96 -0
- package/dist/_internal/server/features/invoicing/issue.js +202 -0
- package/dist/_internal/server/features/offers/destinations.d.ts +40 -0
- package/dist/_internal/server/features/offers/destinations.js +65 -0
- package/dist/_internal/server/features/orders/actions.d.ts +8 -1
- package/dist/_internal/server/features/orders/actions.js +81 -8
- package/dist/_internal/server/features/orders/adapters.js +54 -0
- package/dist/_internal/server/features/orders/amend-delivery.d.ts +56 -0
- package/dist/_internal/server/features/orders/amend-delivery.js +124 -0
- package/dist/_internal/server/features/orders/balance.d.ts +89 -0
- package/dist/_internal/server/features/orders/balance.js +256 -0
- package/dist/_internal/server/features/orders/cancellation-refund.d.ts +15 -9
- package/dist/_internal/server/features/orders/cancellation-refund.js +15 -9
- package/dist/_internal/server/features/points/award.js +46 -4
- package/dist/_internal/server/features/pricing/actions.d.ts +58 -0
- package/dist/_internal/server/features/pricing/actions.js +144 -0
- package/dist/_internal/server/features/refunds/actions.js +26 -0
- package/dist/_internal/server/features/shipping/book-split.d.ts +86 -0
- package/dist/_internal/server/features/shipping/book-split.js +130 -0
- package/dist/_internal/server/features/shipping/book.d.ts +61 -0
- package/dist/_internal/server/features/shipping/book.js +176 -0
- package/dist/_internal/server/features/shipping/courier-block.d.ts +69 -0
- package/dist/_internal/server/features/shipping/courier-block.js +264 -0
- package/dist/_internal/server/features/site-settings/adapters.d.ts +2 -2
- package/dist/_internal/server/features/site-settings/adapters.js +29 -0
- package/dist/_internal/server/features/stores/adapters.d.ts +2 -2
- package/dist/_internal/server/features/stores/adapters.js +65 -0
- package/dist/_internal/server/functions/scheduled.d.ts +2 -1
- package/dist/_internal/server/functions/scheduled.js +95 -2
- package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +11 -2
- package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +4 -0
- package/dist/_internal/server/jobs/core/dailyStatusDigest.js +19 -2
- package/dist/_internal/server/jobs/core/index.d.ts +2 -1
- package/dist/_internal/server/jobs/core/index.js +2 -1
- package/dist/_internal/server/jobs/core/jobRunners.js +45 -0
- package/dist/_internal/server/jobs/core/onJobCreated.d.ts +30 -7
- package/dist/_internal/server/jobs/core/onJobCreated.js +78 -45
- package/dist/_internal/server/jobs/core/onOrderStatusChange.d.ts +7 -0
- package/dist/_internal/server/jobs/core/onOrderStatusChange.js +65 -0
- package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +33 -0
- package/dist/_internal/server/jobs/core/reservationExpiry.d.ts +17 -0
- package/dist/_internal/server/jobs/core/reservationExpiry.js +40 -0
- package/dist/_internal/server/jobs/core/runJobOnce.d.ts +48 -0
- package/dist/_internal/server/jobs/core/runJobOnce.js +195 -0
- package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +25 -2
- package/dist/_internal/server/jobs/handlers/index.d.ts +1 -0
- package/dist/_internal/server/jobs/handlers/index.js +1 -0
- package/dist/_internal/server/jobs/handlers/onOrderStatusChange.js +17 -0
- package/dist/_internal/server/jobs/handlers/reservationExpiry.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/reservationExpiry.js +2 -0
- package/dist/_internal/server/notifications/channel-health.d.ts +26 -3
- package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
- package/dist/_internal/shared/actions/action-registry.js +296 -0
- package/dist/_internal/shared/checkout/coupon-discount.d.ts +43 -1
- package/dist/_internal/shared/checkout/coupon-discount.js +26 -1
- package/dist/_internal/shared/checkout/order-math.d.ts +174 -0
- package/dist/_internal/shared/checkout/order-math.js +159 -0
- package/dist/_internal/shared/checkout/refundable-base.d.ts +25 -0
- package/dist/_internal/shared/checkout/refundable-base.js +13 -1
- package/dist/_internal/shared/checkout/rules/index.d.ts +1 -1
- package/dist/_internal/shared/checkout/rules/index.js +1 -1
- package/dist/_internal/shared/checkout/rules/payment-gate.d.ts +18 -0
- package/dist/_internal/shared/checkout/rules/payment-gate.js +25 -0
- package/dist/_internal/shared/checkout/split.d.ts +75 -0
- package/dist/_internal/shared/checkout/split.js +120 -0
- package/dist/_internal/shared/content/disclaimers.d.ts +88 -0
- package/dist/_internal/shared/content/disclaimers.js +217 -0
- package/dist/_internal/shared/content/published-values.d.ts +93 -0
- package/dist/_internal/shared/content/published-values.js +206 -0
- package/dist/_internal/shared/features/admin/integrations.d.ts +139 -0
- package/dist/_internal/shared/features/admin/integrations.js +263 -0
- package/dist/_internal/shared/features/dashboard/hub-sections.d.ts +72 -0
- package/dist/_internal/shared/features/dashboard/hub-sections.js +75 -0
- package/dist/_internal/shared/features/emi/choice.d.ts +98 -0
- package/dist/_internal/shared/features/emi/choice.js +69 -0
- package/dist/_internal/shared/features/emi/group.d.ts +84 -0
- package/dist/_internal/shared/features/emi/group.js +126 -0
- package/dist/_internal/shared/features/ledger/posting.d.ts +107 -0
- package/dist/_internal/shared/features/ledger/posting.js +165 -0
- package/dist/_internal/shared/features/ledger/reports.d.ts +76 -0
- package/dist/_internal/shared/features/ledger/reports.js +127 -0
- package/dist/_internal/shared/features/ledger/rules.d.ts +170 -0
- package/dist/_internal/shared/features/ledger/rules.js +221 -0
- package/dist/_internal/shared/features/offers/coordination.d.ts +122 -0
- package/dist/_internal/shared/features/offers/coordination.js +80 -0
- package/dist/_internal/shared/features/orders/delivery-snapshot.d.ts +114 -0
- package/dist/_internal/shared/features/orders/delivery-snapshot.js +116 -0
- package/dist/_internal/shared/features/orders/dispute-reasons.d.ts +113 -0
- package/dist/_internal/shared/features/orders/dispute-reasons.js +181 -0
- package/dist/_internal/shared/features/orders/refund-copy.d.ts +1 -1
- package/dist/_internal/shared/features/orders/refund-copy.js +18 -1
- package/dist/_internal/shared/features/payouts/pay-period.d.ts +91 -0
- package/dist/_internal/shared/features/payouts/pay-period.js +104 -0
- package/dist/_internal/shared/features/points/accepts.d.ts +29 -0
- package/dist/_internal/shared/features/points/accepts.js +49 -0
- package/dist/_internal/shared/features/pricing/rate-registry.d.ts +150 -0
- package/dist/_internal/shared/features/pricing/rate-registry.js +246 -0
- package/dist/_internal/shared/features/shipping/parcel.d.ts +123 -0
- package/dist/_internal/shared/features/shipping/parcel.js +139 -0
- package/dist/_internal/shared/features/shipping/shared-purchase.d.ts +91 -0
- package/dist/_internal/shared/features/shipping/shared-purchase.js +108 -0
- package/dist/_internal/shared/features/site-settings/fees.d.ts +16 -8
- package/dist/_internal/shared/features/site-settings/fees.js +12 -8
- package/dist/_internal/shared/features/site-settings/types.d.ts +11 -0
- package/dist/_internal/shared/fees/calculator.d.ts +33 -1
- package/dist/_internal/shared/fees/calculator.js +32 -2
- package/dist/_internal/shared/fees/explain.d.ts +81 -0
- package/dist/_internal/shared/fees/explain.js +101 -0
- package/dist/_internal/shared/history/index.d.ts +1 -1
- package/dist/_internal/shared/history/index.js +1 -1
- package/dist/_internal/shared/history/types.d.ts +7 -1
- package/dist/_internal/shared/history/types.js +25 -0
- package/dist/client.d.ts +21 -0
- package/dist/client.js +43 -0
- package/dist/constants/api-endpoints.d.ts +114 -0
- package/dist/constants/api-endpoints.js +55 -0
- package/dist/constants/field-names.d.ts +42 -0
- package/dist/constants/field-names.js +52 -0
- package/dist/contracts/index.d.ts +1 -1
- package/dist/contracts/shipping.d.ts +45 -0
- package/dist/contracts/shipping.js +15 -0
- package/dist/features/about/components/AboutView.js +1 -1
- package/dist/features/account/components/BuyerAuctionsGuideView.js +4 -1
- package/dist/features/account/components/UserOrdersView.js +47 -35
- package/dist/features/admin/components/AdminCouponEditorView.js +17 -0
- package/dist/features/admin/components/AdminIntegrationsView.d.ts +55 -0
- package/dist/features/admin/components/AdminIntegrationsView.js +74 -0
- package/dist/features/admin/components/AdminInvoicingView.d.ts +2 -0
- package/dist/features/admin/components/AdminInvoicingView.js +65 -0
- package/dist/features/admin/components/AdminOrderEditorView.d.ts +33 -1
- package/dist/features/admin/components/AdminOrderEditorView.js +81 -3
- package/dist/features/admin/components/AdminOrdersGuideView.js +23 -2
- package/dist/features/admin/components/AdminOrdersView.js +86 -5
- package/dist/features/admin/components/OwnerQuickActions.js +24 -2
- package/dist/features/admin/constants/filter-tabs.d.ts +6 -0
- package/dist/features/admin/constants/filter-tabs.js +6 -0
- package/dist/features/admin/constants/site-settings-tabs.d.ts +1 -1
- package/dist/features/admin/hooks/useAdminListingData.js +16 -0
- package/dist/features/admin/schemas/admin-user-form.d.ts +2 -2
- package/dist/features/admin/schemas/firestore.d.ts +62 -0
- package/dist/features/admin/schemas/firestore.js +5 -0
- package/dist/features/ads/schemas/booking-write.d.ts +120 -0
- package/dist/features/ads/schemas/booking-write.js +75 -0
- package/dist/features/ads/schemas/creative-form.d.ts +18 -0
- package/dist/features/ads/schemas/creative-form.js +51 -0
- package/dist/features/ads/schemas/firestore.d.ts +140 -0
- package/dist/features/ads/schemas/firestore.js +109 -0
- package/dist/features/auctions/repository/bid.repository.js +3 -1
- package/dist/features/audit-log/schemas/firestore.d.ts +140 -0
- package/dist/features/audit-log/schemas/firestore.js +89 -0
- package/dist/features/auth/actions/profile-actions.d.ts +69 -1
- package/dist/features/auth/actions/profile-actions.js +62 -1
- package/dist/features/auth/permissions/constants.js +13 -0
- package/dist/features/auth/schemas/firestore.d.ts +16 -2
- package/dist/features/auth/schemas/firestore.js +2 -1
- package/dist/features/blog/actions/blog-actions.d.ts +6 -0
- package/dist/features/blog/actions/blog-actions.js +17 -2
- package/dist/features/blog/api/route.js +4 -1
- package/dist/features/blog/columns/index.js +5 -0
- package/dist/features/blog/components/BlogIndexPageView.js +2 -1
- package/dist/features/blog/repository/blog.repository.d.ts +4 -0
- package/dist/features/blog/repository/blog.repository.js +5 -0
- package/dist/features/blog/schemas/blog-form.d.ts +3 -0
- package/dist/features/blog/schemas/blog-form.js +1 -0
- package/dist/features/blog/schemas/firestore.d.ts +38 -1
- package/dist/features/blog/schemas/firestore.js +23 -0
- package/dist/features/blog/schemas/index.d.ts +6 -0
- package/dist/features/blog/schemas/index.js +2 -0
- package/dist/features/blog/types/index.d.ts +2 -0
- package/dist/features/cart/components/CartPriceBreakdown.d.ts +25 -1
- package/dist/features/cart/components/CartPriceBreakdown.js +29 -6
- package/dist/features/cart/components/PointsTenderPicker.d.ts +61 -0
- package/dist/features/cart/components/PointsTenderPicker.js +15 -0
- package/dist/features/cart/components/StoreAddonsPicker.js +2 -1
- package/dist/features/cart/components/index.d.ts +2 -0
- package/dist/features/cart/components/index.js +1 -0
- package/dist/features/cart/repository/cart.repository.d.ts +33 -0
- package/dist/features/cart/repository/cart.repository.js +47 -0
- package/dist/features/cart/schemas/firestore.d.ts +116 -0
- package/dist/features/contact/email.d.ts +27 -10
- package/dist/features/contact/email.js +20 -3
- package/dist/features/dashboard/components/DashboardHubView.d.ts +83 -0
- package/dist/features/dashboard/components/DashboardHubView.js +56 -0
- package/dist/features/dashboard/components/DashboardSectionsClient.d.ts +23 -0
- package/dist/features/dashboard/components/DashboardSectionsClient.js +66 -0
- package/dist/features/dispute-reasons/components/AdminDisputeReasonsView.d.ts +55 -0
- package/dist/features/dispute-reasons/components/AdminDisputeReasonsView.js +175 -0
- package/dist/features/dispute-reasons/repository/dispute-reasons.repository.d.ts +62 -0
- package/dist/features/dispute-reasons/repository/dispute-reasons.repository.js +108 -0
- package/dist/features/dispute-reasons/schemas/firestore.d.ts +62 -0
- package/dist/features/dispute-reasons/schemas/firestore.js +40 -0
- package/dist/features/events/components/EventSaleBanner.js +1 -1
- package/dist/features/faq/components/FAQAccordion.d.ts +13 -1
- package/dist/features/faq/components/FAQAccordion.js +29 -4
- package/dist/features/faq/components/FAQPageContent.js +2 -2
- package/dist/features/gateway-events/schemas/index.d.ts +2 -2
- package/dist/features/homepage/schemas/index.d.ts +8 -8
- package/dist/features/inventory/schemas/stock-reservation.d.ts +114 -0
- package/dist/features/inventory/schemas/stock-reservation.js +103 -0
- package/dist/features/invoicing/schemas/firestore.d.ts +112 -0
- package/dist/features/invoicing/schemas/firestore.js +45 -0
- package/dist/features/invoicing/utils/financial-year.d.ts +43 -0
- package/dist/features/invoicing/utils/financial-year.js +53 -0
- package/dist/features/jobs/actions/enqueue-job.js +18 -1
- package/dist/features/jobs/repository/jobs.repository.d.ts +62 -1
- package/dist/features/jobs/repository/jobs.repository.js +84 -1
- package/dist/features/jobs/schemas/firestore.d.ts +80 -0
- package/dist/features/jobs/schemas/firestore.js +37 -0
- package/dist/features/layout/AppLayoutShell.d.ts +9 -1
- package/dist/features/layout/AppLayoutShell.js +12 -4
- package/dist/features/layout/BottomActions.js +2 -1
- package/dist/features/layout/BottomNavbar.d.ts +10 -2
- package/dist/features/layout/SideActionDock.js +52 -2
- package/dist/features/layout/TitleBarLayout.js +13 -4
- package/dist/features/layout/TitleBarLayout.style.css +59 -0
- package/dist/features/layout/useCtaReveal.d.ts +16 -1
- package/dist/features/layout/useCtaReveal.js +17 -26
- package/dist/features/ledger/repository/journal.repository.d.ts +110 -0
- package/dist/features/ledger/repository/journal.repository.js +312 -0
- package/dist/features/ledger/schemas/expenses.d.ts +87 -0
- package/dist/features/ledger/schemas/expenses.js +27 -0
- package/dist/features/ledger/schemas/firestore.d.ts +183 -0
- package/dist/features/ledger/schemas/firestore.js +69 -0
- package/dist/features/lottery/schemas/zod.d.ts +6 -6
- package/dist/features/media/MediaImage.js +22 -1
- package/dist/features/media/upload/ImageUpload.js +1 -1
- package/dist/features/obligations/constants/policies.js +24 -1
- package/dist/features/orders/components/BalancePaymentPanel.d.ts +12 -0
- package/dist/features/orders/components/BalancePaymentPanel.js +94 -0
- package/dist/features/orders/components/OrderPaymentSummary.js +10 -1
- package/dist/features/orders/components/OrderProvenanceCard.d.ts +8 -0
- package/dist/features/orders/components/OrderProvenanceCard.js +185 -0
- package/dist/features/orders/components/RaiseDisputeForm.d.ts +14 -0
- package/dist/features/orders/components/RaiseDisputeForm.js +119 -0
- package/dist/features/orders/components/RefundRequestView.js +19 -1
- package/dist/features/orders/components/index.d.ts +4 -0
- package/dist/features/orders/components/index.js +2 -0
- package/dist/features/orders/constants/order-lane-tabs.d.ts +69 -0
- package/dist/features/orders/constants/order-lane-tabs.js +88 -0
- package/dist/features/orders/repository/orders.repository.d.ts +85 -1
- package/dist/features/orders/repository/orders.repository.js +205 -6
- package/dist/features/orders/schemas/balance.d.ts +40 -0
- package/dist/features/orders/schemas/balance.js +47 -0
- package/dist/features/orders/schemas/firestore.d.ts +398 -1
- package/dist/features/orders/schemas/firestore.js +43 -0
- package/dist/features/orders/schemas/index.d.ts +56 -8
- package/dist/features/orders/schemas/index.js +12 -0
- package/dist/features/orders/types/index.d.ts +47 -0
- package/dist/features/orders/utils/courier-block.d.ts +25 -0
- package/dist/features/orders/utils/courier-block.js +23 -0
- package/dist/features/payment-cases/schemas/firestore.d.ts +26 -1
- package/dist/features/payment-cases/schemas/firestore.js +1 -0
- package/dist/features/payments/repository/payout.repository.js +3 -2
- package/dist/features/payments/schemas/firestore.d.ts +92 -1
- package/dist/features/payments/schemas/firestore.js +23 -0
- package/dist/features/pricing/components/AdminPricingView.d.ts +13 -0
- package/dist/features/pricing/components/AdminPricingView.js +157 -0
- package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -2
- package/dist/features/products/components/ProductDetailPageView.d.ts +17 -1
- package/dist/features/products/components/ProductDetailPageView.js +2 -2
- package/dist/features/products/schemas/firestore.d.ts +26 -1
- package/dist/features/products/schemas/firestore.js +2 -0
- package/dist/features/products/schemas/index.d.ts +2 -2
- package/dist/features/products/schemas/product-features.validators.d.ts +10 -10
- package/dist/features/promotions/actions/coupon-stacking.d.ts +30 -3
- package/dist/features/promotions/actions/coupon-stacking.js +21 -2
- package/dist/features/promotions/components/CouponCard.js +13 -0
- package/dist/features/promotions/constants/coupon-help.d.ts +2 -2
- package/dist/features/promotions/constants/coupon-help.js +9 -1
- package/dist/features/promotions/schemas/firestore.d.ts +24 -0
- package/dist/features/promotions/schemas/firestore.js +4 -0
- package/dist/features/promotions/types/index.d.ts +19 -1
- package/dist/features/reviews/repository/reviews.repository.d.ts +14 -0
- package/dist/features/reviews/repository/reviews.repository.js +16 -0
- package/dist/features/scams/components/ScamProfileView.js +2 -2
- package/dist/features/scams/components/ScamRegistryView.js +2 -2
- package/dist/features/scams/repository/scammer.repository.js +2 -1
- package/dist/features/scams/schemas/firestore.d.ts +2 -1
- package/dist/features/scams/schemas/firestore.js +2 -1
- package/dist/features/search/action-index/tab-entries.js +1 -1
- package/dist/features/seller/actions/offer-actions.js +56 -0
- package/dist/features/seller/actions/seller-actions.d.ts +1 -1
- package/dist/features/seller/actions/seller-actions.js +37 -3
- package/dist/features/seller/components/DispatchForm.d.ts +11 -0
- package/dist/features/seller/components/DispatchForm.js +190 -0
- package/dist/features/seller/components/SellerOrdersView.js +221 -27
- package/dist/features/seller/components/index.d.ts +1 -0
- package/dist/features/seller/components/index.js +1 -0
- package/dist/features/seller/hooks/useSellerListingData.js +25 -0
- package/dist/features/seller/repository/offer.repository.js +4 -3
- package/dist/features/seller/schemas/firestore.d.ts +23 -2
- package/dist/features/seller/schemas/firestore.js +3 -2
- package/dist/features/seller/schemas/index.d.ts +4 -4
- package/dist/features/seller/schemas/order-forms.d.ts +61 -4
- package/dist/features/seller/schemas/order-forms.js +41 -8
- package/dist/features/shipments/schemas/firestore.d.ts +25 -0
- package/dist/features/shipments/schemas/validation.d.ts +4 -4
- package/dist/features/shipping-boxes/repository/shipping-boxes.repository.d.ts +82 -0
- package/dist/features/shipping-boxes/repository/shipping-boxes.repository.js +145 -0
- package/dist/features/shipping-boxes/schemas/firestore.d.ts +80 -0
- package/dist/features/shipping-boxes/schemas/firestore.js +53 -0
- package/dist/features/store-extensions/schemas/report-create-form.d.ts +2 -2
- package/dist/features/store-extensions/schemas/shipping-config-form.d.ts +2 -2
- package/dist/features/stores/components/StoreOrdersGuideView.js +6 -1
- package/dist/features/stores/repository/store.repository.d.ts +18 -0
- package/dist/features/stores/repository/store.repository.js +27 -1
- package/dist/features/stores/schemas/firestore.d.ts +112 -0
- package/dist/features/stores/schemas/firestore.js +20 -0
- package/dist/features/stores/schemas/index.d.ts +6 -6
- package/dist/features/stores/types/index.d.ts +19 -0
- package/dist/features/support/repository/support.repository.js +72 -6
- package/dist/features/support/schemas/firestore.d.ts +17 -0
- package/dist/features/support/schemas/index.d.ts +8 -8
- package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +33 -1
- package/dist/next/routing/route-map.d.ts +112 -0
- package/dist/next/routing/route-map.js +63 -0
- package/dist/providers/shipping-shiprocket/index.d.ts +27 -1
- package/dist/providers/shipping-shiprocket/index.js +84 -1
- package/dist/react/contexts/SessionContext.d.ts +17 -1
- package/dist/schemas/registry.d.ts +69 -34
- package/dist/schemas/sieve.d.ts +2 -2
- package/dist/security/pii-schemas.d.ts +1 -1
- package/dist/security/pii-schemas.js +45 -0
- package/dist/server-entry.d.ts +2 -2
- package/dist/server-entry.js +8 -1
- package/dist/server.d.ts +36 -1
- package/dist/server.js +183 -1
- package/dist/styles.css +412 -80
- package/dist/tailwind-utilities.css +1 -1
- package/dist/tokens/themes/default-dark.js +1 -0
- package/dist/tokens/themes/default-light.js +1 -0
- package/dist/tokens/themes/required.d.ts +1 -1
- package/dist/tokens/themes/required.js +1 -0
- package/dist/tokens/tokens.css +15 -0
- package/dist/ui/components/Button.d.ts +10 -1
- package/dist/ui/components/Button.js +25 -3
- package/dist/ui/components/Chart.d.ts +63 -0
- package/dist/ui/components/Chart.js +169 -0
- package/dist/ui/components/Chart.style.css +214 -0
- package/dist/ui/components/Disclaimer.d.ts +19 -0
- package/dist/ui/components/Disclaimer.js +83 -0
- package/dist/ui/components/OverflowRow.js +54 -2
- package/dist/ui/components/OverflowRow.style.css +38 -0
- package/dist/ui/components/RichTextEditor.js +99 -8
- package/dist/ui/components/chart-spec.d.ts +68 -0
- package/dist/ui/components/chart-spec.js +140 -0
- package/dist/ui/components/index.style.css +1 -0
- package/dist/ui/components/surface-tokens.d.ts +1 -1
- package/dist/ui/components/surface-tokens.js +9 -0
- package/dist/ui/components/tabs-overflow.js +64 -11
- package/dist/ui/components/toolbar-collapse.d.ts +13 -0
- package/dist/ui/components/toolbar-collapse.js +10 -1
- package/dist/ui/index.d.ts +8 -0
- package/dist/ui/index.js +9 -0
- package/dist/ui/rich-text/RichText.d.ts +10 -1
- package/dist/ui/rich-text/RichText.js +33 -2
- package/dist/ui/rich-text/RichText.style.css +83 -79
- package/dist/ui/rich-text/RichTextRenderer.d.ts +30 -1
- package/dist/ui/rich-text/RichTextRenderer.js +34 -2
- package/dist/ui/rich-text/chart-blocks.d.ts +62 -0
- package/dist/ui/rich-text/chart-blocks.js +87 -0
- package/package.json +1 -1
- package/scripts/seed-cli.mjs +1834 -1822
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* D56 — a SELF-SERVE ad booking: one advertiser, one placement, one period.
|
|
3
|
+
*
|
|
4
|
+
* ## 🛑 Flat fee per slot per period, and explicitly NOT CPM
|
|
5
|
+
*
|
|
6
|
+
* Impression counting is a write per page view, which is the exact cost
|
|
7
|
+
* pattern that suspended this project (Root Cause #104: 3.1M ISR writes
|
|
8
|
+
* against a 200K allowance, 52.52 GB of Fast Origin Transfer against 10 GB,
|
|
9
|
+
* for eleven monthly active users). A flat fee is one write per BOOKING.
|
|
10
|
+
* Nothing here counts anything per render, and nothing should be added that
|
|
11
|
+
* does.
|
|
12
|
+
*
|
|
13
|
+
* ## Why a PERIOD rather than an arbitrary date range
|
|
14
|
+
*
|
|
15
|
+
* The plan's requirement is slot-availability locking — two advertisers must
|
|
16
|
+
* not book the same slot for overlapping dates. Firestore has no range
|
|
17
|
+
* constraint, so an arbitrary `startAt`/`endAt` pair can only be checked by
|
|
18
|
+
* QUERYING for overlaps and then writing, and two concurrent bookings both
|
|
19
|
+
* read "no overlap" and both write. That race is invisible in testing and
|
|
20
|
+
* sells the same slot twice.
|
|
21
|
+
*
|
|
22
|
+
* Discretising to a period makes the conflict a DOCUMENT COLLISION instead:
|
|
23
|
+
* the booking id is derived from `(placementId, period)`, so the second
|
|
24
|
+
* writer fails on an existing document inside its own transaction and
|
|
25
|
+
* Firestore does the locking. There is no query to race against.
|
|
26
|
+
*
|
|
27
|
+
* It also matches what is being sold. "The homepage banner for November" is
|
|
28
|
+
* the product; "the homepage banner from the 9th to the 23rd" is a pricing
|
|
29
|
+
* model nobody asked for and an availability calendar nobody can render.
|
|
30
|
+
*/
|
|
31
|
+
export const AD_BOOKING_COLLECTION = "adBookings";
|
|
32
|
+
const PERIOD_PATTERN = /^\d{4}-(0[1-9]|1[0-2])$/;
|
|
33
|
+
export function isAdPeriod(value) {
|
|
34
|
+
return PERIOD_PATTERN.test(value);
|
|
35
|
+
}
|
|
36
|
+
/** The period a date falls in, in UTC. */
|
|
37
|
+
export function adPeriodOf(date) {
|
|
38
|
+
const y = date.getUTCFullYear();
|
|
39
|
+
const m = String(date.getUTCMonth() + 1).padStart(2, "0");
|
|
40
|
+
return `${y}-${m}`;
|
|
41
|
+
}
|
|
42
|
+
/** First instant of a period, UTC. */
|
|
43
|
+
export function adPeriodStart(period) {
|
|
44
|
+
const [y, m] = period.split("-").map(Number);
|
|
45
|
+
return new Date(Date.UTC(y, m - 1, 1, 0, 0, 0, 0));
|
|
46
|
+
}
|
|
47
|
+
/** First instant of the NEXT period — the exclusive end. */
|
|
48
|
+
export function adPeriodEnd(period) {
|
|
49
|
+
const [y, m] = period.split("-").map(Number);
|
|
50
|
+
return new Date(Date.UTC(y, m, 1, 0, 0, 0, 0));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* 🛑 The booking id IS the lock. Derived, never generated.
|
|
54
|
+
*
|
|
55
|
+
* Two advertisers booking `banner-home` for `2026-11` compute the same id and
|
|
56
|
+
* the second `tx.create` throws `ALREADY_EXISTS` — which is the whole
|
|
57
|
+
* availability guarantee, enforced by Firestore rather than by a check
|
|
58
|
+
* somebody could forget to run.
|
|
59
|
+
*/
|
|
60
|
+
export function adBookingId(placementId, period) {
|
|
61
|
+
return `${placementId}__${period}`;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Payment state. Deliberately coarse: this records whether the slot is PAID
|
|
65
|
+
* FOR, not how. The invoice and the ledger posting are Part 4's job and carry
|
|
66
|
+
* the detail; duplicating any of it here would be two records of one fact.
|
|
67
|
+
*/
|
|
68
|
+
export const AD_BOOKING_PAYMENT_STATES = ["unpaid", "paid", "refunded"];
|
|
69
|
+
/**
|
|
70
|
+
* Creative moderation. **Nothing renders on the site until `approved`.**
|
|
71
|
+
*
|
|
72
|
+
* 🛑 `pending` is the initial value and there is no way to write `approved`
|
|
73
|
+
* through the advertiser's own schema — see `adBookingWriteSchema`. A
|
|
74
|
+
* self-serve flow where the submitter can set their own moderation state is
|
|
75
|
+
* not moderated; it is a form with an extra field (Root Cause #76 — a field
|
|
76
|
+
* the form can send is a field the form can destroy, here inverted into a
|
|
77
|
+
* field the form can grant itself).
|
|
78
|
+
*/
|
|
79
|
+
export const AD_MODERATION_STATES = ["pending", "approved", "rejected"];
|
|
80
|
+
/**
|
|
81
|
+
* Does this booking put a creative on the page right now?
|
|
82
|
+
*
|
|
83
|
+
* 🛑 All four conditions, and the order is not an accident — moderation is
|
|
84
|
+
* checked before the calendar so an approved-but-future booking and an
|
|
85
|
+
* unreviewed current one are distinguishable in a debugger.
|
|
86
|
+
*/
|
|
87
|
+
export function isAdBookingLive(booking, now = new Date()) {
|
|
88
|
+
if (booking.cancelledAt)
|
|
89
|
+
return false;
|
|
90
|
+
if (booking.moderation.state !== "approved")
|
|
91
|
+
return false;
|
|
92
|
+
if (booking.paymentState !== "paid")
|
|
93
|
+
return false;
|
|
94
|
+
const start = adPeriodStart(booking.period);
|
|
95
|
+
const end = adPeriodEnd(booking.period);
|
|
96
|
+
return now >= start && now < end;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* 🛑 A cancelled booking KEEPS its document, and therefore keeps the slot
|
|
100
|
+
* locked for its own period.
|
|
101
|
+
*
|
|
102
|
+
* Deleting it would free the slot — which sounds like the point and is the
|
|
103
|
+
* wrong behaviour twice over: the advertiser has paid for a period that has
|
|
104
|
+
* possibly already started, and re-selling a month mid-flight means two
|
|
105
|
+
* creatives were live in one slot at different times with one invoice
|
|
106
|
+
* between them. Freeing a period is an ADMIN act (`releaseAdSlot`), done
|
|
107
|
+
* knowingly, not a side effect of a cancel button.
|
|
108
|
+
*/
|
|
109
|
+
export const AD_BOOKING_CANCELLED_KEEPS_SLOT = true;
|
|
@@ -276,7 +276,9 @@ export class BidRepository extends BaseRepository {
|
|
|
276
276
|
reason: ctx?.reason,
|
|
277
277
|
note: ctx?.note,
|
|
278
278
|
// `userName`/`userEmail` are denormalised onto every bid, and
|
|
279
|
-
// `encryptPiiFields`
|
|
279
|
+
// `encryptPiiFields` covers a field only where it is NAMED. It CAN reach
|
|
280
|
+
// into an array via `array[].key`, but a bare key does not — so an
|
|
281
|
+
// undeclared nested value is stored in plaintext.
|
|
280
282
|
piiFields: BID_HISTORY_PII_FIELDS,
|
|
281
283
|
});
|
|
282
284
|
return withEntry ?? patch;
|
|
@@ -44,6 +44,76 @@ export declare const AdminAuditActionValues: {
|
|
|
44
44
|
* same class as `payout_mark_paid` and `coupon_update`, which are both here.
|
|
45
45
|
*/
|
|
46
46
|
readonly POINTS_ADJUST: "points_adjust";
|
|
47
|
+
/**
|
|
48
|
+
* Staff added a buyer-facing dispute reason.
|
|
49
|
+
*
|
|
50
|
+
* 🛑 Here because the list is POLICY VOCABULARY, even though no single row
|
|
51
|
+
* decides money. The reasons are what buyers are offered when something goes
|
|
52
|
+
* wrong, so the wording shapes what gets reported and how it is triaged —
|
|
53
|
+
* and a badly-worded or leading option is the kind of thing that is only
|
|
54
|
+
* ever noticed later, by which time "who added this, and when" is the
|
|
55
|
+
* question. `createdByName` on the row answers it for the list; this answers
|
|
56
|
+
* it in the one place an admin looks for "what have staff done lately".
|
|
57
|
+
*
|
|
58
|
+
* Recorded only on a REAL creation. Re-adding wording that already exists
|
|
59
|
+
* returns the existing row, which is not an act worth logging.
|
|
60
|
+
*/
|
|
61
|
+
readonly DISPUTE_REASON_CREATE: "dispute_reason_create";
|
|
62
|
+
readonly DISPUTE_REASON_RETIRE: "dispute_reason_retire";
|
|
63
|
+
/**
|
|
64
|
+
* An admin changed a platform rate through `/admin/pricing`.
|
|
65
|
+
*
|
|
66
|
+
* 🛑 Recorded here as well as in `siteSettings.rateChanges`, and the two are
|
|
67
|
+
* not redundant. The rate log answers "when did THIS rate last move" and is
|
|
68
|
+
* capped, so it can lose its oldest entries; this answers "what have admins
|
|
69
|
+
* done lately" across every privileged act, and is the one that has to
|
|
70
|
+
* survive. Same split as `points_adjust` against its ledger.
|
|
71
|
+
*
|
|
72
|
+
* Every rate here is money the platform charges or withholds, so this is the
|
|
73
|
+
* same class as `coupon_update` and `payout_mark_paid`.
|
|
74
|
+
*/
|
|
75
|
+
readonly PRICING_UPDATE: "pricing_update";
|
|
76
|
+
/**
|
|
77
|
+
* An admin granted or revoked `trustedSeller` on a store.
|
|
78
|
+
*
|
|
79
|
+
* 🛑 Its OWN action rather than folded into `store_status_change`, because
|
|
80
|
+
* "what changed about this store" and "who accepted this risk" are
|
|
81
|
+
* different questions. Trusting a seller means paying before delivery, so
|
|
82
|
+
* the platform carries a lost parcel and a non-delivery dispute — and when
|
|
83
|
+
* one of those lands, the question is who decided and when.
|
|
84
|
+
*
|
|
85
|
+
* Recorded on a real change only. Re-saving an unrelated field on an
|
|
86
|
+
* already-trusted store writes nothing; a log of non-events stops being
|
|
87
|
+
* read.
|
|
88
|
+
*/
|
|
89
|
+
readonly STORE_TRUST_CHANGE: "store_trust_change";
|
|
90
|
+
/** A role's permission set changed — the definition of who can do what. */
|
|
91
|
+
readonly ROLE_CHANGE: "role_change";
|
|
92
|
+
/**
|
|
93
|
+
* A tax code's rate or HSN mapping changed.
|
|
94
|
+
*
|
|
95
|
+
* 🛑 The one STATUTORY thing an admin can edit, which is why
|
|
96
|
+
* `/admin/pricing` deliberately does not mirror it. A wrong rate here is a
|
|
97
|
+
* wrong return, so "who set this and when" is the question an assessment
|
|
98
|
+
* asks first.
|
|
99
|
+
*/
|
|
100
|
+
readonly TAX_CODE_CHANGE: "tax_code_change";
|
|
101
|
+
/** Sessions forcibly revoked — the user is signed out everywhere, now. */
|
|
102
|
+
readonly SESSION_REVOKE: "session_revoke";
|
|
103
|
+
/** A bulk operation over many users at once. */
|
|
104
|
+
readonly USER_BULK_ACTION: "user_bulk_action";
|
|
105
|
+
/** A moderation report resolved, dismissed or actioned. */
|
|
106
|
+
readonly MODERATION_DECISION: "moderation_decision";
|
|
107
|
+
/** A payment case claimed or resolved — money a buyer says did not arrive. */
|
|
108
|
+
readonly PAYMENT_CASE_DECISION: "payment_case_decision";
|
|
109
|
+
/**
|
|
110
|
+
* A scammer profile edited.
|
|
111
|
+
*
|
|
112
|
+
* 🛑 Public-facing accusation. The profile names a person or a payment
|
|
113
|
+
* handle, so the wording and the status are reputational — and the one
|
|
114
|
+
* question that follows a complaint is who wrote it.
|
|
115
|
+
*/
|
|
116
|
+
readonly SCAMMER_PROFILE_UPDATE: "scammer_profile_update";
|
|
47
117
|
};
|
|
48
118
|
export type AdminAuditAction = (typeof AdminAuditActionValues)[keyof typeof AdminAuditActionValues];
|
|
49
119
|
export interface AdminAuditLogDocument extends BaseDocument {
|
|
@@ -97,5 +167,75 @@ export declare const ADMIN_AUDIT_LOG_FIELDS: {
|
|
|
97
167
|
* same class as `payout_mark_paid` and `coupon_update`, which are both here.
|
|
98
168
|
*/
|
|
99
169
|
readonly POINTS_ADJUST: "points_adjust";
|
|
170
|
+
/**
|
|
171
|
+
* Staff added a buyer-facing dispute reason.
|
|
172
|
+
*
|
|
173
|
+
* 🛑 Here because the list is POLICY VOCABULARY, even though no single row
|
|
174
|
+
* decides money. The reasons are what buyers are offered when something goes
|
|
175
|
+
* wrong, so the wording shapes what gets reported and how it is triaged —
|
|
176
|
+
* and a badly-worded or leading option is the kind of thing that is only
|
|
177
|
+
* ever noticed later, by which time "who added this, and when" is the
|
|
178
|
+
* question. `createdByName` on the row answers it for the list; this answers
|
|
179
|
+
* it in the one place an admin looks for "what have staff done lately".
|
|
180
|
+
*
|
|
181
|
+
* Recorded only on a REAL creation. Re-adding wording that already exists
|
|
182
|
+
* returns the existing row, which is not an act worth logging.
|
|
183
|
+
*/
|
|
184
|
+
readonly DISPUTE_REASON_CREATE: "dispute_reason_create";
|
|
185
|
+
readonly DISPUTE_REASON_RETIRE: "dispute_reason_retire";
|
|
186
|
+
/**
|
|
187
|
+
* An admin changed a platform rate through `/admin/pricing`.
|
|
188
|
+
*
|
|
189
|
+
* 🛑 Recorded here as well as in `siteSettings.rateChanges`, and the two are
|
|
190
|
+
* not redundant. The rate log answers "when did THIS rate last move" and is
|
|
191
|
+
* capped, so it can lose its oldest entries; this answers "what have admins
|
|
192
|
+
* done lately" across every privileged act, and is the one that has to
|
|
193
|
+
* survive. Same split as `points_adjust` against its ledger.
|
|
194
|
+
*
|
|
195
|
+
* Every rate here is money the platform charges or withholds, so this is the
|
|
196
|
+
* same class as `coupon_update` and `payout_mark_paid`.
|
|
197
|
+
*/
|
|
198
|
+
readonly PRICING_UPDATE: "pricing_update";
|
|
199
|
+
/**
|
|
200
|
+
* An admin granted or revoked `trustedSeller` on a store.
|
|
201
|
+
*
|
|
202
|
+
* 🛑 Its OWN action rather than folded into `store_status_change`, because
|
|
203
|
+
* "what changed about this store" and "who accepted this risk" are
|
|
204
|
+
* different questions. Trusting a seller means paying before delivery, so
|
|
205
|
+
* the platform carries a lost parcel and a non-delivery dispute — and when
|
|
206
|
+
* one of those lands, the question is who decided and when.
|
|
207
|
+
*
|
|
208
|
+
* Recorded on a real change only. Re-saving an unrelated field on an
|
|
209
|
+
* already-trusted store writes nothing; a log of non-events stops being
|
|
210
|
+
* read.
|
|
211
|
+
*/
|
|
212
|
+
readonly STORE_TRUST_CHANGE: "store_trust_change";
|
|
213
|
+
/** A role's permission set changed — the definition of who can do what. */
|
|
214
|
+
readonly ROLE_CHANGE: "role_change";
|
|
215
|
+
/**
|
|
216
|
+
* A tax code's rate or HSN mapping changed.
|
|
217
|
+
*
|
|
218
|
+
* 🛑 The one STATUTORY thing an admin can edit, which is why
|
|
219
|
+
* `/admin/pricing` deliberately does not mirror it. A wrong rate here is a
|
|
220
|
+
* wrong return, so "who set this and when" is the question an assessment
|
|
221
|
+
* asks first.
|
|
222
|
+
*/
|
|
223
|
+
readonly TAX_CODE_CHANGE: "tax_code_change";
|
|
224
|
+
/** Sessions forcibly revoked — the user is signed out everywhere, now. */
|
|
225
|
+
readonly SESSION_REVOKE: "session_revoke";
|
|
226
|
+
/** A bulk operation over many users at once. */
|
|
227
|
+
readonly USER_BULK_ACTION: "user_bulk_action";
|
|
228
|
+
/** A moderation report resolved, dismissed or actioned. */
|
|
229
|
+
readonly MODERATION_DECISION: "moderation_decision";
|
|
230
|
+
/** A payment case claimed or resolved — money a buyer says did not arrive. */
|
|
231
|
+
readonly PAYMENT_CASE_DECISION: "payment_case_decision";
|
|
232
|
+
/**
|
|
233
|
+
* A scammer profile edited.
|
|
234
|
+
*
|
|
235
|
+
* 🛑 Public-facing accusation. The profile names a person or a payment
|
|
236
|
+
* handle, so the wording and the status are reputational — and the one
|
|
237
|
+
* question that follows a complaint is who wrote it.
|
|
238
|
+
*/
|
|
239
|
+
readonly SCAMMER_PROFILE_UPDATE: "scammer_profile_update";
|
|
100
240
|
};
|
|
101
241
|
};
|
|
@@ -42,6 +42,95 @@ export const AdminAuditActionValues = {
|
|
|
42
42
|
* same class as `payout_mark_paid` and `coupon_update`, which are both here.
|
|
43
43
|
*/
|
|
44
44
|
POINTS_ADJUST: "points_adjust",
|
|
45
|
+
/**
|
|
46
|
+
* Staff added a buyer-facing dispute reason.
|
|
47
|
+
*
|
|
48
|
+
* 🛑 Here because the list is POLICY VOCABULARY, even though no single row
|
|
49
|
+
* decides money. The reasons are what buyers are offered when something goes
|
|
50
|
+
* wrong, so the wording shapes what gets reported and how it is triaged —
|
|
51
|
+
* and a badly-worded or leading option is the kind of thing that is only
|
|
52
|
+
* ever noticed later, by which time "who added this, and when" is the
|
|
53
|
+
* question. `createdByName` on the row answers it for the list; this answers
|
|
54
|
+
* it in the one place an admin looks for "what have staff done lately".
|
|
55
|
+
*
|
|
56
|
+
* Recorded only on a REAL creation. Re-adding wording that already exists
|
|
57
|
+
* returns the existing row, which is not an act worth logging.
|
|
58
|
+
*/
|
|
59
|
+
DISPUTE_REASON_CREATE: "dispute_reason_create",
|
|
60
|
+
/*
|
|
61
|
+
* Retiring is recorded and reactivating is not, which is deliberate rather
|
|
62
|
+
* than an omission. Retiring REMOVES an option buyers could pick, so "who
|
|
63
|
+
* narrowed the list, and when" is the question an audit of a dispute trend
|
|
64
|
+
* needs answered. Putting a row back restores the documented default, and a
|
|
65
|
+
* log of both would read as churn.
|
|
66
|
+
*/
|
|
67
|
+
DISPUTE_REASON_RETIRE: "dispute_reason_retire",
|
|
68
|
+
/**
|
|
69
|
+
* An admin changed a platform rate through `/admin/pricing`.
|
|
70
|
+
*
|
|
71
|
+
* 🛑 Recorded here as well as in `siteSettings.rateChanges`, and the two are
|
|
72
|
+
* not redundant. The rate log answers "when did THIS rate last move" and is
|
|
73
|
+
* capped, so it can lose its oldest entries; this answers "what have admins
|
|
74
|
+
* done lately" across every privileged act, and is the one that has to
|
|
75
|
+
* survive. Same split as `points_adjust` against its ledger.
|
|
76
|
+
*
|
|
77
|
+
* Every rate here is money the platform charges or withholds, so this is the
|
|
78
|
+
* same class as `coupon_update` and `payout_mark_paid`.
|
|
79
|
+
*/
|
|
80
|
+
PRICING_UPDATE: "pricing_update",
|
|
81
|
+
/**
|
|
82
|
+
* An admin granted or revoked `trustedSeller` on a store.
|
|
83
|
+
*
|
|
84
|
+
* 🛑 Its OWN action rather than folded into `store_status_change`, because
|
|
85
|
+
* "what changed about this store" and "who accepted this risk" are
|
|
86
|
+
* different questions. Trusting a seller means paying before delivery, so
|
|
87
|
+
* the platform carries a lost parcel and a non-delivery dispute — and when
|
|
88
|
+
* one of those lands, the question is who decided and when.
|
|
89
|
+
*
|
|
90
|
+
* Recorded on a real change only. Re-saving an unrelated field on an
|
|
91
|
+
* already-trusted store writes nothing; a log of non-events stops being
|
|
92
|
+
* read.
|
|
93
|
+
*/
|
|
94
|
+
STORE_TRUST_CHANGE: "store_trust_change",
|
|
95
|
+
/*
|
|
96
|
+
* ── Part 14 / A5 ─────────────────────────────────────────────────────────
|
|
97
|
+
*
|
|
98
|
+
* `audit-privileged-write-unlogged` found 14 admin write paths that record
|
|
99
|
+
* nothing. These are the action values the ones being closed now need; the
|
|
100
|
+
* rest stay on the ratchet until each is given one deliberately.
|
|
101
|
+
*
|
|
102
|
+
* 🛑 Each is a SEPARATE value rather than a shared `admin_write`. The log's
|
|
103
|
+
* question is "what have admins done lately", and an undifferentiated value
|
|
104
|
+
* answers it with a row that says only "something". Filtering is the whole
|
|
105
|
+
* point of the collection.
|
|
106
|
+
*/
|
|
107
|
+
/** A role's permission set changed — the definition of who can do what. */
|
|
108
|
+
ROLE_CHANGE: "role_change",
|
|
109
|
+
/**
|
|
110
|
+
* A tax code's rate or HSN mapping changed.
|
|
111
|
+
*
|
|
112
|
+
* 🛑 The one STATUTORY thing an admin can edit, which is why
|
|
113
|
+
* `/admin/pricing` deliberately does not mirror it. A wrong rate here is a
|
|
114
|
+
* wrong return, so "who set this and when" is the question an assessment
|
|
115
|
+
* asks first.
|
|
116
|
+
*/
|
|
117
|
+
TAX_CODE_CHANGE: "tax_code_change",
|
|
118
|
+
/** Sessions forcibly revoked — the user is signed out everywhere, now. */
|
|
119
|
+
SESSION_REVOKE: "session_revoke",
|
|
120
|
+
/** A bulk operation over many users at once. */
|
|
121
|
+
USER_BULK_ACTION: "user_bulk_action",
|
|
122
|
+
/** A moderation report resolved, dismissed or actioned. */
|
|
123
|
+
MODERATION_DECISION: "moderation_decision",
|
|
124
|
+
/** A payment case claimed or resolved — money a buyer says did not arrive. */
|
|
125
|
+
PAYMENT_CASE_DECISION: "payment_case_decision",
|
|
126
|
+
/**
|
|
127
|
+
* A scammer profile edited.
|
|
128
|
+
*
|
|
129
|
+
* 🛑 Public-facing accusation. The profile names a person or a payment
|
|
130
|
+
* handle, so the wording and the status are reputational — and the one
|
|
131
|
+
* question that follows a complaint is who wrote it.
|
|
132
|
+
*/
|
|
133
|
+
SCAMMER_PROFILE_UPDATE: "scammer_profile_update",
|
|
45
134
|
};
|
|
46
135
|
export const ADMIN_AUDIT_LOG_FIELDS = {
|
|
47
136
|
ACTOR_UID: "actorUid",
|
|
@@ -23,6 +23,64 @@ export type UpdateProfileInput = {
|
|
|
23
23
|
export declare function updateUserProfile(userId: string, input: UpdateProfileInput): Promise<UserDocument>;
|
|
24
24
|
export declare function getUserProfile(userId: string): Promise<UserDocument | null>;
|
|
25
25
|
export declare function getUserSessions(userId: string): Promise<import("..").SessionDocument[]>;
|
|
26
|
+
/**
|
|
27
|
+
* What an account has actually DONE, counted from the collections that record
|
|
28
|
+
* it rather than read off `users/{uid}.stats`.
|
|
29
|
+
*
|
|
30
|
+
* 🛑 `users/{uid}.stats.*` HAS NO WRITER. Measured 2026-10-23: every occurrence
|
|
31
|
+
* of `stats.totalOrders` / `auctionsWon` / `itemsSold` / `reviewsCount` across
|
|
32
|
+
* both repos is a READ, and the only `stats.itemsSold` write in the codebase is
|
|
33
|
+
* `StoreRepository`'s, on the STORE document. So the stored numbers are
|
|
34
|
+
* whatever `users-seed-data.ts` hardcoded — the admin persona ships
|
|
35
|
+
* `{ totalOrders: 20, auctionsWon: 2, itemsSold: 200 }` — and a real signup gets
|
|
36
|
+
* `DEFAULT_USER_DATA.stats`, all zeros, which stay zero after twenty orders.
|
|
37
|
+
*
|
|
38
|
+
* A number nobody maintains is worse than no number: it is indistinguishable
|
|
39
|
+
* from a maintained one at every call site. These are counted live instead.
|
|
40
|
+
*
|
|
41
|
+
* ## Cost
|
|
42
|
+
*
|
|
43
|
+
* Three Firestore AGGREGATIONS, in parallel — billed at one read per 1000 index
|
|
44
|
+
* entries matched, so ~3 reads for any real account and flat as history grows.
|
|
45
|
+
* That is what makes this affordable on `GET /api/user/profile`, which the
|
|
46
|
+
* session hits on every page load. Never replace one with `findByUser(...).length`:
|
|
47
|
+
* that downloads the whole history to learn its size.
|
|
48
|
+
*
|
|
49
|
+
* ## Failure is `undefined`, never 0
|
|
50
|
+
*
|
|
51
|
+
* A failed count means "unknown", and 0 means "none" — Root Cause #72's rule.
|
|
52
|
+
* Callers render nothing for `undefined`, so a transient Firestore error hides
|
|
53
|
+
* a tile rather than telling a buyer with 30 orders that they have none.
|
|
54
|
+
*/
|
|
55
|
+
export interface BuyerActivityStats {
|
|
56
|
+
/** Orders this account placed, all lanes. */
|
|
57
|
+
totalOrders?: number;
|
|
58
|
+
/** Orders that came from winning (or buying out) an auction. */
|
|
59
|
+
auctionsWon?: number;
|
|
60
|
+
/** Reviews this account WROTE — the set `/user/reviews` lists. */
|
|
61
|
+
reviewsCount?: number;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* 🛑 React.cache-wrapped: `/api/user/profile` and the public profile page can
|
|
65
|
+
* both ask for the same uid inside one request, and three aggregations is a
|
|
66
|
+
* cost worth paying once.
|
|
67
|
+
*/
|
|
68
|
+
export declare const getBuyerActivityStats: (uid: string) => Promise<BuyerActivityStats>;
|
|
69
|
+
/**
|
|
70
|
+
* Buyer activity plus, for an account that owns a store, the one SELLER number
|
|
71
|
+
* that is genuinely maintained.
|
|
72
|
+
*
|
|
73
|
+
* `stores/{storeId}.stats.itemsSold` has real writers — `incrementItemsSold`
|
|
74
|
+
* from the fulfilment trigger and `setStats` from the nightly reconciliation —
|
|
75
|
+
* unlike its namesake on the user document. It is read here, from the store, so
|
|
76
|
+
* a seller's PUBLIC profile can keep showing it honestly.
|
|
77
|
+
*
|
|
78
|
+
* It deliberately does NOT reach the sidebar's own profile block, which is the
|
|
79
|
+
* buyer's view of their own account: see `AppLayoutShell`.
|
|
80
|
+
*/
|
|
81
|
+
export declare function getProfileStats(user: Pick<UserDocument, "uid" | "id" | "storeId">): Promise<BuyerActivityStats & {
|
|
82
|
+
itemsSold?: number;
|
|
83
|
+
}>;
|
|
26
84
|
/**
|
|
27
85
|
* Resolve a profile by slug, then document id, then Auth uid.
|
|
28
86
|
*
|
|
@@ -51,8 +109,18 @@ export declare function resolveProfileUser(identifier: string): Promise<UserDocu
|
|
|
51
109
|
* page + generateMetadata pair is memoised per argument list, so the second call
|
|
52
110
|
* is free. Note it caches the NARROW public projection, which is what both
|
|
53
111
|
* callers want; anything needing the whole document still goes to the repository.
|
|
112
|
+
*
|
|
113
|
+
* 🛑 `stats` is DERIVED by `getProfileStats`, not `user.stats`. The stored field
|
|
114
|
+
* has no writer and is seed fiction — see `getBuyerActivityStats`. It is derived
|
|
115
|
+
* here as well as on the session endpoint deliberately: fixing only the sidebar
|
|
116
|
+
* would have left a signed-in user reading real counts in the nav and seeded
|
|
117
|
+
* ones on their own public profile, which is a worse state than both being wrong.
|
|
54
118
|
*/
|
|
55
|
-
export declare const getPublicUserProfile: (userId: string) => Promise<Pick<UserDocument, "id" | "slug" | "displayName" | "photoURL" | "role" | "createdAt" | "storeId" | "storeSlug" | "publicProfile"
|
|
119
|
+
export declare const getPublicUserProfile: (userId: string) => Promise<(Pick<UserDocument, "id" | "slug" | "displayName" | "photoURL" | "role" | "createdAt" | "storeId" | "storeSlug" | "publicProfile"> & {
|
|
120
|
+
stats: BuyerActivityStats & {
|
|
121
|
+
itemsSold?: number;
|
|
122
|
+
};
|
|
123
|
+
}) | null>;
|
|
56
124
|
/** Fetch approved reviews for a store. storeId === storeSlug in this project. */
|
|
57
125
|
export declare function getSellerReviews(storeId: string): Promise<Review[]>;
|
|
58
126
|
export declare function getProfileStoreProducts(storeId: string): Promise<import("../../products").ProductDocument[]>;
|
|
@@ -12,6 +12,8 @@ import { sessionRepository } from "../repository/session.repository.js";
|
|
|
12
12
|
import { productRepository } from "../../products/repository/products.repository.js";
|
|
13
13
|
import { ProductStatusValues } from "../../products/schemas/index.js";
|
|
14
14
|
import { reviewRepository } from "../../reviews/repository/reviews.repository.js";
|
|
15
|
+
import { orderRepository } from "../../orders/repository/orders.repository.js";
|
|
16
|
+
import { storeRepository } from "../../stores/repository/store.repository.js";
|
|
15
17
|
export async function updateUserProfile(userId, input) {
|
|
16
18
|
const finalPhotoURL = await finalizeStagedMediaField(input.photoURL);
|
|
17
19
|
const data = finalPhotoURL !== undefined ? { ...input, photoURL: finalPhotoURL } : input;
|
|
@@ -23,6 +25,59 @@ export async function getUserProfile(userId) {
|
|
|
23
25
|
export async function getUserSessions(userId) {
|
|
24
26
|
return sessionRepository.findAllByUser(userId);
|
|
25
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* 🛑 React.cache-wrapped: `/api/user/profile` and the public profile page can
|
|
30
|
+
* both ask for the same uid inside one request, and three aggregations is a
|
|
31
|
+
* cost worth paying once.
|
|
32
|
+
*/
|
|
33
|
+
export const getBuyerActivityStats = cache(async function getBuyerActivityStats(uid) {
|
|
34
|
+
const route = "profile:buyer-activity-stats";
|
|
35
|
+
const [totalOrders, auctionsWon, reviewsCount] = await Promise.all([
|
|
36
|
+
safeRead(() => orderRepository.countForUser(uid), {
|
|
37
|
+
route,
|
|
38
|
+
key: "orders:total",
|
|
39
|
+
fallback: undefined,
|
|
40
|
+
}),
|
|
41
|
+
safeRead(() => orderRepository.countForUser(uid, "auction"), {
|
|
42
|
+
route,
|
|
43
|
+
key: "orders:auction",
|
|
44
|
+
fallback: undefined,
|
|
45
|
+
}),
|
|
46
|
+
safeRead(() => reviewRepository.countByUser(uid), {
|
|
47
|
+
route,
|
|
48
|
+
key: "reviews:written",
|
|
49
|
+
fallback: undefined,
|
|
50
|
+
}),
|
|
51
|
+
]);
|
|
52
|
+
return { totalOrders, auctionsWon, reviewsCount };
|
|
53
|
+
});
|
|
54
|
+
/**
|
|
55
|
+
* Buyer activity plus, for an account that owns a store, the one SELLER number
|
|
56
|
+
* that is genuinely maintained.
|
|
57
|
+
*
|
|
58
|
+
* `stores/{storeId}.stats.itemsSold` has real writers — `incrementItemsSold`
|
|
59
|
+
* from the fulfilment trigger and `setStats` from the nightly reconciliation —
|
|
60
|
+
* unlike its namesake on the user document. It is read here, from the store, so
|
|
61
|
+
* a seller's PUBLIC profile can keep showing it honestly.
|
|
62
|
+
*
|
|
63
|
+
* It deliberately does NOT reach the sidebar's own profile block, which is the
|
|
64
|
+
* buyer's view of their own account: see `AppLayoutShell`.
|
|
65
|
+
*/
|
|
66
|
+
export async function getProfileStats(user) {
|
|
67
|
+
const uid = user.uid ?? user.id;
|
|
68
|
+
const [activity, itemsSold] = await Promise.all([
|
|
69
|
+
getBuyerActivityStats(uid),
|
|
70
|
+
user.storeId
|
|
71
|
+
? safeRead(async () => (await storeRepository.findById(user.storeId))?.stats
|
|
72
|
+
?.itemsSold, {
|
|
73
|
+
route: "profile:store-items-sold",
|
|
74
|
+
key: "store:itemsSold",
|
|
75
|
+
fallback: undefined,
|
|
76
|
+
})
|
|
77
|
+
: Promise.resolve(undefined),
|
|
78
|
+
]);
|
|
79
|
+
return { ...activity, itemsSold };
|
|
80
|
+
}
|
|
26
81
|
/**
|
|
27
82
|
* Resolve a profile by slug, then document id, then Auth uid.
|
|
28
83
|
*
|
|
@@ -59,6 +114,12 @@ export async function resolveProfileUser(identifier) {
|
|
|
59
114
|
* page + generateMetadata pair is memoised per argument list, so the second call
|
|
60
115
|
* is free. Note it caches the NARROW public projection, which is what both
|
|
61
116
|
* callers want; anything needing the whole document still goes to the repository.
|
|
117
|
+
*
|
|
118
|
+
* 🛑 `stats` is DERIVED by `getProfileStats`, not `user.stats`. The stored field
|
|
119
|
+
* has no writer and is seed fiction — see `getBuyerActivityStats`. It is derived
|
|
120
|
+
* here as well as on the session endpoint deliberately: fixing only the sidebar
|
|
121
|
+
* would have left a signed-in user reading real counts in the nav and seeded
|
|
122
|
+
* ones on their own public profile, which is a worse state than both being wrong.
|
|
62
123
|
*/
|
|
63
124
|
export const getPublicUserProfile = cache(async function getPublicUserProfile(userId) {
|
|
64
125
|
const user = await resolveProfileUser(userId);
|
|
@@ -74,7 +135,7 @@ export const getPublicUserProfile = cache(async function getPublicUserProfile(us
|
|
|
74
135
|
storeId: user.storeId,
|
|
75
136
|
storeSlug: user.storeSlug,
|
|
76
137
|
publicProfile: user.publicProfile,
|
|
77
|
-
stats: user
|
|
138
|
+
stats: await getProfileStats(user),
|
|
78
139
|
};
|
|
79
140
|
});
|
|
80
141
|
/** Fetch approved reviews for a store. storeId === storeSlug in this project. */
|
|
@@ -344,6 +344,19 @@ export const ROUTE_PERMISSION_MAP = {
|
|
|
344
344
|
// Payment protection — admin-only, see the permission union's own 🛑 note.
|
|
345
345
|
"/admin/money-cases": "admin:payment-cases:read",
|
|
346
346
|
"/admin/protection-claims": "admin:protection-claims:read",
|
|
347
|
+
/*
|
|
348
|
+
* Phase 7 invoicing — the GSTR-1 draft export.
|
|
349
|
+
*
|
|
350
|
+
* 🛑 `settings:write` rather than a new permission, and that is a judgement
|
|
351
|
+
* worth stating. The page exports the company's tax position for a quarter
|
|
352
|
+
* plus every buyer's place of supply; the set of people who should see that
|
|
353
|
+
* is the set who can already change the GSTIN and the fee schedule, which is
|
|
354
|
+
* exactly what `settings:write` names. Minting
|
|
355
|
+
* `admin:invoicing:read` would add a permission with one route and one
|
|
356
|
+
* holder — a distinction with no decision behind it, which is how a
|
|
357
|
+
* permission union becomes unreadable.
|
|
358
|
+
*/
|
|
359
|
+
"/admin/invoicing": "admin:settings:write",
|
|
347
360
|
};
|
|
348
361
|
/**
|
|
349
362
|
* Every capability, as a runtime value.
|
|
@@ -126,12 +126,27 @@ export interface UserDocument extends BaseDocument {
|
|
|
126
126
|
isVacationMode?: boolean;
|
|
127
127
|
vacationMessage?: string;
|
|
128
128
|
};
|
|
129
|
+
/**
|
|
130
|
+
* 🛑 LEGACY AND UNMAINTAINED — do not read these to answer "how many X does
|
|
131
|
+
* this account have". Nothing in either repo writes them: every occurrence
|
|
132
|
+
* across the codebase is a read, and the only `stats.itemsSold` write is
|
|
133
|
+
* `StoreRepository`'s, on the STORE document. The values present in Firestore
|
|
134
|
+
* today are seed literals.
|
|
135
|
+
*
|
|
136
|
+
* `getBuyerActivityStats` / `getProfileStats` count the real collections, and
|
|
137
|
+
* every surface that showed a number now goes through them.
|
|
138
|
+
*
|
|
139
|
+
* Kept on the schema because the documents still carry the field and a
|
|
140
|
+
* migration to strip it would buy nothing. `rating` was REMOVED outright: it
|
|
141
|
+
* had no writer AND no buyer-rating concept behind it, so its one reader
|
|
142
|
+
* (`/admin/users/[id]`) rendered a tile guarded on a value that could never
|
|
143
|
+
* be set.
|
|
144
|
+
*/
|
|
129
145
|
stats?: {
|
|
130
146
|
totalOrders: number;
|
|
131
147
|
auctionsWon: number;
|
|
132
148
|
itemsSold: number;
|
|
133
149
|
reviewsCount: number;
|
|
134
|
-
rating?: number;
|
|
135
150
|
};
|
|
136
151
|
metadata?: {
|
|
137
152
|
lastSignInTime?: Date;
|
|
@@ -334,7 +349,6 @@ export declare const USER_FIELDS: {
|
|
|
334
349
|
readonly AUCTIONS_WON: "stats.auctionsWon";
|
|
335
350
|
readonly ITEMS_SOLD: "stats.itemsSold";
|
|
336
351
|
readonly REVIEWS_COUNT: "stats.reviewsCount";
|
|
337
|
-
readonly RATING: "stats.rating";
|
|
338
352
|
};
|
|
339
353
|
readonly METADATA: "metadata";
|
|
340
354
|
readonly META: {
|
|
@@ -150,7 +150,8 @@ export const USER_FIELDS = {
|
|
|
150
150
|
AUCTIONS_WON: "stats.auctionsWon",
|
|
151
151
|
ITEMS_SOLD: "stats.itemsSold",
|
|
152
152
|
REVIEWS_COUNT: "stats.reviewsCount",
|
|
153
|
-
RATING
|
|
153
|
+
// `RATING` removed — `stats.rating` had no writer and no buyer-rating
|
|
154
|
+
// concept behind it anywhere in the codebase.
|
|
154
155
|
},
|
|
155
156
|
METADATA: "metadata",
|
|
156
157
|
META: {
|
|
@@ -9,6 +9,7 @@ export declare const createBlogPostSchema: z.ZodObject<{
|
|
|
9
9
|
category: z.ZodEnum<["news", "tips", "guides", "updates", "community"]>;
|
|
10
10
|
tags: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
11
11
|
isFeatured: z.ZodDefault<z.ZodBoolean>;
|
|
12
|
+
isPinned: z.ZodDefault<z.ZodBoolean>;
|
|
12
13
|
status: z.ZodDefault<z.ZodEnum<["draft", "published", "archived"]>>;
|
|
13
14
|
coverImage: z.ZodOptional<z.ZodNullable<z.ZodUnion<[z.ZodObject<{
|
|
14
15
|
url: z.ZodEffects<z.ZodString, string, string>;
|
|
@@ -78,6 +79,7 @@ export declare const createBlogPostSchema: z.ZodObject<{
|
|
|
78
79
|
isFeatured: boolean;
|
|
79
80
|
excerpt: string;
|
|
80
81
|
readTimeMinutes: number;
|
|
82
|
+
isPinned: boolean;
|
|
81
83
|
additionalImages: {
|
|
82
84
|
type: "video" | "image" | "file";
|
|
83
85
|
url: string;
|
|
@@ -124,6 +126,7 @@ export declare const createBlogPostSchema: z.ZodObject<{
|
|
|
124
126
|
authorId?: string | undefined;
|
|
125
127
|
authorName?: string | undefined;
|
|
126
128
|
readTimeMinutes?: number | undefined;
|
|
129
|
+
isPinned?: boolean | undefined;
|
|
127
130
|
additionalImages?: {
|
|
128
131
|
type: "video" | "image" | "file";
|
|
129
132
|
url: string;
|
|
@@ -148,6 +151,7 @@ export declare const updateBlogPostSchema: z.ZodObject<{
|
|
|
148
151
|
category: z.ZodOptional<z.ZodEnum<["news", "tips", "guides", "updates", "community"]>>;
|
|
149
152
|
tags: z.ZodOptional<z.ZodDefault<z.ZodArray<z.ZodString, "many">>>;
|
|
150
153
|
isFeatured: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
|
|
154
|
+
isPinned: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
|
|
151
155
|
status: z.ZodOptional<z.ZodDefault<z.ZodEnum<["draft", "published", "archived"]>>>;
|
|
152
156
|
coverImage: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodUnion<[z.ZodObject<{
|
|
153
157
|
url: z.ZodEffects<z.ZodString, string, string>;
|
|
@@ -229,6 +233,7 @@ export declare const updateBlogPostSchema: z.ZodObject<{
|
|
|
229
233
|
authorId?: string | undefined;
|
|
230
234
|
authorName?: string | undefined;
|
|
231
235
|
readTimeMinutes?: number | undefined;
|
|
236
|
+
isPinned?: boolean | undefined;
|
|
232
237
|
additionalImages?: {
|
|
233
238
|
type: "video" | "image" | "file";
|
|
234
239
|
url: string;
|
|
@@ -263,6 +268,7 @@ export declare const updateBlogPostSchema: z.ZodObject<{
|
|
|
263
268
|
authorId?: string | undefined;
|
|
264
269
|
authorName?: string | undefined;
|
|
265
270
|
readTimeMinutes?: number | undefined;
|
|
271
|
+
isPinned?: boolean | undefined;
|
|
266
272
|
additionalImages?: {
|
|
267
273
|
type: "video" | "image" | "file";
|
|
268
274
|
url: string;
|