@mohasinac/appkit 4.42.18 → 4.44.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 (263) hide show
  1. package/dist/_internal/client/features/lottery/LotteryDetailView.js +22 -1
  2. package/dist/_internal/server/features/categories/adapters.d.ts +47 -0
  3. package/dist/_internal/server/features/categories/adapters.js +235 -0
  4. package/dist/_internal/server/features/checkout/actions.js +161 -22
  5. package/dist/_internal/server/features/checkout/expand-order-items.js +34 -0
  6. package/dist/_internal/server/features/orders/adapters.js +21 -0
  7. package/dist/_internal/server/features/products/list-public.d.ts +24 -0
  8. package/dist/_internal/server/features/products/list-public.js +10 -2
  9. package/dist/_internal/server/features/refunds/actions.js +1 -1
  10. package/dist/_internal/server/features/seo/sitemap.js +54 -15
  11. package/dist/_internal/server/features/stores/adapters.d.ts +1 -1
  12. package/dist/_internal/server/features/stores/adapters.js +6 -0
  13. package/dist/_internal/server/functions/scheduled.d.ts +4 -2
  14. package/dist/_internal/server/functions/scheduled.js +64 -6
  15. package/dist/_internal/server/jobs/core/adminAnalytics.d.ts +0 -1
  16. package/dist/_internal/server/jobs/core/adminAnalytics.js +9 -1
  17. package/dist/_internal/server/jobs/core/analyticsAlertEvaluate.d.ts +47 -0
  18. package/dist/_internal/server/jobs/core/analyticsAlertEvaluate.js +468 -0
  19. package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +14 -1
  20. package/dist/_internal/server/jobs/core/countersReconcile.js +24 -8
  21. package/dist/_internal/server/jobs/core/onCategoryWrite.js +59 -0
  22. package/dist/_internal/server/jobs/core/onProductWrite.js +31 -0
  23. package/dist/_internal/server/jobs/core/onReviewWrite.js +8 -0
  24. package/dist/_internal/server/jobs/core/onStoreWrite.d.ts +1 -1
  25. package/dist/_internal/server/jobs/core/onStoreWrite.js +8 -2
  26. package/dist/_internal/server/jobs/core/priceIndexRollup.d.ts +47 -0
  27. package/dist/_internal/server/jobs/core/priceIndexRollup.js +234 -0
  28. package/dist/_internal/server/jobs/core/revalidateNotify.d.ts +28 -0
  29. package/dist/_internal/server/jobs/core/revalidateNotify.js +125 -0
  30. package/dist/_internal/server/jobs/core/{testerSandboxCleanup.d.ts → testDataCleanup.d.ts} +3 -3
  31. package/dist/_internal/server/jobs/core/{testerSandboxCleanup.js → testDataCleanup.js} +3 -3
  32. package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +5 -1
  33. package/dist/_internal/server/jobs/handlers/analyticsAlertEvaluate.d.ts +2 -0
  34. package/dist/_internal/server/jobs/handlers/analyticsAlertEvaluate.js +2 -0
  35. package/dist/_internal/server/jobs/handlers/index.d.ts +3 -1
  36. package/dist/_internal/server/jobs/handlers/index.js +3 -1
  37. package/dist/_internal/server/jobs/handlers/messages.d.ts +5 -2
  38. package/dist/_internal/server/jobs/handlers/messages.js +5 -2
  39. package/dist/_internal/server/jobs/handlers/priceIndexRollup.d.ts +2 -0
  40. package/dist/_internal/server/jobs/handlers/priceIndexRollup.js +2 -0
  41. package/dist/_internal/server/jobs/handlers/testDataCleanup.d.ts +2 -0
  42. package/dist/_internal/server/jobs/handlers/testDataCleanup.js +2 -0
  43. package/dist/_internal/shared/actions/action-registry.js +34 -0
  44. package/dist/_internal/shared/cache/revalidate-targets.d.ts +49 -0
  45. package/dist/_internal/shared/cache/revalidate-targets.js +157 -0
  46. package/dist/_internal/shared/checkout/order-math.d.ts +113 -3
  47. package/dist/_internal/shared/checkout/order-math.js +194 -7
  48. package/dist/_internal/shared/features/categories/price-guidance.d.ts +110 -0
  49. package/dist/_internal/shared/features/categories/price-guidance.js +136 -0
  50. package/dist/_internal/shared/features/site-settings/gst-registration.d.ts +90 -0
  51. package/dist/_internal/shared/features/site-settings/gst-registration.js +126 -0
  52. package/dist/_internal/shared/fees/calculator.d.ts +105 -0
  53. package/dist/_internal/shared/fees/calculator.js +143 -0
  54. package/dist/_internal/shared/listing-types/art/config.d.ts +0 -6
  55. package/dist/_internal/shared/listing-types/classified/config.d.ts +0 -6
  56. package/dist/_internal/shared/listing-types/digital-code/config.d.ts +0 -6
  57. package/dist/_internal/shared/listing-types/live/config.d.ts +0 -6
  58. package/dist/_internal/shared/listing-types/standard/config.d.ts +0 -6
  59. package/dist/_internal/shared/listing-types/stickers/config.d.ts +0 -6
  60. package/dist/_internal/shared/templating/placeholders.d.ts +70 -0
  61. package/dist/_internal/shared/templating/placeholders.js +73 -0
  62. package/dist/client.d.ts +2 -0
  63. package/dist/client.js +1 -0
  64. package/dist/constants/api-endpoints.d.ts +42 -0
  65. package/dist/constants/api-endpoints.js +14 -0
  66. package/dist/features/admin/actions/admin-actions.d.ts +1 -1
  67. package/dist/features/admin/actions/admin-actions.js +1 -1
  68. package/dist/features/admin/components/AdminCategoryEditorView.js +269 -3
  69. package/dist/features/admin/components/AdminProductEditorView.js +8 -1
  70. package/dist/features/admin/components/AdminProductsView.js +78 -7
  71. package/dist/features/admin/components/AdminSiteSettingsView.js +20 -1
  72. package/dist/features/admin/components/AdminTaxCodeEditorView.d.ts +10 -0
  73. package/dist/features/admin/components/AdminTaxCodeEditorView.js +160 -0
  74. package/dist/features/admin/components/AdminTaxCodesView.d.ts +13 -0
  75. package/dist/features/admin/components/AdminTaxCodesView.js +86 -0
  76. package/dist/features/admin/components/AdminTesterChecklistView.js +1 -1
  77. package/dist/features/admin/components/analytics/AdminTopProductsTable.js +1 -1
  78. package/dist/features/auctions/components/AuctionBottomActions.js +10 -1
  79. package/dist/features/auctions/components/AuctionDetailPageView.js +2 -1
  80. package/dist/features/auctions/components/AuctionLiveStatusBadge.d.ts +20 -0
  81. package/dist/features/auctions/components/AuctionLiveStatusBadge.js +21 -0
  82. package/dist/features/auctions/components/PlaceBidFormClient.d.ts +1 -1
  83. package/dist/features/auctions/components/PlaceBidFormClient.js +20 -2
  84. package/dist/features/auctions/hooks/useIsAuctionEnded.d.ts +41 -0
  85. package/dist/features/auctions/hooks/useIsAuctionEnded.js +76 -0
  86. package/dist/features/auth/schemas/firestore.d.ts +0 -1
  87. package/dist/features/blog/api/route.js +16 -1
  88. package/dist/features/blog/schemas/firestore.d.ts +2 -2
  89. package/dist/features/catalogue/components/CatalogueItemEditorView.js +14 -3
  90. package/dist/features/categories/actions/category-actions.d.ts +2 -2
  91. package/dist/features/categories/actions/category-actions.js +22 -10
  92. package/dist/features/categories/api/[id]/description-template/route.d.ts +45 -0
  93. package/dist/features/categories/api/[id]/description-template/route.js +252 -0
  94. package/dist/features/categories/api/route.js +156 -11
  95. package/dist/features/categories/components/CategoriesIndexListing.d.ts +1 -3
  96. package/dist/features/categories/components/CategoriesIndexListing.js +1 -1
  97. package/dist/features/categories/components/CategoriesIndexPageView.d.ts +27 -1
  98. package/dist/features/categories/components/CategoriesIndexPageView.js +24 -33
  99. package/dist/features/categories/components/CategoryDetailPageView.js +43 -10
  100. package/dist/features/categories/components/CategoryTemplatePicker.d.ts +65 -0
  101. package/dist/features/categories/components/CategoryTemplatePicker.js +170 -0
  102. package/dist/features/categories/constants/listing-categories.d.ts +17 -0
  103. package/dist/features/categories/constants/listing-categories.js +53 -0
  104. package/dist/features/categories/hooks/useCategoryTree.js +28 -2
  105. package/dist/features/categories/repository/categories.repository.d.ts +73 -12
  106. package/dist/features/categories/repository/categories.repository.js +203 -42
  107. package/dist/features/categories/repository/price-index.repository.d.ts +115 -0
  108. package/dist/features/categories/repository/price-index.repository.js +85 -0
  109. package/dist/features/categories/schemas/category-content.d.ts +206 -0
  110. package/dist/features/categories/schemas/category-content.js +28 -0
  111. package/dist/features/categories/schemas/firestore.d.ts +74 -5
  112. package/dist/features/categories/schemas/firestore.js +74 -3
  113. package/dist/features/categories/schemas/index.d.ts +1047 -0
  114. package/dist/features/categories/schemas/index.js +96 -0
  115. package/dist/features/categories/server.d.ts +1 -0
  116. package/dist/features/categories/server.js +7 -0
  117. package/dist/features/categories/types/index.d.ts +9 -0
  118. package/dist/features/events/schemas/firestore.d.ts +2 -2
  119. package/dist/features/faq/schemas/firestore.d.ts +2 -1
  120. package/dist/features/faq/schemas/firestore.js +20 -8
  121. package/dist/features/faq/utils/getHomepageFaqsCached.d.ts +20 -0
  122. package/dist/features/faq/utils/getHomepageFaqsCached.js +22 -0
  123. package/dist/features/homepage/components/MarketplaceHomepageView.js +13 -3
  124. package/dist/features/homepage/lib/live-stats.js +18 -8
  125. package/dist/features/media/MediaImage.js +19 -2
  126. package/dist/features/orders/schemas/firestore.d.ts +70 -0
  127. package/dist/features/orders/types/index.d.ts +55 -0
  128. package/dist/features/products/actions/product-actions.d.ts +0 -9
  129. package/dist/features/products/actions/product-actions.js +25 -0
  130. package/dist/features/products/columns/index.d.ts +0 -1
  131. package/dist/features/products/columns/index.js +5 -1
  132. package/dist/features/products/components/ArtStickersListView.js +7 -1
  133. package/dist/features/products/components/PrizeDrawsSection.js +5 -0
  134. package/dist/features/products/components/ProductFilters.d.ts +0 -9
  135. package/dist/features/products/components/ProductForm.d.ts +27 -1
  136. package/dist/features/products/components/ProductForm.js +26 -12
  137. package/dist/features/products/components/ProductsIndexPageView.js +1 -1
  138. package/dist/features/products/constants/sieve.d.ts +0 -6
  139. package/dist/features/products/constants/sieve.js +35 -2
  140. package/dist/features/products/repository/products.repository.d.ts +115 -1
  141. package/dist/features/products/repository/products.repository.js +491 -39
  142. package/dist/features/products/schemas/firestore.d.ts +65 -5
  143. package/dist/features/products/schemas/firestore.js +9 -0
  144. package/dist/features/products/schemas/product-features.d.ts +140 -2
  145. package/dist/features/products/schemas/product-features.js +62 -1
  146. package/dist/features/promotions/repository/coupons.repository.js +6 -1
  147. package/dist/features/promotions/schemas/firestore.d.ts +44 -1
  148. package/dist/features/promotions/schemas/firestore.js +76 -2
  149. package/dist/features/reviews/repository/reviews.repository.d.ts +22 -0
  150. package/dist/features/reviews/repository/reviews.repository.js +35 -0
  151. package/dist/features/seller/actions/seller-actions.js +17 -2
  152. package/dist/features/seller/components/PrintCenterView.d.ts +3 -2
  153. package/dist/features/seller/components/PrintCenterView.js +3 -2
  154. package/dist/features/seller/components/SellerAnalyticsAlertsView.js +21 -11
  155. package/dist/features/seller/components/SellerOrdersView.js +6 -1
  156. package/dist/features/seller/components/SellerPayoutSettingsView.js +19 -3
  157. package/dist/features/seller/components/SellerProductShell.d.ts +50 -2
  158. package/dist/features/seller/components/SellerProductShell.js +101 -9
  159. package/dist/features/seller/components/SellerProductsFilterDrawer.d.ts +13 -1
  160. package/dist/features/seller/components/SellerProductsFilterDrawer.js +2 -2
  161. package/dist/features/seller/components/SellerProductsView.js +108 -3
  162. package/dist/features/seller/types/index.d.ts +17 -0
  163. package/dist/features/seller/utils/product-draft-mapping.d.ts +13 -0
  164. package/dist/features/seller/utils/product-draft-mapping.js +17 -0
  165. package/dist/features/store-extensions/constants/alert-metrics.d.ts +86 -0
  166. package/dist/features/store-extensions/constants/alert-metrics.js +142 -0
  167. package/dist/features/store-extensions/schemas/firestore.d.ts +19 -1
  168. package/dist/features/stores/schemas/firestore.d.ts +31 -2
  169. package/dist/features/tax-codes/repository/tax-codes.repository.d.ts +55 -0
  170. package/dist/features/tax-codes/repository/tax-codes.repository.js +131 -0
  171. package/dist/features/tax-codes/schemas/firestore.d.ts +125 -0
  172. package/dist/features/tax-codes/schemas/firestore.js +82 -0
  173. package/dist/features/tax-codes/schemas/tax-code-form.d.ts +63 -0
  174. package/dist/features/tax-codes/schemas/tax-code-form.js +152 -0
  175. package/dist/features/tax-codes/schemas/tax-codes.validators.d.ts +107 -0
  176. package/dist/features/tax-codes/schemas/tax-codes.validators.js +85 -0
  177. package/dist/features/tester/actions/index.d.ts +0 -1
  178. package/dist/features/tester/actions/index.js +0 -1
  179. package/dist/features/tester/components/AdminTesterFeedbackIssuesView.js +1 -1
  180. package/dist/features/tester/components/AdminTesterFeedbackListView.js +1 -1
  181. package/dist/features/tester/components/index.d.ts +0 -4
  182. package/dist/features/tester/components/index.js +0 -2
  183. package/dist/features/tester/repository/tester-checklist-item.repository.d.ts +1 -20
  184. package/dist/features/tester/repository/tester-checklist-item.repository.js +0 -52
  185. package/dist/features/tester/schemas/firestore.d.ts +0 -6
  186. package/dist/features/tester/seed-data/authored/admin__admin-detail-round-trips.js +3 -3
  187. package/dist/features/tester/seed-data/authored/admin__site-system.js +4 -5
  188. package/dist/features/tester/seed-data/authored/content-discovery__category-counts-and-rollup.js +2 -2
  189. package/dist/features/tester/seed-data/authored/index.js +0 -2
  190. package/dist/features/tester/seed-data/authored/page-wiring__reachability.js +0 -19
  191. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +10 -29
  192. package/dist/index.d.ts +21 -7
  193. package/dist/index.js +53 -7
  194. package/dist/next/routing/route-map.d.ts +2 -4
  195. package/dist/next/routing/route-map.js +1 -2
  196. package/dist/repositories/index.d.ts +1 -0
  197. package/dist/repositories/index.js +1 -0
  198. package/dist/schemas/registry.d.ts +506 -0
  199. package/dist/seed/_helpers/brand-rows.d.ts +35 -0
  200. package/dist/seed/_helpers/brand-rows.js +576 -0
  201. package/dist/seed/_helpers/category-content.d.ts +39 -0
  202. package/dist/seed/_helpers/category-content.js +634 -0
  203. package/dist/seed/_helpers/category-forest.d.ts +2 -0
  204. package/dist/seed/_helpers/category-forest.js +585 -243
  205. package/dist/seed/_helpers/category-models.d.ts +5 -0
  206. package/dist/seed/_helpers/category-models.js +1364 -0
  207. package/dist/seed/_helpers/category-tree.js +17 -1
  208. package/dist/seed/_helpers/character-features.d.ts +10 -0
  209. package/dist/seed/_helpers/character-features.js +118 -0
  210. package/dist/seed/_helpers/media.d.ts +1 -1
  211. package/dist/seed/_helpers/media.js +44 -8
  212. package/dist/seed/_helpers/search-txt-wrappers.d.ts +10 -0
  213. package/dist/seed/_helpers/search-txt-wrappers.js +12 -1
  214. package/dist/seed/categories-seed-data.js +147 -169
  215. package/dist/seed/index.d.ts +1 -0
  216. package/dist/seed/index.js +1 -0
  217. package/dist/seed/manifest.d.ts +1 -1
  218. package/dist/seed/manifest.js +5 -0
  219. package/dist/seed/orders-seed-data.js +5 -3
  220. package/dist/seed/product-features-seed-data.d.ts +1 -8
  221. package/dist/seed/product-features-seed-data.js +358 -154
  222. package/dist/seed/products-art-seed-data.js +16 -4
  223. package/dist/seed/products-auctions-seed-data.js +6 -6
  224. package/dist/seed/products-classifieds-seed-data.js +17 -7
  225. package/dist/seed/products-digital-codes-seed-data.js +12 -12
  226. package/dist/seed/products-preorders-seed-data.js +8 -8
  227. package/dist/seed/products-prize-draws-seed-data.js +25 -8
  228. package/dist/seed/products-standard-seed-data.js +10 -60
  229. package/dist/seed/products-stickers-seed-data.js +6 -6
  230. package/dist/seed/site-settings-seed-data.js +24 -0
  231. package/dist/seed/store-extensions-seed-data.js +10 -4
  232. package/dist/seed/tax-codes-seed-data.d.ts +34 -0
  233. package/dist/seed/tax-codes-seed-data.js +100 -0
  234. package/dist/seed/test-data-ttl.d.ts +29 -0
  235. package/dist/seed/test-data-ttl.js +31 -0
  236. package/dist/server-entry.d.ts +1 -1
  237. package/dist/server-entry.js +6 -1
  238. package/dist/server.d.ts +4 -1
  239. package/dist/server.js +11 -2
  240. package/dist/styles.css +40 -0
  241. package/dist/ui/components/PaginatedSelect.d.ts +14 -0
  242. package/dist/ui/components/PaginatedSelect.js +0 -0
  243. package/dist/ui/components/PaginatedSelect.style.css +40 -0
  244. package/dist/utils/media-url.d.ts +26 -0
  245. package/dist/utils/media-url.js +144 -0
  246. package/dist/utils/physical-location.d.ts +23 -0
  247. package/dist/utils/physical-location.js +52 -0
  248. package/dist/utils/search-txt-builders.d.ts +20 -0
  249. package/dist/utils/search-txt-builders.js +36 -0
  250. package/package.json +1 -1
  251. package/scripts/seed-cli.mjs +4 -1
  252. package/dist/_internal/server/jobs/handlers/testerSandboxCleanup.d.ts +0 -2
  253. package/dist/_internal/server/jobs/handlers/testerSandboxCleanup.js +0 -2
  254. package/dist/features/tester/actions/leaderboard-actions.d.ts +0 -3
  255. package/dist/features/tester/actions/leaderboard-actions.js +0 -5
  256. package/dist/features/tester/components/BugHunterLeaderboardView.d.ts +0 -23
  257. package/dist/features/tester/components/BugHunterLeaderboardView.js +0 -18
  258. package/dist/features/tester/components/TesterHubView.d.ts +0 -5
  259. package/dist/features/tester/components/TesterHubView.js +0 -110
  260. package/dist/features/tester/seed-data/authored/public-pages__bug-hunters.d.ts +0 -2
  261. package/dist/features/tester/seed-data/authored/public-pages__bug-hunters.js +0 -78
  262. package/dist/features/tester/seed-data/tester-ttl.d.ts +0 -4
  263. package/dist/features/tester/seed-data/tester-ttl.js +0 -6
@@ -1,17 +1,34 @@
1
1
  /*
2
- * WHY: Provides the Beyblade-focused category hierarchy plus brand entries for the
3
- * demo seed. The site itself stays generically branded as a collectibles marketplace —
4
- * only the seeded catalog data is narrowed to Beyblade so the demo has a coherent
5
- * dataset instead of a sprawling multi-franchise catalog.
6
- * WHAT: Exports categoriesSeedData — a 4-level, TWO-root category forest
7
- * (`Spinning Tops` + `Living Collectibles`, see _helpers/category-forest.ts),
8
- * brand rows (categoryType:"brand") and pricing bundles (categoryType:"bundle").
2
+ * WHY: The real catalogue taxonomy. 🛑 This file is NO LONGER Beyblade-only —
3
+ * its header said "narrowed to Beyblade so the demo has a coherent
4
+ * dataset instead of a sprawling multi-franchise catalog" and B5 reversed
5
+ * that deliberately, on evidence: a 15-site crawl of ~25,900 live Indian
6
+ * listings showed trading cards, collectible figures and Hot Wheels are
7
+ * each a real vertical with its own measured price bands, and three of
8
+ * the five largest competitors sell more than one of them.
9
9
  *
10
- * The tree was 2 levels under a single root until 2026-08-24. That made
10
+ * The old framing is not contradicted here, it is superseded — coherence
11
+ * now comes from the TREE being one axis deep per vertical rather than
12
+ * from the catalogue being one franchise wide.
13
+ *
14
+ * WHAT: Exports categoriesSeedData — a 5-level, SIX-root forest (Spinning Tops,
15
+ * Trading Cards, Collectible Figures, Hot Wheels, Model Kits, Living
16
+ * Collectibles — see _helpers/category-forest.ts), 28 brand rows
17
+ * (categoryType:"brand", _helpers/brand-rows.ts), two sublisting rows and
18
+ * five pricing bundles (categoryType:"bundle").
19
+ *
20
+ * The tree was 2 levels under a single root until 2026-08-24 and 47 nodes
21
+ * across 2 roots until B5. The first state made
11
22
  * `categoryType:"sublisting"` — documented as "tier-4 leaf groups under a
12
23
  * parent category" — structurally unreachable, and left the live-item
13
24
  * products with no category at all.
14
25
  *
26
+ * The tier-4 layer is 216 NAMED MODEL leaves (Lost Longinus, Storm
27
+ * Pegasus, Dran Sword …), GENERATED from the canonical corpus in
28
+ * _helpers/category-models.ts rather than typed by hand — a slug is the
29
+ * document id, the public URL and a searchTxt source, so it is the one
30
+ * field that cannot be quietly corrected later.
31
+ *
15
32
  * Products tag their FULL ancestor chain (leaf -> … -> root) so a single
16
33
  * array-contains at any level returns the whole subtree. That is what lets
17
34
  * a category page match on its own id alone; expanding descendants into an
@@ -36,7 +53,12 @@
36
53
  import { CATEGORY_FIELDS } from "../constants/field-names";
37
54
  import { seedPhoto } from "./_helpers/media";
38
55
  import { buildCategoryTree } from "./_helpers/category-tree";
56
+ import { withCategorySearchTxt } from "./_helpers/search-txt-wrappers";
39
57
  import { CATEGORY_FOREST } from "./_helpers/category-forest";
58
+ import { BRAND_ROW_COUNT, buildBrandRows } from "./_helpers/brand-rows";
59
+ import { MODEL_LEAF_COUNT } from "./_helpers/category-models";
60
+ import { MARKET_BAND_LEAF_IDS } from "./_helpers/category-content";
61
+ import { productsStandardSeedData } from "./products-standard-seed-data";
40
62
  const NOW = new Date();
41
63
  const daysAgo = (n) => new Date(NOW.getTime() - n * 86400000);
42
64
  const emptyMetrics = {
@@ -50,9 +72,14 @@ const emptyMetrics = {
50
72
  lastUpdated: daysAgo(1),
51
73
  };
52
74
  // ──────────────────────────────────────────────────────────────────────────────
53
- // Categories — 47 rows across 4 tiers and 2 roots, all structural fields derived.
54
- // The shape lives in _helpers/category-forest.ts; the derivation in
55
- // _helpers/category-tree.ts.
75
+ // Categories — 381 rows across 5 tiers and 6 roots, every structural field
76
+ // derived. The shape lives in _helpers/category-forest.ts, the named-model
77
+ // tier-4 leaves in the GENERATED _helpers/category-models.ts, and the
78
+ // derivation in _helpers/category-tree.ts.
79
+ //
80
+ // 🛑 Never quote this count without running `buildCategoryTree` against the
81
+ // forest — it was 47 before B5 and the comment here said so for months after
82
+ // the tree changed underneath it.
56
83
  // ──────────────────────────────────────────────────────────────────────────────
57
84
  const rawCategories = buildCategoryTree(CATEGORY_FOREST, {
58
85
  createdBy: "user-admin-letitrip",
@@ -153,157 +180,61 @@ const sublistingRows = [
153
180
  },
154
181
  ];
155
182
  // ──────────────────────────────────────────────────────────────────────────────
156
- // Brands (categoryType:"brand").
183
+ // Brands (categoryType:"brand") — 4 rows -> 28, built by a factory.
157
184
  //
158
- // ⚠️ `BrandDetailPageView` matches products on the free-text `brand` DISPLAY
159
- // NAME (`sieveFilter("brand", EQ, brandName)`), not on `brandSlug`. So a brand
160
- // row's `name` here and the `brand:` string on every product that belongs to it
161
- // must match EXACTLY — renaming a brand silently orphans its whole catalogue.
162
- // Keep `brand` and `brandSlug` in lockstep on the product side.
185
+ // The shape, the three live traps (display-name matching, icon-beats-cover,
186
+ // and why a brand with no products is worse than no brand) and the logo
187
+ // decision all live in _helpers/brand-rows.ts. Four inline rows at ~35 lines
188
+ // each was already the wrong shape for 28.
163
189
  // ──────────────────────────────────────────────────────────────────────────────
164
- const brandRows = [
165
- {
166
- id: "brand-takara-tomy",
167
- slug: "brand-takara-tomy",
168
- name: "Takara-Tomy",
169
- categoryType: CATEGORY_FIELDS.CATEGORY_TYPE_VALUES.BRAND,
170
- description: "Japanese toy company behind Beyblade, Tomica, Transformers (Japan), and Duel Masters. Known for premium quality and Japan-exclusive releases.",
171
- brandWebsite: "https://www.takaratomy.co.jp",
172
- brandCountry: "Japan",
173
- brandFounded: 2006,
174
- highlights: [
175
- "The Japanese toy company that manufactures every Beyblade generation",
176
- "Also behind Tomica, Transformers (Japan region), and Duel Masters",
177
- "Known for Japan-exclusive releases and premium tooling quality",
178
- ],
179
- faqs: [
180
- { question: "Is Takara-Tomy the same company as Hasbro's Beyblade line?", answer: "No — Takara-Tomy manufactures and sells Beyblade in Japan and most of Asia; Hasbro licenses and distributes a separate (sometimes different) product line internationally, primarily in North America." },
181
- { question: "Are Takara-Tomy imports compatible with Hasbro Beyblade parts?", answer: "Within the same generation (e.g. Burst-to-Burst), yes, in most cases — cross-generation compatibility is not guaranteed." },
182
- ],
183
- rootId: "brand-takara-tomy",
184
- parentIds: [],
185
- tier: 0,
186
- path: "brand-takara-tomy",
187
- isLeaf: true,
188
- order: 1,
189
- display: { coverImage: seedPhoto("brand-logo-takara-tomy-20260101", 800, 800), showInMenu: false, showInFooter: true },
190
- isFeatured: true,
191
- isBrand: true,
192
- isActive: true,
193
- isSearchable: true,
194
- createdBy: "user-admin-letitrip",
195
- createdAt: daysAgo(300),
196
- updatedAt: daysAgo(30),
197
- seo: { title: "Takara-Tomy | LetItRip", description: "Shop Takara-Tomy collectibles — Beyblade, Tomica, Transformers.", keywords: ["takara tomy", "takara tomy beyblade", "tomica takara"] },
198
- },
199
- {
200
- id: "brand-beyblade",
201
- slug: "brand-beyblade",
202
- name: "Beyblade",
203
- categoryType: CATEGORY_FIELDS.CATEGORY_TYPE_VALUES.BRAND,
204
- description: "Spinning top battle franchise by Takara-Tomy (Japan) and Hasbro (international). Covers the Original series, Metal Fight, Burst, and the latest Beyblade X generation.",
205
- brandWebsite: "https://beyblade.takaratomy.co.jp",
206
- brandCountry: "Japan",
207
- brandFounded: 1999,
208
- highlights: [
209
- "The franchise itself — spanning four generations since 1999",
210
- "One of the best-selling spinning-top toy lines in the world",
211
- "A competitive tournament scene alongside casual collecting",
212
- ],
213
- faqs: [
214
- { question: "What age range is Beyblade designed for?", answer: "Most sets are labeled for ages 8+ due to small parts and launcher spring mechanisms — always check the age rating on the listing before buying for a young child." },
215
- { question: "Where can I find official tournament rules?", answer: "Takara-Tomy and Hasbro both publish official battle rules for their respective regions — check the manufacturer's site linked from this page's \"Website\" field for the current rulebook." },
216
- ],
217
- rootId: "brand-beyblade",
218
- parentIds: [],
219
- tier: 0,
220
- path: "brand-beyblade",
221
- isLeaf: true,
222
- order: 2,
223
- display: { coverImage: seedPhoto("brand-logo-beyblade-20260101", 800, 800), showInMenu: false, showInFooter: true },
224
- isFeatured: true,
225
- isBrand: true,
226
- isActive: true,
227
- isSearchable: true,
228
- createdBy: "user-admin-letitrip",
229
- createdAt: daysAgo(300),
230
- updatedAt: daysAgo(30),
231
- seo: { title: "Beyblade | LetItRip", description: "Shop Beyblade — Original, X, Burst, Metal Fight tops and stadiums.", keywords: ["beyblade", "beyblade x", "beyblade burst", "spinning top battle"] },
232
- },
233
- {
234
- id: "brand-hasbro",
235
- slug: "brand-hasbro",
236
- name: "Hasbro",
237
- categoryType: CATEGORY_FIELDS.CATEGORY_TYPE_VALUES.BRAND,
238
- description: "The international Beyblade licensee — Hasbro distributes its own Beyblade product line outside Japan, with different packaging, part names and sometimes different mould tolerances from the Takara-Tomy originals.",
239
- brandWebsite: "https://shop.hasbro.com",
240
- brandCountry: "United States",
241
- brandFounded: 1923,
242
- highlights: [
243
- "The Beyblade line most collectors outside Japan grew up with",
244
- "Widely available and generally cheaper than Japanese imports",
245
- "Same-generation parts are usually cross-compatible with Takara-Tomy",
246
- ],
247
- faqs: [
248
- { question: "Is a Hasbro Beyblade worse than the Takara-Tomy version?", answer: "Not worse, but often different — Hasbro releases can use different plastics and slightly looser tolerances, which competitive players notice. For casual play they perform comparably." },
249
- { question: "Can I mix Hasbro and Takara-Tomy parts?", answer: "Within the same generation, almost always yes. Across generations, no — the launcher and locking systems differ." },
250
- ],
251
- rootId: "brand-hasbro",
252
- parentIds: [],
253
- tier: 0,
254
- path: "brand-hasbro",
255
- isLeaf: true,
256
- order: 3,
257
- display: { coverImage: seedPhoto("brand-logo-hasbro-20260101", 800, 800), showInMenu: false, showInFooter: true },
258
- isFeatured: false,
259
- isBrand: true,
260
- isActive: true,
261
- isSearchable: true,
262
- createdBy: "user-admin-letitrip",
263
- createdAt: daysAgo(300),
264
- updatedAt: daysAgo(30),
265
- seo: { title: "Hasbro | LetItRip", description: "Shop Hasbro Beyblade — the international product line.", keywords: ["hasbro", "hasbro beyblade", "beyblade burst hasbro"] },
266
- },
267
- {
268
- // The Living Collectibles root needs a brand of its own: live listings are
269
- // sold by individual keepers and breeders, not by a manufacturer. Without
270
- // one, the three live-item products carried a `brand: "Beyblade Arena"`
271
- // string (a STORE name in a brand field) that matched no brand row, so they
272
- // were invisible on every brand page.
273
- id: "brand-independent-keepers",
274
- slug: "brand-independent-keepers",
275
- name: "Independent Keepers",
276
- categoryType: CATEGORY_FIELDS.CATEGORY_TYPE_VALUES.BRAND,
277
- description: "Live animals and plants come from individual keepers, breeders and growers rather than a manufacturer. This entry groups those listings so they are reachable from brand browsing like everything else.",
278
- brandCountry: "India",
279
- highlights: [
280
- "Every seller is verified before a live listing can go public",
281
- "Provenance, age and health information disclosed per listing",
282
- ],
283
- faqs: [
284
- { question: "Why is there a \"brand\" for living things at all?", answer: "Purely so live listings behave like every other listing in browse and search. It identifies the class of seller, not a manufacturer." },
285
- ],
286
- rootId: "brand-independent-keepers",
287
- parentIds: [],
288
- tier: 0,
289
- path: "brand-independent-keepers",
290
- isLeaf: true,
291
- order: 4,
292
- display: { coverImage: seedPhoto("brand-logo-independent-keepers-20260101", 800, 800), showInMenu: false, showInFooter: false },
293
- isFeatured: false,
294
- isBrand: true,
295
- isActive: true,
296
- isSearchable: true,
297
- createdBy: "user-admin-letitrip",
298
- createdAt: daysAgo(300),
299
- updatedAt: daysAgo(30),
300
- seo: { title: "Independent Keepers | LetItRip", description: "Live animals and plants from verified independent keepers and growers.", keywords: ["independent keepers", "breeders", "live plants"] },
301
- },
302
- ];
190
+ const brandRows = buildBrandRows({
191
+ createdBy: "user-admin-letitrip",
192
+ createdAt: daysAgo(300),
193
+ updatedAt: daysAgo(30),
194
+ });
303
195
  // P-17 — 5 bundle rows (categoryType:"bundle") grouping the Beyblade-minimal
304
196
  // standard products by generation, plus one cross-generation starter pack.
305
197
  // Every bundle references real seeded product ids (products-standard-seed-data.ts),
306
198
  // all currently under store-beyblade-arena.
199
+ /*
200
+ * 🛑 `bundleCategorySlugs` is DERIVED, because it is a MIRROR and mirrors
201
+ * drift (Root Cause #42).
202
+ *
203
+ * The field is the union of the members' `categorySlugs`, and it is what lets
204
+ * a category page scope its Bundles tab at all. It was hand-written across
205
+ * all five bundles — and it drifted in B5 the moment the Beyblade X tree
206
+ * changed: two bundles still named `category-x-starters` and
207
+ * `category-x-boosters`, leaves that no longer exist, so those bundles had
208
+ * silently stopped appearing under any Beyblade X category.
209
+ *
210
+ * Worse, the stale strings were still being READ as valid seed ids by
211
+ * `audit-tester-plugin-wiring` R7 once its id scan was widened, which briefly
212
+ * made two genuinely-broken authored tester cases stop being reported. A
213
+ * hand-maintained mirror does not only go wrong — it can keep the check that
214
+ * would have caught it quiet.
215
+ *
216
+ * Deriving from the members' own chains means the union cannot disagree with
217
+ * them, and a member whose chain moves updates every bundle holding it.
218
+ */
219
+ const PRODUCT_CHAINS = new Map(productsStandardSeedData.map((p) => [String(p.id), (p.categorySlugs ?? [])]));
220
+ function bundleCategorySlugsFor(productIds) {
221
+ const out = [];
222
+ for (const id of productIds) {
223
+ const chain = PRODUCT_CHAINS.get(id);
224
+ /*
225
+ * A member missing from the standard seed is a BUG, not something to shrug
226
+ * past: the bundle would silently lose that member's categories and the
227
+ * Bundles tab would under-report. All eight current members are standard
228
+ * products; if that changes, widen the map rather than softening this.
229
+ */
230
+ if (!chain)
231
+ throw new Error(`bundle member ${id} is not in productsStandardSeedData`);
232
+ for (const c of chain)
233
+ if (!out.includes(c))
234
+ out.push(c);
235
+ }
236
+ return out;
237
+ }
307
238
  const bundleRows = [
308
239
  {
309
240
  id: "bundle-original-collectors-set",
@@ -319,7 +250,7 @@ const bundleRows = [
319
250
  productIds: ["product-beyblade-original-dranzer-s", "product-beyblade-original-driger-v", "product-beyblade-metal-storm-pegasus"],
320
251
  },
321
252
  bundleProductIds: ["product-beyblade-original-dranzer-s", "product-beyblade-original-driger-v", "product-beyblade-metal-storm-pegasus"],
322
- bundleCategorySlugs: ["category-original-hms", "category-original-tops", "category-beyblade-original", "category-spinning-tops", "category-original-plastic-gen", "category-metal-masters", "category-metal-tops", "category-beyblade-metal"],
253
+ bundleCategorySlugs: bundleCategorySlugsFor(["product-beyblade-original-dranzer-s", "product-beyblade-original-driger-v", "product-beyblade-metal-storm-pegasus"]),
323
254
  bundleOriginalTotal: 4597, // 1499 + 1799 + 1299
324
255
  bundleStockStatus: "in_stock",
325
256
  display: { coverImage: seedPhoto("bundle-original-collectors-set-20260101", 1200, 900), showInFooter: false },
@@ -354,7 +285,7 @@ const bundleRows = [
354
285
  productIds: ["product-beyblade-metal-storm-pegasus", "product-beyblade-metal-flame-sagittario", "product-beyblade-original-dranzer-s"],
355
286
  },
356
287
  bundleProductIds: ["product-beyblade-metal-storm-pegasus", "product-beyblade-metal-flame-sagittario", "product-beyblade-original-dranzer-s"],
357
- bundleCategorySlugs: ["category-metal-masters", "category-metal-tops", "category-beyblade-metal", "category-spinning-tops", "category-metal-fury", "category-original-hms", "category-original-tops", "category-beyblade-original"],
288
+ bundleCategorySlugs: bundleCategorySlugsFor(["product-beyblade-metal-storm-pegasus", "product-beyblade-metal-flame-sagittario", "product-beyblade-original-dranzer-s"]),
358
289
  bundleOriginalTotal: 3997, // 1299 + 1199 + 1499
359
290
  bundleStockStatus: "in_stock",
360
291
  display: { coverImage: seedPhoto("bundle-metal-fusion-duo-20260101", 1200, 900), showInFooter: false },
@@ -391,7 +322,7 @@ const bundleRows = [
391
322
  productIds: ["product-beyblade-burst-valkyrie", "product-beyblade-burst-regalia-genesis", "product-beyblade-metal-flame-sagittario"],
392
323
  },
393
324
  bundleProductIds: ["product-beyblade-burst-valkyrie", "product-beyblade-burst-regalia-genesis", "product-beyblade-metal-flame-sagittario"],
394
- bundleCategorySlugs: ["category-burst-superking", "category-burst-tops", "category-beyblade-burst", "category-spinning-tops", "category-burst-classic", "category-metal-fury", "category-metal-tops", "category-beyblade-metal"],
325
+ bundleCategorySlugs: bundleCategorySlugsFor(["product-beyblade-burst-valkyrie", "product-beyblade-burst-regalia-genesis", "product-beyblade-metal-flame-sagittario"]),
395
326
  bundleOriginalTotal: 3597, // 999 + 1399 + 1199
396
327
  bundleStockStatus: "in_stock",
397
328
  display: { coverImage: seedPhoto("bundle-burst-battlers-pack-20260101", 1200, 900), showInFooter: false },
@@ -426,7 +357,7 @@ const bundleRows = [
426
357
  productIds: ["product-beyblade-x-wizard-arrow", "product-beyblade-x-knife-shinobi", "product-beyblade-burst-valkyrie"],
427
358
  },
428
359
  bundleProductIds: ["product-beyblade-x-wizard-arrow", "product-beyblade-x-knife-shinobi", "product-beyblade-burst-valkyrie"],
429
- bundleCategorySlugs: ["category-x-starters", "category-x-tops", "category-beyblade-x", "category-spinning-tops", "category-x-boosters", "category-burst-superking", "category-burst-tops", "category-beyblade-burst"],
360
+ bundleCategorySlugs: bundleCategorySlugsFor(["product-beyblade-x-wizard-arrow", "product-beyblade-x-knife-shinobi", "product-beyblade-burst-valkyrie"]),
430
361
  bundleOriginalTotal: 2847, // 899 + 949 + 999
431
362
  bundleStockStatus: "in_stock",
432
363
  display: { coverImage: seedPhoto("bundle-x-series-starter-20260101", 1200, 900), showInFooter: false },
@@ -474,7 +405,7 @@ const bundleRows = [
474
405
  "product-beyblade-burst-valkyrie",
475
406
  "product-beyblade-x-wizard-arrow",
476
407
  ],
477
- bundleCategorySlugs: ["category-original-plastic-gen", "category-original-tops", "category-beyblade-original", "category-spinning-tops", "category-metal-masters", "category-metal-tops", "category-beyblade-metal", "category-burst-superking", "category-burst-tops", "category-beyblade-burst", "category-x-starters", "category-x-tops", "category-beyblade-x"],
408
+ bundleCategorySlugs: bundleCategorySlugsFor(["product-beyblade-original-driger-v", "product-beyblade-metal-storm-pegasus", "product-beyblade-burst-valkyrie", "product-beyblade-x-wizard-arrow"]),
478
409
  bundleOriginalTotal: 4996, // 1799 + 1299 + 999 + 899
479
410
  bundleStockStatus: "in_stock",
480
411
  display: { coverImage: seedPhoto("bundle-every-generation-starter-pack-20260101", 1200, 900), showInFooter: false },
@@ -496,17 +427,64 @@ const bundleRows = [
496
427
  updatedAt: daysAgo(1),
497
428
  },
498
429
  ];
499
- export const categoriesSeedData = [
430
+ /*
431
+ * One array, wrapped once.
432
+ *
433
+ * `categoriesSeedData` and `categoriesP1SeedData` were two byte-identical
434
+ * literals, so every change had to be made twice — and `searchTxt` would have
435
+ * been two derivations to keep in step, which is the exact drift
436
+ * `search-txt-wrappers.ts` exists to prevent.
437
+ *
438
+ * 🛑 `withCategorySearchTxt` is applied AFTER the spread, deliberately:
439
+ * `buildCategorySearchTxt` indexes `path` and `ancestors[].name`, both DERIVED
440
+ * by `buildCategoryTree`. Wrapping a row before derivation would index
441
+ * name/slug/description only and silently drop the lineage search — typing
442
+ * "burst" would stop reaching a tier-4 model under Beyblade Burst.
443
+ */
444
+ const allCategoryRows = [
500
445
  ...rawCategories.map((c) => ({ ancestors: [], ...c, createdByType: "admin" })),
501
446
  ...sublistingRows.map((s) => ({ ancestors: [], ...s, createdByType: "admin" })),
502
447
  ...brandRows.map((b) => ({ ancestors: [], ...b, createdByType: "admin" })),
503
448
  ...bundleRows.map((b) => ({ ancestors: [], ...b })),
504
- ];
449
+ ].map(withCategorySearchTxt);
450
+ /*
451
+ * ── Assertions, at MODULE LOAD, so a silent drop is loud ─────────────────────
452
+ *
453
+ * 🛑 These exist because of a specific failure shape this file is exposed to:
454
+ * `appkit-seed status` counts documents BY ID, so it cannot see content drift
455
+ * at all, and `load` is a `set(…, {merge:true})` that never removes a field.
456
+ * A generated map that silently emptied — `MODEL_LEAVES` keyed on a line id
457
+ * the forest renamed, say — would produce a tree that builds, typechecks,
458
+ * seeds without error, reports perfectly in sync, and is missing 216 pages.
459
+ *
460
+ * Throwing at import is the right severity: every consumer of this module
461
+ * (the seed CLI, the tester fixtures, the audits) wants to fail before writing
462
+ * rather than after.
463
+ */
464
+ const modelLeafRows = rawCategories.filter((c) => c.tier === 4).length;
465
+ if (modelLeafRows !== MODEL_LEAF_COUNT) {
466
+ throw new Error(`category seed: ${modelLeafRows} tier-4 model leaves reached the tree but ` +
467
+ `category-models.ts generated ${MODEL_LEAF_COUNT}. A line id in the ` +
468
+ `forest no longer matches a key in MODEL_LEAVES — re-run ` +
469
+ `node scripts/gen-category-models.mjs and check the line ids.`);
470
+ }
471
+ if (brandRows.length !== BRAND_ROW_COUNT) {
472
+ throw new Error(`category seed: ${brandRows.length} brand rows built, expected ${BRAND_ROW_COUNT}`);
473
+ }
474
+ {
475
+ /*
476
+ * A price band keyed on a leaf that does not exist is dead weight that READS
477
+ * AS COVERAGE — the hint renders nowhere and nothing says so. Cheap to
478
+ * check, and it is the most likely thing to rot as the tree is edited.
479
+ */
480
+ const ids = new Set(rawCategories.map((c) => c.id));
481
+ const orphans = MARKET_BAND_LEAF_IDS.filter((id) => !ids.has(id));
482
+ if (orphans.length) {
483
+ throw new Error(`category seed: ${orphans.length} market band(s) key a non-existent ` +
484
+ `leaf: ${orphans.join(", ")}`);
485
+ }
486
+ }
487
+ export const categoriesSeedData = allCategoryRows;
505
488
  // P-1 default seed: identical to categoriesSeedData (bundle rows included — P-17
506
489
  // re-added them 2026-08-15 after the earlier removal referenced below).
507
- export const categoriesP1SeedData = [
508
- ...rawCategories.map((c) => ({ ancestors: [], ...c, createdByType: "admin" })),
509
- ...sublistingRows.map((s) => ({ ancestors: [], ...s, createdByType: "admin" })),
510
- ...brandRows.map((b) => ({ ancestors: [], ...b, createdByType: "admin" })),
511
- ...bundleRows.map((b) => ({ ancestors: [], ...b })),
512
- ];
490
+ export const categoriesP1SeedData = allCategoryRows;
@@ -80,6 +80,7 @@ export { scammersSeedData } from "./scammers-seed-data";
80
80
  export { supportTicketsSeedData } from "./support-tickets-seed-data";
81
81
  export { testerChecklistSeedData, testerResponsesSeedData, } from "../features/tester/seed-data";
82
82
  export { productFeaturesSeedData } from "./product-features-seed-data";
83
+ export { taxCodesSeedData } from "./tax-codes-seed-data";
83
84
  export { offersSeedData } from "./offers-seed-data";
84
85
  export { payoutMethodsSeedData, shippingConfigsSeedData, analyticsCardsSeedData, analyticsAlertsSeedData, storeCategoriesSeedData, listingTemplatesSeedData, moderationQueueSeedData, reportsSeedData, itemRequestsSeedData, storeWhatsAppConfigSeedData, storeGoogleConfigSeedData, } from "./store-extensions-seed-data";
85
86
  export type { SeedManifest, SeedManifestEntry, SeedCollectionName } from "./manifest";
@@ -77,6 +77,7 @@ export { testerChecklistSeedData,
77
77
  // continues, which is exactly what happened on the first attempt here.
78
78
  testerResponsesSeedData, } from "../features/tester/seed-data";
79
79
  export { productFeaturesSeedData } from "./product-features-seed-data";
80
+ export { taxCodesSeedData } from "./tax-codes-seed-data";
80
81
  export { offersSeedData } from "./offers-seed-data";
81
82
  // S-STORE Extensions (Tier S-STORE) — 11 new collections
82
83
  export { payoutMethodsSeedData, shippingConfigsSeedData, analyticsCardsSeedData, analyticsAlertsSeedData, storeCategoriesSeedData, listingTemplatesSeedData, moderationQueueSeedData, reportsSeedData, itemRequestsSeedData, storeWhatsAppConfigSeedData, storeGoogleConfigSeedData, } from "./store-extensions-seed-data";
@@ -11,6 +11,6 @@ export interface SeedManifestEntry {
11
11
  type?: string;
12
12
  }
13
13
  /** Every collection name the CLI seeder (appkit/scripts/seed-cli.mjs) and this manifest cover. */
14
- export type SeedCollectionName = "users" | "addresses" | "categories" | "stores" | "products" | "orders" | "reviews" | "bids" | "coupons" | "carousels" | "carouselSlides" | "homepageSections" | "siteSettings" | "faqs" | "notifications" | "payouts" | "blogPosts" | "events" | "eventEntries" | "sessions" | "carts" | "wishlists" | "history" | "groupedListings" | "scammerProfiles" | "supportTickets" | "productFeatures" | "offers" | "couponUsage" | "claimedCoupons" | "payoutMethods" | "shippingConfigs" | "analyticsCards" | "analyticsAlerts" | "storeCategories" | "listingTemplates" | "moderationQueue" | "reports" | "itemRequests" | "storeWhatsAppConfig" | "storeGoogleConfig" | "roleOverrides" | "customRoles" | "adminNotifications" | "lotteryEntries" | "shipments" | "shipmentLots" | "shipmentItems" | "catalogueItems" | "testerChecklistItems";
14
+ export type SeedCollectionName = "users" | "addresses" | "categories" | "stores" | "products" | "orders" | "reviews" | "bids" | "coupons" | "carousels" | "carouselSlides" | "homepageSections" | "siteSettings" | "faqs" | "notifications" | "payouts" | "blogPosts" | "events" | "eventEntries" | "sessions" | "carts" | "wishlists" | "history" | "groupedListings" | "scammerProfiles" | "supportTickets" | "productFeatures" | "taxCodes" | "offers" | "couponUsage" | "claimedCoupons" | "payoutMethods" | "shippingConfigs" | "analyticsCards" | "analyticsAlerts" | "storeCategories" | "listingTemplates" | "moderationQueue" | "reports" | "itemRequests" | "storeWhatsAppConfig" | "storeGoogleConfig" | "roleOverrides" | "customRoles" | "adminNotifications" | "lotteryEntries" | "shipments" | "shipmentLots" | "shipmentItems" | "catalogueItems" | "testerChecklistItems";
15
15
  export type SeedManifest = Record<SeedCollectionName, SeedManifestEntry[]>;
16
16
  export declare const SEED_MANIFEST: SeedManifest;
@@ -46,6 +46,7 @@ import { groupedListingsSeedData } from "./grouped-listings-seed-data";
46
46
  import { scammersSeedData } from "./scammers-seed-data";
47
47
  import { supportTicketsSeedData } from "./support-tickets-seed-data";
48
48
  import { productFeaturesSeedData } from "./product-features-seed-data";
49
+ import { taxCodesSeedData } from "./tax-codes-seed-data";
49
50
  import { offersSeedData } from "./offers-seed-data";
50
51
  import { couponUsageSeedData } from "./coupon-usage-seed-data";
51
52
  import { claimedCouponsSeedData } from "./claimed-coupons-seed-data";
@@ -193,6 +194,10 @@ export const SEED_MANIFEST = {
193
194
  ...f,
194
195
  name: f.label ?? f.id,
195
196
  }))),
197
+ taxCodes: pick(asArr(taxCodesSeedData).map((t) => ({
198
+ ...t,
199
+ name: t.label ?? t.id,
200
+ }))),
196
201
  offers: pick(asArr(offersSeedData).map((o) => ({
197
202
  ...o,
198
203
  name: o.productTitle ?? o.id,
@@ -67,9 +67,11 @@ const daysAgo = (n) => new Date(NOW.getTime() - n * 86400000);
67
67
  * authored against one day's ids and could never resolve afterwards.
68
68
  */
69
69
  const SEED_EPOCH = new Date("2026-01-01T00:00:00.000Z");
70
- // Deterministic per-product thumbnail — picsum.photos returns a stable image
71
- // for any seed string, so this doesn't need to match the real product seed's
72
- // own image, just be present and consistent across reseeds. Backfills the
70
+ // Deterministic per-product thumbnail — `seedPhoto` maps a seed string to one
71
+ // of six LOCAL tiles, so this doesn't need to match the real product seed's
72
+ // own image, just be present and consistent across reseeds. (It used to name
73
+ // picsum.photos here; seeded imagery stopped being a third-party fetch on
74
+ // 2026-10-09 — see seedPhoto's header.) Backfills the
73
75
  // `image`/`imageUrls` fields real checkout orders only started carrying
74
76
  // 2026-08-20 (see OrderDocumentItem.image), so seeded order fixtures show a
75
77
  // thumbnail on My Orders / order-detail like real orders do.
@@ -1,10 +1,3 @@
1
- /**
2
- * Product Features Seed Data
3
- *
4
- * 10 platform-scope feature flags available to every store. Store-scope custom
5
- * features are not seeded — sellers create their own via /store/[slug]/features.
6
- *
7
- * id === slug, prefix: feature-
8
- */
9
1
  import type { ProductFeatureDocument } from "../features/products/schemas/product-features";
10
2
  export declare const productFeaturesSeedData: ProductFeatureDocument[];
3
+ export declare const PRODUCT_FEATURE_COUNT: number;