@mohasinac/appkit 4.59.0 → 4.60.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 (531) hide show
  1. package/dist/.build-stamp.json +3 -3
  2. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +62 -5
  3. package/dist/_internal/client/features/maintenance/views/MaintenanceDashboardView.js +2 -2
  4. package/dist/_internal/server/features/brands/actions.js +78 -4
  5. package/dist/_internal/server/features/checkout/actions.d.ts +36 -13
  6. package/dist/_internal/server/features/checkout/actions.js +668 -183
  7. package/dist/_internal/server/features/checkout/supplier-identity.js +18 -1
  8. package/dist/_internal/server/features/gateway-events/index.d.ts +10 -0
  9. package/dist/_internal/server/features/gateway-events/index.js +10 -0
  10. package/dist/_internal/server/features/gateway-events/ingest.d.ts +127 -0
  11. package/dist/_internal/server/features/gateway-events/ingest.js +188 -0
  12. package/dist/_internal/server/features/gateway-events/redact.d.ts +66 -0
  13. package/dist/_internal/server/features/gateway-events/redact.js +151 -0
  14. package/dist/_internal/server/features/grievance/actions.d.ts +63 -0
  15. package/dist/_internal/server/features/grievance/actions.js +173 -0
  16. package/dist/_internal/server/features/grievance/index.d.ts +8 -0
  17. package/dist/_internal/server/features/grievance/index.js +8 -0
  18. package/dist/_internal/server/features/grouped/data.js +28 -3
  19. package/dist/_internal/server/features/lottery/actions.js +99 -4
  20. package/dist/_internal/server/features/order-completion/actions.d.ts +92 -0
  21. package/dist/_internal/server/features/order-completion/actions.js +336 -0
  22. package/dist/_internal/server/features/order-completion/index.d.ts +7 -0
  23. package/dist/_internal/server/features/order-completion/index.js +7 -0
  24. package/dist/_internal/server/features/orders/actions.d.ts +13 -0
  25. package/dist/_internal/server/features/orders/actions.js +56 -2
  26. package/dist/_internal/server/features/orders/adapters.js +26 -0
  27. package/dist/_internal/server/features/orders/cancellation-refund.d.ts +116 -0
  28. package/dist/_internal/server/features/orders/cancellation-refund.js +466 -0
  29. package/dist/_internal/server/features/orders/index.d.ts +2 -1
  30. package/dist/_internal/server/features/orders/index.js +1 -1
  31. package/dist/_internal/server/features/orders/service.d.ts +60 -0
  32. package/dist/_internal/server/features/orders/service.js +74 -0
  33. package/dist/_internal/server/features/payment-cases/disputes.d.ts +76 -0
  34. package/dist/_internal/server/features/payment-cases/disputes.js +241 -0
  35. package/dist/_internal/server/features/payment-cases/index.d.ts +9 -0
  36. package/dist/_internal/server/features/payment-cases/index.js +9 -0
  37. package/dist/_internal/server/features/payouts/actions.d.ts +28 -3
  38. package/dist/_internal/server/features/payouts/actions.js +84 -10
  39. package/dist/_internal/server/features/points/adjust.d.ts +61 -0
  40. package/dist/_internal/server/features/points/adjust.js +121 -0
  41. package/dist/_internal/server/features/points/award.d.ts +65 -0
  42. package/dist/_internal/server/features/points/award.js +145 -0
  43. package/dist/_internal/server/features/price-index/market.d.ts +33 -0
  44. package/dist/_internal/server/features/price-index/market.js +54 -1
  45. package/dist/_internal/server/features/products/data.js +40 -22
  46. package/dist/_internal/server/features/protection-claims/actions.d.ts +72 -0
  47. package/dist/_internal/server/features/protection-claims/actions.js +228 -0
  48. package/dist/_internal/server/features/protection-claims/index.d.ts +8 -0
  49. package/dist/_internal/server/features/protection-claims/index.js +8 -0
  50. package/dist/_internal/server/features/refunds/actions.d.ts +20 -0
  51. package/dist/_internal/server/features/refunds/actions.js +259 -17
  52. package/dist/_internal/server/features/refunds/capacity.d.ts +29 -0
  53. package/dist/_internal/server/features/refunds/capacity.js +37 -0
  54. package/dist/_internal/server/features/reviews/actions.js +3 -2
  55. package/dist/_internal/server/features/search/index-build/sources.js +20 -1
  56. package/dist/_internal/server/features/shipping/reconcile.d.ts +10 -1
  57. package/dist/_internal/server/features/shipping/reconcile.js +34 -3
  58. package/dist/_internal/server/features/shipping/reimbursement.d.ts +117 -0
  59. package/dist/_internal/server/features/shipping/reimbursement.js +223 -0
  60. package/dist/_internal/server/features/stores/tabs.d.ts +19 -4
  61. package/dist/_internal/server/features/stores/tabs.js +24 -4
  62. package/dist/_internal/server/functions/https.d.ts +31 -1
  63. package/dist/_internal/server/functions/https.js +52 -1
  64. package/dist/_internal/server/functions/scheduled.d.ts +72 -1
  65. package/dist/_internal/server/functions/scheduled.js +124 -1
  66. package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +62 -16
  67. package/dist/_internal/server/jobs/core/boxRollupReconcile.d.ts +46 -0
  68. package/dist/_internal/server/jobs/core/boxRollupReconcile.js +142 -0
  69. package/dist/_internal/server/jobs/core/dailyDataCleanup.js +149 -1
  70. package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +14 -0
  71. package/dist/_internal/server/jobs/core/dailyStatusDigest.js +79 -1
  72. package/dist/_internal/server/jobs/core/index.d.ts +2 -0
  73. package/dist/_internal/server/jobs/core/index.js +2 -0
  74. package/dist/_internal/server/jobs/core/marketPriceRollup.d.ts +64 -0
  75. package/dist/_internal/server/jobs/core/marketPriceRollup.js +153 -0
  76. package/dist/_internal/server/jobs/core/obligationSweep.d.ts +36 -0
  77. package/dist/_internal/server/jobs/core/obligationSweep.js +503 -0
  78. package/dist/_internal/server/jobs/core/paymentReconcile.d.ts +79 -0
  79. package/dist/_internal/server/jobs/core/paymentReconcile.js +614 -0
  80. package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +34 -0
  81. package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +35 -4
  82. package/dist/_internal/server/jobs/handlers/boxRollupReconcile.d.ts +2 -0
  83. package/dist/_internal/server/jobs/handlers/boxRollupReconcile.js +15 -0
  84. package/dist/_internal/server/jobs/handlers/countersReconcileNow.d.ts +65 -0
  85. package/dist/_internal/server/jobs/handlers/countersReconcileNow.js +89 -0
  86. package/dist/_internal/server/jobs/handlers/index.d.ts +5 -0
  87. package/dist/_internal/server/jobs/handlers/index.js +5 -0
  88. package/dist/_internal/server/jobs/handlers/marketPriceRollup.d.ts +2 -0
  89. package/dist/_internal/server/jobs/handlers/marketPriceRollup.js +2 -0
  90. package/dist/_internal/server/jobs/handlers/obligationSweep.d.ts +2 -0
  91. package/dist/_internal/server/jobs/handlers/obligationSweep.js +15 -0
  92. package/dist/_internal/server/jobs/handlers/onShipmentAllocationSync.js +30 -1
  93. package/dist/_internal/server/jobs/handlers/paymentReconcile.d.ts +2 -0
  94. package/dist/_internal/server/jobs/handlers/paymentReconcile.js +6 -0
  95. package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
  96. package/dist/_internal/shared/actions/action-registry.js +71 -0
  97. package/dist/_internal/shared/checkout/coupon-discount.d.ts +73 -0
  98. package/dist/_internal/shared/checkout/coupon-discount.js +103 -0
  99. package/dist/_internal/shared/checkout/lanes.d.ts +42 -0
  100. package/dist/_internal/shared/checkout/lanes.js +46 -0
  101. package/dist/_internal/shared/checkout/order-math.d.ts +149 -1
  102. package/dist/_internal/shared/checkout/order-math.js +251 -3
  103. package/dist/_internal/shared/checkout/refundable-base.d.ts +116 -0
  104. package/dist/_internal/shared/checkout/refundable-base.js +122 -0
  105. package/dist/_internal/shared/features/auctions/config.d.ts +14 -1
  106. package/dist/_internal/shared/features/auctions/config.js +30 -1
  107. package/dist/_internal/shared/features/brands/schema.d.ts +42 -0
  108. package/dist/_internal/shared/features/brands/schema.js +18 -0
  109. package/dist/_internal/shared/features/orders/refund-copy.d.ts +22 -0
  110. package/dist/_internal/shared/features/orders/refund-copy.js +34 -0
  111. package/dist/_internal/shared/features/print/label-profiles.d.ts +198 -0
  112. package/dist/_internal/shared/features/print/label-profiles.js +350 -0
  113. package/dist/_internal/shared/features/products/to-product-item.js +33 -5
  114. package/dist/_internal/shared/fees/calculator.d.ts +31 -2
  115. package/dist/_internal/shared/fees/calculator.js +103 -5
  116. package/dist/_internal/shared/fees/india-states.d.ts +195 -0
  117. package/dist/_internal/shared/fees/india-states.js +190 -0
  118. package/dist/_internal/shared/fees/payout-hold.d.ts +80 -0
  119. package/dist/_internal/shared/fees/payout-hold.js +74 -0
  120. package/dist/_internal/shared/obligations/deadlines.d.ts +94 -0
  121. package/dist/_internal/shared/obligations/deadlines.js +155 -0
  122. package/dist/_internal/shared/shipping/quote.d.ts +96 -0
  123. package/dist/_internal/shared/shipping/quote.js +67 -0
  124. package/dist/_internal/shared/time/business-days.d.ts +91 -0
  125. package/dist/_internal/shared/time/business-days.js +185 -0
  126. package/dist/cli/index.js +0 -2
  127. package/dist/client.d.ts +9 -4
  128. package/dist/client.js +26 -3
  129. package/dist/configs/tailwind.d.ts +0 -12
  130. package/dist/configs/tailwind.js +28 -15
  131. package/dist/constants/api-endpoints.d.ts +51 -9
  132. package/dist/constants/api-endpoints.js +23 -7
  133. package/dist/constants/index.d.ts +1 -1
  134. package/dist/constants/index.js +1 -1
  135. package/dist/contracts/index.d.ts +1 -1
  136. package/dist/contracts/payment.d.ts +131 -0
  137. package/dist/features/about/components/AboutView.js +1 -1
  138. package/dist/features/about/components/DeveloperView.js +5 -2
  139. package/dist/features/about/components/FAQPageView.js +2 -1
  140. package/dist/features/about/components/FeesView.js +2 -1
  141. package/dist/features/about/components/HelpPageView.js +2 -1
  142. package/dist/features/about/components/HowAuctionsWorkView.js +2 -1
  143. package/dist/features/about/components/HowCheckoutWorksView.js +2 -1
  144. package/dist/features/about/components/HowEmiWorksView.js +2 -1
  145. package/dist/features/about/components/HowOffersWorkView.js +2 -1
  146. package/dist/features/about/components/HowOrdersWorkView.js +2 -1
  147. package/dist/features/about/components/HowPayoutsWorkView.js +2 -1
  148. package/dist/features/about/components/HowPreOrdersWorkView.js +2 -1
  149. package/dist/features/about/components/HowReviewsWorkView.js +2 -1
  150. package/dist/features/about/components/PolicyPageView.js +2 -1
  151. package/dist/features/about/components/ProseHero.d.ts +73 -0
  152. package/dist/features/about/components/ProseHero.js +18 -0
  153. package/dist/features/about/components/SecurityPrivacyView.js +2 -1
  154. package/dist/features/about/components/ShippingPolicyView.js +2 -1
  155. package/dist/features/about/components/TrackOrderView.js +2 -1
  156. package/dist/features/about/components/UnauthorizedView.js +1 -1
  157. package/dist/features/about/index.d.ts +2 -0
  158. package/dist/features/about/index.js +5 -0
  159. package/dist/features/account/actions/address-actions.d.ts +26 -2
  160. package/dist/features/account/actions/address-actions.js +25 -1
  161. package/dist/features/account/components/BuyerShoppingGuideView.js +1 -1
  162. package/dist/features/account/components/NotificationPreferencesPanel.js +1 -1
  163. package/dist/features/account/components/UserOrdersView.js +17 -0
  164. package/dist/features/account/components/UserSidebar.js +1 -1
  165. package/dist/features/account/hooks/useNotifications.js +29 -0
  166. package/dist/features/admin/actions/admin-coupon-actions.js +36 -0
  167. package/dist/features/admin/components/AdminBeysView.js +2 -2
  168. package/dist/features/admin/components/AdminBlogEditorView.js +2 -2
  169. package/dist/features/admin/components/AdminBrandEditorView.js +32 -2
  170. package/dist/features/admin/components/AdminBundleEditorView.js +1 -1
  171. package/dist/features/admin/components/AdminCarouselEditorView.js +1 -1
  172. package/dist/features/admin/components/AdminCategoriesView.js +1 -1
  173. package/dist/features/admin/components/AdminCategoryEditorView.js +73 -17
  174. package/dist/features/admin/components/AdminContactEditorView.js +1 -1
  175. package/dist/features/admin/components/AdminCouponEditorView.js +26 -1
  176. package/dist/features/admin/components/AdminFaqEditorView.js +1 -1
  177. package/dist/features/admin/components/AdminFaqsView.js +2 -2
  178. package/dist/features/admin/components/AdminGatewayEventsView.d.ts +54 -0
  179. package/dist/features/admin/components/AdminGatewayEventsView.js +209 -0
  180. package/dist/features/admin/components/AdminGuideHubView.js +1 -1
  181. package/dist/features/admin/components/AdminMoneyCasesView.d.ts +60 -0
  182. package/dist/features/admin/components/AdminMoneyCasesView.js +287 -0
  183. package/dist/features/admin/components/AdminPartsView.js +2 -2
  184. package/dist/features/admin/components/AdminProductsView.js +75 -4
  185. package/dist/features/admin/components/AdminSidebar.js +2 -2
  186. package/dist/features/admin/components/AdminSiteSettingsView.js +65 -7
  187. package/dist/features/admin/components/AdminSublistingCategoriesView.js +2 -0
  188. package/dist/features/admin/components/AdminSupportTicketDetailView.js +1 -1
  189. package/dist/features/admin/components/AdminSupportTicketsView.js +2 -2
  190. package/dist/features/admin/components/AdminTesterChecklistView.js +2 -2
  191. package/dist/features/admin/components/AdminUsersView.js +72 -1
  192. package/dist/features/admin/components/AdminViewCards.d.ts +3 -1
  193. package/dist/features/admin/components/AdminViewCards.js +4 -4
  194. package/dist/features/admin/components/DataListingView.d.ts +28 -0
  195. package/dist/features/admin/components/DataListingView.js +175 -14
  196. package/dist/features/admin/components/DataTable.d.ts +12 -1
  197. package/dist/features/admin/components/DataTable.js +3 -3
  198. package/dist/features/admin/components/OwnerQuickActions.d.ts +1 -1
  199. package/dist/features/admin/components/OwnerQuickActions.js +60 -2
  200. package/dist/features/admin/components/RecordOwnerQuickActions.d.ts +1 -1
  201. package/dist/features/admin/components/RecordOwnerQuickActions.js +61 -14
  202. package/dist/features/admin/components/analytics/AdminStatCard.d.ts +35 -1
  203. package/dist/features/admin/components/analytics/AdminStatCard.js +77 -2
  204. package/dist/features/admin/components/index.d.ts +4 -0
  205. package/dist/features/admin/components/index.js +6 -0
  206. package/dist/features/admin/constants/filter-tabs.d.ts +156 -0
  207. package/dist/features/admin/constants/filter-tabs.js +106 -0
  208. package/dist/features/admin/repository/site-settings.repository.d.ts +22 -0
  209. package/dist/features/admin/repository/site-settings.repository.js +82 -1
  210. package/dist/features/admin/schemas/admin-editor-forms.d.ts +21 -0
  211. package/dist/features/admin/schemas/admin-editor-forms.js +44 -0
  212. package/dist/features/admin/schemas/firestore.js +5 -1
  213. package/dist/features/admin/schemas/site-settings-form.js +30 -1
  214. package/dist/features/auctions/actions/bid-actions.js +13 -1
  215. package/dist/features/auctions/components/AuctionBottomActions.js +2 -2
  216. package/dist/features/auctions/components/AuctionDetailPageView.js +3 -1
  217. package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +11 -0
  218. package/dist/features/auctions/components/MarketplaceAuctionCard.js +5 -3
  219. package/dist/features/auctions/components/PlaceBidFormClient.d.ts +8 -1
  220. package/dist/features/auctions/components/PlaceBidFormClient.js +2 -2
  221. package/dist/features/audit-log/schemas/firestore.d.ts +28 -0
  222. package/dist/features/audit-log/schemas/firestore.js +14 -0
  223. package/dist/features/auth/permissions/constants.d.ts +17 -1
  224. package/dist/features/auth/permissions/constants.js +18 -0
  225. package/dist/features/blog/components/BlogPostView.js +1 -1
  226. package/dist/features/catalogue/components/AdminCatalogueApprovalsView.js +1 -1
  227. package/dist/features/categories/api/[id]/description-template/route.js +107 -1
  228. package/dist/features/categories/components/BrandDetailPageView.js +2 -2
  229. package/dist/features/categories/components/BreadcrumbTrail.js +7 -1
  230. package/dist/features/categories/components/BundleDetailView.js +1 -1
  231. package/dist/features/categories/components/CategoryDetailPageView.js +2 -2
  232. package/dist/features/categories/components/CategoryForm.js +12 -1
  233. package/dist/features/categories/components/CategoryTemplatePicker.js +38 -5
  234. package/dist/features/categories/repository/market-price-index.repository.d.ts +123 -0
  235. package/dist/features/categories/repository/market-price-index.repository.js +105 -0
  236. package/dist/features/categories/repository/price-observation.repository.d.ts +166 -0
  237. package/dist/features/categories/repository/price-observation.repository.js +132 -0
  238. package/dist/features/events/components/EventSaleBanner.js +1 -1
  239. package/dist/features/events/components/EventStatusBadge.js +1 -1
  240. package/dist/features/faq/components/FAQAccordion.js +2 -1
  241. package/dist/features/faq/components/FAQCategorySidebar.js +2 -2
  242. package/dist/features/faq/components/FAQHelpfulButtons.js +4 -4
  243. package/dist/features/faq/components/RelatedFAQs.js +1 -1
  244. package/dist/features/filters/FilterFacetSection.js +1 -1
  245. package/dist/features/filters/SwitchFilter.js +1 -1
  246. package/dist/features/gateway-events/repository/gateway-events.repository.d.ts +117 -0
  247. package/dist/features/gateway-events/repository/gateway-events.repository.js +274 -0
  248. package/dist/features/gateway-events/schemas/firestore.d.ts +217 -0
  249. package/dist/features/gateway-events/schemas/firestore.js +125 -0
  250. package/dist/features/gateway-events/schemas/index.d.ts +81 -0
  251. package/dist/features/gateway-events/schemas/index.js +79 -0
  252. package/dist/features/grouped/components/GroupedListingDetailView.js +1 -1
  253. package/dist/features/homepage/components/AnnouncementBar.js +37 -1
  254. package/dist/features/homepage/components/AnnouncementBar.style.css +30 -0
  255. package/dist/features/homepage/components/BrandsSection.js +1 -1
  256. package/dist/features/homepage/components/CTABannerSection.js +1 -1
  257. package/dist/features/homepage/components/FeaturedBundlesSection.js +14 -24
  258. package/dist/features/homepage/components/HeroCarousel.js +2 -2
  259. package/dist/features/homepage/components/SocialPostCard.js +1 -1
  260. package/dist/features/inventory/components/AdminMoveLedgerView.d.ts +7 -0
  261. package/dist/features/inventory/components/AdminMoveLedgerView.js +157 -0
  262. package/dist/features/inventory/components/AdminStorageBoxesView.d.ts +11 -0
  263. package/dist/features/inventory/components/AdminStorageBoxesView.js +168 -0
  264. package/dist/features/inventory/components/ReceiveStationView.d.ts +39 -0
  265. package/dist/features/inventory/components/ReceiveStationView.js +413 -0
  266. package/dist/features/inventory/components/operator-message.d.ts +29 -0
  267. package/dist/features/inventory/components/operator-message.js +41 -0
  268. package/dist/features/inventory/index.d.ts +13 -0
  269. package/dist/features/inventory/index.js +28 -0
  270. package/dist/features/inventory/repository/inventory-movements.repository.d.ts +97 -0
  271. package/dist/features/inventory/repository/inventory-movements.repository.js +186 -0
  272. package/dist/features/inventory/repository/inventory-placements.repository.d.ts +179 -0
  273. package/dist/features/inventory/repository/inventory-placements.repository.js +345 -0
  274. package/dist/features/inventory/repository/storage-boxes.repository.d.ts +83 -0
  275. package/dist/features/inventory/repository/storage-boxes.repository.js +127 -0
  276. package/dist/features/inventory/schemas/firestore.d.ts +197 -0
  277. package/dist/features/inventory/schemas/firestore.js +159 -0
  278. package/dist/features/layout/AppLayoutShell.d.ts +12 -1
  279. package/dist/features/layout/AppLayoutShell.js +25 -12
  280. package/dist/features/layout/AutoBreadcrumbs.js +162 -3
  281. package/dist/features/layout/AutoBreadcrumbs.style.css +45 -0
  282. package/dist/features/layout/BottomNavbar.d.ts +1 -1
  283. package/dist/features/layout/BottomNavbar.js +2 -2
  284. package/dist/features/media/MediaAvatar.js +1 -1
  285. package/dist/features/media/MediaImage.d.ts +24 -4
  286. package/dist/features/media/MediaImage.js +44 -4
  287. package/dist/features/media/MediaLightbox.js +1 -1
  288. package/dist/features/media/modals/ImageCropModal.js +1 -1
  289. package/dist/features/media/modals/ImageEditor.js +1 -1
  290. package/dist/features/media/upload/MediaUploadField.js +91 -3
  291. package/dist/features/obligations/constants/policies.d.ts +92 -0
  292. package/dist/features/obligations/constants/policies.js +378 -0
  293. package/dist/features/obligations/repository/obligations.repository.d.ts +68 -0
  294. package/dist/features/obligations/repository/obligations.repository.js +158 -0
  295. package/dist/features/obligations/schemas/firestore.d.ts +160 -0
  296. package/dist/features/obligations/schemas/firestore.js +87 -0
  297. package/dist/features/orders/actions/order-actions.d.ts +43 -4
  298. package/dist/features/orders/actions/order-actions.js +60 -3
  299. package/dist/features/orders/actions/refund-actions.js +70 -10
  300. package/dist/features/orders/components/OrderCompletionPanel.d.ts +27 -0
  301. package/dist/features/orders/components/OrderCompletionPanel.js +192 -0
  302. package/dist/features/orders/components/OrdersList.js +2 -2
  303. package/dist/features/orders/components/RefundHistoryTable.js +3 -1
  304. package/dist/features/orders/components/index.d.ts +2 -0
  305. package/dist/features/orders/components/index.js +6 -0
  306. package/dist/features/orders/constants/transitions.d.ts +59 -0
  307. package/dist/features/orders/constants/transitions.js +104 -0
  308. package/dist/features/orders/repository/orders.repository.d.ts +109 -6
  309. package/dist/features/orders/repository/orders.repository.js +464 -21
  310. package/dist/features/orders/schemas/firestore.d.ts +270 -0
  311. package/dist/features/orders/schemas/firestore.js +24 -0
  312. package/dist/features/orders/schemas/index.d.ts +61 -0
  313. package/dist/features/orders/schemas/index.js +22 -0
  314. package/dist/features/orders/types/index.d.ts +79 -0
  315. package/dist/features/parts/components/PartsIndexPageView.js +8 -1
  316. package/dist/features/payment-cases/repository/payment-cases.repository.d.ts +170 -0
  317. package/dist/features/payment-cases/repository/payment-cases.repository.js +342 -0
  318. package/dist/features/payment-cases/schemas/firestore.d.ts +229 -0
  319. package/dist/features/payment-cases/schemas/firestore.js +105 -0
  320. package/dist/features/payment-cases/schemas/resolve-form.d.ts +97 -0
  321. package/dist/features/payment-cases/schemas/resolve-form.js +114 -0
  322. package/dist/features/payments/repository/payout.repository.d.ts +0 -1
  323. package/dist/features/payments/repository/payout.repository.js +0 -1
  324. package/dist/features/points/repository/points.repository.d.ts +122 -0
  325. package/dist/features/points/repository/points.repository.js +304 -1
  326. package/dist/features/points/schemas/adjust-form.d.ts +58 -0
  327. package/dist/features/points/schemas/adjust-form.js +63 -0
  328. package/dist/features/points/schemas/firestore.d.ts +108 -1
  329. package/dist/features/points/schemas/firestore.js +84 -0
  330. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +3 -3
  331. package/dist/features/pre-orders/components/PreOrderBadge.js +1 -1
  332. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +1 -1
  333. package/dist/features/price-index/components/PriceIndexToolView.d.ts +23 -4
  334. package/dist/features/price-index/components/PriceIndexToolView.js +71 -6
  335. package/dist/features/price-index/market-stats.d.ts +82 -0
  336. package/dist/features/price-index/market-stats.js +230 -0
  337. package/dist/features/print/components/BoxLabelPrintView.d.ts +25 -0
  338. package/dist/features/print/components/BoxLabelPrintView.js +66 -0
  339. package/dist/features/print/components/LabelProfilePicker.d.ts +13 -0
  340. package/dist/features/print/components/LabelProfilePicker.js +38 -0
  341. package/dist/features/print/components/labels.d.ts +117 -0
  342. package/dist/features/print/components/labels.js +258 -0
  343. package/dist/features/print/components/labels.style.css +46 -0
  344. package/dist/features/print/index.d.ts +6 -0
  345. package/dist/features/print/index.js +16 -0
  346. package/dist/features/products/columns/productTableColumns.js +5 -4
  347. package/dist/features/products/components/MarketplaceBundleCard.js +2 -2
  348. package/dist/features/products/components/MarketplacePrizeDrawCard.js +6 -6
  349. package/dist/features/products/components/PrizeDrawCollage.js +1 -1
  350. package/dist/features/products/components/PrizeDrawItemsEditor.js +1 -1
  351. package/dist/features/products/components/PrizeRevealModal.js +2 -2
  352. package/dist/features/products/components/ProductDetailPageView.js +18 -4
  353. package/dist/features/products/components/ProductForm.js +34 -23
  354. package/dist/features/products/components/ProductGrid.js +86 -62
  355. package/dist/features/products/constants/card-badges.d.ts +97 -0
  356. package/dist/features/products/constants/card-badges.js +100 -0
  357. package/dist/features/products/repository/products.repository.js +34 -1
  358. package/dist/features/products/schemas/firestore.d.ts +46 -3
  359. package/dist/features/products/schemas/firestore.js +21 -0
  360. package/dist/features/promotions/components/PromotionsView.js +1 -1
  361. package/dist/features/promotions/repository/claimed-coupons.repository.d.ts +32 -0
  362. package/dist/features/promotions/repository/claimed-coupons.repository.js +58 -0
  363. package/dist/features/promotions/schemas/firestore.js +30 -3
  364. package/dist/features/promotions/schemas/index.d.ts +6 -6
  365. package/dist/features/protection-claims/repository/protection-claims.repository.d.ts +54 -0
  366. package/dist/features/protection-claims/repository/protection-claims.repository.js +174 -0
  367. package/dist/features/protection-claims/schemas/firestore.d.ts +168 -0
  368. package/dist/features/protection-claims/schemas/firestore.js +130 -0
  369. package/dist/features/reviews/actions/review-actions.js +3 -2
  370. package/dist/features/reviews/components/ReviewModal.js +1 -1
  371. package/dist/features/reviews/components/ReviewsList.js +1 -1
  372. package/dist/features/reviews/schemas/firestore.d.ts +20 -1
  373. package/dist/features/scams/constants/scam-types.d.ts +2 -0
  374. package/dist/features/scams/constants/scam-types.js +18 -0
  375. package/dist/features/scams/schemas/report-form.d.ts +3 -3
  376. package/dist/features/scams/schemas/report-form.js +26 -1
  377. package/dist/features/search/components/Search.js +9 -9
  378. package/dist/features/search/components/SearchResultsClient.js +18 -3
  379. package/dist/features/search/components/SearchResultsPageView.d.ts +1 -6
  380. package/dist/features/search/components/SearchResultsPageView.js +2 -2
  381. package/dist/features/seller/actions/offer-actions.js +16 -1
  382. package/dist/features/seller/actions/seller-actions.js +14 -3
  383. package/dist/features/seller/components/CategoryInlineSelect.js +75 -11
  384. package/dist/features/seller/components/PrintCenterView.d.ts +5 -0
  385. package/dist/features/seller/components/PrintCenterView.js +41 -30
  386. package/dist/features/seller/components/SellerOrdersView.js +1 -1
  387. package/dist/features/seller/components/SellerPayoutRequestView.js +16 -5
  388. package/dist/features/seller/components/SellerPayoutSettingsView.js +1 -1
  389. package/dist/features/seller/components/SellerProductShell.d.ts +16 -0
  390. package/dist/features/seller/components/SellerProductShell.js +123 -13
  391. package/dist/features/seller/components/SellerReviewsView.js +4 -2
  392. package/dist/features/seller/components/SellerSidebar.js +1 -1
  393. package/dist/features/seller/schemas/coupon-form.d.ts +26 -0
  394. package/dist/features/seller/schemas/coupon-form.js +27 -0
  395. package/dist/features/seller/schemas/product-form.d.ts +3 -0
  396. package/dist/features/seller/schemas/product-form.js +5 -0
  397. package/dist/features/shell/FormShell.js +2 -2
  398. package/dist/features/shell/QuickFormDrawer.js +14 -0
  399. package/dist/features/shell/SectionForm.d.ts +19 -0
  400. package/dist/features/shell/SectionForm.js +133 -9
  401. package/dist/features/shell/SectionForm.style.css +54 -0
  402. package/dist/features/shipments/components/AdminShipmentsView.js +16 -1
  403. package/dist/features/shipments/repository/shipment-items.repository.d.ts +9 -0
  404. package/dist/features/shipments/repository/shipment-items.repository.js +14 -0
  405. package/dist/features/site-settings/components/ActionPermissionsManager.js +1 -1
  406. package/dist/features/sticker-trace/components/StickerCommitPanel.js +1 -1
  407. package/dist/features/store-extensions/schemas/report-review-form.d.ts +8 -8
  408. package/dist/features/stores/components/StoreGuideHubView.js +1 -1
  409. package/dist/features/stores/components/StoreHeader.js +1 -1
  410. package/dist/features/support/schemas/firestore.d.ts +73 -2
  411. package/dist/features/support/schemas/firestore.js +59 -0
  412. package/dist/index.d.ts +16 -24
  413. package/dist/index.js +38 -47
  414. package/dist/next/ErrorBoundary.js +1 -1
  415. package/dist/next/routing/route-map.d.ts +24 -0
  416. package/dist/next/routing/route-map.js +40 -0
  417. package/dist/providers/payment-manual/index.d.ts +15 -1
  418. package/dist/providers/payment-manual/index.js +37 -0
  419. package/dist/providers/payment-phonepe/index.d.ts +14 -1
  420. package/dist/providers/payment-phonepe/index.js +36 -0
  421. package/dist/providers/payment-razorpay/index.d.ts +44 -1
  422. package/dist/providers/payment-razorpay/index.js +99 -0
  423. package/dist/providers/shipping-shiprocket/index.d.ts +18 -0
  424. package/dist/providers/shipping-shiprocket/index.js +18 -0
  425. package/dist/schemas/registry.d.ts +44 -11
  426. package/dist/server-entry.d.ts +2 -0
  427. package/dist/server-entry.js +27 -0
  428. package/dist/server.d.ts +42 -0
  429. package/dist/server.js +93 -0
  430. package/dist/styles.css +418 -149
  431. package/dist/tailwind-utilities.css +1 -1
  432. package/dist/tokens/themes/default-dark.js +15 -12
  433. package/dist/tokens/themes/default-light.js +14 -11
  434. package/dist/tokens/tokens.css +106 -23
  435. package/dist/ui/DataTable.style.css +4 -4
  436. package/dist/ui/columns/cell-renderers.d.ts +20 -0
  437. package/dist/ui/columns/cell-renderers.js +26 -1
  438. package/dist/ui/columns/index.d.ts +1 -1
  439. package/dist/ui/columns/index.js +4 -1
  440. package/dist/ui/components/Badge.style.css +1 -1
  441. package/dist/ui/components/Breadcrumb.js +19 -1
  442. package/dist/ui/components/BulkActionBar.style.css +4 -4
  443. package/dist/ui/components/Button.style.css +1 -1
  444. package/dist/ui/components/Checkbox.style.css +1 -1
  445. package/dist/ui/components/FallbackShell.js +1 -1
  446. package/dist/ui/components/Form.d.ts +14 -1
  447. package/dist/ui/components/Form.js +2 -2
  448. package/dist/ui/components/FormField.js +18 -4
  449. package/dist/ui/components/FormField.style.css +43 -3
  450. package/dist/ui/components/GatedPrice.style.css +1 -1
  451. package/dist/ui/components/IconButton.style.css +1 -1
  452. package/dist/ui/components/Input.js +22 -1
  453. package/dist/ui/components/Input.style.css +38 -22
  454. package/dist/ui/components/ListingFilterDrawer.js +1 -1
  455. package/dist/ui/components/ListingToolbar.js +1 -1
  456. package/dist/ui/components/PaginatedSelect.js +0 -0
  457. package/dist/ui/components/Radio.style.css +1 -1
  458. package/dist/ui/components/Repeater.d.ts +53 -0
  459. package/dist/ui/components/Repeater.js +7 -0
  460. package/dist/ui/components/RichTextEditor.d.ts +20 -1
  461. package/dist/ui/components/RichTextEditor.js +23 -2
  462. package/dist/ui/components/Select.style.css +7 -21
  463. package/dist/ui/components/Semantic.js +27 -3
  464. package/dist/ui/components/TagInput.style.css +4 -9
  465. package/dist/ui/components/Textarea.style.css +4 -18
  466. package/dist/ui/components/Toggle.style.css +1 -1
  467. package/dist/ui/components/Typography.d.ts +3 -3
  468. package/dist/ui/components/Typography.js +15 -15
  469. package/dist/ui/components/ViewToggle.style.css +4 -4
  470. package/dist/ui/forms/AddAnotherToggle.d.ts +16 -0
  471. package/dist/ui/forms/AddAnotherToggle.js +56 -0
  472. package/dist/ui/forms/ColorPickerField.js +15 -2
  473. package/dist/ui/forms/FieldCheckbox.js +15 -2
  474. package/dist/ui/forms/FieldInput.d.ts +22 -1
  475. package/dist/ui/forms/FieldInput.js +19 -5
  476. package/dist/ui/forms/FieldLabel.d.ts +35 -0
  477. package/dist/ui/forms/FieldLabel.js +70 -0
  478. package/dist/ui/forms/FieldSelect.d.ts +4 -1
  479. package/dist/ui/forms/FieldSelect.js +27 -5
  480. package/dist/ui/forms/FieldTextarea.d.ts +4 -1
  481. package/dist/ui/forms/FieldTextarea.js +22 -5
  482. package/dist/ui/forms/FormShell.d.ts +17 -1
  483. package/dist/ui/forms/FormShell.js +36 -2
  484. package/dist/ui/forms/FormShell.style.css +41 -33
  485. package/dist/ui/forms/index.d.ts +5 -1
  486. package/dist/ui/forms/index.js +2 -0
  487. package/dist/ui/icons/icon-registry.d.ts +1 -0
  488. package/dist/ui/icons/icon-registry.js +17 -1
  489. package/dist/utils/id-generators.d.ts +80 -0
  490. package/dist/utils/id-generators.js +93 -0
  491. package/dist/utils/search-txt-builders.d.ts +12 -0
  492. package/dist/utils/search-txt-builders.js +17 -0
  493. package/package.json +1 -1
  494. package/scripts/seed-cli.mjs +106 -5
  495. package/dist/features/loyalty/api/admin/loyalty/grant/route.d.ts +0 -12
  496. package/dist/features/loyalty/api/admin/loyalty/grant/route.js +0 -38
  497. package/dist/features/loyalty/api/balance/route.d.ts +0 -12
  498. package/dist/features/loyalty/api/balance/route.js +0 -41
  499. package/dist/features/loyalty/api/earn/route.d.ts +0 -12
  500. package/dist/features/loyalty/api/earn/route.js +0 -38
  501. package/dist/features/loyalty/api/history/route.d.ts +0 -12
  502. package/dist/features/loyalty/api/history/route.js +0 -58
  503. package/dist/features/loyalty/api/redeem/route.d.ts +0 -12
  504. package/dist/features/loyalty/api/redeem/route.js +0 -38
  505. package/dist/features/loyalty/columns/index.d.ts +0 -17
  506. package/dist/features/loyalty/columns/index.js +0 -40
  507. package/dist/features/loyalty/components/CoinsDisplay.d.ts +0 -12
  508. package/dist/features/loyalty/components/CoinsDisplay.js +0 -10
  509. package/dist/features/loyalty/components/index.d.ts +0 -1
  510. package/dist/features/loyalty/components/index.js +0 -1
  511. package/dist/features/loyalty/hooks/useLoyaltyBalance.d.ts +0 -4
  512. package/dist/features/loyalty/hooks/useLoyaltyBalance.js +0 -25
  513. package/dist/features/loyalty/index.d.ts +0 -6
  514. package/dist/features/loyalty/index.js +0 -6
  515. package/dist/features/loyalty/manifest.d.ts +0 -2
  516. package/dist/features/loyalty/manifest.js +0 -16
  517. package/dist/features/loyalty/messages/en.json +0 -19
  518. package/dist/features/loyalty/repository/loyalty.repository.d.ts +0 -8
  519. package/dist/features/loyalty/repository/loyalty.repository.js +0 -22
  520. package/dist/features/loyalty/schemas/index.d.ts +0 -85
  521. package/dist/features/loyalty/schemas/index.js +0 -40
  522. package/dist/features/loyalty/server.d.ts +0 -6
  523. package/dist/features/loyalty/server.js +0 -6
  524. package/dist/features/loyalty/types/index.d.ts +0 -31
  525. package/dist/features/loyalty/types/index.js +0 -1
  526. package/dist/features/loyalty/types/loyalty-config.d.ts +0 -7
  527. package/dist/features/loyalty/types/loyalty-config.js +0 -1
  528. package/dist/features/loyalty/types/loyalty-math.d.ts +0 -9
  529. package/dist/features/loyalty/types/loyalty-math.js +0 -27
  530. package/dist/features/products/components/ProductOwnerQuickActions.d.ts +0 -11
  531. package/dist/features/products/components/ProductOwnerQuickActions.js +0 -120
@@ -0,0 +1,345 @@
1
+ /*
2
+ * WHY: "What is in AC60-03" and "where is this product" are the two questions
3
+ * the whole feature exists to answer, and both must be one bounded read.
4
+ * WHAT: The current placement of stock, moved only through transactions that
5
+ * also append to the ledger.
6
+ *
7
+ * ── 🛑 A ZERO-QUANTITY PLACEMENT IS DELETED, NEVER STORED AT ZERO ──────────
8
+ *
9
+ * Keeping zeros would force every box read to pair `quantity > 0` with an
10
+ * `orderBy`. Firestore appends an inequality's field to the sort implicitly,
11
+ * so that demands a composite index in an order nobody declares, fails with
12
+ * FAILED_PRECONDITION, and every caller in this codebase wraps such a read in
13
+ * `.catch(() => null)` — which renders as an EMPTY BOX rather than an error.
14
+ * Root Cause #59. Absence means zero, and no query needs an inequality.
15
+ *
16
+ * ── 🛑 EVERY MOVE IS A TRANSACTION THAT ALSO WRITES THE LEDGER ────────────
17
+ *
18
+ * A placement changed without a movement row is stock that teleported: the
19
+ * count is right and nobody can say why. Doing them in one transaction is
20
+ * what makes the ledger complete rather than best-effort — the alternative
21
+ * (write the placement, then append) leaves a gap whenever the second write
22
+ * fails, and a ledger with gaps cannot be used to find a missing item.
23
+ *
24
+ * Holds no PII.
25
+ *
26
+ * EXPORTS: InventoryPlacementsRepository, inventoryPlacementsRepository
27
+ *
28
+ * @tag domain:inventory
29
+ * @tag layer:feature
30
+ * @tag pattern:repository
31
+ * @tag access:server
32
+ * @tag sideEffects:firestore
33
+ */
34
+ import { BaseRepository, parseSieveDateValue, } from "../../../providers/db-firebase/index.js";
35
+ import { unitOfWork } from "../../../core/unit-of-work.js";
36
+ import { INVENTORY_MOVEMENTS_COLLECTION, INVENTORY_PLACEMENTS_COLLECTION, INVENTORY_PLACEMENT_FIELDS, placementId, } from "../schemas/firestore.js";
37
+ export class InventoryPlacementsRepository extends BaseRepository {
38
+ constructor() {
39
+ super(INVENTORY_PLACEMENTS_COLLECTION);
40
+ }
41
+ /**
42
+ * Is this product in this box, and how many?
43
+ *
44
+ * 🛑 One document READ, because the id is deterministic. With a generated
45
+ * id this would be a two-field query needing its own composite index — and
46
+ * a double-submit could create a second row for the same pair that silently
47
+ * doubles the count.
48
+ */
49
+ async get(boxId, productId) {
50
+ return this.findById(placementId(boxId, productId));
51
+ }
52
+ /** What is in this box. One equality, served by the automatic index. */
53
+ async listByBox(boxId, limit = 200) {
54
+ const snap = await this.getCollection()
55
+ .where(INVENTORY_PLACEMENT_FIELDS.BOX_ID, "==", boxId)
56
+ .limit(limit)
57
+ .get();
58
+ return snap.docs.map((d) => this.mapDoc(d));
59
+ }
60
+ /** Where is this product. Also one equality — this is the pair that matters. */
61
+ async listByProduct(productId, limit = 50) {
62
+ const snap = await this.getCollection()
63
+ .where(INVENTORY_PLACEMENT_FIELDS.PRODUCT_ID, "==", productId)
64
+ .limit(limit)
65
+ .get();
66
+ return snap.docs.map((d) => this.mapDoc(d));
67
+ }
68
+ /**
69
+ * Put stock into a box — a receive, or an adjustment that found some.
70
+ *
71
+ * 🛑 Idempotent upsert via the deterministic id, and the increment happens
72
+ * INSIDE the transaction from the value read inside it. Reading first and
73
+ * writing after would lose one of two concurrent receives of the same
74
+ * product into the same box, which is exactly what a receive station with
75
+ * two people scanning does.
76
+ */
77
+ async place(input) {
78
+ this.assertQuantity(input.quantity);
79
+ const pid = placementId(input.boxId, input.productId);
80
+ await unitOfWork.runTransaction(async (tx) => {
81
+ const ref = this.getCollection().doc(pid);
82
+ const snap = await tx.get(ref);
83
+ const now = new Date();
84
+ const prior = snap.exists ? snap.data()?.quantity ?? 0 : 0;
85
+ tx.set(ref, {
86
+ boxId: input.boxId,
87
+ productId: input.productId,
88
+ boxCode: input.boxCode,
89
+ productTitle: input.productTitle,
90
+ ...(input.productSku ? { productSku: input.productSku } : {}),
91
+ ...(input.slot ? { slot: input.slot } : {}),
92
+ quantity: prior + input.quantity,
93
+ updatedAt: now,
94
+ ...(snap.exists ? {} : { createdAt: now }),
95
+ }, { merge: true });
96
+ this.appendMovement(tx, {
97
+ kind: input.kind,
98
+ productId: input.productId,
99
+ quantity: input.quantity,
100
+ toBoxId: input.boxId,
101
+ toBoxCode: input.boxCode,
102
+ productTitle: input.productTitle,
103
+ actorUid: input.actorUid,
104
+ ...(input.reason ? { reason: input.reason } : {}),
105
+ ...(input.shipmentId ? { shipmentId: input.shipmentId } : {}),
106
+ occurredAt: new Date(),
107
+ });
108
+ });
109
+ }
110
+ /**
111
+ * Box → box.
112
+ *
113
+ * 🛑 REFUSES rather than going negative. A move of more than the source
114
+ * holds is a miscount, and clamping it would make the ledger assert a
115
+ * movement of a quantity that was not there — the one thing that makes the
116
+ * ledger unusable as evidence.
117
+ */
118
+ async move(input) {
119
+ this.assertQuantity(input.quantity);
120
+ if (input.fromBoxId === input.toBoxId) {
121
+ throw new Error("Source and destination box are the same");
122
+ }
123
+ const fromId = placementId(input.fromBoxId, input.productId);
124
+ const toId = placementId(input.toBoxId, input.productId);
125
+ await unitOfWork.runTransaction(async (tx) => {
126
+ const fromRef = this.getCollection().doc(fromId);
127
+ const toRef = this.getCollection().doc(toId);
128
+ /*
129
+ * Both reads before either write — a transaction cannot read after a
130
+ * write, and the destination read is what makes the upsert correct when
131
+ * the product is already in the target box.
132
+ */
133
+ const [fromSnap, toSnap] = await Promise.all([tx.get(fromRef), tx.get(toRef)]);
134
+ const have = fromSnap.exists ? fromSnap.data()?.quantity ?? 0 : 0;
135
+ if (have < input.quantity) {
136
+ throw new Error(`${input.fromBoxCode} holds ${have} of that product, cannot move ${input.quantity}. ` +
137
+ `Record an \`adjust\` with a reason if the count is wrong.`);
138
+ }
139
+ const now = new Date();
140
+ const remaining = have - input.quantity;
141
+ // Absence means zero — see the header.
142
+ if (remaining === 0)
143
+ tx.delete(fromRef);
144
+ else
145
+ tx.update(fromRef, { quantity: remaining, updatedAt: now });
146
+ const already = toSnap.exists ? toSnap.data()?.quantity ?? 0 : 0;
147
+ tx.set(toRef, {
148
+ boxId: input.toBoxId,
149
+ productId: input.productId,
150
+ boxCode: input.toBoxCode,
151
+ productTitle: input.productTitle,
152
+ ...(input.productSku ? { productSku: input.productSku } : {}),
153
+ quantity: already + input.quantity,
154
+ updatedAt: now,
155
+ ...(toSnap.exists ? {} : { createdAt: now }),
156
+ }, { merge: true });
157
+ this.appendMovement(tx, {
158
+ kind: "move",
159
+ productId: input.productId,
160
+ quantity: input.quantity,
161
+ fromBoxId: input.fromBoxId,
162
+ fromBoxCode: input.fromBoxCode,
163
+ toBoxId: input.toBoxId,
164
+ toBoxCode: input.toBoxCode,
165
+ productTitle: input.productTitle,
166
+ actorUid: input.actorUid,
167
+ occurredAt: now,
168
+ });
169
+ });
170
+ }
171
+ /**
172
+ * Take stock out of a box.
173
+ *
174
+ * 🛑 MANUAL, and never fired from checkout. An automatic decrement on
175
+ * payment would have the ledger assert a movement nobody performed — the
176
+ * stock is sold, but it is still in the box until a person walks over and
177
+ * picks it. A ledger recording intentions instead of actions cannot be used
178
+ * to find a missing item, which is its only real job.
179
+ *
180
+ * 🛑 And this does NOT touch `product.stockQuantity`. That stays
181
+ * authoritative and is owned by the order path; writing both is how a
182
+ * reserved unit gets handed back to the shelf (see the schema header).
183
+ */
184
+ async pick(input) {
185
+ this.assertQuantity(input.quantity);
186
+ const pid = placementId(input.boxId, input.productId);
187
+ await unitOfWork.runTransaction(async (tx) => {
188
+ const ref = this.getCollection().doc(pid);
189
+ const snap = await tx.get(ref);
190
+ const have = snap.exists ? snap.data()?.quantity ?? 0 : 0;
191
+ if (have < input.quantity) {
192
+ throw new Error(`${input.boxCode} holds ${have} of that product, cannot pick ${input.quantity}.`);
193
+ }
194
+ const now = new Date();
195
+ const remaining = have - input.quantity;
196
+ if (remaining === 0)
197
+ tx.delete(ref);
198
+ else
199
+ tx.update(ref, { quantity: remaining, updatedAt: now });
200
+ this.appendMovement(tx, {
201
+ kind: "pick",
202
+ productId: input.productId,
203
+ quantity: input.quantity,
204
+ fromBoxId: input.boxId,
205
+ fromBoxCode: input.boxCode,
206
+ productTitle: input.productTitle,
207
+ actorUid: input.actorUid,
208
+ ...(input.reason ? { reason: input.reason } : {}),
209
+ occurredAt: now,
210
+ });
211
+ });
212
+ }
213
+ /**
214
+ * The receive station's bulk commit — many rows, ONE transaction.
215
+ *
216
+ * 🛑 ONE TRANSACTION FOR THE WHOLE TABLE, not a loop of them. A partial
217
+ * receive is the worst outcome available: the operator has already
218
+ * physically put everything in the boxes, so a half-written commit leaves
219
+ * the ledger disagreeing with the shelf and no way to tell which rows
220
+ * landed.
221
+ *
222
+ * Firestore caps a transaction at 500 writes and each row here is two (the
223
+ * placement and its movement), so the caller's row limit of 50 is what
224
+ * keeps this inside the cap — that is why the limit exists, rather than
225
+ * being a UI preference.
226
+ *
227
+ * 🛑 Lives HERE rather than in the route for two reasons. API routes do not
228
+ * touch Firestore directly in this codebase, and more specifically
229
+ * `audit-inventory-ledger-append-only` allows only this file and the
230
+ * movements repository to write the ledger — a route doing it would be the
231
+ * second writer the audit exists to prevent, and I wrote exactly that before
232
+ * the audit caught me.
233
+ *
234
+ * 🛑 Does NOT touch `product.stockQuantity`. The shipment-link route already
235
+ * does, and doing both double-counts. This records WHERE stock is, never how
236
+ * much exists.
237
+ */
238
+ async receiveBatch(input) {
239
+ if (input.rows.length === 0)
240
+ throw new Error("Nothing to receive");
241
+ for (const r of input.rows)
242
+ this.assertQuantity(r.quantity);
243
+ await unitOfWork.runTransaction(async (tx) => {
244
+ const col = this.getCollection();
245
+ /*
246
+ * All reads first — a transaction cannot read after a write. The
247
+ * existing quantity is read INSIDE the transaction and the increment
248
+ * computed from it, so two operators receiving the same product into
249
+ * the same box cannot lose one of the two. Not hypothetical: that is
250
+ * what two people with scanners do.
251
+ */
252
+ const refs = input.rows.map((r) => col.doc(placementId(r.boxId, r.productId)));
253
+ const snaps = await Promise.all(refs.map((ref) => tx.get(ref)));
254
+ const now = new Date();
255
+ input.rows.forEach((r, i) => {
256
+ const snap = snaps[i];
257
+ const prior = snap.exists ? (snap.data()?.quantity ?? 0) : 0;
258
+ tx.set(refs[i], {
259
+ boxId: r.boxId,
260
+ productId: r.productId,
261
+ boxCode: r.boxCode,
262
+ productTitle: r.productTitle,
263
+ ...(r.productSku ? { productSku: r.productSku } : {}),
264
+ ...(r.slot ? { slot: r.slot } : {}),
265
+ quantity: prior + r.quantity,
266
+ updatedAt: now,
267
+ ...(snap.exists ? {} : { createdAt: now }),
268
+ }, { merge: true });
269
+ this.appendMovement(tx, {
270
+ kind: "receive",
271
+ productId: r.productId,
272
+ quantity: r.quantity,
273
+ toBoxId: r.boxId,
274
+ toBoxCode: r.boxCode,
275
+ productTitle: r.productTitle,
276
+ actorUid: input.actorUid,
277
+ ...(input.shipmentId ? { shipmentId: input.shipmentId } : {}),
278
+ occurredAt: now,
279
+ });
280
+ });
281
+ });
282
+ return {
283
+ rows: input.rows.length,
284
+ units: input.rows.reduce((n, r) => n + r.quantity, 0),
285
+ };
286
+ }
287
+ assertQuantity(q) {
288
+ if (!Number.isInteger(q) || q < 1) {
289
+ throw new Error(`Quantity must be a positive whole number, got ${q}. Direction is carried by the operation, never by the sign.`);
290
+ }
291
+ }
292
+ /**
293
+ * Append a ledger row inside the caller's transaction.
294
+ *
295
+ * 🛑 Written through the raw collection rather than
296
+ * `inventoryMovementsRepository.append`, because that method is not
297
+ * transaction-aware and a second, non-transactional write would reopen the
298
+ * gap this whole design closes. The VALIDATION it performs is mirrored by
299
+ * the typed `MovementKind` endpoints above and by the quantity assert — so
300
+ * the shape is still checked, by the compiler rather than at runtime.
301
+ *
302
+ * `audit-inventory-ledger-append-only` allows this one path by name.
303
+ */
304
+ /*
305
+ * 🛑 `Transaction`, not a structural `{ set: (ref: unknown, data: unknown)
306
+ * => void }`. That shortcut did not compile and the reason is worth keeping:
307
+ * parameter types are CONTRAVARIANT, so a parameter annotated
308
+ * `(ref: unknown) => void` promises to accept anything at all — a stronger
309
+ * guarantee than `Transaction.set`, whose first argument must be a
310
+ * `DocumentReference`. So `Transaction` was not assignable to it and all
311
+ * three call sites failed. Widening a parameter to `unknown` narrows what
312
+ * can be passed IN, which is the opposite of what it looks like.
313
+ *
314
+ * `import type` keeps this free at runtime — it emits nothing, which is the
315
+ * same reason `unit-of-work.ts` can name the type without pulling
316
+ * firebase-admin into the graph (Root Cause #24).
317
+ */
318
+ appendMovement(tx, row) {
319
+ const ref = this.db.collection(INVENTORY_MOVEMENTS_COLLECTION).doc();
320
+ tx.set(ref, { ...row, createdAt: new Date(), updatedAt: new Date() });
321
+ }
322
+ async listForAdmin(model) {
323
+ return this.sieveQuery(model, InventoryPlacementsRepository.SIEVE_FIELDS, { defaultPageSize: 25, maxPageSize: 50 });
324
+ }
325
+ }
326
+ /** Every Timestamp field carries `parseSieveDateValue` — Root Cause #47. */
327
+ InventoryPlacementsRepository.SIEVE_FIELDS = {
328
+ id: { canFilter: true, canSort: false },
329
+ [INVENTORY_PLACEMENT_FIELDS.BOX_ID]: { canFilter: true, canSort: false },
330
+ [INVENTORY_PLACEMENT_FIELDS.PRODUCT_ID]: { canFilter: true, canSort: false },
331
+ [INVENTORY_PLACEMENT_FIELDS.QUANTITY]: { canFilter: true, canSort: true },
332
+ [INVENTORY_PLACEMENT_FIELDS.BOX_CODE]: { canFilter: true, canSort: true },
333
+ [INVENTORY_PLACEMENT_FIELDS.PRODUCT_SKU]: { canFilter: true, canSort: false },
334
+ [INVENTORY_PLACEMENT_FIELDS.CREATED_AT]: {
335
+ canFilter: true,
336
+ canSort: true,
337
+ parseValue: parseSieveDateValue,
338
+ },
339
+ [INVENTORY_PLACEMENT_FIELDS.UPDATED_AT]: {
340
+ canFilter: true,
341
+ canSort: true,
342
+ parseValue: parseSieveDateValue,
343
+ },
344
+ };
345
+ export const inventoryPlacementsRepository = new InventoryPlacementsRepository();
@@ -0,0 +1,83 @@
1
+ import { BaseRepository, parseSieveDateValue, type SieveModel, type FirebaseSieveResult } from "../../../providers/db-firebase";
2
+ import { type BoxStatus, type BoxType, type StorageBoxDocument } from "../schemas/firestore";
3
+ export interface StorageBoxCreateInput {
4
+ code: string;
5
+ boxType: BoxType;
6
+ location?: string;
7
+ capacityNote?: string;
8
+ status?: BoxStatus;
9
+ }
10
+ export declare class StorageBoxesRepository extends BaseRepository<StorageBoxDocument> {
11
+ constructor();
12
+ /**
13
+ * Create a box at its own code.
14
+ *
15
+ * 🛑 `createWithId`, not `create`, and that is the uniqueness guarantee: the
16
+ * id IS `storagebox-{code}`, so a second `AC60-03` lands on the same
17
+ * document instead of making a second registry row for one physical object.
18
+ *
19
+ * 🛑 And it REFUSES rather than overwriting. An operator labelling a new box
20
+ * who types a code already in use has made a mistake that silently merging
21
+ * two boxes would hide — and the merge would be unrecoverable, because the
22
+ * placements of both would then point at one id.
23
+ */
24
+ createBox(input: StorageBoxCreateInput): Promise<StorageBoxDocument>;
25
+ /** Box by its printed code, which is what a scan or a typed search gives. */
26
+ findByCode(code: string): Promise<StorageBoxDocument | null>;
27
+ setStatus(id: string, status: BoxStatus): Promise<StorageBoxDocument>;
28
+ /**
29
+ * Write the advisory rollup.
30
+ *
31
+ * 🛑 Called ONLY by the scheduled repair job, never from a trigger on a
32
+ * collection this also writes. That shape is Root Cause #92 — a
33
+ * documentWritten trigger writing back to its own collection, whose no-op
34
+ * guard compared maps with `JSON.stringify` while Firestore returns map keys
35
+ * alphabetically, so the guard could never match and it recursed to 12M
36
+ * invocations against a 2M/month quota. A scheduled recompute cannot
37
+ * recurse, which is the entire reason for the choice.
38
+ */
39
+ setRollup(id: string, distinctProducts: number, totalUnits: number): Promise<void>;
40
+ listForAdmin(model: SieveModel): Promise<FirebaseSieveResult<StorageBoxDocument>>;
41
+ /** Every Timestamp field carries `parseSieveDateValue` — Root Cause #47. */
42
+ static readonly SIEVE_FIELDS: {
43
+ id: {
44
+ canFilter: boolean;
45
+ canSort: boolean;
46
+ };
47
+ code: {
48
+ canFilter: boolean;
49
+ canSort: boolean;
50
+ };
51
+ boxType: {
52
+ canFilter: boolean;
53
+ canSort: boolean;
54
+ };
55
+ ordinal: {
56
+ canFilter: boolean;
57
+ canSort: boolean;
58
+ };
59
+ status: {
60
+ canFilter: boolean;
61
+ canSort: boolean;
62
+ };
63
+ location: {
64
+ canFilter: boolean;
65
+ canSort: boolean;
66
+ };
67
+ searchTxt: {
68
+ canFilter: boolean;
69
+ canSort: boolean;
70
+ };
71
+ createdAt: {
72
+ canFilter: boolean;
73
+ canSort: boolean;
74
+ parseValue: typeof parseSieveDateValue;
75
+ };
76
+ updatedAt: {
77
+ canFilter: boolean;
78
+ canSort: boolean;
79
+ parseValue: typeof parseSieveDateValue;
80
+ };
81
+ };
82
+ }
83
+ export declare const storageBoxesRepository: StorageBoxesRepository;
@@ -0,0 +1,127 @@
1
+ /*
2
+ * WHY: A box is a physical object with a label on it, and the registry is
3
+ * what makes "AC60-03" mean something to the software.
4
+ * WHAT: Create by code, list, status transitions, and the rollup write the
5
+ * scheduled repair job calls.
6
+ *
7
+ * Holds no PII.
8
+ *
9
+ * EXPORTS: StorageBoxesRepository, storageBoxesRepository,
10
+ * StorageBoxCreateInput
11
+ *
12
+ * @tag domain:inventory
13
+ * @tag layer:feature
14
+ * @tag pattern:repository
15
+ * @tag access:server
16
+ * @tag sideEffects:firestore
17
+ */
18
+ import { BaseRepository, parseSieveDateValue, } from "../../../providers/db-firebase/index.js";
19
+ import { generateStorageBoxId } from "../../../utils/id-generators.js";
20
+ import { buildStorageBoxSearchTxt } from "../../../utils/search-txt-builders.js";
21
+ import { BoxStatusValues, BoxTypeValues, STORAGE_BOXES_COLLECTION, STORAGE_BOX_FIELDS, } from "../schemas/firestore.js";
22
+ /**
23
+ * `AC60-03` → ordinal 3.
24
+ *
25
+ * Denormalised because a list sorted by `code` as a STRING puts AC60-10
26
+ * before AC60-2, which is the kind of ordering that makes an operator
27
+ * distrust the whole screen. Derived on write, never typed.
28
+ */
29
+ function ordinalOf(code) {
30
+ const m = code.match(/(\d+)\s*$/);
31
+ return m ? Number.parseInt(m[1], 10) : 0;
32
+ }
33
+ export class StorageBoxesRepository extends BaseRepository {
34
+ constructor() {
35
+ super(STORAGE_BOXES_COLLECTION);
36
+ }
37
+ /**
38
+ * Create a box at its own code.
39
+ *
40
+ * 🛑 `createWithId`, not `create`, and that is the uniqueness guarantee: the
41
+ * id IS `storagebox-{code}`, so a second `AC60-03` lands on the same
42
+ * document instead of making a second registry row for one physical object.
43
+ *
44
+ * 🛑 And it REFUSES rather than overwriting. An operator labelling a new box
45
+ * who types a code already in use has made a mistake that silently merging
46
+ * two boxes would hide — and the merge would be unrecoverable, because the
47
+ * placements of both would then point at one id.
48
+ */
49
+ async createBox(input) {
50
+ const code = input.code.trim().toUpperCase();
51
+ if (!code)
52
+ throw new Error("A box needs a code");
53
+ if (!BoxTypeValues.includes(input.boxType)) {
54
+ throw new Error(`Unknown box type: ${input.boxType}`);
55
+ }
56
+ const id = generateStorageBoxId({ code });
57
+ const existing = await this.findById(id);
58
+ if (existing) {
59
+ throw new Error(`Box ${code} already exists. A second ${code} is the same box — ` +
60
+ `edit it instead, or use a new code.`);
61
+ }
62
+ return this.createWithId(id, {
63
+ code,
64
+ boxType: input.boxType,
65
+ ordinal: ordinalOf(code),
66
+ status: input.status ?? "active",
67
+ ...(input.location ? { location: input.location } : {}),
68
+ ...(input.capacityNote ? { capacityNote: input.capacityNote } : {}),
69
+ searchTxt: buildStorageBoxSearchTxt({
70
+ code,
71
+ boxType: input.boxType,
72
+ location: input.location,
73
+ }),
74
+ });
75
+ }
76
+ /** Box by its printed code, which is what a scan or a typed search gives. */
77
+ async findByCode(code) {
78
+ return this.findById(generateStorageBoxId({ code: code.trim().toUpperCase() }));
79
+ }
80
+ async setStatus(id, status) {
81
+ if (!BoxStatusValues.includes(status)) {
82
+ throw new Error(`Unknown box status: ${status}`);
83
+ }
84
+ return this.update(id, { status, updatedAt: new Date() });
85
+ }
86
+ /**
87
+ * Write the advisory rollup.
88
+ *
89
+ * 🛑 Called ONLY by the scheduled repair job, never from a trigger on a
90
+ * collection this also writes. That shape is Root Cause #92 — a
91
+ * documentWritten trigger writing back to its own collection, whose no-op
92
+ * guard compared maps with `JSON.stringify` while Firestore returns map keys
93
+ * alphabetically, so the guard could never match and it recursed to 12M
94
+ * invocations against a 2M/month quota. A scheduled recompute cannot
95
+ * recurse, which is the entire reason for the choice.
96
+ */
97
+ async setRollup(id, distinctProducts, totalUnits) {
98
+ await this.update(id, {
99
+ rollup: { distinctProducts, totalUnits, computedAt: new Date() },
100
+ updatedAt: new Date(),
101
+ });
102
+ }
103
+ async listForAdmin(model) {
104
+ return this.sieveQuery(model, StorageBoxesRepository.SIEVE_FIELDS, { defaultPageSize: 25, maxPageSize: 50 });
105
+ }
106
+ }
107
+ /** Every Timestamp field carries `parseSieveDateValue` — Root Cause #47. */
108
+ StorageBoxesRepository.SIEVE_FIELDS = {
109
+ id: { canFilter: true, canSort: false },
110
+ [STORAGE_BOX_FIELDS.CODE]: { canFilter: true, canSort: true },
111
+ [STORAGE_BOX_FIELDS.BOX_TYPE]: { canFilter: true, canSort: false },
112
+ [STORAGE_BOX_FIELDS.ORDINAL]: { canFilter: true, canSort: true },
113
+ [STORAGE_BOX_FIELDS.STATUS]: { canFilter: true, canSort: false },
114
+ [STORAGE_BOX_FIELDS.LOCATION]: { canFilter: true, canSort: false },
115
+ [STORAGE_BOX_FIELDS.SEARCH_TXT]: { canFilter: true, canSort: false },
116
+ [STORAGE_BOX_FIELDS.CREATED_AT]: {
117
+ canFilter: true,
118
+ canSort: true,
119
+ parseValue: parseSieveDateValue,
120
+ },
121
+ [STORAGE_BOX_FIELDS.UPDATED_AT]: {
122
+ canFilter: true,
123
+ canSort: true,
124
+ parseValue: parseSieveDateValue,
125
+ },
126
+ };
127
+ export const storageBoxesRepository = new StorageBoxesRepository();