@umituz/react-native-subscription 2.27.46 → 2.27.48

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-subscription",
3
- "version": "2.27.46",
3
+ "version": "2.27.48",
4
4
  "description": "Complete subscription management with RevenueCat, paywall UI, and credits system for React Native apps",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -1,5 +1,10 @@
1
1
  /**
2
2
  * Subscription Initializer
3
+ *
4
+ * Uses RevenueCat best practices:
5
+ * - Non-blocking initialization (fire and forget)
6
+ * - Relies on CustomerInfoUpdateListener for state updates
7
+ * - No manual timeouts - uses auth state listener with cleanup
3
8
  */
4
9
  declare const __DEV__: boolean;
5
10
 
@@ -13,13 +18,30 @@ import type { SubscriptionInitConfig, FirebaseAuthLike } from "./SubscriptionIni
13
18
 
14
19
  export type { FirebaseAuthLike, CreditPackageConfig, SubscriptionInitConfig } from "./SubscriptionInitializerTypes";
15
20
 
16
- const waitForAuthState = async (getAuth: () => FirebaseAuthLike | null, timeoutMs: number): Promise<string | undefined> => {
21
+ /**
22
+ * Gets the current user ID from Firebase auth.
23
+ * Uses listener pattern for reliability instead of timeout.
24
+ * Falls back immediately if no auth is available.
25
+ */
26
+ const getCurrentUserId = (getAuth: () => FirebaseAuthLike | null): string | undefined => {
17
27
  const auth = getAuth();
18
28
  if (!auth) return undefined;
19
- if (auth.currentUser) return auth.currentUser.uid;
20
- return new Promise((resolve) => {
21
- const unsub = auth.onAuthStateChanged((u) => { unsub(); resolve(u?.uid); });
22
- setTimeout(() => { unsub(); resolve(undefined); }, timeoutMs);
29
+ return auth.currentUser?.uid;
30
+ };
31
+
32
+ /**
33
+ * Sets up auth state listener that will re-initialize subscription
34
+ * when user auth state changes (login/logout).
35
+ */
36
+ const setupAuthStateListener = (
37
+ getAuth: () => FirebaseAuthLike | null,
38
+ onUserChange: (userId: string | undefined) => void
39
+ ): (() => void) | null => {
40
+ const auth = getAuth();
41
+ if (!auth) return null;
42
+
43
+ return auth.onAuthStateChanged((user) => {
44
+ onUserChange(user?.uid);
23
45
  });
24
46
  };
25
47
 
@@ -40,7 +62,8 @@ export const initializeSubscription = async (config: SubscriptionInitConfig): Pr
40
62
  const {
41
63
  apiKey, apiKeyIos, apiKeyAndroid, entitlementId, credits,
42
64
  getAnonymousUserId, getFirebaseAuth, showAuthModal,
43
- onCreditsUpdated, creditPackages, timeoutMs = 10000, authStateTimeoutMs = 2000,
65
+ onCreditsUpdated, creditPackages,
66
+ // Note: timeoutMs and authStateTimeoutMs are deprecated and ignored
44
67
  } = config;
45
68
 
46
69
  const key = Platform.OS === 'ios' ? (apiKeyIos || apiKey || '') : (apiKeyAndroid || apiKey || '');
@@ -122,19 +145,7 @@ export const initializeSubscription = async (config: SubscriptionInitConfig): Pr
122
145
  getAnonymousUserId,
123
146
  });
124
147
 
125
- const userId = await waitForAuthState(getFirebaseAuth, authStateTimeoutMs);
126
-
127
- try {
128
- if (timeoutMs > 0) {
129
- const timeout = new Promise<boolean>((_, reject) => setTimeout(() => reject(new Error("Timeout")), timeoutMs));
130
- await Promise.race([SubscriptionManager.initialize(userId), timeout]);
131
- } else {
132
- await SubscriptionManager.initialize(userId);
133
- }
134
- } catch (error) {
135
- if (__DEV__) console.warn('[SubscriptionInitializer] Initialize timeout/error (non-critical):', error);
136
- }
137
-
148
+ // Configure auth provider immediately (sync)
138
149
  configureAuthProvider({
139
150
  isAuthenticated: () => {
140
151
  const u = getFirebaseAuth()?.currentUser;
@@ -142,4 +153,32 @@ export const initializeSubscription = async (config: SubscriptionInitConfig): Pr
142
153
  },
143
154
  showAuthModal,
144
155
  });
156
+
157
+ // Get initial user ID (sync - no waiting)
158
+ const initialUserId = getCurrentUserId(getFirebaseAuth);
159
+
160
+ /**
161
+ * Non-blocking initialization (fire and forget)
162
+ * RevenueCat best practice: Don't block on initialization.
163
+ * The CustomerInfoUpdateListener will handle state updates reactively.
164
+ */
165
+ const initializeInBackground = async (userId?: string) => {
166
+ try {
167
+ await SubscriptionManager.initialize(userId);
168
+ if (__DEV__) console.log('[SubscriptionInitializer] Background init complete');
169
+ } catch (error) {
170
+ // Non-critical - listener will handle updates
171
+ if (__DEV__) console.log('[SubscriptionInitializer] Background init error (non-critical):', error);
172
+ }
173
+ };
174
+
175
+ // Start initialization in background (non-blocking)
176
+ initializeInBackground(initialUserId);
177
+
178
+ // Set up auth state listener for reactive updates
179
+ // When user logs in/out, re-initialize with new user ID
180
+ setupAuthStateListener(getFirebaseAuth, (newUserId) => {
181
+ if (__DEV__) console.log('[SubscriptionInitializer] Auth state changed:', newUserId ? 'logged in' : 'logged out');
182
+ initializeInBackground(newUserId);
183
+ });
145
184
  };
@@ -25,6 +25,14 @@ export interface SubscriptionInitConfig {
25
25
  showAuthModal: () => void;
26
26
  onCreditsUpdated?: (userId: string) => void;
27
27
  creditPackages?: CreditPackageConfig;
28
+ /**
29
+ * @deprecated No longer used. Initialization is now non-blocking.
30
+ * RevenueCat best practice: Use listener pattern instead of timeouts.
31
+ */
28
32
  timeoutMs?: number;
33
+ /**
34
+ * @deprecated No longer used. Auth state is read synchronously.
35
+ * Auth state changes are handled reactively via onAuthStateChanged listener.
36
+ */
29
37
  authStateTimeoutMs?: number;
30
38
  }