@mohasinac/appkit 4.30.19 → 4.31.1

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 (417) hide show
  1. package/dist/_internal/client/features/layout/useSidebarSearch.d.ts +21 -5
  2. package/dist/_internal/client/features/layout/useSidebarSearch.js +27 -6
  3. package/dist/_internal/client/features/lottery/LotteryAdminEditView.d.ts +23 -3
  4. package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +106 -87
  5. package/dist/_internal/client/features/lottery/LotteryPullForm.d.ts +16 -5
  6. package/dist/_internal/client/features/lottery/LotteryPullForm.js +65 -40
  7. package/dist/_internal/server/features/auth/permissions.d.ts +2 -0
  8. package/dist/_internal/server/features/auth/permissions.js +3 -2
  9. package/dist/_internal/server/features/categories/data.js +15 -4
  10. package/dist/_internal/server/features/classified/index.d.ts +0 -1
  11. package/dist/_internal/server/features/classified/index.js +0 -1
  12. package/dist/_internal/server/features/digital-code/index.d.ts +0 -1
  13. package/dist/_internal/server/features/digital-code/index.js +0 -1
  14. package/dist/_internal/server/features/live/index.d.ts +0 -1
  15. package/dist/_internal/server/features/live/index.js +0 -1
  16. package/dist/_internal/server/features/products/data.js +15 -5
  17. package/dist/_internal/server/features/products/list-public.d.ts +9 -0
  18. package/dist/_internal/server/features/products/list-public.js +95 -7
  19. package/dist/_internal/server/features/site-settings/adapters.d.ts +2 -2
  20. package/dist/_internal/server/features/site-settings/adapters.js +8 -5
  21. package/dist/_internal/server/features/tester/visibility.d.ts +2 -1
  22. package/dist/_internal/server/features/tester/visibility.js +2 -2
  23. package/dist/_internal/server/functions/scheduled.d.ts +3 -1
  24. package/dist/_internal/server/functions/scheduled.js +27 -1
  25. package/dist/_internal/server/jobs/core/hardBanCascade.js +4 -0
  26. package/dist/_internal/server/jobs/core/index.d.ts +2 -0
  27. package/dist/_internal/server/jobs/core/index.js +2 -0
  28. package/dist/_internal/server/jobs/core/pageViewPrune.d.ts +10 -0
  29. package/dist/_internal/server/jobs/core/pageViewPrune.js +44 -0
  30. package/dist/_internal/server/jobs/core/pageViewRollup.d.ts +2 -0
  31. package/dist/_internal/server/jobs/core/pageViewRollup.js +87 -0
  32. package/dist/_internal/server/jobs/handlers/index.d.ts +2 -0
  33. package/dist/_internal/server/jobs/handlers/index.js +2 -0
  34. package/dist/_internal/server/jobs/handlers/pageViewPrune.d.ts +2 -0
  35. package/dist/_internal/server/jobs/handlers/pageViewPrune.js +2 -0
  36. package/dist/_internal/server/jobs/handlers/pageViewRollup.d.ts +2 -0
  37. package/dist/_internal/server/jobs/handlers/pageViewRollup.js +2 -0
  38. package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
  39. package/dist/_internal/shared/actions/action-registry.js +69 -22
  40. package/dist/_internal/shared/checkout/rules/classified.rule.d.ts +9 -4
  41. package/dist/_internal/shared/checkout/rules/classified.rule.js +7 -2
  42. package/dist/_internal/shared/features/layout/matchesNavQuery.d.ts +14 -0
  43. package/dist/_internal/shared/features/layout/matchesNavQuery.js +72 -0
  44. package/dist/_internal/shared/features/layout/types.d.ts +37 -1
  45. package/dist/_internal/shared/features/layout/types.js +19 -1
  46. package/dist/_internal/shared/features/notifications/action-url.d.ts +9 -1
  47. package/dist/_internal/shared/features/notifications/action-url.js +47 -0
  48. package/dist/_internal/shared/features/offers/config.d.ts +65 -0
  49. package/dist/_internal/shared/features/offers/config.js +73 -2
  50. package/dist/_internal/shared/features/orders/schema.d.ts +19 -1
  51. package/dist/_internal/shared/features/orders/schema.js +22 -2
  52. package/dist/_internal/shared/features/site-settings/types.d.ts +12 -3
  53. package/dist/_internal/shared/listing-types/capabilities.d.ts +8 -2
  54. package/dist/_internal/shared/listing-types/capabilities.js +6 -1
  55. package/dist/_internal/shared/listing-types/classified/ctas.js +6 -1
  56. package/dist/_internal/shared/listing-types/feature-flags.d.ts +10 -5
  57. package/dist/_internal/shared/listing-types/feature-flags.js +11 -6
  58. package/dist/client.d.ts +37 -20
  59. package/dist/client.js +36 -14
  60. package/dist/configs/next.js +10 -2
  61. package/dist/constants/api-endpoints.d.ts +18 -54
  62. package/dist/constants/api-endpoints.js +6 -26
  63. package/dist/constants/field-names.d.ts +6 -24
  64. package/dist/constants/field-names.js +10 -27
  65. package/dist/constants/geo/countries.d.ts +50 -0
  66. package/dist/constants/geo/countries.js +129 -0
  67. package/dist/constants/geo/subdivisions.d.ts +13 -0
  68. package/dist/constants/geo/subdivisions.js +104 -0
  69. package/dist/constants/index.d.ts +2 -2
  70. package/dist/constants/index.js +2 -2
  71. package/dist/constants/table-keys.d.ts +24 -0
  72. package/dist/constants/table-keys.js +28 -0
  73. package/dist/contracts/extend.d.ts +0 -9
  74. package/dist/contracts/index.d.ts +1 -1
  75. package/dist/contracts/realtime-session.js +7 -0
  76. package/dist/core/browser.d.ts +1 -1
  77. package/dist/core/browser.js +1 -1
  78. package/dist/core/index.d.ts +1 -1
  79. package/dist/core/index.js +1 -1
  80. package/dist/core/site-config.d.ts +0 -3
  81. package/dist/core/site-config.js +0 -3
  82. package/dist/errors/messages.d.ts +0 -8
  83. package/dist/errors/messages.js +0 -9
  84. package/dist/features/about/schemas/index.d.ts +8 -8
  85. package/dist/features/account/components/AddressFilters.js +32 -11
  86. package/dist/features/account/components/AddressForm.d.ts +26 -25
  87. package/dist/features/account/components/AddressForm.js +81 -103
  88. package/dist/features/account/components/AddressesIndexListing.js +8 -4
  89. package/dist/features/account/components/UserSidebar.d.ts +3 -4
  90. package/dist/features/account/components/UserSupportView.js +89 -58
  91. package/dist/features/account/components/index.d.ts +1 -7
  92. package/dist/features/account/components/index.js +0 -3
  93. package/dist/features/account/hooks/useAddresses.d.ts +4 -3
  94. package/dist/features/account/hooks/useAddresses.js +4 -6
  95. package/dist/features/account/hooks/useCollapsedSections.d.ts +51 -10
  96. package/dist/features/account/hooks/useCollapsedSections.js +211 -38
  97. package/dist/features/account/hooks/useProfile.d.ts +8 -0
  98. package/dist/features/account/index.d.ts +0 -3
  99. package/dist/features/account/index.js +0 -3
  100. package/dist/features/account/schemas/index.d.ts +0 -92
  101. package/dist/features/account/schemas/index.js +42 -20
  102. package/dist/features/addresses/components/AddressLocationFields.d.ts +13 -0
  103. package/dist/features/addresses/components/AddressLocationFields.js +41 -0
  104. package/dist/features/addresses/hooks/usePostalLookup.d.ts +17 -0
  105. package/dist/features/addresses/hooks/usePostalLookup.js +133 -0
  106. package/dist/features/addresses/schemas/address-form.d.ts +423 -0
  107. package/dist/features/addresses/schemas/address-form.js +212 -0
  108. package/dist/features/addresses/schemas/index.d.ts +1 -0
  109. package/dist/features/addresses/schemas/index.js +8 -0
  110. package/dist/features/admin/actions/admin-read-actions.d.ts +1 -1
  111. package/dist/features/admin/actions/index.d.ts +0 -1
  112. package/dist/features/admin/actions/index.js +0 -1
  113. package/dist/features/admin/actions/notification-actions.js +1 -41
  114. package/dist/features/admin/components/AdminActionIndexView.d.ts +32 -0
  115. package/dist/features/admin/components/AdminActionIndexView.js +128 -0
  116. package/dist/features/admin/components/AdminAdEditorView.js +159 -163
  117. package/dist/features/admin/components/AdminAddressEditorView.js +97 -55
  118. package/dist/features/admin/components/AdminBrandEditorView.d.ts +15 -0
  119. package/dist/features/admin/components/AdminBrandEditorView.js +113 -77
  120. package/dist/features/admin/components/AdminBundleEditorView.d.ts +19 -9
  121. package/dist/features/admin/components/AdminBundleEditorView.js +136 -168
  122. package/dist/features/admin/components/AdminCategoryEditorView.js +120 -43
  123. package/dist/features/admin/components/AdminCouponEditorView.js +145 -109
  124. package/dist/features/admin/components/AdminEmployeeEditorView.js +125 -56
  125. package/dist/features/admin/components/AdminFaqEditorView.js +112 -58
  126. package/dist/features/admin/components/AdminFeatureEditorView.js +108 -68
  127. package/dist/features/admin/components/AdminNavEditorView.js +69 -44
  128. package/dist/features/admin/components/AdminOrderEditorView.js +47 -10
  129. package/dist/features/admin/components/AdminPrizeDrawsView.js +16 -2
  130. package/dist/features/admin/components/AdminSidebar.d.ts +11 -7
  131. package/dist/features/admin/components/AdminSiteSettingsView.js +37 -37
  132. package/dist/features/admin/components/AdminStoreEditorView.js +75 -52
  133. package/dist/features/admin/components/AdminSublistingCategoryEditorView.js +71 -30
  134. package/dist/features/admin/components/AdminTesterChecklistItemEditorView.js +95 -65
  135. package/dist/features/admin/components/BrandQuickCreateForm.d.ts +10 -0
  136. package/dist/features/admin/components/BrandQuickCreateForm.js +49 -26
  137. package/dist/features/admin/components/CategoryQuickCreateForm.d.ts +11 -0
  138. package/dist/features/admin/components/CategoryQuickCreateForm.js +48 -26
  139. package/dist/features/admin/components/index.d.ts +2 -2
  140. package/dist/features/admin/components/index.js +1 -1
  141. package/dist/features/admin/constants/site-settings-tabs.d.ts +120 -0
  142. package/dist/features/admin/constants/site-settings-tabs.js +152 -0
  143. package/dist/features/admin/index.d.ts +0 -3
  144. package/dist/features/admin/index.js +0 -2
  145. package/dist/features/admin/repository/analytics-rollup.repository.d.ts +35 -0
  146. package/dist/features/admin/repository/analytics-rollup.repository.js +30 -0
  147. package/dist/features/admin/schemas/admin-editor-forms.d.ts +56 -57
  148. package/dist/features/admin/schemas/admin-editor-forms.js +97 -54
  149. package/dist/features/admin/schemas/admin-ops-forms.d.ts +57 -5
  150. package/dist/features/admin/schemas/admin-ops-forms.js +104 -20
  151. package/dist/features/admin/schemas/admin-user-form.js +7 -0
  152. package/dist/features/admin/schemas/firestore.d.ts +48 -95
  153. package/dist/features/admin/schemas/firestore.js +15 -151
  154. package/dist/features/admin/schemas/nav-item-form.js +9 -2
  155. package/dist/features/admin/server.d.ts +0 -4
  156. package/dist/features/admin/server.js +0 -2
  157. package/dist/features/admin/types/index.d.ts +0 -7
  158. package/dist/features/analytics/repository/page-views.repository.d.ts +14 -0
  159. package/dist/features/analytics/repository/page-views.repository.js +24 -0
  160. package/dist/features/auth/actions/index.d.ts +0 -1
  161. package/dist/features/auth/actions/index.js +0 -1
  162. package/dist/features/auth/actions/realtime-token-actions.js +1 -12
  163. package/dist/features/auth/auth-helpers.js +5 -7
  164. package/dist/features/auth/components/Guards.js +2 -1
  165. package/dist/features/auth/components/LoginForm.d.ts +0 -2
  166. package/dist/features/auth/components/LoginForm.js +1 -3
  167. package/dist/features/auth/components/RegisterForm.js +62 -19
  168. package/dist/features/auth/permissions/constants.d.ts +27 -1
  169. package/dist/features/auth/role-predicates.d.ts +75 -7
  170. package/dist/features/auth/role-predicates.js +28 -2
  171. package/dist/features/auth/schemas/firestore.d.ts +22 -0
  172. package/dist/features/auth/schemas/index.d.ts +1 -1
  173. package/dist/features/auth/schemas/index.js +44 -8
  174. package/dist/features/auth/types/index.d.ts +14 -1
  175. package/dist/features/blog/api/route.js +10 -2
  176. package/dist/features/blog/components/BlogIndexListing.js +1 -1
  177. package/dist/features/blog/hooks/useBlog.js +2 -2
  178. package/dist/features/blog/schemas/index.d.ts +4 -0
  179. package/dist/features/blog/schemas/index.js +2 -0
  180. package/dist/features/blog/types/index.d.ts +1 -1
  181. package/dist/features/catalogue/components/CatalogueItemEditorView.d.ts +22 -0
  182. package/dist/features/catalogue/components/CatalogueItemEditorView.js +112 -52
  183. package/dist/features/catalogue/schemas/validation.d.ts +4 -4
  184. package/dist/features/catalogue/schemas/validation.js +47 -10
  185. package/dist/features/categories/schemas/bundle-form.d.ts +142 -0
  186. package/dist/features/categories/schemas/bundle-form.js +149 -0
  187. package/dist/features/classified/components/ClassifiedDetailPageView.d.ts +5 -4
  188. package/dist/features/classified/components/ClassifiedDetailPageView.js +37 -16
  189. package/dist/features/consultation/components/ConsultationForm.js +1 -1
  190. package/dist/features/consultation/schemas/index.js +34 -10
  191. package/dist/features/corporate/schemas/index.js +36 -15
  192. package/dist/features/filters/FilterPanel.js +3 -3
  193. package/dist/features/filters/RangeFilter.d.ts +10 -0
  194. package/dist/features/filters/RangeFilter.js +41 -4
  195. package/dist/features/homepage/components/MarketplaceHomepageView.js +24 -5
  196. package/dist/features/homepage/hooks/useBlogArticles.js +1 -1
  197. package/dist/features/layout/BottomActions.js +84 -11
  198. package/dist/features/layout/BottomActionsContext.d.ts +1 -6
  199. package/dist/features/layout/BottomActionsContext.js +1 -1
  200. package/dist/features/layout/hooks/useBottomActions.js +2 -2
  201. package/dist/features/layout/hooks/useFormBottomActions.d.ts +12 -1
  202. package/dist/features/layout/hooks/useFormBottomActions.js +12 -6
  203. package/dist/features/lottery/schemas/config-write.d.ts +9 -5
  204. package/dist/features/lottery/schemas/config-write.js +69 -9
  205. package/dist/features/orders/schemas/buyer-forms.d.ts +6 -3
  206. package/dist/features/orders/schemas/buyer-forms.js +31 -3
  207. package/dist/features/orders/schemas/index.d.ts +2 -2
  208. package/dist/features/products/components/GroupSettingsPanel.js +3 -1
  209. package/dist/features/products/components/MakeOfferButton.d.ts +13 -2
  210. package/dist/features/products/components/MakeOfferButton.js +33 -11
  211. package/dist/features/products/components/ProductDetailActions.js +0 -1
  212. package/dist/features/products/components/ProductDetailPageView.d.ts +7 -3
  213. package/dist/features/products/components/ProductDetailPageView.js +8 -5
  214. package/dist/features/products/constants/action-defs.d.ts +1 -2
  215. package/dist/features/products/constants/action-defs.js +40 -43
  216. package/dist/features/products/repository/products.repository.d.ts +5 -1
  217. package/dist/features/products/repository/products.repository.js +23 -1
  218. package/dist/features/products/schemas/firestore.d.ts +7 -3
  219. package/dist/features/products/schemas/product-features.validators.js +3 -0
  220. package/dist/features/promotions/components/CouponCard.js +8 -7
  221. package/dist/features/scams/schemas/firestore.d.ts +15 -1
  222. package/dist/features/scams/schemas/report-form.d.ts +5 -5
  223. package/dist/features/scams/schemas/report-form.js +18 -3
  224. package/dist/features/search/action-index/derive.d.ts +49 -0
  225. package/dist/features/search/action-index/derive.js +121 -0
  226. package/dist/features/search/action-index/repository.d.ts +42 -0
  227. package/dist/features/search/action-index/repository.js +100 -0
  228. package/dist/features/search/action-index/settings-entries.d.ts +41 -0
  229. package/dist/features/search/action-index/settings-entries.js +268 -0
  230. package/dist/features/search/action-index/types.d.ts +81 -0
  231. package/dist/features/search/action-index/types.js +102 -0
  232. package/dist/features/search/action-index/validate-entry.d.ts +34 -0
  233. package/dist/features/search/action-index/validate-entry.js +114 -0
  234. package/dist/features/search/hooks/useNavSuggestions.d.ts +5 -1
  235. package/dist/features/search/hooks/useNavSuggestions.js +23 -3
  236. package/dist/features/search/repository/search.repository.js +3 -1
  237. package/dist/features/seller/actions/offer-actions.js +43 -24
  238. package/dist/features/seller/actions/seller-actions.js +29 -5
  239. package/dist/features/seller/components/CategoryChipPicker.d.ts +9 -0
  240. package/dist/features/seller/components/CategoryChipPicker.js +12 -0
  241. package/dist/features/seller/components/SellerAddressesView.js +5 -1
  242. package/dist/features/seller/components/SellerAnalyticsAlertsView.js +83 -43
  243. package/dist/features/seller/components/SellerArtView.d.ts +14 -7
  244. package/dist/features/seller/components/SellerArtView.js +4 -119
  245. package/dist/features/seller/components/SellerClassifiedView.d.ts +14 -7
  246. package/dist/features/seller/components/SellerClassifiedView.js +4 -124
  247. package/dist/features/seller/components/SellerCouponEditorView.d.ts +22 -1
  248. package/dist/features/seller/components/SellerCouponEditorView.js +91 -45
  249. package/dist/features/seller/components/SellerDigitalCodesView.d.ts +14 -7
  250. package/dist/features/seller/components/SellerDigitalCodesView.js +4 -126
  251. package/dist/features/seller/components/SellerListingTypeView.d.ts +66 -0
  252. package/dist/features/seller/components/SellerListingTypeView.js +277 -0
  253. package/dist/features/seller/components/SellerLiveView.d.ts +14 -7
  254. package/dist/features/seller/components/SellerLiveView.js +4 -126
  255. package/dist/features/seller/components/SellerSidebar.d.ts +3 -6
  256. package/dist/features/seller/components/SellerStickersView.d.ts +14 -7
  257. package/dist/features/seller/components/SellerStickersView.js +4 -119
  258. package/dist/features/seller/components/SellerSupportView.d.ts +31 -0
  259. package/dist/features/seller/components/SellerSupportView.js +100 -0
  260. package/dist/features/seller/components/index.d.ts +4 -8
  261. package/dist/features/seller/components/index.js +2 -4
  262. package/dist/features/seller/index.d.ts +0 -1
  263. package/dist/features/seller/index.js +0 -1
  264. package/dist/features/seller/schemas/coupon-form.d.ts +214 -0
  265. package/dist/features/seller/schemas/coupon-form.js +155 -23
  266. package/dist/features/seller/schemas/offer-forms.d.ts +16 -7
  267. package/dist/features/seller/schemas/offer-forms.js +28 -12
  268. package/dist/features/shell/FormShell.js +2 -2
  269. package/dist/features/shell/QuickFormDrawer.js +2 -2
  270. package/dist/features/shell/SectionForm.d.ts +19 -1
  271. package/dist/features/shell/SectionForm.js +104 -17
  272. package/dist/features/shell/build-sections.d.ts +23 -0
  273. package/dist/features/shell/build-sections.js +106 -8
  274. package/dist/features/shell/field-ui-meta.d.ts +44 -0
  275. package/dist/features/shell/field-ui-meta.js +14 -7
  276. package/dist/features/shell/form-sections.d.ts +46 -0
  277. package/dist/features/shell/form-sections.js +114 -0
  278. package/dist/features/shipments/components/AdminShipmentEditorView.js +87 -64
  279. package/dist/features/shipments/schemas/validation.d.ts +2 -2
  280. package/dist/features/shipments/schemas/validation.js +44 -13
  281. package/dist/features/store-extensions/schemas/custom-role-form.js +6 -2
  282. package/dist/features/store-extensions/schemas/listing-template-form.d.ts +7 -7
  283. package/dist/features/store-extensions/schemas/payout-method-form.js +14 -0
  284. package/dist/features/stores/actions/store-query-actions.js +3 -2
  285. package/dist/features/stores/api/[storeSlug]/auctions/route.js +3 -1
  286. package/dist/features/stores/api/[storeSlug]/products/route.js +3 -1
  287. package/dist/features/support/repository/support.repository.d.ts +21 -0
  288. package/dist/features/support/repository/support.repository.js +63 -0
  289. package/dist/features/support/schemas/firestore.d.ts +27 -2
  290. package/dist/features/support/schemas/firestore.js +2 -0
  291. package/dist/features/support/schemas/ticket-create-form.js +7 -0
  292. package/dist/features/tester/schemas/checklist-item-form.d.ts +43 -0
  293. package/dist/features/tester/schemas/checklist-item-form.js +109 -0
  294. package/dist/features/tester/seed-data/blog-tester-seed-data.js +2 -2
  295. package/dist/features/tester/seed-data/categories-tester-seed-data.js +2 -2
  296. package/dist/features/tester/seed-data/events-tester-seed-data.js +5 -5
  297. package/dist/features/tester/seed-data/orders-tester-seed-data.js +2 -2
  298. package/dist/features/tester/seed-data/products-tester-seed-data.js +48 -49
  299. package/dist/features/tester/seed-data/stores-tester-seed-data.js +3 -3
  300. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +275 -29
  301. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +48 -12
  302. package/dist/http/api-handler.js +2 -1
  303. package/dist/index.d.ts +24 -103
  304. package/dist/index.js +33 -141
  305. package/dist/jobs.d.ts +1 -1
  306. package/dist/jobs.js +1 -1
  307. package/dist/monitoring/browser.d.ts +0 -2
  308. package/dist/monitoring/browser.js +12 -1
  309. package/dist/monitoring/index.d.ts +0 -2
  310. package/dist/monitoring/index.js +0 -1
  311. package/dist/next/api/routeHandler.js +6 -3
  312. package/dist/next/index.d.ts +7 -2
  313. package/dist/next/index.js +36 -1
  314. package/dist/next/middleware/index.d.ts +0 -2
  315. package/dist/next/middleware/index.js +0 -1
  316. package/dist/next/routing/route-map.d.ts +8 -7
  317. package/dist/next/routing/route-map.js +10 -3
  318. package/dist/providers/db-firebase/admin.js +15 -1
  319. package/dist/providers/db-firebase/sieve.d.ts +22 -0
  320. package/dist/react/hooks/useListingTypeFlags.d.ts +1 -1
  321. package/dist/react/hooks/useListingTypeFlags.js +1 -1
  322. package/dist/react/hooks/usePendingFilters.js +5 -3
  323. package/dist/react/hooks/usePendingTable.js +15 -3
  324. package/dist/repositories/index.d.ts +0 -1
  325. package/dist/repositories/index.js +0 -1
  326. package/dist/schemas/registry.d.ts +197 -232
  327. package/dist/schemas/registry.js +5 -6
  328. package/dist/schemas/webhooks/razorpay.d.ts +50 -50
  329. package/dist/security/authorization.d.ts +9 -0
  330. package/dist/security/authorization.js +16 -2
  331. package/dist/security/browser.d.ts +1 -3
  332. package/dist/security/browser.js +5 -2
  333. package/dist/security/index.d.ts +1 -3
  334. package/dist/security/index.js +19 -2
  335. package/dist/security/pii-encrypt.js +16 -0
  336. package/dist/security/pii-schemas.d.ts +0 -14
  337. package/dist/security/pii-schemas.js +7 -15
  338. package/dist/seed/_helpers/category-forest.js +2 -2
  339. package/dist/seed/_helpers/media.d.ts +19 -0
  340. package/dist/seed/_helpers/media.js +75 -0
  341. package/dist/seed/blog-posts-seed-data.js +17 -17
  342. package/dist/seed/carousel-slides-seed-data.js +7 -7
  343. package/dist/seed/cart-seed-data.js +13 -13
  344. package/dist/seed/categories-seed-data.js +10 -10
  345. package/dist/seed/events-seed-data.js +24 -24
  346. package/dist/seed/factories/product.factory.js +4 -4
  347. package/dist/seed/factories/store.factory.js +3 -3
  348. package/dist/seed/factories/user.factory.js +2 -2
  349. package/dist/seed/grouped-listings-seed-data.js +11 -11
  350. package/dist/seed/homepage-sections-seed-data.js +2 -2
  351. package/dist/seed/index.d.ts +0 -1
  352. package/dist/seed/index.js +0 -1
  353. package/dist/seed/manifest.d.ts +1 -1
  354. package/dist/seed/manifest.js +0 -5
  355. package/dist/seed/notifications-seed-data.js +20 -1
  356. package/dist/seed/orders-seed-data.js +2 -2
  357. package/dist/seed/products-art-seed-data.js +16 -16
  358. package/dist/seed/products-auctions-seed-data.js +34 -34
  359. package/dist/seed/products-classifieds-seed-data.js +35 -37
  360. package/dist/seed/products-digital-codes-seed-data.js +20 -20
  361. package/dist/seed/products-live-items-seed-data.js +11 -11
  362. package/dist/seed/products-preorders-seed-data.js +13 -13
  363. package/dist/seed/products-prize-draws-seed-data.js +43 -43
  364. package/dist/seed/products-standard-seed-data.js +54 -54
  365. package/dist/seed/products-stickers-seed-data.js +15 -15
  366. package/dist/seed/reviews-seed-data.js +4 -4
  367. package/dist/seed/scammers-seed-data.js +3 -3
  368. package/dist/seed/site-settings-seed-data.js +11 -24
  369. package/dist/seed/store-extensions-seed-data.js +10 -10
  370. package/dist/seed/stores-seed-data.js +11 -11
  371. package/dist/seed/support-tickets-seed-data.d.ts +14 -0
  372. package/dist/seed/support-tickets-seed-data.js +20 -1
  373. package/dist/seed/users-seed-data.js +20 -20
  374. package/dist/server-entry.d.ts +0 -1
  375. package/dist/server-entry.js +0 -1
  376. package/dist/server.d.ts +9 -6
  377. package/dist/server.js +7 -13
  378. package/dist/styles.css +248 -68
  379. package/dist/tailwind-utilities.css +1 -1
  380. package/dist/tokens/themes/default-dark.js +2 -2
  381. package/dist/tokens/themes/default-light.js +2 -2
  382. package/dist/tokens/tokens.css +24 -4
  383. package/dist/ui/components/ActionRow.d.ts +50 -0
  384. package/dist/ui/components/ActionRow.js +53 -0
  385. package/dist/ui/components/ActionRow.style.css +145 -0
  386. package/dist/ui/components/Drawer.d.ts +10 -0
  387. package/dist/ui/components/Drawer.js +2 -1
  388. package/dist/ui/components/FilterDrawer.js +4 -1
  389. package/dist/ui/components/FilterDrawer.style.css +6 -12
  390. package/dist/ui/components/FormActionBar.js +14 -1
  391. package/dist/ui/components/FormActionBar.style.css +12 -11
  392. package/dist/ui/components/ListingLayout.js +8 -1
  393. package/dist/ui/components/ListingLayout.style.css +6 -13
  394. package/dist/ui/components/Modal.d.ts +15 -1
  395. package/dist/ui/components/Modal.js +17 -3
  396. package/dist/ui/components/QuickCreateModal.js +2 -2
  397. package/dist/ui/components/QuickCreateModal.style.css +78 -84
  398. package/dist/ui/components/RecordDetailModal.js +2 -2
  399. package/dist/ui/components/SideDrawer.d.ts +8 -0
  400. package/dist/ui/components/SideDrawer.js +2 -1
  401. package/dist/ui/components/SideDrawer.style.css +6 -3
  402. package/dist/ui/components/SideModal.d.ts +11 -1
  403. package/dist/ui/components/SideModal.js +3 -2
  404. package/dist/ui/components/SideModal.style.css +14 -0
  405. package/dist/ui/components/Typography.style.css +33 -24
  406. package/dist/ui/components/index.style.css +1 -0
  407. package/dist/ui/forms/FormShell.style.css +260 -311
  408. package/dist/ui/index.d.ts +2 -0
  409. package/dist/ui/index.js +1 -0
  410. package/dist/utils/index.d.ts +0 -1
  411. package/dist/utils/index.js +0 -1
  412. package/dist/validation/index.d.ts +1 -1
  413. package/dist/validation/index.js +1 -1
  414. package/dist/validation/schemas.d.ts +0 -19
  415. package/dist/validation/schemas.js +8 -19
  416. package/package.json +1 -1
  417. package/scripts/seed-cli.mjs +3 -6
@@ -15,7 +15,7 @@
15
15
  * WHAT: One schema per editor.
16
16
  *
17
17
  * EXPORTS:
18
- * adminAddressFormSchema, adminStoreUpdateSchema, announcementBarSchema,
18
+ * adminStoreUpdateSchema, announcementBarSchema,
19
19
  * and their inferred value types
20
20
  *
21
21
  * @tag domain:admin
@@ -27,60 +27,18 @@
27
27
  */
28
28
  import { z } from "zod";
29
29
  import { annotate } from "../../shell/field-ui-meta";
30
+ import { mediaUrlSchema } from "../../../validation/schemas";
31
+ import { StoreStatusValues } from "../../stores/schemas/firestore";
30
32
  const PHONE_RE = /^(\+?91[-\s]?)?[6-9]\d{9}$/;
31
- /** Indian PIN: six digits, never starting at zero. */
32
- const PIN_RE = /^[1-9]\d{5}$/;
33
- /**
34
- * An address written by an admin on someone's behalf.
33
+ /*
34
+ * `adminAddressFormSchema` is DELETED (W5 / D19).
35
35
  *
36
- * Shapes match `AddressDocument` (`addressLine1`, not `line1`) — deliberately
37
- * NOT `userAddressSchema`, which is the account-side view of the same data
38
- * under different field names. Reusing that one here would have meant
39
- * translating on every write.
36
+ * It was a twelfth restatement of the same eleven address fields, with an
37
+ * India-only `postalCode: /^\d{6}$/` on a form whose `country` was free text.
38
+ * The one address shape and the one country-aware postal rule now live in
39
+ * `features/addresses/schemas/address-form.ts`, and this editor imports
40
+ * `adminAddressCreateSchema` from there.
40
41
  */
41
- export const adminAddressFormSchema = z.object({
42
- ownerType: annotate(z.enum(["user", "store"]), {
43
- section: "owner", sectionLabel: "Belongs to", sectionRequired: true, quick: true, order: 1, row: "pair",
44
- }),
45
- ownerId: annotate(z.string().trim().min(1, "Choose who this address belongs to."), {
46
- section: "owner", quick: true, order: 2, row: "pair",
47
- }),
48
- label: annotate(z.string().trim().max(60, "Keep the label short — e.g. Home, Warehouse.").optional(), {
49
- section: "address", sectionLabel: "Address", order: 1, row: "pair",
50
- }),
51
- fullName: annotate(z.string().trim().min(2, "A recipient name is required.").max(120), {
52
- section: "address", sectionRequired: true, quick: true, order: 2, row: "pair",
53
- }),
54
- phone: annotate(z.string().trim().regex(PHONE_RE, "Enter a 10-digit Indian mobile number."), {
55
- section: "address", quick: true, order: 3, row: "pair",
56
- }),
57
- addressLine1: annotate(z.string().trim().min(3, "Street address is required.").max(200), {
58
- section: "address", quick: true, order: 4, row: "full",
59
- }),
60
- addressLine2: annotate(z.string().trim().max(200).optional(), {
61
- section: "address", order: 5, row: "full",
62
- }),
63
- landmark: annotate(z.string().trim().max(120).optional(), {
64
- section: "address", order: 6, row: "pair",
65
- }),
66
- city: annotate(z.string().trim().min(2, "City is required.").max(80), {
67
- section: "address", order: 7, row: "pair",
68
- }),
69
- state: annotate(z.string().trim().min(2, "State is required.").max(80), {
70
- section: "address", order: 8, row: "pair",
71
- }),
72
- // A wrong PIN is the single most common reason a parcel is undeliverable,
73
- // and it was previously any string at all.
74
- postalCode: annotate(z.string().trim().regex(PIN_RE, "Enter a 6-digit PIN code."), {
75
- section: "address", order: 9, row: "pair",
76
- }),
77
- country: annotate(z.string().trim().min(2).max(60), {
78
- section: "address", order: 10, row: "pair",
79
- }),
80
- isDefault: annotate(z.boolean().optional(), {
81
- section: "address", order: 11, row: "quarter",
82
- }),
83
- });
84
42
  /**
85
43
  * An admin changing a store's standing.
86
44
  *
@@ -90,8 +48,25 @@ export const adminAddressFormSchema = z.object({
90
48
  */
91
49
  export const adminStoreUpdateSchema = z
92
50
  .object({
93
- storeStatus: annotate(z.enum(["pending", "active", "suspended", "closed"]), {
94
- section: "standing", sectionLabel: "Store standing", sectionRequired: true, quick: true, order: 1, row: "pair",
51
+ /*
52
+ * 🛑 DERIVED from `StoreStatusValues`, never hand-written.
53
+ *
54
+ * This was `["pending","active","suspended","closed"]` — and `"closed"` is
55
+ * not a store status. The real union (`stores/schemas/firestore.ts:57`) is
56
+ * pending · active · suspended · **rejected**, which is what
57
+ * `AdminStoreEditorView`'s dropdown has always offered and what the API
58
+ * has always stored. So the schema declared a value nothing can produce and
59
+ * omitted the one the UI actually sends.
60
+ *
61
+ * It went unnoticed because the `<Form schema>` prop was never parsed —
62
+ * selecting "Rejected" reached the API unchecked. Under `<SectionForm>`,
63
+ * which parses on every change, it would have become a hard failure on a
64
+ * legitimate value. A fifth hand-written copy of this union is exactly how
65
+ * that happens again.
66
+ */
67
+ storeStatus: annotate(z.enum(Object.values(StoreStatusValues)), {
68
+ section: "standing", sectionLabel: "Store standing", sectionRequired: true,
69
+ quick: true, order: 1, row: "pair", kind: "select",
95
70
  }),
96
71
  isVerified: annotate(z.boolean().optional(), {
97
72
  section: "standing", order: 2, row: "quarter",
@@ -99,8 +74,15 @@ export const adminStoreUpdateSchema = z
99
74
  isFeatured: annotate(z.boolean().optional(), {
100
75
  section: "standing", order: 3, row: "quarter",
101
76
  }),
77
+ /*
78
+ * `when` mirrors the superRefine below, which is what stops the two from
79
+ * disagreeing. The page used to keep this textarea live at all times and
80
+ * then drop its value unless the status was exactly "suspended" — choose
81
+ * "rejected", write the reason, save, and it vanished silently.
82
+ */
102
83
  suspensionReason: annotate(z.string().trim().max(500).optional(), {
103
84
  section: "standing", order: 4, row: "full", kind: "textarea",
85
+ when: (v) => v.storeStatus === "suspended",
104
86
  }),
105
87
  capabilities: annotate(z.array(z.string().min(1)).max(50).optional(), {
106
88
  section: "capabilities", sectionLabel: "Capabilities", order: 1, row: "full", kind: "list",
@@ -139,3 +121,64 @@ export const announcementBarSchema = z.object({
139
121
  section: "announcement", order: 3, row: "full",
140
122
  }),
141
123
  });
124
+ /**
125
+ * A brand, as an admin edits it.
126
+ *
127
+ * Lifted out of `AdminBrandEditorView`, where it was declared locally and
128
+ * unannotated — so it could not drive a generated form, and, more to the point,
129
+ * it never ran: the submit handler checked `name.trim()` and called the
130
+ * mutation. `website: z.string().url()` had therefore never rejected anything,
131
+ * and the raw `<Input>`s it would have reported on carry no `name`, so
132
+ * `applyZodIssues` had nowhere to put an error even if it had.
133
+ *
134
+ * ## "Logo" is the cover image, and the labels used to say the opposite
135
+ *
136
+ * `logoURL` maps to `display.coverImage` — the brand page's full-bleed hero
137
+ * banner. The form once offered a "Logo" input beside a "Banner" input, where
138
+ * the first drove the banner and the second wrote `brandBannerImage`, a field
139
+ * with no reader anywhere (Root Cause #51). The dead field is gone and the
140
+ * label now describes what it controls.
141
+ */
142
+ export const brandFormSchema = z.object({
143
+ name: annotate(z.string().min(1, "Brand name is required").max(120), {
144
+ section: "basics", sectionLabel: "Brand", sectionRequired: true, quick: true,
145
+ order: 1, row: "pair", label: "Brand name",
146
+ }),
147
+ /*
148
+ * Derived from the name, and create-only.
149
+ *
150
+ * Slug immutability after creation is the convention every other taxonomy in
151
+ * this codebase follows (categories, bundles — Root Cause #39), and it is
152
+ * what keeps existing links and `brand:` product references resolving. The
153
+ * editor used to expose it as a free-text box on the EDIT form too, which is
154
+ * a live rename waiting to orphan a whole catalogue: `BrandDetailPageView`
155
+ * matches products by display NAME, and nothing re-points them.
156
+ */
157
+ slug: annotate(z.string().regex(/^[a-z0-9-]+$/i).optional().or(z.literal("")), {
158
+ section: "basics", order: 2, row: "pair", derived: true, tier: "t1-derive",
159
+ help: "Generated from the brand name.",
160
+ }),
161
+ description: annotate(z.string().max(2000).optional().or(z.literal("")), {
162
+ section: "basics", order: 3, row: "full", kind: "textarea",
163
+ }),
164
+ logoURL: annotate(mediaUrlSchema.optional().or(z.literal("")), {
165
+ section: "media", sectionLabel: "Cover image", order: 1, row: "full",
166
+ kind: "media", sectionKeepMounted: true, label: "Cover image",
167
+ help: "Renders as the full-bleed banner at the top of the brand page.",
168
+ }),
169
+ website: annotate(z.string().url("Enter a full URL, including https://").optional().or(z.literal("")), {
170
+ section: "identity", sectionLabel: "About this brand", order: 1, row: "pair",
171
+ inputType: "url",
172
+ }),
173
+ country: annotate(z.string().max(80).optional().or(z.literal("")), {
174
+ section: "identity", order: 2, row: "pair", label: "Country of origin",
175
+ }),
176
+ founded: annotate(z.number().int().min(1800, "That is earlier than any brand on record.").max(new Date().getFullYear(), "A founding year cannot be in the future.").optional(), { section: "identity", order: 3, row: "pair", kind: "number", label: "Founded year" }),
177
+ isActive: annotate(z.boolean(), {
178
+ section: "visibility", sectionLabel: "Visibility", order: 1, row: "quarter",
179
+ label: "Active",
180
+ }),
181
+ displayOrder: annotate(z.number().int().min(0).optional(), {
182
+ section: "visibility", order: 2, row: "pair", kind: "number", label: "Display order",
183
+ }),
184
+ });
@@ -34,6 +34,28 @@ export declare const employeeInviteSchema: z.ZodObject<{
34
34
  permissions?: string[] | undefined;
35
35
  }>;
36
36
  export type EmployeeInviteValues = z.infer<typeof employeeInviteSchema>;
37
+ /**
38
+ * Editing an existing team member's access.
39
+ *
40
+ * Derived by omission rather than declared, so the two cannot drift: it is the
41
+ * invite form minus the one field that only makes sense while inviting. The
42
+ * editor rendered the email input under `mode === "invite"` and parsed the
43
+ * full schema regardless, so an edit could only ever have failed validation on
44
+ * a control that was not on screen — which nothing noticed, because nothing
45
+ * parsed it.
46
+ */
47
+ export declare const employeePermissionsSchema: z.ZodObject<Omit<{
48
+ email: z.ZodString;
49
+ permissionGroup: z.ZodString;
50
+ permissions: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
51
+ }, "email">, "strip", z.ZodTypeAny, {
52
+ permissionGroup: string;
53
+ permissions?: string[] | undefined;
54
+ }, {
55
+ permissionGroup: string;
56
+ permissions?: string[] | undefined;
57
+ }>;
58
+ export type EmployeePermissionsValues = z.infer<typeof employeePermissionsSchema>;
37
59
  /**
38
60
  * The reason recorded against a hard ban.
39
61
  *
@@ -78,7 +100,13 @@ export declare const adminAdFormSchema: z.ZodEffects<z.ZodObject<{
78
100
  requiresConsent: z.ZodBoolean;
79
101
  startAt: z.ZodOptional<z.ZodString>;
80
102
  endAt: z.ZodOptional<z.ZodString>;
81
- creative: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodType<import("../../..").FirestoreValue, z.ZodTypeDef, import("../../..").FirestoreValue>>>;
103
+ creativeTitle: z.ZodUnion<[z.ZodOptional<z.ZodString>, z.ZodLiteral<"">]>;
104
+ creativeBody: z.ZodUnion<[z.ZodOptional<z.ZodString>, z.ZodLiteral<"">]>;
105
+ creativeImageUrl: z.ZodUnion<[z.ZodOptional<z.ZodString>, z.ZodLiteral<"">]>;
106
+ ctaLabel: z.ZodUnion<[z.ZodOptional<z.ZodString>, z.ZodLiteral<"">]>;
107
+ ctaHref: z.ZodUnion<[z.ZodOptional<z.ZodString>, z.ZodLiteral<"">]>;
108
+ adsenseSlot: z.ZodUnion<[z.ZodOptional<z.ZodString>, z.ZodLiteral<"">]>;
109
+ thirdPartyUrl: z.ZodUnion<[z.ZodOptional<z.ZodString>, z.ZodLiteral<"">]>;
82
110
  }, "strip", z.ZodTypeAny, {
83
111
  status: "draft" | "active" | "scheduled" | "paused";
84
112
  name: string;
@@ -88,7 +116,13 @@ export declare const adminAdFormSchema: z.ZodEffects<z.ZodObject<{
88
116
  requiresConsent: boolean;
89
117
  startAt?: string | undefined;
90
118
  endAt?: string | undefined;
91
- creative?: Record<string, import("../../..").FirestoreValue> | undefined;
119
+ creativeTitle?: string | undefined;
120
+ creativeBody?: string | undefined;
121
+ creativeImageUrl?: string | undefined;
122
+ ctaLabel?: string | undefined;
123
+ ctaHref?: string | undefined;
124
+ adsenseSlot?: string | undefined;
125
+ thirdPartyUrl?: string | undefined;
92
126
  }, {
93
127
  status: "draft" | "active" | "scheduled" | "paused";
94
128
  name: string;
@@ -98,7 +132,13 @@ export declare const adminAdFormSchema: z.ZodEffects<z.ZodObject<{
98
132
  requiresConsent: boolean;
99
133
  startAt?: string | undefined;
100
134
  endAt?: string | undefined;
101
- creative?: Record<string, import("../../..").FirestoreValue> | undefined;
135
+ creativeTitle?: string | undefined;
136
+ creativeBody?: string | undefined;
137
+ creativeImageUrl?: string | undefined;
138
+ ctaLabel?: string | undefined;
139
+ ctaHref?: string | undefined;
140
+ adsenseSlot?: string | undefined;
141
+ thirdPartyUrl?: string | undefined;
102
142
  }>, {
103
143
  status: "draft" | "active" | "scheduled" | "paused";
104
144
  name: string;
@@ -108,7 +148,13 @@ export declare const adminAdFormSchema: z.ZodEffects<z.ZodObject<{
108
148
  requiresConsent: boolean;
109
149
  startAt?: string | undefined;
110
150
  endAt?: string | undefined;
111
- creative?: Record<string, import("../../..").FirestoreValue> | undefined;
151
+ creativeTitle?: string | undefined;
152
+ creativeBody?: string | undefined;
153
+ creativeImageUrl?: string | undefined;
154
+ ctaLabel?: string | undefined;
155
+ ctaHref?: string | undefined;
156
+ adsenseSlot?: string | undefined;
157
+ thirdPartyUrl?: string | undefined;
112
158
  }, {
113
159
  status: "draft" | "active" | "scheduled" | "paused";
114
160
  name: string;
@@ -118,6 +164,12 @@ export declare const adminAdFormSchema: z.ZodEffects<z.ZodObject<{
118
164
  requiresConsent: boolean;
119
165
  startAt?: string | undefined;
120
166
  endAt?: string | undefined;
121
- creative?: Record<string, import("../../..").FirestoreValue> | undefined;
167
+ creativeTitle?: string | undefined;
168
+ creativeBody?: string | undefined;
169
+ creativeImageUrl?: string | undefined;
170
+ ctaLabel?: string | undefined;
171
+ ctaHref?: string | undefined;
172
+ adsenseSlot?: string | undefined;
173
+ thirdPartyUrl?: string | undefined;
122
174
  }>;
123
175
  export type AdminAdFormValues = z.infer<typeof adminAdFormSchema>;
@@ -22,18 +22,19 @@
22
22
  * @tag layer:schema
23
23
  * @tag pattern:none
24
24
  * @tag access:isomorphic
25
- * @tag consumers:AdminOrderEditorView,AdminEmployeeEditorView,AdminUsersView,AdminFeatureFlagsView,AdminAdEditorView
25
+ * @tag consumers:AdminOrderEditorView,AdminEmployeeEditorView,AdminUsersView,AdminAdEditorView
26
26
  * @tag sideEffects:none
27
27
  */
28
28
  import { z } from "zod";
29
29
  import { annotate } from "../../shell/field-ui-meta";
30
- import { firestoreValueSchema } from "../../../schemas/firestore-value";
30
+ import { normalizeError } from "../../../errors/normalize";
31
31
  import { OrderStatusValues } from "../../orders/schemas/firestore";
32
32
  /** Derived from the real 9-value union, never restated (Root Cause #36). */
33
33
  const orderStatusSchema = z.enum(Object.values(OrderStatusValues));
34
34
  export const adminOrderUpdateSchema = z.object({
35
35
  status: annotate(orderStatusSchema, {
36
- section: "status", sectionLabel: "Order", sectionRequired: true, quick: true, order: 1, row: "pair",
36
+ section: "status", sectionLabel: "Order", sectionRequired: true, quick: true,
37
+ order: 1, row: "pair", kind: "select",
37
38
  }),
38
39
  trackingNumber: annotate(z.string().trim().max(120).optional(), {
39
40
  section: "shipping", sectionLabel: "Shipping", order: 1, row: "pair",
@@ -51,7 +52,12 @@ export const adminOrderUpdateSchema = z.object({
51
52
  .number({ invalid_type_error: "Enter the refund amount as a number." })
52
53
  .positive("A refund must be greater than zero.")
53
54
  .max(10000000, "That looks like a typo — check the decimal point.")
54
- .optional(), { section: "shipping", order: 3, row: "pair", kind: "number" }),
55
+ .optional(), {
56
+ section: "shipping", order: 3, row: "pair", kind: "number",
57
+ // Only meaningful on a refunding status, which is the condition the page
58
+ // already used to decide whether to render the input.
59
+ when: (v) => v.status === "refunded" || v.status === "return_requested",
60
+ }),
55
61
  notes: annotate(z.string().trim().max(2000).optional(), {
56
62
  section: "shipping", order: 4, row: "full", kind: "textarea",
57
63
  }),
@@ -66,6 +72,17 @@ export const employeeInviteSchema = z.object({
66
72
  section: "member", order: 3, row: "full", kind: "list",
67
73
  }),
68
74
  });
75
+ /**
76
+ * Editing an existing team member's access.
77
+ *
78
+ * Derived by omission rather than declared, so the two cannot drift: it is the
79
+ * invite form minus the one field that only makes sense while inviting. The
80
+ * editor rendered the email input under `mode === "invite"` and parsed the
81
+ * full schema regardless, so an edit could only ever have failed validation on
82
+ * a control that was not on screen — which nothing noticed, because nothing
83
+ * parsed it.
84
+ */
85
+ export const employeePermissionsSchema = employeeInviteSchema.omit({ email: true });
69
86
  /**
70
87
  * The reason recorded against a hard ban.
71
88
  *
@@ -120,28 +137,95 @@ export const adminAdFormSchema = z
120
137
  endAt: annotate(z.string().optional(), {
121
138
  section: "schedule", order: 2, row: "pair", kind: "date",
122
139
  }),
123
- // Creative shape varies by provider, so it stays open — an AdSense slot and
124
- // a manual banner share almost no fields. Open to a Firestore VALUE tree,
125
- // not to anything: `z.unknown()` would pass a function straight to the
126
- // driver, which then throws at write time rather than at parse time.
127
- creative: annotate(z.record(firestoreValueSchema).optional(), {
128
- section: "creative", sectionLabel: "Creative", order: 1, row: "full", kind: "list",
140
+ /*
141
+ * The creative, FLAT.
142
+ *
143
+ * It was one open `z.record(firestoreValueSchema)` — "the shape varies by
144
+ * provider, so it stays open" — which is true of the STORED shape and was
145
+ * the wrong conclusion for the FORM. Open meant the seven inputs the
146
+ * editor renders were validated by nothing, and the two provider-specific
147
+ * ones were filtered out of the payload by a hand-written ternary instead
148
+ * of by the predicate that hides them. The nested shape is reassembled at
149
+ * the payload boundary, where the API wants it.
150
+ */
151
+ creativeTitle: annotate(z.string().trim().max(200).optional().or(z.literal("")), {
152
+ section: "creative", sectionLabel: "Creative", order: 1, row: "pair",
153
+ label: "Creative title",
154
+ }),
155
+ creativeBody: annotate(z.string().trim().max(500).optional().or(z.literal("")), {
156
+ section: "creative", order: 2, row: "pair", label: "Creative body",
157
+ }),
158
+ creativeImageUrl: annotate(z.string().trim().max(2000).optional().or(z.literal("")), {
159
+ section: "creative", order: 3, row: "pair", label: "Image URL", inputType: "url",
160
+ }),
161
+ ctaLabel: annotate(z.string().trim().max(80).optional().or(z.literal("")), {
162
+ section: "creative", order: 4, row: "pair", label: "CTA label",
163
+ }),
164
+ ctaHref: annotate(z.string().trim().max(2000).optional().or(z.literal("")), {
165
+ section: "creative", order: 5, row: "pair", label: "CTA URL",
166
+ }),
167
+ adsenseSlot: annotate(z.string().trim().max(120).optional().or(z.literal("")), {
168
+ section: "creative", order: 6, row: "pair", label: "AdSense slot",
169
+ when: (v) => v.provider === "adsense",
170
+ }),
171
+ thirdPartyUrl: annotate(z.string().trim().max(2000).optional().or(z.literal("")), {
172
+ section: "creative", order: 7, row: "pair", label: "Third-party URL",
173
+ when: (v) => v.provider === "thirdParty",
129
174
  }),
130
175
  })
131
176
  .superRefine((v, ctx) => {
177
+ const issue = (path, message) => ctx.addIssue({ code: z.ZodIssueCode.custom, path: [path], message });
132
178
  // A scheduled ad with no start date never runs, and nothing would say so.
133
179
  if (v.status === "scheduled" && !v.startAt) {
134
- ctx.addIssue({
135
- code: z.ZodIssueCode.custom,
136
- path: ["startAt"],
137
- message: "A scheduled ad needs a start date.",
138
- });
180
+ issue("startAt", "A scheduled ad needs a start date.");
139
181
  }
140
182
  if (v.startAt && v.endAt && v.endAt <= v.startAt) {
141
- ctx.addIssue({
142
- code: z.ZodIssueCode.custom,
143
- path: ["endAt"],
144
- message: "The end date must be after the start date.",
145
- });
183
+ issue("endAt", "The end date must be after the start date.");
184
+ }
185
+ /*
186
+ * The three provider rules, moved off the page's `publishIssues` list.
187
+ *
188
+ * There they were strings in a warning banner that only appeared once the
189
+ * status was already `active` or `scheduled` — so a DRAFT AdSense ad could
190
+ * be saved with no slot, and the omission surfaced later, as a block on
191
+ * publishing, far from the empty field. Stated here they reach the field
192
+ * that is wrong, whatever the status.
193
+ *
194
+ * The rest of that list stays on the page: it depends on the live
195
+ * placements and on whether the provider's credentials are configured,
196
+ * neither of which a schema can see.
197
+ */
198
+ if (v.provider === "manual") {
199
+ const hasCreative = v.creativeTitle?.trim() ||
200
+ v.creativeBody?.trim() ||
201
+ v.creativeImageUrl?.trim() ||
202
+ v.ctaHref?.trim();
203
+ if (!hasCreative) {
204
+ issue("creativeTitle", "A manual ad needs at least one of: title, body, image or CTA URL.");
205
+ }
206
+ }
207
+ if (v.provider === "adsense" && !v.adsenseSlot?.trim()) {
208
+ issue("adsenseSlot", "An AdSense ad needs a slot id.");
209
+ }
210
+ if (v.provider === "thirdParty") {
211
+ const url = v.thirdPartyUrl?.trim();
212
+ if (!url) {
213
+ issue("thirdPartyUrl", "A third-party ad needs a URL.");
214
+ }
215
+ else {
216
+ let parsed = null;
217
+ try {
218
+ parsed = new URL(url);
219
+ }
220
+ catch (err) {
221
+ void normalizeError(err);
222
+ parsed = null;
223
+ }
224
+ if (!parsed)
225
+ issue("thirdPartyUrl", "That is not a valid URL.");
226
+ else if (parsed.protocol !== "https:") {
227
+ issue("thirdPartyUrl", "A third-party ad URL must use https.");
228
+ }
229
+ }
146
230
  }
147
231
  });
@@ -89,8 +89,15 @@ export const whatsappSettingsSchema = z.object({
89
89
  * `NaN` written to the entry.
90
90
  */
91
91
  export const lotteryPullSchema = z.object({
92
+ /*
93
+ * Context, not input. Whether this pull belongs to an event or a product is
94
+ * decided by the page that mounts the form, so rendering a picker for it
95
+ * would offer the user a choice that can only be wrong. `t2-server` keeps it
96
+ * in the parsed payload and out of the UI.
97
+ */
92
98
  sourceType: annotate(z.enum(["event", "product"]), {
93
99
  section: "entry", sectionLabel: "Entry", sectionRequired: true, quick: true, order: 1, row: "pair",
100
+ derived: true, tier: "t2-server",
94
101
  }),
95
102
  transactionId: annotate(z.string().trim().min(4, "Enter the payment reference from your app.").max(120), { section: "entry", quick: true, order: 2, row: "pair" }),
96
103
  paymentTime: annotate(z.string().trim().min(1, "When did you pay?").refine((v) => !Number.isNaN(Date.parse(v)), "That isn't a valid date and time."), { section: "entry", quick: true, order: 3, row: "pair", kind: "date" }),
@@ -79,54 +79,6 @@ export declare const notificationQueryHelpers: {
79
79
  readonly unread: (userId: string) => readonly [readonly ["userId", "==", string], readonly ["isRead", "==", false]];
80
80
  readonly byType: (type: NotificationType) => readonly ["type", "==", "system" | "welcome" | "promotion" | "order_placed" | "order_confirmed" | "order_shipped" | "order_delivered" | "order_cancelled" | "bid_placed" | "bid_outbid" | "bid_won" | "bid_lost" | "auction_ended" | "review_approved" | "review_replied" | "product_available" | "account_action" | "offer_received" | "offer_responded" | "offer_expired" | "offer_counter_accepted" | "refund_initiated" | "prize_won" | "prize_reveal_expired" | "emi_installment_due_soon" | "emi_installment_overdue" | "payment_review" | "catalogue_images_stale"];
81
81
  };
82
- export interface ChatRoomDocument extends BaseDocument {
83
- buyerId: string;
84
- ownerId: string;
85
- orderId: string;
86
- productId?: string;
87
- productTitle?: string;
88
- buyerName: string;
89
- ownerName: string;
90
- lastMessage?: string;
91
- lastMessageAt?: Date;
92
- /** UIDs of participants who soft-deleted this room on their side. */
93
- deletedBy: string[];
94
- /** True for admin-created group chats (> 2 participants). */
95
- isGroup: boolean;
96
- /** All participant UIDs. For 1-1 rooms: [buyerId, ownerId]. */
97
- participantIds: string[];
98
- /** Set by admin to permanently revoke all access. */
99
- adminDeleted: boolean;
100
- }
101
- export declare const CHAT_ROOM_COLLECTION: "chatRooms";
102
- export declare const CHAT_ROOM_INDEXED_FIELDS: readonly ["buyerId", "ownerId", "orderId", "participantIds", "adminDeleted", "updatedAt"];
103
- export declare const CHAT_ROOM_FIELDS: {
104
- readonly ID: "id";
105
- readonly BUYER_ID: "buyerId";
106
- readonly OWNER_ID: "ownerId";
107
- readonly ORDER_ID: "orderId";
108
- readonly PRODUCT_ID: "productId";
109
- readonly PRODUCT_TITLE: "productTitle";
110
- readonly BUYER_NAME: "buyerName";
111
- readonly OWNER_NAME: "ownerName";
112
- readonly LAST_MESSAGE: "lastMessage";
113
- readonly LAST_MESSAGE_AT: "lastMessageAt";
114
- readonly CREATED_AT: "createdAt";
115
- readonly UPDATED_AT: "updatedAt";
116
- readonly DELETED_BY: "deletedBy";
117
- readonly IS_GROUP: "isGroup";
118
- readonly PARTICIPANT_IDS: "participantIds";
119
- readonly ADMIN_DELETED: "adminDeleted";
120
- };
121
- export declare const DEFAULT_CHAT_ROOM_DATA: Omit<ChatRoomDocument, "id" | "createdAt" | "updatedAt" | "lastMessage" | "lastMessageAt" | "productId" | "productTitle">;
122
- export type ChatRoomCreateInput = Omit<ChatRoomDocument, "id" | "createdAt" | "updatedAt" | "lastMessage" | "lastMessageAt" | "deletedBy" | "adminDeleted">;
123
- export type ChatRoomUpdateInput = Pick<ChatRoomDocument, "lastMessage" | "lastMessageAt" | "updatedAt">;
124
- export declare const chatRoomQueryHelpers: {
125
- readonly byBuyer: (buyerId: string) => readonly ["buyerId", "==", string];
126
- readonly byOwner: (ownerId: string) => readonly ["ownerId", "==", string];
127
- readonly byOrder: (orderId: string) => readonly ["orderId", "==", string];
128
- readonly active: () => readonly ["adminDeleted", "==", false];
129
- };
130
82
  export interface TrustBarItem {
131
83
  icon: string;
132
84
  label: string;
@@ -381,6 +333,32 @@ export interface SiteSettingsDocument extends BaseDocument {
381
333
  codEnabled: boolean;
382
334
  /** Tier PP — cart total (rupees) at/above which checkout requires OTP verification. Applies to all payment methods except COD. Optional — falls back to no OTP gate when unset. */
383
335
  otpCheckoutThreshold?: number;
336
+ /**
337
+ * Phone-number OTP verification during signup/checkout. Real per-SMS cost
338
+ * via the Firebase phone-auth quota, so it stays OFF by default.
339
+ *
340
+ * Toggling it false->true resets every user's `phoneVerified` and clears
341
+ * rate-limit state via the `resetOtpVerification` job — a verification that
342
+ * happened while the gate was off was not a verification.
343
+ *
344
+ * Was `featureFlags.smsVerification`. It is a real setting with real cost
345
+ * and a real side effect, which is why it survived that group's deletion.
346
+ */
347
+ smsVerification?: boolean;
348
+ /**
349
+ * Lets an admin place an order skipping OTP and payment capture.
350
+ *
351
+ * Kept as a SETTING rather than folded into the `admin:checkout:bypass`
352
+ * permission, and the distinction matters: admins bypass every permission
353
+ * check (`isEffectiveAdminUser`), so a permission alone would turn this on
354
+ * for every admin the moment it shipped. Two independent gates — the
355
+ * permission decides WHO may use it, this decides WHETHER it is available
356
+ * at all — preserve the default-off posture a checkout bypass needs.
357
+ *
358
+ * Writable only through `/api/admin/checkout-bypass`, which logs actorUid
359
+ * and reason on every use (audit-checkout-bypass rule 1).
360
+ */
361
+ adminCheckoutBypass?: boolean;
384
362
  };
385
363
  /** Site-wide EMI (installment) settings. A seller must ALSO have `StoreDocument.emiEnabled` on for EMI to appear at checkout for their items. */
386
364
  emi: {
@@ -501,44 +479,28 @@ export interface SiteSettingsDocument extends BaseDocument {
501
479
  icon: string;
502
480
  enabled: boolean;
503
481
  }[];
504
- featureFlags: {
505
- chats: boolean;
506
- smsVerification: boolean;
507
- translations: boolean;
508
- wishlists: boolean;
509
- auctions: boolean;
510
- reviews: boolean;
511
- events: boolean;
512
- blog: boolean;
513
- coupons: boolean;
514
- notifications: boolean;
515
- sellerRegistration: boolean;
516
- preOrders: boolean;
517
- /**
518
- * Buyer price negotiation (Make an Offer / counter-offer).
519
- *
520
- * The global kill switch. Per-listing opt-in still applies on top of it via
521
- * `ProductDocument.allowOffers`, and only certain listing types support
522
- * offers at all (`LISTING_TYPE_CAPABILITIES.canMakeOffer`) — a product needs
523
- * all three to show the CTA.
524
- *
525
- * Guards NEW offers only. Switching it off must not strand in-flight ones:
526
- * sellers keep responding, buyers keep checking out accepted offers, and
527
- * both dashboards stay reachable.
528
- */
529
- offers: boolean;
530
- /** When true, admin users see a bypass button in checkout that skips OTP and payment. Server-enforced. */
531
- adminCheckoutBypass?: boolean;
532
- listingTypes?: {
533
- standard?: boolean;
534
- auction?: boolean;
535
- "pre-order"?: boolean;
536
- "prize-draw"?: boolean;
537
- bundle?: boolean;
538
- classified?: boolean;
539
- "digital-code"?: boolean;
540
- live?: boolean;
541
- };
482
+ /**
483
+ * Which listing and category types the marketplace offers.
484
+ *
485
+ * 🛑 This is a PRODUCT CONTROL, not a feature flag. It was
486
+ * `featureFlags.listingTypes` / `.categoryTypes` until 2026-08-29, when the
487
+ * `featureFlags` group was deleted: 11 of its 14 keys had zero readers, and
488
+ * the survivors were not flags at all. A flag is a temporary switch around
489
+ * unfinished work; "we don't sell live animals" is a standing decision about
490
+ * the catalogue, and it belongs somewhere an admin can find it.
491
+ *
492
+ * Disabled types are hidden from every listing surface and rejected on
493
+ * create/add-to-cart via `isListingTypeEnabled` / `isCategoryTypeEnabled`.
494
+ *
495
+ * ⚠️ `listingTypes` is DELIBERATELY optional-per-key and absent-means-enabled.
496
+ * `ALL_LISTING_TYPES_MAP` (`_internal/shared/listing-types/feature-flags.ts`)
497
+ * is the `Record<ListingType, true>` that makes omitting a union member a
498
+ * compile error — this interface is not, and historically drifted: it still
499
+ * listed 8 types after the union reached 10 (`art` and `stickers` missing),
500
+ * which is Root Cause #58's shape. Add new types to that Record, not here.
501
+ */
502
+ listings?: {
503
+ listingTypes?: Partial<Record<string, boolean>>;
542
504
  categoryTypes?: {
543
505
  category?: boolean;
544
506
  sublisting?: boolean;
@@ -693,14 +655,6 @@ export interface SiteSettingsDocument extends BaseDocument {
693
655
  */
694
656
  notificationChannels?: NotificationChannelConfig;
695
657
  }
696
- export type FeatureFlagKey = keyof SiteSettingsDocument["featureFlags"];
697
- export interface FeatureFlagMeta {
698
- key: FeatureFlagKey;
699
- labelKey: string;
700
- descKey: string;
701
- icon: string;
702
- category: "platform" | "payment";
703
- }
704
658
  export declare const SITE_SETTINGS_COLLECTION: "siteSettings";
705
659
  export declare const SITE_SETTINGS_INDEXED_FIELDS: readonly [];
706
660
  /**
@@ -714,4 +668,3 @@ export declare const DEFAULT_SITE_SETTINGS_DATA: Partial<SiteSettingsDocument>;
714
668
  export declare const SITE_SETTINGS_PUBLIC_FIELDS: readonly ["siteName", "motto", "logo", "background", "contact.email", "contact.phone", "payment", "commissions", "socialLinks", "seo", "features", "featureFlags", "faq.variables", "announcementBar"];
715
669
  export type SiteSettingsUpdateInput = Partial<Omit<SiteSettingsDocument, "id" | "createdAt" | "updatedAt">>;
716
670
  export declare const DEFAULT_TRUST_BAR_ITEMS: TrustBarItem[];
717
- export declare const FEATURE_FLAG_META: FeatureFlagMeta[];