@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
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Zod validators for the `/api/admin/tax-codes` route handlers.
3
+ *
4
+ * Separate from `tax-code-form.ts`, which is the EDITOR's schema: that one is
5
+ * annotated for `buildSectionsFromSchema`, takes strings from inputs, and
6
+ * coerces. These are the wire contracts, and they are `.strict()`.
7
+ *
8
+ * ## 🛑 `.strict()`, not `z.object()` and not `.passthrough()`
9
+ *
10
+ * `z.object()` STRIPS unknown keys, which is how a PATCH returns 200 having
11
+ * written nothing (Root Cause #40's shape, and the admin grouped-listings
12
+ * route's documented bug). `.passthrough()` writes whatever arrives, which is
13
+ * how a form overwrote booked lottery slots. `.strict()` 400s on a field the
14
+ * contract does not name — the caller is told, and nothing silently vanishes.
15
+ *
16
+ * ## The id is NOT accepted on update
17
+ *
18
+ * `createTaxCodeId` derives the id from the HSN code, so accepting an id (or
19
+ * re-deriving one on update) would let an edit orphan every
20
+ * `CategoryProductDefaults.taxCodeId` pointing at the old one — with a GST
21
+ * invoice at the end of that chain. To correct a wrong HSN: deactivate, create
22
+ * the right row, repoint the categories.
23
+ */
24
+ import { z } from "zod";
25
+ import { GST_RATE_VALUES } from "./firestore";
26
+ const LABEL_MAX = 150;
27
+ const DESCRIPTION_MAX = 500;
28
+ const NOTES_MAX = 1000;
29
+ /**
30
+ * 🛑 `z.custom<GstRate>`, not `z.number().refine(...)`.
31
+ *
32
+ * A `.refine()` validates at runtime and does NOT narrow the inferred type —
33
+ * the payload still types as `number`, so `repository.create(body)` fails to
34
+ * compile against `gstRate: GstRate`, and the obvious unblock is a cast. A
35
+ * cast at a request boundary is where this codebase's worst bugs live (an
36
+ * `ActionResult` envelope spread as a product, a raw `StoreDocument` published
37
+ * as HTML), so the type is narrowed here instead.
38
+ *
39
+ * And `z.custom` rather than a hand-written `z.union([z.literal(0), …])`
40
+ * because the slab list then has ONE definition — `GST_RATE_VALUES`, which
41
+ * `ProductDocument.gstRate` and the form's option list also derive from. A
42
+ * literal union here would be a second enumeration of the same union, which is
43
+ * Root Cause #61's shape.
44
+ */
45
+ export const GST_RATE_ENUM = z.custom((v) => typeof v === "number" && GST_RATE_VALUES.includes(v), { message: "gstRate must be one of 0, 5, 12, 18 or 28." });
46
+ export const HSN_CHAPTER_ENUM = z.enum(["9503", "4911", "9504", "exempt"]);
47
+ /**
48
+ * 🛑 `hsnCode` is OPTIONAL here and the blank-only-at-0% rule lives in the
49
+ * repository, not this schema. Deliberate: the same rule has to hold for the
50
+ * seed path and any future importer, neither of which goes through a Zod
51
+ * request schema. A rule enforced only at the HTTP edge is a rule with a side
52
+ * door.
53
+ */
54
+ export const taxCodeCreateSchema = z
55
+ .object({
56
+ /*
57
+ * Omitted becomes `""`, not `undefined`, because `TaxCodeDocument.hsnCode`
58
+ * is REQUIRED and the exemption row's value genuinely is the empty string.
59
+ * An optional-into-required field here would force a cast at the one call
60
+ * site, and "no HSN" and "nobody filled this in" would become
61
+ * indistinguishable — exactly the `undefined`-vs-`0` distinction `gstRate`
62
+ * depends on, one field over.
63
+ */
64
+ hsnCode: z.string().trim().max(8).default(""),
65
+ label: z.string().trim().min(1).max(LABEL_MAX),
66
+ description: z.string().max(DESCRIPTION_MAX).optional(),
67
+ gstRate: GST_RATE_ENUM,
68
+ chapter: HSN_CHAPTER_ENUM.optional(),
69
+ effectiveFrom: z.coerce.date().optional(),
70
+ isActive: z.boolean().default(true),
71
+ notes: z.string().max(NOTES_MAX).optional(),
72
+ })
73
+ .strict();
74
+ export const taxCodeUpdateSchema = z
75
+ .object({
76
+ hsnCode: z.string().trim().max(8).optional(),
77
+ label: z.string().trim().min(1).max(LABEL_MAX).optional(),
78
+ description: z.string().max(DESCRIPTION_MAX).optional(),
79
+ gstRate: GST_RATE_ENUM.optional(),
80
+ chapter: HSN_CHAPTER_ENUM.optional(),
81
+ effectiveFrom: z.coerce.date().optional(),
82
+ isActive: z.boolean().optional(),
83
+ notes: z.string().max(NOTES_MAX).optional(),
84
+ })
85
+ .strict();
@@ -1,2 +1 @@
1
1
  export * from "./checklist-item-actions";
2
- export * from "./leaderboard-actions";
@@ -1,2 +1 @@
1
1
  export * from "./checklist-item-actions";
2
- export * from "./leaderboard-actions";
@@ -4,7 +4,7 @@ import { useQuery, useQueryClient } from "@tanstack/react-query";
4
4
  import { Button, Card, Details, Div, Row, Stack, Summary, Text } from "../../../ui";
5
5
  import { MediaImage } from "../../media/MediaImage";
6
6
  import { apiClient } from "../../../http";
7
- import { useApiMutation } from "../../../client";
7
+ import { useApiMutation } from "../../../client/api/useApiMutation";
8
8
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
9
9
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
10
10
  const REPORT_QUERY_KEY = ["admin", "tester-feedback", "report"];
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { useApiMutation } from "../../../client";
3
+ import { useApiMutation } from "../../../client/api/useApiMutation";
4
4
  import { SIEVE_OP, sieveFilter } from "../../../utils/sieve-builder";
5
5
  import { sortBy } from "../../../constants/sort";
6
6
  import { TESTER_CHECKLIST_RESPONSE_FIELDS } from "../schemas/firestore";
@@ -1,5 +1,3 @@
1
- export { TesterHubView } from "./TesterHubView";
2
- export type { TesterHubViewProps } from "./TesterHubView";
3
1
  export { TesterChecklistStepRow } from "./TesterChecklistStepRow";
4
2
  export type { TesterChecklistStepRowProps, TesterChecklistStepItem } from "./TesterChecklistStepRow";
5
3
  export { TesterFeedbackChart } from "./TesterFeedbackChart";
@@ -9,5 +7,3 @@ export { AdminTesterFeedbackReportView } from "./AdminTesterFeedbackReportView";
9
7
  export { AdminTesterFeedbackIssuesView } from "./AdminTesterFeedbackIssuesView";
10
8
  export { AdminTesterFeedbackListView } from "./AdminTesterFeedbackListView";
11
9
  export type { AdminTesterFeedbackListViewProps } from "./AdminTesterFeedbackListView";
12
- export { BugHunterLeaderboardView } from "./BugHunterLeaderboardView";
13
- export type { BugHunterLeaderboardViewProps } from "./BugHunterLeaderboardView";
@@ -1,8 +1,6 @@
1
- export { TesterHubView } from "./TesterHubView";
2
1
  export { TesterChecklistStepRow } from "./TesterChecklistStepRow";
3
2
  export { TesterFeedbackChart } from "./TesterFeedbackChart";
4
3
  export { AdminTesterFeedbackView } from "./AdminTesterFeedbackView";
5
4
  export { AdminTesterFeedbackReportView } from "./AdminTesterFeedbackReportView";
6
5
  export { AdminTesterFeedbackIssuesView } from "./AdminTesterFeedbackIssuesView";
7
6
  export { AdminTesterFeedbackListView } from "./AdminTesterFeedbackListView";
8
- export { BugHunterLeaderboardView } from "./BugHunterLeaderboardView";
@@ -1,6 +1,6 @@
1
1
  import { BaseRepository } from "../../../providers/db-firebase";
2
2
  import type { FirebaseSieveFields, FirebaseSieveResult, SieveModel } from "../../../providers/db-firebase";
3
- import { type TesterChecklistItemDocument, type TesterChecklistItemCreateInput, type TesterChecklistItemUpdateInput, type BugHunterLeaderboardEntry } from "../schemas/firestore";
3
+ import { type TesterChecklistItemDocument, type TesterChecklistItemCreateInput, type TesterChecklistItemUpdateInput } from "../schemas/firestore";
4
4
  export declare class TesterChecklistItemRepository extends BaseRepository<TesterChecklistItemDocument> {
5
5
  static readonly SIEVE_FIELDS: FirebaseSieveFields;
6
6
  constructor();
@@ -15,24 +15,5 @@ export declare class TesterChecklistItemRepository extends BaseRepository<Tester
15
15
  /** Reopens a fixed, bug-confirmed case as a new, active version for retest.
16
16
  * The old item stays disabled forever with its bug-hunter credit intact. */
17
17
  reopenAsNewVersion(oldItemId: string): Promise<TesterChecklistItemDocument>;
18
- /**
19
- * Ids of automated (non-human) accounts, excluded from the PUBLIC leaderboard.
20
- *
21
- * Read as a bare collection query rather than through `userRepository` on purpose:
22
- * no repository in this codebase imports another, and this needs a key set, not
23
- * user documents. `.select()` with no fields returns refs only, so the read is as
24
- * cheap as Firestore allows, and `isBot == true` is a single-field equality served
25
- * by the automatic index — no composite index to declare.
26
- */
27
- private botHunterIds;
28
- /** Single-query, in-memory aggregation of bug credits per hunter — mirrors
29
- * EventEntryRepository.getLeaderboard()'s shape. Includes old/disabled/
30
- * superseded items, since bug credit is permanent.
31
- *
32
- * Bot accounts are aggregated out (not merely ranked last): the board exists to
33
- * credit people, and a runner working all 943 cases would otherwise dominate it.
34
- * The credit still lives on the item, so admin triage and the item's own
35
- * `bugHunterName` are unaffected. */
36
- getBugHunterLeaderboard(limit?: number): Promise<BugHunterLeaderboardEntry[]>;
37
18
  }
38
19
  export declare const testerChecklistItemRepository: TesterChecklistItemRepository;
@@ -1,7 +1,6 @@
1
1
  import { BaseRepository, parseSieveDateValue } from "../../../providers/db-firebase";
2
2
  import { buildSearchTxt } from "../../../utils/search-txt";
3
3
  import { DatabaseError } from "../../../errors";
4
- import { USER_COLLECTION } from "../../auth/schemas/firestore";
5
4
  import { TESTER_CHECKLIST_ITEM_COLLECTION, TESTER_CHECKLIST_ITEM_FIELDS, createChecklistItemId, } from "../schemas/firestore";
6
5
  export class TesterChecklistItemRepository extends BaseRepository {
7
6
  constructor() {
@@ -87,57 +86,6 @@ export class TesterChecklistItemRepository extends BaseRepository {
87
86
  await this.update(old.id, { supersededByItemId: newId });
88
87
  return newItem;
89
88
  }
90
- /**
91
- * Ids of automated (non-human) accounts, excluded from the PUBLIC leaderboard.
92
- *
93
- * Read as a bare collection query rather than through `userRepository` on purpose:
94
- * no repository in this codebase imports another, and this needs a key set, not
95
- * user documents. `.select()` with no fields returns refs only, so the read is as
96
- * cheap as Firestore allows, and `isBot == true` is a single-field equality served
97
- * by the automatic index — no composite index to declare.
98
- */
99
- async botHunterIds() {
100
- const snapshot = await this.db
101
- .collection(USER_COLLECTION)
102
- .where("isBot", "==", true)
103
- .select()
104
- .get();
105
- return new Set(snapshot.docs.map((d) => d.id));
106
- }
107
- /** Single-query, in-memory aggregation of bug credits per hunter — mirrors
108
- * EventEntryRepository.getLeaderboard()'s shape. Includes old/disabled/
109
- * superseded items, since bug credit is permanent.
110
- *
111
- * Bot accounts are aggregated out (not merely ranked last): the board exists to
112
- * credit people, and a runner working all 943 cases would otherwise dominate it.
113
- * The credit still lives on the item, so admin triage and the item's own
114
- * `bugHunterName` are unaffected. */
115
- async getBugHunterLeaderboard(limit = 50) {
116
- const [snapshot, botIds] = await Promise.all([
117
- this.db
118
- .collection(this.collection)
119
- .where(TESTER_CHECKLIST_ITEM_FIELDS.BUG_CONFIRMED, "==", true)
120
- .get(),
121
- this.botHunterIds(),
122
- ]);
123
- const byHunter = new Map();
124
- for (const doc of snapshot.docs) {
125
- const item = this.mapDoc(doc);
126
- if (!item.bugHunterId || botIds.has(item.bugHunterId))
127
- continue;
128
- const entry = byHunter.get(item.bugHunterId) ?? {
129
- name: item.bugHunterName ?? "Unknown tester",
130
- count: 0,
131
- };
132
- entry.count += 1;
133
- byHunter.set(item.bugHunterId, entry);
134
- }
135
- return Array.from(byHunter.entries())
136
- .map(([hunterId, v]) => ({ hunterId, hunterName: v.name, bugCount: v.count }))
137
- .sort((a, b) => b.bugCount - a.bugCount)
138
- .slice(0, limit)
139
- .map((entry, index) => ({ ...entry, rank: index + 1 }));
140
- }
141
89
  }
142
90
  TesterChecklistItemRepository.SIEVE_FIELDS = {
143
91
  groupKey: { canFilter: true, canSort: true },
@@ -164,12 +164,6 @@ export declare const testerChecklistItemQueryHelpers: {
164
164
  readonly active: () => readonly ["isActive", "==", true];
165
165
  readonly confirmedBugs: () => readonly ["bugConfirmed", "==", true];
166
166
  };
167
- export interface BugHunterLeaderboardEntry {
168
- rank: number;
169
- hunterId: string;
170
- hunterName: string;
171
- bugCount: number;
172
- }
173
167
  export declare function slugifyChecklistLabel(label: string): string;
174
168
  export declare function createChecklistItemId(groupKey: string, pageKey: string, label: string): string;
175
169
  /**
@@ -64,15 +64,15 @@ export const authored = {
64
64
  startPage: "/admin/categories",
65
65
  steps: [
66
66
  "Sign in as admin@letitrip.in / TempPass123!.",
67
- "Open /categories/category-x-starters as a visitor in a second tab and write down its product count. Note the FULL id — /categories/x-starters serves 'Category Not Found'; every category id carries the category- prefix.",
68
- "In the first tab open /admin/categories and find Starter Sets — that is the display name of category-x-starters; there is no category called 'X Starters'.",
67
+ "Open /categories/category-x-basic as a visitor in a second tab and write down its product count. Note the FULL id — /categories/x-basic serves 'Category Not Found'; every category id carries the category- prefix.",
68
+ "In the first tab open /admin/categories and find Basic Line — that is the display name of category-x-basic; there is no category called 'X Basic'.",
69
69
  "Write down its parent and how many children it has.",
70
70
  "Open its Edit action, change ONLY its description, and press Save.",
71
71
  "Reload the admin list and reopen it.",
72
72
  "Reload the public category page in the second tab.",
73
73
  "Restore the description by removing the word you appended, then save again. Three of the cases on this page append a marker and this one accumulated 'roundtrip' from an earlier run — categories is SEED_OWNED, but a run does not reseed.",
74
74
  ],
75
- inputs: { categorySlug: "x-starters" },
75
+ inputs: { categorySlug: "x-basic" },
76
76
  expectedBehaviour: "A rename or a description edit touches that field alone. The hierarchy fields — parent, children, ancestors, tier — are derived and must never be rewritten from form state, and the product count is derived from a trigger rather than typed.",
77
77
  expectedUiState: "The parent and the child count are unchanged, and the public page shows the same product count as before.",
78
78
  expectedData: { hierarchyChanged: false, countChanged: false },
@@ -576,13 +576,12 @@ export const authored = {
576
576
  "Open /admin/tester-checklist and read the catalogue.",
577
577
  "Create a case with a label, a description, a group, a page, roles, a start page and steps.",
578
578
  "Save, RELOAD, and read every field including roles and steps.",
579
- "Open /user/tester as a tester and find the new case.",
580
- "Check its roles, steps and expectations all render there.",
579
+ "Reopen the catalogue list and find the new case by searching its label.",
581
580
  "Delete the case and confirm it disappears from both surfaces.",
582
581
  ],
583
- expectedBehaviour: "The admin editor accepts every field a case carries, including the roles list, the input values and the expected data — fields added to the document type reach this form too, or the admin can create cases the hub cannot fully display.",
584
- expectedUiState: "After the reload the case holds every field. The Tester Hub shows its roles, steps, both value tables and the expectations. A field the editor accepts but the hub never shows, or the reverse, is the finding.",
585
- endResult: "The case is deleted from both surfaces.",
582
+ expectedBehaviour: "The admin editor accepts every field a case carries, including the roles list, the input values and the expected data — a field added to the document type must reach this form too, or an admin can create a case the harness cannot read.",
583
+ expectedUiState: "After the reload the case holds every field, including roles, steps, both value tables and the expectations. A field the editor accepts but does not read back is the finding.",
584
+ endResult: "The case is deleted from the catalogue.",
586
585
  },
587
586
  "checklist-admin-site-system-tester-feedback-report-export": {
588
587
  roles: ["admin"],
@@ -45,7 +45,7 @@ export const authored = {
45
45
  roles: ["guest"],
46
46
  startPage: "/categories",
47
47
  steps: [
48
- "Open /categories/category-x-tops — a parent whose children are category-x-starters and category-x-boosters — every category id carries the `category-` prefix, and a URL without it does not resolve.",
48
+ "Open /categories/category-x-tops — a parent whose children are the four Beyblade X retail lines, category-x-basic, category-x-unique-ux, category-x-custom-cx and category-x-over — every category id carries the `category-` prefix, and a URL without it does not resolve.",
49
49
  "Write down the count on the parent's tile.",
50
50
  "Open the parent and write down the count shown on each of its child chips.",
51
51
  "Add the children's counts together.",
@@ -74,7 +74,7 @@ export const authored = {
74
74
  roles: ["guest"],
75
75
  startPage: "/categories",
76
76
  steps: [
77
- "Open /categories/category-x-tops, a parent that shows a row of child chips — category-x-starters and category-x-boosters.",
77
+ "Open /categories/category-x-tops, a parent that shows a row of child chips — category-x-basic, category-x-unique-ux, category-x-custom-cx and category-x-over.",
78
78
  "Write down the number in the page header.",
79
79
  "Write down the number on each child chip.",
80
80
  "Open one child and compare its own header number to the number its chip showed.",
@@ -94,7 +94,6 @@ import { authored as a_design_ux__hand_mode_layout } from "./design-ux__hand-mod
94
94
  import { authored as a_design_ux__homepage_carousels } from "./design-ux__homepage-carousels";
95
95
  import { authored as a_page_wiring__data_loss } from "./page-wiring__data-loss";
96
96
  import { authored as a_public_pages__auth_error_pages } from "./public-pages__auth-error-pages";
97
- import { authored as a_public_pages__bug_hunters } from "./public-pages__bug-hunters";
98
97
  import { authored as a_public_pages__core_listing_pages } from "./public-pages__core-listing-pages";
99
98
  import { authored as a_public_pages__help_how_it_works } from "./public-pages__help-how-it-works";
100
99
  import { authored as a_public_pages__legal_policy_pages } from "./public-pages__legal-policy-pages";
@@ -214,7 +213,6 @@ export const AUTHORED_CASES = {
214
213
  ...a_design_ux__homepage_carousels,
215
214
  ...a_page_wiring__data_loss,
216
215
  ...a_public_pages__auth_error_pages,
217
- ...a_public_pages__bug_hunters,
218
216
  ...a_public_pages__core_listing_pages,
219
217
  ...a_public_pages__help_how_it_works,
220
218
  ...a_public_pages__legal_policy_pages,
@@ -112,23 +112,4 @@ export const authored = {
112
112
  expectedData: { brokenLinkCount: 0, linksChecked: 62 },
113
113
  endResult: "Read-only; nothing persists. Record every broken href in the comment, not just the first — one report naming all of them is worth more than a verdict.",
114
114
  },
115
- "checklist-page-wiring-reachability-user-tester-hub-reachable-from-user-sidebar": {
116
- roles: ["admin", "buyer"],
117
- startPage: "/user",
118
- steps: [
119
- "Sign in as admin@letitrip.in / TempPass123!, open /admin/users, and turn the tester flag ON for vivaan.kapoor@gmail.com — no seeded account carries it, so the case sets up the flag it is about.",
120
- "Sign out and sign in as vivaan.kapoor@gmail.com / TempPass123!, which now carries the tester flag.",
121
- "Open /user and read the sidebar.",
122
- "Find the Testing group and click Tester Hub.",
123
- "Read where it lands.",
124
- "Sign out and sign in as rehan.sheikh@gmail.com / TempPass123!, which does not carry the flag.",
125
- "Open /user and read the sidebar for a Testing group.",
126
- "Sign back in as admin@letitrip.in and turn the tester flag on vivaan.kapoor@gmail.com back off.",
127
- ],
128
- inputs: { testerAccount: "vivaan.kapoor@gmail.com", nonTesterAccount: "rehan.sheikh@gmail.com" },
129
- expectedBehaviour: "The Testing group is injected at runtime for accounts carrying the tester flag and is empty for everyone else. An empty group must not render as a heading with nothing under it.",
130
- expectedUiState: "The tester sees a Testing group containing Tester Hub, and clicking it opens /user/tester with the checklist. The non-tester sees no Testing group at all — not a heading with no children, and not a link that leads to a 'Testers only' warning.",
131
- expectedData: { testingGroupVisibleForNonTester: false },
132
- endResult: "The flag is revoked by the final step, leaving vivaan.kapoor@gmail.com on its seeded settings. Checking both accounts is the case — a group that renders for everybody would pass the first half alone.",
133
- },
134
115
  };
@@ -3,8 +3,9 @@
3
3
  * WHAT: Default test cases across 8 groups (Account & Auth, Buying, Selling, Content & Discovery,
4
4
  * Community & Support, Design & UX, Public & Marketing Pages, Admin (Testing)). Admins add/edit
5
5
  * further cases via /admin/tester-checklist — this array is a starting point, not the source of
6
- * truth. Every case is searchable by title or route in the Tester Hub (/user/tester), which any
7
- * isTester account OR admin can open. Items in the "admin" group carry adminOnly:true — only
6
+ * truth. Every case is searchable by title or route at /admin/tester-checklist — the human-facing
7
+ * Tester Hub at /user/tester was deleted in B2, and the Claude tester reads the catalogue
8
+ * through GET /api/user/tester-checklist instead. Items in the "admin" group carry adminOnly:true — only
8
9
  * visible to a tester with canTestAdmin (or a real admin); see `group()`'s `opts.adminOnly`.
9
10
  *
10
11
  * EXPORTS:
@@ -509,8 +510,8 @@ const rawTesterChecklistItems = [
509
510
  },
510
511
  {
511
512
  key: "seed-images-are-labelled-tiles",
512
- label: "Every seeded product image is a readable tile showing the item's own name — NOT a broken-image icon and NOT an empty grey box",
513
- description: "Fixed 2026-08-31. BEFORE: 409 of the ~437 seeded image URLs pointed at picsum.photos, which went down (503 from its origin AND its CDN), so nearly every image on the site returned 502 and rendered as the browser's broken-image icon. AFTER: images come from `seedPhoto()`, which names its host in ONE place and renders the item's name on the tile. Open a product grid and confirm the tiles show text like \"Dranzer Phoenix\" rather than broken icons. A grid of identical blank tiles is also a fail — each should differ.",
513
+ label: "Every seeded product image is a coloured local tile — NOT a broken-image icon, and NOT all the same colour",
514
+ description: "Updated 2026-10-09. BEFORE: seeded images were fetched from a third party through /api/media/ext — one Node lambda plus a sharp re-encode PER IMAGE, 160 of them on the homepage alone. That is what exceeded the Vercel Hobby caps and suspended the site (HTTP 402). AFTER: `seedPhoto()` returns a static local file under `/images/seed-tiles/<hex>.svg`, so a seeded image costs no function and no upstream request. Open a product grid and confirm each card shows a coloured tile with a faint ring motif. Two checks that matter: view-source on a card image and confirm the src starts with `/images/seed-tiles/` and NOT `/api/media/ext`; and confirm the tiles are not all one colour (the colour is hashed per item, so a grid should show several). NOTE: tiles deliberately no longer render the item's NAME — that text cost a function invocation per card to draw, and the card already displays the title beside the image.", // audit-hardcoded-api-routes-ok: prose, not a call site — the tester must be told the exact string to look for in an image src, and "the external-media proxy route" is not checkable
514
515
  href: "/products",
515
516
  },
516
517
  {
@@ -3829,7 +3830,7 @@ const rawTesterChecklistItems = [
3829
3830
  {
3830
3831
  key: "detail-page-tags-readable",
3831
3832
  label: "Opening an individual auction, pre-order, prize draw, classified, digital code and live-item page, each one's type tag and status chips are readable in light mode",
3832
- description: "Card grids and detail pages don't always share the same component, so check both. Use the sandbox listings linked from the Tester Hub if you need one of each type.",
3833
+ description: "Card grids and detail pages don't always share the same component, so check both. Use the seeded listings of each type if you need one of each.",
3833
3834
  href: "/auctions/auction-beyblade-original-dragoon-storm",
3834
3835
  },
3835
3836
  {
@@ -4623,21 +4624,6 @@ const rawTesterChecklistItems = [
4623
4624
  },
4624
4625
  ],
4625
4626
  },
4626
- {
4627
- pageKey: "bug-hunters",
4628
- pageLabel: "Bug Hunters Leaderboard",
4629
- href: "/bug-hunters",
4630
- cases: [
4631
- {
4632
- key: "leaderboard-loads",
4633
- label: "The public Bug Hunters leaderboard (/bug-hunters) loads and lists testers ranked by confirmed-bug count, most bugs first",
4634
- description: "Verify against the seeded demo fixture — \"Mock User 3\" should appear on the leaderboard with 1 confirmed bug (from the \"Demo fixture\" case under Admin (Testing) → Bug Hunter Rewards).",
4635
- href: "/bug-hunters",
4636
- },
4637
- { key: "leaderboard-empty-state", label: "If no bugs have been confirmed yet, the leaderboard shows a clear \"No confirmed bugs yet\" empty state instead of a blank page or error" },
4638
- { key: "leaderboard-footer-link", label: "A \"Bug Hunters\" link is present in the site footer's Support column and navigates to /bug-hunters" },
4639
- ],
4640
- },
4641
4627
  ]),
4642
4628
  ...group("seo", "SEO & Metadata", [
4643
4629
  {
@@ -5630,7 +5616,7 @@ const rawTesterChecklistItems = [
5630
5616
  {
5631
5617
  key: "confirm-bug",
5632
5618
  label: "Admin can mark a tester's \"No\" answer as a confirmed bug from the Main Issues tab (or the All Submissions tab) — the reporting tester is credited as the bug hunter and the case is disabled so no other tester can answer it",
5633
- description: "From /admin/tester-feedback → Main Issues, click \"Mark as Bug\" on any open issue. Confirm: (1) the confirmation dialog appears before it commits, (2) the issue's card now shows a \"🐛 Confirmed — credited to [tester name]\" badge, (3) re-opening the Tester Hub as any other tester no longer shows that case at all.",
5619
+ description: "From /admin/tester-feedback → Main Issues, click \"Mark as Bug\" on any open issue. Confirm: (1) the confirmation dialog appears before it commits, (2) the issue's card now shows a \"🐛 Confirmed — credited to [tester name]\" badge, (3) the case no longer appears for any other tester in GET /api/user/tester-checklist.",
5634
5620
  href: "/admin/tester-feedback",
5635
5621
  },
5636
5622
  {
@@ -5640,7 +5626,7 @@ const rawTesterChecklistItems = [
5640
5626
  {
5641
5627
  key: "reopen-case",
5642
5628
  label: "Admin can reopen a bug-confirmed case as a new version for retest — the new version is active and answerable again, while the old case stays disabled in the catalog with its bug-hunter credit intact",
5643
- description: "Verify against the seeded \"Demo fixture — reported bug, already confirmed and reopened\" pair under this page: the v1 case should show Status \"Bug Confirmed\" and be hidden from the catalog's default (Active-only) view, while its v2 case shows Status \"Active\" and is answerable from the Tester Hub. From /admin/tester-checklist, switch the Status filter to \"Inactive\" or \"Bug status → Bug Confirmed\" to find v1, then use its \"Reopen as New Test Case\" row action on any other bug-confirmed case to try the flow live.",
5629
+ description: "Verify against the seeded \"Demo fixture — reported bug, already confirmed and reopened\" pair under this page: the v1 case should show Status \"Bug Confirmed\" and be hidden from the catalog's default (Active-only) view, while its v2 case shows Status \"Active\" and is answerable. From /admin/tester-checklist, switch the Status filter to \"Inactive\" or \"Bug status → Bug Confirmed\" to find v1, then use its \"Reopen as New Test Case\" row action on any other bug-confirmed case to try the flow live.",
5644
5630
  href: "/admin/tester-checklist",
5645
5631
  },
5646
5632
  {
@@ -5994,7 +5980,8 @@ const rawTesterChecklistItems = [
5994
5980
  // (bugConfirmed/bugHunterId/version/previousVersionId/supersededByItemId
5995
5981
  // are not part of the CaseInput shape group() builds). Lets an admin/
5996
5982
  // tester see the full state machine immediately after a fresh reseed,
5997
- // and gives the /bug-hunters leaderboard a non-empty first entry.
5983
+ // The /bug-hunters leaderboard this also fed was deleted in B2; the pair
5984
+ // stays because /admin/tester-feedback reads the same credit fields.
5998
5985
  {
5999
5986
  id: "checklist-admin-bug-hunter-rewards-demo-fixture",
6000
5987
  groupKey: "admin",
@@ -6133,12 +6120,6 @@ const rawTesterChecklistItems = [
6133
6120
  description: "Walk the public header nav, the sidebar support links and every footer column. All 55 hrefs must land on a real page. No audit checked ANY of them until this wave — the nav audit only ever looked at the three portal sidebars.",
6134
6121
  href: "/",
6135
6122
  },
6136
- {
6137
- key: "user-tester-hub-reachable-from-user-sidebar",
6138
- label: "A tester reaches the Tester Hub from their OWN sidebar",
6139
- description: "As a user with the tester flag, open /user and find Tester Hub in the sidebar under Testing. The group is injected at runtime and is empty for non-testers — confirm a NON-tester account does not see it.",
6140
- href: "/user",
6141
- },
6142
6123
  ],
6143
6124
  },
6144
6125
  ]),
package/dist/index.d.ts CHANGED
@@ -546,9 +546,14 @@ export { ELIGIBLE_ORDER_STATUSES_FOR_TICKET, SUPPORT_TICKET_COLLECTION, ACTIVE_T
546
546
  export { supportTicketsSeedData } from "./seed/index";
547
547
  export { offersSeedData } from "./seed/index";
548
548
  export { payoutMethodsSeedData, shippingConfigsSeedData, analyticsCardsSeedData, analyticsAlertsSeedData, storeCategoriesSeedData, listingTemplatesSeedData, moderationQueueSeedData, reportsSeedData, itemRequestsSeedData, storeWhatsAppConfigSeedData, storeGoogleConfigSeedData, } from "./seed/index";
549
+ export { AdminTaxCodesView } from "./features/admin/components/AdminTaxCodesView";
550
+ export type { AdminTaxCodesViewProps } from "./features/admin/components/AdminTaxCodesView";
551
+ export { AdminTaxCodeEditorView } from "./features/admin/components/AdminTaxCodeEditorView";
552
+ export type { AdminTaxCodeEditorViewProps } from "./features/admin/components/AdminTaxCodeEditorView";
549
553
  export { productFeaturesRepository } from "./repositories/index";
550
554
  export type { ProductFeatureListFilter } from "./repositories/index";
551
555
  export { loadProductFeaturesForStore } from "./repositories/index";
556
+ export { taxCodesRepository } from "./repositories/index";
552
557
  export { productTemplateRepository } from "./repositories/index";
553
558
  export type { ProductTemplateDocument, ProductTemplateCreateInput, ProductTemplateUpdateInput, } from "./repositories/index";
554
559
  export { tokenRepository } from "./repositories/index";
@@ -1032,11 +1037,7 @@ export { AdminTesterChecklistView } from "./features/admin/index";
1032
1037
  export type { AdminTesterChecklistViewProps } from "./features/admin/index";
1033
1038
  export { AdminTesterChecklistItemEditorView } from "./features/admin/index";
1034
1039
  export type { AdminTesterChecklistItemEditorViewProps } from "./features/admin/index";
1035
- export { TesterHubView } from "./features/tester/index";
1036
- export type { TesterHubViewProps } from "./features/tester/index";
1037
1040
  export { AdminTesterFeedbackView } from "./features/tester/index";
1038
- export { BugHunterLeaderboardView } from "./features/tester/index";
1039
- export type { BugHunterLeaderboardViewProps } from "./features/tester/index";
1040
1041
  export { AdminNavEditorView } from "./features/admin/index";
1041
1042
  export type { AdminNavEditorViewProps, NavItemData } from "./features/admin/index";
1042
1043
  export { AdminNewsletterView } from "./features/admin/index";
@@ -1555,6 +1556,7 @@ export { POST } from "./features/categories/server";
1555
1556
  export { categoriesGET } from "./features/categories/server";
1556
1557
  export { categoryItemDELETE } from "./features/categories/server";
1557
1558
  export { categoryItemGET } from "./features/categories/server";
1559
+ export { categoryDescriptionTemplateGET } from "./features/categories/server";
1558
1560
  export { categoryItemPATCH } from "./features/categories/server";
1559
1561
  export { createCategory } from "./features/categories/server";
1560
1562
  export { deleteCategory } from "./features/categories/server";
@@ -1767,7 +1769,6 @@ export { getEventLeaderboard } from "./features/events/server";
1767
1769
  export { getEventPollResults } from "./features/events/server";
1768
1770
  export { getEventSpinResults } from "./features/events/server";
1769
1771
  export { getUserSpinResultsForEvent } from "./features/events/server";
1770
- export { getBugHunterLeaderboard } from "./features/tester/server";
1771
1772
  export { getPublicEventById } from "./features/events/server";
1772
1773
  export { listPublicEvents } from "./features/events/server";
1773
1774
  export { getRelatedEvents } from "./features/events/server";
@@ -1792,7 +1793,6 @@ export type { TesterChecklistItemDocument } from "./features/tester/index";
1792
1793
  export type { TesterChecklistResponseDocument } from "./features/tester/index";
1793
1794
  export type { TesterAnswer } from "./features/tester/index";
1794
1795
  export type { TesterFeedbackStatus } from "./features/tester/index";
1795
- export type { BugHunterLeaderboardEntry } from "./features/tester/index";
1796
1796
  export { FAQS_PUBLIC_FIELDS } from "./features/faq/index";
1797
1797
  export { FAQSortDropdown } from "./features/faq/index";
1798
1798
  export { FAQ_CATEGORY_LABELS } from "./features/faq/index";
@@ -2370,6 +2370,8 @@ export { checkEmiEligibility, computeEmiSchedule, computeBuyerEmiQuote } from ".
2370
2370
  export type { BuyerEmiQuote } from "./_internal/shared/features/emi/schedule";
2371
2371
  export { toBuyerFacingFees, toBuyerEmiSettings, } from "./_internal/shared/features/site-settings/fees";
2372
2372
  export type { BuyerFacingFees, BuyerEmiSettings, } from "./_internal/shared/features/site-settings/fees";
2373
+ export { GSTIN_PATTERN, gstinCheckCharacter, isValidGstin, validateGstEnablement, canEnableGst, } from "./_internal/shared/features/site-settings/gst-registration";
2374
+ export type { GstEnablementInput, GstEnablementProblems, } from "./_internal/shared/features/site-settings/gst-registration";
2373
2375
  export type { EmiSettings, EmiIneligibleReason, EmiEligibility, EmiInstallmentPlan, EmiScheduleResult, } from "./_internal/shared/features/emi/schedule";
2374
2376
  export { isAdminUser, isSellerUser, isModeratorUser, isEmployeeUser, isBuyerUser, isEffectiveAdminUser, isTesterUser, canTestAdminSurfaces, isStrictSellerUser, isAccountDisabled, } from "./features/auth/role-predicates";
2375
2377
  export { sanitizeProductForPublic, sanitizeProductsForPublic } from "./features/products/index";
@@ -3023,7 +3025,14 @@ export { resolveMediaUrl, resolveVideoUrl, FIREBASE_STORAGE_HOST, GCS_HOST, isSt
3023
3025
  export { generateFAQId } from "./utils/id-generators";
3024
3026
  export type { GenerateFAQIdInput } from "./utils/id-generators";
3025
3027
  export { generateCroppedImageFilename } from "./utils/id-generators";
3026
- export { PRODUCT_FEATURES_COLLECTION, PRODUCT_FEATURE_PREFIX, MAX_STORE_CUSTOM_FEATURES, MAX_FEATURES_PER_PRODUCT, PRODUCT_FEATURE_SIEVE_FIELDS, isFeatureIconPath, } from "./features/products/schemas/product-features";
3028
+ export { PRODUCT_FEATURES_COLLECTION, PRODUCT_FEATURE_PREFIX, MAX_STORE_CUSTOM_FEATURES, MAX_FEATURES_PER_PRODUCT, PRODUCT_FEATURE_SIEVE_FIELDS, FEATURE_GROUP_VALUES, FEATURE_GROUP_LABEL, isFeatureIconPath, } from "./features/products/schemas/product-features";
3029
+ export type { FeatureGroup } from "./features/products/schemas/product-features";
3030
+ export { TAX_CODES_COLLECTION, TAX_CODE_PREFIX, TAX_CODE_FIELDS, TAX_CODE_SIEVE_FIELDS, TAX_CODE_UPDATABLE_FIELDS, GST_RATE_VALUES, createTaxCodeId, isValidHsnCode, } from "./features/tax-codes/schemas/firestore";
3031
+ export type { TaxCodeDocument, TaxCodeCreateInput, TaxCodeUpdateInput, GstRate, HsnChapter, } from "./features/tax-codes/schemas/firestore";
3032
+ export { taxCodeFormSchema, GST_RATE_OPTIONS, HSN_CHAPTER_OPTIONS } from "./features/tax-codes/schemas/tax-code-form";
3033
+ export type { TaxCodeFormValues } from "./features/tax-codes/schemas/tax-code-form";
3034
+ export { taxCodeCreateSchema, taxCodeUpdateSchema, } from "./features/tax-codes/schemas/tax-codes.validators";
3035
+ export type { TaxCodeCreatePayload, TaxCodeUpdatePayload, } from "./features/tax-codes/schemas/tax-codes.validators";
3027
3036
  export type { ProductFeatureDocument, ProductFeatureCreateInput, ProductFeatureUpdateInput, ProductFeatureScope, ProductFeatureCategory, ProductFeatureProductType, ProductFeatureIcon, } from "./features/products/schemas/product-features";
3028
3037
  export { productFeatureAdminCreateSchema, productFeatureStoreCreateSchema, productFeatureUpdateSchema, PRODUCT_FEATURE_PRODUCT_TYPE_ENUM, PRODUCT_FEATURE_CATEGORY_ENUM, PRODUCT_FEATURE_SCOPE_ENUM, } from "./features/products/schemas/product-features.validators";
3029
3038
  export type { ProductFeatureAdminCreatePayload, ProductFeatureStoreCreatePayload, ProductFeatureUpdatePayload, } from "./features/products/schemas/product-features.validators";
@@ -3053,6 +3062,7 @@ export { navItemFormSchema, navItemCreateSchema, navItemUpdateSchema, type NavIt
3053
3062
  export { groupedListingFormSchema, groupedListingCreateSchema, groupedListingUpdateSchema, type GroupedListingFormValues, } from "./features/grouped/schemas/grouped-listing-form";
3054
3063
  export { scammersSeedData } from "./seed/index";
3055
3064
  export { productFeaturesSeedData } from "./seed/index";
3065
+ export { taxCodesSeedData } from "./seed/index";
3056
3066
  export { SCAMMER_COLLECTION, SCAMMER_ID_PREFIX, SCAMMER_MATCH_FIELDS, SCAMMER_INDEXED_FIELDS, SCAMMER_FIELDS, SCAMMER_INCIDENTS_SUBCOLLECTION, SCAMMER_COMMENTS_SUBCOLLECTION, SCAMMER_CONTESTS_SUBCOLLECTION, MAX_COMMENT_BODY_LENGTH, MAX_PENDING_SCAMMER_REPORTS_PER_USER, ScammerStatusValues, ScamPlatformValues, SocialPlatformValues, ContestTypeValues, ContestStatusValues, SCAM_PLATFORM_LABELS, SOCIAL_PLATFORM_LABELS, SCAMMER_STATUS_LABELS, CONTEST_TYPE_LABELS, CONTEST_STATUS_LABELS, DEFAULT_SCAMMER_DATA, DEFAULT_SCAMMER_INCIDENT_DATA, DEFAULT_SCAMMER_COMMENT_DATA, DEFAULT_SCAMMER_CONTEST_DATA, } from "./features/scams/schemas/firestore";
3057
3067
  export type { ScammerStatus, ScamPlatform, SocialPlatform, ContestType, ContestStatus, ScammerMatchField, ScammerMatchStrength, ScammerSocialMedia, ScammerDocument, ScammerIncidentDocument, ScammerCommentDocument, ScammerContestDocument, ScammerSuggestion, ScammerCreateInput, ScammerAdminUpdateInput, ScammerIncidentCreateInput, ScammerCommentCreateInput, ScammerContestCreateInput, } from "./features/scams/schemas/firestore";
3058
3068
  export { SCAM_TYPES, SCAM_CATEGORIES, SCAM_TYPE_LABELS, SCAM_CATEGORY_LABELS, getScamType, getScamTypesByCategory, getCategoryForScamType, } from "./features/scams/constants/scam-types";
@@ -3073,6 +3083,10 @@ export { SellerProductShell } from "./features/seller/components/SellerProductSh
3073
3083
  export type { SellerProductShellProps, SellerProductDraft, ProductListingMode } from "./features/seller/components/SellerProductShell";
3074
3084
  export { CategoryInlineSelect } from "./features/seller/components/CategoryInlineSelect";
3075
3085
  export type { CategoryInlineSelectProps } from "./features/seller/components/CategoryInlineSelect";
3086
+ export { ALERT_METRIC_VALUES, ALERT_METRICS, isAlertMetric, alertMetricsForScope, LOW_STOCK_THRESHOLD, } from "./features/store-extensions/constants/alert-metrics";
3087
+ export type { AlertMetric, AlertMetricDef, AlertMetricScope, AlertMetricUnit, } from "./features/store-extensions/constants/alert-metrics";
3088
+ export { CategoryTemplatePicker, variantForCondition } from "./features/categories/components/CategoryTemplatePicker";
3089
+ export type { CategoryTemplatePickerProps, CategoryTemplateApply } from "./features/categories/components/CategoryTemplatePicker";
3076
3090
  export { BrandInlineSelect } from "./features/seller/components/BrandInlineSelect";
3077
3091
  export type { BrandInlineSelectProps } from "./features/seller/components/BrandInlineSelect";
3078
3092
  export { SublistingInlineSelect } from "./features/seller/components/SublistingInlineSelect";