@mohasinac/appkit 3.2.8 → 3.2.10

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 (269) hide show
  1. package/dist/_internal/client/features/filters/filter-load-options.js +12 -9
  2. package/dist/_internal/client/theme/ThemeProvider.js +14 -4
  3. package/dist/_internal/server/features/auth/firebase-identity.d.ts +12 -0
  4. package/dist/_internal/server/features/auth/firebase-identity.js +25 -0
  5. package/dist/_internal/server/features/site-settings/safe-settings.d.ts +12 -0
  6. package/dist/_internal/server/features/site-settings/safe-settings.js +25 -0
  7. package/dist/_internal/shared/features/layout/config.js +7 -7
  8. package/dist/_internal/shared/styles/skeleton.d.ts +8 -8
  9. package/dist/_internal/shared/styles/skeleton.js +10 -10
  10. package/dist/_internal/shared/styles/themed.d.ts +12 -12
  11. package/dist/_internal/shared/styles/themed.js +12 -12
  12. package/dist/features/about/components/AboutView.js +1 -1
  13. package/dist/features/about/components/FAQPageView.js +1 -1
  14. package/dist/features/about/components/FeesView.js +2 -2
  15. package/dist/features/about/components/HowAuctionsWorkView.js +2 -2
  16. package/dist/features/about/components/HowCheckoutWorksView.js +2 -2
  17. package/dist/features/about/components/HowOffersWorkView.js +2 -2
  18. package/dist/features/about/components/HowOrdersWorkView.js +2 -2
  19. package/dist/features/about/components/HowPayoutsWorkView.js +2 -2
  20. package/dist/features/about/components/HowPreOrdersWorkView.js +2 -2
  21. package/dist/features/about/components/HowReviewsWorkView.js +2 -2
  22. package/dist/features/about/components/PublicProfileView.js +3 -3
  23. package/dist/features/about/components/SecurityPrivacyView.js +2 -2
  24. package/dist/features/account/components/AddressBook.js +2 -2
  25. package/dist/features/account/components/AddressesIndexListing.js +1 -1
  26. package/dist/features/account/components/ChatWindow.js +1 -1
  27. package/dist/features/account/components/MessagesView.js +1 -1
  28. package/dist/features/account/components/NotificationBell.js +2 -2
  29. package/dist/features/account/components/NotificationPreferencesPanel.js +1 -1
  30. package/dist/features/account/components/UserSidebar.js +3 -3
  31. package/dist/features/account/components/UserSupportView.js +3 -3
  32. package/dist/features/admin/components/AdminAdEditorView.js +1 -1
  33. package/dist/features/admin/components/AdminAdsView.js +5 -5
  34. package/dist/features/admin/components/AdminAnalyticsView.js +1 -1
  35. package/dist/features/admin/components/AdminBrandsView.js +1 -1
  36. package/dist/features/admin/components/AdminBundlesView.js +2 -2
  37. package/dist/features/admin/components/AdminCarouselEditorView.js +4 -4
  38. package/dist/features/admin/components/AdminCarouselView.js +2 -2
  39. package/dist/features/admin/components/AdminCategoriesView.js +2 -2
  40. package/dist/features/admin/components/AdminContactEditorView.js +1 -1
  41. package/dist/features/admin/components/AdminCouponEditorView.js +1 -1
  42. package/dist/features/admin/components/AdminEmployeeEditorView.js +3 -3
  43. package/dist/features/admin/components/AdminFaqsView.js +1 -1
  44. package/dist/features/admin/components/AdminFeatureEditorView.js +2 -2
  45. package/dist/features/admin/components/AdminFeatureFlagsView.js +1 -1
  46. package/dist/features/admin/components/AdminFeaturesView.js +2 -2
  47. package/dist/features/admin/components/AdminNavigationView.js +2 -2
  48. package/dist/features/admin/components/AdminNotificationsView.js +1 -1
  49. package/dist/features/admin/components/AdminOrderEditorView.js +1 -1
  50. package/dist/features/admin/components/AdminPageHeader.d.ts +1 -1
  51. package/dist/features/admin/components/AdminPageHeader.js +1 -1
  52. package/dist/features/admin/components/AdminReviewsView.js +1 -1
  53. package/dist/features/admin/components/AdminScammerEditorView.js +3 -3
  54. package/dist/features/admin/components/AdminScammersView.js +1 -1
  55. package/dist/features/admin/components/AdminSectionsView.js +1 -1
  56. package/dist/features/admin/components/AdminSessionsView.js +1 -1
  57. package/dist/features/admin/components/AdminSidebar.js +5 -5
  58. package/dist/features/admin/components/AdminSiteSettingsView.js +3 -3
  59. package/dist/features/admin/components/AdminStoreEditorView.js +3 -3
  60. package/dist/features/admin/components/AdminSupportTicketDetailView.js +3 -3
  61. package/dist/features/admin/components/AdminSupportTicketsView.js +2 -2
  62. package/dist/features/admin/components/AdminViewCards.js +5 -5
  63. package/dist/features/admin/components/DataTable.js +1 -1
  64. package/dist/features/admin/components/DrawerFormFooter.js +1 -1
  65. package/dist/features/admin/components/QuickActionsPanel.js +1 -1
  66. package/dist/features/admin/components/analytics/AdminTopProductsTable.js +1 -1
  67. package/dist/features/auctions/components/AuctionDetailPageView.js +2 -2
  68. package/dist/features/auctions/components/CollapsibleBidHistory.js +1 -1
  69. package/dist/features/auctions/components/MarketplaceAuctionCard.js +1 -1
  70. package/dist/features/auth/components/ForgotPasswordView.js +1 -1
  71. package/dist/features/auth/components/Guards.js +1 -1
  72. package/dist/features/auth/components/RegisterForm.js +1 -1
  73. package/dist/features/auth/components/ResetPasswordView.js +1 -1
  74. package/dist/features/auth/components/SocialAuthButtons.js +1 -1
  75. package/dist/features/blog/components/BlogIndexListing.js +1 -1
  76. package/dist/features/blog/components/BlogListView.js +3 -3
  77. package/dist/features/blog/components/BlogPostView.js +1 -1
  78. package/dist/features/cart/components/CartDrawer.js +5 -5
  79. package/dist/features/categories/components/BrandDetailPageView.js +1 -1
  80. package/dist/features/categories/components/BrandDetailTabs.js +1 -1
  81. package/dist/features/categories/components/CategoriesIndexListing.js +2 -2
  82. package/dist/features/categories/components/CategoryDetailPageView.js +1 -1
  83. package/dist/features/categories/components/CategoryDetailTabs.js +1 -1
  84. package/dist/features/categories/components/CategoryGrid.js +3 -3
  85. package/dist/features/categories/components/CategoryTree.js +2 -2
  86. package/dist/features/categories/components/ConcernCard.js +1 -1
  87. package/dist/features/checkout/components/CheckoutStepper.js +1 -1
  88. package/dist/features/classified/components/ClassifiedIndexListing.js +1 -1
  89. package/dist/features/collections/components/CollectionCard.js +1 -1
  90. package/dist/features/collections/hooks/useCollections.js +12 -12
  91. package/dist/features/contact/components/ContactForm.js +1 -1
  92. package/dist/features/copilot/components/AdminCopilotView.js +5 -5
  93. package/dist/features/digital-codes/components/DigitalCodesIndexListing.js +1 -1
  94. package/dist/features/events/components/AdminEventEntriesView.js +1 -1
  95. package/dist/features/events/components/EventCard.js +1 -1
  96. package/dist/features/events/components/EventPollWidget.js +1 -1
  97. package/dist/features/events/components/EventStatusBadge.js +1 -1
  98. package/dist/features/events/components/EventsIndexListing.js +1 -1
  99. package/dist/features/faq/components/ContactCTA.js +2 -2
  100. package/dist/features/faq/components/FAQAccordion.js +4 -4
  101. package/dist/features/faq/components/FAQCategorySidebar.js +2 -2
  102. package/dist/features/faq/components/FAQHelpfulButtons.js +4 -4
  103. package/dist/features/faq/components/RelatedFAQs.js +1 -1
  104. package/dist/features/filters/AsyncFacetSection.js +3 -3
  105. package/dist/features/filters/FilterFacetSection.js +5 -5
  106. package/dist/features/filters/RangeFilter.js +3 -3
  107. package/dist/features/filters/SwitchFilter.js +2 -2
  108. package/dist/features/forms/Checkbox.js +1 -1
  109. package/dist/features/forms/Input.js +2 -2
  110. package/dist/features/forms/Radio.js +2 -2
  111. package/dist/features/forms/Select.js +1 -1
  112. package/dist/features/forms/Slider.js +1 -1
  113. package/dist/features/forms/Textarea.js +1 -1
  114. package/dist/features/forms/Toggle.js +3 -3
  115. package/dist/features/forms/utils.d.ts +4 -4
  116. package/dist/features/forms/utils.js +4 -4
  117. package/dist/features/homepage/components/AdSlot.js +1 -1
  118. package/dist/features/homepage/components/AdvertisementBanner.js +3 -3
  119. package/dist/features/homepage/components/BrandsSection.js +2 -2
  120. package/dist/features/homepage/components/GoogleReviewsSection.js +1 -1
  121. package/dist/features/homepage/components/HeroSection.js +1 -1
  122. package/dist/features/homepage/components/HomepageCustomerReviewsSection.js +1 -1
  123. package/dist/features/homepage/components/HowItWorksSection.js +1 -1
  124. package/dist/features/homepage/components/ShopByCategorySection.js +2 -2
  125. package/dist/features/homepage/components/SiteFeaturesSection.js +1 -1
  126. package/dist/features/homepage/components/SocialPostCard.js +1 -1
  127. package/dist/features/homepage/components/StatsCounterSection.js +1 -1
  128. package/dist/features/homepage/components/TrustIndicatorsSection.js +1 -1
  129. package/dist/features/homepage/constants/hero-carousel-styles.d.ts +3 -3
  130. package/dist/features/homepage/constants/hero-carousel-styles.js +3 -3
  131. package/dist/features/homepage/hooks/useActiveAd.d.ts +1 -3
  132. package/dist/features/homepage/hooks/useActiveAd.js +9 -17
  133. package/dist/features/layout/AppLayoutShell.js +12 -12
  134. package/dist/features/layout/AutoBreadcrumbs.js +1 -1
  135. package/dist/features/layout/BackToTop.js +2 -2
  136. package/dist/features/layout/BottomActions.js +8 -8
  137. package/dist/features/layout/BottomNavItem.js +1 -1
  138. package/dist/features/layout/BottomNavLayout.js +1 -1
  139. package/dist/features/layout/BottomNavbar.d.ts +1 -1
  140. package/dist/features/layout/BottomNavbar.js +2 -2
  141. package/dist/features/layout/BottomSheet.js +1 -1
  142. package/dist/features/layout/Breadcrumbs.js +2 -2
  143. package/dist/features/layout/FooterLayout.js +2 -2
  144. package/dist/features/layout/MainNavbar.js +1 -1
  145. package/dist/features/layout/NavItem.js +1 -1
  146. package/dist/features/layout/NavbarLayout.js +3 -3
  147. package/dist/features/layout/SidebarLayout.js +1 -1
  148. package/dist/features/layout/TitleBarLayout.js +3 -3
  149. package/dist/features/live/components/LiveItemsIndexListing.js +1 -1
  150. package/dist/features/loyalty/components/CoinsDisplay.js +1 -1
  151. package/dist/features/loyalty/hooks/useLoyaltyBalance.js +11 -3
  152. package/dist/features/media/AvatarUpload.js +1 -1
  153. package/dist/features/media/MediaPickerModal.js +1 -1
  154. package/dist/features/media/components/MediaSlider.js +1 -1
  155. package/dist/features/media/finalize.d.ts +12 -1
  156. package/dist/features/media/finalize.js +64 -11
  157. package/dist/features/media/modals/ImageCropModal.js +1 -1
  158. package/dist/features/media/modals/ImageEditor.js +1 -1
  159. package/dist/features/media/repository/media-assets.repository.d.ts +33 -0
  160. package/dist/features/media/repository/media-assets.repository.js +43 -0
  161. package/dist/features/media/upload/MediaUploadField.js +1 -1
  162. package/dist/features/messages/hooks/useConversation.js +12 -17
  163. package/dist/features/messages/hooks/useConversations.js +3 -5
  164. package/dist/features/orders/components/MarketplaceOrderCard.js +1 -1
  165. package/dist/features/orders/components/OrdersList.js +3 -3
  166. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +1 -1
  167. package/dist/features/pre-orders/components/PreOrderBadge.js +1 -1
  168. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +2 -2
  169. package/dist/features/pre-orders/components/PreOrdersIndexListing.js +1 -1
  170. package/dist/features/pre-orders/hooks/usePreOrders.js +12 -12
  171. package/dist/features/products/columns/productTableColumns.js +3 -3
  172. package/dist/features/products/components/BidHistory.js +1 -1
  173. package/dist/features/products/components/CompareOverlay.js +9 -9
  174. package/dist/features/products/components/CustomSectionTabContent.js +1 -1
  175. package/dist/features/products/components/CustomSectionsEditor.js +1 -1
  176. package/dist/features/products/components/FeatureBadge.js +2 -2
  177. package/dist/features/products/components/GroupSettingsPanel.js +2 -2
  178. package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -2
  179. package/dist/features/products/components/PrizeDrawsIndexListing.js +1 -1
  180. package/dist/features/products/components/ProductDetailPageView.js +4 -4
  181. package/dist/features/products/components/ProductFeatureBadges.js +2 -2
  182. package/dist/features/products/components/ProductFeaturesSelector.js +4 -4
  183. package/dist/features/products/components/ProductGalleryClient.js +1 -1
  184. package/dist/features/products/components/ProductGrid.js +8 -8
  185. package/dist/features/products/components/ProductTabs.js +1 -1
  186. package/dist/features/products/components/ProductTabsShell.js +1 -1
  187. package/dist/features/products/components/ShareButton.js +1 -1
  188. package/dist/features/products/components/ShowGroupSection.js +2 -2
  189. package/dist/features/products/components/SublistingCarouselSection.js +2 -2
  190. package/dist/features/promotions/components/CouponCard.js +2 -2
  191. package/dist/features/promotions/components/CouponsIndexListing.js +2 -2
  192. package/dist/features/reviews/components/ReviewDetailPageView.js +1 -1
  193. package/dist/features/reviews/components/ReviewDetailShell.js +5 -5
  194. package/dist/features/reviews/components/ReviewModal.js +1 -1
  195. package/dist/features/reviews/components/ReviewSummary.js +2 -2
  196. package/dist/features/reviews/components/ReviewsIndexListing.js +1 -1
  197. package/dist/features/reviews/components/ReviewsList.js +2 -2
  198. package/dist/features/scams/components/ScamRegistryView.js +2 -2
  199. package/dist/features/search/components/Search.js +11 -11
  200. package/dist/features/search/components/SearchFiltersRow.js +1 -1
  201. package/dist/features/search/components/SearchResultsSection.js +2 -2
  202. package/dist/features/seller/components/SellerAddressesView.js +4 -4
  203. package/dist/features/seller/components/SellerAnalyticsAlertsView.js +1 -1
  204. package/dist/features/seller/components/SellerCouponEditorView.js +1 -1
  205. package/dist/features/seller/components/SellerCouponsView.js +1 -1
  206. package/dist/features/seller/components/SellerFeaturesView.js +2 -2
  207. package/dist/features/seller/components/SellerGoogleReviewsView.js +1 -1
  208. package/dist/features/seller/components/SellerOrdersView.js +1 -1
  209. package/dist/features/seller/components/SellerPayoutMethodsView.js +1 -1
  210. package/dist/features/seller/components/SellerSidebar.js +4 -4
  211. package/dist/features/seller/components/analytics/SellerRevenueChart.js +1 -1
  212. package/dist/features/seller/components/analytics/SellerTopProducts.js +1 -1
  213. package/dist/features/site-settings/components/ActionPermissionsManager.js +2 -2
  214. package/dist/features/site-settings/components/NavPermissionsManager.js +1 -1
  215. package/dist/features/stores/components/InteractiveStoreCard.js +3 -3
  216. package/dist/features/stores/components/StoreHeader.js +2 -2
  217. package/dist/features/stores/components/StoreNavTabs.js +2 -2
  218. package/dist/features/stores/components/StorePreOrdersListing.js +1 -1
  219. package/dist/features/stores/components/StoreReviewsListing.js +1 -1
  220. package/dist/features/stores/components/StoresIndexListing.js +1 -1
  221. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +2 -2
  222. package/dist/features/wishlist/components/WishlistPage.js +2 -2
  223. package/dist/features/wishlist/hooks/useWishlistCount.js +5 -13
  224. package/dist/http/index.d.ts +1 -0
  225. package/dist/http/index.js +1 -0
  226. package/dist/http/retry.d.ts +1 -0
  227. package/dist/http/retry.js +26 -0
  228. package/dist/index.d.ts +4 -0
  229. package/dist/index.js +8 -0
  230. package/dist/next/ErrorBoundary.js +1 -1
  231. package/dist/providers/storage-firebase/provider.js +109 -55
  232. package/dist/repositories/index.d.ts +2 -0
  233. package/dist/repositories/index.js +2 -0
  234. package/dist/seed/site-settings-seed-data.js +476 -0
  235. package/dist/server.d.ts +4 -0
  236. package/dist/server.js +9 -0
  237. package/dist/styles.css +1 -1
  238. package/dist/tailwind-utilities.css +1 -1
  239. package/dist/tokens/index.d.ts +6 -6
  240. package/dist/tokens/index.js +59 -59
  241. package/dist/ui/DataTable.js +3 -3
  242. package/dist/ui/components/Avatar.js +1 -1
  243. package/dist/ui/components/BaseListingCard.js +7 -7
  244. package/dist/ui/components/Button.js +3 -3
  245. package/dist/ui/components/DetailPageGallery.js +3 -3
  246. package/dist/ui/components/DetailPageHero.js +1 -1
  247. package/dist/ui/components/DetailPageTabs.js +4 -4
  248. package/dist/ui/components/FilterChipGroup.js +2 -2
  249. package/dist/ui/components/Input.js +1 -1
  250. package/dist/ui/components/Layout.d.ts +2 -2
  251. package/dist/ui/components/ListingFilterDrawer.js +2 -2
  252. package/dist/ui/components/ListingToolbar.js +6 -6
  253. package/dist/ui/components/LoginRequiredModal.js +1 -1
  254. package/dist/ui/components/Modal.js +1 -1
  255. package/dist/ui/components/NavbarChevron.js +1 -1
  256. package/dist/ui/components/PageLoader.js +3 -3
  257. package/dist/ui/components/Radio.js +1 -1
  258. package/dist/ui/components/RichTextEditor.js +1 -1
  259. package/dist/ui/components/Select.js +1 -1
  260. package/dist/ui/components/SettingsSection.js +3 -3
  261. package/dist/ui/components/SideModal.js +1 -1
  262. package/dist/ui/components/Slider.js +2 -2
  263. package/dist/ui/components/StatsGrid.js +1 -1
  264. package/dist/ui/components/Typography.js +3 -3
  265. package/dist/ui/components/surface-tokens.d.ts +11 -11
  266. package/dist/ui/components/surface-tokens.js +12 -12
  267. package/dist/utils/safe-fire-forget.d.ts +14 -0
  268. package/dist/utils/safe-fire-forget.js +23 -0
  269. package/package.json +1 -1
@@ -0,0 +1,26 @@
1
+ /** Exponential-backoff retry for idempotent async operations.
2
+ *
3
+ * Use for GCS / Firestore transient errors (429, 503) where retrying is safe.
4
+ * Do NOT use for non-idempotent writes unless the underlying operation is
5
+ * already idempotent (e.g. Firestore set-with-merge at a known document path).
6
+ *
7
+ * @param fn Async operation to attempt.
8
+ * @param retries Number of additional attempts after the first (default 2 → up to 3 total).
9
+ * @param baseDelayMs Base delay before first retry; doubles each attempt (default 200ms).
10
+ */
11
+ import { normalizeError } from "../errors/normalize";
12
+ export async function withRetry(fn, retries = 2, baseDelayMs = 200) {
13
+ let lastErr;
14
+ for (let attempt = 0; attempt <= retries; attempt++) {
15
+ try {
16
+ return await fn();
17
+ }
18
+ catch (err) {
19
+ lastErr = normalizeError(err);
20
+ if (attempt < retries) {
21
+ await new Promise((res) => setTimeout(res, baseDelayMs * 2 ** attempt));
22
+ }
23
+ }
24
+ }
25
+ throw lastErr;
26
+ }
package/dist/index.d.ts CHANGED
@@ -586,6 +586,8 @@ export type { ProductTemplateDocument, ProductTemplateCreateInput, ProductTempla
586
586
  export { tokenRepository } from "./repositories/index";
587
587
  export { userRepository } from "./repositories/index";
588
588
  export { wishlistRepository } from "./repositories/index";
589
+ export { MediaAssetsRepository, mediaAssetsRepository } from "./repositories/index";
590
+ export type { MediaAssetDocument, MediaAssetCreateInput } from "./repositories/index";
589
591
  export { GroupedListingsRepository, groupedListingsRepository } from "./repositories/index";
590
592
  export type { NewsletterListModel } from "./repositories/index";
591
593
  export type { WishlistItem } from "./repositories/index";
@@ -3212,5 +3214,7 @@ export { SellerLiveView } from "./features/seller/components/SellerLiveView";
3212
3214
  export type { SellerLiveViewProps } from "./features/seller/components/SellerLiveView";
3213
3215
  export { SCHEMAS, lookupApiSchema, lookupFirestoreSchema, } from "./schemas/index";
3214
3216
  export type { ApiRouteKey, ApiRouteSchema, FirestoreDocument, FirestoreValue, FormFieldValue, FormValues, HttpVerb, JsonArray, JsonObject, JsonObjectWithUndefined, JsonPrimitive, JsonValue, JsonValueWithUndefined, RegisteredApiRouteKey, RegisteredFirestoreCollection, RegisteredFormId, RegisteredRtdbChannel, RegisteredSieveCollection, RegisteredStorageOp, RegisteredWebhookProvider, RegistryEntry, SchemaRegistry, SchemasShape, WebhookSchemaBucket, } from "./schemas/index";
3217
+ export { safeFireAndForget } from "./utils/safe-fire-forget";
3218
+ export { withRetry } from "./http/retry";
3215
3219
  export { normalizeError, getErrorMessage, isApiNormalized, isAppNormalized, isFirebaseAuthNormalized, isFirebaseFirestoreNormalized, isFirebaseStorageNormalized, isNativeNormalized, isNetworkNormalized, isUnknownNormalized, isZodNormalized, } from "./errors/normalize";
3216
3220
  export type { NormalizedError, NormalizedApiError, NormalizedAppError, NormalizedFirebaseAuthError, NormalizedFirebaseFirestoreError, NormalizedFirebaseStorageError, NormalizedNativeError, NormalizedNetworkError, NormalizedUnknownThrownValue, NormalizedZodError, } from "./errors/normalize";
package/dist/index.js CHANGED
@@ -1170,6 +1170,8 @@ export { userRepository } from "./repositories/index";
1170
1170
  // [DB]-Database layer â€" uses firebase-admin or another server-side DB SDK; can only run in a trusted server environment.
1171
1171
  // wishlistRepository - Shared export for wishlist repository.
1172
1172
  export { wishlistRepository } from "./repositories/index";
1173
+ // [DB]-Database layer — mediaAssetsRepository for SEO-friendly /media/{shortId} URL mapping.
1174
+ export { MediaAssetsRepository, mediaAssetsRepository } from "./repositories/index";
1173
1175
  export { GroupedListingsRepository, groupedListingsRepository } from "./repositories/index";
1174
1176
  // ./seed/index
1175
1177
  // [SERVER-ONLY]-Server-only â€" uses Node.js, Next.js server internals, or third-party server SDKs (auth, email, payment, shipping).
@@ -5660,6 +5662,12 @@ export { SellerLiveView } from "./features/seller/components/SellerLiveView";
5660
5662
  // Per-feature `schemas/index.ts` files register into the relevant bucket.
5661
5663
  // Pure Zod, isomorphic — safe on both client and server.
5662
5664
  export { SCHEMAS, lookupApiSchema, lookupFirestoreSchema, } from "./schemas/index";
5665
+ // ── Fire-and-forget safety wrapper ─────────────────────────────────────────
5666
+ // Replaces .catch(console.error) for non-critical background operations.
5667
+ export { safeFireAndForget } from "./utils/safe-fire-forget";
5668
+ // ── Exponential-backoff retry ───────────────────────────────────────────────
5669
+ // Use for GCS / Firestore transient errors where retrying is safe.
5670
+ export { withRetry } from "./http/retry";
5663
5671
  // ── W3 catch-clause normalizer ──────────────────────────────────────────────
5664
5672
  // Every catch (e: unknown) funnels through normalizeError(e) which returns
5665
5673
  // a NormalizedError discriminated union. Audit-catch-normalize enforces this.
@@ -4,7 +4,7 @@ import { Component } from "react";
4
4
  import { Button } from "../ui/components/Button";
5
5
  import { Heading, Text } from "../ui/components/Typography";
6
6
  function DefaultFallback({ error, onReset, }) {
7
- return (_jsxs("div", { className: "flex min-h-[40vh] flex-col items-center justify-center gap-4 rounded-xl border border-zinc-200 bg-white p-6 text-center dark:border-slate-700 dark:bg-slate-900", "data-section": "errorboundary-div-445", children: [_jsx(Heading, { level: 2, children: "Something went wrong" }), _jsx(Text, { variant: "secondary", children: "An unexpected error occurred. Please try again." }), process.env.NODE_ENV === "development" && error ? (_jsx("pre", { className: "max-w-full overflow-auto rounded-md bg-zinc-100 p-3 text-left text-xs dark:bg-slate-800", children: error.message })) : null, _jsx(Button, { type: "button", onClick: onReset, children: "Try again" })] }));
7
+ return (_jsxs("div", { className: "flex min-h-[40vh] flex-col items-center justify-center gap-4 rounded-xl border border-zinc-200 bg-[var(--appkit-color-surface)] p-6 text-center border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", "data-section": "errorboundary-div-445", children: [_jsx(Heading, { level: 2, children: "Something went wrong" }), _jsx(Text, { variant: "secondary", children: "An unexpected error occurred. Please try again." }), process.env.NODE_ENV === "development" && error ? (_jsx("pre", { className: "max-w-full overflow-auto rounded-md bg-[var(--appkit-color-surface)] p-3 text-left text-xs bg-[var(--appkit-color-surface-elevated)]", children: error.message })) : null, _jsx(Button, { type: "button", onClick: onReset, children: "Try again" })] }));
8
8
  }
9
9
  export class ErrorBoundary extends Component {
10
10
  constructor(props) {
@@ -20,6 +20,9 @@
20
20
  * ```
21
21
  */
22
22
  import { getAdminStorageLite } from "../db-firebase/admin-storage-lite";
23
+ import { withRetry } from "../../http/retry";
24
+ import { normalizeError } from "../../errors/normalize";
25
+ import { serverLogger } from "../../monitoring/server-logger";
23
26
  function getBucket() {
24
27
  const bucketName = process.env.FIREBASE_ADMIN_STORAGE_BUCKET?.trim() ??
25
28
  process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET?.trim();
@@ -29,75 +32,126 @@ function getBucket() {
29
32
  }
30
33
  export const firebaseStorageProvider = {
31
34
  async upload(file, storagePath, options) {
32
- const bucket = getBucket();
33
- const fileRef = bucket.file(storagePath);
34
- await fileRef.save(file, {
35
- metadata: {
36
- contentType: options?.contentType ?? "application/octet-stream",
37
- cacheControl: options?.cacheControl ?? "public, max-age=31536000",
38
- metadata: options?.metadata ?? {},
39
- },
40
- public: options?.isPublic !== false,
41
- });
42
- const [metadata] = await fileRef.getMetadata();
43
- const url = options?.isPublic !== false
44
- ? `https://storage.googleapis.com/${bucket.name}/${storagePath}`
45
- : await fileRef
46
- .getSignedUrl({
47
- action: "read",
48
- expires: Date.now() + 60 * 60 * 1000, // 1 hour
49
- })
50
- .then(([u]) => u);
51
- return {
52
- path: storagePath,
53
- url,
54
- contentType: metadata.contentType,
55
- size: Number(metadata.size),
56
- updatedAt: metadata.updated,
57
- };
35
+ try {
36
+ const bucket = getBucket();
37
+ const fileRef = bucket.file(storagePath);
38
+ await withRetry(() => fileRef.save(file, {
39
+ metadata: {
40
+ contentType: options?.contentType ?? "application/octet-stream",
41
+ cacheControl: options?.cacheControl ?? "public, max-age=31536000",
42
+ metadata: options?.metadata ?? {},
43
+ },
44
+ public: options?.isPublic !== false,
45
+ }), 2, 300);
46
+ const [metadata] = await withRetry(() => fileRef.getMetadata(), 2, 300);
47
+ const url = options?.isPublic !== false
48
+ ? `https://storage.googleapis.com/${bucket.name}/${storagePath}`
49
+ : await withRetry(() => fileRef
50
+ .getSignedUrl({
51
+ action: "read",
52
+ expires: Date.now() + 60 * 60 * 1000,
53
+ })
54
+ .then(([u]) => u), 2, 300);
55
+ return {
56
+ path: storagePath,
57
+ url,
58
+ contentType: metadata.contentType,
59
+ size: Number(metadata.size),
60
+ updatedAt: metadata.updated,
61
+ };
62
+ }
63
+ catch (err) {
64
+ void normalizeError(err);
65
+ serverLogger.error("storage-provider: upload failed", {
66
+ storagePath,
67
+ error: err instanceof Error ? err.message : String(err),
68
+ });
69
+ throw err;
70
+ }
58
71
  },
59
72
  async delete(storagePath) {
60
- await getBucket().file(storagePath).delete({ ignoreNotFound: true });
73
+ try {
74
+ await withRetry(() => getBucket().file(storagePath).delete({ ignoreNotFound: true }), 2, 300);
75
+ }
76
+ catch (err) {
77
+ void normalizeError(err);
78
+ serverLogger.error("storage-provider: delete failed", {
79
+ storagePath,
80
+ error: err instanceof Error ? err.message : String(err),
81
+ });
82
+ throw err;
83
+ }
61
84
  },
62
85
  getPublicUrl(storagePath) {
63
86
  const bucket = getBucket();
64
87
  return `https://storage.googleapis.com/${bucket.name}/${storagePath}`;
65
88
  },
66
89
  async getSignedUrl(storagePath, expiresInSeconds = 3600) {
67
- const [url] = await getBucket()
68
- .file(storagePath)
69
- .getSignedUrl({
70
- action: "read",
71
- expires: Date.now() + expiresInSeconds * 1000,
72
- });
73
- return url;
90
+ try {
91
+ const [url] = await withRetry(() => getBucket()
92
+ .file(storagePath)
93
+ .getSignedUrl({
94
+ action: "read",
95
+ expires: Date.now() + expiresInSeconds * 1000,
96
+ }), 2, 300);
97
+ return url;
98
+ }
99
+ catch (err) {
100
+ void normalizeError(err);
101
+ serverLogger.error("storage-provider: getSignedUrl failed", {
102
+ storagePath,
103
+ error: err instanceof Error ? err.message : String(err),
104
+ });
105
+ throw err;
106
+ }
74
107
  },
75
108
  async copy(from, to) {
76
- const bucket = getBucket();
77
- const src = bucket.file(from);
78
- const dest = bucket.file(to);
79
- await src.copy(dest);
80
- const [metadata] = await dest.getMetadata();
81
- return {
82
- path: to,
83
- url: `https://storage.googleapis.com/${bucket.name}/${to}`,
84
- contentType: metadata.contentType,
85
- size: Number(metadata.size),
86
- updatedAt: metadata.updated,
87
- };
88
- },
89
- async list(prefix) {
90
- const bucket = getBucket();
91
- const [files] = await bucket.getFiles({ prefix });
92
- return Promise.all(files.map(async (f) => {
93
- const [metadata] = await f.getMetadata();
109
+ try {
110
+ const bucket = getBucket();
111
+ const src = bucket.file(from);
112
+ const dest = bucket.file(to);
113
+ await withRetry(() => src.copy(dest), 2, 300);
114
+ const [metadata] = await withRetry(() => dest.getMetadata(), 2, 300);
94
115
  return {
95
- path: f.name,
96
- url: `https://storage.googleapis.com/${bucket.name}/${f.name}`,
116
+ path: to,
117
+ url: `https://storage.googleapis.com/${bucket.name}/${to}`,
97
118
  contentType: metadata.contentType,
98
119
  size: Number(metadata.size),
99
120
  updatedAt: metadata.updated,
100
121
  };
101
- }));
122
+ }
123
+ catch (err) {
124
+ void normalizeError(err);
125
+ serverLogger.error("storage-provider: copy failed", {
126
+ from,
127
+ to,
128
+ error: err instanceof Error ? err.message : String(err),
129
+ });
130
+ throw err;
131
+ }
132
+ },
133
+ async list(prefix) {
134
+ try {
135
+ const bucket = getBucket();
136
+ const [files] = await withRetry(() => bucket.getFiles({ prefix }), 2, 300);
137
+ return Promise.all(files.map(async (f) => {
138
+ const [metadata] = await withRetry(() => f.getMetadata(), 2, 300);
139
+ return {
140
+ path: f.name,
141
+ url: `https://storage.googleapis.com/${bucket.name}/${f.name}`,
142
+ contentType: metadata.contentType,
143
+ size: Number(metadata.size),
144
+ updatedAt: metadata.updated,
145
+ };
146
+ }));
147
+ }
148
+ catch (err) {
149
+ void normalizeError(err);
150
+ serverLogger.error("storage-provider: list failed", {
151
+ prefix,
152
+ error: err instanceof Error ? err.message : String(err),
153
+ });
154
+ throw err;
155
+ }
102
156
  },
103
157
  };
@@ -51,3 +51,5 @@ export { ProductFeaturesRepository, productFeaturesRepository, } from "../featur
51
51
  export type { ProductFeatureListFilter } from "../features/products/repository/product-features.repository";
52
52
  export { loadProductFeaturesForStore } from "../features/products/repository/loadProductFeatures";
53
53
  export { LotteryEntryRepository, lotteryEntryRepository, } from "../features/lottery/repository/lottery-entry.repository";
54
+ export { MediaAssetsRepository, mediaAssetsRepository, } from "../features/media/repository/media-assets.repository";
55
+ export type { MediaAssetDocument, MediaAssetCreateInput, } from "../features/media/repository/media-assets.repository";
@@ -62,3 +62,5 @@ export { loadProductFeaturesForStore } from "../features/products/repository/loa
62
62
  // listByType / findBySlugAndType helpers.
63
63
  // Lottery entries repository
64
64
  export { LotteryEntryRepository, lotteryEntryRepository, } from "../features/lottery/repository/lottery-entry.repository";
65
+ // Media assets — short ID → storagePath mapping for SEO-friendly /media/{id} URLs
66
+ export { MediaAssetsRepository, mediaAssetsRepository, } from "../features/media/repository/media-assets.repository";