@mohasinac/appkit 4.53.2 → 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.
Files changed (348) hide show
  1. package/dist/.build-stamp.json +3 -3
  2. package/dist/_internal/server/features/auth/capabilities.js +7 -5
  3. package/dist/_internal/server/features/checkout/actions.d.ts +22 -6
  4. package/dist/_internal/server/features/checkout/actions.js +96 -51
  5. package/dist/_internal/server/features/checkout/index.d.ts +1 -1
  6. package/dist/_internal/server/features/checkout/index.js +1 -1
  7. package/dist/_internal/server/features/checkout/supplier-identity.js +28 -6
  8. package/dist/_internal/server/features/orders/adapters.js +1 -3
  9. package/dist/_internal/server/features/products/listing-tab-counts.js +81 -25
  10. package/dist/_internal/server/features/search/index-build/sources.js +43 -2
  11. package/dist/_internal/server/features/site-settings/adapters.js +1 -1
  12. package/dist/_internal/server/features/stores/adapters.d.ts +1 -1
  13. package/dist/_internal/server/features/stores/adapters.js +0 -1
  14. package/dist/_internal/server/jobs/core/analyticsAlertEvaluate.js +2 -5
  15. package/dist/_internal/server/jobs/core/jobRunners.js +0 -10
  16. package/dist/_internal/server/jobs/core/onOrderCreate.js +10 -104
  17. package/dist/_internal/server/jobs/core/onOrderStatusChange.d.ts +0 -2
  18. package/dist/_internal/server/jobs/core/onOrderStatusChange.js +0 -1
  19. package/dist/_internal/server/jobs/core/onScamReportCreate.js +0 -1
  20. package/dist/_internal/server/jobs/core/onScamReportRejected.js +0 -1
  21. package/dist/_internal/server/jobs/core/onScamReportVerified.js +0 -1
  22. package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +0 -1
  23. package/dist/_internal/server/jobs/core/pendingOrderTimeout.js +0 -1
  24. package/dist/_internal/server/notifications/channel-health.d.ts +7 -3
  25. package/dist/_internal/server/notifications/channel-health.js +2 -2
  26. package/dist/_internal/server/notifications/send-guard.d.ts +1 -1
  27. package/dist/_internal/server/notifications/send-guard.js +2 -4
  28. package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
  29. package/dist/_internal/shared/actions/action-registry.js +128 -28
  30. package/dist/_internal/shared/checkout/order-math.d.ts +1 -1
  31. package/dist/_internal/shared/checkout/order-math.js +1 -1
  32. package/dist/_internal/shared/features/categories/bundle-copy.d.ts +1 -1
  33. package/dist/_internal/shared/features/checkout/config.d.ts +0 -2
  34. package/dist/_internal/shared/features/checkout/config.js +0 -2
  35. package/dist/_internal/shared/features/messaging/config.d.ts +7 -5
  36. package/dist/_internal/shared/features/messaging/config.js +1 -4
  37. package/dist/_internal/shared/features/site-settings/fees.d.ts +0 -2
  38. package/dist/_internal/shared/features/site-settings/fees.js +0 -2
  39. package/dist/_internal/shared/features/site-settings/supplier-of-record.d.ts +56 -0
  40. package/dist/_internal/shared/features/site-settings/supplier-of-record.js +57 -0
  41. package/dist/_internal/shared/fees/calculator.d.ts +0 -8
  42. package/dist/_internal/shared/fees/calculator.js +0 -7
  43. package/dist/_internal/shared/listing-types/tiers.d.ts +94 -0
  44. package/dist/_internal/shared/listing-types/tiers.js +150 -0
  45. package/dist/cli/index.js +0 -2
  46. package/dist/client.d.ts +25 -4
  47. package/dist/client.js +36 -5
  48. package/dist/constants/api-endpoints.d.ts +21 -15
  49. package/dist/constants/api-endpoints.js +7 -8
  50. package/dist/constants/field-names.d.ts +1 -0
  51. package/dist/constants/field-names.js +1 -0
  52. package/dist/constants/notification-types.d.ts +1 -1
  53. package/dist/constants/notification-types.js +1 -1
  54. package/dist/core/integration-keys.d.ts +5 -5
  55. package/dist/core/integration-keys.js +21 -10
  56. package/dist/features/about/components/FeesView.js +0 -6
  57. package/dist/features/about/components/GuidesHubView.js +15 -2
  58. package/dist/features/account/components/NotificationPreferencesPanel.js +3 -4
  59. package/dist/features/account/components/UserOrdersView.js +26 -7
  60. package/dist/features/account/types/index.d.ts +0 -2
  61. package/dist/features/addresses/utils/postal-autofill.d.ts +39 -0
  62. package/dist/features/addresses/utils/postal-autofill.js +54 -0
  63. package/dist/features/admin/actions/notification-actions.d.ts +2 -8
  64. package/dist/features/admin/actions/notification-actions.js +9 -104
  65. package/dist/features/admin/components/AdminGuideHubView.js +1 -8
  66. package/dist/features/admin/components/AdminOrderEditorView.d.ts +1 -1
  67. package/dist/features/admin/components/AdminOrdersView.js +0 -2
  68. package/dist/features/admin/components/AdminSectionsView.js +3 -2
  69. package/dist/features/admin/components/AdminSiteSettingsView.js +22 -68
  70. package/dist/features/admin/components/AdminStoreEditorView.js +72 -34
  71. package/dist/features/admin/components/OwnerQuickActions.d.ts +29 -0
  72. package/dist/features/admin/components/OwnerQuickActions.js +142 -0
  73. package/dist/features/admin/components/sections/adminSectionsTypes.js +13 -4
  74. package/dist/features/admin/components/sections/icon-options.d.ts +21 -0
  75. package/dist/features/admin/components/sections/icon-options.js +23 -0
  76. package/dist/features/admin/components/sections/sectionTemplates.js +4 -1
  77. package/dist/features/admin/constants/site-settings-tabs.d.ts +7 -12
  78. package/dist/features/admin/constants/site-settings-tabs.js +6 -12
  79. package/dist/features/admin/repository/site-settings.repository.js +1 -1
  80. package/dist/features/admin/schemas/admin-editor-forms.d.ts +1 -1
  81. package/dist/features/admin/schemas/admin-editor-forms.js +4 -1
  82. package/dist/features/admin/schemas/admin-user-form.d.ts +0 -61
  83. package/dist/features/admin/schemas/admin-user-form.js +3 -44
  84. package/dist/features/admin/schemas/firestore.d.ts +28 -54
  85. package/dist/features/admin/schemas/firestore.js +40 -18
  86. package/dist/features/auctions/components/AuctionDetailPageView.js +4 -3
  87. package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +11 -1
  88. package/dist/features/auctions/components/MarketplaceAuctionCard.js +9 -2
  89. package/dist/features/auth/checkout-value-otp.d.ts +1 -1
  90. package/dist/features/auth/checkout-value-otp.js +1 -1
  91. package/dist/features/auth/permissions/constants.d.ts +29 -2
  92. package/dist/features/auth/permissions/constants.js +67 -1
  93. package/dist/features/blog/components/BlogFeaturedCard.d.ts +11 -1
  94. package/dist/features/blog/components/BlogFeaturedCard.js +9 -2
  95. package/dist/features/cart/components/CartDrawer.js +3 -2
  96. package/dist/features/cart/components/CartGroupLineRow.js +2 -1
  97. package/dist/features/cart/components/CartPriceBreakdown.d.ts +0 -2
  98. package/dist/features/cart/components/CartPriceBreakdown.js +1 -1
  99. package/dist/features/cart/components/StoreAddonsPicker.d.ts +2 -5
  100. package/dist/features/cart/components/StoreAddonsPicker.js +4 -5
  101. package/dist/features/cart/hooks/useAddToCart.js +10 -5
  102. package/dist/features/cart/repository/cart.repository.js +1 -2
  103. package/dist/features/cart/schemas/firestore.d.ts +1 -2
  104. package/dist/features/cart/utils/pending-ops.d.ts +11 -1
  105. package/dist/features/cart/utils/pending-ops.js +14 -2
  106. package/dist/features/categories/components/BrandDetailPageView.js +2 -1
  107. package/dist/features/categories/components/BundleDetailView.js +2 -1
  108. package/dist/features/categories/components/CategoryDetailPageView.js +2 -1
  109. package/dist/features/categories/components/CategoryGrid.d.ts +11 -1
  110. package/dist/features/categories/components/CategoryGrid.js +9 -2
  111. package/dist/features/checkout/actions/checkout-value-otp-actions.d.ts +10 -5
  112. package/dist/features/checkout/actions/checkout-value-otp-actions.js +2 -88
  113. package/dist/features/classified/components/ClassifiedDetailPageView.js +2 -1
  114. package/dist/features/digital-codes/components/DigitalCodeDetailPageView.js +2 -1
  115. package/dist/features/events/components/EventCard.d.ts +11 -1
  116. package/dist/features/events/components/EventCard.js +9 -2
  117. package/dist/features/grouped/components/GroupedListingDetailView.js +3 -1
  118. package/dist/features/homepage/components/CTABannerSection.d.ts +3 -1
  119. package/dist/features/homepage/components/CTABannerSection.js +6 -3
  120. package/dist/features/homepage/components/HeroCarousel.js +8 -6
  121. package/dist/features/homepage/components/MarketplaceHomepageView.js +33 -7
  122. package/dist/features/homepage/components/SectionCarousel.js +13 -5
  123. package/dist/features/homepage/components/SecurityHighlightsSection.d.ts +8 -3
  124. package/dist/features/homepage/components/SecurityHighlightsSection.js +2 -2
  125. package/dist/features/homepage/components/StatsCounterSection.d.ts +9 -4
  126. package/dist/features/homepage/components/StatsCounterSection.js +2 -2
  127. package/dist/features/homepage/components/TestimonialsCarousel.js +1 -1
  128. package/dist/features/homepage/components/TrustFeaturesSection.d.ts +18 -4
  129. package/dist/features/homepage/components/TrustFeaturesSection.js +5 -5
  130. package/dist/features/homepage/components/WelcomeSection.d.ts +13 -2
  131. package/dist/features/homepage/components/WelcomeSection.js +3 -3
  132. package/dist/features/homepage/components/WhatsAppCommunitySection.d.ts +28 -0
  133. package/dist/features/homepage/components/WhatsAppCommunitySection.js +42 -6
  134. package/dist/features/homepage/components/WhatsAppGlyph.d.ts +20 -0
  135. package/dist/features/homepage/components/WhatsAppGlyph.js +20 -0
  136. package/dist/features/homepage/constants/hero-carousel-styles.d.ts +8 -6
  137. package/dist/features/homepage/constants/hero-carousel-styles.js +8 -6
  138. package/dist/features/homepage/constants/section-copy.d.ts +12 -10
  139. package/dist/features/homepage/constants/section-copy.js +28 -6
  140. package/dist/features/homepage/constants/stat-icons.d.ts +12 -0
  141. package/dist/features/homepage/constants/stat-icons.js +17 -0
  142. package/dist/features/homepage/constants/trust-icon-aliases.d.ts +8 -0
  143. package/dist/features/homepage/constants/trust-icon-aliases.js +75 -0
  144. package/dist/features/homepage/lib/section-defaults.d.ts +16 -1
  145. package/dist/features/homepage/lib/section-defaults.js +24 -4
  146. package/dist/features/homepage/lib/section-renderer.js +48 -8
  147. package/dist/features/homepage/schemas/firestore.d.ts +18 -1
  148. package/dist/features/layout/AppLayoutShell.js +2 -1
  149. package/dist/features/layout/BottomActions.d.ts +1 -0
  150. package/dist/features/layout/BottomActions.js +330 -0
  151. package/dist/features/layout/BottomChrome.d.ts +45 -0
  152. package/dist/features/layout/BottomChrome.js +5 -17
  153. package/dist/features/layout/SideActionDock.js +36 -13
  154. package/dist/features/layout/index.d.ts +2 -7
  155. package/dist/features/layout/index.js +7 -7
  156. package/dist/features/layout/useIsDesktop.d.ts +36 -0
  157. package/dist/features/layout/useIsDesktop.js +48 -0
  158. package/dist/features/live/components/LiveItemDetailPageView.js +2 -1
  159. package/dist/features/orders/actions/refund-actions.js +0 -1
  160. package/dist/features/orders/components/OrderAddonBadges.d.ts +1 -3
  161. package/dist/features/orders/components/OrderAddonBadges.js +3 -4
  162. package/dist/features/orders/components/OrderPaymentSummary.js +15 -2
  163. package/dist/features/orders/components/YourPurchaseStrip.d.ts +24 -0
  164. package/dist/features/orders/components/YourPurchaseStrip.js +77 -0
  165. package/dist/features/orders/components/index.d.ts +2 -1
  166. package/dist/features/orders/components/index.js +1 -1
  167. package/dist/features/orders/repository/orders.repository.d.ts +0 -8
  168. package/dist/features/orders/repository/orders.repository.js +0 -2
  169. package/dist/features/orders/schemas/firestore.d.ts +17 -9
  170. package/dist/features/orders/types/index.d.ts +2 -5
  171. package/dist/features/orders/utils/order-announcement-message.d.ts +18 -0
  172. package/dist/features/orders/utils/order-announcement-message.js +16 -0
  173. package/dist/features/orders/utils/payment-proof-message.d.ts +20 -0
  174. package/dist/features/orders/utils/payment-proof-message.js +17 -0
  175. package/dist/features/parts/components/PartDetailPageView.js +96 -1
  176. package/dist/features/parts/schemas/firestore.d.ts +247 -0
  177. package/dist/features/parts/schemas/firestore.js +6 -6
  178. package/dist/features/pre-orders/components/MarketplacePreorderCard.d.ts +11 -1
  179. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +10 -3
  180. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +4 -3
  181. package/dist/features/products/api/[id]/route.js +8 -1
  182. package/dist/features/products/api/route.js +16 -4
  183. package/dist/features/products/components/AvailabilityScopeHint.js +1 -1
  184. package/dist/features/products/components/InteractiveProductCard.d.ts +7 -1
  185. package/dist/features/products/components/InteractiveProductCard.js +16 -4
  186. package/dist/features/products/components/MarketplaceBundleCard.d.ts +11 -1
  187. package/dist/features/products/components/MarketplaceBundleCard.js +9 -2
  188. package/dist/features/products/components/MarketplacePrizeDrawCard.d.ts +11 -1
  189. package/dist/features/products/components/MarketplacePrizeDrawCard.js +9 -2
  190. package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -1
  191. package/dist/features/products/components/ProductDetailPageView.js +27 -2
  192. package/dist/features/products/components/ProductGrid.d.ts +14 -1
  193. package/dist/features/products/components/ProductGrid.js +22 -5
  194. package/dist/features/products/components/ProductsIndexListing.js +2 -2
  195. package/dist/features/reviews/api/[id]/route.js +83 -23
  196. package/dist/features/reviews/components/PurchaseReviewAffordance.d.ts +6 -0
  197. package/dist/features/reviews/components/PurchaseReviewAffordance.js +42 -0
  198. package/dist/features/reviews/components/ReviewFormDrawer.d.ts +34 -0
  199. package/dist/features/reviews/components/ReviewFormDrawer.js +127 -0
  200. package/dist/features/reviews/components/index.d.ts +4 -0
  201. package/dist/features/reviews/components/index.js +2 -0
  202. package/dist/features/scams/schemas/index.d.ts +10 -10
  203. package/dist/features/search/action-index/settings-entries.js +0 -9
  204. package/dist/features/seller/actions/seller-actions.d.ts +1 -1
  205. package/dist/features/seller/actions/seller-actions.js +49 -3
  206. package/dist/features/seller/components/SellerPayoutSettingsView.js +30 -2
  207. package/dist/features/seller/components/SellerProductShell.d.ts +17 -1
  208. package/dist/features/seller/hooks/useStoreListingEntitlements.d.ts +8 -0
  209. package/dist/features/seller/hooks/useStoreListingEntitlements.js +70 -0
  210. package/dist/features/store-extensions/repository/store-extensions.repositories.d.ts +1 -6
  211. package/dist/features/store-extensions/repository/store-extensions.repositories.js +1 -10
  212. package/dist/features/store-extensions/schemas/firestore.d.ts +1 -17
  213. package/dist/features/store-extensions/schemas/firestore.js +0 -10
  214. package/dist/features/stores/components/InteractiveStoreCard.d.ts +11 -1
  215. package/dist/features/stores/components/InteractiveStoreCard.js +9 -2
  216. package/dist/features/stores/components/StoreCapabilitiesGuideView.js +0 -1
  217. package/dist/features/stores/components/StoreGuideHubView.js +2 -8
  218. package/dist/features/stores/components/StoreSettingsGuideView.js +2 -6
  219. package/dist/features/stores/components/index.d.ts +0 -2
  220. package/dist/features/stores/components/index.js +0 -1
  221. package/dist/features/stores/repository/store.repository.d.ts +1 -26
  222. package/dist/features/stores/repository/store.repository.js +5 -60
  223. package/dist/features/stores/schemas/firestore.d.ts +6 -25
  224. package/dist/features/stores/schemas/firestore.js +6 -3
  225. package/dist/features/stores/schemas/index.d.ts +1 -87
  226. package/dist/features/stores/schemas/index.js +10 -15
  227. package/dist/features/tester/seed-data/authored/admin__site-system.js +0 -48
  228. package/dist/features/tester/seed-data/authored/buying__buying-checkout.js +0 -40
  229. package/dist/features/tester/seed-data/authored/selling__quick-add-minimum-details.js +0 -16
  230. package/dist/features/tester/seed-data/authored/selling__seller-guide.js +1 -1
  231. package/dist/features/tester/seed-data/authored/selling__seller-marketing-extras.js +0 -79
  232. package/dist/features/tester/seed-data/authored/selling__seller-orders.js +1 -1
  233. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +415 -69
  234. package/dist/index.d.ts +20 -32
  235. package/dist/index.js +34 -43
  236. package/dist/next/routing/route-map.d.ts +2 -8
  237. package/dist/next/routing/route-map.js +21 -4
  238. package/dist/providers/db-firebase/base.repository.d.ts +1 -1
  239. package/dist/providers/db-firebase/base.repository.js +1 -1
  240. package/dist/providers/payment-razorpay/index.d.ts +125 -0
  241. package/dist/providers/payment-razorpay/index.js +232 -0
  242. package/dist/providers/payment-razorpay/signature.d.ts +53 -0
  243. package/dist/providers/payment-razorpay/signature.js +71 -0
  244. package/dist/providers/shipping-shiprocket/index.d.ts +98 -0
  245. package/dist/providers/shipping-shiprocket/index.js +356 -0
  246. package/dist/providers.d.ts +3 -0
  247. package/dist/providers.js +3 -0
  248. package/dist/react/hooks/useCanSeePrices.d.ts +0 -27
  249. package/dist/react/hooks/useCanSeePrices.js +25 -0
  250. package/dist/repositories/index.d.ts +1 -1
  251. package/dist/repositories/index.js +1 -1
  252. package/dist/schemas/registry.d.ts +10 -115
  253. package/dist/schemas/registry.js +1 -2
  254. package/dist/security/pii-encrypt.js +1 -1
  255. package/dist/seed/_helpers/category-forest.js +27 -0
  256. package/dist/seed/_helpers/category-parts-glossary-map.js +1816 -86
  257. package/dist/seed/_helpers/category-parts.d.ts +1 -1
  258. package/dist/seed/_helpers/category-parts.js +13412 -3020
  259. package/dist/seed/carousel-slides-seed-data.js +47 -10
  260. package/dist/seed/categories-seed-data.js +48 -6
  261. package/dist/seed/faq-seed-data.js +2 -2
  262. package/dist/seed/homepage-sections-seed-data.js +286 -54
  263. package/dist/seed/index.d.ts +1 -1
  264. package/dist/seed/index.js +1 -1
  265. package/dist/seed/manifest.d.ts +1 -1
  266. package/dist/seed/manifest.js +1 -2
  267. package/dist/seed/model-composition-seed-data.js +6 -8
  268. package/dist/seed/part-glossary/chunk0.d.ts +9 -0
  269. package/dist/seed/part-glossary/chunk0.js +35448 -0
  270. package/dist/seed/part-glossary/chunk1.d.ts +9 -0
  271. package/dist/seed/part-glossary/chunk1.js +40494 -0
  272. package/dist/seed/part-glossary/chunk2.d.ts +9 -0
  273. package/dist/seed/part-glossary/chunk2.js +51242 -0
  274. package/dist/seed/part-glossary/chunk3.d.ts +9 -0
  275. package/dist/seed/part-glossary/chunk3.js +53337 -0
  276. package/dist/seed/part-glossary/chunk4.d.ts +9 -0
  277. package/dist/seed/part-glossary/chunk4.js +51454 -0
  278. package/dist/seed/part-glossary-seed-data.d.ts +1 -1
  279. package/dist/seed/part-glossary-seed-data.js +23 -47483
  280. package/dist/seed/site-settings-seed-data.js +34 -35
  281. package/dist/seed/store-extensions-seed-data.d.ts +1 -2
  282. package/dist/seed/store-extensions-seed-data.js +1 -23
  283. package/dist/seed/stores-seed-data.js +0 -1
  284. package/dist/server-entry.d.ts +1 -1
  285. package/dist/server-entry.js +1 -1
  286. package/dist/server.d.ts +8 -10
  287. package/dist/server.js +16 -22
  288. package/dist/styles.css +392 -43
  289. package/dist/tailwind-utilities.css +1 -1
  290. package/dist/tokens/themes/default-dark.js +1 -1
  291. package/dist/tokens/themes/default-light.js +2 -1
  292. package/dist/tokens/tokens.css +6 -2
  293. package/dist/ui/components/Button.d.ts +11 -0
  294. package/dist/ui/components/Button.js +11 -0
  295. package/dist/ui/components/Button.style.css +29 -0
  296. package/dist/ui/components/CarouselNav.d.ts +57 -0
  297. package/dist/ui/components/CarouselNav.js +25 -0
  298. package/dist/ui/components/CarouselNav.style.css +265 -0
  299. package/dist/ui/components/GatedPrice.js +30 -3
  300. package/dist/ui/components/GatedPrice.style.css +43 -40
  301. package/dist/ui/components/HorizontalScroller.d.ts +12 -1
  302. package/dist/ui/components/HorizontalScroller.js +43 -3
  303. package/dist/ui/components/ImageMosaic.d.ts +8 -1
  304. package/dist/ui/components/ImageMosaic.js +3 -2
  305. package/dist/ui/components/ImageMosaic.style.css +22 -0
  306. package/dist/ui/components/Layout.style.css +6 -0
  307. package/dist/ui/components/Semantic.d.ts +3 -2
  308. package/dist/ui/components/Semantic.js +1 -0
  309. package/dist/ui/components/Typography.d.ts +2 -0
  310. package/dist/ui/components/Typography.js +2 -0
  311. package/dist/ui/components/Typography.style.css +19 -0
  312. package/dist/ui/components/index.style.css +1 -0
  313. package/dist/ui/index.d.ts +3 -1
  314. package/dist/ui/index.js +4 -0
  315. package/package.json +3 -2
  316. package/dist/_internal/server/jobs/core/whatsappCatalogImport.d.ts +0 -27
  317. package/dist/_internal/server/jobs/core/whatsappCatalogImport.js +0 -172
  318. package/dist/_internal/server/jobs/core/whatsappNotify.d.ts +0 -35
  319. package/dist/_internal/server/jobs/core/whatsappNotify.js +0 -140
  320. package/dist/features/admin/components/AdminWhatsAppGuideView.d.ts +0 -2
  321. package/dist/features/admin/components/AdminWhatsAppGuideView.js +0 -35
  322. package/dist/features/orders/components/MarketplaceOrderCard.d.ts +0 -36
  323. package/dist/features/orders/components/MarketplaceOrderCard.js +0 -57
  324. package/dist/features/stores/components/StoreWhatsAppGuideView.d.ts +0 -3
  325. package/dist/features/stores/components/StoreWhatsAppGuideView.js +0 -12
  326. package/dist/features/whatsapp-bot/api/send-status/route.d.ts +0 -12
  327. package/dist/features/whatsapp-bot/api/send-status/route.js +0 -38
  328. package/dist/features/whatsapp-bot/api/webhook/route.d.ts +0 -12
  329. package/dist/features/whatsapp-bot/api/webhook/route.js +0 -43
  330. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.d.ts +0 -6
  331. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +0 -270
  332. package/dist/features/whatsapp-bot/components/WhatsAppChatButton.d.ts +0 -9
  333. package/dist/features/whatsapp-bot/components/WhatsAppChatButton.js +0 -7
  334. package/dist/features/whatsapp-bot/components/index.d.ts +0 -3
  335. package/dist/features/whatsapp-bot/components/index.js +0 -2
  336. package/dist/features/whatsapp-bot/helpers/payment-proof-message.d.ts +0 -14
  337. package/dist/features/whatsapp-bot/helpers/payment-proof-message.js +0 -17
  338. package/dist/features/whatsapp-bot/helpers/whatsapp.d.ts +0 -52
  339. package/dist/features/whatsapp-bot/helpers/whatsapp.js +0 -283
  340. package/dist/features/whatsapp-bot/index.d.ts +0 -3
  341. package/dist/features/whatsapp-bot/index.js +0 -3
  342. package/dist/features/whatsapp-bot/manifest.d.ts +0 -2
  343. package/dist/features/whatsapp-bot/manifest.js +0 -13
  344. package/dist/features/whatsapp-bot/messages/en.json +0 -7
  345. package/dist/features/whatsapp-bot/server.d.ts +0 -7
  346. package/dist/features/whatsapp-bot/server.js +0 -7
  347. package/dist/features/whatsapp-bot/types/index.d.ts +0 -126
  348. package/dist/features/whatsapp-bot/types/index.js +0 -1
@@ -182,16 +182,6 @@ export const DEFAULT_ITEM_REQUEST_DATA = {
182
182
  replies: [],
183
183
  replyCount: 0,
184
184
  };
185
- export const STORE_WHATSAPP_CONFIG_COLLECTION = "storeWhatsAppConfig";
186
- export const STORE_WHATSAPP_CONFIG_INDEXED_FIELDS = [
187
- "storeId",
188
- "isConnected",
189
- "isPaid",
190
- ];
191
- export const DEFAULT_STORE_WHATSAPP_CONFIG_DATA = {
192
- isConnected: false,
193
- isPaid: false,
194
- };
195
185
  export const STORE_GOOGLE_CONFIG_COLLECTION = "storeGoogleConfig";
196
186
  export const STORE_GOOGLE_CONFIG_INDEXED_FIELDS = [
197
187
  "storeId",
@@ -12,5 +12,15 @@ export interface InteractiveStoreCardProps {
12
12
  visitStore?: string;
13
13
  };
14
14
  className?: string;
15
+ /**
16
+ * Owner-only pencil / clone / bin, for an admin or whoever owns this record.
17
+ * Pass `<OwnerQuickActions>`; it renders nothing for anyone else.
18
+ *
19
+ * 🛑 Rendered OUTSIDE this card's own `<Link>`/`<TextLink>`, as a sibling.
20
+ * A `<button>` inside an `<a>` is invalid HTML that browsers resolve by
21
+ * closing the anchor early, which breaks the CARD's navigation rather than
22
+ * just the button's — `stopPropagation` stops a click but cannot fix a parse.
23
+ */
24
+ renderOwnerActions?: () => React.ReactNode;
15
25
  }
16
- export declare function InteractiveStoreCard({ store, href, selectable, isSelected, onSelect, labels, className, }: InteractiveStoreCardProps): import("react").JSX.Element;
26
+ export declare function InteractiveStoreCard({ store, href, selectable, isSelected, onSelect, labels, className, renderOwnerActions, }: InteractiveStoreCardProps): import("react").JSX.Element;
@@ -10,13 +10,13 @@ const __O = {
10
10
  hidden: "overflow-hidden",
11
11
  };
12
12
  const CLS_RATING_BADGE = "absolute top-2 right-2 flex items-center gap-[var(--appkit-space-1)] rounded-full bg-black/50 backdrop-blur-sm px-[var(--appkit-space-2)] py-[var(--appkit-space-0-5)] text-[length:var(--appkit-text-xs)] font-semibold text-warning";
13
- export function InteractiveStoreCard({ store, href, selectable, isSelected = false, onSelect, labels = {}, className = "", }) {
13
+ export function InteractiveStoreCard({ store, href, selectable, isSelected = false, onSelect, labels = {}, className = "", renderOwnerActions, }) {
14
14
  const initial = store.storeName[0]?.toUpperCase() ?? "S";
15
15
  const [logoBroken, setLogoBroken] = useState(false);
16
16
  const hasLogo = Boolean(store.storeLogoURL) && !logoBroken;
17
17
  const hasBanner = Boolean(store.storeBannerURL);
18
18
  const longPress = useLongPress(() => onSelect?.(store.id, !isSelected));
19
- return (_jsxs(Div, { className: [
19
+ const card = (_jsxs(Div, { className: [
20
20
  "group relative flex flex-col h-full overflow-hidden rounded-xl border bg-[var(--appkit-color-surface)] shadow-sm transition-shadow hover:shadow-lg",
21
21
  isSelected
22
22
  ? "border-[var(--appkit-color-primary,theme(colors.violet.600))] outline outline-2 outline-[var(--appkit-color-primary,theme(colors.violet.600))]"
@@ -26,4 +26,11 @@ export function InteractiveStoreCard({ store, href, selectable, isSelected = fal
26
26
  e.preventDefault();
27
27
  onSelect(store.id, !isSelected);
28
28
  }, label: isSelected ? "Deselect store" : "Select store", position: "top-2 left-2", className: selectable || isSelected ? "opacity-100" : "opacity-0 pointer-events-none group-hover:opacity-100 group-hover:pointer-events-auto transition-opacity" })), _jsxs(Link, { href: href, className: "flex flex-col flex-1 min-h-0", children: [_jsxs(Div, { surface: "muted", className: `relative aspect-video w-full ${__O.hidden} flex-shrink-0`, children: [hasBanner ? (_jsx(MediaImage, { src: store.storeBannerURL, alt: `${store.storeName} banner`, size: "banner", className: "h-full w-full object-cover transition-transform duration-500 group-hover:scale-105" })) : (_jsx(Row, { className: "absolute inset-0", align: "center", justify: "center", children: _jsx(Span, { className: "opacity-20 select-none", size: "5xl", "aria-hidden": "true", children: "\uD83C\uDFEA" }) })), _jsx(Scrim, { direction: "bottom-up", intensity: "subtle", className: "absolute inset-x-0 bottom-0 h-12" }), store.averageRating != null && store.averageRating > 0 && (_jsxs(Div, { className: CLS_RATING_BADGE, children: ["\u2605 ", store.averageRating.toFixed(1)] }))] }), _jsxs(Stack, { paddingY: "b-md", className: "flex-1", padding: "x-md", children: [_jsx(Row, { className: "-mt-5 mb-2", align: "end", justify: "between", children: _jsx(Div, { className: "flex-shrink-0", children: hasLogo ? (_jsx(Div, { className: "relative h-10 w-10 border-2 border-[var(--appkit-color-border-subtle)] bg-[var(--appkit-color-surface)]", rounded: "lg", shadow: "md", overflow: "hidden", children: _jsx(MediaImage, { src: store.storeLogoURL, alt: store.storeName, size: "thumbnail", onError: () => setLogoBroken(true) }) })) : (_jsx(Row, { textWeight: "bold", textSize: "base", className: "h-10 w-10 border-2 border-white bg-primary/10 dark:bg-primary/20 text-primary", align: "center", justify: "center", rounded: "lg", shadow: "md", children: initial })) }) }), _jsx(Heading, { level: 3, className: `group-hover:text-primary transition-colors`, truncate: true, size: "sm", weight: "bold", color: "primary", children: store.storeName }), store.storeDescription ? (_jsx(RichText, { html: normalizeRichTextHtml(store.storeDescription), proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: "mt-1 line-clamp-2 text-[length:var(--appkit-text-xs)] text-[var(--appkit-color-text-muted)] flex-1" })) : (_jsx(Div, { className: "flex-1" })), _jsxs(Row, { color: "muted", textSize: "xs", gap: "sm", className: "mt-2.5", wrap: true, children: [store.totalProducts != null && store.totalProducts > 0 && (_jsxs(Span, { layout: "flex", gap: "2xs", children: [_jsx(Span, { "aria-hidden": "true", children: "\uD83D\uDCE6" }), " ", store.totalProducts, " ", labels.products ?? "products"] })), store.itemsSold != null && store.itemsSold > 0 && (_jsxs(Span, { layout: "flex", gap: "2xs", children: [_jsx(Span, { "aria-hidden": "true", children: "\uD83D\uDECD\uFE0F" }), " ", store.itemsSold, " ", labels.sold ?? "sold"] }))] }), _jsxs(Row, { border: "top-subtle", paddingY: "y-xs-tall", className: "mt-3", align: "center", justify: "between", children: [_jsxs(Span, { size: "xs", weight: "semibold", className: "text-primary group-hover:underline transition-colors", children: [labels.visitStore ?? "Visit store", " \u2192"] }), store.totalReviews != null && store.totalReviews > 0 && (_jsxs(Span, { size: "xs", color: "muted", children: [store.totalReviews, " ", labels.reviews ?? "reviews"] }))] })] })] })] }));
29
+ if (!renderOwnerActions)
30
+ return card;
31
+ /*
32
+ * Sibling of the card, never a child — see the prop's docstring. `z-20`
33
+ * beats this card's own overlays, which all sit at `z-10`.
34
+ */
35
+ return (_jsxs(Div, { className: "relative h-full", children: [card, _jsx(Div, { className: "absolute right-2 bottom-2 z-20", children: renderOwnerActions() })] }));
29
36
  }
@@ -45,7 +45,6 @@ const CAPABILITY_GROUPS = [
45
45
  { cap: "lower_commission_rate", unlocks: "Negotiated reduced platform fee. Requires a signed agreement and minimum volume.", defaultOn: false },
46
46
  { cap: "early_access_features", unlocks: "Access to beta features before they are publicly available.", defaultOn: false },
47
47
  { cap: "advanced_analytics", unlocks: "Cohort retention, basket analysis, and top-buyer breakdown (beyond summary stats).", defaultOn: false },
48
- { cap: "whatsapp_catalog_sync", unlocks: "Sync your store products to your WhatsApp Business Catalog automatically.", defaultOn: false },
49
48
  ],
50
49
  },
51
50
  ];
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Package, ShoppingBag, Wallet, Settings, Shield, Headphones, CheckCircle2, Circle, BookOpen, MessageSquare, } from "lucide-react";
2
+ import { Package, ShoppingBag, Wallet, Settings, Shield, Headphones, CheckCircle2, Circle, BookOpen, } from "lucide-react";
3
3
  import { Div, Grid, Heading, Progress, Row, Section, Stack, Text, TextLink } from "../../../ui/index.js";
4
4
  import { ROUTES } from "../../../next/routing/route-map.js";
5
5
  const CLS_CHECK_ICON = "w-5 h-5 flex-shrink-0 text-emerald-500";
@@ -27,7 +27,7 @@ const GUIDE_CARDS = [
27
27
  {
28
28
  Icon: Settings,
29
29
  title: "Settings",
30
- description: "Store profile, shipping config, return policy, vacation mode, and WhatsApp integration.",
30
+ description: "Store profile, shipping config, return policy, and vacation mode.",
31
31
  href: String(ROUTES.STORE.GUIDE_SETTINGS),
32
32
  },
33
33
  {
@@ -36,12 +36,6 @@ const GUIDE_CARDS = [
36
36
  description: "Admin-granted feature flags — auctions, pre-orders, lower commissions, and more.",
37
37
  href: String(ROUTES.STORE.GUIDE_CAPABILITIES),
38
38
  },
39
- {
40
- Icon: MessageSquare,
41
- title: "WhatsApp Catalog Sync",
42
- description: "Push your product catalog to Meta Commerce Manager for WhatsApp, Facebook, and Instagram Shops.",
43
- href: String(ROUTES.STORE.GUIDE_WHATSAPP),
44
- },
45
39
  {
46
40
  Icon: Headphones,
47
41
  title: "Support",
@@ -26,11 +26,7 @@ function ReturnPolicySection() {
26
26
  function VacationModeSection() {
27
27
  return (_jsxs(Div, { className: SECTION_BODY, children: [_jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "What vacation mode does" }), _jsxs(Ul, { spacing: "tight", indent: "lg", children: [_jsx(Li, { className: LIST_DISC, children: "All your published listings are hidden from search results and browse pages." }), _jsx(Li, { className: LIST_DISC, children: "Your store profile page shows a \"On Vacation\" banner." }), _jsx(Li, { className: LIST_DISC, children: "Buyers cannot add your items to cart or checkout while on vacation." }), _jsx(Li, { className: LIST_DISC, children: "Existing orders that were placed before vacation mode must still be fulfilled." })] })] }), _jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "How to enable" }), _jsx(Text, { className: "leading-relaxed", children: "Go to your Store Dashboard \u2192 Settings \u2192 Storefront tab. Toggle \"Vacation mode\" on. Your listings re-appear instantly when you toggle it off." })] }), _jsx(Alert, { variant: "warning", title: "Ongoing orders are not paused", children: "Enabling vacation mode does not pause or cancel any existing orders. You are still responsible for fulfilling orders placed before vacation mode was enabled." })] }));
28
28
  }
29
- // -- Section 5: WhatsApp integration ------------------------------------------
30
- function WhatsAppSection() {
31
- return (_jsxs(Div, { className: SECTION_BODY, children: [_jsxs(Text, { className: "leading-relaxed", children: ["The WhatsApp integration allows your customers to contact you via WhatsApp from your store profile and lets you sync your product catalog to your WhatsApp Business Catalog (requires the", _jsx(Code, { className: "mx-1", size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "whatsapp_catalog_sync" }), " capability)."] }), _jsxs(Text, { className: "leading-relaxed", children: ["Full settings and the catalog sync toggle are at", " ", _jsx(TextLink, { variant: "bare", href: String(ROUTES.STORE.WHATSAPP), className: "underline text-[var(--appkit-color-primary)] hover:opacity-80", children: "Settings \u2192 WhatsApp" }), ". See the WhatsApp settings page for step-by-step setup instructions."] })] }));
32
- }
33
- // -- Section 6: Visibility states ---------------------------------------------
29
+ // -- Section 5: Visibility states ---------------------------------------------
34
30
  function VisibilityStatesSection() {
35
31
  const STATES = [
36
32
  {
@@ -53,5 +49,5 @@ function VisibilityStatesSection() {
53
49
  return (_jsx(Stack, { gap: "3", children: STATES.map(({ state, note }) => (_jsxs(Row, { textSize: "sm", gap: "3", children: [_jsx(Text, { className: "shrink-0 w-32 text-[var(--appkit-color-text)]", weight: "semibold", children: state }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)] leading-relaxed", children: note })] }, state))) }));
54
50
  }
55
51
  export function StoreSettingsGuideView(_props) {
56
- return (_jsxs(Stack, { gap: "lg", padding: "b-2xl", children: [_jsxs(TextLink, { variant: "bare", href: String(ROUTES.STORE.GUIDE), size: "sm", layout: "inline-flex", align: "center", gap: "sm", className: "text-[var(--appkit-color-text-muted)] hover:text-[var(--appkit-color-text)] transition-colors", children: [_jsx(ArrowLeft, { className: "h-4 w-4" }), "Back to Seller Guide"] }), _jsxs(Div, { children: [_jsx(Heading, { level: 1, className: "text-[var(--appkit-color-text)]", size: "2xl", weight: "bold", children: "Settings Guide" }), _jsx(Text, { className: "mt-1 text-[var(--appkit-color-text-muted)]", size: "sm", children: "Store profile, shipping, returns, vacation mode, WhatsApp, and visibility." })] }), _jsx(GuideSection, { title: "1. Store profile", children: _jsx(StoreProfileSection, {}) }), _jsx(GuideSection, { title: "2. Shipping configuration", children: _jsx(ShippingSection, {}) }), _jsx(GuideSection, { title: "3. Return policy", children: _jsx(ReturnPolicySection, {}) }), _jsx(GuideSection, { title: "4. Vacation mode", children: _jsx(VacationModeSection, {}) }), _jsx(GuideSection, { title: "5. WhatsApp integration", children: _jsx(WhatsAppSection, {}) }), _jsx(GuideSection, { title: "6. Visibility states", children: _jsx(VisibilityStatesSection, {}) })] }));
52
+ return (_jsxs(Stack, { gap: "lg", padding: "b-2xl", children: [_jsxs(TextLink, { variant: "bare", href: String(ROUTES.STORE.GUIDE), size: "sm", layout: "inline-flex", align: "center", gap: "sm", className: "text-[var(--appkit-color-text-muted)] hover:text-[var(--appkit-color-text)] transition-colors", children: [_jsx(ArrowLeft, { className: "h-4 w-4" }), "Back to Seller Guide"] }), _jsxs(Div, { children: [_jsx(Heading, { level: 1, className: "text-[var(--appkit-color-text)]", size: "2xl", weight: "bold", children: "Settings Guide" }), _jsx(Text, { className: "mt-1 text-[var(--appkit-color-text-muted)]", size: "sm", children: "Store profile, shipping, returns, vacation mode, and visibility." })] }), _jsx(GuideSection, { title: "1. Store profile", children: _jsx(StoreProfileSection, {}) }), _jsx(GuideSection, { title: "2. Shipping configuration", children: _jsx(ShippingSection, {}) }), _jsx(GuideSection, { title: "3. Return policy", children: _jsx(ReturnPolicySection, {}) }), _jsx(GuideSection, { title: "4. Vacation mode", children: _jsx(VacationModeSection, {}) }), _jsx(GuideSection, { title: "5. Visibility states", children: _jsx(VisibilityStatesSection, {}) })] }));
57
53
  }
@@ -47,5 +47,3 @@ export { StoreCapabilitiesGuideView } from "./StoreCapabilitiesGuideView";
47
47
  export type { StoreCapabilitiesGuideViewProps } from "./StoreCapabilitiesGuideView";
48
48
  export { StoreSettingsGuideView } from "./StoreSettingsGuideView";
49
49
  export type { StoreSettingsGuideViewProps } from "./StoreSettingsGuideView";
50
- export { StoreWhatsAppGuideView } from "./StoreWhatsAppGuideView";
51
- export type { StoreWhatsAppGuideViewProps } from "./StoreWhatsAppGuideView";
@@ -20,4 +20,3 @@ export { StoreOrdersGuideView } from "./StoreOrdersGuideView.js";
20
20
  export { StoreFinanceGuideView } from "./StoreFinanceGuideView.js";
21
21
  export { StoreCapabilitiesGuideView } from "./StoreCapabilitiesGuideView.js";
22
22
  export { StoreSettingsGuideView } from "./StoreSettingsGuideView.js";
23
- export { StoreWhatsAppGuideView } from "./StoreWhatsAppGuideView.js";
@@ -4,7 +4,7 @@
4
4
  * Data access layer for the `stores` Firestore collection.
5
5
  * One store per seller; identified by storeSlug (used as document ID).
6
6
  */
7
- import { BaseRepository, type SieveModel, type FirebaseSieveResult, type DocumentSnapshot } from "../../../providers/db-firebase";
7
+ import { BaseRepository, type SieveModel, type FirebaseSieveResult } from "../../../providers/db-firebase";
8
8
  import { StoreDocument } from "../schemas";
9
9
  import { type HistoryActor } from "../../../_internal/shared/history/index";
10
10
  import type { JsonValue } from "../../../schemas/types";
@@ -17,31 +17,6 @@ export interface StoreWriteContext {
17
17
  }
18
18
  export declare class StoreRepository extends BaseRepository<StoreDocument> {
19
19
  constructor();
20
- private encryptSecrets;
21
- private decryptSecrets;
22
- protected mapDoc<D = StoreDocument>(snap: DocumentSnapshot): D;
23
- /**
24
- * LIST reads never carry the WhatsApp token — not even encrypted.
25
- *
26
- * `mapDoc` above decrypts it, and `listStores(model, activeOnly)` backs the
27
- * PUBLIC `/stores` page. Once `sieveQuery` started routing list rows through
28
- * `mapDoc` (it previously mapped documents itself and skipped every
29
- * override), that decrypt would have put a plaintext Meta OAuth bearer token
30
- * on a public listing — the exact shape of Root Cause #70.
31
- *
32
- * So the list path deliberately does NOT call `decryptSecrets`, and drops
33
- * `accessToken` outright: a list has no legitimate use for it, and a value
34
- * that is never in the payload cannot be leaked by a projection someone
35
- * forgets to write.
36
- *
37
- * Detail reads are unchanged — `findBySlug`/`findById` still decrypt, so the
38
- * WhatsApp settings and catalog-sync routes keep working exactly as before.
39
- * Removing the decrypt from `mapDoc` itself is a separate, riskier change
40
- * that CLAUDE.md explicitly defers; this closes the public-exposure half
41
- * without touching the encryption round-trip at all.
42
- */
43
- protected mapDocForList<D = StoreDocument>(snap: DocumentSnapshot): D;
44
- update(id: string, data: Partial<StoreDocument>): Promise<StoreDocument>;
45
20
  /**
46
21
  * Create a new store.
47
22
  * The document ID is set to storeSlug for easy URL-based lookups.
@@ -9,7 +9,6 @@ import { increment } from "../../../contracts/field-ops.js";
9
9
  import { STORE_COLLECTION, STORE_FIELDS, DEFAULT_STORE_DATA, StoreStatusValues, STORE_TRACKED_FIELDS, STORE_HISTORY_PII_FIELDS, } from "../schemas/index.js";
10
10
  import { DatabaseError } from "../../../errors/index.js";
11
11
  import { normalizeError } from "../../../errors/normalize.js";
12
- import { encryptSecret, decryptSecret, } from "../../../security/settings-encryption.js";
13
12
  import { withHistory } from "../../../_internal/shared/history/index.js";
14
13
  import { buildStoreSearchTxt } from "../../../utils/search-txt-builders.js";
15
14
  import { planSearchTxt, beginSearchWindow, emptySearchResult, } from "../../../utils/search-txt-query.js";
@@ -17,57 +16,6 @@ export class StoreRepository extends BaseRepository {
17
16
  constructor() {
18
17
  super(STORE_COLLECTION);
19
18
  }
20
- encryptSecrets(data) {
21
- const token = data.whatsappConfig?.accessToken;
22
- if (!token)
23
- return data;
24
- return {
25
- ...data,
26
- whatsappConfig: { ...data.whatsappConfig, accessToken: encryptSecret(token) },
27
- };
28
- }
29
- decryptSecrets(data) {
30
- const token = data.whatsappConfig?.accessToken;
31
- if (!token)
32
- return data;
33
- return {
34
- ...data,
35
- whatsappConfig: { ...data.whatsappConfig, accessToken: decryptSecret(token) },
36
- };
37
- }
38
- mapDoc(snap) {
39
- return this.decryptSecrets(super.mapDoc(snap));
40
- }
41
- /**
42
- * LIST reads never carry the WhatsApp token — not even encrypted.
43
- *
44
- * `mapDoc` above decrypts it, and `listStores(model, activeOnly)` backs the
45
- * PUBLIC `/stores` page. Once `sieveQuery` started routing list rows through
46
- * `mapDoc` (it previously mapped documents itself and skipped every
47
- * override), that decrypt would have put a plaintext Meta OAuth bearer token
48
- * on a public listing — the exact shape of Root Cause #70.
49
- *
50
- * So the list path deliberately does NOT call `decryptSecrets`, and drops
51
- * `accessToken` outright: a list has no legitimate use for it, and a value
52
- * that is never in the payload cannot be leaked by a projection someone
53
- * forgets to write.
54
- *
55
- * Detail reads are unchanged — `findBySlug`/`findById` still decrypt, so the
56
- * WhatsApp settings and catalog-sync routes keep working exactly as before.
57
- * Removing the decrypt from `mapDoc` itself is a separate, riskier change
58
- * that CLAUDE.md explicitly defers; this closes the public-exposure half
59
- * without touching the encryption round-trip at all.
60
- */
61
- mapDocForList(snap) {
62
- const doc = super.mapDoc(snap);
63
- if (!doc.whatsappConfig)
64
- return doc;
65
- const { accessToken: _dropped, ...safeConfig } = doc.whatsappConfig;
66
- return { ...doc, whatsappConfig: safeConfig };
67
- }
68
- async update(id, data) {
69
- return super.update(id, this.encryptSecrets(data));
70
- }
71
19
  /**
72
20
  * Create a new store.
73
21
  * The document ID is set to storeSlug for easy URL-based lookups.
@@ -93,7 +41,7 @@ export class StoreRepository extends BaseRepository {
93
41
  await this.db
94
42
  .collection(this.collection)
95
43
  .doc(input.storeSlug)
96
- .create(prepareForFirestore(this.encryptSecrets(storeData)));
44
+ .create(prepareForFirestore(storeData));
97
45
  }
98
46
  catch (err) {
99
47
  void normalizeError(err);
@@ -169,9 +117,8 @@ export class StoreRepository extends BaseRepository {
169
117
  trigger: ctx?.trigger ?? defaultTrigger,
170
118
  reason: ctx?.reason,
171
119
  note: ctx?.note,
172
- // `mapDoc` decrypts whatsappConfig.accessToken on EVERY read, so a
173
- // live Meta credential is in memory whenever this diff runs, and
174
- // `encryptPiiFields` never descends into arrays.
120
+ // `encryptPiiFields` never descends into arrays, so a nested secret
121
+ // would be stored in plaintext — the list below is the scrub.
175
122
  piiFields: STORE_HISTORY_PII_FIELDS,
176
123
  });
177
124
  return withEntry ?? patch;
@@ -233,9 +180,7 @@ export class StoreRepository extends BaseRepository {
233
180
  options: { maxPageSize: win.maxPageSize(100) },
234
181
  fields: sieveFields,
235
182
  // Called DIRECTLY, not through `sieveQuery`, so the mapper has to be
236
- // passed by hand — and it is the list mapper, never `mapDoc`. With
237
- // `activeOnly` this is the public /stores listing; `mapDoc` decrypts the
238
- // WhatsApp bearer token and a list has no use for it.
183
+ // passed by hand. With `activeOnly` this is the public /stores listing.
239
184
  mapDoc: (snap) => this.mapDocForList(snap),
240
185
  });
241
186
  const searched = win.finish(result);
@@ -372,7 +317,7 @@ export class StoreRepository extends BaseRepository {
372
317
  const batch = this.db.batch();
373
318
  const newRef = this.db.collection(this.collection).doc(newSlug);
374
319
  const oldRef = this.db.collection(this.collection).doc(currentSlug);
375
- batch.create(newRef, prepareForFirestore(this.encryptSecrets(newDoc)));
320
+ batch.create(newRef, prepareForFirestore(newDoc));
376
321
  batch.delete(oldRef);
377
322
  await batch.commit();
378
323
  return { id: newSlug, ...newDoc };
@@ -254,28 +254,6 @@ export interface StoreDocument extends BaseDocument {
254
254
  * than trusting that nobody adds it.
255
255
  */
256
256
  returnsDirectToSeller?: boolean;
257
- whatsappConfig?: {
258
- /** Seller's WhatsApp Business phone number, digits-only with country code e.g. "919876543210" */
259
- phoneNumber?: string;
260
- /** Meta WABA ID for this store */
261
- wabaId?: string;
262
- /** Meta Commerce Catalog ID linked to this store */
263
- catalogId?: string;
264
- /** Encrypted access token (AES-256-GCM via encryptPii) — never returned to client */
265
- accessToken?: string;
266
- /** Whether catalog sync is enabled for this store */
267
- catalogSyncEnabled: boolean;
268
- /** Timestamp of last successful catalog sync */
269
- lastCatalogSyncAt?: Date;
270
- /** Number of products synced in last run */
271
- lastSyncCount?: number;
272
- /** Status of last sync attempt */
273
- lastSyncStatus?: "success" | "partial" | "failed";
274
- /** True when wabaId + catalogId + accessToken are all set */
275
- connected: boolean;
276
- /** When the seller first connected their account */
277
- connectedAt?: Date;
278
- };
279
257
  /**
280
258
  * Who changed what, when, and why. See § "Status History" in CLAUDE.md.
281
259
  *
@@ -300,9 +278,12 @@ export interface StoreDocument extends BaseDocument {
300
278
  */
301
279
  export declare const STORE_TRACKED_FIELDS: readonly ["status", "isPublic", "isVerified", "isFeatured", "suspensionReason", "capabilities"];
302
280
  /**
303
- * PII on this document, for `withHistory`'s scrub. `whatsappConfig.accessToken`
304
- * is a live Meta credential; `mapDoc` decrypts it on EVERY read, so it is
305
- * present in memory whenever a diff runs.
281
+ * PII on this document, for the `withHistory` scrub.
282
+ *
283
+ * `accessToken` stays listed although the WhatsApp integration that produced
284
+ * one was removed 2026-10-20: a scrub list is cheap, and a future secret
285
+ * reaching this document under that name should be scrubbed by default
286
+ * rather than by someone remembering to add it.
306
287
  */
307
288
  export declare const STORE_HISTORY_PII_FIELDS: readonly ["accessToken", "payoutDetails", "upiVpa", "accountNumber"];
308
289
  export type { StoreCapability } from "../../auth/permissions/constants";
@@ -33,9 +33,12 @@ export const STORE_TRACKED_FIELDS = [
33
33
  "capabilities",
34
34
  ];
35
35
  /**
36
- * PII on this document, for `withHistory`'s scrub. `whatsappConfig.accessToken`
37
- * is a live Meta credential; `mapDoc` decrypts it on EVERY read, so it is
38
- * present in memory whenever a diff runs.
36
+ * PII on this document, for the `withHistory` scrub.
37
+ *
38
+ * `accessToken` stays listed although the WhatsApp integration that produced
39
+ * one was removed 2026-10-20: a scrub list is cheap, and a future secret
40
+ * reaching this document under that name should be scrubbed by default
41
+ * rather than by someone remembering to add it.
39
42
  */
40
43
  export const STORE_HISTORY_PII_FIELDS = [
41
44
  "accessToken",
@@ -228,7 +228,7 @@ export declare const storeFirestoreSchema: z.ZodObject<{
228
228
  totalReviews: number;
229
229
  averageRating?: number | undefined;
230
230
  }>>;
231
- capabilities: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
231
+ capabilities: z.ZodOptional<z.ZodArray<z.ZodEnum<[string, ...string[]]>, "many">>;
232
232
  customCommissionRate: z.ZodOptional<z.ZodNumber>;
233
233
  googleReviews: z.ZodOptional<z.ZodObject<{
234
234
  placeId: z.ZodString;
@@ -347,60 +347,6 @@ export declare const storeFirestoreSchema: z.ZodObject<{
347
347
  defaultProviderId: string;
348
348
  }>>;
349
349
  emiEnabled: z.ZodOptional<z.ZodBoolean>;
350
- whatsappConfig: z.ZodOptional<z.ZodObject<{
351
- phoneNumber: z.ZodOptional<z.ZodString>;
352
- wabaId: z.ZodOptional<z.ZodString>;
353
- catalogId: z.ZodOptional<z.ZodString>;
354
- accessToken: z.ZodOptional<z.ZodString>;
355
- catalogSyncEnabled: z.ZodBoolean;
356
- lastCatalogSyncAt: z.ZodOptional<z.ZodUnion<[z.ZodDate, z.ZodString, z.ZodObject<{
357
- toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
358
- }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
359
- toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
360
- }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
361
- toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
362
- }, z.ZodTypeAny, "passthrough">>]>>;
363
- lastSyncCount: z.ZodOptional<z.ZodNumber>;
364
- lastSyncStatus: z.ZodOptional<z.ZodEnum<["success", "partial", "failed"]>>;
365
- connected: z.ZodBoolean;
366
- connectedAt: z.ZodOptional<z.ZodUnion<[z.ZodDate, z.ZodString, z.ZodObject<{
367
- toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
368
- }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
369
- toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
370
- }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
371
- toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
372
- }, z.ZodTypeAny, "passthrough">>]>>;
373
- }, "strip", z.ZodTypeAny, {
374
- catalogSyncEnabled: boolean;
375
- connected: boolean;
376
- phoneNumber?: string | undefined;
377
- accessToken?: string | undefined;
378
- wabaId?: string | undefined;
379
- catalogId?: string | undefined;
380
- lastCatalogSyncAt?: string | Date | z.objectOutputType<{
381
- toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
382
- }, z.ZodTypeAny, "passthrough"> | undefined;
383
- lastSyncCount?: number | undefined;
384
- lastSyncStatus?: "success" | "failed" | "partial" | undefined;
385
- connectedAt?: string | Date | z.objectOutputType<{
386
- toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
387
- }, z.ZodTypeAny, "passthrough"> | undefined;
388
- }, {
389
- catalogSyncEnabled: boolean;
390
- connected: boolean;
391
- phoneNumber?: string | undefined;
392
- accessToken?: string | undefined;
393
- wabaId?: string | undefined;
394
- catalogId?: string | undefined;
395
- lastCatalogSyncAt?: string | Date | z.objectInputType<{
396
- toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
397
- }, z.ZodTypeAny, "passthrough"> | undefined;
398
- lastSyncCount?: number | undefined;
399
- lastSyncStatus?: "success" | "failed" | "partial" | undefined;
400
- connectedAt?: string | Date | z.objectInputType<{
401
- toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
402
- }, z.ZodTypeAny, "passthrough"> | undefined;
403
- }>>;
404
350
  }, "strip", z.ZodTypeAny, {
405
351
  status: "pending" | "active" | "rejected" | "suspended";
406
352
  id: string;
@@ -470,22 +416,6 @@ export declare const storeFirestoreSchema: z.ZodObject<{
470
416
  maxReviews?: number | undefined;
471
417
  minRating?: number | undefined;
472
418
  } | undefined;
473
- whatsappConfig?: {
474
- catalogSyncEnabled: boolean;
475
- connected: boolean;
476
- phoneNumber?: string | undefined;
477
- accessToken?: string | undefined;
478
- wabaId?: string | undefined;
479
- catalogId?: string | undefined;
480
- lastCatalogSyncAt?: string | Date | z.objectOutputType<{
481
- toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
482
- }, z.ZodTypeAny, "passthrough"> | undefined;
483
- lastSyncCount?: number | undefined;
484
- lastSyncStatus?: "success" | "failed" | "partial" | undefined;
485
- connectedAt?: string | Date | z.objectOutputType<{
486
- toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
487
- }, z.ZodTypeAny, "passthrough"> | undefined;
488
- } | undefined;
489
419
  }, {
490
420
  status: "pending" | "active" | "rejected" | "suspended";
491
421
  id: string;
@@ -555,22 +485,6 @@ export declare const storeFirestoreSchema: z.ZodObject<{
555
485
  maxReviews?: number | undefined;
556
486
  minRating?: number | undefined;
557
487
  } | undefined;
558
- whatsappConfig?: {
559
- catalogSyncEnabled: boolean;
560
- connected: boolean;
561
- phoneNumber?: string | undefined;
562
- accessToken?: string | undefined;
563
- wabaId?: string | undefined;
564
- catalogId?: string | undefined;
565
- lastCatalogSyncAt?: string | Date | z.objectInputType<{
566
- toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
567
- }, z.ZodTypeAny, "passthrough"> | undefined;
568
- lastSyncCount?: number | undefined;
569
- lastSyncStatus?: "success" | "failed" | "partial" | undefined;
570
- connectedAt?: string | Date | z.objectInputType<{
571
- toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
572
- }, z.ZodTypeAny, "passthrough"> | undefined;
573
- } | undefined;
574
488
  }>;
575
489
  export type StoreFromSchema = z.infer<typeof storeFirestoreSchema>;
576
490
  /** Zod schema for store status — use instead of inline `z.enum(["pending",...])`. */
@@ -1,6 +1,7 @@
1
1
  export * from "./firestore.js";
2
2
  import { z } from "zod";
3
3
  import { StoreStatusValues } from "./firestore.js";
4
+ import { ALL_STORE_CAPABILITIES } from "../../auth/permissions/constants.js";
4
5
  import { auditTimestampsShape, firestoreDateSchema, rupeesSchema } from "../../../schemas/firestore-helpers.js";
5
6
  // ─── Firestore document schema (W2) ───────────────────────────────────────────
6
7
  // Mirrors StoreDocument in ./firestore.ts. Registered into SCHEMAS.firestore.stores.
@@ -70,7 +71,15 @@ export const storeFirestoreSchema = z.object({
70
71
  averageRating: z.number().optional(),
71
72
  })
72
73
  .optional(),
73
- capabilities: z.array(z.string()).optional(),
74
+ /*
75
+ * 🛑 A `z.enum`, not `z.array(z.string())`. Nothing used to check a stored
76
+ * capability against the union, so a typo saved successfully and the gate it
77
+ * was meant to open never opened — with no error anywhere, because an
78
+ * unrecognised capability is indistinguishable from an ungranted one.
79
+ */
80
+ capabilities: z
81
+ .array(z.enum(ALL_STORE_CAPABILITIES))
82
+ .optional(),
74
83
  customCommissionRate: z.number().min(0).max(100).optional(),
75
84
  googleReviews: z
76
85
  .object({
@@ -83,20 +92,6 @@ export const storeFirestoreSchema = z.object({
83
92
  .optional(),
84
93
  shippingConfig: storeShippingConfigSchema.optional(),
85
94
  emiEnabled: z.boolean().optional(),
86
- whatsappConfig: z
87
- .object({
88
- phoneNumber: z.string().optional(),
89
- wabaId: z.string().optional(),
90
- catalogId: z.string().optional(),
91
- accessToken: z.string().optional(),
92
- catalogSyncEnabled: z.boolean(),
93
- lastCatalogSyncAt: firestoreDateSchema.optional(),
94
- lastSyncCount: z.number().int().optional(),
95
- lastSyncStatus: z.enum(["success", "partial", "failed"]).optional(),
96
- connected: z.boolean(),
97
- connectedAt: firestoreDateSchema.optional(),
98
- })
99
- .optional(),
100
95
  ...auditTimestampsShape,
101
96
  });
102
97
  /** Zod schema for store status — use instead of inline `z.enum(["pending",...])`. */
@@ -174,54 +174,6 @@ export const authored = {
174
174
  expectedUiState: "With the toggle OFF, /checkout offers only whichever of manual UPI/cash and COD are separately enabled — no 'Pay Online (PhonePe)' button. With it back ON, the button reappears.",
175
175
  endResult: "The toggle is restored to ON, matching the state before this case started.",
176
176
  },
177
- "checklist-admin-site-system-whatsapp-credentials-persist": {
178
- roles: ["admin"],
179
- startPage: "/admin/site",
180
- steps: [
181
- "Sign in as admin@letitrip.in / TempPass123!.",
182
- "Open /admin/site, switch to the Integrations tab, and WRITE DOWN every WhatsApp field and its current masked state before touching anything.",
183
- "Type QA-WA-TOKEN-552310 into the access-token field and fill any account identifier fields.",
184
- "Save and RELOAD, then read how each field displays.",
185
- "Open /api/site-settings in a private window and search for QA-WA-TOKEN-552310.",
186
- "Open a public store page's source and search for it too.",
187
- "RESTORE every field to exactly what step 3 recorded — clearing is not restoring, and a real Meta token cleared here cannot be recovered from the seed. Save and reload to confirm.",
188
- ],
189
- inputs: { token: "QA-WA-TOKEN-552310" },
190
- expectedBehaviour: "The token is encrypted at rest and masked on read. It is also decrypted on every read of a store document, so any page handing a raw store document to a client component serialises it into public HTML — which is why both the settings response and a public store page are checked rather than the admin form alone.",
191
- expectedUiState: "After the reload the token displays masked. Neither the public settings response nor a public store page's source contains it.",
192
- expectedData: { tokenInPublicSurfaces: 0 },
193
- endResult: "The fields are cleared by the final step.",
194
- },
195
- "checklist-admin-site-system-whatsapp-channel-toggle-persists": {
196
- roles: ["admin"],
197
- startPage: "/admin/site",
198
- steps: [
199
- "Sign in as admin@letitrip.in / TempPass123!.",
200
- "Open /admin/site, switch to the Notifications tab, and read every channel toggle and its state. Four are listed: in-app, email, WhatsApp and SMS.",
201
- "Turn the WHATSAPP channel off and save. Pick that one specifically — SMS is seeded OFF (and has no sender at all), so toggling it off would be a no-op that proves nothing.",
202
- "RELOAD and read every toggle.",
203
- "Check only the one changed.",
204
- "Turn it back on, save, and reload to confirm.",
205
- ],
206
- expectedBehaviour: "Off is the direction that proves persistence when the default is on: a toggle that never saves reads back as its default and passes a test that only ever turns it on. Saving one toggle must not rewrite the rest.",
207
- expectedUiState: "After the reload the toggled channel is off and every other is unchanged. A toggle that has reverted to on is the failure, and the save reported success.",
208
- endResult: "The toggle is restored.",
209
- },
210
- "checklist-admin-site-system-whatsapp-order-announcement-fires": {
211
- roles: ["admin", "buyer"],
212
- startPage: "/admin/site",
213
- steps: [
214
- "Sign in as admin@letitrip.in / TempPass123! and confirm the WhatsApp order channel is enabled.",
215
- "Read whether real credentials are configured or whether the fields are empty.",
216
- "Sign in as rehan.sheikh@gmail.com / TempPass123! and place an order that would trigger an order announcement.",
217
- "Read whether the buyer opted into WhatsApp updates and what fee was charged for it.",
218
- "Check the in-app notification for the order arrived.",
219
- "If real credentials are configured, check whether a WhatsApp message arrived.",
220
- ],
221
- expectedBehaviour: "WhatsApp order announcements are a paid per-store add-on, so the charge and the delivery must agree — a buyer charged the add-on fee and sent nothing is the failure that matters. With no credentials configured, the dispatch skips cleanly rather than failing loudly: the Meta secrets are seeded as empty strings rather than placeholders for exactly that reason.",
222
- expectedUiState: "The in-app notification arrives regardless. With credentials configured a message arrives; without them nothing is sent and no error surfaces to the buyer. A charged add-on with no delivery is the finding.",
223
- endResult: "One order exists. Record whether credentials were configured — the case reads differently either way.",
224
- },
225
177
  "checklist-admin-site-system-auction-bid-tiers-admin": {
226
178
  roles: ["admin", "buyer"],
227
179
  startPage: "/admin/site",
@@ -226,46 +226,6 @@ export const authored = {
226
226
  expectedData: { otpRequiredAbove: true, otpRequiredBelow: false },
227
227
  endResult: "Entering the correct code completes the order. Three items only add to ₹4,597 — the fourth is what actually crosses the threshold, and an earlier draft of this case stopped at three and could never have triggered the prompt it was checking for.",
228
228
  },
229
- "checklist-buying-buying-checkout-checkout-otp-whatsapp-hidden-without-phone": {
230
- roles: ["buyer"],
231
- startPage: "/checkout",
232
- steps: [
233
- "Sign in as admin@letitrip.in / TempPass123! and confirm Site Settings → Notifications → WhatsApp → 'WhatsApp OTP' is enabled.",
234
- "Sign in as rehan.sheikh@gmail.com / TempPass123!.",
235
- "Open /user/addresses and add an address named 'QA Address otp-whatsapp-hidden', 2 Test Road, Mumbai, Maharashtra 400001, leaving the phone field empty.",
236
- "Add product-beyblade-original-dranzer-s (₹1,499), product-beyblade-original-driger-v (₹1,799), product-beyblade-metal-storm-pegasus (₹1,299) and product-beyblade-burst-regalia-genesis (₹1,399) to the cart, making ₹5,996.",
237
- "Open /checkout, select 'QA Address otp-whatsapp-hidden' on Step 1, and continue to the payment step.",
238
- "Select a non-COD payment method.",
239
- "Read every option offered on the OTP prompt.",
240
- ],
241
- inputs: { addressLabel: "QA Address otp-whatsapp-hidden", phone: "", subtotal: 5996 },
242
- expectedBehaviour: "The WhatsApp channel needs three things at once — admin-enabled, real credentials, and a phone number on the SELECTED address. Missing the third hides the option rather than offering it and failing at send time, which would waste the buyer's OTP window on a channel that could never deliver.",
243
- expectedUiState: "The prompt offers email only. There is no 'Send via WhatsApp instead' control, disabled or otherwise, even though the same setting shows one for an address that has a phone.",
244
- expectedData: { whatsappOptionPresent: false },
245
- endResult: "The order still completes by email OTP. Delete the address afterwards so it does not accumulate across runs.",
246
- },
247
- "checklist-buying-buying-checkout-checkout-otp-whatsapp-option": {
248
- roles: ["buyer"],
249
- startPage: "/checkout",
250
- steps: [
251
- "Sign in as admin@letitrip.in / TempPass123! and confirm Site Settings → Notifications → WhatsApp → 'WhatsApp OTP' is enabled with real Meta Cloud API credentials.",
252
- "Sign in as rehan.sheikh@gmail.com / TempPass123!.",
253
- "Open /user/addresses and add a phone number to the existing address 'Home — 123 Stadium Lane, Vijay Nagar, Indore, Madhya Pradesh 452010' if it does not already have one.",
254
- "Add product-beyblade-original-dranzer-s (₹1,499), product-beyblade-original-driger-v (₹1,799), product-beyblade-metal-storm-pegasus (₹1,299) and product-beyblade-burst-regalia-genesis (₹1,399) to the cart, making ₹5,996.",
255
- "Open /cart and click 'Proceed to checkout'.",
256
- "Select the address with a phone number on Step 1 and click 'Continue'.",
257
- "Click 'Continue to payment' on Step 2.",
258
- "On Step 3, select a non-COD payment method.",
259
- "Read the default send channel shown on the OTP prompt.",
260
- "Click 'Send via WhatsApp instead'.",
261
- "Type the code received on WhatsApp into the OTP field and submit it.",
262
- ],
263
- inputs: { subtotal: 5996, defaultChannel: "email", alternateChannel: "WhatsApp" },
264
- expectedBehaviour: "Email is the default channel and WhatsApp is opt-in per attempt. The alternate appears only when the feature is enabled, real Meta credentials are configured, and the selected address carries a phone — the seeded Meta secrets are empty strings rather than placeholders precisely so a missing credential skips cleanly instead of making a billed call that fails.",
265
- expectedUiState: "The prompt first shows a masked email. After 'Send via WhatsApp instead' it shows a masked phone in the shape '+91 ••••••7890'. The code that arrives on WhatsApp is accepted and payment proceeds.",
266
- expectedData: { defaultChannel: "email" },
267
- endResult: "The order is placed after the WhatsApp code verifies. With no real Meta credentials configured this case is unreachable — answer null rather than reporting the missing option as a bug.",
268
- },
269
229
  "checklist-buying-buying-checkout-checkout-phonepe-charge-includes-shipping": {
270
230
  roles: ["buyer"],
271
231
  startPage: "/checkout",