@mohasinac/appkit 4.52.4 → 4.53.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 (633) hide show
  1. package/dist/.build-stamp.json +4 -4
  2. package/dist/_internal/client/features/sticker-trace/canvas-codec.d.ts +2 -0
  3. package/dist/_internal/client/features/sticker-trace/canvas-codec.js +148 -0
  4. package/dist/_internal/server/features/auctions/actions.js +1 -1
  5. package/dist/_internal/server/features/categories/data.js +23 -7
  6. package/dist/_internal/server/features/checkout/actions.js +10 -3
  7. package/dist/_internal/server/features/checkout/data.d.ts +15 -0
  8. package/dist/_internal/server/features/checkout/data.js +20 -3
  9. package/dist/_internal/server/features/lottery/actions.js +9 -1
  10. package/dist/_internal/server/features/lottery/og.d.ts +40 -0
  11. package/dist/_internal/server/features/lottery/og.js +79 -0
  12. package/dist/_internal/server/features/messages/actions.js +4 -0
  13. package/dist/_internal/server/features/offers/adapters.js +17 -3
  14. package/dist/_internal/server/features/orders/actions.js +7 -2
  15. package/dist/_internal/server/features/raffle/actions.d.ts +19 -0
  16. package/dist/_internal/server/features/raffle/actions.js +25 -0
  17. package/dist/_internal/server/features/reviews/actions.js +1 -1
  18. package/dist/_internal/server/features/reviews/data.d.ts +1 -1
  19. package/dist/_internal/server/features/search/index-build/artifact-store.d.ts +89 -0
  20. package/dist/_internal/server/features/search/index-build/artifact-store.js +208 -0
  21. package/dist/_internal/server/features/search/index-build/build.d.ts +57 -0
  22. package/dist/_internal/server/features/search/index-build/build.js +285 -0
  23. package/dist/_internal/server/features/search/index-build/sources.d.ts +53 -0
  24. package/dist/_internal/server/features/search/index-build/sources.js +385 -0
  25. package/dist/_internal/server/features/search/search-sources.d.ts +0 -15
  26. package/dist/_internal/server/features/search/search-sources.js +142 -7
  27. package/dist/_internal/server/features/seo/robots.js +21 -1
  28. package/dist/_internal/server/features/seo/sitemap.js +1 -1
  29. package/dist/_internal/server/features/shared/listing-data-factory.js +16 -4
  30. package/dist/_internal/server/features/site-settings/adapters.d.ts +1 -1
  31. package/dist/_internal/server/features/site-settings/adapters.js +26 -0
  32. package/dist/_internal/server/features/sticker-trace/actions.d.ts +109 -0
  33. package/dist/_internal/server/features/sticker-trace/actions.js +172 -0
  34. package/dist/_internal/server/features/sticker-trace/adapters.d.ts +80 -0
  35. package/dist/_internal/server/features/sticker-trace/adapters.js +174 -0
  36. package/dist/_internal/server/features/sticker-trace/build-cut-file.d.ts +26 -0
  37. package/dist/_internal/server/features/sticker-trace/build-cut-file.js +127 -0
  38. package/dist/_internal/server/features/sticker-trace/coordinator.d.ts +27 -0
  39. package/dist/_internal/server/features/sticker-trace/coordinator.js +169 -0
  40. package/dist/_internal/server/features/sticker-trace/fanout.d.ts +43 -0
  41. package/dist/_internal/server/features/sticker-trace/fanout.js +180 -0
  42. package/dist/_internal/server/features/sticker-trace/finalizer.d.ts +25 -0
  43. package/dist/_internal/server/features/sticker-trace/finalizer.js +123 -0
  44. package/dist/_internal/server/features/sticker-trace/mosaic-inputs.d.ts +30 -0
  45. package/dist/_internal/server/features/sticker-trace/mosaic-inputs.js +112 -0
  46. package/dist/_internal/server/features/sticker-trace/progress.d.ts +81 -0
  47. package/dist/_internal/server/features/sticker-trace/progress.js +198 -0
  48. package/dist/_internal/server/features/sticker-trace/promote.d.ts +23 -0
  49. package/dist/_internal/server/features/sticker-trace/promote.js +193 -0
  50. package/dist/_internal/server/features/sticker-trace/shard.d.ts +50 -0
  51. package/dist/_internal/server/features/sticker-trace/shard.js +174 -0
  52. package/dist/_internal/server/features/sticker-trace/sheet-actions.d.ts +141 -0
  53. package/dist/_internal/server/features/sticker-trace/sheet-actions.js +279 -0
  54. package/dist/_internal/server/features/sticker-trace/storage.d.ts +135 -0
  55. package/dist/_internal/server/features/sticker-trace/storage.js +282 -0
  56. package/dist/_internal/server/functions/scheduled.d.ts +2 -1
  57. package/dist/_internal/server/functions/scheduled.js +25 -1
  58. package/dist/_internal/server/jobs/core/_event-ref.d.ts +51 -0
  59. package/dist/_internal/server/jobs/core/_event-ref.js +63 -0
  60. package/dist/_internal/server/jobs/core/assignSpinPrize.d.ts +18 -0
  61. package/dist/_internal/server/jobs/core/assignSpinPrize.js +77 -16
  62. package/dist/_internal/server/jobs/core/auctionSettlement.js +13 -4
  63. package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +44 -15
  64. package/dist/_internal/server/jobs/core/bundleStockSync.js +3 -4
  65. package/dist/_internal/server/jobs/core/cleanupRtdbEvents.js +44 -0
  66. package/dist/_internal/server/jobs/core/event-draw-reasons.d.ts +78 -0
  67. package/dist/_internal/server/jobs/core/event-draw-reasons.js +133 -0
  68. package/dist/_internal/server/jobs/core/listingProcessor.js +28 -8
  69. package/dist/_internal/server/jobs/core/onOrderCreate.js +12 -1
  70. package/dist/_internal/server/jobs/core/onScamReportCreate.js +13 -2
  71. package/dist/_internal/server/jobs/core/onScamReportRejected.js +8 -2
  72. package/dist/_internal/server/jobs/core/onScamReportVerified.js +8 -2
  73. package/dist/_internal/server/jobs/core/onStoreWrite.js +11 -4
  74. package/dist/_internal/server/jobs/core/prizeDrawAssignWinner.js +5 -4
  75. package/dist/_internal/server/jobs/core/prizeDrawExpiryReveal.js +1 -4
  76. package/dist/_internal/server/jobs/core/prizeDrawSoldOutReveal.js +1 -2
  77. package/dist/_internal/server/jobs/core/promotions.js +7 -4
  78. package/dist/_internal/server/jobs/core/searchIndexBuild.d.ts +7 -0
  79. package/dist/_internal/server/jobs/core/searchIndexBuild.js +211 -0
  80. package/dist/_internal/server/jobs/core/triggerEventRaffle.d.ts +35 -0
  81. package/dist/_internal/server/jobs/core/triggerEventRaffle.js +213 -31
  82. package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +20 -14
  83. package/dist/_internal/server/jobs/handlers/assignSpinPrize.d.ts +8 -0
  84. package/dist/_internal/server/jobs/handlers/assignSpinPrize.js +15 -15
  85. package/dist/_internal/server/jobs/handlers/index.d.ts +1 -0
  86. package/dist/_internal/server/jobs/handlers/index.js +1 -0
  87. package/dist/_internal/server/jobs/handlers/onCategoryWrite.js +18 -0
  88. package/dist/_internal/server/jobs/handlers/onProductWrite.js +18 -0
  89. package/dist/_internal/server/jobs/handlers/onReviewWrite.js +18 -0
  90. package/dist/_internal/server/jobs/handlers/onScamReportUpdate.js +18 -0
  91. package/dist/_internal/server/jobs/handlers/onStoreWrite.js +18 -0
  92. package/dist/_internal/server/jobs/handlers/searchIndexBuild.d.ts +2 -0
  93. package/dist/_internal/server/jobs/handlers/searchIndexBuild.js +2 -0
  94. package/dist/_internal/server/jobs/handlers/triggerEventRaffle.d.ts +8 -0
  95. package/dist/_internal/server/jobs/handlers/triggerEventRaffle.js +15 -6
  96. package/dist/_internal/shared/actions/action-registry.js +29 -0
  97. package/dist/_internal/shared/cache/revalidate-targets.d.ts +0 -1
  98. package/dist/_internal/shared/cache/revalidate-targets.js +10 -8
  99. package/dist/_internal/shared/features/events/config.d.ts +14 -0
  100. package/dist/_internal/shared/features/events/config.js +14 -0
  101. package/dist/_internal/shared/features/notifications/action-url.js +8 -0
  102. package/dist/_internal/shared/features/site-settings/types.d.ts +11 -0
  103. package/dist/_internal/shared/features/sticker-trace/codec.d.ts +81 -0
  104. package/dist/_internal/shared/features/sticker-trace/codec.js +30 -0
  105. package/dist/_internal/shared/features/sticker-trace/config.d.ts +81 -0
  106. package/dist/_internal/shared/features/sticker-trace/config.js +177 -0
  107. package/dist/_internal/shared/features/sticker-trace/cut-contour.d.ts +20 -0
  108. package/dist/_internal/shared/features/sticker-trace/cut-contour.js +60 -0
  109. package/dist/_internal/shared/features/sticker-trace/export/build-export-set.d.ts +65 -0
  110. package/dist/_internal/shared/features/sticker-trace/export/build-export-set.js +176 -0
  111. package/dist/_internal/shared/features/sticker-trace/export/cut-svg.d.ts +56 -0
  112. package/dist/_internal/shared/features/sticker-trace/export/cut-svg.js +120 -0
  113. package/dist/_internal/shared/features/sticker-trace/export/machine-profiles.d.ts +92 -0
  114. package/dist/_internal/shared/features/sticker-trace/export/machine-profiles.js +153 -0
  115. package/dist/_internal/shared/features/sticker-trace/export/nesting.d.ts +51 -0
  116. package/dist/_internal/shared/features/sticker-trace/export/nesting.js +110 -0
  117. package/dist/_internal/shared/features/sticker-trace/export/page-sizes.d.ts +68 -0
  118. package/dist/_internal/shared/features/sticker-trace/export/page-sizes.js +223 -0
  119. package/dist/_internal/shared/features/sticker-trace/export/part-tiling.d.ts +51 -0
  120. package/dist/_internal/shared/features/sticker-trace/export/part-tiling.js +178 -0
  121. package/dist/_internal/shared/features/sticker-trace/export/simplify-budget.d.ts +26 -0
  122. package/dist/_internal/shared/features/sticker-trace/export/simplify-budget.js +134 -0
  123. package/dist/_internal/shared/features/sticker-trace/export/vectorise-art.d.ts +40 -0
  124. package/dist/_internal/shared/features/sticker-trace/export/vectorise-art.js +195 -0
  125. package/dist/_internal/shared/features/sticker-trace/index.d.ts +2 -0
  126. package/dist/_internal/shared/features/sticker-trace/index.js +59 -0
  127. package/dist/_internal/shared/features/sticker-trace/math/catmull-rom.d.ts +11 -0
  128. package/dist/_internal/shared/features/sticker-trace/math/catmull-rom.js +66 -0
  129. package/dist/_internal/shared/features/sticker-trace/math/edt.d.ts +27 -0
  130. package/dist/_internal/shared/features/sticker-trace/math/edt.js +165 -0
  131. package/dist/_internal/shared/features/sticker-trace/math/label.d.ts +15 -0
  132. package/dist/_internal/shared/features/sticker-trace/math/label.js +156 -0
  133. package/dist/_internal/shared/features/sticker-trace/math/marching-squares.d.ts +16 -0
  134. package/dist/_internal/shared/features/sticker-trace/math/marching-squares.js +242 -0
  135. package/dist/_internal/shared/features/sticker-trace/math/morphology.d.ts +46 -0
  136. package/dist/_internal/shared/features/sticker-trace/math/morphology.js +168 -0
  137. package/dist/_internal/shared/features/sticker-trace/math/rasterize-path.d.ts +88 -0
  138. package/dist/_internal/shared/features/sticker-trace/math/rasterize-path.js +286 -0
  139. package/dist/_internal/shared/features/sticker-trace/math/rdp.d.ts +10 -0
  140. package/dist/_internal/shared/features/sticker-trace/math/rdp.js +74 -0
  141. package/dist/_internal/shared/features/sticker-trace/resume.d.ts +50 -0
  142. package/dist/_internal/shared/features/sticker-trace/resume.js +160 -0
  143. package/dist/_internal/shared/features/sticker-trace/trace/cluster.d.ts +20 -0
  144. package/dist/_internal/shared/features/sticker-trace/trace/cluster.js +132 -0
  145. package/dist/_internal/shared/features/sticker-trace/trace/cross-profile.d.ts +28 -0
  146. package/dist/_internal/shared/features/sticker-trace/trace/cross-profile.js +120 -0
  147. package/dist/_internal/shared/features/sticker-trace/trace/flood.d.ts +21 -0
  148. package/dist/_internal/shared/features/sticker-trace/trace/flood.js +104 -0
  149. package/dist/_internal/shared/features/sticker-trace/trace/geometry.d.ts +3 -0
  150. package/dist/_internal/shared/features/sticker-trace/trace/geometry.js +140 -0
  151. package/dist/_internal/shared/features/sticker-trace/trace/line-filter.d.ts +15 -0
  152. package/dist/_internal/shared/features/sticker-trace/trace/line-filter.js +138 -0
  153. package/dist/_internal/shared/features/sticker-trace/trace/merge.d.ts +27 -0
  154. package/dist/_internal/shared/features/sticker-trace/trace/merge.js +187 -0
  155. package/dist/_internal/shared/features/sticker-trace/trace/paper.d.ts +32 -0
  156. package/dist/_internal/shared/features/sticker-trace/trace/paper.js +147 -0
  157. package/dist/_internal/shared/features/sticker-trace/trace/prefilter.d.ts +30 -0
  158. package/dist/_internal/shared/features/sticker-trace/trace/prefilter.js +125 -0
  159. package/dist/_internal/shared/features/sticker-trace/trace/quantise.d.ts +10 -0
  160. package/dist/_internal/shared/features/sticker-trace/trace/quantise.js +153 -0
  161. package/dist/_internal/shared/features/sticker-trace/trace/ridge.d.ts +88 -0
  162. package/dist/_internal/shared/features/sticker-trace/trace/ridge.js +344 -0
  163. package/dist/_internal/shared/features/sticker-trace/trace/segment.d.ts +10 -0
  164. package/dist/_internal/shared/features/sticker-trace/trace/segment.js +251 -0
  165. package/dist/_internal/shared/features/sticker-trace/types.d.ts +197 -0
  166. package/dist/_internal/shared/features/sticker-trace/types.js +49 -0
  167. package/dist/_internal/shared/listing-types/_registry.d.ts +11 -0
  168. package/dist/_internal/shared/listing-types/art/config.d.ts +1 -0
  169. package/dist/_internal/shared/listing-types/art/config.js +1 -0
  170. package/dist/_internal/shared/listing-types/auction/config.d.ts +1 -0
  171. package/dist/_internal/shared/listing-types/auction/config.js +1 -0
  172. package/dist/_internal/shared/listing-types/classified/config.d.ts +1 -0
  173. package/dist/_internal/shared/listing-types/classified/config.js +1 -0
  174. package/dist/_internal/shared/listing-types/digital-code/config.d.ts +1 -0
  175. package/dist/_internal/shared/listing-types/digital-code/config.js +1 -0
  176. package/dist/_internal/shared/listing-types/feature-flags.d.ts +7 -0
  177. package/dist/_internal/shared/listing-types/feature-flags.js +9 -0
  178. package/dist/_internal/shared/listing-types/live/config.d.ts +1 -0
  179. package/dist/_internal/shared/listing-types/live/config.js +1 -0
  180. package/dist/_internal/shared/listing-types/pre-order/config.d.ts +1 -0
  181. package/dist/_internal/shared/listing-types/pre-order/config.js +1 -0
  182. package/dist/_internal/shared/listing-types/prize-draw/config.d.ts +1 -0
  183. package/dist/_internal/shared/listing-types/prize-draw/config.js +1 -0
  184. package/dist/_internal/shared/listing-types/standard/config.d.ts +1 -0
  185. package/dist/_internal/shared/listing-types/standard/config.js +1 -0
  186. package/dist/_internal/shared/listing-types/stickers/config.d.ts +1 -0
  187. package/dist/_internal/shared/listing-types/stickers/config.js +1 -0
  188. package/dist/_internal/shared/media/limits.d.ts +12 -2
  189. package/dist/_internal/shared/media/limits.js +12 -2
  190. package/dist/_internal/shared/search/artifact-url.d.ts +35 -0
  191. package/dist/_internal/shared/search/artifact-url.js +119 -0
  192. package/dist/_internal/shared/search/index-record.d.ts +68 -0
  193. package/dist/_internal/shared/search/index-record.js +96 -0
  194. package/dist/_internal/shared/search/match.d.ts +65 -0
  195. package/dist/_internal/shared/search/match.js +263 -0
  196. package/dist/client.d.ts +8 -7
  197. package/dist/client.js +12 -5
  198. package/dist/configs/eslint.js +22 -2
  199. package/dist/constants/api-endpoints.d.ts +68 -0
  200. package/dist/constants/api-endpoints.js +32 -0
  201. package/dist/constants/field-names.d.ts +7 -1
  202. package/dist/constants/field-names.js +36 -1
  203. package/dist/contracts/repository.d.ts +8 -7
  204. package/dist/contracts/search.d.ts +2 -2
  205. package/dist/contracts/table.d.ts +3 -3
  206. package/dist/contracts/table.js +3 -3
  207. package/dist/core/contact-submissions.repository.js +2 -2
  208. package/dist/core/integration-keys.js +7 -1
  209. package/dist/core/newsletter.repository.js +2 -2
  210. package/dist/core/site-config.js +1 -1
  211. package/dist/errors/error-codes.d.ts +30 -0
  212. package/dist/errors/error-codes.js +30 -0
  213. package/dist/errors/error-display-map.js +40 -1
  214. package/dist/features/account/api/[userId]/addresses/route.js +1 -1
  215. package/dist/features/account/components/UserBidsView.js +1 -1
  216. package/dist/features/account/components/index.d.ts +0 -8
  217. package/dist/features/account/components/index.js +0 -4
  218. package/dist/features/addresses/repository/addresses.repository.d.ts +17 -6
  219. package/dist/features/addresses/repository/addresses.repository.js +65 -9
  220. package/dist/features/addresses/schemas/firestore.d.ts +17 -6
  221. package/dist/features/admin/actions/notification-actions.js +15 -6
  222. package/dist/features/admin/api/bids/route.js +1 -1
  223. package/dist/features/admin/api/coupons/route.js +1 -1
  224. package/dist/features/admin/api/products/route.js +1 -1
  225. package/dist/features/admin/api/reviews/route.js +1 -1
  226. package/dist/features/admin/components/AdminAdEditorView.js +19 -5
  227. package/dist/features/admin/components/AdminAuditLogView.js +1 -1
  228. package/dist/features/admin/components/AdminBlogEditorView.js +0 -1
  229. package/dist/features/admin/components/AdminBlogView.js +1 -1
  230. package/dist/features/admin/components/AdminBrandsView.js +17 -1
  231. package/dist/features/admin/components/AdminCategoryEditorView.js +0 -1
  232. package/dist/features/admin/components/AdminContactView.js +1 -1
  233. package/dist/features/admin/components/AdminEmployeeEditorView.js +1 -3
  234. package/dist/features/admin/components/AdminNewsletterView.js +1 -1
  235. package/dist/features/admin/components/AdminOrdersView.js +9 -2
  236. package/dist/features/admin/components/AdminPayoutsView.js +1 -1
  237. package/dist/features/admin/components/AdminPrizeDrawsView.js +11 -0
  238. package/dist/features/admin/components/AdminProductEditorView.d.ts +10 -1
  239. package/dist/features/admin/components/AdminProductEditorView.js +24 -37
  240. package/dist/features/admin/components/AdminProductsView.js +10 -3
  241. package/dist/features/admin/components/AdminScammersView.js +1 -1
  242. package/dist/features/admin/components/AdminSectionsView.js +21 -5
  243. package/dist/features/admin/components/AdminSessionsView.js +1 -1
  244. package/dist/features/admin/components/AdminSublistingCategoriesView.js +22 -1
  245. package/dist/features/admin/components/AdminTeamView.js +1 -1
  246. package/dist/features/admin/components/AdminTesterChecklistItemEditorView.js +0 -1
  247. package/dist/features/admin/components/AdminUsersView.js +1 -1
  248. package/dist/features/admin/components/DataListingView.d.ts +2 -1
  249. package/dist/features/admin/components/DataListingView.js +9 -4
  250. package/dist/features/admin/components/analytics/AdminPageViewsReportView.js +0 -2
  251. package/dist/features/admin/hooks/useAdminListing.d.ts +1 -1
  252. package/dist/features/admin/repository/site-settings.repository.js +8 -3
  253. package/dist/features/admin/schemas/firestore.d.ts +62 -1
  254. package/dist/features/admin/schemas/firestore.js +32 -0
  255. package/dist/features/admin/types/index.d.ts +1 -1
  256. package/dist/features/auctions/actions/bid-actions.d.ts +2 -2
  257. package/dist/features/auctions/actions/bid-actions.js +16 -4
  258. package/dist/features/auctions/api/route.js +1 -1
  259. package/dist/features/auctions/components/AuctionBottomActions.js +4 -0
  260. package/dist/features/auctions/repository/bid.repository.d.ts +46 -4
  261. package/dist/features/auctions/repository/bid.repository.js +114 -13
  262. package/dist/features/auctions/schemas/firestore.d.ts +24 -4
  263. package/dist/features/auctions/schemas/firestore.js +1 -0
  264. package/dist/features/auth/actions/profile-actions.js +30 -4
  265. package/dist/features/auth/components/index.d.ts +0 -1
  266. package/dist/features/auth/components/index.js +0 -1
  267. package/dist/features/auth/repository/session.repository.d.ts +17 -3
  268. package/dist/features/auth/repository/session.repository.js +46 -5
  269. package/dist/features/auth/repository/token.repository.d.ts +27 -4
  270. package/dist/features/auth/repository/token.repository.js +65 -11
  271. package/dist/features/auth/repository/user.repository.d.ts +33 -7
  272. package/dist/features/auth/repository/user.repository.js +100 -15
  273. package/dist/features/auth/schemas/firestore.d.ts +63 -12
  274. package/dist/features/auth/schemas/firestore.js +11 -0
  275. package/dist/features/before-after/api/route.js +1 -1
  276. package/dist/features/blog/components/BlogListView.js +16 -3
  277. package/dist/features/blog/components/BlogPostView.js +1 -1
  278. package/dist/features/blog/schemas/index.d.ts +2 -2
  279. package/dist/features/cart/api/route.js +1 -1
  280. package/dist/features/catalogue/repository/catalogue.repository.d.ts +7 -7
  281. package/dist/features/catalogue/repository/catalogue.repository.js +28 -10
  282. package/dist/features/catalogue/schemas/firestore.d.ts +11 -0
  283. package/dist/features/categories/api/route.js +10 -10
  284. package/dist/features/categories/components/CategoryDetailPageView.js +35 -5
  285. package/dist/features/categories/components/CategorySelectorCreate.js +0 -1
  286. package/dist/features/categories/components/index.d.ts +0 -2
  287. package/dist/features/categories/components/index.js +0 -1
  288. package/dist/features/categories/repository/categories.repository.d.ts +1 -0
  289. package/dist/features/categories/repository/categories.repository.js +31 -1
  290. package/dist/features/categories/schemas/index.d.ts +2 -2
  291. package/dist/features/categories/utils/taxonomy-visual.d.ts +21 -0
  292. package/dist/features/categories/utils/taxonomy-visual.js +58 -0
  293. package/dist/features/checkout/actions/checkout-value-otp-actions.js +8 -1
  294. package/dist/features/collections/api/[slug]/route.js +3 -3
  295. package/dist/features/collections/api/route.js +1 -1
  296. package/dist/features/consultation/api/route.js +1 -1
  297. package/dist/features/consultation/repository/consultations.repository.js +1 -1
  298. package/dist/features/consultation/types/index.d.ts +1 -1
  299. package/dist/features/contact/components/ContactForm.js +1 -3
  300. package/dist/features/corporate/api/route.js +1 -1
  301. package/dist/features/corporate/repository/corporate.repository.js +1 -1
  302. package/dist/features/corporate/types/index.d.ts +1 -1
  303. package/dist/features/cron/jobs/auction-expiry.job.js +1 -1
  304. package/dist/features/cron/jobs/preorder-reminder.job.js +1 -1
  305. package/dist/features/events/actions/event-actions.d.ts +14 -0
  306. package/dist/features/events/actions/event-actions.js +82 -3
  307. package/dist/features/events/api/[id]/route.js +2 -2
  308. package/dist/features/events/components/AdminEventEditorView.js +22 -3
  309. package/dist/features/events/components/AdminEventsView.js +32 -8
  310. package/dist/features/events/components/EventRafflesSection.d.ts +34 -1
  311. package/dist/features/events/components/EventRafflesSection.js +52 -3
  312. package/dist/features/events/components/SpinWheelView.d.ts +2 -2
  313. package/dist/features/events/components/SpinWheelView.js +41 -4
  314. package/dist/features/events/repository/event-entry.repository.d.ts +14 -2
  315. package/dist/features/events/repository/event-entry.repository.js +41 -7
  316. package/dist/features/events/schemas/firestore.d.ts +17 -4
  317. package/dist/features/events/types/index.d.ts +37 -0
  318. package/dist/features/faq/repository/faqs.repository.js +1 -1
  319. package/dist/features/faq/schemas/index.d.ts +5 -2
  320. package/dist/features/faq/schemas/index.js +6 -0
  321. package/dist/features/faq/types/index.d.ts +0 -1
  322. package/dist/features/grouped/components/GroupedListingEditorView.js +17 -2
  323. package/dist/features/homepage/api/carousel/[id]/route.js +1 -1
  324. package/dist/features/homepage/api/carousel/route.js +4 -4
  325. package/dist/features/homepage/api/route.js +2 -2
  326. package/dist/features/homepage/api/sections/route.js +1 -1
  327. package/dist/features/homepage/components/AnnouncementBar.d.ts +1 -9
  328. package/dist/features/homepage/components/AnnouncementBar.js +13 -19
  329. package/dist/features/homepage/components/MarketplaceHomepageView.js +6 -1
  330. package/dist/features/homepage/components/index.d.ts +0 -2
  331. package/dist/features/homepage/components/index.js +0 -1
  332. package/dist/features/homepage/repository/homepage.repository.js +1 -1
  333. package/dist/features/homepage/schemas/firestore.d.ts +6 -0
  334. package/dist/features/homepage/schemas/index.d.ts +10 -10
  335. package/dist/features/layout/AppLayoutShell.d.ts +12 -3
  336. package/dist/features/layout/AppLayoutShell.js +65 -13
  337. package/dist/features/layout/BottomActionsContext.d.ts +16 -0
  338. package/dist/features/layout/BottomActionsContext.js +5 -0
  339. package/dist/features/layout/BottomChrome.js +48 -9
  340. package/dist/features/layout/BottomNavbar.d.ts +14 -0
  341. package/dist/features/layout/BottomNavbar.js +43 -3
  342. package/dist/features/layout/MainNavbar.d.ts +11 -0
  343. package/dist/features/layout/NavbarLayout.d.ts +3 -0
  344. package/dist/features/layout/NavbarLayout.js +88 -11
  345. package/dist/features/layout/SideActionDock.d.ts +1 -0
  346. package/dist/features/layout/SideActionDock.js +219 -0
  347. package/dist/features/layout/TitleBarLayout.d.ts +1 -3
  348. package/dist/features/layout/TitleBarLayout.js +3 -4
  349. package/dist/features/layout/cta-anchor.d.ts +31 -0
  350. package/dist/features/layout/cta-anchor.js +31 -0
  351. package/dist/features/layout/hooks/useBottomActions.d.ts +7 -0
  352. package/dist/features/layout/hooks/useBottomActions.js +6 -1
  353. package/dist/features/layout/index.d.ts +9 -1
  354. package/dist/features/layout/index.js +9 -1
  355. package/dist/features/layout/useCtaReveal.d.ts +24 -0
  356. package/dist/features/layout/useCtaReveal.js +82 -0
  357. package/dist/features/layout/useHoldToOpen.d.ts +41 -0
  358. package/dist/features/layout/useHoldToOpen.js +84 -0
  359. package/dist/features/lottery/repository/lottery-entry.repository.d.ts +18 -3
  360. package/dist/features/lottery/repository/lottery-entry.repository.js +48 -6
  361. package/dist/features/lottery/schemas/firestore.d.ts +33 -5
  362. package/dist/features/loyalty/api/balance/route.js +1 -1
  363. package/dist/features/loyalty/api/history/route.js +1 -1
  364. package/dist/features/media/MediaImage.js +0 -1
  365. package/dist/features/media/MediaPickerModal.js +7 -1
  366. package/dist/features/media/modals/ImageEditor.js +5 -1
  367. package/dist/features/media/modals/VideoThumbnailSelector.js +17 -1
  368. package/dist/features/media/repository/media-assets.repository.d.ts +19 -0
  369. package/dist/features/media/upload/CameraCapture.js +16 -1
  370. package/dist/features/media/upload/ImageUpload.js +42 -4
  371. package/dist/features/media/upload/MediaUploadField.js +69 -13
  372. package/dist/features/media/upload/downscale-image.d.ts +56 -0
  373. package/dist/features/media/upload/downscale-image.js +150 -0
  374. package/dist/features/messages/components/ConversationThreadView.js +45 -2
  375. package/dist/features/messages/components/MessageSellerButton.d.ts +15 -1
  376. package/dist/features/messages/components/MessageSellerButton.js +10 -2
  377. package/dist/features/messages/schemas/firestore.d.ts +15 -0
  378. package/dist/features/orders/hooks/useOrders.js +4 -2
  379. package/dist/features/orders/repository/orders.repository.d.ts +15 -4
  380. package/dist/features/orders/repository/orders.repository.js +52 -20
  381. package/dist/features/orders/schemas/firestore.d.ts +15 -4
  382. package/dist/features/orders/schemas/index.d.ts +8 -8
  383. package/dist/features/orders/types/index.d.ts +2 -2
  384. package/dist/features/payments/repository/payments.repository.js +2 -2
  385. package/dist/features/payments/repository/payout.repository.d.ts +23 -6
  386. package/dist/features/payments/repository/payout.repository.js +63 -23
  387. package/dist/features/payments/repository/saved-payment-methods.repository.d.ts +17 -6
  388. package/dist/features/payments/repository/saved-payment-methods.repository.js +59 -11
  389. package/dist/features/payments/schemas/firestore.d.ts +14 -3
  390. package/dist/features/payments/schemas/saved-methods-firestore.d.ts +12 -1
  391. package/dist/features/pre-orders/api/[slug]/route.js +1 -1
  392. package/dist/features/pre-orders/api/admin/route.js +1 -1
  393. package/dist/features/pre-orders/api/route.js +1 -1
  394. package/dist/features/pre-orders/repository/pre-orders.repository.d.ts +3 -3
  395. package/dist/features/pre-orders/repository/pre-orders.repository.js +6 -6
  396. package/dist/features/products/api/[id]/route.js +1 -1
  397. package/dist/features/products/components/ListingBottomActions.js +4 -0
  398. package/dist/features/products/components/ProductDetailPageView.js +2 -1
  399. package/dist/features/products/components/ProductGalleryClient.js +2 -2
  400. package/dist/features/products/components/ProductGrid.js +12 -1
  401. package/dist/features/products/components/index.d.ts +0 -2
  402. package/dist/features/products/components/index.js +0 -1
  403. package/dist/features/products/config/listing-type-listing-config.d.ts +0 -3
  404. package/dist/features/products/config/listing-type-listing-config.js +27 -2
  405. package/dist/features/products/constants/listing-tabs.d.ts +9 -0
  406. package/dist/features/products/constants/listing-tabs.js +3 -2
  407. package/dist/features/products/hooks/useProducts.js +2 -2
  408. package/dist/features/products/repository/products.repository.js +13 -1
  409. package/dist/features/products/schemas/index.d.ts +2 -2
  410. package/dist/features/products/types/index.d.ts +1 -1
  411. package/dist/features/promotions/api/route.js +1 -1
  412. package/dist/features/reviews/actions/review-actions.d.ts +6 -6
  413. package/dist/features/reviews/actions/review-actions.js +22 -8
  414. package/dist/features/reviews/components/ReviewDetailPageView.js +13 -1
  415. package/dist/features/reviews/components/ReviewsIndexPageView.js +21 -4
  416. package/dist/features/reviews/repository/reviews.repository.d.ts +19 -7
  417. package/dist/features/reviews/repository/reviews.repository.js +63 -12
  418. package/dist/features/reviews/schemas/firestore.d.ts +13 -2
  419. package/dist/features/reviews/schemas/index.d.ts +2 -2
  420. package/dist/features/scams/actions/scam-actions.js +16 -4
  421. package/dist/features/search/components/SearchResultsPageView.js +2 -1
  422. package/dist/features/search/hooks/useSearchIndex.d.ts +34 -0
  423. package/dist/features/search/hooks/useSearchIndex.js +172 -0
  424. package/dist/features/search/repository/search.repository.js +2 -2
  425. package/dist/features/seller/actions/offer-actions.d.ts +5 -5
  426. package/dist/features/seller/actions/offer-actions.js +38 -8
  427. package/dist/features/seller/actions/seller-actions.js +34 -7
  428. package/dist/features/seller/api/coupons/route.js +1 -1
  429. package/dist/features/seller/api/products/route.js +1 -1
  430. package/dist/features/seller/api/store/route.js +1 -1
  431. package/dist/features/seller/components/SellerBidsView.js +1 -1
  432. package/dist/features/seller/components/SellerCouponsView.js +1 -1
  433. package/dist/features/seller/components/SellerListingTypeView.js +9 -1
  434. package/dist/features/seller/components/SellerOrdersView.js +1 -1
  435. package/dist/features/seller/components/SellerPayoutSettingsView.js +0 -1
  436. package/dist/features/seller/components/SellerPayoutsView.js +1 -1
  437. package/dist/features/seller/components/SellerProductShell.js +0 -1
  438. package/dist/features/seller/components/SellerProductsView.js +1 -1
  439. package/dist/features/seller/components/SellerShippingView.js +0 -1
  440. package/dist/features/seller/components/SellerStorefrontView.js +0 -1
  441. package/dist/features/seller/components/index.d.ts +0 -4
  442. package/dist/features/seller/components/index.js +0 -2
  443. package/dist/features/seller/repository/offer.repository.d.ts +15 -3
  444. package/dist/features/seller/repository/offer.repository.js +43 -7
  445. package/dist/features/seller/schemas/firestore.d.ts +14 -3
  446. package/dist/features/seller/schemas/index.d.ts +4 -4
  447. package/dist/features/seller/schemas/order-forms.d.ts +39 -0
  448. package/dist/features/seller/schemas/order-forms.js +37 -0
  449. package/dist/features/shell/FormShell.js +6 -2
  450. package/dist/features/shell/QuickFormDrawer.js +15 -1
  451. package/dist/features/shipments/components/AdminShipmentEditorView.js +0 -1
  452. package/dist/features/shipments/components/AdminShipmentsView.js +1 -1
  453. package/dist/features/sticker-trace/components/StickerCommitPanel.d.ts +30 -0
  454. package/dist/features/sticker-trace/components/StickerCommitPanel.js +93 -0
  455. package/dist/features/sticker-trace/components/StickerPrintPanel.d.ts +33 -0
  456. package/dist/features/sticker-trace/components/StickerPrintPanel.js +104 -0
  457. package/dist/features/sticker-trace/components/StickerRetryPanel.d.ts +20 -0
  458. package/dist/features/sticker-trace/components/StickerRetryPanel.js +128 -0
  459. package/dist/features/sticker-trace/components/StickerRunHistoryPanel.d.ts +45 -0
  460. package/dist/features/sticker-trace/components/StickerRunHistoryPanel.js +84 -0
  461. package/dist/features/sticker-trace/components/StickerTraceStudio.d.ts +27 -0
  462. package/dist/features/sticker-trace/components/StickerTraceStudio.js +171 -0
  463. package/dist/features/sticker-trace/constants/help-content.d.ts +23 -0
  464. package/dist/features/sticker-trace/constants/help-content.js +172 -0
  465. package/dist/features/sticker-trace/hooks/useLiveTrace.d.ts +27 -0
  466. package/dist/features/sticker-trace/hooks/useLiveTrace.js +160 -0
  467. package/dist/features/sticker-trace/hooks/useStickerTraceProgress.d.ts +22 -0
  468. package/dist/features/sticker-trace/hooks/useStickerTraceProgress.js +106 -0
  469. package/dist/features/sticker-trace/repository/sticker-sheets.repository.d.ts +113 -0
  470. package/dist/features/sticker-trace/repository/sticker-sheets.repository.js +146 -0
  471. package/dist/features/sticker-trace/repository/sticker-trace-runs.repository.d.ts +132 -0
  472. package/dist/features/sticker-trace/repository/sticker-trace-runs.repository.js +174 -0
  473. package/dist/features/sticker-trace/schemas/firestore.d.ts +248 -0
  474. package/dist/features/sticker-trace/schemas/firestore.js +79 -0
  475. package/dist/features/sticker-trace/server.d.ts +8 -0
  476. package/dist/features/sticker-trace/server.js +51 -0
  477. package/dist/features/stores/actions/store-query-actions.d.ts +2 -2
  478. package/dist/features/stores/actions/store-query-actions.js +7 -2
  479. package/dist/features/stores/api/[storeSlug]/auctions/route.js +3 -3
  480. package/dist/features/stores/api/[storeSlug]/products/route.js +3 -3
  481. package/dist/features/stores/api/[storeSlug]/reviews/route.js +1 -1
  482. package/dist/features/stores/api/[storeSlug]/route.js +1 -1
  483. package/dist/features/stores/components/StoreNavTabs.js +17 -2
  484. package/dist/features/stores/manifest.js +8 -4
  485. package/dist/features/support/repository/support.repository.d.ts +14 -3
  486. package/dist/features/support/repository/support.repository.js +93 -13
  487. package/dist/features/support/schemas/firestore.d.ts +16 -5
  488. package/dist/features/tester/seed-data/authored/admin__events-raffles-spin.js +61 -19
  489. package/dist/features/tester/seed-data/authored/buying__browsing-search.js +19 -3
  490. package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.d.ts +2 -0
  491. package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.js +243 -0
  492. package/dist/features/tester/seed-data/authored/content-discovery__events.js +36 -10
  493. package/dist/features/tester/seed-data/authored/content-discovery__overflowing-pill-rows.d.ts +2 -0
  494. package/dist/features/tester/seed-data/authored/content-discovery__overflowing-pill-rows.js +209 -0
  495. package/dist/features/tester/seed-data/authored/design-ux__header-brand-mark-centring.d.ts +2 -0
  496. package/dist/features/tester/seed-data/authored/design-ux__header-brand-mark-centring.js +90 -0
  497. package/dist/features/tester/seed-data/authored/design-ux__header-controls-and-messages.d.ts +2 -0
  498. package/dist/features/tester/seed-data/authored/design-ux__header-controls-and-messages.js +85 -0
  499. package/dist/features/tester/seed-data/authored/index.js +10 -0
  500. package/dist/features/tester/seed-data/authored/selling__media-limits.js +19 -17
  501. package/dist/features/tester/seed-data/authored/selling__product-upload-details.js +10 -5
  502. package/dist/features/tester/seed-data/authored/tools__sticker-tracer.d.ts +2 -0
  503. package/dist/features/tester/seed-data/authored/tools__sticker-tracer.js +283 -0
  504. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +235 -22
  505. package/dist/index.d.ts +10 -23
  506. package/dist/index.js +27 -19
  507. package/dist/next/api/routeHandler.js +9 -0
  508. package/dist/next/routing/require-record.d.ts +13 -0
  509. package/dist/next/routing/require-record.js +62 -0
  510. package/dist/next/routing/route-map.d.ts +4 -4
  511. package/dist/next/routing/route-map.js +25 -3
  512. package/dist/providers/db-firebase/base.d.ts +4 -2
  513. package/dist/providers/db-firebase/base.js +21 -5
  514. package/dist/providers/db-firebase/base.repository.d.ts +11 -9
  515. package/dist/providers/db-firebase/base.repository.js +19 -0
  516. package/dist/providers/db-firebase/rtdb-paths.d.ts +12 -0
  517. package/dist/providers/db-firebase/rtdb-paths.js +12 -0
  518. package/dist/react/ErrorBoundary.js +6 -1
  519. package/dist/react/hooks/realtime-event-constants.d.ts +1 -0
  520. package/dist/react/hooks/realtime-event-constants.js +8 -0
  521. package/dist/react/hooks/useEntityDelete.js +5 -1
  522. package/dist/react/hooks/useMessage.js +5 -1
  523. package/dist/repositories/index.d.ts +2 -2
  524. package/dist/repositories/index.js +6 -1
  525. package/dist/schemas/registry.d.ts +13 -20
  526. package/dist/schemas/registry.js +31 -14
  527. package/dist/schemas/webhooks/google-oauth.d.ts +2 -2
  528. package/dist/security/encrypted.d.ts +117 -0
  529. package/dist/security/encrypted.js +100 -0
  530. package/dist/security/index.d.ts +5 -2
  531. package/dist/security/index.js +16 -2
  532. package/dist/security/pii-accessors.d.ts +71 -0
  533. package/dist/security/pii-accessors.js +150 -0
  534. package/dist/security/pii-encrypt.d.ts +0 -8
  535. package/dist/security/pii-encrypt.js +22 -15
  536. package/dist/security/pii-mask.d.ts +18 -0
  537. package/dist/security/pii-mask.js +27 -0
  538. package/dist/seed/_helpers/search-txt-wrappers.d.ts +6 -6
  539. package/dist/seed/_helpers/search-txt-wrappers.js +22 -0
  540. package/dist/seed/addresses-seed-data.d.ts +2 -2
  541. package/dist/seed/authenticity-knowledge-seed-data.d.ts +34 -0
  542. package/dist/seed/authenticity-knowledge-seed-data.js +1277 -0
  543. package/dist/seed/bids-seed-data.d.ts +2 -2
  544. package/dist/seed/bids-seed-data.js +23 -2
  545. package/dist/seed/events-seed-data.d.ts +2 -2
  546. package/dist/seed/events-seed-data.js +5 -0
  547. package/dist/seed/faq-seed-data.js +175 -5
  548. package/dist/seed/homepage-sections-seed-data.js +39 -23
  549. package/dist/seed/index.d.ts +1 -0
  550. package/dist/seed/index.js +1 -0
  551. package/dist/seed/lottery-entries-seed-data.d.ts +2 -2
  552. package/dist/seed/offers-seed-data.d.ts +2 -2
  553. package/dist/seed/offers-seed-data.js +1 -1
  554. package/dist/seed/orders-seed-data.d.ts +2 -2
  555. package/dist/seed/payouts-seed-data.d.ts +2 -2
  556. package/dist/seed/payouts-seed-data.js +1 -1
  557. package/dist/seed/reviews-seed-data.d.ts +1 -2
  558. package/dist/seed/seed-purpose.js +7 -0
  559. package/dist/seed/sessions-seed-data.d.ts +2 -2
  560. package/dist/seed/sessions-seed-data.js +5 -0
  561. package/dist/seed/site-settings-seed-data.js +1 -1
  562. package/dist/seed/support-tickets-seed-data.d.ts +2 -2
  563. package/dist/seed/support-tickets-seed-data.js +1 -1
  564. package/dist/seed/users-seed-data.d.ts +2 -2
  565. package/dist/seed/users-seed-data.js +1 -1
  566. package/dist/seo/json-ld.js +5 -1
  567. package/dist/server.d.ts +18 -3
  568. package/dist/server.js +59 -3
  569. package/dist/styles.css +237 -1
  570. package/dist/tailwind-utilities.css +1 -1
  571. package/dist/ui/components/Button.js +7 -1
  572. package/dist/ui/components/FilterChipGroup.d.ts +11 -0
  573. package/dist/ui/components/FilterChipGroup.js +1 -1
  574. package/dist/ui/components/ImageGallery.js +6 -1
  575. package/dist/ui/components/ListingLayout.js +14 -8
  576. package/dist/ui/components/OverflowRow.d.ts +92 -0
  577. package/dist/ui/components/OverflowRow.js +203 -0
  578. package/dist/ui/components/OverflowRow.style.css +235 -0
  579. package/dist/ui/components/RecordDetailModal.js +14 -1
  580. package/dist/ui/components/RowActionMenu.js +5 -1
  581. package/dist/ui/components/SideDrawer.js +5 -1
  582. package/dist/ui/components/SideModal.js +9 -1
  583. package/dist/ui/components/TabBarShell.d.ts +12 -1
  584. package/dist/ui/components/TabBarShell.js +3 -2
  585. package/dist/ui/components/Tabs.js +36 -24
  586. package/dist/ui/components/Toast.d.ts +3 -24
  587. package/dist/ui/components/Toast.js +2 -19
  588. package/dist/ui/components/TopBannerPortal.d.ts +15 -0
  589. package/dist/ui/components/TopBannerPortal.js +19 -0
  590. package/dist/ui/components/UnsavedChangesModal.js +5 -1
  591. package/dist/ui/components/index.style.css +1 -0
  592. package/dist/ui/components/row-collapse.d.ts +15 -0
  593. package/dist/ui/components/row-collapse.js +127 -0
  594. package/dist/ui/components/toast-context.d.ts +63 -0
  595. package/dist/ui/components/toast-context.js +48 -0
  596. package/dist/ui/components/top-banner-slot.d.ts +37 -0
  597. package/dist/ui/components/top-banner-slot.js +45 -0
  598. package/dist/ui/icons/icon-registry.d.ts +6 -0
  599. package/dist/ui/icons/icon-registry.js +17 -1
  600. package/dist/ui/index.d.ts +2 -0
  601. package/dist/ui/index.js +1 -0
  602. package/dist/utils/array.helper.d.ts +2 -2
  603. package/dist/utils/array.helper.js +5 -5
  604. package/dist/utils/id-generators.d.ts +6 -0
  605. package/dist/utils/id-generators.js +10 -0
  606. package/dist/utils/media-url.js +0 -2
  607. package/dist/utils/search-txt-builders.d.ts +28 -4
  608. package/dist/utils/search-txt-builders.js +41 -1
  609. package/dist/validation/schemas.d.ts +8 -8
  610. package/package.json +6 -2
  611. package/scripts/seed-cli.mjs +3 -0
  612. package/dist/features/account/components/UserAddressesView.d.ts +0 -13
  613. package/dist/features/account/components/UserAddressesView.js +0 -5
  614. package/dist/features/account/components/UserNotificationsView.d.ts +0 -15
  615. package/dist/features/account/components/UserNotificationsView.js +0 -12
  616. package/dist/features/account/components/UserSettingsView.d.ts +0 -16
  617. package/dist/features/account/components/UserSettingsView.js +0 -13
  618. package/dist/features/account/components/UserSupportView.d.ts +0 -3
  619. package/dist/features/account/components/UserSupportView.js +0 -166
  620. package/dist/features/admin/components/DemoSeedView.d.ts +0 -11
  621. package/dist/features/admin/components/DemoSeedView.js +0 -5
  622. package/dist/features/auth/components/AuthStatusPanel.d.ts +0 -10
  623. package/dist/features/auth/components/AuthStatusPanel.js +0 -22
  624. package/dist/features/categories/components/CategoryProductsView.d.ts +0 -45
  625. package/dist/features/categories/components/CategoryProductsView.js +0 -21
  626. package/dist/features/homepage/components/HowItWorksInfoView.d.ts +0 -36
  627. package/dist/features/homepage/components/HowItWorksInfoView.js +0 -10
  628. package/dist/features/layout/BottomActions.d.ts +0 -1
  629. package/dist/features/layout/BottomActions.js +0 -311
  630. package/dist/features/products/components/ProductsView.d.ts +0 -6
  631. package/dist/features/products/components/ProductsView.js +0 -5
  632. package/dist/features/seller/components/SellerStoreView.d.ts +0 -8
  633. package/dist/features/seller/components/SellerStoreView.js +0 -8
@@ -1,7 +1,7 @@
1
1
  import { BaseRepository, getFirestoreCount, prepareForFirestore, parseSieveDateValue, } from "../../../providers/db-firebase/index.js";
2
2
  import { NotFoundError } from "../../../errors/index.js";
3
3
  import { REVIEW_MAX_RATING, REVIEW_MIN_RATING } from "../../../_internal/shared/features/reviews/config.js";
4
- import { decryptPiiFields, REVIEW_PII_FIELDS, REVIEW_PII_INDEX_MAP, } from "../../../security/index.js";
4
+ import { maskPii, revealPii, REVIEW_PII_FIELDS, REVIEW_PII_INDEX_MAP, } from "../../../security/index.js";
5
5
  import { createReviewId, REVIEW_COLLECTION, } from "../schemas/index.js";
6
6
  import { buildReviewSearchTxt } from "../../../utils/search-txt-builders.js";
7
7
  import { planSearchTxt, beginSearchWindow, emptySearchResult, } from "../../../utils/search-txt-query.js";
@@ -35,12 +35,23 @@ class ReviewRepository extends BaseRepository {
35
35
  this.piiFields = REVIEW_PII_FIELDS;
36
36
  this.piiIndexMap = REVIEW_PII_INDEX_MAP;
37
37
  }
38
- decryptSieveResult(result) {
38
+ /*
39
+ * 🛑 Was `decryptSieveResult`, an UNCONDITIONAL decrypt on the list path.
40
+ *
41
+ * Same defect as the `mapDoc` one and invisible to R3, which only looks at
42
+ * `mapDoc` — a repository can leak plaintext through any read path, and this
43
+ * one did it for all three list methods. Renamed rather than deleted because
44
+ * these three callers are public-facing and genuinely need a displayable
45
+ * name, so they now take the MASKED form: "R*** K***" rather than the full
46
+ * name a scraper could harvest alongside every purchase it describes.
47
+ *
48
+ * A caller that needs the real name calls `revealReview` on the row it
49
+ * actually needs, which is one row rather than a page of fifty.
50
+ */
51
+ maskSieveResult(result) {
39
52
  return {
40
53
  ...result,
41
- items: result.items.map((item) => decryptPiiFields(item, [
42
- ...REVIEW_PII_FIELDS,
43
- ])),
54
+ items: this.maskedReviews(result.items),
44
55
  };
45
56
  }
46
57
  mapDoc(snap) {
@@ -52,13 +63,53 @@ class ReviewRepository extends BaseRepository {
52
63
  // forgotten call site away from a leak. `voteHelpful` reads the raw snapshot
53
64
  // inside its transaction and is unaffected.
54
65
  const { helpfulVoterIds: _voters, ...rest } = raw;
55
- return decryptPiiFields(rest, [
56
- ...REVIEW_PII_FIELDS,
57
- ]);
66
+ /*
67
+ * 🛑 The DECRYPT is gone; the STRIP stays, and the distinction matters.
68
+ *
69
+ * This is the one R3 subject whose `mapDoc` did something besides decrypt,
70
+ * so the override survives — which is also why the audit's rule had to be
71
+ * scoped to mapDoc's own body rather than "a decrypt call anywhere in this
72
+ * file": the named accessors below call one, and a file-level test would
73
+ * report this correctly-converted repository as unconverted forever.
74
+ *
75
+ * `userName` is now ciphertext to every caller. `maskPublicReview` masks
76
+ * it for the public list, and it refuses ciphertext by design — so that
77
+ * path goes through `maskedReview` instead, which decrypts first.
78
+ */
79
+ return rest;
58
80
  }
59
- async create(input) {
81
+ /** Plaintext PII. **Opt-in and named** — shows up in review and in a grep. */
82
+ revealReview(doc) {
83
+ return revealPii(doc, REVIEW_PII_FIELDS);
84
+ }
85
+ /** As `revealReview`, for a list read. */
86
+ revealReviews(docs) {
87
+ return docs.map((d) => this.revealReview(d));
88
+ }
89
+ /**
90
+ * Masked PII — **the default for any public surface.** Decrypts first, then
91
+ * masks: `maskName` returns "Anonymous" for a ciphertext input by design, so
92
+ * handing it a stored `userName` would anonymise every reviewer.
93
+ */
94
+ maskedReview(doc) {
95
+ return maskPii(doc, REVIEW_PII_FIELDS);
96
+ }
97
+ /** As `maskedReview`, for a list read. */
98
+ maskedReviews(docs) {
99
+ return docs.map((d) => this.maskedReview(d));
100
+ }
101
+ /*
102
+ * 🛑 NOT an `override`. `BaseRepository.create` promises to accept the
103
+ * CIPHERTEXT shape; this accepts PLAINTEXT and encrypts, and `string` vs
104
+ * `Encrypted<string>` is incompatible in both directions, so an override is a
105
+ * TS2416 either way — correctly, because the signatures disagree about what
106
+ * the caller holds. Returns `ReviewPlain`: it echoes the input rather than
107
+ * re-reading.
108
+ */
109
+ async createReview(input) {
60
110
  const firstName = input.userName.split(" ")[0] || input.userName;
61
111
  const id = createReviewId(input.productTitle, firstName, new Date());
112
+ // Plain in, ciphertext out — the write hook encrypts below.
62
113
  const reviewData = {
63
114
  ...input,
64
115
  helpfulCount: 0,
@@ -334,7 +385,7 @@ class ReviewRepository extends BaseRepository {
334
385
  defaultPageSize: 10,
335
386
  maxPageSize: 50,
336
387
  });
337
- return this.decryptSieveResult(result);
388
+ return this.maskSieveResult(result);
338
389
  }
339
390
  async listForStore(storeId, model) {
340
391
  const baseQuery = this.getCollection().where(REVIEW_FIELDS.STORE_ID, "==", storeId);
@@ -343,7 +394,7 @@ class ReviewRepository extends BaseRepository {
343
394
  defaultPageSize: 10,
344
395
  maxPageSize: 100,
345
396
  });
346
- return this.decryptSieveResult(result);
397
+ return this.maskSieveResult(result);
347
398
  }
348
399
  /**
349
400
  * Derived on every write path via `applyWriteHooks`.
@@ -376,7 +427,7 @@ class ReviewRepository extends BaseRepository {
376
427
  });
377
428
  // Refine BEFORE decrypting: the refine reads `searchTxt`, which is never
378
429
  // encrypted, and decrypting rows that are about to be dropped is waste.
379
- return this.decryptSieveResult(win.finish(result));
430
+ return this.maskSieveResult(win.finish(result));
380
431
  }
381
432
  }
382
433
  ReviewRepository.SIEVE_FIELDS = {
@@ -4,6 +4,7 @@
4
4
  import type { ReviewStatus } from "../types";
5
5
  import type { BaseDocument } from "../../../_internal/shared/types/base-document";
6
6
  import type { ListingType } from "../../products/types/index";
7
+ import type { Encrypted, Plaintext } from "../../../security/encrypted";
7
8
  /** Runtime-accessible review status values — use instead of bare string literals. */
8
9
  export declare const ReviewStatusValues: {
9
10
  readonly PENDING: "pending";
@@ -17,6 +18,16 @@ export interface ReviewVideoField {
17
18
  trimStart?: number;
18
19
  trimEnd?: number;
19
20
  }
21
+ /**
22
+ * `ReviewDocument` with its PII as plain `string` — what the named repository
23
+ * accessors return, and what a WRITE path accepts (the repository encrypts).
24
+ *
25
+ * `Plaintext<T>` is the one definition of this shape; see `security/encrypted.ts`.
26
+ * It is deliberately NOT distinguishable from a MASKED value — `maskPii`
27
+ * returns plain strings too, and no type can express "these characters are
28
+ * asterisks". The distinction is which named method you called.
29
+ */
30
+ export type ReviewPlain = Plaintext<ReviewDocument>;
20
31
  export interface ReviewDocument extends BaseDocument {
21
32
  /** Normalized edge-n-gram search field — see appkit/src/utils/search-txt.ts. */
22
33
  searchTxt?: string[];
@@ -29,7 +40,7 @@ export interface ReviewDocument extends BaseDocument {
29
40
  userId: string;
30
41
  /** Firestore document ID of the reviewer (slug like `user-mohsin-c`). Populated on create; used to build profile links. */
31
42
  userSlug?: string;
32
- userName: string;
43
+ userName: Encrypted<string>;
33
44
  userAvatar?: string;
34
45
  rating: number;
35
46
  title: string;
@@ -67,7 +78,7 @@ export declare const REVIEW_INDEXED_FIELDS: readonly ["searchTxt", "productId",
67
78
  export declare const DEFAULT_REVIEW_DATA: Partial<ReviewDocument>;
68
79
  export declare const REVIEW_PUBLIC_FIELDS: readonly ["id", "productId", "userName", "userAvatar", "rating", "title", "comment", "helpfulCount", "verified", "images", "createdAt"];
69
80
  export declare const REVIEW_UPDATABLE_FIELDS: readonly ["rating", "title", "comment", "images"];
70
- export type ReviewCreateInput = Omit<ReviewDocument, "id" | "createdAt" | "updatedAt" | "helpfulCount" | "reportCount" | "moderatorId" | "moderatorNote" | "approvedAt" | "rejectedAt">;
81
+ export type ReviewCreateInput = Omit<ReviewPlain, "id" | "createdAt" | "updatedAt" | "helpfulCount" | "reportCount" | "moderatorId" | "moderatorNote" | "approvedAt" | "rejectedAt">;
71
82
  export type ReviewUpdateInput = Partial<Pick<ReviewDocument, (typeof REVIEW_UPDATABLE_FIELDS)[number]>>;
72
83
  export type ReviewModerationInput = {
73
84
  status: ReviewStatus;
@@ -367,20 +367,20 @@ export declare const reviewListParamsSchema: z.ZodObject<{
367
367
  sort?: string | undefined;
368
368
  status?: "pending" | "approved" | "rejected" | undefined;
369
369
  page?: number | undefined;
370
- perPage?: number | undefined;
371
370
  storeId?: string | undefined;
372
371
  rating?: number | undefined;
373
372
  featured?: boolean | undefined;
374
373
  productId?: string | undefined;
375
374
  userId?: string | undefined;
375
+ perPage?: number | undefined;
376
376
  }, {
377
377
  sort?: string | undefined;
378
378
  status?: "pending" | "approved" | "rejected" | undefined;
379
379
  page?: number | undefined;
380
- perPage?: number | undefined;
381
380
  storeId?: string | undefined;
382
381
  rating?: number | undefined;
383
382
  featured?: boolean | undefined;
384
383
  productId?: string | undefined;
385
384
  userId?: string | undefined;
385
+ perPage?: number | undefined;
386
386
  }>;
@@ -119,13 +119,25 @@ export async function getSellerTrustStatus(storeId) {
119
119
  if (!owner.value)
120
120
  return TRUST_STATUS_CLEAR;
121
121
  const ownerDoc = owner.value;
122
+ /*
123
+ * 🛑 REVEALED — without this, THIS SECURITY CONTROL SILENTLY ALWAYS PASSES.
124
+ *
125
+ * `userRepository` is ciphertext-by-default, while the scam registry's
126
+ * `phones`/`emails` are PLAINTEXT on purpose (decision D1: a victim googles a
127
+ * UPI id before paying, so SEO is the feature). Comparing ciphertext against
128
+ * plaintext never matches, so every lookup returned zero rows and
129
+ * `sellerTrustStatus` answered CLEAR for every seller — including ones
130
+ * already in the registry. No error, no log, and the one check a buyer
131
+ * relies on degraded to a constant.
132
+ */
133
+ const ownerPlain = userRepository.revealUser(ownerDoc);
122
134
  const lookups = [];
123
- if (ownerDoc.phoneNumber) {
124
- const phone = ownerDoc.phoneNumber;
135
+ if (ownerPlain.phoneNumber) {
136
+ const phone = ownerPlain.phoneNumber;
125
137
  lookups.push(() => scammerRepository.findByContactField("phones", phone));
126
138
  }
127
- if (ownerDoc.email) {
128
- const email = ownerDoc.email;
139
+ if (ownerPlain.email) {
140
+ const email = ownerPlain.email;
129
141
  lookups.push(() => scammerRepository.findByContactField("emails", email));
130
142
  }
131
143
  if (lookups.length === 0)
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ROUTES } from "../../../next/routing/route-map.js";
2
3
  import { Section, Container, Stack, Row, Div, Heading, Text, Span, TextLink } from "../../../ui/index.js";
3
4
  export function SearchResultsPageView({ result, renderSearchInput, }) {
4
5
  const { q, terms, groups, totalHits } = result;
@@ -17,5 +18,5 @@ export function SearchResultsPageView({ result, renderSearchInput, }) {
17
18
  const normalisedAway = hasQuery && terms.length === 0;
18
19
  return (_jsx(Section, { padding: "page", children: _jsx(Container, { children: _jsxs(Stack, { gap: "loose", children: [_jsxs(Stack, { gap: "xs", children: [_jsx(Heading, { level: 1, children: hasQuery ? `Search: ${q}` : "Search" }), hasQuery && !normalisedAway && (_jsx(Text, { color: "muted", size: "sm", children: totalHits === 0
19
20
  ? "Nothing matched."
20
- : `${totalHits}${groups.some((g) => g.truncated) ? "+" : ""} result${totalHits === 1 ? "" : "s"} across ${groups.length} section${groups.length === 1 ? "" : "s"}.` }))] }), renderSearchInput?.(), !hasQuery && (_jsx(Text, { color: "muted", children: "Search listings, categories, brands, stores, articles and help pages at once." })), normalisedAway && (_jsx(Text, { color: "muted", children: "That search had no searchable words in it. Try a product, part or category name." })), groups.map((group) => (_jsxs(Stack, { gap: "sm", children: [_jsxs(Row, { justify: "between", align: "center", wrap: true, gap: "sm", children: [_jsxs(Heading, { level: 2, size: "lg", children: [group.label, group.truncated && (_jsxs(Span, { size: "sm", color: "muted", children: [" ", "(", group.hits.length, "+)"] }))] }), _jsxs(TextLink, { href: group.moreHref, children: ["See all ", group.label.toLowerCase(), " \u2192"] })] }), _jsx(Stack, { gap: "xs", children: group.hits.map((hit) => (_jsxs(Div, { surface: "card", padding: "sm", rounded: "md", children: [_jsx(TextLink, { href: hit.href, children: hit.title }), hit.detail && (_jsx(Text, { size: "xs", color: "muted", children: hit.detail }))] }, `${group.key}-${hit.id}`))) })] }, group.key))), hasQuery && !normalisedAway && totalHits === 0 && (_jsxs(Stack, { gap: "xs", children: [_jsxs(Text, { color: "muted", children: ["No listings, categories, brands, stores, articles or help pages matched \u201C", q, "\u201D."] }), _jsx(TextLink, { href: "/products", children: "Browse all listings \u2192" })] }))] }) }) }));
21
+ : `${totalHits}${groups.some((g) => g.truncated) ? "+" : ""} result${totalHits === 1 ? "" : "s"} across ${groups.length} section${groups.length === 1 ? "" : "s"}.` }))] }), renderSearchInput?.(), !hasQuery && (_jsx(Text, { color: "muted", children: "Search listings, categories, brands, stores, articles and help pages at once." })), normalisedAway && (_jsx(Text, { color: "muted", children: "That search had no searchable words in it. Try a product, part or category name." })), groups.map((group) => (_jsxs(Stack, { gap: "sm", children: [_jsxs(Row, { justify: "between", align: "center", wrap: true, gap: "sm", children: [_jsxs(Heading, { level: 2, size: "lg", children: [group.label, group.truncated && (_jsxs(Span, { size: "sm", color: "muted", children: [" ", "(", group.hits.length, "+)"] }))] }), _jsxs(TextLink, { href: group.moreHref, children: ["See all ", group.label.toLowerCase(), " \u2192"] })] }), _jsx(Stack, { gap: "xs", children: group.hits.map((hit) => (_jsxs(Div, { surface: "card", padding: "sm", rounded: "md", children: [_jsx(TextLink, { href: hit.href, children: hit.title }), hit.detail && (_jsx(Text, { size: "xs", color: "muted", children: hit.detail }))] }, `${group.key}-${hit.id}`))) })] }, group.key))), hasQuery && !normalisedAway && totalHits === 0 && (_jsxs(Stack, { gap: "xs", children: [_jsxs(Text, { color: "muted", children: ["No listings, categories, brands, stores, articles or help pages matched \u201C", q, "\u201D."] }), _jsx(TextLink, { href: ROUTES.PUBLIC.PRODUCTS, children: "Browse all listings \u2192" })] }))] }) }) }));
21
22
  }
@@ -0,0 +1,34 @@
1
+ import { type SearchIndexArtifact } from "../../../_internal/shared/search/index-record";
2
+ import { type PreparedIndex } from "../../../_internal/shared/search/match";
3
+ export type SearchIndexStatus = "idle" | "loading" | "ready" | "failed" | "disabled";
4
+ export interface LoadedSearchIndex {
5
+ readonly artifact: SearchIndexArtifact;
6
+ readonly prepared: PreparedIndex[];
7
+ readonly version: number;
8
+ readonly builtAt: string;
9
+ }
10
+ export interface SearchIndexState {
11
+ readonly status: SearchIndexStatus;
12
+ readonly index: LoadedSearchIndex | null;
13
+ /** Present on `failed`. Short, for a log line — never rendered to a user. */
14
+ readonly reason: string | null;
15
+ }
16
+ /** Reset hook, for the verify script and for a kill-switch flip mid-session. */
17
+ export declare function __resetSearchIndexForTests(): void;
18
+ /** Start the load if it has not started. Idempotent; safe to call per render. */
19
+ export declare function ensureSearchIndex(): Promise<LoadedSearchIndex | null>;
20
+ export interface UseSearchIndexOptions {
21
+ /**
22
+ * Flip true when the user shows intent — focus, or the first keypress.
23
+ * False keeps the hook in `idle` and issues no request at all.
24
+ */
25
+ active: boolean;
26
+ /**
27
+ * `siteSettings.search?.indexEnabled`. 🛑 Read as `!== false`, so an
28
+ * undefined settings object — a failed fetch, a stale cached response from
29
+ * before the field existed — leaves search WORKING. Only an explicit
30
+ * `false` disables it.
31
+ */
32
+ indexEnabled?: boolean;
33
+ }
34
+ export declare function useSearchIndex({ active, indexEnabled, }: UseSearchIndexOptions): SearchIndexState;
@@ -0,0 +1,172 @@
1
+ "use client";
2
+ /*
3
+ * WHY: Fetch the public search artifact exactly once per page session and
4
+ * hand every caller the SAME prepared copy, so typing costs nothing.
5
+ * WHAT: A module-level singleton loader plus the hook that exposes its state.
6
+ *
7
+ * ## 🛑 ONE fetch and ONE `prepareIndex`, per page session, shared
8
+ *
9
+ * The artifact is ~420 KB and `prepareIndex` normalises ~3,700 titles and
10
+ * details. Both are cheap once and ruinous per component: the header
11
+ * dropdown, `/search`, `/parts` and two `/tools` surfaces all want the same
12
+ * index, and a hook that loaded per mount would download it five times and
13
+ * re-normalise 18,500 strings. The singleton lives at module scope — not in a
14
+ * React context — because a context would make every one of those consumers
15
+ * require a provider they cannot guarantee (Root Cause #20), and the data is
16
+ * immutable so there is nothing for a provider to coordinate.
17
+ *
18
+ * ## 🛑 Nothing loads until somebody intends to search
19
+ *
20
+ * `active` gates the fetch, and callers flip it on first focus or first
21
+ * keypress — never on mount. The action-index route states the rule this
22
+ * follows: one request per session, never per keystroke. Firing on mount
23
+ * would put 420 KB on the critical path of every page view for a feature
24
+ * most visits never touch, which is the opposite of the trade this whole
25
+ * design exists to make.
26
+ *
27
+ * ## 🛑 It NEVER stores the artifact in localStorage
28
+ *
29
+ * The service worker holds the bytes, against an `immutable` version-addressed
30
+ * URL. localStorage is synchronous, ~5 MB, shared with everything else the app
31
+ * keeps, and would have to be invalidated by hand on every build. The plan
32
+ * called for keeping the version integer there to skip the manifest hop; that
33
+ * is dropped deliberately, because the manifest is a ~100-byte 60s-cached
34
+ * document and a remembered version is wrong exactly when it matters — after
35
+ * a rebuild — at which point it costs a WASTED 420 KB download instead of
36
+ * saving a tiny one.
37
+ *
38
+ * ## Four states, and `loading` is not `empty`
39
+ *
40
+ * Same discipline as `GatedPrice`'s three: a caller must be able to tell "no
41
+ * matches" from "we have not loaded the haystack yet". Rendering an empty
42
+ * state while the index is in flight says "nothing matched" about a question
43
+ * nobody has asked yet.
44
+ *
45
+ * `failed` and `disabled` are also distinct, and both mean *fall back to the
46
+ * server path* rather than *show nothing*.
47
+ *
48
+ * @tag domain:search
49
+ * @tag layer:feature
50
+ * @tag pattern:hook
51
+ * @tag access:client
52
+ * @tag consumers:Search,SearchResultsPageView,/parts,/tools/price-index
53
+ * @tag sideEffects:network
54
+ */
55
+ import * as React from "react";
56
+ import { SEARCH_INDEX_SCHEMA_VERSION, } from "../../../_internal/shared/search/index-record.js";
57
+ import { searchArtifactUrl, searchManifestUrl, } from "../../../_internal/shared/search/artifact-url.js";
58
+ import { prepareIndex } from "../../../_internal/shared/search/match.js";
59
+ import { normalizeError } from "../../../errors/normalize.js";
60
+ /**
61
+ * Read at module scope, exactly as `utils/media-url.ts` does for the same
62
+ * variable. Next inlines `NEXT_PUBLIC_*` at build time, so this is a constant
63
+ * in the bundle rather than a runtime lookup.
64
+ */
65
+ const BUCKET = process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET ?? "";
66
+ /**
67
+ * The singleton. `undefined` until the first caller asks; thereafter the same
68
+ * promise forever, resolving to `null` on any failure.
69
+ *
70
+ * 🛑 Resolving to `null` rather than rejecting is deliberate: a rejected
71
+ * module-scope promise with no attached handler is an unhandled rejection in
72
+ * every tab where nothing happens to be awaiting it yet.
73
+ */
74
+ let inflight;
75
+ let failureReason = null;
76
+ /** Reset hook, for the verify script and for a kill-switch flip mid-session. */
77
+ export function __resetSearchIndexForTests() {
78
+ inflight = undefined;
79
+ failureReason = null;
80
+ }
81
+ async function fetchJson(url, label) {
82
+ /*
83
+ * 🛑 `mode: "cors"`, explicitly, and never `no-cors`.
84
+ *
85
+ * A `no-cors` fetch of a cross-origin object yields an OPAQUE response: the
86
+ * body cannot be read, the status reads as 0, and a 404 is indistinguishable
87
+ * from a successful empty index — which is this feature's single favourite
88
+ * failure mode. The bucket carries a CORS entry for the app origins
89
+ * precisely so this can be `cors` and the status can be real.
90
+ */
91
+ const res = await fetch(url, { mode: "cors", credentials: "omit" });
92
+ if (!res.ok)
93
+ throw new Error(`${label}: HTTP ${res.status}`);
94
+ return (await res.json());
95
+ }
96
+ async function load() {
97
+ try {
98
+ if (!BUCKET)
99
+ throw new Error("NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET is unset");
100
+ const manifest = await fetchJson(searchManifestUrl(BUCKET), "manifest");
101
+ /*
102
+ * 🛑 Refuse a schema this build does not understand, rather than render a
103
+ * half-understood artifact.
104
+ *
105
+ * The tuple is positional. A future `[typeIdx, title, detail, slug,
106
+ * facets, badge]` would parse without error in this build and simply be
107
+ * read wrong — wrong slugs, wrong hrefs, confidently. The version lives
108
+ * in the ENVELOPE and not in the URL for exactly this check; falling back
109
+ * to the server path is always better than being quietly wrong.
110
+ */
111
+ if (manifest.schema !== SEARCH_INDEX_SCHEMA_VERSION) {
112
+ throw new Error(`schema ${manifest.schema} != client ${SEARCH_INDEX_SCHEMA_VERSION}`);
113
+ }
114
+ const artifact = await fetchJson(searchArtifactUrl(BUCKET, manifest.version), "artifact");
115
+ if (artifact.schema !== SEARCH_INDEX_SCHEMA_VERSION) {
116
+ throw new Error(`artifact schema ${artifact.schema} disagrees with its manifest`);
117
+ }
118
+ return {
119
+ artifact,
120
+ // Once, here. See the header, and `prepareIndex`'s own 🛑.
121
+ prepared: [...prepareIndex(artifact)],
122
+ version: artifact.version,
123
+ builtAt: artifact.builtAt,
124
+ };
125
+ }
126
+ catch (err) {
127
+ const n = normalizeError(err);
128
+ /*
129
+ * normalizeError FIRST, before the body touches the value — the project-wide
130
+ * rule, and what audit-catch-normalize is strict-zero about. It also removes
131
+ * the hand-rolled `err instanceof Error ? … : String(err)` narrowing that
132
+ * every catch otherwise reinvents slightly differently, which is the whole
133
+ * reason the helper exists (Root Cause #31).
134
+ */
135
+ failureReason = n.message;
136
+ return null;
137
+ }
138
+ }
139
+ /** Start the load if it has not started. Idempotent; safe to call per render. */
140
+ export function ensureSearchIndex() {
141
+ inflight ?? (inflight = load());
142
+ return inflight;
143
+ }
144
+ export function useSearchIndex({ active, indexEnabled, }) {
145
+ const enabled = indexEnabled !== false;
146
+ const [index, setIndex] = React.useState(null);
147
+ const [settled, setSettled] = React.useState(false);
148
+ React.useEffect(() => {
149
+ if (!active || !enabled || settled)
150
+ return;
151
+ let alive = true;
152
+ void ensureSearchIndex().then((loaded) => {
153
+ if (!alive)
154
+ return;
155
+ setIndex(loaded);
156
+ setSettled(true);
157
+ });
158
+ return () => {
159
+ alive = false;
160
+ };
161
+ }, [active, enabled, settled]);
162
+ const status = !enabled
163
+ ? "disabled"
164
+ : !active
165
+ ? "idle"
166
+ : !settled
167
+ ? "loading"
168
+ : index
169
+ ? "ready"
170
+ : "failed";
171
+ return { status, index, reason: status === "failed" ? failureReason : null };
172
+ }
@@ -43,7 +43,7 @@ export class SearchRepository {
43
43
  : "createdAt",
44
44
  order: query.sort?.startsWith("-") ? "desc" : "asc",
45
45
  page: query.page ?? 1,
46
- perPage: query.pageSize ?? 24,
46
+ pageSize: query.pageSize ?? 24,
47
47
  };
48
48
  const result = await this.repo.findAll(sieveQuery);
49
49
  return {
@@ -51,7 +51,7 @@ export class SearchRepository {
51
51
  q: query.q ?? "",
52
52
  total: result.total,
53
53
  page: result.page,
54
- pageSize: result.perPage,
54
+ pageSize: result.pageSize,
55
55
  totalPages: result.totalPages,
56
56
  hasMore: result.page < result.totalPages,
57
57
  };
@@ -4,7 +4,7 @@
4
4
  * Business logic for the Make-an-Offer feature lifecycle.
5
5
  * Auth, rate-limiting, and input validation are handled by the calling server action.
6
6
  */
7
- import type { OfferDocument } from "../schemas";
7
+ import type { OfferDocument, OfferPlain } from "../schemas";
8
8
  /**
9
9
  * How long an accepted offer stays claimable at its locked price. Shared by the
10
10
  * seller-accept path, the buyer-accepts-counter path, and the expiry sweep so
@@ -28,11 +28,11 @@ export interface BuyerCounterInput {
28
28
  counterAmount: number;
29
29
  buyerNote?: string;
30
30
  }
31
- export declare function makeOffer(userId: string, userEmail: string, input: MakeOfferInput): Promise<OfferDocument>;
31
+ export declare function makeOffer(userId: string, userEmail: string, input: MakeOfferInput): Promise<OfferPlain>;
32
32
  export declare function respondToOffer(userId: string, input: RespondToOfferInput): Promise<OfferDocument>;
33
33
  export declare function acceptCounterOffer(userId: string, offerId: string): Promise<OfferDocument>;
34
- export declare function counterOfferByBuyer(userId: string, userEmail: string, input: BuyerCounterInput): Promise<OfferDocument>;
34
+ export declare function counterOfferByBuyer(userId: string, userEmail: string, input: BuyerCounterInput): Promise<OfferPlain>;
35
35
  export declare function withdrawOffer(userId: string, offerId: string): Promise<void>;
36
- export declare function listBuyerOffers(userId: string): Promise<OfferDocument[]>;
37
- export declare function listSellerOffers(userId: string): Promise<OfferDocument[]>;
36
+ export declare function listBuyerOffers(userId: string): Promise<OfferPlain[]>;
37
+ export declare function listSellerOffers(userId: string): Promise<OfferPlain[]>;
38
38
  export declare function checkoutOffer(userId: string, offerId: string): Promise<CartDocument>;
@@ -12,7 +12,6 @@ import { sendNotification } from "../../admin/actions/notification-actions.js";
12
12
  import { userRepository } from "../../auth/repository/user.repository.js";
13
13
  import { storeRepository } from "../../stores/repository/store.repository.js";
14
14
  import { cartRepository } from "../../cart/repository/cart.repository.js";
15
- import { maskOfferForSeller } from "../../../security/index.js";
16
15
  import { ERROR_MESSAGES, AuthorizationError, ValidationError, NotFoundError, OFFER_ERROR_CODES, } from "../../../errors/index.js";
17
16
  import { canMakeOffer } from "../../../_internal/shared/listing-types/capabilities.js";
18
17
  import { normalizeListingType } from "../../products/utils/listing-type.js";
@@ -122,17 +121,27 @@ export async function makeOffer(userId, userEmail, input) {
122
121
  if (alreadyActive)
123
122
  throw new ValidationError(ERROR_MESSAGES.OFFER.ACTIVE_OFFER_EXISTS);
124
123
  const profile = await userRepository.findById(userId);
124
+ /*
125
+ * 🛑 REVEALED. `createOffer` encrypts `buyerEmail` (`OFFER_PII_FIELDS`), so
126
+ * the ciphertext this read returns would have been encrypted a second time
127
+ * and become permanently unreadable — the seller could never see who made
128
+ * the offer. The sibling `bid-actions.ts:223,481` was fixed for exactly this;
129
+ * this line is the same shape, missed.
130
+ *
131
+ * `userEmail` (the parameter) is already plaintext, so it needs no unwrap.
132
+ */
133
+ const profilePlain = profile ? userRepository.revealUser(profile) : null;
125
134
  const buyerDisplayName = profile?.displayName ?? "Buyer";
126
135
  if (!product.storeId)
127
136
  throw new ValidationError("Product is not associated with a store.");
128
- const offer = await offerRepository.create({
137
+ const offer = await offerRepository.createOffer({
129
138
  productId,
130
139
  productTitle: product.title,
131
140
  productSlug: product.slug,
132
141
  productImageUrl: product.mainImage,
133
142
  buyerUid: userId,
134
143
  buyerName: buyerDisplayName,
135
- buyerEmail: profile?.email ?? userEmail ?? "",
144
+ buyerEmail: profilePlain?.email ?? userEmail ?? "",
136
145
  storeId: product.storeId,
137
146
  storeName: product.storeName ?? "",
138
147
  offerAmount,
@@ -284,14 +293,24 @@ export async function counterOfferByBuyer(userId, userEmail, input) {
284
293
  // single-field equality served by the automatic index.
285
294
  const chainRoot = offer.chainRootOfferId ?? offer.id;
286
295
  const nextRound = (offer.counterRound ?? 1) + 1;
287
- const newOffer = await offerRepository.create({
296
+ /*
297
+ * 🛑 A NINTH double-encryption site, found by the nominal brand.
298
+ *
299
+ * A buyer counter creates a NEW offer document carrying the previous round's
300
+ * buyer identity forward. `offer` came from a read, so those two fields are
301
+ * ciphertext — and `createOffer` encrypts `buyerName`/`buyerEmail` again
302
+ * (`OFFER_PII_FIELDS`), so round 2 onward stored a permanently unreadable
303
+ * buyer. Rounds 1 was fine, which is why nothing looked wrong.
304
+ */
305
+ const offerPlain = offerRepository.revealOffer(offer);
306
+ const newOffer = await offerRepository.createOffer({
288
307
  productId: offer.productId,
289
308
  productTitle: offer.productTitle,
290
309
  productSlug: offer.productSlug,
291
310
  productImageUrl: offer.productImageUrl,
292
311
  buyerUid: userId,
293
- buyerName: offer.buyerName,
294
- buyerEmail: offer.buyerEmail,
312
+ buyerName: offerPlain.buyerName,
313
+ buyerEmail: offerPlain.buyerEmail,
295
314
  storeId: offer.storeId,
296
315
  storeName: offer.storeName,
297
316
  offerAmount: counterAmount,
@@ -349,14 +368,25 @@ export async function withdrawOffer(userId, offerId) {
349
368
  // --- Read ------------------------------------------------------------------
350
369
  export async function listBuyerOffers(userId) {
351
370
  const result = await offerRepository.findByBuyer(userId);
352
- return result.items;
371
+ /*
372
+ * REVEALED: these are the buyer's OWN offers, so showing them their own name
373
+ * and email in full is the canonical legitimate plaintext read. The seller's
374
+ * view of the same documents goes through `maskedOffer` instead.
375
+ */
376
+ return result.items.map((o) => offerRepository.revealOffer(o));
353
377
  }
354
378
  export async function listSellerOffers(userId) {
355
379
  const store = await storeRepository.findByOwnerId(userId);
356
380
  if (!store)
357
381
  return [];
358
382
  const result = await offerRepository.findByStore(store.id);
359
- return result.items.map(maskOfferForSeller);
383
+ /*
384
+ * `maskedOffer`, not `maskOfferForSeller`. The latter calls `maskName`,
385
+ * which refuses ciphertext by design and answers "Anonymous" — and
386
+ * `findByStore` returns raw documents. So the seller's own offers list
387
+ * showed every buyer as Anonymous. `maskedOffer` decrypts first, then masks.
388
+ */
389
+ return result.items.map((o) => offerRepository.maskedOffer(o));
360
390
  }
361
391
  // --- Buyer: Checkout accepted offer ----------------------------------------
362
392
  export async function checkoutOffer(userId, offerId) {
@@ -257,7 +257,7 @@ export async function requestPayout(userId, userName, userEmail, input) {
257
257
  const earnings = await computeSellerEarnings(userId);
258
258
  if (earnings.netAmount <= 0 || earnings.eligibleOrders.length === 0)
259
259
  throw new ValidationError("No eligible earnings available for payout.");
260
- const payout = await payoutRepository.create({
260
+ const payout = await payoutRepository.createPayout({
261
261
  storeId: userId,
262
262
  sellerName: userName,
263
263
  sellerEmail: userEmail,
@@ -288,6 +288,16 @@ export async function bulkSellerOrder(userId, userRole, userDisplayName, userEma
288
288
  const userDoc = await userRepository.findById(userId);
289
289
  if (!userDoc)
290
290
  throw new AuthorizationError("User not found");
291
+ /*
292
+ * 🛑 REVEALED before building a payout — the same active corruption the two
293
+ * payout crons had. `findById` is ciphertext-by-default and `createPayout`
294
+ * encrypts `upiId` again (`PAYOUT_PII_FIELDS`), so the seller-initiated path
295
+ * wrote a permanently unreadable payee address too.
296
+ *
297
+ * `payoutDetails` is encrypted by `encryptPayoutDetails`, a separate scheme
298
+ * from the `piiFields` path, which is why `revealUser` unwraps it explicitly.
299
+ */
300
+ const userPlain = userRepository.revealUser(userDoc);
291
301
  if (!userDoc.payoutDetails?.isConfigured) {
292
302
  throw new ValidationError("Payout details are not set up. Please configure your payout method before requesting a payout.");
293
303
  }
@@ -337,7 +347,7 @@ export async function bulkSellerOrder(userId, userRole, userDisplayName, userEma
337
347
  const grossAmount = ordersTaxableValue(eligible);
338
348
  const bulkSiteSettings = await siteSettingsRepository.getSingleton();
339
349
  const bulkDeduction = computePayoutDeduction(grossAmount, bulkSiteSettings.commissions);
340
- const payoutDoc = await payoutRepository.create({
350
+ const payoutDoc = await payoutRepository.createPayout({
341
351
  storeId: userId,
342
352
  sellerName: userDisplayName,
343
353
  sellerEmail: userEmail,
@@ -351,14 +361,31 @@ export async function bulkSellerOrder(userId, userRole, userDisplayName, userEma
351
361
  gstAmount: bulkDeduction.gstOnFee,
352
362
  gstRate: bulkSiteSettings.commissions.gstPercent / 100,
353
363
  currency: getDefaultCurrency(),
354
- paymentMethod: userDoc.payoutDetails.method === "upi"
364
+ paymentMethod: userPlain.payoutDetails?.method === "upi"
355
365
  ? "upi"
356
366
  : "bank_transfer",
357
- upiId: userDoc.payoutDetails.method === "upi"
358
- ? userDoc.payoutDetails.upiId
367
+ upiId: userPlain.payoutDetails?.method === "upi"
368
+ ? userPlain.payoutDetails.upiId
359
369
  : undefined,
360
- bankAccount: userDoc.payoutDetails.method === "bank_transfer"
361
- ? userDoc.payoutDetails.bankAccount
370
+ /*
371
+ * 🛑 Only the MASKED subset, matching both payout crons.
372
+ *
373
+ * This used to copy the whole `bankAccount`, including the real
374
+ * `accountNumber` that `encryptPayoutDetails` had encrypted on the user
375
+ * document. `PAYOUT_PII_FIELDS` does not list it and
376
+ * `encryptPayoutBankAccount` is a no-op, so the ciphertext was stored
377
+ * verbatim on the payout where nothing would ever unwrap it — and
378
+ * revealing it instead would store a real account number in the clear.
379
+ * A payout does not need the full number; it needs to identify the account.
380
+ */
381
+ bankAccount: userPlain.payoutDetails?.method === "bank_transfer" &&
382
+ userPlain.payoutDetails.bankAccount
383
+ ? {
384
+ accountHolderName: userPlain.payoutDetails.bankAccount.accountHolderName,
385
+ accountNumberMasked: userPlain.payoutDetails.bankAccount.accountNumberMasked,
386
+ ifscCode: userPlain.payoutDetails.bankAccount.ifscCode,
387
+ bankName: userPlain.payoutDetails.bankAccount.bankName,
388
+ }
362
389
  : undefined,
363
390
  notes: `Payout request for ${eligible.length} custom-shipped delivered order(s)`,
364
391
  });