@mohasinac/appkit 4.46.0 → 4.48.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 (175) hide show
  1. package/dist/.build-stamp.json +4 -4
  2. package/dist/_internal/server/features/checkout/expand-order-items.js +3 -0
  3. package/dist/_internal/server/features/messages/actions.d.ts +68 -0
  4. package/dist/_internal/server/features/messages/actions.js +249 -0
  5. package/dist/_internal/server/features/parts/buildable.d.ts +47 -0
  6. package/dist/_internal/server/features/parts/buildable.js +159 -0
  7. package/dist/_internal/server/features/products/list-public.d.ts +17 -0
  8. package/dist/_internal/server/features/products/list-public.js +92 -5
  9. package/dist/_internal/server/features/products/og.d.ts +7 -0
  10. package/dist/_internal/server/features/products/og.js +38 -0
  11. package/dist/_internal/server/features/site-settings/adapters.d.ts +1 -1
  12. package/dist/_internal/server/features/site-settings/adapters.js +6 -0
  13. package/dist/_internal/server/jobs/core/cleanupRtdbEvents.js +28 -0
  14. package/dist/_internal/server/jobs/core/notificationPrune.js +87 -3
  15. package/dist/_internal/server/jobs/core/priceIndexRollup.js +36 -1
  16. package/dist/_internal/shared/actions/action-registry.js +8 -0
  17. package/dist/_internal/shared/features/notifications/action-url.js +8 -0
  18. package/dist/_internal/shared/features/notifications/email-eligibility.js +3 -0
  19. package/dist/_internal/shared/features/site-settings/types.d.ts +4 -0
  20. package/dist/client.d.ts +10 -0
  21. package/dist/client.js +8 -0
  22. package/dist/constants/api-endpoints.d.ts +48 -0
  23. package/dist/constants/api-endpoints.js +30 -0
  24. package/dist/constants/notification-types.d.ts +1 -1
  25. package/dist/features/about/components/GstExplainerView.d.ts +28 -0
  26. package/dist/features/about/components/GstExplainerView.js +59 -0
  27. package/dist/features/about/components/GuidesHubView.d.ts +28 -0
  28. package/dist/features/about/components/GuidesHubView.js +58 -0
  29. package/dist/features/about/components/PublicProfileView.js +5 -0
  30. package/dist/features/about/components/SpotAFakeView.d.ts +29 -0
  31. package/dist/features/about/components/SpotAFakeView.js +49 -0
  32. package/dist/features/admin/actions/notification-actions.js +4 -0
  33. package/dist/features/admin/schemas/firestore.d.ts +13 -3
  34. package/dist/features/admin/schemas/firestore.js +8 -0
  35. package/dist/features/blog/repository/blog.repository.js +21 -7
  36. package/dist/features/categories/api/route.js +41 -1
  37. package/dist/features/categories/components/BreadcrumbTrail.d.ts +58 -13
  38. package/dist/features/categories/components/BreadcrumbTrail.js +63 -26
  39. package/dist/features/categories/components/CategoryDetailPageView.js +92 -38
  40. package/dist/features/categories/components/ContextualTrail.d.ts +62 -0
  41. package/dist/features/categories/components/ContextualTrail.js +81 -0
  42. package/dist/features/categories/components/LastCategoryBeacon.d.ts +18 -0
  43. package/dist/features/categories/components/LastCategoryBeacon.js +33 -0
  44. package/dist/features/categories/repository/categories.repository.d.ts +21 -0
  45. package/dist/features/categories/repository/categories.repository.js +36 -3
  46. package/dist/features/categories/repository/price-index.repository.d.ts +25 -0
  47. package/dist/features/email/notification-templates.js +4 -0
  48. package/dist/features/events/repository/events.repository.js +10 -3
  49. package/dist/features/faq/constants/read-caps.d.ts +29 -0
  50. package/dist/features/faq/constants/read-caps.js +29 -0
  51. package/dist/features/faq/repository/faqs.repository.d.ts +0 -2
  52. package/dist/features/faq/repository/faqs.repository.js +19 -16
  53. package/dist/features/homepage/components/AdSlot.js +10 -4
  54. package/dist/features/homepage/hooks/useActiveAd.d.ts +18 -1
  55. package/dist/features/homepage/hooks/useActiveAd.js +42 -2
  56. package/dist/features/homepage/lib/section-renderer.js +12 -2
  57. package/dist/features/layout/AppLayoutShell.d.ts +4 -1
  58. package/dist/features/layout/AppLayoutShell.js +2 -2
  59. package/dist/features/layout/TitleBarLayout.d.ts +4 -1
  60. package/dist/features/layout/TitleBarLayout.js +8 -4
  61. package/dist/features/media/AvatarUpload.js +8 -1
  62. package/dist/features/media/MediaAvatar.js +1 -1
  63. package/dist/features/media/MediaImage.js +3 -1
  64. package/dist/features/media/MediaLightbox.js +4 -1
  65. package/dist/features/media/MediaPickerModal.js +6 -1
  66. package/dist/features/media/MediaVideo.js +3 -1
  67. package/dist/features/messages/components/ConversationThreadView.d.ts +3 -0
  68. package/dist/features/messages/components/ConversationThreadView.js +75 -0
  69. package/dist/features/messages/components/ConversationsInboxView.d.ts +1 -0
  70. package/dist/features/messages/components/ConversationsInboxView.js +39 -0
  71. package/dist/features/messages/components/MessageSellerButton.d.ts +17 -0
  72. package/dist/features/messages/components/MessageSellerButton.js +33 -0
  73. package/dist/features/messages/hooks/useConversationChannel.d.ts +24 -0
  74. package/dist/features/messages/hooks/useConversationChannel.js +89 -0
  75. package/dist/features/messages/hooks/useMessages.d.ts +347 -0
  76. package/dist/features/messages/hooks/useMessages.js +113 -0
  77. package/dist/features/messages/repository/conversations.repository.d.ts +44 -0
  78. package/dist/features/messages/repository/conversations.repository.js +173 -0
  79. package/dist/features/messages/repository/messages.repository.d.ts +42 -0
  80. package/dist/features/messages/repository/messages.repository.js +142 -0
  81. package/dist/features/messages/schemas/firestore.d.ts +99 -0
  82. package/dist/features/messages/schemas/firestore.js +46 -0
  83. package/dist/features/orders/repository/orders.repository.js +21 -7
  84. package/dist/features/orders/schemas/firestore.d.ts +11 -0
  85. package/dist/features/products/components/CityCollectiblesView.d.ts +31 -0
  86. package/dist/features/products/components/CityCollectiblesView.js +82 -0
  87. package/dist/features/products/components/MarketPriceAnchor.d.ts +45 -0
  88. package/dist/features/products/components/MarketPriceAnchor.js +62 -0
  89. package/dist/features/products/components/ProductDetailPageView.js +71 -5
  90. package/dist/features/products/constants/meetup-cities.d.ts +47 -0
  91. package/dist/features/products/constants/meetup-cities.js +49 -0
  92. package/dist/features/products/repository/category-assignment.d.ts +82 -11
  93. package/dist/features/products/repository/category-assignment.js +93 -12
  94. package/dist/features/products/repository/products.repository.d.ts +12 -1
  95. package/dist/features/products/repository/products.repository.js +66 -34
  96. package/dist/features/products/schemas/firestore.d.ts +24 -2
  97. package/dist/features/products/schemas/firestore.js +13 -1
  98. package/dist/features/products/schemas/index.d.ts +2 -2
  99. package/dist/features/promotions/repository/coupons.repository.js +11 -4
  100. package/dist/features/reviews/repository/reviews.repository.js +11 -4
  101. package/dist/features/scams/repository/scammer.repository.js +21 -7
  102. package/dist/features/seller/components/CategoryInlineSelect.d.ts +17 -1
  103. package/dist/features/seller/components/CategoryInlineSelect.js +14 -3
  104. package/dist/features/seller/components/SellerProductShell.d.ts +27 -2
  105. package/dist/features/seller/components/SellerProductShell.js +32 -3
  106. package/dist/features/seller/repository/offer.repository.js +21 -6
  107. package/dist/features/seller/schemas/product-form.d.ts +3 -3
  108. package/dist/features/seller/schemas/product-form.js +1 -1
  109. package/dist/features/server-errors/repository/server-errors.repository.js +11 -0
  110. package/dist/features/server-errors/schemas/firestore.d.ts +17 -0
  111. package/dist/features/server-errors/schemas/firestore.js +2 -0
  112. package/dist/features/store-extensions/repository/store-extensions.repositories.d.ts +17 -1
  113. package/dist/features/store-extensions/repository/store-extensions.repositories.js +31 -0
  114. package/dist/features/store-extensions/schemas/firestore.d.ts +1 -1
  115. package/dist/features/store-extensions/schemas/firestore.js +4 -0
  116. package/dist/features/stores/repository/store.repository.js +11 -3
  117. package/dist/features/tester/seed-data/authored/community-support__messages.d.ts +2 -0
  118. package/dist/features/tester/seed-data/authored/community-support__messages.js +200 -0
  119. package/dist/features/tester/seed-data/authored/index.js +2 -0
  120. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +64 -1
  121. package/dist/index.d.ts +8 -2
  122. package/dist/index.js +1 -1
  123. package/dist/next/routing/route-map.d.ts +14 -0
  124. package/dist/next/routing/route-map.js +26 -0
  125. package/dist/providers/db-firebase/rtdb-paths.d.ts +8 -0
  126. package/dist/providers/db-firebase/rtdb-paths.js +8 -0
  127. package/dist/repositories/index.d.ts +1 -0
  128. package/dist/repositories/index.js +4 -0
  129. package/dist/schemas/registry.d.ts +3 -3
  130. package/dist/security/index.d.ts +1 -1
  131. package/dist/security/index.js +1 -1
  132. package/dist/security/pii-schemas.d.ts +17 -0
  133. package/dist/security/pii-schemas.js +15 -7
  134. package/dist/seed/_helpers/category-content-generated.d.ts +24 -0
  135. package/dist/seed/_helpers/category-content-generated.js +1853 -0
  136. package/dist/seed/_helpers/category-models.d.ts +1 -1
  137. package/dist/seed/_helpers/category-models.js +25 -1
  138. package/dist/seed/_helpers/category-names.d.ts +54 -0
  139. package/dist/seed/_helpers/category-names.js +118 -0
  140. package/dist/seed/_helpers/character-features.d.ts +1 -1
  141. package/dist/seed/_helpers/character-features.js +5 -4
  142. package/dist/seed/_helpers/final-sale-fixtures.js +1 -1
  143. package/dist/seed/categories-seed-data.js +55 -1
  144. package/dist/seed/grouped-listings-seed-data.js +2 -2
  145. package/dist/seed/products-art-seed-data.js +2 -1
  146. package/dist/seed/products-auctions-seed-data.js +42 -22
  147. package/dist/seed/products-classifieds-seed-data.js +21 -3
  148. package/dist/seed/products-digital-codes-seed-data.js +2 -1
  149. package/dist/seed/products-live-items-seed-data.js +2 -1
  150. package/dist/seed/products-preorders-seed-data.js +26 -11
  151. package/dist/seed/products-prize-draws-seed-data.js +8 -1
  152. package/dist/seed/products-standard-seed-data.js +26 -25
  153. package/dist/seed/products-stickers-seed-data.js +12 -11
  154. package/dist/server.d.ts +8 -0
  155. package/dist/server.js +15 -0
  156. package/dist/styles.css +113 -1
  157. package/dist/tailwind-utilities.css +1 -1
  158. package/dist/tokens/themes/sunset.js +17 -0
  159. package/dist/tokens/tokens.css +5 -0
  160. package/dist/ui/components/Breadcrumb.d.ts +8 -1
  161. package/dist/ui/components/Breadcrumb.js +2 -2
  162. package/dist/ui/components/Breadcrumb.style.css +37 -0
  163. package/dist/ui/components/Details.d.ts +11 -1
  164. package/dist/ui/components/Details.js +2 -2
  165. package/dist/ui/components/ImageMosaic.d.ts +43 -0
  166. package/dist/ui/components/ImageMosaic.js +46 -0
  167. package/dist/ui/components/ImageMosaic.style.css +69 -0
  168. package/dist/ui/components/SplitTile.d.ts +34 -0
  169. package/dist/ui/components/SplitTile.js +28 -0
  170. package/dist/ui/components/index.style.css +1 -0
  171. package/dist/ui/index.d.ts +4 -0
  172. package/dist/ui/index.js +4 -0
  173. package/dist/utils/search-txt-query.d.ts +77 -0
  174. package/dist/utils/search-txt-query.js +50 -28
  175. package/package.json +1 -1
@@ -29,11 +29,13 @@ import { PRODUCT_FIELDS } from "../constants/field-names.js";
29
29
  import { buildSearchTxt } from "../utils/search-txt.js";
30
30
  import { seedPhoto } from "./_helpers/media.js";
31
31
  import { withFinalSale } from "./_helpers/final-sale-fixtures.js";
32
+ import { withDerivedCategoryNames } from "./_helpers/category-names.js";
32
33
  const _rawproductsClassifiedsSeedData = [
33
34
  {
34
35
  id: "classified-beyblade-stadium-set",
35
36
  slug: "classified-beyblade-stadium-set",
36
37
  title: "Used Beyblade Burst Stadium Set — Local Pickup Only",
38
+ isLot: true,
37
39
  description: "Well-loved Beyblade stadium with 6 tops and 2 launchers, sold as-is. Meet up locally — price is negotiable.",
38
40
  /*
39
41
  * 🛑 Re-filed in B5. A stadium is GENERATION-SPECIFIC — a BX-10 Xtreme
@@ -45,7 +47,16 @@ const _rawproductsClassifiedsSeedData = [
45
47
  * a specific generation while the title stays silent makes the data
46
48
  * disagree with itself, and the title is the half a buyer reads.
47
49
  */
48
- categorySlugs: ["category-burst-standard-stadiums", "category-burst-stadiums", "category-beyblade-burst", "category-spinning-tops"],
50
+ /*
51
+ * 🛑 A LOT FILES AT A NON-LEAF, which is the other half of the leaf rule
52
+ * and the only offender of its kind in the catalogue. This set was filed
53
+ * at `category-burst-standard-stadiums` — a LEAF, i.e. one specific
54
+ * stadium model — while being `isLot: true`. Filing a mixed used set under
55
+ * a single model's leaf is a false claim about what is in the box, which
56
+ * is exactly what the lot half of the rule refuses. Its parent is the
57
+ * correct home.
58
+ */
59
+ categorySlugs: ["category-burst-stadiums", "category-beyblade-burst", "category-spinning-tops"],
49
60
  categoryNames: ["Standard BeyStadiums", "Burst Stadiums", "Beyblade Burst", "Spinning Tops"],
50
61
  brandSlug: "brand-beyblade",
51
62
  brand: "Beyblade",
@@ -96,6 +107,8 @@ const _rawproductsClassifiedsSeedData = [
96
107
  id: "classified-beyblade-burst-collection-bengaluru",
97
108
  slug: "classified-beyblade-burst-collection-bengaluru",
98
109
  title: "Beyblade Burst Collection (12 Tops) — Bengaluru",
110
+ isLot: true,
111
+ lotSize: 12,
99
112
  description: "Downsizing my Burst collection — 12 tops in good condition, fixed price, will also ship nationwide if you'd rather not meet up.",
100
113
  categorySlugs: ["category-burst-cho-z", "category-burst-tops", "category-beyblade-burst", "category-spinning-tops"],
101
114
  categoryNames: ["Cho-Z", "Burst Tops", "Beyblade Burst", "Spinning Tops"],
@@ -142,6 +155,7 @@ const _rawproductsClassifiedsSeedData = [
142
155
  id: "classified-beyblade-x-starter-pune",
143
156
  slug: "classified-beyblade-x-starter-pune",
144
157
  title: "Beyblade X Starter Pack — Pune, Phone Contact Only",
158
+ isLot: true,
145
159
  description: "Barely used Beyblade X starter pack, selling because I upgraded to a full set. Call or WhatsApp only, no chat.",
146
160
  categorySlugs: ["category-x-basic", "category-x-tops", "category-beyblade-x", "category-spinning-tops"],
147
161
  categoryNames: ["Basic Line", "Beyblade X Tops", "Beyblade X", "Spinning Tops"],
@@ -191,6 +205,8 @@ const _rawproductsClassifiedsSeedData = [
191
205
  id: "classified-beyblade-metal-vintage-delhi",
192
206
  slug: "classified-beyblade-metal-vintage-delhi",
193
207
  title: "Vintage Metal Fight Lot (5 Tops) — Delhi NCR",
208
+ isLot: true,
209
+ lotSize: 5,
194
210
  description: "A well-preserved 5-top Metal Fight lot from a long-time collector. Firm price, ships anywhere in India.",
195
211
  categorySlugs: ["category-metal-fusion", "category-metal-tops", "category-beyblade-metal", "category-spinning-tops"],
196
212
  categoryNames: ["Metal Fusion", "Metal Fight Tops", "Beyblade Metal Fight", "Spinning Tops"],
@@ -290,6 +306,7 @@ const _rawproductsClassifiedsSeedData = [
290
306
  id: "classified-beyblade-x-tournament-kit-hyderabad",
291
307
  slug: "classified-beyblade-x-tournament-kit-hyderabad",
292
308
  title: "Tournament-Ready Beyblade X Kit — Hyderabad",
309
+ isLot: true,
293
310
  description: "Complete tournament-legal kit including 3 tops, stadium, and a scorecard pad from our last local meetup event.",
294
311
  categorySlugs: ["category-x-basic", "category-x-tops", "category-beyblade-x", "category-spinning-tops"],
295
312
  categoryNames: ["Basic Line", "Beyblade X Tops", "Beyblade X", "Spinning Tops"],
@@ -342,6 +359,7 @@ const _rawproductsClassifiedsSeedData = [
342
359
  id: "classified-beyblade-burst-parts-mumbai",
343
360
  slug: "classified-beyblade-burst-parts-mumbai",
344
361
  title: "Spare Burst Parts Bundle — Mumbai, Ships Too",
362
+ isLot: true,
345
363
  description: "Assorted spare Burst layers, discs, and drivers cleared out from my parts box. Happy to meet locally or ship.",
346
364
  categorySlugs: ["category-burst-superking", "category-burst-tops", "category-beyblade-burst", "category-spinning-tops"],
347
365
  categoryNames: ["Superking", "Burst Tops", "Beyblade Burst", "Spinning Tops"],
@@ -394,7 +412,7 @@ const _rawproductsClassifiedsSeedData = [
394
412
  slug: "classified-beyblade-metal-galaxy-pegasus-sold-mumbai",
395
413
  title: "Galaxy Pegasus W105R2F — Sold (Mumbai)",
396
414
  description: "Vintage Metal Fight Galaxy Pegasus, sold to a local collector. Listing kept up for reference.",
397
- categorySlugs: ["category-metal-masters", "category-metal-tops", "category-beyblade-metal", "category-spinning-tops"],
415
+ categorySlugs: ["category-galaxy-pegasus-w105r2f", "category-metal-fusion", "category-metal-tops", "category-beyblade-metal", "category-spinning-tops"],
398
416
  categoryNames: ["Metal Masters", "Metal Fight Tops", "Beyblade Metal Fight", "Spinning Tops"],
399
417
  brandSlug: "brand-beyblade",
400
418
  brand: "Beyblade",
@@ -432,4 +450,4 @@ const _rawproductsClassifiedsSeedData = [
432
450
  * the bottom of the array cannot ship without it — which is exactly how the
433
451
  * sold/depleted fixture in this file ended up unsearchable.
434
452
  */
435
- export const productsClassifiedsSeedData = _rawproductsClassifiedsSeedData.map(withProductSearchTxt).map(withFinalSale);
453
+ export const productsClassifiedsSeedData = _rawproductsClassifiedsSeedData.map(withProductSearchTxt).map(withFinalSale).map(withDerivedCategoryNames);
@@ -22,6 +22,7 @@ import { PRODUCT_FIELDS } from "../constants/field-names.js";
22
22
  import { buildSearchTxt } from "../utils/search-txt.js";
23
23
  import { seedPhoto } from "./_helpers/media.js";
24
24
  import { withFinalSale } from "./_helpers/final-sale-fixtures.js";
25
+ import { withDerivedCategoryNames } from "./_helpers/category-names.js";
25
26
  const _rawproductsDigitalCodesSeedData = [
26
27
  {
27
28
  id: "digitalcode-beyblade-x-app-starter-pack",
@@ -400,4 +401,4 @@ const _rawproductsDigitalCodesSeedData = [
400
401
  * the bottom of the array cannot ship without it — which is exactly how the
401
402
  * sold/depleted fixture in this file ended up unsearchable.
402
403
  */
403
- export const productsDigitalCodesSeedData = _rawproductsDigitalCodesSeedData.map(withProductSearchTxt).map(withFinalSale);
404
+ export const productsDigitalCodesSeedData = _rawproductsDigitalCodesSeedData.map(withProductSearchTxt).map(withFinalSale).map(withDerivedCategoryNames);
@@ -35,6 +35,7 @@ import { PRODUCT_FIELDS } from "../constants/field-names.js";
35
35
  import { buildSearchTxt } from "../utils/search-txt.js";
36
36
  import { seedPhoto } from "./_helpers/media.js";
37
37
  import { withFinalSale } from "./_helpers/final-sale-fixtures.js";
38
+ import { withDerivedCategoryNames } from "./_helpers/category-names.js";
38
39
  const _rawproductsLiveItemsSeedData = [
39
40
  {
40
41
  id: "live-golden-retriever-puppy",
@@ -273,4 +274,4 @@ const _rawproductsLiveItemsSeedData = [
273
274
  * the bottom of the array cannot ship without it — which is exactly how the
274
275
  * sold/depleted fixture in this file ended up unsearchable.
275
276
  */
276
- export const productsLiveItemsSeedData = _rawproductsLiveItemsSeedData.map(withProductSearchTxt).map(withFinalSale);
277
+ export const productsLiveItemsSeedData = _rawproductsLiveItemsSeedData.map(withProductSearchTxt).map(withFinalSale).map(withDerivedCategoryNames);
@@ -23,9 +23,11 @@ import { PRODUCT_FIELDS } from "../constants/field-names.js";
23
23
  import { buildSearchTxt } from "../utils/search-txt.js";
24
24
  import { seedPhoto } from "./_helpers/media.js";
25
25
  import { withFinalSale } from "./_helpers/final-sale-fixtures.js";
26
+ import { withDerivedCategoryNames } from "./_helpers/category-names.js";
26
27
  const _rawPreordersSeedData = [
27
28
  {
28
29
  id: "preorder-beyblade-x-bx-08-wave",
30
+ isLot: true,
29
31
  storeId: "store-beyblade-arena",
30
32
  brandSlug: "brand-takara-tomy",
31
33
  title: "Beyblade X BX-08 Booster — Next Wave",
@@ -70,15 +72,15 @@ const _rawPreordersSeedData = [
70
72
  id: "preorder-beyblade-x-bx-09-glide-ring",
71
73
  storeId: "store-beyblade-arena",
72
74
  brandSlug: "brand-takara-tomy",
73
- title: "Beyblade X BX-09 Glide Ring Booster — Coming Soon",
75
+ title: "Beyblade X UnicornSting 5-60GP — Coming Soon",
74
76
  slug: "preorder-beyblade-x-bx-09-glide-ring",
75
- description: "Announced but not yet in production — lock in your spot for the BX-09 Glide Ring wave before it goes into manufacturing.",
77
+ description: "Announced but not yet in production — lock in your spot for the UnicornSting 5-60GP wave before it goes into manufacturing.",
76
78
  price: 849,
77
79
  currency: "INR",
78
80
  condition: PRODUCT_FIELDS.CONDITION_VALUES.NEW,
79
81
  status: PRODUCT_FIELDS.STATUS_VALUES.PUBLISHED,
80
82
  listingType: "pre-order",
81
- categorySlugs: ["category-x-basic", "category-x-tops", "category-beyblade-x", "category-spinning-tops"],
83
+ categorySlugs: ["category-unicornsting-5-60gp", "category-x-basic", "category-x-tops", "category-beyblade-x", "category-spinning-tops"],
82
84
  categoryNames: ["Basic Line", "Beyblade X Tops", "Beyblade X", "Spinning Tops"],
83
85
  brand: "Takara-Tomy",
84
86
  images: [
@@ -114,7 +116,7 @@ const _rawPreordersSeedData = [
114
116
  condition: PRODUCT_FIELDS.CONDITION_VALUES.NEW,
115
117
  status: PRODUCT_FIELDS.STATUS_VALUES.PUBLISHED,
116
118
  listingType: "pre-order",
117
- categorySlugs: ["category-burst-superking", "category-burst-tops", "category-beyblade-burst", "category-spinning-tops"],
119
+ categorySlugs: ["category-union-achilles-cn-xt-retsu", "category-burst-superking", "category-burst-tops", "category-beyblade-burst", "category-spinning-tops"],
118
120
  categoryNames: ["Superking", "Burst Tops", "Beyblade Burst", "Spinning Tops"],
119
121
  brand: "Beyblade",
120
122
  images: [
@@ -143,6 +145,7 @@ const _rawPreordersSeedData = [
143
145
  },
144
146
  {
145
147
  id: "preorder-beyblade-x-bx-11-sold-out",
148
+ isLot: true,
146
149
  storeId: "store-beyblade-arena",
147
150
  brandSlug: "brand-takara-tomy",
148
151
  title: "Beyblade X BX-11 Limited Wave (Sold Out)",
@@ -184,15 +187,15 @@ const _rawPreordersSeedData = [
184
187
  id: "preorder-beyblade-burst-b-215-hells-scythe",
185
188
  storeId: "store-beyblade-arena",
186
189
  brandSlug: "brand-beyblade",
187
- title: "Beyblade Burst B-215 Hells Scythe — Deposit Locked",
190
+ title: "Beyblade Burst Dark Deathscyther Force Jaggy — Deposit Locked",
188
191
  slug: "preorder-beyblade-burst-b-215-hells-scythe",
189
- description: "Hells Scythe Giga Reboost, a full-payment pre-order — no cancellation once reserved, guaranteeing your slot in a strictly limited case allocation.",
192
+ description: "Dark Deathscyther Force Jaggy, a full-payment pre-order — no cancellation once reserved, guaranteeing your slot in a strictly limited case allocation.",
190
193
  price: 1299,
191
194
  currency: "INR",
192
195
  condition: PRODUCT_FIELDS.CONDITION_VALUES.NEW,
193
196
  status: PRODUCT_FIELDS.STATUS_VALUES.PUBLISHED,
194
197
  listingType: "pre-order",
195
- categorySlugs: ["category-burst-classic", "category-burst-tops", "category-beyblade-burst", "category-spinning-tops"],
198
+ categorySlugs: ["category-dark-deathscyther-force-jaggy", "category-burst-god", "category-burst-tops", "category-beyblade-burst", "category-spinning-tops"],
196
199
  categoryNames: ["Burst Classic", "Burst Tops", "Beyblade Burst", "Spinning Tops"],
197
200
  brand: "Beyblade",
198
201
  images: [
@@ -224,6 +227,7 @@ const _rawPreordersSeedData = [
224
227
  storeId: "store-beyblade-arena",
225
228
  brandSlug: "brand-beyblade",
226
229
  title: "Beyblade Original Remaster Set — Announced",
230
+ isLot: true,
227
231
  slug: "preorder-beyblade-original-remaster",
228
232
  description: "A 25th-anniversary remaster of the original 1999 lineup, freshly announced. Production hasn't started — early reservations lock in launch pricing.",
229
233
  price: 1899,
@@ -265,7 +269,7 @@ const _rawPreordersSeedData = [
265
269
  id: "preorder-beyblade-x-bx-12-closed",
266
270
  storeId: "store-beyblade-arena",
267
271
  brandSlug: "brand-takara-tomy",
268
- title: "Beyblade X BX-12 Wave — Allocation Closed",
272
+ title: "Beyblade X TyrannoBeat 4-70Q — Allocation Closed",
269
273
  slug: "preorder-beyblade-x-bx-12-closed",
270
274
  description: "Every slot in this wave is spoken for and the units are ready to ship to existing pre-orderers.",
271
275
  price: 1299,
@@ -273,7 +277,7 @@ const _rawPreordersSeedData = [
273
277
  condition: PRODUCT_FIELDS.CONDITION_VALUES.NEW,
274
278
  status: PRODUCT_FIELDS.STATUS_VALUES.PUBLISHED,
275
279
  listingType: "pre-order",
276
- categorySlugs: ["category-x-basic", "category-x-tops", "category-beyblade-x", "category-spinning-tops"],
280
+ categorySlugs: ["category-tyrannobeat-4-70q", "category-x-basic", "category-x-tops", "category-beyblade-x", "category-spinning-tops"],
277
281
  categoryNames: ["Basic Line", "Beyblade X Tops", "Beyblade X", "Spinning Tops"],
278
282
  brand: "Takara-Tomy",
279
283
  images: [
@@ -297,15 +301,26 @@ const _rawPreordersSeedData = [
297
301
  updatedAt: new Date("2026-08-24"),
298
302
  },
299
303
  ];
300
- export const productsPreordersSeedData = _rawPreordersSeedData.map((p) => withFinalSale({
304
+ export const productsPreordersSeedData = _rawPreordersSeedData.map((p) => withDerivedCategoryNames(withFinalSale({
301
305
  tags: [],
302
306
  stockQuantity: p.availableQuantity ?? 1,
303
307
  mainImage: p.images?.[0] ?? "",
304
308
  ...p,
305
309
  listingType: "pre-order",
310
+ /*
311
+ * 🛑 `searchTxt` reads p.categoryNames — the RAW record's, deliberately.
312
+ *
313
+ * The derivation wraps the OUTSIDE of this call, so at this point the names
314
+ * are still whatever the record hand-wrote. That is correct rather than a
315
+ * sequencing bug: the search index should carry the names a buyer might
316
+ * type, and a stale-but-real generation name ("Metal Masters") is still a
317
+ * term worth matching. Swapping to the derived chain would silently narrow
318
+ * the index. The DISPLAY chain is the one that must be exact, and that is
319
+ * what the wrapper fixes.
320
+ */
306
321
  searchTxt: buildSearchTxt([
307
322
  p.title, p.description, p.brand, p.brandSlug,
308
323
  p.categoryNames, p.tags, p.features, p.condition,
309
324
  p.specifications?.map((s) => `${s.name} ${s.value}`),
310
325
  ]),
311
- }));
326
+ })));
@@ -23,9 +23,11 @@ import { PRODUCT_FIELDS } from "../constants/field-names.js";
23
23
  import { buildSearchTxt } from "../utils/search-txt.js";
24
24
  import { seedPhoto } from "./_helpers/media.js";
25
25
  import { withFinalSale } from "./_helpers/final-sale-fixtures.js";
26
+ import { withDerivedCategoryNames } from "./_helpers/category-names.js";
26
27
  const _rawproductsPrizeDrawsSeedData = [
27
28
  {
28
29
  id: "prizedraw-beyblade-mystery-box",
30
+ isLot: true,
29
31
  slug: "prizedraw-beyblade-mystery-box",
30
32
  title: "Beyblade Mystery Box — Prize Draw",
31
33
  description: "Buy an entry for ₹99 and reveal your prize instantly — win anything from a rare limited-edition Beyblade down to a spare launcher grip. 4 prizes available, revealed on a first-come basis.",
@@ -90,6 +92,7 @@ const _rawproductsPrizeDrawsSeedData = [
90
92
  },
91
93
  {
92
94
  id: "prizedraw-beyblade-scheduled-demo",
95
+ isLot: true,
93
96
  slug: "prizedraw-beyblade-scheduled-demo",
94
97
  title: "Beyblade Champion's Draw — Prize Draw",
95
98
  description: "Two entries, two prizes — the winners are revealed automatically the moment the draw closes (3 days) or sells out, whichever comes first.",
@@ -148,6 +151,7 @@ const _rawproductsPrizeDrawsSeedData = [
148
151
  // --- Partially sold: prizeCurrentEntries > 0, main seed never exercised this before ---
149
152
  {
150
153
  id: "prizedraw-beyblade-x-legendary-vault",
154
+ isLot: true,
151
155
  slug: "prizedraw-beyblade-x-legendary-vault",
152
156
  title: "Beyblade X Legendary Vault — Prize Draw",
153
157
  description: "6 entries, 6 prizes ranging from a legendary chase top to spare parts — over half the draw is already sold, don't miss the remaining slots.",
@@ -207,6 +211,7 @@ const _rawproductsPrizeDrawsSeedData = [
207
211
  // --- Closed + revealed: real winners, isWon:true — permanent-catalog example (previously only in tester sandbox) ---
208
212
  {
209
213
  id: "prizedraw-beyblade-metal-closed-revealed",
214
+ isLot: true,
210
215
  slug: "prizedraw-beyblade-metal-closed-revealed",
211
216
  title: "Metal Fight Mystery Draw — Ended (Revealed)",
212
217
  description: "This draw has closed and every prize has been revealed to its winner. Browse the results below.",
@@ -260,6 +265,7 @@ const _rawproductsPrizeDrawsSeedData = [
260
265
  // --- Nearly sold out, scheduled reveal ---
261
266
  {
262
267
  id: "prizedraw-beyblade-burst-collectors-draw",
268
+ isLot: true,
263
269
  slug: "prizedraw-beyblade-burst-collectors-draw",
264
270
  title: "Beyblade Burst Collector's Draw — Almost Sold Out",
265
271
  description: "Only 1 entry left — 4 of 5 slots are already claimed for this Burst-generation collector's draw. Winners revealed the moment the draw closes.",
@@ -379,6 +385,7 @@ const _rawproductsPrizeDrawsSeedData = [
379
385
  // isSold true, so it is caught by the shared base check and would still
380
386
  // look correct even if the type-specific rule were deleted.
381
387
  id: "prizedraw-beyblade-x-vault-closed-pending-reveal",
388
+ isLot: true,
382
389
  slug: "prizedraw-beyblade-x-vault-closed-pending-reveal",
383
390
  title: "Beyblade X Vault Draw — Closed Early",
384
391
  description: "The seller closed this draw before every slot sold. Remaining entries were refunded; no further entries are accepted.",
@@ -426,4 +433,4 @@ const _rawproductsPrizeDrawsSeedData = [
426
433
  * the bottom of the array cannot ship without it — which is exactly how the
427
434
  * sold/depleted fixture in this file ended up unsearchable.
428
435
  */
429
- export const productsPrizeDrawsSeedData = _rawproductsPrizeDrawsSeedData.map(withProductSearchTxt).map(withFinalSale);
436
+ export const productsPrizeDrawsSeedData = _rawproductsPrizeDrawsSeedData.map(withProductSearchTxt).map(withFinalSale).map(withDerivedCategoryNames);
@@ -26,6 +26,7 @@ import { PRODUCT_FIELDS } from "../constants/field-names.js";
26
26
  import { buildSearchTxt } from "../utils/search-txt.js";
27
27
  import { seedPhoto } from "./_helpers/media.js";
28
28
  import { withFinalSale } from "./_helpers/final-sale-fixtures.js";
29
+ import { withDerivedCategoryNames } from "./_helpers/category-names.js";
29
30
  /*
30
31
  * Real Beyblade attributes per fixture — Root Cause #6 (standard was the
31
32
  * "richest" seed file by fixture count but never exercised customFields/
@@ -186,7 +187,7 @@ const _rawProductsStandardSeedData = [
186
187
  barcodeId: "LIR-BEY-ORIG-001",
187
188
  title: "Beyblade Original — Dranzer S",
188
189
  description: "Plastic Generation era Dranzer S with launcher and ripcord. A classic from the original 1999-2003 Beyblade series.",
189
- categorySlugs: ["category-original-hms", "category-original-tops", "category-beyblade-original", "category-spinning-tops"],
190
+ categorySlugs: ["category-dranzer-s", "category-original-spin-gear", "category-original-tops", "category-beyblade-original", "category-spinning-tops"],
190
191
  categoryNames: ["Heavy Metal System", "Original Tops", "Beyblade Original", "Spinning Tops"],
191
192
  brandSlug: "brand-beyblade",
192
193
  brand: "Beyblade",
@@ -232,7 +233,7 @@ const _rawProductsStandardSeedData = [
232
233
  barcodeId: "LIR-BEY-ORIG-002",
233
234
  title: "Beyblade Original — Driger V",
234
235
  description: "Vintage Driger V attack-type top from the original series, complete with launcher grip.",
235
- categorySlugs: ["category-original-plastic-gen", "category-original-tops", "category-beyblade-original", "category-spinning-tops"],
236
+ categorySlugs: ["category-driger-v", "category-original-tops", "category-beyblade-original", "category-spinning-tops"],
236
237
  categoryNames: ["Plastic Generation", "Original Tops", "Beyblade Original", "Spinning Tops"],
237
238
  brandSlug: "brand-beyblade",
238
239
  brand: "Beyblade",
@@ -264,7 +265,7 @@ const _rawProductsStandardSeedData = [
264
265
  barcodeId: "LIR-BEY-META-001",
265
266
  title: "Metal Fight Beyblade BB-28 Storm Pegasus",
266
267
  description: "Storm Pegasus 105RF from the Metal Fusion era — one of the most iconic Metal Fight tops.",
267
- categorySlugs: ["category-metal-masters", "category-metal-tops", "category-beyblade-metal", "category-spinning-tops"],
268
+ categorySlugs: ["category-storm-pegasus-105rf", "category-metal-fusion", "category-metal-tops", "category-beyblade-metal", "category-spinning-tops"],
268
269
  categoryNames: ["Metal Masters", "Metal Fight Tops", "Beyblade Metal Fight", "Spinning Tops"],
269
270
  brandSlug: "brand-takara-tomy",
270
271
  brand: "Takara-Tomy",
@@ -296,7 +297,7 @@ const _rawProductsStandardSeedData = [
296
297
  barcodeId: "LIR-BEY-META-002",
297
298
  title: "Metal Fight Beyblade BB-43 Flame Sagittario",
298
299
  description: "Flame Sagittario C145S, a balance-type top from the Metal Masters generation.",
299
- categorySlugs: ["category-metal-fury-4d", "category-metal-tops", "category-beyblade-metal", "category-spinning-tops"],
300
+ categorySlugs: ["category-flame-sagittario-c145s", "category-metal-fusion", "category-metal-tops", "category-beyblade-metal", "category-spinning-tops"],
300
301
  categoryNames: ["Metal Fury (4D)", "Metal Fight Tops", "Beyblade Metal Fight", "Spinning Tops"],
301
302
  brandSlug: "brand-takara-tomy",
302
303
  brand: "Takara-Tomy",
@@ -326,9 +327,9 @@ const _rawProductsStandardSeedData = [
326
327
  id: "product-beyblade-burst-valkyrie",
327
328
  slug: "product-beyblade-burst-valkyrie",
328
329
  barcodeId: "LIR-BEY-BURS-001",
329
- title: "Beyblade Burst B-01 Valkyrie",
330
- description: "Starter set Valkyrie Wing Accel with launcher and grip — the top that launched the Burst generation.",
331
- categorySlugs: ["category-burst-superking", "category-burst-tops", "category-beyblade-burst", "category-spinning-tops"],
330
+ title: "Beyblade Burst B-34 Victory Valkyrie Boost Variable",
331
+ description: "Starter set Victory Valkyrie Boost Variable with launcher and grip — an early Burst-generation Valkyrie.",
332
+ categorySlugs: ["category-victory-valkyrie-boost-variable", "category-burst-classic", "category-burst-tops", "category-beyblade-burst", "category-spinning-tops"],
332
333
  categoryNames: ["Superking", "Burst Tops", "Beyblade Burst", "Spinning Tops"],
333
334
  brandSlug: "brand-beyblade",
334
335
  brand: "Beyblade",
@@ -358,9 +359,9 @@ const _rawProductsStandardSeedData = [
358
359
  id: "product-beyblade-burst-regalia-genesis",
359
360
  slug: "product-beyblade-burst-regalia-genesis",
360
361
  barcodeId: "LIR-BEY-BURS-002",
361
- title: "Beyblade Burst B-59 Regalia Genesis",
362
- description: "Regalia Genesis.Zt with switch launcher — Burst Rise generation attack-type top.",
363
- categorySlugs: ["category-burst-classic", "category-burst-tops", "category-beyblade-burst", "category-spinning-tops"],
362
+ title: "Beyblade Burst Xeno Xcalibur Magnet Loop",
363
+ description: "Xeno Xcalibur Magnet Loop with switch launcher — a Burst Classic attack-type top.",
364
+ categorySlugs: ["category-xeno-xcalibur-magnet-loop", "category-burst-classic", "category-burst-tops", "category-beyblade-burst", "category-spinning-tops"],
364
365
  categoryNames: ["Burst Classic", "Burst Tops", "Beyblade Burst", "Spinning Tops"],
365
366
  brandSlug: "brand-beyblade",
366
367
  brand: "Beyblade",
@@ -392,7 +393,7 @@ const _rawProductsStandardSeedData = [
392
393
  barcodeId: "LIR-BEY-X-001",
393
394
  title: "Beyblade X BX-01 Wizard Arrow",
394
395
  description: "Wizard Arrow 4-60F, a starter top from the Beyblade X Xtreme Gear generation.",
395
- categorySlugs: ["category-x-basic", "category-x-tops", "category-beyblade-x", "category-spinning-tops"],
396
+ categorySlugs: ["category-wizardarrow-4-80b", "category-x-tops", "category-beyblade-x", "category-spinning-tops"],
396
397
  categoryNames: ["Basic Line", "Beyblade X Tops", "Beyblade X", "Spinning Tops"],
397
398
  brandSlug: "brand-takara-tomy",
398
399
  brand: "Takara-Tomy",
@@ -422,9 +423,9 @@ const _rawProductsStandardSeedData = [
422
423
  id: "product-beyblade-x-knife-shinobi",
423
424
  slug: "product-beyblade-x-knife-shinobi",
424
425
  barcodeId: "LIR-BEY-X-002",
425
- title: "Beyblade X BX-05 Knife Shinobi",
426
- description: "Knife Shinobi 3-60GF, a balance-type top with tournament-grade stamina parts.",
427
- categorySlugs: ["category-x-basic", "category-x-tops", "category-beyblade-x", "category-spinning-tops"],
426
+ title: "Beyblade X CrimsonGaruda 4-70TP",
427
+ description: "CrimsonGaruda 4-70TP, a balance-type top with tournament-grade stamina parts.",
428
+ categorySlugs: ["category-crimsongaruda-4-70tp", "category-x-basic", "category-x-tops", "category-beyblade-x", "category-spinning-tops"],
428
429
  categoryNames: ["Basic Line", "Beyblade X Tops", "Beyblade X", "Spinning Tops"],
429
430
  brandSlug: "brand-takara-tomy",
430
431
  brand: "Takara-Tomy",
@@ -456,7 +457,7 @@ const _rawProductsStandardSeedData = [
456
457
  barcodeId: "LIR-BEY-VID-001",
457
458
  title: "Beyblade Original — Dragoon F (Video Demo)",
458
459
  description: "Dragoon F attack-type top from the original series. Listed with an unboxing/spin video for gallery testing.",
459
- categorySlugs: ["category-original-hms", "category-original-tops", "category-beyblade-original", "category-spinning-tops"],
460
+ categorySlugs: ["category-dragoon-f", "category-original-tops", "category-beyblade-original", "category-spinning-tops"],
460
461
  categoryNames: ["Heavy Metal System", "Original Tops", "Beyblade Original", "Spinning Tops"],
461
462
  brandSlug: "brand-beyblade",
462
463
  brand: "Beyblade",
@@ -489,7 +490,7 @@ const _rawProductsStandardSeedData = [
489
490
  barcodeId: "LIR-BEY-VID-002",
490
491
  title: "Beyblade X BX-02 Dran Sword (Video Demo)",
491
492
  description: "Dran Sword 3-60F attack-type top from the Beyblade X Xtreme Gear generation. Listed with a battle-test video for gallery testing.",
492
- categorySlugs: ["category-x-basic", "category-x-tops", "category-beyblade-x", "category-spinning-tops"],
493
+ categorySlugs: ["category-dransword-3-60f", "category-x-tops", "category-beyblade-x", "category-spinning-tops"],
493
494
  categoryNames: ["Basic Line", "Beyblade X Tops", "Beyblade X", "Spinning Tops"],
494
495
  brandSlug: "brand-takara-tomy",
495
496
  brand: "Takara-Tomy",
@@ -530,7 +531,7 @@ const _rawProductsStandardSeedData = [
530
531
  barcodeId: "LIR-BEY-VID-003",
531
532
  title: "Metal Fight Beyblade BB-118 Dark Bull (Video Demo, YouTube)",
532
533
  description: "Dark Bull H145SD, a defense-type top from the Metal Masters generation. Listed with a YouTube battle video to exercise the gallery's YouTube-embed video source.",
533
- categorySlugs: ["category-metal-fusion", "category-metal-tops", "category-beyblade-metal", "category-spinning-tops"],
534
+ categorySlugs: ["category-dark-bull-h145sd", "category-metal-fusion", "category-metal-tops", "category-beyblade-metal", "category-spinning-tops"],
534
535
  categoryNames: ["Metal Fusion", "Metal Fight Tops", "Beyblade Metal Fight", "Spinning Tops"],
535
536
  brandSlug: "brand-takara-tomy",
536
537
  brand: "Takara-Tomy",
@@ -572,7 +573,7 @@ const _rawProductsStandardSeedData = [
572
573
  barcodeId: "LIR-BEY-VID-004",
573
574
  title: "Beyblade Burst B-97 Spryzen S2 (Video Demo, Wikimedia)",
574
575
  description: "Spryzen S2 stamina-type top from the God Layer generation. Listed with a Wikimedia-hosted spin video to exercise a second raw-external-host video source.",
575
- categorySlugs: ["category-burst-cho-z", "category-burst-tops", "category-beyblade-burst", "category-spinning-tops"],
576
+ categorySlugs: ["category-spryzen-s2-0q", "category-burst-classic", "category-burst-tops", "category-beyblade-burst", "category-spinning-tops"],
576
577
  categoryNames: ["Cho-Z", "Burst Tops", "Beyblade Burst", "Spinning Tops"],
577
578
  brandSlug: "brand-beyblade",
578
579
  brand: "Beyblade",
@@ -606,11 +607,11 @@ const _rawProductsStandardSeedData = [
606
607
  // predicate ever runs, so it would prove nothing.
607
608
  id: "product-beyblade-x-dran-buster-sold-out",
608
609
  slug: "product-beyblade-x-dran-buster-sold-out",
609
- title: "Beyblade X BX-34 Dran Buster (Sold Out)",
610
- description: "The BX-34 Dran Buster attack type — this batch is fully sold. Watch for the next restock.",
610
+ title: "Beyblade X DranDagger 4-60R (Sold Out)",
611
+ description: "The DranDagger 4-60R attack type — this batch is fully sold. Watch for the next restock.",
611
612
  price: 1499,
612
613
  currency: "INR",
613
- categorySlugs: ["category-x-basic", "category-x-tops", "category-beyblade-x", "category-spinning-tops"],
614
+ categorySlugs: ["category-drandagger-4-60r", "category-x-basic", "category-x-tops", "category-beyblade-x", "category-spinning-tops"],
614
615
  categoryNames: ["Basic Line", "Beyblade X Tops", "Beyblade X", "Spinning Tops"],
615
616
  brandSlug: "brand-takara-tomy",
616
617
  brand: "Takara-Tomy",
@@ -633,11 +634,11 @@ const _rawProductsStandardSeedData = [
633
634
  {
634
635
  id: "product-beyblade-burst-valtryek-v3-sold-out",
635
636
  slug: "product-beyblade-burst-valtryek-v3-sold-out",
636
- title: "Beyblade Burst Valtryek V3 (Sold Out)",
637
- description: "Valtryek V3, the balance-type staple. This run sold through — no units remaining.",
637
+ title: "Beyblade Burst God Valkyrie 6Vortex Reboot (Sold Out)",
638
+ description: "God Valkyrie 6Vortex Reboot, the balance-type staple. This run sold through — no units remaining.",
638
639
  price: 899,
639
640
  currency: "INR",
640
- categorySlugs: ["category-burst-superking", "category-burst-tops", "category-beyblade-burst", "category-spinning-tops"],
641
+ categorySlugs: ["category-god-valkyrie-6vortex-reboot", "category-burst-god", "category-burst-tops", "category-beyblade-burst", "category-spinning-tops"],
641
642
  categoryNames: ["Superking", "Burst Tops", "Beyblade Burst", "Spinning Tops"],
642
643
  brandSlug: "brand-beyblade",
643
644
  brand: "Beyblade",
@@ -715,4 +716,4 @@ export const productsStandardSeedData = [
715
716
  ...(p.id ? SPEC_OVERRIDES[p.id] : undefined),
716
717
  listingType: PRODUCT_FIELDS.LISTING_TYPE_VALUES.STANDARD,
717
718
  })),
718
- ].map(withFinalSale);
719
+ ].map(withFinalSale).map(withDerivedCategoryNames);
@@ -20,10 +20,11 @@ import { PRODUCT_FIELDS } from "../constants/field-names.js";
20
20
  import { buildSearchTxt } from "../utils/search-txt.js";
21
21
  import { seedPhoto } from "./_helpers/media.js";
22
22
  import { withFinalSale } from "./_helpers/final-sale-fixtures.js";
23
+ import { withDerivedCategoryNames } from "./_helpers/category-names.js";
23
24
  const _rawProductsStickersSeedData = [
24
25
  {
25
- id: "stickers-beyblade-original-classic-sheet",
26
- slug: "stickers-beyblade-original-classic-sheet",
26
+ id: "sticker-beyblade-original-classic-sheet",
27
+ slug: "sticker-beyblade-original-classic-sheet",
27
28
  title: "Beyblade Original Classic — Sticker Sheet",
28
29
  description: "A 5x5 cm sticker sheet featuring Dranzer, Driger, Draciel, and Dragoon in classic original-series art style.",
29
30
  categorySlugs: ["category-original-plastic-gen", "category-original-tops", "category-beyblade-original", "category-spinning-tops"],
@@ -61,8 +62,8 @@ const _rawProductsStickersSeedData = [
61
62
  ]),
62
63
  },
63
64
  {
64
- id: "stickers-beyblade-x-holographic-pack",
65
- slug: "stickers-beyblade-x-holographic-pack",
65
+ id: "sticker-beyblade-x-holographic-pack",
66
+ slug: "sticker-beyblade-x-holographic-pack",
66
67
  title: "Beyblade X Holographic Sticker Pack",
67
68
  description: "A holographic-finish sticker pack featuring the current Beyblade X lineup — catches the light with a rainbow shimmer.",
68
69
  categorySlugs: ["category-x-basic", "category-x-tops", "category-beyblade-x", "category-spinning-tops"],
@@ -103,8 +104,8 @@ const _rawProductsStickersSeedData = [
103
104
  ]),
104
105
  },
105
106
  {
106
- id: "stickers-beyblade-burst-diecut-set",
107
- slug: "stickers-beyblade-burst-diecut-set",
107
+ id: "sticker-beyblade-burst-diecut-set",
108
+ slug: "sticker-beyblade-burst-diecut-set",
108
109
  title: "Beyblade Burst Die-Cut Sticker Set (6-Pack)",
109
110
  description: "Individually die-cut vinyl stickers of 6 fan-favorite Burst tops — no background, clean edges, weatherproof.",
110
111
  categorySlugs: ["category-burst-classic", "category-burst-tops", "category-beyblade-burst", "category-spinning-tops"],
@@ -142,8 +143,8 @@ const _rawProductsStickersSeedData = [
142
143
  ]),
143
144
  },
144
145
  {
145
- id: "stickers-beyblade-metal-retro-sheet",
146
- slug: "stickers-beyblade-metal-retro-sheet",
146
+ id: "sticker-beyblade-metal-retro-sheet",
147
+ slug: "sticker-beyblade-metal-retro-sheet",
147
148
  title: "Metal Fight Retro Sticker Sheet — Limited /500",
148
149
  description: "A limited-edition retro-styled sticker sheet celebrating Metal Fight favorites, numbered out of 500.",
149
150
  categorySlugs: ["category-metal-masters", "category-metal-tops", "category-beyblade-metal", "category-spinning-tops"],
@@ -181,8 +182,8 @@ const _rawProductsStickersSeedData = [
181
182
  ]),
182
183
  },
183
184
  {
184
- id: "stickers-beyblade-x-glow-in-dark",
185
- slug: "stickers-beyblade-x-glow-in-dark",
185
+ id: "sticker-beyblade-x-glow-in-dark",
186
+ slug: "sticker-beyblade-x-glow-in-dark",
186
187
  title: "Beyblade X Glow-in-the-Dark Sticker Pack",
187
188
  description: "Charge these stickers under light and watch the Beyblade X logos glow in the dark. Great for stadium cases and water bottles.",
188
189
  categorySlugs: ["category-x-basic", "category-x-tops", "category-beyblade-x", "category-spinning-tops"],
@@ -271,4 +272,4 @@ const _rawProductsStickersSeedData = [
271
272
  * so the final-sale opt-outs are applied the same way everywhere rather than
272
273
  * being hand-written into two records that reviewers would have to find.
273
274
  */
274
- export const productsStickersSeedData = _rawProductsStickersSeedData.map(withFinalSale);
275
+ export const productsStickersSeedData = _rawProductsStickersSeedData.map(withFinalSale).map(withDerivedCategoryNames);
package/dist/server.d.ts CHANGED
@@ -3,6 +3,8 @@ export { searchEverything } from "./_internal/server/features/search/search-ever
3
3
  export type { SearchHit, SearchGroup, SearchSource, SearchEverythingResult, } from "./_internal/server/features/search/search-everything";
4
4
  export { SEARCH_SOURCES } from "./_internal/server/features/search/search-sources";
5
5
  export { getPartByKey, getModelsUsingPart, getCompositionById, getPartsForComposition, getCompositionsForCategory, listPartsBySlot, } from "./_internal/server/features/parts/data";
6
+ export { renderCityOg, type CityOgData } from "./_internal/server/features/products/og";
7
+ export { listBuildableModels, BUILDABLE_HOLDINGS_LIMIT, BUILDABLE_CANDIDATE_LIMIT, type BuildableModel, type BuildableResult, type BuildableSlot, } from "./_internal/server/features/parts/buildable";
6
8
  export { renderPartOg, renderPartClassificationOg, } from "./_internal/server/features/parts/og";
7
9
  export { assembleFromComponents, partOutToComponents, planAssembly, assertAssemblyInput, MAX_ASSEMBLY_COMPONENTS, } from "./_internal/server/features/parts/assembly";
8
10
  export type { AssemblyComponent, AssembleInput, PartOutInput, AssemblyResult, AssemblyPlan, StockWrite, } from "./_internal/server/features/parts/assembly";
@@ -567,6 +569,12 @@ export { buildDigitalCodeMetadata, type DigitalCodeMetadataOptions } from "./_in
567
569
  export { renderDigitalCodeOg, renderDigitalCodeOgImage, renderDigitalCodeOgFromDoc, type DigitalCodeOgData } from "./_internal/server/features/digital-code/og";
568
570
  export { addPoolEntries, listPoolEntries, deletePoolEntry, recountPool, assertCanUploadContentKind, DIGITAL_CONTENT_PREFIX, type AddPoolEntryInput, } from "./_internal/server/features/digital-code/pool";
569
571
  export { signDigitalContentUpload, finalizeDigitalContentUpload, contentKindForMime, type SignedDigitalContent, type FinalizedDigitalContent, } from "./_internal/server/features/digital-code/upload";
572
+ /**
573
+ * D9 — chat. The one writer path for conversations and messages; every
574
+ * mutation runs through the Admin SDK here, never a client Firestore write
575
+ * (`firestore.rules` is `allow read, write: if false` on every document).
576
+ */
577
+ export { createOrOpenConversation, openConversationWithSeller, listConversationsForUser, listMessagesForConversation, sendMessage, markConversationRead, blockConversationParticipant, softDeleteOwnMessage, mintChatEventToken, getUnreadConversationCount, deleteAllMessages as deleteAllConversationMessages, listAllAttachmentUrls as listConversationAttachmentUrls, stripPii as stripChatPii, type SendMessageInput, } from "./_internal/server/features/messages/actions";
570
578
  export { resolveCodeAssetForOrder, codeAssetHeaders, CODE_DOWNLOAD_STATUSES, type CodeAssetResolution, } from "./_internal/server/features/digital-code/download";
571
579
  export { getLiveItemForDetail } from "./_internal/server/features/live/data";
572
580
  export { toClientLiveItem, type LiveItemClientShape } from "./_internal/server/features/live/adapters";
package/dist/server.js CHANGED
@@ -10,6 +10,15 @@ export { SEARCH_SOURCES } from "./_internal/server/features/search/search-source
10
10
  // D12 — part + composition reads. Every one is by document id or ONE
11
11
  // indexed equality; none needs a composite index.
12
12
  export { getPartByKey, getModelsUsingPart, getCompositionById, getPartsForComposition, getCompositionsForCategory, listPartsBySlot, } from "./_internal/server/features/parts/data.js";
13
+ /*
14
+ * D13's last item — "which models can I build from the parts I hold".
15
+ * Exported because its only caller is a consumer route; the matcher it is built
16
+ * on (`matchSlotToHoldings`) stays internal, since a caller reaching for the
17
+ * matcher directly would be re-deriving the rollup's (part, colourway) rule.
18
+ */
19
+ /* D5 — the city OG card. No money on it, by rule (Root Cause #93). */
20
+ export { renderCityOg } from "./_internal/server/features/products/og.js";
21
+ export { listBuildableModels, BUILDABLE_HOLDINGS_LIMIT, BUILDABLE_CANDIDATE_LIMIT, } from "./_internal/server/features/parts/buildable.js";
13
22
  export { renderPartOg, renderPartClassificationOg, } from "./_internal/server/features/parts/og.js";
14
23
  // D13 — assembly and part-out. Both run in a real transaction that RE-READS.
15
24
  export { assembleFromComponents, partOutToComponents, planAssembly, assertAssemblyInput, MAX_ASSEMBLY_COMPONENTS, } from "./_internal/server/features/parts/assembly.js";
@@ -1468,6 +1477,12 @@ export { renderDigitalCodeOg, renderDigitalCodeOgImage, renderDigitalCodeOgFromD
1468
1477
  */
1469
1478
  export { addPoolEntries, listPoolEntries, deletePoolEntry, recountPool, assertCanUploadContentKind, DIGITAL_CONTENT_PREFIX, } from "./_internal/server/features/digital-code/pool.js";
1470
1479
  export { signDigitalContentUpload, finalizeDigitalContentUpload, contentKindForMime, } from "./_internal/server/features/digital-code/upload.js";
1480
+ /**
1481
+ * D9 — chat. The one writer path for conversations and messages; every
1482
+ * mutation runs through the Admin SDK here, never a client Firestore write
1483
+ * (`firestore.rules` is `allow read, write: if false` on every document).
1484
+ */
1485
+ export { createOrOpenConversation, openConversationWithSeller, listConversationsForUser, listMessagesForConversation, sendMessage, markConversationRead, blockConversationParticipant, softDeleteOwnMessage, mintChatEventToken, getUnreadConversationCount, deleteAllMessages as deleteAllConversationMessages, listAllAttachmentUrls as listConversationAttachmentUrls, stripPii as stripChatPii, } from "./_internal/server/features/messages/actions.js";
1471
1486
  export { resolveCodeAssetForOrder, codeAssetHeaders, CODE_DOWNLOAD_STATUSES, } from "./_internal/server/features/digital-code/download.js";
1472
1487
  // ── Live-item listing — data + adapters + metadata + OG ──────────────────────
1473
1488
  export { getLiveItemForDetail } from "./_internal/server/features/live/data.js";