@mohasinac/appkit 4.6.1 → 4.6.3

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.
package/dist/client.d.ts CHANGED
@@ -194,6 +194,8 @@ export type { AuthGuardUser, ForgotPasswordViewProps, LoginFormProps, LoginFormV
194
194
  export { useLogout, useLogin, useGoogleLogin, useLinkGoogleAccount, useRegister, useForgotPassword, useResetPassword, useVerifyEmail, useChangePassword, useRequestPasswordChangeOtp, useVerifyPasswordChangeOtp, useChangeEmail } from "./features/auth/index";
195
195
  export type { LoginCredentials, RegisterData, ForgotPasswordData, ResetPasswordData, VerifyEmailData, ChangePasswordData, ChangeEmailData } from "./features/auth/index";
196
196
  export { CartView, CartItemRow, CartSummary, CartDrawer, CheckoutView, CheckoutSuccessView, CheckoutAddressStep, useGuestCart, useCartCount, useAddToCart, useCart, useGuestCartMerge, useCartQuery } from "./features/cart/index";
197
+ export { getCartOps, CART_OPS_CHANGE_EVENT } from "./features/cart/utils/pending-ops";
198
+ export type { CartOp } from "./features/cart/utils/pending-ops";
197
199
  export type { CartItem, CartItemMeta, CartData, GuestCartItem } from "./features/cart/index";
198
200
  export { useAddresses, useCreateAddress, useUpdateAddress, useDeleteAddress, useSetDefaultAddress, useAddress } from "./features/account/index";
199
201
  export type { Address, AddressFormData } from "./features/account/index";
@@ -220,6 +222,7 @@ export type { AdSlotId, AdProvider, AdSlotConfig } from "./features/homepage/ad-
220
222
  export { WishlistView, useGuestWishlist, useWishlistWithGuest } from "./features/wishlist/index";
221
223
  export type { WishlistViewProps, GuestWishlistItem, WishlistItem, WishlistResponse, WishlistProductData, EnrichedWishlistItem } from "./features/wishlist/index";
222
224
  export { WishlistCapWatcher } from "./features/wishlist/components/WishlistCapWatcher";
225
+ export { SyncManagerMount } from "./core/components/SyncManagerMount";
223
226
  export { useWishlistCount, useWishlistCountWithLimit, WISHLIST_CAP_EVENT } from "./features/wishlist/hooks/useWishlistCount";
224
227
  export type { WishlistCapEventDetail } from "./features/wishlist/hooks/useWishlistCount";
225
228
  export { getGuestWishlistItems, addToGuestWishlist, removeFromGuestWishlist, isInGuestWishlist, clearGuestWishlist, getGuestWishlistCount, getGuestWishlistByType, } from "./features/wishlist/utils/guest-wishlist";
package/dist/client.js CHANGED
@@ -224,6 +224,7 @@ export { AuctionBidsTable } from "./features/auctions/components/AuctionBidsTabl
224
224
  export { ProtectedRoute, AuthStatusPanel, ForgotPasswordView, LoginForm, RegisterForm, ResetPasswordView, VerifyEmailView } from "./features/auth/index";
225
225
  export { useLogout, useLogin, useGoogleLogin, useLinkGoogleAccount, useRegister, useForgotPassword, useResetPassword, useVerifyEmail, useChangePassword, useRequestPasswordChangeOtp, useVerifyPasswordChangeOtp, useChangeEmail } from "./features/auth/index";
226
226
  export { CartView, CartItemRow, CartSummary, CartDrawer, CheckoutView, CheckoutSuccessView, CheckoutAddressStep, useGuestCart, useCartCount, useAddToCart, useCart, useGuestCartMerge, useCartQuery } from "./features/cart/index";
227
+ export { getCartOps, CART_OPS_CHANGE_EVENT } from "./features/cart/utils/pending-ops";
227
228
  export { useAddresses, useCreateAddress, useUpdateAddress, useDeleteAddress, useSetDefaultAddress, useAddress } from "./features/account/index";
228
229
  export { AddressBook, AddressCard, AddressForm } from "./features/account/index";
229
230
  export { useProfile, useUpdateProfile } from "./features/account/index";
@@ -239,6 +240,7 @@ export { useActiveAd } from "./features/homepage/hooks/useActiveAd";
239
240
  export { registerAdSlot, registerAdSlots, unregisterAdSlot, clearAdRegistry, setAdConsentGranted, isAdConsentGranted, isAdSlotRenderable, } from "./features/homepage/ad-registry";
240
241
  export { WishlistView, useGuestWishlist, useWishlistWithGuest } from "./features/wishlist/index";
241
242
  export { WishlistCapWatcher } from "./features/wishlist/components/WishlistCapWatcher";
243
+ export { SyncManagerMount } from "./core/components/SyncManagerMount";
242
244
  export { useWishlistCount, useWishlistCountWithLimit, WISHLIST_CAP_EVENT } from "./features/wishlist/hooks/useWishlistCount";
243
245
  export { getGuestWishlistItems, addToGuestWishlist, removeFromGuestWishlist, isInGuestWishlist, clearGuestWishlist, getGuestWishlistCount, getGuestWishlistByType, } from "./features/wishlist/utils/guest-wishlist";
244
246
  export { InteractiveProductCard } from "./features/products/index";
@@ -0,0 +1 @@
1
+ export declare function SyncManagerMount(): null;
@@ -0,0 +1,23 @@
1
+ "use client";
2
+ /**
3
+ * SyncManagerMount — mounts useSyncManager() once, globally.
4
+ *
5
+ * Root-caused 2026-08-20: useSyncManager (the hook that replays the
6
+ * local-first cart/wishlist op queue against the server — see
7
+ * ../hooks/useSyncManager.ts) was never actually called anywhere in the
8
+ * app. Every listing-grid "Add to Cart"/"Add to Wishlist" button writes to
9
+ * a localStorage op queue and shows an immediately-optimistic toast +
10
+ * badge-count update (via the pending-ops delta), but with no mounted
11
+ * useSyncManager the queued op had no code path that would ever POST it
12
+ * to the server — the badge looked right, but the actual /cart or
13
+ * /user/wishlist page (reading the real server state) stayed empty
14
+ * forever, not just briefly. Mount this once, high in the tree, wherever
15
+ * the current session's uid is known.
16
+ */
17
+ import { useSyncManager } from "../hooks/useSyncManager";
18
+ import { useSession } from "../../react/contexts/SessionContext";
19
+ export function SyncManagerMount() {
20
+ const { user } = useSession();
21
+ useSyncManager(user?.uid);
22
+ return null;
23
+ }
@@ -14,6 +14,8 @@ export declare class FirebaseClientAuthProvider implements IClientAuthProvider {
14
14
  applyActionCode(code: string): Promise<void>;
15
15
  sendPasswordResetEmail(email: string): Promise<void>;
16
16
  confirmPasswordReset(code: string, newPassword: string): Promise<void>;
17
+ /** Re-authenticates the current user against `currentPassword`, returning the now-fresh user. Throws if no user is signed in. */
18
+ private _reauthenticate;
17
19
  reauthenticateAndChangePassword(currentPassword: string, newPassword: string): Promise<void>;
18
20
  reauthenticateOnly(currentPassword: string): Promise<void>;
19
21
  reauthenticateAndSendEmailUpdateVerification(currentPassword: string, newEmail: string): Promise<void>;
@@ -1,4 +1,5 @@
1
1
  import { applyActionCode as fbApplyActionCode, confirmPasswordReset as fbConfirmPasswordReset, EmailAuthProvider, reauthenticateWithCredential, sendPasswordResetEmail as fbSendPasswordResetEmail, signInWithEmailAndPassword as fbSignInWithEmailAndPassword, updatePassword, verifyBeforeUpdateEmail, } from "firebase/auth";
2
+ const NO_AUTHENTICATED_USER_MESSAGE = "No authenticated user.";
2
3
  /**
3
4
  * Firebase Auth client SDK implementation of IClientAuthProvider.
4
5
  *
@@ -22,27 +23,24 @@ export class FirebaseClientAuthProvider {
22
23
  async confirmPasswordReset(code, newPassword) {
23
24
  await fbConfirmPasswordReset(this._auth, code, newPassword);
24
25
  }
25
- async reauthenticateAndChangePassword(currentPassword, newPassword) {
26
+ /** Re-authenticates the current user against `currentPassword`, returning the now-fresh user. Throws if no user is signed in. */
27
+ async _reauthenticate(currentPassword) {
26
28
  const user = this._auth.currentUser;
27
29
  if (!user?.email)
28
- throw new Error("No authenticated user.");
30
+ throw new Error(NO_AUTHENTICATED_USER_MESSAGE);
29
31
  const credential = EmailAuthProvider.credential(user.email, currentPassword);
30
32
  await reauthenticateWithCredential(user, credential);
33
+ return user;
34
+ }
35
+ async reauthenticateAndChangePassword(currentPassword, newPassword) {
36
+ const user = await this._reauthenticate(currentPassword);
31
37
  await updatePassword(user, newPassword);
32
38
  }
33
39
  async reauthenticateOnly(currentPassword) {
34
- const user = this._auth.currentUser;
35
- if (!user?.email)
36
- throw new Error("No authenticated user.");
37
- const credential = EmailAuthProvider.credential(user.email, currentPassword);
38
- await reauthenticateWithCredential(user, credential);
40
+ await this._reauthenticate(currentPassword);
39
41
  }
40
42
  async reauthenticateAndSendEmailUpdateVerification(currentPassword, newEmail) {
41
- const user = this._auth.currentUser;
42
- if (!user?.email)
43
- throw new Error("No authenticated user.");
44
- const credential = EmailAuthProvider.credential(user.email, currentPassword);
45
- await reauthenticateWithCredential(user, credential);
43
+ const user = await this._reauthenticate(currentPassword);
46
44
  await verifyBeforeUpdateEmail(user, newEmail);
47
45
  }
48
46
  async reloadCurrentUser() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mohasinac/appkit",
3
- "version": "4.6.1",
3
+ "version": "4.6.3",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"