@mohasinac/appkit 4.27.0 → 4.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (298) hide show
  1. package/dist/_internal/client/features/lottery/LotteryAdminEditView.d.ts +16 -16
  2. package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +29 -6
  3. package/dist/_internal/client/features/lottery/LotteryListView.js +13 -1
  4. package/dist/_internal/server/features/checkout/actions.js +6 -4
  5. package/dist/_internal/server/features/classified/metadata.js +3 -1
  6. package/dist/_internal/server/features/digital-code/metadata.js +3 -1
  7. package/dist/_internal/server/features/live/metadata.js +3 -1
  8. package/dist/_internal/server/features/refunds/actions.js +3 -2
  9. package/dist/_internal/server/features/reviews/actions.js +3 -2
  10. package/dist/_internal/server/features/seo/sitemap.js +189 -40
  11. package/dist/_internal/server/features/stores/adapters.d.ts +1 -1
  12. package/dist/_internal/server/features/stores/adapters.js +5 -0
  13. package/dist/_internal/server/jobs/core/listingProcessor.d.ts +0 -1
  14. package/dist/_internal/server/jobs/core/listingProcessor.js +19 -1
  15. package/dist/_internal/shared/actions/action-registry.js +14 -0
  16. package/dist/_internal/shared/checkout/order-math.d.ts +25 -3
  17. package/dist/_internal/shared/features/checkout/config.d.ts +3 -3
  18. package/dist/_internal/shared/features/checkout/config.js +6 -3
  19. package/dist/client.d.ts +32 -2
  20. package/dist/client.js +37 -2
  21. package/dist/constants/api-endpoints.d.ts +21 -3
  22. package/dist/constants/api-endpoints.js +14 -1
  23. package/dist/constants/field-names.d.ts +2 -2
  24. package/dist/constants/field-names.js +2 -2
  25. package/dist/core/newsletter.repository.js +14 -1
  26. package/dist/features/about/components/FAQPageView.js +1 -1
  27. package/dist/features/about/components/FeesView.js +1 -1
  28. package/dist/features/account/components/AddressForm.d.ts +2 -0
  29. package/dist/features/account/components/AddressForm.js +5 -1
  30. package/dist/features/account/components/UserBidsView.js +1 -1
  31. package/dist/features/account/components/UserSidebar.js +1 -1
  32. package/dist/features/account/components/UserSupportView.js +24 -2
  33. package/dist/features/account/hooks/useAddresses.d.ts +29 -1
  34. package/dist/features/account/hooks/useAddresses.js +4 -1
  35. package/dist/features/account/hooks/useProfile.d.ts +1 -1
  36. package/dist/features/account/hooks/useProfile.js +1 -1
  37. package/dist/features/addresses/repository/addresses.repository.d.ts +13 -0
  38. package/dist/features/addresses/repository/addresses.repository.js +19 -0
  39. package/dist/features/admin/actions/chat-actions.js +5 -1
  40. package/dist/features/admin/components/AdminAdsView.js +1 -1
  41. package/dist/features/admin/components/AdminBidsView.js +6 -1
  42. package/dist/features/admin/components/AdminCarouselGroupEditorView.d.ts +9 -1
  43. package/dist/features/admin/components/AdminCarouselGroupEditorView.js +42 -10
  44. package/dist/features/admin/components/AdminCarouselView.js +1 -1
  45. package/dist/features/admin/components/AdminContentGuideView.js +1 -1
  46. package/dist/features/admin/components/AdminFeatureEditorView.js +1 -1
  47. package/dist/features/admin/components/AdminGroupedListingsView.js +14 -2
  48. package/dist/features/admin/components/AdminSidebar.js +1 -1
  49. package/dist/features/admin/components/AdminViewCards.js +2 -2
  50. package/dist/features/admin/components/DataTable.js +2 -2
  51. package/dist/features/admin/schemas/firestore.js +9 -3
  52. package/dist/features/auctions/actions/bid-actions.js +45 -4
  53. package/dist/features/auctions/components/AuctionBottomActions.d.ts +21 -6
  54. package/dist/features/auctions/components/AuctionBottomActions.js +42 -11
  55. package/dist/features/auctions/components/AuctionDetailPageView.d.ts +8 -3
  56. package/dist/features/auctions/components/AuctionDetailPageView.js +2 -2
  57. package/dist/features/auctions/components/MarketplaceAuctionCard.js +4 -5
  58. package/dist/features/auctions/components/PlaceBidFormClient.d.ts +27 -2
  59. package/dist/features/auctions/components/PlaceBidFormClient.js +42 -20
  60. package/dist/features/auth/components/SocialAuthButtons.js +1 -1
  61. package/dist/features/auth/hooks/useAuth.d.ts +23 -1
  62. package/dist/features/auth/hooks/useAuth.js +27 -1
  63. package/dist/features/auth/permissions/constants.d.ts +1 -1
  64. package/dist/features/auth/permissions/constants.js +3 -0
  65. package/dist/features/auth/repository/session.repository.d.ts +16 -1
  66. package/dist/features/auth/repository/session.repository.js +23 -0
  67. package/dist/features/auth/repository/user.repository.js +13 -2
  68. package/dist/features/blog/components/BlogListView.js +2 -2
  69. package/dist/features/blog/repository/blog.repository.d.ts +4 -0
  70. package/dist/features/blog/repository/blog.repository.js +1 -0
  71. package/dist/features/blog/schemas/firestore.d.ts +3 -1
  72. package/dist/features/blog/schemas/firestore.js +1 -0
  73. package/dist/features/cart/components/CartPriceBreakdown.d.ts +11 -1
  74. package/dist/features/cart/components/CartPriceBreakdown.js +3 -3
  75. package/dist/features/cart/components/StoreAddonsPicker.d.ts +9 -0
  76. package/dist/features/cart/components/StoreAddonsPicker.js +15 -5
  77. package/dist/features/cart/components/index.d.ts +1 -1
  78. package/dist/features/cart/components/index.js +1 -1
  79. package/dist/features/cart/hooks/useGuestCartMerge.d.ts +8 -1
  80. package/dist/features/cart/hooks/useGuestCartMerge.js +2 -1
  81. package/dist/features/cart/utils/line-total.d.ts +25 -0
  82. package/dist/features/cart/utils/line-total.js +26 -0
  83. package/dist/features/catalogue/repository/catalogue.repository.d.ts +12 -0
  84. package/dist/features/catalogue/repository/catalogue.repository.js +15 -0
  85. package/dist/features/categories/components/CategoryTree.js +2 -2
  86. package/dist/features/contact/components/ContactForm.js +1 -1
  87. package/dist/features/copilot/hooks/useCopilotFeedback.d.ts +1 -1
  88. package/dist/features/copilot/hooks/useCopilotFeedback.js +1 -1
  89. package/dist/features/events/components/AdminEventEditorView.js +16 -9
  90. package/dist/features/events/components/AdminEventEntriesView.js +7 -13
  91. package/dist/features/events/components/EventRafflesSection.js +14 -2
  92. package/dist/features/events/components/EventStatusBadge.js +1 -1
  93. package/dist/features/events/components/event-entry-detail-fields.d.ts +24 -0
  94. package/dist/features/events/components/event-entry-detail-fields.js +13 -0
  95. package/dist/features/events/repository/events.repository.js +1 -0
  96. package/dist/features/events/schemas/firestore.d.ts +3 -1
  97. package/dist/features/events/schemas/firestore.js +1 -0
  98. package/dist/features/faq/components/ContactCTA.js +1 -1
  99. package/dist/features/faq/components/FAQHelpfulButtons.js +2 -2
  100. package/dist/features/faq/repository/faqs.repository.d.ts +16 -1
  101. package/dist/features/faq/repository/faqs.repository.js +64 -54
  102. package/dist/features/faq/schemas/firestore.d.ts +3 -2
  103. package/dist/features/faq/schemas/firestore.js +2 -2
  104. package/dist/features/faq/schemas/index.d.ts +3 -3
  105. package/dist/features/faq/schemas/index.js +1 -1
  106. package/dist/features/filters/FilterFacetSection.js +2 -2
  107. package/dist/features/forms/Toggle.js +1 -1
  108. package/dist/features/grouped/components/GroupedListingEditorView.d.ts +18 -0
  109. package/dist/features/grouped/components/GroupedListingEditorView.js +192 -0
  110. package/dist/features/homepage/components/AdvertisementBanner.js +2 -2
  111. package/dist/features/homepage/components/BrandsSection.js +1 -1
  112. package/dist/features/homepage/components/CTABannerSection.js +1 -1
  113. package/dist/features/homepage/components/HomepageCustomerReviewsSection.js +1 -1
  114. package/dist/features/homepage/components/HomepageSectionBoundary.d.ts +39 -0
  115. package/dist/features/homepage/components/HomepageSectionBoundary.js +49 -0
  116. package/dist/features/homepage/components/ShopByCategorySection.js +1 -1
  117. package/dist/features/homepage/components/WelcomeSection.js +1 -1
  118. package/dist/features/homepage/lib/section-renderer.js +2 -1
  119. package/dist/features/layout/AppLayoutShell.js +5 -5
  120. package/dist/features/layout/BottomActions.js +5 -5
  121. package/dist/features/layout/BottomSheet.js +1 -1
  122. package/dist/features/layout/MainNavbar.js +1 -1
  123. package/dist/features/layout/NavbarLayout.js +1 -1
  124. package/dist/features/layout/TitleBarLayout.js +3 -3
  125. package/dist/features/layout/hooks/useFormBottomActions.d.ts +11 -1
  126. package/dist/features/layout/hooks/useFormBottomActions.js +16 -2
  127. package/dist/features/lottery/schemas/config-write.d.ts +141 -0
  128. package/dist/features/lottery/schemas/config-write.js +139 -0
  129. package/dist/features/media/MediaPickerModal.js +3 -1
  130. package/dist/features/media/MediaVideo.js +4 -2
  131. package/dist/features/media/components/MediaSlider.js +1 -1
  132. package/dist/features/messages/repository/conversations.repository.js +15 -5
  133. package/dist/features/orders/components/OrdersList.js +2 -2
  134. package/dist/features/payments/repository/payout.repository.d.ts +11 -1
  135. package/dist/features/payments/repository/payout.repository.js +14 -6
  136. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +3 -2
  137. package/dist/features/pre-orders/components/PreOrderBadge.js +1 -1
  138. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +1 -1
  139. package/dist/features/products/columns/productTableColumns.js +3 -3
  140. package/dist/features/products/components/CompareOverlay.js +1 -1
  141. package/dist/features/products/components/PrizeDrawDetailPageView.js +1 -1
  142. package/dist/features/products/components/PrizeDrawEntryActions.js +2 -2
  143. package/dist/features/products/components/PrizeDrawsSection.js +5 -1
  144. package/dist/features/products/components/ProductDetailActions.js +11 -7
  145. package/dist/features/products/components/ProductDetailPageView.js +3 -3
  146. package/dist/features/products/components/ProductFeatureBadges.js +2 -2
  147. package/dist/features/products/components/ProductFeaturesSelector.js +1 -1
  148. package/dist/features/products/components/ProductFilters.js +15 -8
  149. package/dist/features/products/components/ProductGrid.js +8 -17
  150. package/dist/features/products/components/ProductTabs.js +7 -4
  151. package/dist/features/products/components/ProductTabsShell.js +2 -7
  152. package/dist/features/products/constants/action-defs.d.ts +21 -4
  153. package/dist/features/products/constants/action-defs.js +7 -3
  154. package/dist/features/products/hooks/useRelatedProducts.js +2 -1
  155. package/dist/features/products/repository/products.repository.d.ts +1 -1
  156. package/dist/features/products/repository/products.repository.js +38 -16
  157. package/dist/features/products/schemas/firestore.d.ts +3 -2
  158. package/dist/features/products/schemas/firestore.js +1 -1
  159. package/dist/features/reviews/actions/review-actions.d.ts +8 -1
  160. package/dist/features/reviews/actions/review-actions.js +14 -3
  161. package/dist/features/reviews/components/ReviewDetailShell.js +10 -4
  162. package/dist/features/reviews/components/ReviewModal.js +1 -1
  163. package/dist/features/reviews/repository/reviews.repository.d.ts +29 -1
  164. package/dist/features/reviews/repository/reviews.repository.js +54 -13
  165. package/dist/features/reviews/schemas/firestore.d.ts +9 -1
  166. package/dist/features/reviews/schemas/firestore.js +1 -0
  167. package/dist/features/scams/components/ScamRegistryView.js +2 -2
  168. package/dist/features/search/components/Search.js +3 -3
  169. package/dist/features/search/components/SearchResultsSection.js +1 -1
  170. package/dist/features/seller/components/SellerAddressesView.js +3 -1
  171. package/dist/features/seller/components/SellerBidsView.js +6 -1
  172. package/dist/features/seller/components/SellerSidebar.js +1 -1
  173. package/dist/features/shell/SectionForm.d.ts +21 -1
  174. package/dist/features/shell/SectionForm.js +15 -3
  175. package/dist/features/shell/build-sections.js +10 -1
  176. package/dist/features/shell/field-ui-meta.d.ts +21 -0
  177. package/dist/features/shipments/components/AdminShipmentLotItemsView.js +23 -6
  178. package/dist/features/site-settings/components/ActionPermissionsManager.js +1 -1
  179. package/dist/features/store-extensions/repository/store-extensions.repositories.d.ts +21 -4
  180. package/dist/features/store-extensions/repository/store-extensions.repositories.js +24 -4
  181. package/dist/features/store-extensions/schemas/shipping-config-form.js +13 -0
  182. package/dist/features/store-extensions/schemas/store-category-form.js +1 -1
  183. package/dist/features/stores/actions/store-query-actions.js +25 -1
  184. package/dist/features/stores/components/InteractiveStoreCard.js +1 -1
  185. package/dist/features/stores/components/StoreHeader.js +1 -1
  186. package/dist/features/stores/components/StoreNavTabs.js +20 -8
  187. package/dist/features/stores/repository/store.repository.js +1 -0
  188. package/dist/features/stores/schemas/firestore.d.ts +2 -0
  189. package/dist/features/support/repository/support.repository.d.ts +12 -0
  190. package/dist/features/support/repository/support.repository.js +15 -0
  191. package/dist/features/support/schemas/ticket-create-form.d.ts +33 -0
  192. package/dist/features/support/schemas/ticket-create-form.js +82 -0
  193. package/dist/features/tester/repository/tester-checklist-item.repository.d.ts +0 -1
  194. package/dist/features/tester/repository/tester-checklist-item.repository.js +6 -15
  195. package/dist/features/tester/schemas/firestore.d.ts +5 -4
  196. package/dist/features/tester/schemas/firestore.js +3 -3
  197. package/dist/features/tester/seed-data/products-tester-seed-data.js +2 -2
  198. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +138 -1
  199. package/dist/features/wishlist/components/WishlistHeartButton.d.ts +55 -0
  200. package/dist/features/wishlist/components/WishlistHeartButton.js +52 -0
  201. package/dist/features/wishlist/components/index.d.ts +2 -1
  202. package/dist/features/wishlist/components/index.js +1 -1
  203. package/dist/index.d.ts +10 -3
  204. package/dist/index.js +19 -4
  205. package/dist/monitoring/error-tracking.js +39 -5
  206. package/dist/monitoring/server-logger.js +70 -32
  207. package/dist/next/components/ErrorView.js +1 -1
  208. package/dist/next/routing/route-map.d.ts +39 -7
  209. package/dist/next/routing/route-map.js +34 -4
  210. package/dist/providers/db-firebase/base.repository.d.ts +30 -0
  211. package/dist/providers/db-firebase/base.repository.js +56 -9
  212. package/dist/react/ErrorBoundary.js +9 -1
  213. package/dist/react/contexts/SessionContext.js +6 -2
  214. package/dist/react/hooks/useAuthGate.d.ts +22 -0
  215. package/dist/react/hooks/useAuthGate.js +86 -7
  216. package/dist/schemas/registry.d.ts +3 -3
  217. package/dist/security/index.d.ts +1 -1
  218. package/dist/security/index.js +1 -1
  219. package/dist/security/pii-encrypt.d.ts +13 -5
  220. package/dist/security/pii-encrypt.js +132 -6
  221. package/dist/security/pii-schemas.d.ts +32 -4
  222. package/dist/security/pii-schemas.js +38 -5
  223. package/dist/seed/_helpers/product-search-txt.d.ts +18 -0
  224. package/dist/seed/_helpers/product-search-txt.js +33 -0
  225. package/dist/seed/_helpers/search-txt-wrappers.d.ts +20 -0
  226. package/dist/seed/_helpers/search-txt-wrappers.js +73 -0
  227. package/dist/seed/blog-posts-seed-data.d.ts +4 -0
  228. package/dist/seed/blog-posts-seed-data.js +7 -1
  229. package/dist/seed/events-seed-data.d.ts +5 -1
  230. package/dist/seed/events-seed-data.js +7 -1
  231. package/dist/seed/faq-seed-data.d.ts +16 -0
  232. package/dist/seed/faq-seed-data.js +22 -1
  233. package/dist/seed/products-art-seed-data.js +49 -7
  234. package/dist/seed/products-auctions-seed-data.js +12 -4
  235. package/dist/seed/products-classifieds-seed-data.d.ts +5 -0
  236. package/dist/seed/products-classifieds-seed-data.js +65 -9
  237. package/dist/seed/products-digital-codes-seed-data.d.ts +5 -0
  238. package/dist/seed/products-digital-codes-seed-data.js +65 -9
  239. package/dist/seed/products-live-items-seed-data.d.ts +5 -0
  240. package/dist/seed/products-live-items-seed-data.js +33 -5
  241. package/dist/seed/products-preorders-seed-data.d.ts +1 -1
  242. package/dist/seed/products-preorders-seed-data.js +6 -2
  243. package/dist/seed/products-prize-draws-seed-data.d.ts +5 -0
  244. package/dist/seed/products-prize-draws-seed-data.js +57 -8
  245. package/dist/seed/products-standard-seed-data.js +6 -2
  246. package/dist/seed/products-stickers-seed-data.js +49 -7
  247. package/dist/seed/reviews-seed-data.js +2 -1
  248. package/dist/seed/site-settings-seed-data.js +5 -3
  249. package/dist/seed/stores-seed-data.d.ts +4 -0
  250. package/dist/seed/stores-seed-data.js +7 -1
  251. package/dist/seo/json-ld.d.ts +44 -2
  252. package/dist/seo/json-ld.js +57 -11
  253. package/dist/styles.css +368 -90
  254. package/dist/tailwind-utilities.css +1 -1
  255. package/dist/tokens/index.d.ts +1 -1
  256. package/dist/tokens/index.js +1 -1
  257. package/dist/tokens/themes/default-dark.js +6 -0
  258. package/dist/tokens/themes/default-light.js +5 -0
  259. package/dist/tokens/tokens.css +84 -0
  260. package/dist/ui/DataTable.js +1 -1
  261. package/dist/ui/DataTable.style.css +3 -3
  262. package/dist/ui/components/BulkActionBar.style.css +1 -3
  263. package/dist/ui/components/Button.js +15 -6
  264. package/dist/ui/components/Dropdown.style.css +1 -4
  265. package/dist/ui/components/FilterChipGroup.js +1 -1
  266. package/dist/ui/components/FilterDrawer.style.css +1 -1
  267. package/dist/ui/components/Icon.d.ts +53 -0
  268. package/dist/ui/components/Icon.js +41 -0
  269. package/dist/ui/components/IconButton.d.ts +13 -0
  270. package/dist/ui/components/IconButton.js +13 -0
  271. package/dist/ui/components/IconButton.style.css +18 -10
  272. package/dist/ui/components/ListingLayout.style.css +2 -10
  273. package/dist/ui/components/ListingToolbar.js +6 -6
  274. package/dist/ui/components/Modal.js +1 -1
  275. package/dist/ui/components/PaginatedSelect.style.css +3 -3
  276. package/dist/ui/components/Pagination.style.css +1 -6
  277. package/dist/ui/components/RichTextEditor.js +1 -1
  278. package/dist/ui/components/RowActionMenu.style.css +1 -1
  279. package/dist/ui/components/SideDrawer.style.css +1 -1
  280. package/dist/ui/components/Slider.js +1 -1
  281. package/dist/ui/components/TabBarShell.d.ts +78 -0
  282. package/dist/ui/components/TabBarShell.js +95 -0
  283. package/dist/ui/components/Tabs.js +12 -8
  284. package/dist/ui/components/Tabs.style.css +249 -41
  285. package/dist/ui/components/ViewToggle.style.css +1 -5
  286. package/dist/ui/components/tabs-overflow.d.ts +17 -0
  287. package/dist/ui/components/tabs-overflow.js +142 -0
  288. package/dist/ui/icons/icon-registry.d.ts +38 -0
  289. package/dist/ui/icons/icon-registry.js +37 -0
  290. package/dist/ui/index.d.ts +6 -0
  291. package/dist/ui/index.js +3 -0
  292. package/dist/utils/index.d.ts +1 -1
  293. package/dist/utils/index.js +1 -1
  294. package/dist/utils/media-url.d.ts +27 -4
  295. package/dist/utils/media-url.js +37 -6
  296. package/dist/utils/search-txt.d.ts +71 -0
  297. package/dist/utils/search-txt.js +118 -0
  298. package/package.json +1 -1
@@ -18,10 +18,11 @@
18
18
  * @tag consumers:seed/index.ts,seed/runner.ts
19
19
  * @tag sideEffects:none
20
20
  */
21
+ import { withProductSearchTxt } from "./_helpers/product-search-txt";
21
22
  import { PRODUCT_FIELDS } from "../constants/field-names";
22
- import { buildSearchTokens } from "../utils/search-tokens";
23
+ import { buildSearchTxt } from "../utils/search-txt";
23
24
  import { seedExtMedia } from "./_helpers/media";
24
- export const productsPrizeDrawsSeedData = [
25
+ const _rawproductsPrizeDrawsSeedData = [
25
26
  {
26
27
  id: "prizedraw-beyblade-mystery-box",
27
28
  slug: "prizedraw-beyblade-mystery-box",
@@ -66,7 +67,14 @@ export const productsPrizeDrawsSeedData = [
66
67
  tags: ["prize-draw", "mystery-box"],
67
68
  createdAt: new Date("2026-05-01"),
68
69
  updatedAt: new Date("2026-05-01"),
69
- searchTokens: buildSearchTokens("Beyblade Mystery Box — Prize Draw", "Buy an entry and reveal your prize instantly.", "Beyblade", "brand-beyblade", ["Spinning Tops"], ["prize-draw", "mystery-box"]),
70
+ searchTxt: buildSearchTxt([
71
+ "Beyblade Mystery Box — Prize Draw",
72
+ "Buy an entry and reveal your prize instantly.",
73
+ "Beyblade",
74
+ "brand-beyblade",
75
+ ["Spinning Tops"],
76
+ ["prize-draw", "mystery-box"],
77
+ ]),
70
78
  },
71
79
  {
72
80
  id: "prizedraw-beyblade-scheduled-demo",
@@ -110,7 +118,14 @@ export const productsPrizeDrawsSeedData = [
110
118
  tags: ["prize-draw", "mystery-box"],
111
119
  createdAt: new Date("2026-05-01"),
112
120
  updatedAt: new Date("2026-05-01"),
113
- searchTokens: buildSearchTokens("Beyblade Champion's Draw — Prize Draw", "Two entries, two prizes, revealed automatically at close or sellout.", "Beyblade", "brand-beyblade", ["Spinning Tops"], ["prize-draw", "mystery-box"]),
121
+ searchTxt: buildSearchTxt([
122
+ "Beyblade Champion's Draw — Prize Draw",
123
+ "Two entries, two prizes, revealed automatically at close or sellout.",
124
+ "Beyblade",
125
+ "brand-beyblade",
126
+ ["Spinning Tops"],
127
+ ["prize-draw", "mystery-box"],
128
+ ]),
114
129
  },
115
130
  // --- Partially sold: prizeCurrentEntries > 0, main seed never exercised this before ---
116
131
  {
@@ -162,7 +177,14 @@ export const productsPrizeDrawsSeedData = [
162
177
  tags: ["prize-draw", "mystery-box", "chase-top"],
163
178
  createdAt: new Date("2026-08-15"),
164
179
  updatedAt: new Date("2026-08-19"),
165
- searchTokens: buildSearchTokens("Beyblade X Legendary Vault — Prize Draw", "6 entries, 6 prizes, over half already sold.", "Takara-Tomy", "brand-takara-tomy", ["Beyblade X", "Spinning Tops"], ["prize-draw", "mystery-box", "chase-top"]),
180
+ searchTxt: buildSearchTxt([
181
+ "Beyblade X Legendary Vault — Prize Draw",
182
+ "6 entries, 6 prizes, over half already sold.",
183
+ "Takara-Tomy",
184
+ "brand-takara-tomy",
185
+ ["Beyblade X", "Spinning Tops"],
186
+ ["prize-draw", "mystery-box", "chase-top"],
187
+ ]),
166
188
  },
167
189
  // --- Closed + revealed: real winners, isWon:true — permanent-catalog example (previously only in tester sandbox) ---
168
190
  {
@@ -208,7 +230,14 @@ export const productsPrizeDrawsSeedData = [
208
230
  tags: ["prize-draw", "mystery-box"],
209
231
  createdAt: new Date("2026-08-05"),
210
232
  updatedAt: new Date("2026-08-12"),
211
- searchTokens: buildSearchTokens("Metal Fight Mystery Draw — Ended (Revealed)", "This draw has closed and every prize has been revealed.", "Takara-Tomy", "brand-takara-tomy", ["Beyblade Metal Fight", "Spinning Tops"], ["prize-draw", "mystery-box"]),
233
+ searchTxt: buildSearchTxt([
234
+ "Metal Fight Mystery Draw — Ended (Revealed)",
235
+ "This draw has closed and every prize has been revealed.",
236
+ "Takara-Tomy",
237
+ "brand-takara-tomy",
238
+ ["Beyblade Metal Fight", "Spinning Tops"],
239
+ ["prize-draw", "mystery-box"],
240
+ ]),
212
241
  },
213
242
  // --- Nearly sold out, scheduled reveal ---
214
243
  {
@@ -259,7 +288,14 @@ export const productsPrizeDrawsSeedData = [
259
288
  tags: ["prize-draw", "mystery-box"],
260
289
  createdAt: new Date("2026-08-17"),
261
290
  updatedAt: new Date("2026-08-19"),
262
- searchTokens: buildSearchTokens("Beyblade Burst Collector's Draw — Almost Sold Out", "Only 1 entry left, 4 of 5 slots already claimed.", "Beyblade", "brand-beyblade", ["Beyblade Burst", "Spinning Tops"], ["prize-draw", "mystery-box"]),
291
+ searchTxt: buildSearchTxt([
292
+ "Beyblade Burst Collector's Draw — Almost Sold Out",
293
+ "Only 1 entry left, 4 of 5 slots already claimed.",
294
+ "Beyblade",
295
+ "brand-beyblade",
296
+ ["Beyblade Burst", "Spinning Tops"],
297
+ ["prize-draw", "mystery-box"],
298
+ ]),
263
299
  },
264
300
  // --- High-value vintage vault, multi-image collage per prize ---
265
301
  {
@@ -308,7 +344,14 @@ export const productsPrizeDrawsSeedData = [
308
344
  tags: ["prize-draw", "mystery-box", "vintage-collectible"],
309
345
  createdAt: new Date("2026-08-18"),
310
346
  updatedAt: new Date("2026-08-18"),
311
- searchTokens: buildSearchTokens("Beyblade Original Vintage Vault — Prize Draw", "High-value original-series vault, multi-angle photos per prize.", "Beyblade", "brand-beyblade", ["Beyblade Original", "Spinning Tops"], ["prize-draw", "mystery-box", "vintage-collectible"]),
347
+ searchTxt: buildSearchTxt([
348
+ "Beyblade Original Vintage Vault — Prize Draw",
349
+ "High-value original-series vault, multi-angle photos per prize.",
350
+ "Beyblade",
351
+ "brand-beyblade",
352
+ ["Beyblade Original", "Spinning Tops"],
353
+ ["prize-draw", "mystery-box", "vintage-collectible"],
354
+ ]),
312
355
  },
313
356
  {
314
357
  // Closed, but with slots still unsold and `isSold: false`.
@@ -360,3 +403,9 @@ export const productsPrizeDrawsSeedData = [
360
403
  updatedAt: new Date("2026-08-24"),
361
404
  },
362
405
  ];
406
+ /**
407
+ * Every record gains `searchTxt` here rather than inline, so a fixture added at
408
+ * the bottom of the array cannot ship without it — which is exactly how the
409
+ * sold/depleted fixture in this file ended up unsearchable.
410
+ */
411
+ export const productsPrizeDrawsSeedData = _rawproductsPrizeDrawsSeedData.map(withProductSearchTxt);
@@ -23,7 +23,7 @@
23
23
  * @tag sideEffects:none
24
24
  */
25
25
  import { PRODUCT_FIELDS } from "../constants/field-names";
26
- import { buildSearchTokens } from "../utils/search-tokens";
26
+ import { buildSearchTxt } from "../utils/search-txt";
27
27
  import { seedExtMedia } from "./_helpers/media";
28
28
  /*
29
29
  * Real Beyblade attributes per fixture — Root Cause #6 (standard was the
@@ -170,7 +170,11 @@ function withTokens(p) {
170
170
  tags: [],
171
171
  featured: false,
172
172
  ...p,
173
- searchTokens: buildSearchTokens(p.title, p.description, p.brand, p.brandSlug, p.categoryNames, p.tags, p.features, p.condition, p.specifications?.map((s) => `${s.name} ${s.value}`)),
173
+ searchTxt: buildSearchTxt([
174
+ p.title, p.description, p.brand, p.brandSlug,
175
+ p.categoryNames, p.tags, p.features, p.condition,
176
+ p.specifications?.map((s) => `${s.name} ${s.value}`),
177
+ ]),
174
178
  };
175
179
  }
176
180
  const _rawProductsStandardSeedData = [
@@ -17,7 +17,7 @@
17
17
  * @tag sideEffects:none
18
18
  */
19
19
  import { PRODUCT_FIELDS } from "../constants/field-names";
20
- import { buildSearchTokens } from "../utils/search-tokens";
20
+ import { buildSearchTxt } from "../utils/search-txt";
21
21
  import { seedExtMedia } from "./_helpers/media";
22
22
  export const productsStickersSeedData = [
23
23
  {
@@ -50,7 +50,14 @@ export const productsStickersSeedData = [
50
50
  tags: ["stickers", "vintage-collectible"],
51
51
  createdAt: new Date("2026-08-17"),
52
52
  updatedAt: new Date("2026-08-17"),
53
- searchTokens: buildSearchTokens("Beyblade Original Classic — Sticker Sheet", "5x5 cm sticker sheet featuring Dranzer, Driger, Draciel, and Dragoon.", "Beyblade", "brand-beyblade", ["Beyblade Original", "Spinning Tops"], ["stickers", "vintage-collectible"]),
53
+ searchTxt: buildSearchTxt([
54
+ "Beyblade Original Classic — Sticker Sheet",
55
+ "5x5 cm sticker sheet featuring Dranzer, Driger, Draciel, and Dragoon.",
56
+ "Beyblade",
57
+ "brand-beyblade",
58
+ ["Beyblade Original", "Spinning Tops"],
59
+ ["stickers", "vintage-collectible"],
60
+ ]),
54
61
  },
55
62
  {
56
63
  id: "stickers-beyblade-x-holographic-pack",
@@ -85,7 +92,14 @@ export const productsStickersSeedData = [
85
92
  tags: ["stickers"],
86
93
  createdAt: new Date("2026-08-18"),
87
94
  updatedAt: new Date("2026-08-19"),
88
- searchTokens: buildSearchTokens("Beyblade X Holographic Sticker Pack", "Holographic-finish sticker pack featuring the current Beyblade X lineup.", "Takara-Tomy", "brand-takara-tomy", ["Beyblade X", "Spinning Tops"], ["stickers"]),
95
+ searchTxt: buildSearchTxt([
96
+ "Beyblade X Holographic Sticker Pack",
97
+ "Holographic-finish sticker pack featuring the current Beyblade X lineup.",
98
+ "Takara-Tomy",
99
+ "brand-takara-tomy",
100
+ ["Beyblade X", "Spinning Tops"],
101
+ ["stickers"],
102
+ ]),
89
103
  },
90
104
  {
91
105
  id: "stickers-beyblade-burst-diecut-set",
@@ -117,7 +131,14 @@ export const productsStickersSeedData = [
117
131
  tags: ["stickers"],
118
132
  createdAt: new Date("2026-08-19"),
119
133
  updatedAt: new Date("2026-08-19"),
120
- searchTokens: buildSearchTokens("Beyblade Burst Die-Cut Sticker Set (6-Pack)", "Individually die-cut vinyl stickers of 6 fan-favorite Burst tops.", "Beyblade", "brand-beyblade", ["Beyblade Burst", "Spinning Tops"], ["stickers"]),
134
+ searchTxt: buildSearchTxt([
135
+ "Beyblade Burst Die-Cut Sticker Set (6-Pack)",
136
+ "Individually die-cut vinyl stickers of 6 fan-favorite Burst tops.",
137
+ "Beyblade",
138
+ "brand-beyblade",
139
+ ["Beyblade Burst", "Spinning Tops"],
140
+ ["stickers"],
141
+ ]),
121
142
  },
122
143
  {
123
144
  id: "stickers-beyblade-metal-retro-sheet",
@@ -149,7 +170,14 @@ export const productsStickersSeedData = [
149
170
  tags: ["stickers", "vintage-collectible", "limited-run"],
150
171
  createdAt: new Date("2026-08-19"),
151
172
  updatedAt: new Date("2026-08-19"),
152
- searchTokens: buildSearchTokens("Metal Fight Retro Sticker Sheet — Limited /500", "Limited-edition retro-styled sticker sheet, numbered out of 500.", "Takara-Tomy", "brand-takara-tomy", ["Beyblade Metal Fight", "Spinning Tops"], ["stickers", "vintage-collectible", "limited-run"]),
173
+ searchTxt: buildSearchTxt([
174
+ "Metal Fight Retro Sticker Sheet — Limited /500",
175
+ "Limited-edition retro-styled sticker sheet, numbered out of 500.",
176
+ "Takara-Tomy",
177
+ "brand-takara-tomy",
178
+ ["Beyblade Metal Fight", "Spinning Tops"],
179
+ ["stickers", "vintage-collectible", "limited-run"],
180
+ ]),
153
181
  },
154
182
  {
155
183
  id: "stickers-beyblade-x-glow-in-dark",
@@ -184,7 +212,14 @@ export const productsStickersSeedData = [
184
212
  tags: ["stickers"],
185
213
  createdAt: new Date("2026-08-19"),
186
214
  updatedAt: new Date("2026-08-19"),
187
- searchTokens: buildSearchTokens("Beyblade X Glow-in-the-Dark Sticker Pack", "Charge under light and watch the Beyblade X logos glow in the dark.", "Takara-Tomy", "brand-takara-tomy", ["Beyblade X", "Spinning Tops"], ["stickers"]),
215
+ searchTxt: buildSearchTxt([
216
+ "Beyblade X Glow-in-the-Dark Sticker Pack",
217
+ "Charge under light and watch the Beyblade X logos glow in the dark.",
218
+ "Takara-Tomy",
219
+ "brand-takara-tomy",
220
+ ["Beyblade X", "Spinning Tops"],
221
+ ["stickers"],
222
+ ]),
188
223
  },
189
224
  {
190
225
  // Sold-out fixture — see the art file's equivalent for the shape rationale.
@@ -219,6 +254,13 @@ export const productsStickersSeedData = [
219
254
  tags: ["stickers", "sold-out"],
220
255
  createdAt: new Date("2026-08-24"),
221
256
  updatedAt: new Date("2026-08-24"),
222
- searchTokens: buildSearchTokens("Beyblade Metal Fight Sticker Sheet (Sold Out)", "The original Metal Fight sticker sheet run, now fully sold out.", "Beyblade", "brand-beyblade", ["Beyblade Metal", "Spinning Tops"], ["stickers", "sold-out"]),
257
+ searchTxt: buildSearchTxt([
258
+ "Beyblade Metal Fight Sticker Sheet (Sold Out)",
259
+ "The original Metal Fight sticker sheet run, now fully sold out.",
260
+ "Beyblade",
261
+ "brand-beyblade",
262
+ ["Beyblade Metal", "Spinning Tops"],
263
+ ["stickers", "sold-out"],
264
+ ]),
223
265
  },
224
266
  ];
@@ -14,6 +14,7 @@
14
14
  * @tag consumers:seed/index.ts,seed/runner.ts
15
15
  * @tag sideEffects:none
16
16
  */
17
+ import { withReviewSearchTxt } from "./_helpers/search-txt-wrappers";
17
18
  import { seedExtMedia } from "./_helpers/media";
18
19
  const NOW = new Date();
19
20
  const daysAgo = (n) => new Date(NOW.getTime() - n * 86400000);
@@ -176,4 +177,4 @@ for (let i = 0; i < 14; i++) {
176
177
  updatedAt: daysAgo(daysAgoCreated),
177
178
  });
178
179
  }
179
- export const reviewsSeedData = _rawReviewsSeedData;
180
+ export const reviewsSeedData = _rawReviewsSeedData.map(withReviewSearchTxt);
@@ -418,11 +418,13 @@ export const siteSettingsSeedData = {
418
418
  codDepositPercent: 10,
419
419
  codHandlingFeeMin: 200,
420
420
  codHandlingFeePercent: 10,
421
- whatsappNotifyFeeEnabled: false,
421
+ // Enabled so a seeded install actually shows the add-ons — see the matching
422
+ // comment on DEFAULT_SITE_SETTINGS_DATA.commissions.
423
+ whatsappNotifyFeeEnabled: true,
422
424
  whatsappNotifyFee: 10,
423
- giftWrapFeeEnabled: false,
425
+ giftWrapFeeEnabled: true,
424
426
  giftWrapFee: 49,
425
- shipmentProtectionFeeEnabled: false,
427
+ shipmentProtectionFeeEnabled: true,
426
428
  shipmentProtectionFeePercent: 2,
427
429
  shipmentProtectionFeeMin: 30,
428
430
  sellerShippingFixed: 0,
@@ -1,2 +1,6 @@
1
1
  import type { StoreDocument } from "../features/stores/schemas";
2
+ /**
3
+ * Tokens derived here, not per record — see _helpers/search-txt-wrappers.ts for
4
+ * why the wrapper form is what makes omission impossible.
5
+ */
2
6
  export declare const storesSeedData: Partial<StoreDocument>[];
@@ -15,6 +15,7 @@
15
15
  * @tag consumers:seed/runner.ts
16
16
  * @tag sideEffects:none
17
17
  */
18
+ import { withStoreSearchTxt } from "./_helpers/search-txt-wrappers";
18
19
  import { STORE_FIELDS } from "../constants/field-names";
19
20
  import { seedExtMedia } from "./_helpers/media";
20
21
  const NOW = new Date();
@@ -30,7 +31,7 @@ const daysAgo = (n) => new Date(NOW.getTime() - n * 86400000);
30
31
  function entry(at, actorRole, trigger, changes, extra) {
31
32
  return { at, actorRole, trigger, changes, ...extra };
32
33
  }
33
- export const storesSeedData = [
34
+ const _rawstoresSeedData = [
34
35
  // ── Store 1: LetItRip Official (admin-owned, platform storefront) ──────────
35
36
  {
36
37
  id: "store-letitrip-official",
@@ -262,3 +263,8 @@ export const storesSeedData = [
262
263
  ],
263
264
  },
264
265
  ];
266
+ /**
267
+ * Tokens derived here, not per record — see _helpers/search-txt-wrappers.ts for
268
+ * why the wrapper form is what makes omission impossible.
269
+ */
270
+ export const storesSeedData = _rawstoresSeedData.map(withStoreSearchTxt);
@@ -36,6 +36,25 @@ export interface ProductJsonLdInput {
36
36
  auctionEndDate?: Date;
37
37
  /** Canonical discriminator (SB1-G Phase 4). */
38
38
  listingType?: ListingType;
39
+ /**
40
+ * Denormalised rating, straight off `ProductDocument.avgRating` /
41
+ * `.reviewCount` — so emitting it costs **zero** extra Firestore reads.
42
+ *
43
+ * Merged into THIS node rather than emitted as a separate `Product` via
44
+ * `aggregateRatingJsonLd`, which builds a second node carrying only
45
+ * name/url/aggregateRating and no `offers`. Two `Product` nodes for one page
46
+ * duplicates the entity, and a `Product` with no offers is incomplete for
47
+ * Google — merging is the shape that actually earns review stars.
48
+ *
49
+ * Deliberately NOT accompanied by per-review `Review` nodes: schema.org
50
+ * `Review.author` is personal data, and reviewer names are masked on public
51
+ * surfaces (`maskPublicReview`). The stars in a SERP come from the aggregate,
52
+ * so this yields the full benefit with no identity exposure.
53
+ */
54
+ rating?: {
55
+ average: number;
56
+ count: number;
57
+ };
39
58
  }
40
59
  export interface ReviewJsonLdInput {
41
60
  id: string;
@@ -74,7 +93,30 @@ export declare function aggregateRatingJsonLd(product: Pick<ProductJsonLdInput,
74
93
  export declare function breadcrumbJsonLd(items: BreadcrumbJsonLdItem[]): Record<string, JsonLdValue>;
75
94
  export declare function faqJsonLd(faqs: FaqJsonLdInput[]): Record<string, JsonLdValue>;
76
95
  export declare function blogPostJsonLd(post: BlogPostJsonLdInput): Record<string, JsonLdValue>;
77
- export declare function organizationJsonLd(): Record<string, JsonLdValue>;
78
- export declare function searchBoxJsonLd(): Record<string, JsonLdValue>;
96
+ /**
97
+ * Site-identity options for the two site-wide nodes.
98
+ *
99
+ * These used to read `NEXT_PUBLIC_SITE_NAME` / `NEXT_PUBLIC_SITE_URL` directly,
100
+ * with fallbacks of `"App"` and `""`. Two live consequences:
101
+ *
102
+ * - Production had `NEXT_PUBLIC_SITE_NAME="Letitrip"` — the wrong casing, which
103
+ * CLAUDE.md's brand rule explicitly forbids — so every page emitted
104
+ * `Organization.name: "Letitrip"`, the string Google may show in a Knowledge
105
+ * Panel. A brand name should not be settable by a mis-typed env var.
106
+ * - With the env unset the nodes emit `name: "App"` and `url: ""`, which is a
107
+ * valid-looking but wrong entity rather than a visible failure.
108
+ *
109
+ * Callers pass their real config (the consumer has `SEO_CONFIG.siteName` /
110
+ * `.siteUrl` from appkit.config.js, the single canonical host definition). The
111
+ * env values remain as a fallback so existing callers keep working.
112
+ */
113
+ export interface SiteIdentityOptions {
114
+ siteName?: string;
115
+ siteUrl?: string;
116
+ /** Real social/profile URLs — feeds schema.org `sameAs`, which drives entity recognition. */
117
+ sameAs?: readonly string[];
118
+ }
119
+ export declare function organizationJsonLd(opts?: SiteIdentityOptions): Record<string, JsonLdValue>;
120
+ export declare function searchBoxJsonLd(opts?: SiteIdentityOptions): Record<string, JsonLdValue>;
79
121
  export declare function auctionJsonLd(auction: ProductJsonLdInput): Record<string, JsonLdValue>;
80
122
  export {};
@@ -14,15 +14,42 @@
14
14
  */
15
15
  const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? "";
16
16
  const SITE_NAME = process.env.NEXT_PUBLIC_SITE_NAME ?? "App";
17
+ /**
18
+ * schema.org requires ABSOLUTE URLs. A relative `image` or `item` is not a
19
+ * lenient-parse case — Google rejects the property, and `image` is *required*
20
+ * for Product rich results, so a relative one costs the whole rich result.
21
+ *
22
+ * `productJsonLd` prefixed `url` and `offers.url` with SITE_URL but passed
23
+ * `image[]` through untouched, so every product emitted four relative
24
+ * `/api/media/ext?...` image URLs and no product could earn a rich result.
25
+ *
26
+ * Leaves already-absolute URLs (and `data:` URIs) alone. Returns undefined for
27
+ * an empty value so `JSON.stringify` drops the key rather than emitting `""`.
28
+ */
29
+ function absoluteUrl(value, base = SITE_URL) {
30
+ const v = value?.trim();
31
+ if (!v)
32
+ return undefined;
33
+ if (/^(https?:)?\/\//i.test(v) || v.startsWith("data:"))
34
+ return v;
35
+ if (!base)
36
+ return undefined; // no base to resolve against — omit rather than emit a bare path
37
+ return `${base.replace(/\/+$/, "")}/${v.replace(/^\/+/, "")}`;
38
+ }
17
39
  import { ProductStatusValues } from "../features/products/schemas";
18
40
  import { getDefaultCurrency } from "../core/baseline-resolver";
19
41
  // --- Helpers -----------------------------------------------------------------
20
42
  export function productJsonLd(product) {
21
43
  const url = `${SITE_URL}/products/${product.slug}`;
44
+ // Absolutise, then de-duplicate: `mainImage` is very often also `images[0]`,
45
+ // which produced the same URL twice in the emitted array.
22
46
  const images = [
23
47
  ...(product.mainImage ? [product.mainImage] : []),
24
48
  ...(product.images || []),
25
- ];
49
+ ]
50
+ .map((img) => absoluteUrl(img))
51
+ .filter((img) => Boolean(img))
52
+ .filter((img, i, arr) => arr.indexOf(img) === i);
26
53
  return {
27
54
  "@context": "https://schema.org",
28
55
  "@type": "Product",
@@ -47,6 +74,18 @@ export function productJsonLd(product) {
47
74
  ? { "@type": "Organization", name: product.sellerName }
48
75
  : undefined,
49
76
  },
77
+ // Google requires ratingValue AND a positive reviewCount; a zero-count
78
+ // AggregateRating is invalid and suppresses the whole rich result, so omit
79
+ // the key entirely rather than emitting an empty one.
80
+ aggregateRating: product.rating && product.rating.count > 0 && product.rating.average > 0
81
+ ? {
82
+ "@type": "AggregateRating",
83
+ ratingValue: product.rating.average,
84
+ reviewCount: product.rating.count,
85
+ bestRating: 5,
86
+ worstRating: 1,
87
+ }
88
+ : undefined,
50
89
  };
51
90
  }
52
91
  export function reviewJsonLd(review) {
@@ -123,32 +162,39 @@ export function blogPostJsonLd(post) {
123
162
  mainEntityOfPage: { "@type": "WebPage", "@id": url },
124
163
  };
125
164
  }
126
- export function organizationJsonLd() {
165
+ export function organizationJsonLd(opts) {
166
+ const name = opts?.siteName?.trim() || SITE_NAME;
167
+ const base = (opts?.siteUrl?.trim() || SITE_URL).replace(/\/+$/, "");
168
+ // `sameAs: []` was hardcoded empty while appkit.config.js carried real
169
+ // socialUrls that nothing read. An empty array is worse than omitting the key.
170
+ const sameAs = (opts?.sameAs ?? []).filter(Boolean);
127
171
  return {
128
172
  "@context": "https://schema.org",
129
173
  "@type": "Organization",
130
- name: SITE_NAME,
131
- url: SITE_URL,
132
- logo: `${SITE_URL}/icons/icon-512x512.png`,
133
- sameAs: [],
174
+ name,
175
+ url: base || undefined,
176
+ logo: absoluteUrl("/icons/icon-512x512.png", base),
177
+ sameAs: sameAs.length > 0 ? [...sameAs] : undefined,
134
178
  contactPoint: {
135
179
  "@type": "ContactPoint",
136
180
  contactType: "customer support",
137
- url: `${SITE_URL}/contact`,
181
+ url: absoluteUrl("/contact", base),
138
182
  },
139
183
  };
140
184
  }
141
- export function searchBoxJsonLd() {
185
+ export function searchBoxJsonLd(opts) {
186
+ const name = opts?.siteName?.trim() || SITE_NAME;
187
+ const base = (opts?.siteUrl?.trim() || SITE_URL).replace(/\/+$/, "");
142
188
  return {
143
189
  "@context": "https://schema.org",
144
190
  "@type": "WebSite",
145
- name: SITE_NAME,
146
- url: SITE_URL,
191
+ name,
192
+ url: base || undefined,
147
193
  potentialAction: {
148
194
  "@type": "SearchAction",
149
195
  target: {
150
196
  "@type": "EntryPoint",
151
- urlTemplate: `${SITE_URL}/search?q={search_term_string}`,
197
+ urlTemplate: `${base}/search?q={search_term_string}`,
152
198
  },
153
199
  "query-input": "required name=search_term_string",
154
200
  },