@mohasinac/appkit 4.53.1 → 4.54.0-next.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 (220) hide show
  1. package/dist/.build-stamp.json +5 -5
  2. package/dist/_internal/client/theme/ThemeProvider.js +15 -1
  3. package/dist/_internal/server/features/auth/capabilities.js +7 -5
  4. package/dist/_internal/server/features/categories/price-guidance-resolve.d.ts +66 -0
  5. package/dist/_internal/server/features/categories/price-guidance-resolve.js +138 -0
  6. package/dist/_internal/server/features/checkout/supplier-identity.js +28 -6
  7. package/dist/_internal/server/features/price-index/market.d.ts +57 -0
  8. package/dist/_internal/server/features/price-index/market.js +120 -0
  9. package/dist/_internal/server/features/products/list-public.d.ts +12 -0
  10. package/dist/_internal/server/features/products/list-public.js +10 -1
  11. package/dist/_internal/server/features/products/listing-tab-counts.d.ts +25 -1
  12. package/dist/_internal/server/features/products/listing-tab-counts.js +184 -10
  13. package/dist/_internal/server/features/search/index-build/sources.js +43 -2
  14. package/dist/_internal/server/features/stores/tabs.d.ts +7 -2
  15. package/dist/_internal/server/features/stores/tabs.js +5 -3
  16. package/dist/_internal/server/jobs/core/jobRunners.js +0 -10
  17. package/dist/_internal/server/jobs/core/onOrderCreate.js +10 -104
  18. package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
  19. package/dist/_internal/shared/actions/action-registry.js +128 -0
  20. package/dist/_internal/shared/features/categories/bundle-copy.d.ts +1 -1
  21. package/dist/_internal/shared/features/site-settings/supplier-of-record.d.ts +56 -0
  22. package/dist/_internal/shared/features/site-settings/supplier-of-record.js +57 -0
  23. package/dist/_internal/shared/listing-types/tiers.d.ts +94 -0
  24. package/dist/_internal/shared/listing-types/tiers.js +150 -0
  25. package/dist/_internal/shared/search/match.js +28 -2
  26. package/dist/cli/index.js +0 -2
  27. package/dist/client.d.ts +21 -2
  28. package/dist/client.js +23 -4
  29. package/dist/constants/api-endpoints.d.ts +28 -0
  30. package/dist/constants/api-endpoints.js +14 -0
  31. package/dist/features/account/components/UserOrdersView.js +26 -7
  32. package/dist/features/addresses/utils/postal-autofill.d.ts +39 -0
  33. package/dist/features/addresses/utils/postal-autofill.js +54 -0
  34. package/dist/features/admin/components/AdminStoreEditorView.js +73 -34
  35. package/dist/features/admin/components/OwnerQuickActions.d.ts +29 -0
  36. package/dist/features/admin/components/OwnerQuickActions.js +142 -0
  37. package/dist/features/admin/schemas/admin-editor-forms.d.ts +1 -1
  38. package/dist/features/admin/schemas/admin-editor-forms.js +4 -1
  39. package/dist/features/auctions/components/AuctionDetailPageView.js +8 -7
  40. package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +11 -1
  41. package/dist/features/auctions/components/MarketplaceAuctionCard.js +9 -2
  42. package/dist/features/auth/permissions/constants.d.ts +29 -2
  43. package/dist/features/auth/permissions/constants.js +68 -1
  44. package/dist/features/blog/components/BlogFeaturedCard.d.ts +11 -1
  45. package/dist/features/blog/components/BlogFeaturedCard.js +9 -2
  46. package/dist/features/cart/components/CartDrawer.js +3 -2
  47. package/dist/features/cart/components/CartGroupLineRow.js +2 -1
  48. package/dist/features/cart/hooks/useAddToCart.js +10 -5
  49. package/dist/features/cart/utils/pending-ops.d.ts +11 -1
  50. package/dist/features/cart/utils/pending-ops.js +14 -2
  51. package/dist/features/categories/api/[id]/price-guidance/route.js +1 -24
  52. package/dist/features/categories/components/BrandDetailPageView.js +15 -6
  53. package/dist/features/categories/components/BrandDetailTabs.d.ts +7 -1
  54. package/dist/features/categories/components/BrandDetailTabs.js +18 -3
  55. package/dist/features/categories/components/BundleCollage.js +3 -2
  56. package/dist/features/categories/components/BundleItemsPicker.js +3 -4
  57. package/dist/features/categories/components/CategoryDetailPageView.js +19 -8
  58. package/dist/features/categories/components/CategoryDetailTabs.d.ts +7 -1
  59. package/dist/features/categories/components/CategoryDetailTabs.js +29 -7
  60. package/dist/features/categories/components/CategoryGrid.d.ts +11 -1
  61. package/dist/features/categories/components/CategoryGrid.js +9 -2
  62. package/dist/features/checkout/actions/checkout-value-otp-actions.d.ts +10 -5
  63. package/dist/features/checkout/actions/checkout-value-otp-actions.js +2 -88
  64. package/dist/features/classified/components/ClassifiedDetailPageView.js +10 -1
  65. package/dist/features/digital-codes/components/DigitalCodeDetailPageView.js +10 -1
  66. package/dist/features/events/components/EventCard.d.ts +11 -1
  67. package/dist/features/events/components/EventCard.js +9 -2
  68. package/dist/features/layout/AppLayoutShell.js +2 -1
  69. package/dist/features/layout/BottomActions.d.ts +1 -0
  70. package/dist/features/layout/BottomActions.js +330 -0
  71. package/dist/features/layout/BottomChrome.d.ts +45 -0
  72. package/dist/features/layout/BottomChrome.js +5 -17
  73. package/dist/features/layout/SideActionDock.js +36 -13
  74. package/dist/features/layout/index.d.ts +2 -7
  75. package/dist/features/layout/index.js +7 -7
  76. package/dist/features/layout/useIsDesktop.d.ts +36 -0
  77. package/dist/features/layout/useIsDesktop.js +48 -0
  78. package/dist/features/live/components/LiveItemDetailPageView.js +10 -1
  79. package/dist/features/media/messages/en.json +67 -67
  80. package/dist/features/orders/components/YourPurchaseStrip.d.ts +24 -0
  81. package/dist/features/orders/components/YourPurchaseStrip.js +77 -0
  82. package/dist/features/orders/components/index.d.ts +2 -1
  83. package/dist/features/orders/components/index.js +1 -1
  84. package/dist/features/orders/utils/order-announcement-message.d.ts +18 -0
  85. package/dist/features/orders/utils/order-announcement-message.js +16 -0
  86. package/dist/features/orders/utils/payment-proof-message.d.ts +20 -0
  87. package/dist/features/orders/utils/payment-proof-message.js +17 -0
  88. package/dist/features/parts/schemas/firestore.d.ts +227 -0
  89. package/dist/features/parts/schemas/firestore.js +6 -6
  90. package/dist/features/pre-orders/components/MarketplacePreorderCard.d.ts +11 -1
  91. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +10 -3
  92. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +8 -7
  93. package/dist/features/price-index/components/PriceIndexToolView.d.ts +21 -0
  94. package/dist/features/price-index/components/PriceIndexToolView.js +230 -27
  95. package/dist/features/price-index/lookup-target.d.ts +48 -0
  96. package/dist/features/price-index/lookup-target.js +107 -0
  97. package/dist/features/products/api/[id]/route.js +8 -1
  98. package/dist/features/products/api/route.js +16 -4
  99. package/dist/features/products/components/AvailabilityScopeHint.d.ts +22 -0
  100. package/dist/features/products/components/AvailabilityScopeHint.js +27 -0
  101. package/dist/features/products/components/CompareOverlay.d.ts +2 -1
  102. package/dist/features/products/components/CompareOverlay.js +2 -1
  103. package/dist/features/products/components/GroupSettingsPanel.js +2 -1
  104. package/dist/features/products/components/InteractiveProductCard.d.ts +7 -1
  105. package/dist/features/products/components/InteractiveProductCard.js +16 -4
  106. package/dist/features/products/components/MarketplaceBundleCard.d.ts +11 -1
  107. package/dist/features/products/components/MarketplaceBundleCard.js +9 -2
  108. package/dist/features/products/components/MarketplacePrizeDrawCard.d.ts +11 -1
  109. package/dist/features/products/components/MarketplacePrizeDrawCard.js +9 -2
  110. package/dist/features/products/components/ProductDetailPageView.js +34 -4
  111. package/dist/features/products/components/ProductGrid.d.ts +14 -1
  112. package/dist/features/products/components/ProductGrid.js +22 -5
  113. package/dist/features/products/components/ProductsIndexListing.js +2 -2
  114. package/dist/features/products/components/SublistingCarouselSection.js +2 -1
  115. package/dist/features/products/repository/products.repository.d.ts +1 -0
  116. package/dist/features/products/repository/products.repository.js +5 -1
  117. package/dist/features/products/utils/group-member-image.d.ts +9 -2
  118. package/dist/features/products/utils/group-member-image.js +2 -1
  119. package/dist/features/reviews/api/[id]/route.js +83 -23
  120. package/dist/features/reviews/components/PurchaseReviewAffordance.d.ts +6 -0
  121. package/dist/features/reviews/components/PurchaseReviewAffordance.js +42 -0
  122. package/dist/features/reviews/components/ReviewFormDrawer.d.ts +34 -0
  123. package/dist/features/reviews/components/ReviewFormDrawer.js +127 -0
  124. package/dist/features/reviews/components/index.d.ts +4 -0
  125. package/dist/features/reviews/components/index.js +2 -0
  126. package/dist/features/seller/actions/seller-actions.d.ts +1 -1
  127. package/dist/features/seller/actions/seller-actions.js +49 -3
  128. package/dist/features/seller/components/SellerPayoutSettingsView.js +30 -2
  129. package/dist/features/seller/components/SellerProductShell.d.ts +17 -1
  130. package/dist/features/seller/components/SellerProductsView.js +3 -2
  131. package/dist/features/seller/hooks/useStoreListingEntitlements.d.ts +8 -0
  132. package/dist/features/seller/hooks/useStoreListingEntitlements.js +70 -0
  133. package/dist/features/stores/components/InteractiveStoreCard.d.ts +11 -1
  134. package/dist/features/stores/components/InteractiveStoreCard.js +9 -2
  135. package/dist/features/stores/components/StoreAuctionsListing.js +2 -1
  136. package/dist/features/stores/components/index.d.ts +0 -2
  137. package/dist/features/stores/components/index.js +0 -1
  138. package/dist/features/stores/schemas/index.d.ts +1 -1
  139. package/dist/features/stores/schemas/index.js +10 -1
  140. package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.js +114 -2
  141. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +415 -0
  142. package/dist/index.d.ts +8 -27
  143. package/dist/index.js +14 -35
  144. package/dist/next/routing/route-map.d.ts +2 -0
  145. package/dist/next/routing/route-map.js +9 -0
  146. package/dist/providers/shipping-shiprocket/index.d.ts +98 -0
  147. package/dist/providers/shipping-shiprocket/index.js +353 -0
  148. package/dist/schemas/registry.d.ts +2 -2
  149. package/dist/security/csp.d.ts +16 -1
  150. package/dist/security/csp.js +5 -3
  151. package/dist/seed/_helpers/category-forest.js +27 -0
  152. package/dist/seed/_helpers/category-parts-glossary-map.js +1816 -86
  153. package/dist/seed/_helpers/category-parts.d.ts +1 -1
  154. package/dist/seed/_helpers/category-parts.js +13412 -3020
  155. package/dist/seed/categories-seed-data.js +48 -6
  156. package/dist/seed/homepage-sections-seed-data.js +41 -28
  157. package/dist/seed/model-composition-seed-data.js +6 -8
  158. package/dist/seed/part-glossary/chunk0.d.ts +9 -0
  159. package/dist/seed/part-glossary/chunk0.js +35044 -0
  160. package/dist/seed/part-glossary/chunk1.d.ts +9 -0
  161. package/dist/seed/part-glossary/chunk1.js +39955 -0
  162. package/dist/seed/part-glossary/chunk2.d.ts +9 -0
  163. package/dist/seed/part-glossary/chunk2.js +50335 -0
  164. package/dist/seed/part-glossary/chunk3.d.ts +9 -0
  165. package/dist/seed/part-glossary/chunk3.js +52386 -0
  166. package/dist/seed/part-glossary/chunk4.d.ts +9 -0
  167. package/dist/seed/part-glossary/chunk4.js +50549 -0
  168. package/dist/seed/part-glossary-seed-data.d.ts +1 -1
  169. package/dist/seed/part-glossary-seed-data.js +23 -47483
  170. package/dist/seed/products-beyblade-x-seed-data.js +36 -1
  171. package/dist/server.d.ts +6 -8
  172. package/dist/server.js +16 -20
  173. package/dist/styles.css +516 -358
  174. package/dist/tailwind-utilities.css +1 -1
  175. package/dist/tokens/themes/index.d.ts +3 -1
  176. package/dist/tokens/themes/index.js +11 -1
  177. package/dist/tokens/themes/technical-dark.d.ts +30 -0
  178. package/dist/tokens/themes/technical-dark.js +103 -0
  179. package/dist/tokens/themes/technical-light.d.ts +22 -0
  180. package/dist/tokens/themes/technical-light.js +89 -0
  181. package/dist/tokens/tokens.css +155 -0
  182. package/dist/ui/components/GatedPrice.js +30 -3
  183. package/dist/ui/components/GatedPrice.style.css +22 -19
  184. package/dist/ui/components/QuickCreateModal.style.css +78 -78
  185. package/dist/ui/forms/FormShell.style.css +260 -260
  186. package/package.json +1 -1
  187. package/scripts/seed-cli.mjs +133 -27
  188. package/dist/_internal/server/jobs/core/whatsappCatalogImport.d.ts +0 -27
  189. package/dist/_internal/server/jobs/core/whatsappCatalogImport.js +0 -172
  190. package/dist/_internal/server/jobs/core/whatsappNotify.d.ts +0 -35
  191. package/dist/_internal/server/jobs/core/whatsappNotify.js +0 -140
  192. package/dist/features/admin/components/AdminWhatsAppGuideView.d.ts +0 -2
  193. package/dist/features/admin/components/AdminWhatsAppGuideView.js +0 -35
  194. package/dist/features/orders/components/MarketplaceOrderCard.d.ts +0 -36
  195. package/dist/features/orders/components/MarketplaceOrderCard.js +0 -57
  196. package/dist/features/stores/components/StoreWhatsAppGuideView.d.ts +0 -3
  197. package/dist/features/stores/components/StoreWhatsAppGuideView.js +0 -12
  198. package/dist/features/whatsapp-bot/api/send-status/route.d.ts +0 -12
  199. package/dist/features/whatsapp-bot/api/send-status/route.js +0 -38
  200. package/dist/features/whatsapp-bot/api/webhook/route.d.ts +0 -12
  201. package/dist/features/whatsapp-bot/api/webhook/route.js +0 -43
  202. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.d.ts +0 -6
  203. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +0 -270
  204. package/dist/features/whatsapp-bot/components/WhatsAppChatButton.d.ts +0 -9
  205. package/dist/features/whatsapp-bot/components/WhatsAppChatButton.js +0 -7
  206. package/dist/features/whatsapp-bot/components/index.d.ts +0 -3
  207. package/dist/features/whatsapp-bot/components/index.js +0 -2
  208. package/dist/features/whatsapp-bot/helpers/payment-proof-message.d.ts +0 -14
  209. package/dist/features/whatsapp-bot/helpers/payment-proof-message.js +0 -17
  210. package/dist/features/whatsapp-bot/helpers/whatsapp.d.ts +0 -52
  211. package/dist/features/whatsapp-bot/helpers/whatsapp.js +0 -283
  212. package/dist/features/whatsapp-bot/index.d.ts +0 -3
  213. package/dist/features/whatsapp-bot/index.js +0 -3
  214. package/dist/features/whatsapp-bot/manifest.d.ts +0 -2
  215. package/dist/features/whatsapp-bot/manifest.js +0 -13
  216. package/dist/features/whatsapp-bot/messages/en.json +0 -7
  217. package/dist/features/whatsapp-bot/server.d.ts +0 -7
  218. package/dist/features/whatsapp-bot/server.js +0 -7
  219. package/dist/features/whatsapp-bot/types/index.d.ts +0 -126
  220. package/dist/features/whatsapp-bot/types/index.js +0 -1
@@ -72,7 +72,7 @@ export declare const BUNDLE_COPY: {
72
72
  readonly adminEditor: {
73
73
  readonly loading: "Loading bundle…";
74
74
  readonly saveButton: (saving: boolean, isEdit: boolean) => "Save changes" | "Saving…" | "Create bundle";
75
- readonly deleteButton: (deleting: boolean) => "Deleting…" | "Delete bundle";
75
+ readonly deleteButton: (deleting: boolean) => "Delete bundle" | "Deleting…";
76
76
  readonly deleteConfirm: "Delete this bundle? This action cannot be undone.";
77
77
  readonly fields: {
78
78
  readonly nameLabel: "Name *";
@@ -0,0 +1,56 @@
1
+ /**
2
+ * The platform's own supplier-of-record identity, injected once at boot.
3
+ *
4
+ * ── Why this seam exists ──────────────────────────────────────────────────
5
+ *
6
+ * `appkit.config.js → business` is documented as "THE one owner of the
7
+ * business's statutory identity", and it records what it was created to end:
8
+ * the legal name, address, GSTIN and support channels had lived in five places
9
+ * that already disagreed — four different support addresses published, the
10
+ * registered address saying Solapur while the warehouse said Hyderabad.
11
+ *
12
+ * But that file belongs to the CONSUMER, and appkit has no runtime reader for
13
+ * it. `resolveSupplierIdentity` therefore read `siteSettings.gst.*` instead,
14
+ * which quietly made the invoice path a SIXTH owner — and the one that decides
15
+ * what a tax invoice says about who issued it.
16
+ *
17
+ * So the consumer injects it at boot, the same way `configureMarketDefaults`
18
+ * injects currency and locale: one call in `providers.config.ts`, values read
19
+ * from `src/constants/business.ts`, which reads `appkit.config.js`. One owner,
20
+ * one hop.
21
+ *
22
+ * 🛑 This is NOT a cache of site settings and must not become one. Whether to
23
+ * charge GST at all stays `siteSettings.gst.enabled` — an operational switch an
24
+ * admin owns. WHO the supplier is is a fact about the registered entity, is
25
+ * legally required to be published, and belongs in a committed file.
26
+ *
27
+ * @tag domain:site-settings
28
+ * @tag layer:shared
29
+ * @tag access:isomorphic
30
+ * @tag sideEffects:module-state
31
+ */
32
+ export interface PlatformSupplierIdentity {
33
+ gstin?: string;
34
+ legalName?: string;
35
+ /** One line, as it should appear in an invoice header. */
36
+ address?: string;
37
+ }
38
+ /**
39
+ * Register the platform's statutory identity. Call once, at boot.
40
+ *
41
+ * Merges rather than replaces, so a partial call cannot blank a field that was
42
+ * already supplied — the same shape `configureMarketDefaults` uses.
43
+ */
44
+ export declare function configurePlatformSupplier(identity: PlatformSupplierIdentity): void;
45
+ /**
46
+ * The registered identity, or an empty object when nothing was injected.
47
+ *
48
+ * 🛑 Returns `{}` rather than throwing, and the caller must treat a missing
49
+ * GSTIN as "not a tax invoice" — which `resolveSupplierIdentity` already does
50
+ * via `source: "none"`. Throwing here would turn a misconfigured deployment
51
+ * into a failed CHECKOUT, and an order that cannot be placed is worse than an
52
+ * invoice that correctly declines to call itself a tax invoice.
53
+ */
54
+ export declare function getPlatformSupplier(): PlatformSupplierIdentity;
55
+ /** Reset — for tests and for the seed CLI's isolated runs. */
56
+ export declare function resetPlatformSupplier(): void;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * The platform's own supplier-of-record identity, injected once at boot.
3
+ *
4
+ * ── Why this seam exists ──────────────────────────────────────────────────
5
+ *
6
+ * `appkit.config.js → business` is documented as "THE one owner of the
7
+ * business's statutory identity", and it records what it was created to end:
8
+ * the legal name, address, GSTIN and support channels had lived in five places
9
+ * that already disagreed — four different support addresses published, the
10
+ * registered address saying Solapur while the warehouse said Hyderabad.
11
+ *
12
+ * But that file belongs to the CONSUMER, and appkit has no runtime reader for
13
+ * it. `resolveSupplierIdentity` therefore read `siteSettings.gst.*` instead,
14
+ * which quietly made the invoice path a SIXTH owner — and the one that decides
15
+ * what a tax invoice says about who issued it.
16
+ *
17
+ * So the consumer injects it at boot, the same way `configureMarketDefaults`
18
+ * injects currency and locale: one call in `providers.config.ts`, values read
19
+ * from `src/constants/business.ts`, which reads `appkit.config.js`. One owner,
20
+ * one hop.
21
+ *
22
+ * 🛑 This is NOT a cache of site settings and must not become one. Whether to
23
+ * charge GST at all stays `siteSettings.gst.enabled` — an operational switch an
24
+ * admin owns. WHO the supplier is is a fact about the registered entity, is
25
+ * legally required to be published, and belongs in a committed file.
26
+ *
27
+ * @tag domain:site-settings
28
+ * @tag layer:shared
29
+ * @tag access:isomorphic
30
+ * @tag sideEffects:module-state
31
+ */
32
+ let _identity = {};
33
+ /**
34
+ * Register the platform's statutory identity. Call once, at boot.
35
+ *
36
+ * Merges rather than replaces, so a partial call cannot blank a field that was
37
+ * already supplied — the same shape `configureMarketDefaults` uses.
38
+ */
39
+ export function configurePlatformSupplier(identity) {
40
+ _identity = { ..._identity, ...identity };
41
+ }
42
+ /**
43
+ * The registered identity, or an empty object when nothing was injected.
44
+ *
45
+ * 🛑 Returns `{}` rather than throwing, and the caller must treat a missing
46
+ * GSTIN as "not a tax invoice" — which `resolveSupplierIdentity` already does
47
+ * via `source: "none"`. Throwing here would turn a misconfigured deployment
48
+ * into a failed CHECKOUT, and an order that cannot be placed is worse than an
49
+ * invoice that correctly declines to call itself a tax invoice.
50
+ */
51
+ export function getPlatformSupplier() {
52
+ return _identity;
53
+ }
54
+ /** Reset — for tests and for the seed CLI's isolated runs. */
55
+ export function resetPlatformSupplier() {
56
+ _identity = {};
57
+ }
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Which listing types a store may create: the basic/advanced split.
3
+ *
4
+ * ── The rule ──────────────────────────────────────────────────────────────
5
+ *
6
+ * `standard`, `spares` and `auction` are BASIC — every store can use them.
7
+ * The other seven are ADVANCED and need the `advanced_listing_types`
8
+ * capability, because each carries an obligation a new seller has not agreed
9
+ * to yet: a pre-order takes money for stock that does not exist, a prize draw
10
+ * is a regulated promotion, a classified happens off-platform with no escrow,
11
+ * a digital code must be delivered from a pool the seller has to keep stocked,
12
+ * and a live listing is an animal.
13
+ *
14
+ * ── Why a Record and not an array ─────────────────────────────────────────
15
+ *
16
+ * 🛑 `Record<ListingType, ListingTypeTier>`, so adding a member to the union
17
+ * is a COMPILE error here rather than a silent omission that defaults to
18
+ * whichever branch the code happens to fall through to.
19
+ * `features/products/types/index.ts` warns that adding a union member touches
20
+ * 21 named sites of which only 11 are compile-checked; this file is written to
21
+ * be one of the eleven. Root Cause #61.
22
+ *
23
+ * ── Why `capabilities` is `readonly string[]` and not `StoreCapability[]` ──
24
+ *
25
+ * Two reasons, and the first is the honest one: that is what is actually
26
+ * STORED. `storeFirestoreSchema` validates the field as `z.array(z.string())`,
27
+ * so a capability that is not a union member round-trips today and this helper
28
+ * must not pretend otherwise. The second is that it keeps this module free of
29
+ * an import from `features/auth/permissions/constants`, which is the kind of
30
+ * cross-feature edge `audit-import-cycles` exists to watch.
31
+ *
32
+ * A `StoreCapability[]` is assignable to it, so a typed caller loses nothing.
33
+ */
34
+ import type { ListingType } from "../../../features/products/types/index";
35
+ import type { JsonValue } from "../../../schemas/types";
36
+ export type ListingTypeTier = "basic" | "advanced";
37
+ /**
38
+ * The capability that unlocks every advanced type at once.
39
+ *
40
+ * One flag rather than seven, deliberately: the question a seller is actually
41
+ * answering is "do I want the complicated listing kinds", and seven checkboxes
42
+ * invite six of them to be wrong. An admin who needs finer control has the
43
+ * per-type legacy grants below.
44
+ */
45
+ export declare const ADVANCED_LISTING_TYPE_CAPABILITY = "advanced_listing_types";
46
+ export declare const LISTING_TYPE_TIER: Record<ListingType, ListingTypeTier>;
47
+ export declare function isAdvancedListingType(listingType: ListingType): boolean;
48
+ /**
49
+ * Does this capability array carry the advanced-types grant?
50
+ *
51
+ * Exists so no call site has to spell the capability string, and so none has
52
+ * to cast: `capabilities` is `StoreCapability[]` in typed code and
53
+ * `string[]` as stored, and an `.includes()` across that boundary is where an
54
+ * `as never` gets reached for — which silences every other check on the
55
+ * expression, not just the one being worked around.
56
+ */
57
+ export declare function hasAdvancedListingTypes(capabilities: readonly string[] | null | undefined): boolean;
58
+ /** The types every store can use, with no capability at all. */
59
+ export declare const BASIC_LISTING_TYPES: ListingType[];
60
+ export declare const ADVANCED_LISTING_TYPES: ListingType[];
61
+ export interface ListingTypeAccessContext {
62
+ /** Admins and employees bypass the tier entirely. */
63
+ isPrivileged?: boolean;
64
+ /** The store's stored capability array. Absent/empty is treated as none. */
65
+ capabilities?: readonly string[] | null;
66
+ }
67
+ /**
68
+ * May this store create or convert to this listing type?
69
+ *
70
+ * Pure — takes the capability array the caller already holds rather than
71
+ * re-reading the store. Every gate site in the codebase has the store document
72
+ * in scope already, and a helper that fetched would add one Firestore read per
73
+ * product write against Rule #6's round-trip budget.
74
+ */
75
+ export declare function isListingTypeAllowedFor(listingType: ListingType, ctx?: ListingTypeAccessContext): boolean;
76
+ /** Every type this store may use, for building a picker or filtering nav. */
77
+ export declare function listingTypesAllowedFor(ctx?: ListingTypeAccessContext): ListingType[];
78
+ /**
79
+ * Throwing form, for the server-side write paths.
80
+ *
81
+ * 🛑 `listingType` being absent is ALLOWED and must stay that way. Both product
82
+ * schemas declare it optional, and a partial update that touches only `status`
83
+ * or `stockQuantity` carries no type at all — refusing those would break every
84
+ * stock decrement and status flip in the app. The gate's job is to refuse a
85
+ * NAMED advanced type, not to require one.
86
+ *
87
+ * 🛑 On an UPDATE, the caller must additionally compare against the STORED
88
+ * type and skip this when they match — see `sellerUpdateProduct`. Every
89
+ * per-type edit page re-sends its own type literal, so asserting on the
90
+ * submitted value alone locks a seller out of editing listings they already
91
+ * own as soon as the capability is withdrawn. The rule is about creating and
92
+ * converting, not about touching.
93
+ */
94
+ export declare function assertListingTypeAllowed(listingType: JsonValue | undefined, ctx?: ListingTypeAccessContext): void;
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Which listing types a store may create: the basic/advanced split.
3
+ *
4
+ * ── The rule ──────────────────────────────────────────────────────────────
5
+ *
6
+ * `standard`, `spares` and `auction` are BASIC — every store can use them.
7
+ * The other seven are ADVANCED and need the `advanced_listing_types`
8
+ * capability, because each carries an obligation a new seller has not agreed
9
+ * to yet: a pre-order takes money for stock that does not exist, a prize draw
10
+ * is a regulated promotion, a classified happens off-platform with no escrow,
11
+ * a digital code must be delivered from a pool the seller has to keep stocked,
12
+ * and a live listing is an animal.
13
+ *
14
+ * ── Why a Record and not an array ─────────────────────────────────────────
15
+ *
16
+ * 🛑 `Record<ListingType, ListingTypeTier>`, so adding a member to the union
17
+ * is a COMPILE error here rather than a silent omission that defaults to
18
+ * whichever branch the code happens to fall through to.
19
+ * `features/products/types/index.ts` warns that adding a union member touches
20
+ * 21 named sites of which only 11 are compile-checked; this file is written to
21
+ * be one of the eleven. Root Cause #61.
22
+ *
23
+ * ── Why `capabilities` is `readonly string[]` and not `StoreCapability[]` ──
24
+ *
25
+ * Two reasons, and the first is the honest one: that is what is actually
26
+ * STORED. `storeFirestoreSchema` validates the field as `z.array(z.string())`,
27
+ * so a capability that is not a union member round-trips today and this helper
28
+ * must not pretend otherwise. The second is that it keeps this module free of
29
+ * an import from `features/auth/permissions/constants`, which is the kind of
30
+ * cross-feature edge `audit-import-cycles` exists to watch.
31
+ *
32
+ * A `StoreCapability[]` is assignable to it, so a typed caller loses nothing.
33
+ */
34
+ import { AuthorizationError } from "../../../errors/index.js";
35
+ import { ALL_LISTING_TYPES } from "./feature-flags.js";
36
+ /**
37
+ * The capability that unlocks every advanced type at once.
38
+ *
39
+ * One flag rather than seven, deliberately: the question a seller is actually
40
+ * answering is "do I want the complicated listing kinds", and seven checkboxes
41
+ * invite six of them to be wrong. An admin who needs finer control has the
42
+ * per-type legacy grants below.
43
+ */
44
+ export const ADVANCED_LISTING_TYPE_CAPABILITY = "advanced_listing_types";
45
+ export const LISTING_TYPE_TIER = {
46
+ standard: "basic",
47
+ spares: "basic",
48
+ auction: "basic",
49
+ "pre-order": "advanced",
50
+ "prize-draw": "advanced",
51
+ classified: "advanced",
52
+ "digital-code": "advanced",
53
+ live: "advanced",
54
+ art: "advanced",
55
+ stickers: "advanced",
56
+ };
57
+ /**
58
+ * Capabilities that grant ONE advanced type on their own, for stores that were
59
+ * granted it before `advanced_listing_types` existed.
60
+ *
61
+ * 🛑 Load-bearing, not politeness. `host_preorders` is a real capability some
62
+ * live stores already carry; dropping it would silently revoke pre-order
63
+ * access from a seller who had been using it, and a permission that disappears
64
+ * on deploy is indistinguishable from a bug.
65
+ *
66
+ * `host_auctions` deliberately has NO entry: `auction` is basic now, so the
67
+ * check is gone. The capability string stays declared in the union so existing
68
+ * store documents carrying it remain valid — it simply no longer gates
69
+ * anything.
70
+ */
71
+ const LEGACY_PER_TYPE_GRANT = {
72
+ "pre-order": "host_preorders",
73
+ };
74
+ export function isAdvancedListingType(listingType) {
75
+ return LISTING_TYPE_TIER[listingType] === "advanced";
76
+ }
77
+ /**
78
+ * Does this capability array carry the advanced-types grant?
79
+ *
80
+ * Exists so no call site has to spell the capability string, and so none has
81
+ * to cast: `capabilities` is `StoreCapability[]` in typed code and
82
+ * `string[]` as stored, and an `.includes()` across that boundary is where an
83
+ * `as never` gets reached for — which silences every other check on the
84
+ * expression, not just the one being worked around.
85
+ */
86
+ export function hasAdvancedListingTypes(capabilities) {
87
+ return (capabilities ?? []).includes(ADVANCED_LISTING_TYPE_CAPABILITY);
88
+ }
89
+ /** The types every store can use, with no capability at all. */
90
+ export const BASIC_LISTING_TYPES = ALL_LISTING_TYPES.filter((t) => LISTING_TYPE_TIER[t] === "basic");
91
+ export const ADVANCED_LISTING_TYPES = ALL_LISTING_TYPES.filter((t) => LISTING_TYPE_TIER[t] === "advanced");
92
+ /**
93
+ * May this store create or convert to this listing type?
94
+ *
95
+ * Pure — takes the capability array the caller already holds rather than
96
+ * re-reading the store. Every gate site in the codebase has the store document
97
+ * in scope already, and a helper that fetched would add one Firestore read per
98
+ * product write against Rule #6's round-trip budget.
99
+ */
100
+ export function isListingTypeAllowedFor(listingType, ctx = {}) {
101
+ if (ctx.isPrivileged)
102
+ return true;
103
+ if (!isAdvancedListingType(listingType))
104
+ return true;
105
+ const caps = ctx.capabilities ?? [];
106
+ if (caps.includes(ADVANCED_LISTING_TYPE_CAPABILITY))
107
+ return true;
108
+ const legacy = LEGACY_PER_TYPE_GRANT[listingType];
109
+ return legacy ? caps.includes(legacy) : false;
110
+ }
111
+ /** Every type this store may use, for building a picker or filtering nav. */
112
+ export function listingTypesAllowedFor(ctx = {}) {
113
+ return ALL_LISTING_TYPES.filter((t) => isListingTypeAllowedFor(t, ctx));
114
+ }
115
+ /**
116
+ * Throwing form, for the server-side write paths.
117
+ *
118
+ * 🛑 `listingType` being absent is ALLOWED and must stay that way. Both product
119
+ * schemas declare it optional, and a partial update that touches only `status`
120
+ * or `stockQuantity` carries no type at all — refusing those would break every
121
+ * stock decrement and status flip in the app. The gate's job is to refuse a
122
+ * NAMED advanced type, not to require one.
123
+ *
124
+ * 🛑 On an UPDATE, the caller must additionally compare against the STORED
125
+ * type and skip this when they match — see `sellerUpdateProduct`. Every
126
+ * per-type edit page re-sends its own type literal, so asserting on the
127
+ * submitted value alone locks a seller out of editing listings they already
128
+ * own as soon as the capability is withdrawn. The rule is about creating and
129
+ * converting, not about touching.
130
+ */
131
+ export function assertListingTypeAllowed(
132
+ /*
133
+ * `JsonValue | undefined`, not `unknown`. The callers hold
134
+ * `Record<string, JsonValue>` request bodies, so this is the widest type the
135
+ * value can genuinely have — and naming it keeps the narrowing below honest,
136
+ * where `unknown` would let any argument at all through the door and leave
137
+ * the type-level signal at the call site worth nothing
138
+ * (`audit-unknown-leakage`).
139
+ */
140
+ listingType, ctx = {}) {
141
+ if (typeof listingType !== "string")
142
+ return;
143
+ if (!(listingType in LISTING_TYPE_TIER))
144
+ return;
145
+ const typed = listingType;
146
+ if (isListingTypeAllowedFor(typed, ctx))
147
+ return;
148
+ throw new AuthorizationError(`Your store is not approved to create ${typed} listings. ` +
149
+ `Enable advanced listing types in your store settings first.`);
150
+ }
@@ -119,6 +119,30 @@ export function prepareIndex(artifact) {
119
119
  };
120
120
  });
121
121
  }
122
+ /**
123
+ * The shortest term allowed to match MID-WORD.
124
+ *
125
+ * 🛑 This exists because of a reported bug, and the mechanism is worth stating:
126
+ * the substring tier is `flat.includes(term)`, and for a one-character term
127
+ * that is satisfied by almost every record in the artifact. A category's
128
+ * `detail` is its " › "-joined path, so `"g"` matches
129
+ * `"Spinning Tops › Beyblade Original › Dragoon Line"` on the `g` in
130
+ * "Spinning". AND semantics then cannot narrow anything: `"dragoon g"` scored
131
+ * identically to `"dragoon"` and returned every Dragoon in the catalogue —
132
+ * which is the "even if I type dragoon g the results show everything"
133
+ * complaint, and it was never the AND logic's fault.
134
+ *
135
+ * 🛑 It does NOT reintroduce a minimum query length. This module's header is
136
+ * explicit that typing `"d"` and seeing something is what a local index is FOR,
137
+ * and it still does: the EXACT and PREFIX tiers are untouched, so a
138
+ * one-character term still matches any word starting with it. Only the mid-word
139
+ * tier is gated, because one character appearing somewhere inside a string is
140
+ * not evidence of intent.
141
+ *
142
+ * Two rather than three: `"cx"`, `"bu"`, `"gt"` and `"1b"` are real product
143
+ * vocabulary a collector types, and they discriminate.
144
+ */
145
+ const MIN_SUBSTRING_TERM = 2;
122
146
  /** Best match quality for one term against one field. 0 means no match. */
123
147
  function fieldScore(term, words, flat) {
124
148
  if (!flat)
@@ -129,8 +153,10 @@ function fieldScore(term, words, flat) {
129
153
  for (const w of words)
130
154
  if (w.startsWith(term))
131
155
  return S_PREFIX;
132
- // Mid-word. The capability the token index cannot have.
133
- if (flat.includes(term))
156
+ // Mid-word. The capability the token index cannot have — but see
157
+ // MIN_SUBSTRING_TERM: for a single character it is not a capability, it is a
158
+ // match against everything.
159
+ if (term.length >= MIN_SUBSTRING_TERM && flat.includes(term))
134
160
  return S_SUBSTRING;
135
161
  return 0;
136
162
  }
package/dist/cli/index.js CHANGED
@@ -60,7 +60,6 @@ export const FEATURE_SUBPATH_MAP = {
60
60
  loyalty: "@mohasinac/appkit/features/loyalty",
61
61
  collections: "@mohasinac/appkit/features/collections",
62
62
  preorders: "@mohasinac/appkit/features/pre-orders",
63
- "whatsapp-bot": "@mohasinac/appkit/features/whatsapp-bot",
64
63
  };
65
64
  /**
66
65
  * Wraps a Next.js config object. With appkit, only `@mohasinac/appkit` needs to
@@ -112,7 +111,6 @@ const FEATURE_NAMESPACE_MAP = {
112
111
  "before-after": "beforeAfter",
113
112
  loyalty: "loyalty",
114
113
  collections: "collections",
115
- "whatsapp-bot": "whatsappBot",
116
114
  };
117
115
  // Opaque dynamic import — prevents bundlers from statically analysing the path
118
116
  const _dynamicImport = new Function("modulePath", "return import(modulePath)");
package/dist/client.d.ts CHANGED
@@ -213,6 +213,14 @@ export type { ActionRowProps, ActionRowAlign } from "./ui/components/ActionRow";
213
213
  export { Textarea } from "./ui/components/Textarea";
214
214
  export { GlobalError } from "./next/components/GlobalError";
215
215
  export { AppLayoutShell, LocaleSwitcher, useDashboardNav, BottomActionsProvider, useBottomActions, DashboardNavProvider, LayoutClient } from "./features/layout/index";
216
+ /**
217
+ * A page declares its own inline primary CTA so the floating action control
218
+ * stays out of its way until that button has been seen and scrolled past. A
219
+ * page that publishes actions and no anchor gets the control immediately —
220
+ * which is right for a bulk-selection screen and wrong for anything with a
221
+ * visible Buy/Checkout button. See `useCtaReveal`.
222
+ */
223
+ export { ctaAnchorProps, CTA_ANCHOR_ATTR } from "./features/layout/index";
216
224
  export type { AppLayoutShellProps, AppLayoutShellSidebarLink, AppLayoutShellSidebarSection, DashboardNavState, MainNavbarItem, LayoutClientProps } from "./features/layout/index";
217
225
  export { ListingLayout } from "./ui/components/ListingLayout";
218
226
  export type { ListingLayoutProps, ListingLayoutLabels } from "./ui/components/ListingLayout";
@@ -240,6 +248,7 @@ export { SELLER_ENDPOINTS } from "./constants/index";
240
248
  * BidDetailPageClient — checklist-page-wiring-detail-pages-detail-page-matches-list-modal.
241
249
  */
242
250
  export { ACCOUNT_ENDPOINTS } from "./constants/index";
251
+ export { REVIEW_ENDPOINTS } from "./constants/index";
243
252
  export { TourProvider, useTour } from "./_internal/client/features/tour/TourProvider";
244
253
  export type { TourContextValue, TourRole } from "./_internal/client/features/tour/TourProvider";
245
254
  export { apiClient, ApiClientError } from "./http/index";
@@ -411,6 +420,8 @@ export { WISHLIST_MAX, HISTORY_MAX, CART_MAX_ITEMS, } from "./constants/limits";
411
420
  export { normalizeListingType, isAuctionListing, isPreOrderListing, isStandardListing, isPrizeDrawListing, isClassifiedListing, isDigitalCodeListing, isLiveListing, isArtListing, isStickersListing, } from "./features/products/utils/listing-type";
412
421
  export { isFinalSale, acceptsChangeOfMindReturns, } from "./features/products/constants/final-sale";
413
422
  export { isListingTypeEnabled, isCategoryTypeEnabled, enabledListingTypes, enabledCategoryTypes, ALL_LISTING_TYPES, isListingType, } from "./_internal/shared/listing-types/feature-flags";
423
+ export { ADVANCED_LISTING_TYPE_CAPABILITY, ADVANCED_LISTING_TYPES, BASIC_LISTING_TYPES, LISTING_TYPE_TIER, hasAdvancedListingTypes, isAdvancedListingType, isListingTypeAllowedFor, listingTypesAllowedFor, } from "./_internal/shared/listing-types/tiers";
424
+ export type { ListingTypeAccessContext, ListingTypeTier, } from "./_internal/shared/listing-types/tiers";
414
425
  export { actionTracker, setActionTrackerSink, resetActionTrackerSink, type ActionEvent, type ActionTrackerSink, } from "./_internal/shared/listing-types/action-tracker";
415
426
  export { cartRequiresShipping, cartIsDigitalOnly, cartIsChatOnly, } from "./_internal/shared/listing-types/cart-shipping";
416
427
  export { ACTIONS, action, act, canPerformAction, actionsForListingType, actionLabel, type ActionDef, type ActionKind, type ActionResource, type ActionTree, type ActionConfirmation, } from "./_internal/shared/actions/action-registry";
@@ -422,6 +433,16 @@ export type { LayoutBreakpoint, DashboardVariant, LayoutRole, SidebarNavItem, Si
422
433
  export { LISTING_TYPE_CAPABILITIES, capabilityFor, canAddToCart, canBid, supportsShipping, requiresVendorVerified, requiresJurisdictionCheck, hasInstantFulfillment, assertNever, } from "./_internal/shared/listing-types/capabilities";
423
434
  export type { ListingTypeCapability } from "./_internal/shared/listing-types/capabilities";
424
435
  export { LISTING_TYPE_REGISTRY, pluginFor, detectListingTypeFromSlug } from "./_internal/shared/listing-types/_registry";
436
+ export { useStoreListingEntitlements } from "./features/seller/hooks/useStoreListingEntitlements";
437
+ export { OwnerQuickActions } from "./features/admin/components/OwnerQuickActions";
438
+ export { YourPurchaseStrip } from "./features/orders/components/YourPurchaseStrip";
439
+ export { ReviewFormDrawer, reviewFormSchema } from "./features/reviews/components/ReviewFormDrawer";
440
+ export type { ReviewFormDrawerProps, ReviewFormValues } from "./features/reviews/components/ReviewFormDrawer";
441
+ export { PurchaseReviewAffordance } from "./features/reviews/components/PurchaseReviewAffordance";
442
+ export type { PurchaseReviewAffordanceProps } from "./features/reviews/components/PurchaseReviewAffordance";
443
+ export type { YourPurchaseStripProps, PurchaseContext } from "./features/orders/components/YourPurchaseStrip";
444
+ export type { OwnerQuickActionsProps, OwnerQuickActionsResource } from "./features/admin/components/OwnerQuickActions";
445
+ export type { StoreListingEntitlements } from "./features/seller/hooks/useStoreListingEntitlements";
425
446
  export type { ListingTypePlugin } from "./_internal/shared/listing-types/_registry";
426
447
  export type { ListingType } from "./features/products/types/index";
427
448
  export { MEGABYTE, MAX_IMAGE_BYTES, MAX_PDF_BYTES, MAX_VIDEO_BYTES, MAX_LABEL, MAX_BYTES, ALLOWED_IMAGE_MIMES, IMAGE_ACCEPT_ATTR, ALLOWED_VIDEO_MIMES, ALLOWED_DOC_MIMES, ALLOWED_MIMES, ALLOWED_TYPES_LABEL, MIME_TO_EXT, PDF_MAGIC, VIDEO_CONVERSION_HINTS, classifyMime, isAllowedMime, maxBytesFor, getConversionHint, PRODUCT_MAX_IMAGES, PRODUCT_MAX_VIDEOS, PRODUCT_IMAGE_INDEX_MAX, } from "./_internal/shared/media/limits";
@@ -468,8 +489,6 @@ export { SCHEMAS, lookupApiSchema, lookupFormSchema, lookupFirestoreSchema, } fr
468
489
  export type { ApiRouteKey, ApiRouteSchema, FirestoreDocument, FirestoreValue, FormFieldValue, FormValues, HttpVerb, JsonArray, JsonObject, JsonObjectWithUndefined, JsonPrimitive, JsonValue, JsonValueWithUndefined, RegisteredApiRouteKey, RegisteredFirestoreCollection, RegisteredFormId, RegisteredRtdbChannel, RegisteredSieveCollection, RegisteredStorageOp, RegisteredWebhookProvider, RegistryEntry, SchemaRegistry, SchemasShape, WebhookSchemaBucket, } from "./schemas/index";
469
490
  export { normalizeError, getErrorMessage, isApiNormalized, isAppNormalized, isFirebaseAuthNormalized, isFirebaseFirestoreNormalized, isFirebaseStorageNormalized, isNativeNormalized, isNetworkNormalized, isUnknownNormalized, isZodNormalized, } from "./errors/normalize";
470
491
  export type { NormalizedError, NormalizedApiError, NormalizedAppError, NormalizedFirebaseAuthError, NormalizedFirebaseFirestoreError, NormalizedFirebaseStorageError, NormalizedNativeError, NormalizedNetworkError, NormalizedUnknownThrownValue, NormalizedZodError, } from "./errors/normalize";
471
- export { buildPaymentProofReviewMessage } from "./features/whatsapp-bot/helpers/payment-proof-message";
472
- export type { PaymentProofReviewMessageInput } from "./features/whatsapp-bot/types";
473
492
  export type { AdminNotificationDocument, ItemRequestDocument, ModerationQueueDocument, ReportDocument, CustomRoleDocument, AnalyticsCardDocument, ListingTemplateDocument, } from "./features/store-extensions/index";
474
493
  export { CommandPalette, useCommandPaletteHotkey } from "./features/shell/index";
475
494
  export type { CommandPaletteGroup } from "./features/shell/index";
package/dist/client.js CHANGED
@@ -263,6 +263,14 @@ export { ActionRow } from "./ui/components/ActionRow.js";
263
263
  export { Textarea } from "./ui/components/Textarea.js";
264
264
  export { GlobalError } from "./next/components/GlobalError.js";
265
265
  export { AppLayoutShell, LocaleSwitcher, useDashboardNav, BottomActionsProvider, useBottomActions, DashboardNavProvider, LayoutClient } from "./features/layout/index.js";
266
+ /**
267
+ * A page declares its own inline primary CTA so the floating action control
268
+ * stays out of its way until that button has been seen and scrolled past. A
269
+ * page that publishes actions and no anchor gets the control immediately —
270
+ * which is right for a bulk-selection screen and wrong for anything with a
271
+ * visible Buy/Checkout button. See `useCtaReveal`.
272
+ */
273
+ export { ctaAnchorProps, CTA_ANCHOR_ATTR } from "./features/layout/index.js";
266
274
  export { ListingLayout } from "./ui/components/ListingLayout.js";
267
275
  export { Search } from "./features/search/components/index.js";
268
276
  export { ToastProvider, SkipToMain, NavigationLoader } from "./ui/index.js";
@@ -290,6 +298,7 @@ export { SELLER_ENDPOINTS } from "./constants/index.js";
290
298
  * BidDetailPageClient — checklist-page-wiring-detail-pages-detail-page-matches-list-modal.
291
299
  */
292
300
  export { ACCOUNT_ENDPOINTS } from "./constants/index.js";
301
+ export { REVIEW_ENDPOINTS } from "./constants/index.js";
293
302
  // P-16 — Tour system (driver.js-backed onboarding walkthrough).
294
303
  export { TourProvider, useTour } from "./_internal/client/features/tour/TourProvider.js";
295
304
  export { apiClient, ApiClientError } from "./http/index.js";
@@ -424,6 +433,10 @@ export { normalizeListingType, isAuctionListing, isPreOrderListing, isStandardLi
424
433
  export { isFinalSale, acceptsChangeOfMindReturns, } from "./features/products/constants/final-sale.js";
425
434
  // SB-UNI-X4 2026-05-13 — per-type feature-flag helpers (client-safe).
426
435
  export { isListingTypeEnabled, isCategoryTypeEnabled, enabledListingTypes, enabledCategoryTypes, ALL_LISTING_TYPES, isListingType, } from "./_internal/shared/listing-types/feature-flags.js";
436
+ // Basic/advanced listing-type split. Client-safe: the nav filter and any
437
+ // seller-facing picker need the same rule the server enforces, and deriving it
438
+ // twice is how the ten hand-written copies of the union happened.
439
+ export { ADVANCED_LISTING_TYPE_CAPABILITY, ADVANCED_LISTING_TYPES, BASIC_LISTING_TYPES, LISTING_TYPE_TIER, hasAdvancedListingTypes, isAdvancedListingType, isListingTypeAllowedFor, listingTypesAllowedFor, } from "./_internal/shared/listing-types/tiers.js";
427
440
  // SB-UNI-X5 2026-05-13 — action telemetry sink (client-safe; defaults to
428
441
  // a no-op + console.debug in dev).
429
442
  export { actionTracker, setActionTrackerSink, resetActionTrackerSink, } from "./_internal/shared/listing-types/action-tracker.js";
@@ -440,6 +453,16 @@ export { DashboardLayoutClient, RoleGuard } from "./_internal/client/features/la
440
453
  // Listing-type capability registry — SB-UNI X1.
441
454
  export { LISTING_TYPE_CAPABILITIES, capabilityFor, canAddToCart, canBid, supportsShipping, requiresVendorVerified, requiresJurisdictionCheck, hasInstantFulfillment, assertNever, } from "./_internal/shared/listing-types/capabilities.js";
442
455
  export { LISTING_TYPE_REGISTRY, pluginFor, detectListingTypeFromSlug } from "./_internal/shared/listing-types/_registry.js";
456
+ // Which listing types the signed-in seller's own store may create. Needs a
457
+ // fetch because `capabilities` is a PRIVATE store field — see the hook.
458
+ export { useStoreListingEntitlements } from "./features/seller/hooks/useStoreListingEntitlements.js";
459
+ // Pencil / clone / bin for whoever owns the record, on a PUBLIC surface.
460
+ export { OwnerQuickActions } from "./features/admin/components/OwnerQuickActions.js";
461
+ // "You ordered this - track it" / "your review - edit it", on a product page.
462
+ export { YourPurchaseStrip } from "./features/orders/components/YourPurchaseStrip.js";
463
+ // The first review form this app has had - see the component's header.
464
+ export { ReviewFormDrawer, reviewFormSchema } from "./features/reviews/components/ReviewFormDrawer.js";
465
+ export { PurchaseReviewAffordance } from "./features/reviews/components/PurchaseReviewAffordance.js";
443
466
  // Media upload limits — shared by client uploaders + server sign/finalize routes.
444
467
  export { MEGABYTE, MAX_IMAGE_BYTES, MAX_PDF_BYTES, MAX_VIDEO_BYTES, MAX_LABEL, MAX_BYTES, ALLOWED_IMAGE_MIMES, IMAGE_ACCEPT_ATTR, ALLOWED_VIDEO_MIMES, ALLOWED_DOC_MIMES, ALLOWED_MIMES, ALLOWED_TYPES_LABEL, MIME_TO_EXT, PDF_MAGIC, VIDEO_CONVERSION_HINTS, classifyMime, isAllowedMime, maxBytesFor, getConversionHint, PRODUCT_MAX_IMAGES, PRODUCT_MAX_VIDEOS, PRODUCT_IMAGE_INDEX_MAX, } from "./_internal/shared/media/limits.js";
445
468
  export { ScamAwarenessModal } from "./features/scams/components/ScamAwarenessModal.js";
@@ -476,10 +499,6 @@ export { SellerLiveView } from "./features/seller/components/SellerLiveView.js";
476
499
  export { SCHEMAS, lookupApiSchema, lookupFormSchema, lookupFirestoreSchema, } from "./schemas/index.js";
477
500
  // ── W3 catch-clause normalizer ──────────────────────────────────────────────
478
501
  export { normalizeError, getErrorMessage, isApiNormalized, isAppNormalized, isFirebaseAuthNormalized, isFirebaseFirestoreNormalized, isFirebaseStorageNormalized, isNativeNormalized, isNetworkNormalized, isUnknownNormalized, isZodNormalized, } from "./errors/normalize.js";
479
- // [CLIENT-SAFE] Pure wa.me share-link message builder — imported directly
480
- // from its isolated file (not ./whatsapp-bot/server) so this barrel's graph
481
- // never touches the sibling crypto-importing helpers.
482
- export { buildPaymentProofReviewMessage } from "./features/whatsapp-bot/helpers/payment-proof-message.js";
483
502
  export { CommandPalette, useCommandPaletteHotkey } from "./features/shell/index.js";
484
503
  export { AdminBlogEditorView, AdminBundleEditorView, AdminCarouselEditorView, AdminCategoryEditorView, AdminCouponEditorView, AdminFaqEditorView, AdminFeatureEditorView, AdminOrderEditorView, AdminPayoutMarkPaidModal, AdminAuditLogView, ViewAuditLogEntryModal, AdminProductEditorView, AdminScammerEditorView,
485
504
  // Client-exported for the W22 /admin/team/{new,[id]/edit} pages. It was
@@ -57,6 +57,11 @@ export declare const ACCOUNT_ENDPOINTS: {
57
57
  readonly HISTORY_ITEM: (productId: string) => string;
58
58
  readonly HISTORY_MERGE: "/api/user/history/merge";
59
59
  readonly REVIEWS: "/api/user/reviews";
60
+ /**
61
+ * "Have I bought this, and did I review it?" for one product — backs the
62
+ * purchase strip on a product page. Per-viewer, never cached.
63
+ */
64
+ readonly PURCHASE_CONTEXT: (productId: string) => string;
60
65
  readonly BIDS: "/api/user/bids";
61
66
  readonly BID_BY_ID: (id: string) => string;
62
67
  readonly EXPORT: "/api/user/export";
@@ -301,6 +306,13 @@ export declare const TOOL_ENDPOINTS: {
301
306
  * is the multi-get `searchPriceIndex` otherwise pays for every lookup.
302
307
  */
303
308
  readonly PRICE_INDEX_BANDS: (ids: readonly string[]) => string;
309
+ /**
310
+ * The competitor-crawl market band for the same leaves — SIGNED-IN ONLY, and
311
+ * therefore a separate request from `PRICE_INDEX_BANDS` rather than more
312
+ * fields on it. That route is public and edge-cached; this one must not be,
313
+ * or one signed-in lookup populates an entry every guest reads.
314
+ */
315
+ readonly PRICE_INDEX_MARKET: (ids: readonly string[]) => string;
304
316
  };
305
317
  /**
306
318
  * The sticker-sheet kiss-cut tracer. Admin-only, every route behind
@@ -445,6 +457,8 @@ export declare const PROMOTION_ENDPOINTS: {
445
457
  export declare const REVIEW_ENDPOINTS: {
446
458
  readonly LIST: "/api/reviews";
447
459
  readonly FEATURED: "/api/reviews?featured=true";
460
+ /** GET / PATCH / DELETE one review. The PATCH is the buyer's own edit. */
461
+ readonly BY_ID: (id: string) => string;
448
462
  };
449
463
  export declare const SEARCH_ENDPOINTS: {
450
464
  readonly SUGGESTIONS: "/api/search/suggestions";
@@ -612,6 +626,11 @@ export declare const API_ENDPOINTS: {
612
626
  readonly HISTORY_ITEM: (productId: string) => string;
613
627
  readonly HISTORY_MERGE: "/api/user/history/merge";
614
628
  readonly REVIEWS: "/api/user/reviews";
629
+ /**
630
+ * "Have I bought this, and did I review it?" for one product — backs the
631
+ * purchase strip on a product page. Per-viewer, never cached.
632
+ */
633
+ readonly PURCHASE_CONTEXT: (productId: string) => string;
615
634
  readonly BIDS: "/api/user/bids";
616
635
  readonly BID_BY_ID: (id: string) => string;
617
636
  readonly EXPORT: "/api/user/export";
@@ -951,6 +970,8 @@ export declare const API_ENDPOINTS: {
951
970
  readonly REVIEWS: {
952
971
  readonly LIST: "/api/reviews";
953
972
  readonly FEATURED: "/api/reviews?featured=true";
973
+ /** GET / PATCH / DELETE one review. The PATCH is the buyer's own edit. */
974
+ readonly BY_ID: (id: string) => string;
954
975
  };
955
976
  readonly SEARCH: {
956
977
  readonly SUGGESTIONS: "/api/search/suggestions";
@@ -1139,6 +1160,11 @@ export declare const API_ROUTES: {
1139
1160
  readonly HISTORY_ITEM: (productId: string) => string;
1140
1161
  readonly HISTORY_MERGE: "/api/user/history/merge";
1141
1162
  readonly REVIEWS: "/api/user/reviews";
1163
+ /**
1164
+ * "Have I bought this, and did I review it?" for one product — backs the
1165
+ * purchase strip on a product page. Per-viewer, never cached.
1166
+ */
1167
+ readonly PURCHASE_CONTEXT: (productId: string) => string;
1142
1168
  readonly BIDS: "/api/user/bids";
1143
1169
  readonly BID_BY_ID: (id: string) => string;
1144
1170
  readonly EXPORT: "/api/user/export";
@@ -1478,6 +1504,8 @@ export declare const API_ROUTES: {
1478
1504
  readonly REVIEWS: {
1479
1505
  readonly LIST: "/api/reviews";
1480
1506
  readonly FEATURED: "/api/reviews?featured=true";
1507
+ /** GET / PATCH / DELETE one review. The PATCH is the buyer's own edit. */
1508
+ readonly BY_ID: (id: string) => string;
1481
1509
  };
1482
1510
  readonly SEARCH: {
1483
1511
  readonly SUGGESTIONS: "/api/search/suggestions";