@mohasinac/appkit 4.53.0 → 4.53.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 (500) hide show
  1. package/dist/.build-stamp.json +3 -3
  2. package/dist/_internal/client/scaffolds/AppShell.js +1 -1
  3. package/dist/_internal/server/features/auctions/og.d.ts +3 -1
  4. package/dist/_internal/server/features/auctions/og.js +3 -1
  5. package/dist/_internal/server/features/bundles/actions.js +1 -1
  6. package/dist/_internal/server/features/business-documents/download.d.ts +41 -0
  7. package/dist/_internal/server/features/business-documents/download.js +91 -0
  8. package/dist/_internal/server/features/categories/adapters.d.ts +1 -1
  9. package/dist/_internal/server/features/categories/adapters.js +10 -0
  10. package/dist/_internal/server/features/checkout/actions.d.ts +14 -0
  11. package/dist/_internal/server/features/checkout/actions.js +106 -12
  12. package/dist/_internal/server/features/checkout/bundle-expansion.js +17 -0
  13. package/dist/_internal/server/features/checkout/data.d.ts +22 -0
  14. package/dist/_internal/server/features/checkout/group-rule-revalidation.d.ts +34 -0
  15. package/dist/_internal/server/features/checkout/group-rule-revalidation.js +124 -0
  16. package/dist/_internal/server/features/checkout/supplier-identity.d.ts +55 -0
  17. package/dist/_internal/server/features/checkout/supplier-identity.js +81 -0
  18. package/dist/_internal/server/features/classified/metadata.js +1 -1
  19. package/dist/_internal/server/features/classified/og.d.ts +3 -1
  20. package/dist/_internal/server/features/classified/og.js +3 -1
  21. package/dist/_internal/server/features/digital-code/metadata.js +1 -1
  22. package/dist/_internal/server/features/digital-code/og.d.ts +3 -1
  23. package/dist/_internal/server/features/digital-code/og.js +3 -1
  24. package/dist/_internal/server/features/digital-code/pool.d.ts +19 -4
  25. package/dist/_internal/server/features/digital-code/pool.js +19 -4
  26. package/dist/_internal/server/features/live/metadata.js +1 -1
  27. package/dist/_internal/server/features/live/og.d.ts +3 -1
  28. package/dist/_internal/server/features/live/og.js +3 -1
  29. package/dist/_internal/server/features/messages/actions.js +1 -1
  30. package/dist/_internal/server/features/parts/og.js +1 -1
  31. package/dist/_internal/server/features/pre-orders/og.d.ts +3 -1
  32. package/dist/_internal/server/features/pre-orders/og.js +3 -1
  33. package/dist/_internal/server/features/price-index/search.d.ts +18 -0
  34. package/dist/_internal/server/features/price-index/search.js +47 -7
  35. package/dist/_internal/server/features/prize-draws/og.d.ts +3 -1
  36. package/dist/_internal/server/features/prize-draws/og.js +3 -1
  37. package/dist/_internal/server/features/products/group-members.d.ts +26 -0
  38. package/dist/_internal/server/features/products/group-members.js +7 -1
  39. package/dist/_internal/server/features/products/og.d.ts +3 -1
  40. package/dist/_internal/server/features/products/og.js +3 -1
  41. package/dist/_internal/server/features/search/scoped-sources.d.ts +26 -0
  42. package/dist/_internal/server/features/search/scoped-sources.js +252 -0
  43. package/dist/_internal/server/features/search/search-everything.d.ts +57 -0
  44. package/dist/_internal/server/features/search/search-everything.js +70 -20
  45. package/dist/_internal/server/features/seo/sitemap.js +6 -0
  46. package/dist/_internal/server/features/shared/listing-adapters.js +4 -2
  47. package/dist/_internal/server/features/sticker-trace/adapters.d.ts +11 -0
  48. package/dist/_internal/server/features/sticker-trace/adapters.js +1 -0
  49. package/dist/_internal/server/features/sticker-trace/promote-to-listings.d.ts +26 -0
  50. package/dist/_internal/server/features/sticker-trace/promote-to-listings.js +264 -0
  51. package/dist/_internal/server/features/sticker-trace/sheet-actions.d.ts +3 -1
  52. package/dist/_internal/server/features/sticker-trace/sheet-actions.js +32 -0
  53. package/dist/_internal/server/features/sticker-trace/storage.d.ts +20 -1
  54. package/dist/_internal/server/features/sticker-trace/storage.js +20 -1
  55. package/dist/_internal/server/features/stores/adapters.d.ts +1 -1
  56. package/dist/_internal/server/features/stores/adapters.js +16 -0
  57. package/dist/_internal/server/features/stores/index.d.ts +1 -0
  58. package/dist/_internal/server/features/stores/index.js +1 -0
  59. package/dist/_internal/server/features/stores/tabs.d.ts +25 -0
  60. package/dist/_internal/server/features/stores/tabs.js +122 -0
  61. package/dist/_internal/shared/checkout/rules/_defaults.js +0 -2
  62. package/dist/_internal/shared/checkout/rules/_limits.d.ts +14 -1
  63. package/dist/_internal/shared/checkout/rules/_limits.js +14 -1
  64. package/dist/_internal/shared/checkout/rules/_registry.js +2 -0
  65. package/dist/_internal/shared/checkout/rules/auction.rule.js +9 -1
  66. package/dist/_internal/shared/checkout/rules/bundle.rule.js +13 -0
  67. package/dist/_internal/shared/checkout/rules/index.d.ts +2 -0
  68. package/dist/_internal/shared/checkout/rules/index.js +9 -0
  69. package/dist/_internal/shared/checkout/rules/offer.rule.js +0 -1
  70. package/dist/_internal/shared/checkout/rules/payment-gate.d.ts +26 -0
  71. package/dist/_internal/shared/checkout/rules/payment-gate.js +133 -0
  72. package/dist/_internal/shared/checkout/rules/prize-draw.rule.js +29 -8
  73. package/dist/_internal/shared/checkout/rules/spares.rule.d.ts +16 -0
  74. package/dist/_internal/shared/checkout/rules/spares.rule.js +5 -0
  75. package/dist/_internal/shared/checkout/rules/types.d.ts +26 -2
  76. package/dist/_internal/shared/config/schema.d.ts +122 -0
  77. package/dist/_internal/shared/features/cart/schema.js +3 -2
  78. package/dist/_internal/shared/features/products/group-rules.d.ts +75 -0
  79. package/dist/_internal/shared/features/products/group-rules.js +142 -0
  80. package/dist/_internal/shared/listing-types/_registry.d.ts +24 -0
  81. package/dist/_internal/shared/listing-types/_registry.js +39 -1
  82. package/dist/_internal/shared/listing-types/art/config.d.ts +1 -0
  83. package/dist/_internal/shared/listing-types/art/config.js +2 -0
  84. package/dist/_internal/shared/listing-types/auction/config.d.ts +1 -0
  85. package/dist/_internal/shared/listing-types/auction/config.js +2 -0
  86. package/dist/_internal/shared/listing-types/availability.js +48 -0
  87. package/dist/_internal/shared/listing-types/capabilities.js +19 -0
  88. package/dist/_internal/shared/listing-types/classified/config.d.ts +1 -0
  89. package/dist/_internal/shared/listing-types/classified/config.js +2 -0
  90. package/dist/_internal/shared/listing-types/digital-code/config.d.ts +1 -0
  91. package/dist/_internal/shared/listing-types/digital-code/config.js +2 -0
  92. package/dist/_internal/shared/listing-types/feature-flags.js +1 -0
  93. package/dist/_internal/shared/listing-types/live/config.d.ts +1 -0
  94. package/dist/_internal/shared/listing-types/live/config.js +2 -0
  95. package/dist/_internal/shared/listing-types/pre-order/config.d.ts +1 -0
  96. package/dist/_internal/shared/listing-types/pre-order/config.js +2 -0
  97. package/dist/_internal/shared/listing-types/prize-draw/config.d.ts +1 -0
  98. package/dist/_internal/shared/listing-types/prize-draw/config.js +2 -0
  99. package/dist/_internal/shared/listing-types/spares/config.d.ts +74 -0
  100. package/dist/_internal/shared/listing-types/spares/config.js +60 -0
  101. package/dist/_internal/shared/listing-types/spares/ctas.d.ts +1 -0
  102. package/dist/_internal/shared/listing-types/spares/ctas.js +4 -0
  103. package/dist/_internal/shared/listing-types/spares/og.js +1 -0
  104. package/dist/_internal/shared/listing-types/spares/schema.d.ts +2 -0
  105. package/dist/_internal/shared/listing-types/spares/schema.js +3 -0
  106. package/dist/_internal/shared/listing-types/spares/seed-factory.d.ts +1 -0
  107. package/dist/_internal/shared/listing-types/spares/seed-factory.js +1 -0
  108. package/dist/_internal/shared/listing-types/standard/config.d.ts +1 -0
  109. package/dist/_internal/shared/listing-types/standard/config.js +2 -0
  110. package/dist/_internal/shared/listing-types/stickers/config.d.ts +1 -0
  111. package/dist/_internal/shared/listing-types/stickers/config.js +2 -0
  112. package/dist/_internal/shared/search/match.d.ts +11 -0
  113. package/dist/_internal/shared/search/match.js +2 -1
  114. package/dist/_internal/shared/search/to-groups.d.ts +52 -0
  115. package/dist/_internal/shared/search/to-groups.js +141 -0
  116. package/dist/client.d.ts +8 -2
  117. package/dist/client.js +4 -1
  118. package/dist/constants/api-endpoints.d.ts +39 -15
  119. package/dist/constants/api-endpoints.js +28 -5
  120. package/dist/constants/cache-invalidation.js +3 -1
  121. package/dist/constants/field-names.d.ts +6 -0
  122. package/dist/constants/field-names.js +6 -0
  123. package/dist/features/about/components/PolicyPageView.d.ts +22 -2
  124. package/dist/features/about/components/PolicyPageView.js +14 -2
  125. package/dist/features/about/components/PublicProfileView.js +2 -1
  126. package/dist/features/about/components/ShippingPolicyView.js +42 -2
  127. package/dist/features/account/components/NotificationBell.js +1 -1
  128. package/dist/features/account/hooks/useProfileStats.js +5 -1
  129. package/dist/features/addresses/repository/addresses.repository.d.ts +16 -0
  130. package/dist/features/addresses/repository/addresses.repository.js +21 -0
  131. package/dist/features/admin/actions/admin-actions.js +16 -1
  132. package/dist/features/admin/components/AdminCategoryEditorView.js +19 -2
  133. package/dist/features/admin/components/AdminNavigationView.js +1 -1
  134. package/dist/features/admin/components/AdminPageHeader.js +1 -1
  135. package/dist/features/admin/components/AdminProductEditorView.js +17 -2
  136. package/dist/features/admin/components/AdminSidebar.js +1 -1
  137. package/dist/features/admin/components/AdminSiteSettingsView.js +39 -8
  138. package/dist/features/admin/components/AdminSparesView.d.ts +12 -0
  139. package/dist/features/admin/components/AdminSparesView.js +30 -0
  140. package/dist/features/admin/components/AdminUsersView.js +9 -7
  141. package/dist/features/admin/components/index.d.ts +2 -0
  142. package/dist/features/admin/components/index.js +1 -0
  143. package/dist/features/admin/components/sections/adminSectionsTypes.js +7 -0
  144. package/dist/features/admin/constants/filter-tabs.d.ts +3 -0
  145. package/dist/features/admin/constants/filter-tabs.js +1 -0
  146. package/dist/features/admin/schemas/firestore.d.ts +26 -2
  147. package/dist/features/auctions/components/AuctionDetailPageView.js +4 -11
  148. package/dist/features/auth/repository/user.repository.d.ts +13 -0
  149. package/dist/features/auth/repository/user.repository.js +28 -0
  150. package/dist/features/auth/schemas/firestore.d.ts +2 -0
  151. package/dist/features/auth/schemas/firestore.js +2 -0
  152. package/dist/features/business-documents/repository/business-documents.repository.d.ts +58 -0
  153. package/dist/features/business-documents/repository/business-documents.repository.js +54 -0
  154. package/dist/features/business-documents/schemas/firestore.d.ts +105 -0
  155. package/dist/features/business-documents/schemas/firestore.js +75 -0
  156. package/dist/features/cart/actions/cart-actions.js +83 -6
  157. package/dist/features/cart/repository/cart.repository.js +32 -4
  158. package/dist/features/cart/schemas/firestore.d.ts +20 -0
  159. package/dist/features/cart/schemas/index.d.ts +2 -2
  160. package/dist/features/catalogue/components/PublicCatalogueItemDetailView.js +1 -1
  161. package/dist/features/categories/api/[id]/price-guidance/route.d.ts +42 -0
  162. package/dist/features/categories/api/[id]/price-guidance/route.js +113 -0
  163. package/dist/features/categories/components/BrandDetailPageView.js +19 -3
  164. package/dist/features/categories/components/BrandDetailTabs.js +10 -0
  165. package/dist/features/categories/components/CategoriesIndexListing.js +23 -8
  166. package/dist/features/categories/components/CategoryDetailPageView.js +141 -14
  167. package/dist/features/categories/components/CategoryDetailTabs.js +12 -0
  168. package/dist/features/categories/components/CategoryGrid.js +10 -1
  169. package/dist/features/categories/components/PriceGuidanceHint.d.ts +29 -0
  170. package/dist/features/categories/components/PriceGuidanceHint.js +61 -0
  171. package/dist/features/categories/components/SubcategoryCardRow.d.ts +27 -0
  172. package/dist/features/categories/components/SubcategoryCardRow.js +98 -0
  173. package/dist/features/categories/constants/category-tabs.d.ts +20 -25
  174. package/dist/features/categories/constants/category-tabs.js +22 -39
  175. package/dist/features/categories/repository/categories.repository.d.ts +12 -0
  176. package/dist/features/categories/repository/categories.repository.js +20 -0
  177. package/dist/features/categories/schemas/firestore.d.ts +22 -1
  178. package/dist/features/categories/schemas/firestore.js +10 -0
  179. package/dist/features/categories/schemas/index.d.ts +6 -0
  180. package/dist/features/categories/schemas/index.js +2 -0
  181. package/dist/features/categories/types/index.d.ts +8 -0
  182. package/dist/features/categories/utils/taxonomy-visual.d.ts +16 -3
  183. package/dist/features/categories/utils/taxonomy-visual.js +26 -10
  184. package/dist/features/classified/components/ClassifiedDetailPageView.js +4 -9
  185. package/dist/features/contact/components/ContactPageView.d.ts +33 -1
  186. package/dist/features/contact/components/ContactPageView.js +58 -28
  187. package/dist/features/digital-codes/components/DigitalCodeDetailPageView.js +4 -9
  188. package/dist/features/grouped/components/GroupedListingDetailView.js +9 -1
  189. package/dist/features/grouped/schemas/firestore.d.ts +5 -0
  190. package/dist/features/homepage/actions/homepage-section-actions.d.ts +3 -3
  191. package/dist/features/homepage/components/CollectionCardsSection.d.ts +28 -6
  192. package/dist/features/homepage/components/CollectionCardsSection.js +43 -8
  193. package/dist/features/homepage/components/HowItWorksSection.d.ts +23 -6
  194. package/dist/features/homepage/components/HowItWorksSection.js +4 -4
  195. package/dist/features/homepage/components/PromoGrid.d.ts +31 -2
  196. package/dist/features/homepage/components/PromoGrid.js +12 -3
  197. package/dist/features/homepage/components/TestimonialsCarousel.d.ts +34 -2
  198. package/dist/features/homepage/components/TestimonialsCarousel.js +1 -1
  199. package/dist/features/homepage/components/index.d.ts +0 -20
  200. package/dist/features/homepage/components/index.js +0 -11
  201. package/dist/features/homepage/index.d.ts +0 -2
  202. package/dist/features/homepage/index.js +0 -2
  203. package/dist/features/homepage/lib/section-renderer.d.ts +9 -0
  204. package/dist/features/homepage/lib/section-renderer.js +202 -58
  205. package/dist/features/homepage/repository/homepage-sections.repository.d.ts +35 -3
  206. package/dist/features/homepage/repository/homepage-sections.repository.js +58 -8
  207. package/dist/features/homepage/schemas/firestore.d.ts +106 -3
  208. package/dist/features/homepage/schemas/firestore.js +32 -2
  209. package/dist/features/homepage/schemas/index.d.ts +36 -7
  210. package/dist/features/homepage/schemas/index.js +39 -27
  211. package/dist/features/homepage/server.d.ts +0 -3
  212. package/dist/features/homepage/server.js +0 -3
  213. package/dist/features/homepage/types/index.d.ts +0 -47
  214. package/dist/features/homepage/types/index.js +49 -0
  215. package/dist/features/layout/AppLayoutShell.js +1 -1
  216. package/dist/features/layout/BottomNavItem.js +1 -1
  217. package/dist/features/layout/BottomSheet.js +1 -1
  218. package/dist/features/layout/TitleBarLayout.js +1 -1
  219. package/dist/features/live/components/LiveItemDetailPageView.js +4 -9
  220. package/dist/features/media/hooks/useMedia.js +17 -0
  221. package/dist/features/media/repository/media-assets.repository.d.ts +46 -0
  222. package/dist/features/media/repository/media-assets.repository.js +31 -0
  223. package/dist/features/media/trust-signals.d.ts +85 -0
  224. package/dist/features/media/trust-signals.js +126 -0
  225. package/dist/features/parts/components/PartDetailPageView.d.ts +14 -1
  226. package/dist/features/parts/components/PartDetailPageView.js +2 -2
  227. package/dist/features/parts/components/PartsIndexPageView.d.ts +11 -2
  228. package/dist/features/parts/components/PartsIndexPageView.js +2 -2
  229. package/dist/features/parts/components/PartsSearchBox.d.ts +9 -0
  230. package/dist/features/parts/components/PartsSearchBox.js +57 -0
  231. package/dist/features/parts/schemas/firestore.d.ts +149 -3
  232. package/dist/features/parts/schemas/firestore.js +184 -0
  233. package/dist/features/payments/repository/payout.repository.d.ts +15 -0
  234. package/dist/features/payments/repository/payout.repository.js +21 -0
  235. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +4 -11
  236. package/dist/features/pre-orders/components/PreOrdersIndexListing.js +1 -1
  237. package/dist/features/price-index/components/PriceIndexToolView.d.ts +3 -1
  238. package/dist/features/price-index/components/PriceIndexToolView.js +92 -13
  239. package/dist/features/products/components/CompareOverlay.d.ts +18 -1
  240. package/dist/features/products/components/CompareOverlay.js +21 -2
  241. package/dist/features/products/components/CustomSectionTabContent.d.ts +31 -0
  242. package/dist/features/products/components/CustomSectionTabContent.js +29 -3
  243. package/dist/features/products/components/GroupMemberPicker.d.ts +19 -1
  244. package/dist/features/products/components/GroupMemberPicker.js +46 -8
  245. package/dist/features/products/components/GroupSettingsPanel.d.ts +11 -1
  246. package/dist/features/products/components/GroupSettingsPanel.js +91 -3
  247. package/dist/features/products/components/PrizeDrawDetailPageView.js +1 -1
  248. package/dist/features/products/components/PrizeDrawEntryActions.d.ts +15 -1
  249. package/dist/features/products/components/PrizeDrawEntryActions.js +70 -8
  250. package/dist/features/products/components/ProductDetailPageView.js +74 -15
  251. package/dist/features/products/components/ProductForm.d.ts +13 -1
  252. package/dist/features/products/components/ProductForm.js +16 -2
  253. package/dist/features/products/components/ProductsIndexListing.d.ts +16 -1
  254. package/dist/features/products/components/ProductsIndexListing.js +3 -3
  255. package/dist/features/products/components/ShowGroupSection.js +15 -2
  256. package/dist/features/products/components/SparesListView.d.ts +7 -0
  257. package/dist/features/products/components/SparesListView.js +39 -0
  258. package/dist/features/products/constants/action-defs.d.ts +1 -0
  259. package/dist/features/products/constants/action-defs.js +1 -0
  260. package/dist/features/products/repository/products.repository.d.ts +98 -0
  261. package/dist/features/products/repository/products.repository.js +235 -17
  262. package/dist/features/products/schemas/firestore.d.ts +97 -4
  263. package/dist/features/products/schemas/firestore.js +104 -0
  264. package/dist/features/products/schemas/index.d.ts +10 -19
  265. package/dist/features/products/schemas/index.js +23 -6
  266. package/dist/features/products/types/index.d.ts +45 -1
  267. package/dist/features/products/utils/group-member-image.d.ts +39 -0
  268. package/dist/features/products/utils/group-member-image.js +3 -0
  269. package/dist/features/products/utils/listing-badge-variant.js +4 -0
  270. package/dist/features/reviews/components/ReviewsList.js +1 -1
  271. package/dist/features/scams/components/ScamProfileView.js +1 -1
  272. package/dist/features/search/components/EntityTypeahead.d.ts +44 -0
  273. package/dist/features/search/components/EntityTypeahead.js +92 -0
  274. package/dist/features/search/components/Search.d.ts +12 -1
  275. package/dist/features/search/components/Search.js +47 -3
  276. package/dist/features/search/components/SearchFacetRail.d.ts +11 -0
  277. package/dist/features/search/components/SearchFacetRail.js +92 -0
  278. package/dist/features/search/components/SearchResultsClient.d.ts +33 -0
  279. package/dist/features/search/components/SearchResultsClient.js +103 -0
  280. package/dist/features/search/components/SearchResultsPageView.d.ts +15 -1
  281. package/dist/features/search/components/SearchResultsPageView.js +2 -2
  282. package/dist/features/search/components/index.d.ts +0 -6
  283. package/dist/features/search/components/index.js +0 -3
  284. package/dist/features/search/hooks/useNavSuggestions.d.ts +13 -0
  285. package/dist/features/search/hooks/useScopedSearch.d.ts +34 -0
  286. package/dist/features/search/hooks/useScopedSearch.js +114 -0
  287. package/dist/features/search/hooks/useSiteSearch.d.ts +26 -0
  288. package/dist/features/search/hooks/useSiteSearch.js +149 -0
  289. package/dist/features/search/index.d.ts +0 -4
  290. package/dist/features/search/index.js +0 -4
  291. package/dist/features/search/manifest.d.ts +12 -0
  292. package/dist/features/search/manifest.js +17 -2
  293. package/dist/features/search/server.d.ts +0 -3
  294. package/dist/features/search/server.js +0 -3
  295. package/dist/features/seller/components/SellerListingTypeView.d.ts +1 -1
  296. package/dist/features/seller/components/SellerListingTypeView.js +20 -0
  297. package/dist/features/seller/components/SellerPayoutSettingsView.js +35 -14
  298. package/dist/features/seller/components/SellerProductShell.d.ts +1 -1
  299. package/dist/features/seller/components/SellerProductShell.js +2 -1
  300. package/dist/features/seller/components/SellerSidebar.js +1 -1
  301. package/dist/features/seller/components/SellerSparesView.d.ts +17 -0
  302. package/dist/features/seller/components/SellerSparesView.js +6 -0
  303. package/dist/features/seller/components/index.d.ts +2 -0
  304. package/dist/features/seller/components/index.js +1 -0
  305. package/dist/features/shell/CommandPalette.js +1 -1
  306. package/dist/features/sticker-trace/schemas/firestore.d.ts +19 -0
  307. package/dist/features/stores/components/StoreDetailLayoutView.d.ts +1 -1
  308. package/dist/features/stores/components/StoreDetailLayoutView.js +7 -82
  309. package/dist/features/stores/components/StoreHeader.js +1 -2
  310. package/dist/features/stores/components/StoreSparesPageView.d.ts +27 -0
  311. package/dist/features/stores/components/StoreSparesPageView.js +48 -0
  312. package/dist/features/stores/schemas/firestore.d.ts +19 -0
  313. package/dist/features/tester/seed-data/authored/buying__spares-and-groups.d.ts +2 -0
  314. package/dist/features/tester/seed-data/authored/buying__spares-and-groups.js +96 -0
  315. package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.d.ts +2 -0
  316. package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.js +280 -45
  317. package/dist/features/tester/seed-data/authored/content-discovery__category-tabs-franchise-bundles.js +54 -32
  318. package/dist/features/tester/seed-data/authored/content-discovery__parts-database.js +3 -2
  319. package/dist/features/tester/seed-data/authored/content-discovery__price-index-and-compare.d.ts +2 -0
  320. package/dist/features/tester/seed-data/authored/content-discovery__price-index-and-compare.js +73 -0
  321. package/dist/features/tester/seed-data/authored/content-discovery__site-wide-index.d.ts +2 -0
  322. package/dist/features/tester/seed-data/authored/content-discovery__site-wide-index.js +340 -0
  323. package/dist/features/tester/seed-data/authored/index.js +16 -0
  324. package/dist/features/tester/seed-data/authored/search-and-nav__header-search.d.ts +1 -0
  325. package/dist/features/tester/seed-data/authored/search-and-nav__header-search.js +57 -0
  326. package/dist/features/tester/seed-data/authored/selling__spares-and-group-editing.d.ts +2 -0
  327. package/dist/features/tester/seed-data/authored/selling__spares-and-group-editing.js +77 -0
  328. package/dist/features/tester/seed-data/authored/tools__sticker-promote-to-listings.d.ts +2 -0
  329. package/dist/features/tester/seed-data/authored/tools__sticker-promote-to-listings.js +58 -0
  330. package/dist/features/tester/seed-data/authored/tools__sticker-tracer.js +5 -4
  331. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +372 -18
  332. package/dist/index.d.ts +17 -57
  333. package/dist/index.js +35 -96
  334. package/dist/next/routing/route-map.d.ts +42 -1
  335. package/dist/next/routing/route-map.js +45 -0
  336. package/dist/providers/db-firebase/base.repository.d.ts +22 -0
  337. package/dist/providers/db-firebase/base.repository.js +36 -0
  338. package/dist/schemas/registry.d.ts +15 -6
  339. package/dist/security/blind-index-tokens.d.ts +54 -0
  340. package/dist/security/blind-index-tokens.js +152 -0
  341. package/dist/security/index.d.ts +1 -1
  342. package/dist/security/index.js +1 -1
  343. package/dist/security/settings-encryption.d.ts +35 -0
  344. package/dist/security/settings-encryption.js +91 -0
  345. package/dist/seed/_helpers/brand-rows.js +38 -14
  346. package/dist/seed/_helpers/category-forest.js +73 -7
  347. package/dist/seed/_helpers/category-images-generated.d.ts +25 -6
  348. package/dist/seed/_helpers/category-images-generated.js +81 -6
  349. package/dist/seed/_helpers/category-models.d.ts +1 -1
  350. package/dist/seed/_helpers/category-models.js +7 -1
  351. package/dist/seed/_helpers/category-parts-glossary-map.js +8 -0
  352. package/dist/seed/_helpers/category-parts.d.ts +1 -1
  353. package/dist/seed/_helpers/category-parts.js +50 -2
  354. package/dist/seed/_helpers/character-features.d.ts +1 -1
  355. package/dist/seed/_helpers/character-features.js +2 -1
  356. package/dist/seed/_helpers/franchise-rows.js +10 -2
  357. package/dist/seed/_helpers/media.d.ts +47 -0
  358. package/dist/seed/_helpers/media.js +34 -0
  359. package/dist/seed/authenticity-knowledge-seed-data.d.ts +49 -5
  360. package/dist/seed/authenticity-knowledge-seed-data.js +10001 -549
  361. package/dist/seed/categories-seed-data.js +124 -20
  362. package/dist/seed/grouped-listings-seed-data.js +16 -0
  363. package/dist/seed/homepage-sections-seed-data.js +94 -5
  364. package/dist/seed/index.d.ts +2 -3
  365. package/dist/seed/index.js +2 -2
  366. package/dist/seed/manifest.js +3 -0
  367. package/dist/seed/media-assets-seed-data.d.ts +1 -1
  368. package/dist/seed/media-assets-seed-data.js +746 -196
  369. package/dist/seed/model-composition-seed-data.js +122 -6
  370. package/dist/seed/part-glossary-seed-data.d.ts +1 -1
  371. package/dist/seed/part-glossary-seed-data.js +37219 -463
  372. package/dist/seed/products-art-seed-data.js +7 -18
  373. package/dist/seed/products-auctions-seed-data.js +56 -47
  374. package/dist/seed/products-beyblade-x-seed-data.d.ts +2 -0
  375. package/dist/seed/products-beyblade-x-seed-data.js +441 -0
  376. package/dist/seed/products-catalogue-seed-data.d.ts +5 -5
  377. package/dist/seed/products-catalogue-seed-data.js +1500 -1240
  378. package/dist/seed/products-classifieds-seed-data.js +9 -27
  379. package/dist/seed/products-digital-codes-seed-data.js +9 -18
  380. package/dist/seed/products-live-items-seed-data.js +5 -13
  381. package/dist/seed/products-preorders-seed-data.js +67 -33
  382. package/dist/seed/products-prize-draws-seed-data.js +8 -17
  383. package/dist/seed/products-spares-seed-data.d.ts +2 -0
  384. package/dist/seed/products-spares-seed-data.js +368 -0
  385. package/dist/seed/products-standard-seed-data.js +39 -126
  386. package/dist/seed/products-stickers-seed-data.js +59 -15
  387. package/dist/seed/site-settings-seed-data.js +8 -0
  388. package/dist/seo/json-ld.d.ts +25 -0
  389. package/dist/seo/json-ld.js +28 -0
  390. package/dist/server-entry.d.ts +3 -1
  391. package/dist/server-entry.js +2 -2
  392. package/dist/server.d.ts +9 -9
  393. package/dist/server.js +27 -25
  394. package/dist/styles.css +202 -1
  395. package/dist/tailwind-input.css +31 -17
  396. package/dist/tailwind-utilities.css +1 -1
  397. package/dist/ui/components/Accordion.js +1 -1
  398. package/dist/ui/components/Breadcrumb.js +1 -1
  399. package/dist/ui/components/DetailPageGallery.js +0 -2
  400. package/dist/ui/components/DetailPageHero.js +0 -1
  401. package/dist/ui/components/DetailPageTabs.js +1 -1
  402. package/dist/ui/components/Divider.js +3 -3
  403. package/dist/ui/components/GatedPrice.js +5 -1
  404. package/dist/ui/components/HorizontalScroller.js +1 -1
  405. package/dist/ui/components/ListingLayout.js +3 -3
  406. package/dist/ui/components/MediaTabs.style.css +81 -0
  407. package/dist/ui/components/Pagination.js +1 -1
  408. package/dist/ui/components/PendingValue.d.ts +45 -0
  409. package/dist/ui/components/PendingValue.js +7 -0
  410. package/dist/ui/components/Radio.style.css +119 -0
  411. package/dist/ui/components/RatingDisplay.js +2 -2
  412. package/dist/ui/components/SettingsSection.js +0 -2
  413. package/dist/ui/components/SiteLogo.js +3 -0
  414. package/dist/ui/components/SiteMark.js +3 -0
  415. package/dist/ui/components/SortDropdown.js +1 -1
  416. package/dist/ui/components/SpecTable.d.ts +58 -0
  417. package/dist/ui/components/SpecTable.js +8 -0
  418. package/dist/ui/components/StarRating.js +1 -3
  419. package/dist/ui/components/SummaryCard.js +1 -1
  420. package/dist/ui/components/index.style.css +1 -0
  421. package/dist/ui/icons/icon-registry.d.ts +1 -0
  422. package/dist/ui/icons/icon-registry.js +9 -1
  423. package/dist/ui/index.d.ts +4 -0
  424. package/dist/ui/index.js +2 -0
  425. package/dist/utils/search-txt-query.d.ts +12 -0
  426. package/dist/utils/search-txt-query.js +12 -0
  427. package/package.json +1 -1
  428. package/scripts/dedupe-peer-deps.mjs +18 -0
  429. package/scripts/seed-cli.mjs +135 -26
  430. package/scripts/verify-css-build.mjs +118 -37
  431. package/dist/_internal/server/features/search/actions.d.ts +0 -7
  432. package/dist/_internal/server/features/search/actions.js +0 -21
  433. package/dist/_internal/server/features/search/data.d.ts +0 -15
  434. package/dist/_internal/server/features/search/data.js +0 -18
  435. package/dist/_internal/server/features/search/index.d.ts +0 -3
  436. package/dist/_internal/server/features/search/index.js +0 -2
  437. package/dist/features/homepage/api/[id]/route.d.ts +0 -23
  438. package/dist/features/homepage/api/[id]/route.js +0 -103
  439. package/dist/features/homepage/api/route.d.ts +0 -14
  440. package/dist/features/homepage/api/route.js +0 -140
  441. package/dist/features/homepage/api/sections/[id]/route.d.ts +0 -26
  442. package/dist/features/homepage/api/sections/[id]/route.js +0 -95
  443. package/dist/features/homepage/api/sections/route.d.ts +0 -13
  444. package/dist/features/homepage/api/sections/route.js +0 -82
  445. package/dist/features/homepage/components/AdvertisementBanner.d.ts +0 -14
  446. package/dist/features/homepage/components/AdvertisementBanner.js +0 -35
  447. package/dist/features/homepage/components/BeforeAfterCard.d.ts +0 -9
  448. package/dist/features/homepage/components/BeforeAfterCard.js +0 -73
  449. package/dist/features/homepage/components/FeaturedResultsSection.d.ts +0 -17
  450. package/dist/features/homepage/components/FeaturedResultsSection.js +0 -17
  451. package/dist/features/homepage/components/HeroBanner.d.ts +0 -7
  452. package/dist/features/homepage/components/HeroBanner.js +0 -43
  453. package/dist/features/homepage/components/HeroSection.d.ts +0 -7
  454. package/dist/features/homepage/components/HeroSection.js +0 -6
  455. package/dist/features/homepage/components/HomepageSkeleton.d.ts +0 -2
  456. package/dist/features/homepage/components/HomepageSkeleton.js +0 -21
  457. package/dist/features/homepage/components/HomepageView.d.ts +0 -25
  458. package/dist/features/homepage/components/HomepageView.js +0 -5
  459. package/dist/features/homepage/components/NewsletterBanner.d.ts +0 -23
  460. package/dist/features/homepage/components/NewsletterBanner.js +0 -37
  461. package/dist/features/homepage/components/SiteFeaturesSection.d.ts +0 -14
  462. package/dist/features/homepage/components/SiteFeaturesSection.js +0 -11
  463. package/dist/features/homepage/components/TrustBadges.d.ts +0 -6
  464. package/dist/features/homepage/components/TrustBadges.js +0 -46
  465. package/dist/features/homepage/components/TrustIndicatorsSection.d.ts +0 -12
  466. package/dist/features/homepage/components/TrustIndicatorsSection.js +0 -11
  467. package/dist/features/homepage/hooks/useHomepage.d.ts +0 -11
  468. package/dist/features/homepage/hooks/useHomepage.js +0 -17
  469. package/dist/features/homepage/hooks/useHomepageSections.d.ts +0 -2
  470. package/dist/features/homepage/hooks/useHomepageSections.js +0 -10
  471. package/dist/features/homepage/repository/homepage.repository.d.ts +0 -11
  472. package/dist/features/homepage/repository/homepage.repository.js +0 -25
  473. package/dist/features/search/actions/index.d.ts +0 -1
  474. package/dist/features/search/actions/index.js +0 -1
  475. package/dist/features/search/actions/search-actions.d.ts +0 -18
  476. package/dist/features/search/actions/search-actions.js +0 -43
  477. package/dist/features/search/api/route.d.ts +0 -22
  478. package/dist/features/search/api/route.js +0 -128
  479. package/dist/features/search/columns/index.d.ts +0 -17
  480. package/dist/features/search/columns/index.js +0 -49
  481. package/dist/features/search/components/SearchFiltersRow.d.ts +0 -22
  482. package/dist/features/search/components/SearchFiltersRow.js +0 -21
  483. package/dist/features/search/components/SearchResultsSection.d.ts +0 -53
  484. package/dist/features/search/components/SearchResultsSection.js +0 -35
  485. package/dist/features/search/components/SearchView.d.ts +0 -27
  486. package/dist/features/search/components/SearchView.js +0 -8
  487. package/dist/features/search/hooks/useSearch.d.ts +0 -21
  488. package/dist/features/search/hooks/useSearch.js +0 -33
  489. package/dist/features/search/repository/search.repository.d.ts +0 -14
  490. package/dist/features/search/repository/search.repository.js +0 -59
  491. package/dist/features/search/schemas/index.d.ts +0 -70
  492. package/dist/features/search/schemas/index.js +0 -36
  493. package/dist/features/search/types/index.d.ts +0 -48
  494. package/dist/features/stores/components/StoreScopedSearch.d.ts +0 -17
  495. package/dist/features/stores/components/StoreScopedSearch.js +0 -27
  496. package/dist/seed/defaults/homepage-sections.d.ts +0 -2
  497. package/dist/seed/defaults/homepage-sections.js +0 -60
  498. package/dist/seed/factories/homepage-section.factory.d.ts +0 -10
  499. package/dist/seed/factories/homepage-section.factory.js +0 -13
  500. /package/dist/{features/search/types/index.js → _internal/shared/listing-types/spares/og.d.ts} +0 -0
@@ -0,0 +1,252 @@
1
+ /*
2
+ * WHY: A signed-in viewer should be able to find their own orders, offers
3
+ * and drafts from the same box — without that box ever being able to
4
+ * return somebody else's.
5
+ * WHAT: Tier 2. Viewer-scoped `SearchSource`s, built per request from the
6
+ * session, plus the budget check.
7
+ *
8
+ * ## 🛑 Filtered SERVER-side, never in the browser
9
+ *
10
+ * The same rule `projectActionIndexForViewer` states for the action index.
11
+ * Every source below carries an OWNER CLAUSE in its `where`, so the query
12
+ * itself cannot return another viewer's rows — a client-side filter over a
13
+ * wider result is one rendering bug away from a disclosure, and the bug is
14
+ * invisible in review because the UI looks right.
15
+ *
16
+ * ## 🛑 A guest makes ZERO authenticated requests
17
+ *
18
+ * `scopedSourcesFor(null)` returns `[]`, and the route refuses before
19
+ * touching Firestore. This is not an optimisation: a signed-out visitor
20
+ * whose search fires an authenticated request has a session the page does
21
+ * not know about, and the only honest way to prove the gate works is for
22
+ * there to be no request at all.
23
+ *
24
+ * ## The read budget, which is why the split exists
25
+ *
26
+ * guest 0 sources 0 docs 0 round trips
27
+ * buyer 6 ~120 1 (one Promise.all)
28
+ * seller +5 ~220 1
29
+ * admin +5 ~320 1
30
+ *
31
+ * Against `SCOPED_SCAN_BUDGET` = 400. Scoped sources use `scanLimit: 20`
32
+ * rather than the 60 the public tier uses, because an owner clause has
33
+ * already collapsed the candidate set — a 60-doc window would be 40 reads
34
+ * spent proving there was nothing else.
35
+ *
36
+ * @tag domain:search
37
+ * @tag layer:server
38
+ * @tag pattern:none
39
+ * @tag access:server
40
+ * @tag consumers:/api/search/scoped
41
+ * @tag sideEffects:none
42
+ */
43
+ import { ROUTES } from "../../../../next/routing/route-map.js";
44
+ import { SCOPED_SCAN_BUDGET } from "./search-everything.js";
45
+ /** Scoped sources read a narrow window; the owner clause did the work. */
46
+ const SCOPED_SCAN = 20;
47
+ const str = (v) => typeof v === "string" && v.length > 0 ? v : undefined;
48
+ /**
49
+ * Every term must appear somewhere in the named fields.
50
+ *
51
+ * 🛑 AND, matching the push-down path's `plan.rest.every(...)`. An OR here
52
+ * would make the two modes disagree about what a two-word query means, on
53
+ * the same page, in adjacent groups.
54
+ *
55
+ * 🛑 Lower-cased comparison only — NOT `normalizeSearchText`. That
56
+ * normaliser exists to make the WRITE path and the token query agree; this
57
+ * path has no tokens, and running it here would strip punctuation out of a
58
+ * tracking number or an order id, which are exactly the strings someone
59
+ * pastes into a scoped search.
60
+ */
61
+ function fieldsContain(fields) {
62
+ return (data, terms) => {
63
+ if (terms.length === 0)
64
+ return false;
65
+ const hay = fields
66
+ .map((f) => str(data[f]) ?? "")
67
+ .join(" ")
68
+ .toLowerCase();
69
+ return terms.every((t) => hay.includes(t.toLowerCase()));
70
+ };
71
+ }
72
+ /**
73
+ * The viewer's own records.
74
+ *
75
+ * 🛑 `mode: "bounded-memory"` for everything PII-bearing, and `search-txt`
76
+ * only where the collection genuinely carries tokens that are safe to have.
77
+ * `orders` is the interesting case: `buildOrderSearchTxt` already indexes
78
+ * productTitle / storeName / trackingNumber and already EXCLUDES the
79
+ * shipping address, so it keeps the push-down. `addresses` has no
80
+ * `searchTxt` and must never grow one.
81
+ */
82
+ function selfSources(viewer) {
83
+ return [
84
+ {
85
+ key: "my-orders",
86
+ label: "Your orders",
87
+ collection: "orders",
88
+ // 🛑 `userId`, NOT `buyerId`. The field is `userId` and a query on
89
+ // `buyerId` returns ZERO while raising nothing — indistinguishable
90
+ // from "this buyer has no orders", which is a false-finding generator.
91
+ where: [["userId", viewer.uid]],
92
+ scanLimit: SCOPED_SCAN,
93
+ mode: "search-txt",
94
+ select: ["productTitle", "status", "trackingNumber"],
95
+ toHit: (id, d) => ({
96
+ id,
97
+ title: str(d.productTitle) ?? `Order ${id}`,
98
+ href: String(ROUTES.USER.ORDER_DETAIL(id)),
99
+ detail: str(d.status),
100
+ }),
101
+ moreHref: () => String(ROUTES.USER.ORDERS),
102
+ },
103
+ {
104
+ key: "my-offers",
105
+ label: "Your offers",
106
+ collection: "offers",
107
+ where: [["buyerId", viewer.uid]],
108
+ scanLimit: SCOPED_SCAN,
109
+ mode: "bounded-memory",
110
+ orderBy: ["createdAt", "desc"],
111
+ select: ["productTitle", "status", "productSlug"],
112
+ matches: fieldsContain(["productTitle", "status"]),
113
+ toHit: (id, d) => ({
114
+ id,
115
+ title: str(d.productTitle) ?? "Offer",
116
+ href: String(ROUTES.USER.OFFERS),
117
+ detail: str(d.status),
118
+ }),
119
+ moreHref: () => String(ROUTES.USER.OFFERS),
120
+ },
121
+ {
122
+ key: "my-catalogue",
123
+ label: "Your catalogue",
124
+ collection: "catalogueItems",
125
+ where: [["ownerId", viewer.uid]],
126
+ scanLimit: SCOPED_SCAN,
127
+ mode: "bounded-memory",
128
+ orderBy: ["createdAt", "desc"],
129
+ select: ["title", "listingStatus"],
130
+ matches: fieldsContain(["title"]),
131
+ toHit: (id, d) => ({
132
+ id,
133
+ title: str(d.title) ?? "Catalogue item",
134
+ href: String(ROUTES.USER.CATALOGUE),
135
+ detail: str(d.listingStatus),
136
+ }),
137
+ moreHref: () => String(ROUTES.USER.CATALOGUE),
138
+ },
139
+ {
140
+ /*
141
+ * 🛑 `bounded-memory`, and this is the source the mode exists for.
142
+ *
143
+ * `addresses` is PII — `fullName`, `phone`, `addressLine1` are all
144
+ * encrypted at rest and decrypted by the repository on read. It has
145
+ * no `searchTxt` and must never get one: a prefix-expanded plaintext
146
+ * token array over a person's name and street is precisely what
147
+ * § Searching PII refuses. The owner clause already bounds this to
148
+ * well under 25 rows, so an index would re-derive a bound we have
149
+ * while adding leak surface for nothing.
150
+ */
151
+ key: "my-addresses",
152
+ label: "Your addresses",
153
+ collection: "addresses",
154
+ where: [
155
+ ["ownerType", "user"],
156
+ ["ownerId", viewer.uid],
157
+ ],
158
+ scanLimit: SCOPED_SCAN,
159
+ mode: "bounded-memory",
160
+ select: ["label", "city", "state"],
161
+ // Only the non-sensitive half is matched AND projected. A label and a
162
+ // city are enough to pick an address out of a list of four; the name,
163
+ // phone and street line never leave the server.
164
+ matches: fieldsContain(["label", "city", "state"]),
165
+ toHit: (id, d) => ({
166
+ id,
167
+ title: str(d.label) ?? "Address",
168
+ href: String(ROUTES.USER.ADDRESSES),
169
+ detail: [str(d.city), str(d.state)].filter(Boolean).join(", ") || undefined,
170
+ }),
171
+ moreHref: () => String(ROUTES.USER.ADDRESSES),
172
+ },
173
+ ];
174
+ }
175
+ /** The viewer's store. Requires a resolved `storeId`, never a uid. */
176
+ function sellerSources(viewer) {
177
+ if (!viewer.storeId)
178
+ return [];
179
+ const storeId = viewer.storeId;
180
+ return [
181
+ {
182
+ /*
183
+ * The seller's own listings INCLUDING drafts — which is the whole
184
+ * point, because a published one is already in the public artifact and
185
+ * the merge dedupes it away. What survives in this group is precisely
186
+ * "your drafts", and labelling it so is what makes the dedupe legible.
187
+ */
188
+ key: "my-listings",
189
+ label: "Your listings (incl. drafts)",
190
+ collection: "products",
191
+ where: [["storeId", storeId]],
192
+ scanLimit: SCOPED_SCAN,
193
+ mode: "search-txt",
194
+ select: ["title", "slug", "status"],
195
+ toHit: (id, d) => ({
196
+ id,
197
+ title: str(d.title) ?? "Listing",
198
+ href: String(ROUTES.STORE.PRODUCTS_EDIT(str(d.slug) ?? id)),
199
+ detail: str(d.status),
200
+ }),
201
+ moreHref: () => String(ROUTES.STORE.PRODUCTS),
202
+ },
203
+ {
204
+ key: "store-orders",
205
+ label: "Orders in your store",
206
+ collection: "orders",
207
+ where: [["storeId", storeId]],
208
+ scanLimit: SCOPED_SCAN,
209
+ mode: "search-txt",
210
+ select: ["productTitle", "status", "trackingNumber"],
211
+ toHit: (id, d) => ({
212
+ id,
213
+ title: str(d.productTitle) ?? `Order ${id}`,
214
+ href: String(ROUTES.STORE.ORDER_DETAIL(id)),
215
+ detail: str(d.status),
216
+ }),
217
+ moreHref: () => String(ROUTES.STORE.ORDERS),
218
+ },
219
+ ];
220
+ }
221
+ /**
222
+ * Build the viewer's sources.
223
+ *
224
+ * 🛑 Returns `[]` for a guest, which is what makes "zero authenticated
225
+ * requests when signed out" structural rather than a caller's discipline.
226
+ */
227
+ export function scopedSourcesFor(viewer) {
228
+ if (!viewer)
229
+ return [];
230
+ const sources = [...selfSources(viewer)];
231
+ if (viewer.isSeller || viewer.isAdmin)
232
+ sources.push(...sellerSources(viewer));
233
+ return sources;
234
+ }
235
+ /**
236
+ * Σ `scanLimit`, for the budget check.
237
+ *
238
+ * Exported so `audit-scoped-search-ownership` R4 can print the arithmetic
239
+ * rather than just a verdict: "over budget" without the per-source figures
240
+ * tells you nothing about which source to shrink.
241
+ */
242
+ export function scopedScanTotal(sources) {
243
+ return sources.reduce((n, s) => n + (s.scanLimit ?? 60), 0);
244
+ }
245
+ export function assertWithinScopedBudget(sources) {
246
+ const total = scopedScanTotal(sources);
247
+ if (total <= SCOPED_SCAN_BUDGET)
248
+ return;
249
+ const breakdown = sources.map((s) => `${s.key}=${s.scanLimit ?? 60}`).join(" + ");
250
+ throw new Error(`Scoped search would read up to ${total} documents, over SCOPED_SCAN_BUDGET ` +
251
+ `(${SCOPED_SCAN_BUDGET}). ${breakdown} = ${total}.`);
252
+ }
@@ -43,7 +43,56 @@ export interface SearchSource {
43
43
  moreHref: (q: string) => string;
44
44
  /** Extra equality narrowing, e.g. `status == published`. */
45
45
  where?: ReadonlyArray<readonly [string, unknown]>;
46
+ /**
47
+ * The bounded window this source reads before the in-memory refine.
48
+ *
49
+ * Defaults to `SCAN` (60). Scoped sources pass 20: an owner clause
50
+ * (`userId == uid`) has already collapsed the candidate set, so a 60-doc
51
+ * window is 40 reads spent proving there was nothing else.
52
+ */
53
+ scanLimit?: number;
54
+ /**
55
+ * How this source FINDS rows. Discriminated so TypeScript forces every
56
+ * source to answer, which is what makes `audit-scoped-search-ownership`
57
+ * R2 checkable rather than advisory.
58
+ *
59
+ * `search-txt` the `array-contains` push-down. Requires the
60
+ * collection to carry `searchTxt`.
61
+ * `bounded-memory` read the owner's bounded window and filter in
62
+ * memory, with no token push-down at all.
63
+ *
64
+ * 🛑 A PII-bearing collection must be `bounded-memory`. `searchTxt` is
65
+ * plaintext, edge-n-gram-expanded and stored on the document — giving
66
+ * `addresses` a token push-down would write a prefix-expanded index over
67
+ * a person's name and street, which is the precise thing § Searching PII
68
+ * refuses (a 1-character prefix has 36 possible values; the frequency
69
+ * distribution unpicks from there). Decrypting a bounded owner-scoped
70
+ * window in memory re-derives a bound ownership already gives, and adds
71
+ * no leak surface.
72
+ */
73
+ mode?: "search-txt" | "bounded-memory";
74
+ /**
75
+ * For `bounded-memory`: does this row match? Receives the DECRYPTED
76
+ * document, so a repository that decrypts on read is the intended caller.
77
+ * Every term must match (AND), consistent with the push-down path.
78
+ */
79
+ matches?: (data: SearchDocData, terms: readonly string[]) => boolean;
80
+ /** Ordering for `bounded-memory`, since there is no token clause to sort by. */
81
+ orderBy?: readonly [string, "asc" | "desc"];
46
82
  }
83
+ /**
84
+ * 🛑 The ceiling on what ONE viewer's scoped search may read.
85
+ *
86
+ * Σ `scanLimit` across the widest role, checked by
87
+ * `audit-scoped-search-ownership` R4 — which PRINTS THE ARITHMETIC on
88
+ * failure, because "the budget is exceeded" is useless without knowing by
89
+ * which source and how much.
90
+ *
91
+ * 400 against Rule #6's ~3-round-trip guidance is defensible because the
92
+ * sources run in ONE `Promise.all`: it is one round trip of fan-out, not
93
+ * twelve sequential ones. The number that matters is documents read.
94
+ */
95
+ export declare const SCOPED_SCAN_BUDGET = 400;
47
96
  /** A projected Firestore document's fields. */
48
97
  export type SearchDocData = Record<string, FirestoreValue>;
49
98
  /** A projected document — the only shape this module reads. */
@@ -55,6 +104,14 @@ interface SearchQueryRef {
55
104
  where(field: string, op: string, value: unknown): SearchQueryRef;
56
105
  select(...fields: string[]): SearchQueryRef;
57
106
  limit(n: number): SearchQueryRef;
107
+ /**
108
+ * Only `bounded-memory` sources use this. The push-down path deliberately
109
+ * does not order: an `orderBy` beside an `array-contains` demands a
110
+ * composite index per source, and a missing one throws
111
+ * `FAILED_PRECONDITION` into the per-source catch, where it renders as an
112
+ * empty group — i.e. silently (Root Cause #59).
113
+ */
114
+ orderBy(field: string, direction: "asc" | "desc"): SearchQueryRef;
58
115
  get(): Promise<{
59
116
  docs: SearchDoc[];
60
117
  }>;
@@ -1,11 +1,21 @@
1
1
  /**
2
2
  * D2 Fix 4 — CROSS-RESOURCE search.
3
3
  *
4
- * 🛑 `/search` is a pure REDIRECT today: it maps each of 15
5
- * `SearchResourceType` values to a browse route and `redirect()`s, `noindex`.
6
- * So there is **no cross-resource search at all** — the dropdown picks which
7
- * single listing page to send you to, and a buyer searching "dranzer" cannot
8
- * see that we have a product, an auction, a blog post and an FAQ about it.
4
+ * 🛑 CORRECTED 2026-10-19 — this header asserted the opposite of the truth.
5
+ *
6
+ * It read: "`/search` is a pure REDIRECT today … there is no cross-resource
7
+ * search at all." That described the state this module was WRITTEN to fix,
8
+ * and it stayed on the file after the fix shipped — so the one document
9
+ * explaining the feature told every later reader the feature did not exist.
10
+ *
11
+ * What is true now: `/search` is a real grouped results page, the header
12
+ * reaches it, and this module is TIER 2 — the authenticated, server-side
13
+ * half. The public half is a prebuilt artifact searched in the browser at
14
+ * zero Firestore reads, and this one is what serves a viewer's OWN records
15
+ * (`scoped-sources.ts`) and what the kill switch falls back to when the
16
+ * artifact is unavailable.
17
+ *
18
+ * That fallback is the reason this file is not deleted.
9
19
  *
10
20
  * ── WHY THIS IS AFFORDABLE ─────────────────────────────────────────────────
11
21
  *
@@ -30,11 +40,15 @@
30
40
  *
31
41
  * ── 🛑 WHAT IT DOES NOT REUSE, AND WHY ─────────────────────────────────────
32
42
  *
33
- * NOT `SearchRepository`. That class builds `title_=${q}` — a case-sensitive
43
+ * NOT `SearchRepository`. That class built `title_=${q}` — a case-sensitive
34
44
  * STARTS-WITH on `title` alone — so "dranzer" would not find "Beyblade
35
- * Original Dranzer S" and "flat" would find nothing at all. It is reachable
36
- * only through `/api/search`, whose own hook (`useSearch`) has zero consumers
37
- * outside barrel re-exports. Recorded rather than deleted here; see F1.
45
+ * Original Dranzer S" and "flat" would find nothing at all. It was reachable
46
+ * only through `/api/search`, whose own hook (`useSearch`) had zero consumers
47
+ * outside barrel re-exports. The whole dead subsystem — `SearchRepository`,
48
+ * `/api/search`, `useSearch`, `SearchView`/`SearchFiltersRow`/
49
+ * `SearchResultsSection`, the legacy `search-actions.ts`/`data.ts`/
50
+ * `actions.ts` chain — was deleted in the Wave 10 cleanup, kept only as this
51
+ * historical note on why `searchEverything` never called it.
38
52
  */
39
53
  import { planSearchTxt } from "../../../../utils/search-txt-query.js";
40
54
  import { parseSearchTxtQuery, SEARCH_TXT_FIELD } from "../../../../utils/search-txt.js";
@@ -44,6 +58,19 @@ import { normalizeError } from "../../../../errors/normalize.js";
44
58
  const PER_GROUP = 6;
45
59
  /** The bounded window each push-down reads before the in-memory refine. */
46
60
  const SCAN = 60;
61
+ /**
62
+ * 🛑 The ceiling on what ONE viewer's scoped search may read.
63
+ *
64
+ * Σ `scanLimit` across the widest role, checked by
65
+ * `audit-scoped-search-ownership` R4 — which PRINTS THE ARITHMETIC on
66
+ * failure, because "the budget is exceeded" is useless without knowing by
67
+ * which source and how much.
68
+ *
69
+ * 400 against Rule #6's ~3-round-trip guidance is defensible because the
70
+ * sources run in ONE `Promise.all`: it is one round trip of fan-out, not
71
+ * twelve sequential ones. The number that matters is documents read.
72
+ */
73
+ export const SCOPED_SCAN_BUDGET = 400;
47
74
  /**
48
75
  * Run every source in parallel and group the results.
49
76
  *
@@ -75,20 +102,41 @@ export async function searchEverything(db, q, sources) {
75
102
  moreHref: src.moreHref(q),
76
103
  };
77
104
  try {
105
+ const scan = src.scanLimit ?? SCAN;
106
+ const boundedMemory = src.mode === "bounded-memory";
78
107
  let ref = db.collection(src.collection);
79
108
  for (const [field, value] of src.where ?? [])
80
109
  ref = ref.where(field, "==", value);
81
- const snap = await ref
82
- .where(SEARCH_TXT_FIELD, "array-contains", plan.head)
83
- .select(...src.select, SEARCH_TXT_FIELD)
84
- .limit(SCAN)
85
- .get();
110
+ /*
111
+ * 🛑 The two modes differ in ONE clause and in nothing else.
112
+ *
113
+ * `bounded-memory` omits the `array-contains` push-down and does not
114
+ * project `searchTxt` — because the collections that use it do not
115
+ * have one, deliberately (see `mode`). Everything downstream —
116
+ * `toHit`, the PER_GROUP slice, the `truncated` floor — is shared, so
117
+ * the two paths cannot drift in how they REPORT, only in how they
118
+ * find.
119
+ */
120
+ const snap = boundedMemory
121
+ ? await (src.orderBy
122
+ ? ref.orderBy(src.orderBy[0], src.orderBy[1])
123
+ : ref)
124
+ .select(...src.select)
125
+ .limit(scan)
126
+ .get()
127
+ : await ref
128
+ .where(SEARCH_TXT_FIELD, "array-contains", plan.head)
129
+ .select(...src.select, SEARCH_TXT_FIELD)
130
+ .limit(scan)
131
+ .get();
86
132
  // AND-refine the remaining terms in memory — one push-down per query is
87
133
  // all Firestore gives, so the rest is a filter over a bounded window.
88
- const matched = snap.docs.filter((d) => {
89
- const txt = d.data()[SEARCH_TXT_FIELD] ?? [];
90
- return plan.rest.every((t) => txt.includes(t));
91
- });
134
+ const matched = boundedMemory
135
+ ? snap.docs.filter((d) => src.matches?.(d.data(), terms) ?? false)
136
+ : snap.docs.filter((d) => {
137
+ const txt = d.data()[SEARCH_TXT_FIELD] ?? [];
138
+ return plan.rest.every((t) => txt.includes(t));
139
+ });
92
140
  const hits = matched
93
141
  .map((d) => src.toHit(d.id, d.data()))
94
142
  .filter((h) => h !== null);
@@ -96,8 +144,10 @@ export async function searchEverything(db, q, sources) {
96
144
  ...base,
97
145
  hits: hits.slice(0, PER_GROUP),
98
146
  // Saturated window OR more matches than we show — either way the
99
- // count on screen is a floor.
100
- truncated: snap.docs.length >= SCAN || hits.length > PER_GROUP,
147
+ // count on screen is a floor. Compared against THIS source's own
148
+ // limit, not the module default: a scoped source scanning 20 that
149
+ // returned 20 is saturated even though 20 < SCAN.
150
+ truncated: snap.docs.length >= scan || hits.length > PER_GROUP,
101
151
  };
102
152
  }
103
153
  catch (err) {
@@ -141,6 +141,12 @@ function staticPages(baseUrl) {
141
141
  page(String(ROUTES.PUBLIC.DIGITAL_CODES), "daily", 0.6),
142
142
  page(String(ROUTES.PUBLIC.LIVE), "hourly", 0.7),
143
143
  page(String(ROUTES.PUBLIC.ART), "weekly", 0.6),
144
+ /*
145
+ * `daily`, matching the other one-of-a-kind types rather than `/art`'s
146
+ * weekly: most spares are quantity 1, so the page turns over as fast as
147
+ * classifieds do.
148
+ */
149
+ page(String(ROUTES.PUBLIC.SPARES), "daily", 0.6),
144
150
  page(String(ROUTES.PUBLIC.FEES), "monthly", 0.4),
145
151
  page(String(ROUTES.PUBLIC.HOW_AUCTIONS_WORK), "monthly", 0.4),
146
152
  page(String(ROUTES.PUBLIC.HOW_PRE_ORDERS_WORK), "monthly", 0.4),
@@ -1,3 +1,4 @@
1
+ import { productImageUrls } from "../../../../features/products/schemas/firestore.js";
1
2
  /** Maps the shared fields from a raw Firestore ProductDocument. */
2
3
  export function mapBaseListingFields(doc) {
3
4
  return {
@@ -10,8 +11,9 @@ export function mapBaseListingFields(doc) {
10
11
  // bypassing <GatedPrice> entirely — and it had zero readers, so it was
11
12
  // pure exposure. Clients format from `price` through the gate.
12
13
  currency: doc.currency ?? "INR",
13
- mainImage: doc.mainImage || doc.images?.[0] || null,
14
- images: doc.images ?? [],
14
+ mainImage: doc.mainImage || doc.images?.[0]?.url || null,
15
+ // A6: the client listing shape is still `string[]`; project, never mirror.
16
+ images: productImageUrls(doc.images),
15
17
  storeId: doc.storeId,
16
18
  storeName: doc.storeName ?? null,
17
19
  category: doc.categorySlugs?.[0] ?? doc.category ?? "",
@@ -15,6 +15,17 @@ export interface ClientSheetPart {
15
15
  areaMm2: number | null;
16
16
  /** Whether a full-resolution render exists, NOT where it is. */
17
17
  hasAsset: boolean;
18
+ /**
19
+ * The PUBLIC `/media/{shortId}` slug, when the part has been promoted.
20
+ *
21
+ * 🛑 Public on purpose and NOT a path. A `mediaShortId` is already a public
22
+ * URL by construction — a `mediaAssets` row IS what mints `/media/{id}`, and
23
+ * `/api/media/[...slug]` serves it to anyone, watermarked. So the thing it
24
+ * names is public whether or not this field is projected, and the admin
25
+ * review UI genuinely needs it to show the marketplace copy beside the clean
26
+ * one. `assetPath` stays private: that is the unwatermarked original.
27
+ */
28
+ mediaShortId?: string;
18
29
  duplicateOf?: number;
19
30
  }
20
31
  export interface ClientStickerSheet {
@@ -105,6 +105,7 @@ function toClientPart(part) {
105
105
  bboxMm: part.bboxMm,
106
106
  areaMm2: part.areaMm2,
107
107
  hasAsset: Boolean(part.assetPath),
108
+ ...(part.mediaShortId !== undefined ? { mediaShortId: part.mediaShortId } : {}),
108
109
  ...(part.duplicateOf !== undefined ? { duplicateOf: part.duplicateOf } : {}),
109
110
  };
110
111
  }
@@ -0,0 +1,26 @@
1
+ export interface PromoteToListingsInput {
2
+ sheetId: string;
3
+ /** Owning store. The admin picks it; there is no sensible default. */
4
+ storeId: string;
5
+ /**
6
+ * ONE price for every part, in rupees.
7
+ *
8
+ * 🛑 Deliberately flat rather than per-part or area-derived. A cut sticker
9
+ * costs about the same to print whatever its size, so a size-scaled price
10
+ * would be a fabricated precision — and a per-part form for a 60-part sheet
11
+ * is 60 inputs nobody fills in honestly. Each child is an ordinary product
12
+ * afterwards and repriceable in the normal editor.
13
+ */
14
+ partPrice: number;
15
+ /** The whole sheet's price, in rupees. */
16
+ sheetPrice: number;
17
+ /** Auth UID, for the `mediaAssets` row's `uploadedBy`. */
18
+ actorUid: string;
19
+ }
20
+ export interface PromoteToListingsResult {
21
+ parentId: string;
22
+ childIds: string[];
23
+ /** Parts skipped as confirmed duplicates of another part. */
24
+ skippedDuplicates: number;
25
+ }
26
+ export declare function promoteStickerSheetToListings(input: PromoteToListingsInput): Promise<PromoteToListingsResult>;