react-native-iap 14.2.2 → 14.2.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.
Files changed (32) hide show
  1. package/NitroIap.podspec +4 -1
  2. package/README.md +10 -0
  3. package/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt +5 -1
  4. package/app.plugin.js +1 -1
  5. package/lib/module/helpers/subscription.js.map +1 -1
  6. package/lib/module/hooks/useIAP.js.map +1 -1
  7. package/lib/module/index.js.map +1 -1
  8. package/lib/module/types/react-test-renderer.d.js +2 -0
  9. package/lib/module/types/react-test-renderer.d.js.map +1 -0
  10. package/lib/module/utils/error.js.map +1 -1
  11. package/lib/module/utils/errorMapping.js.map +1 -1
  12. package/lib/module/utils/type-bridge.js.map +1 -1
  13. package/lib/typescript/plugin/src/withIAP.d.ts.map +1 -1
  14. package/lib/typescript/src/helpers/subscription.d.ts.map +1 -1
  15. package/lib/typescript/src/hooks/useIAP.d.ts.map +1 -1
  16. package/lib/typescript/src/index.d.ts.map +1 -1
  17. package/lib/typescript/src/specs/RnIap.nitro.d.ts.map +1 -1
  18. package/lib/typescript/src/types.d.ts.map +1 -1
  19. package/lib/typescript/src/utils/error.d.ts.map +1 -1
  20. package/lib/typescript/src/utils/errorMapping.d.ts.map +1 -1
  21. package/lib/typescript/src/utils/type-bridge.d.ts.map +1 -1
  22. package/package.json +1 -9
  23. package/plugin/src/withIAP.ts +59 -59
  24. package/src/helpers/subscription.ts +21 -21
  25. package/src/hooks/useIAP.ts +193 -193
  26. package/src/index.ts +346 -344
  27. package/src/specs/RnIap.nitro.ts +160 -157
  28. package/src/types/react-test-renderer.d.ts +7 -0
  29. package/src/types.ts +294 -294
  30. package/src/utils/error.ts +19 -19
  31. package/src/utils/errorMapping.ts +13 -13
  32. package/src/utils/type-bridge.ts +94 -93
@@ -1,6 +1,6 @@
1
1
  // External dependencies
2
- import { useCallback, useEffect, useState, useRef } from 'react'
3
- import { Platform } from 'react-native'
2
+ import {useCallback, useEffect, useState, useRef} from 'react';
3
+ import {Platform} from 'react-native';
4
4
 
5
5
  // Internal modules
6
6
  import {
@@ -16,8 +16,8 @@ import {
16
16
  getActiveSubscriptions,
17
17
  hasActiveSubscriptions,
18
18
  restorePurchases as restorePurchasesTopLevel,
19
- } from '../'
20
- import { getPromotedProductIOS, requestPurchaseOnPromotedProductIOS } from '../'
19
+ } from '../';
20
+ import {getPromotedProductIOS, requestPurchaseOnPromotedProductIOS} from '../';
21
21
 
22
22
  // Types
23
23
  import type {
@@ -29,76 +29,76 @@ import type {
29
29
  RequestPurchaseProps,
30
30
  RequestSubscriptionProps,
31
31
  ActiveSubscription,
32
- } from '../types'
32
+ } from '../types';
33
33
 
34
34
  // Types for event subscriptions
35
35
  interface EventSubscription {
36
- remove(): void
36
+ remove(): void;
37
37
  }
38
38
 
39
39
  type UseIap = {
40
- connected: boolean
41
- products: Product[]
42
- promotedProductsIOS: Purchase[]
43
- promotedProductIdIOS?: string
44
- subscriptions: SubscriptionProduct[]
45
- availablePurchases: Purchase[]
46
- currentPurchase?: Purchase
47
- currentPurchaseError?: PurchaseError
48
- promotedProductIOS?: Product
49
- activeSubscriptions: ActiveSubscription[]
50
- clearCurrentPurchase: () => void
51
- clearCurrentPurchaseError: () => void
40
+ connected: boolean;
41
+ products: Product[];
42
+ promotedProductsIOS: Purchase[];
43
+ promotedProductIdIOS?: string;
44
+ subscriptions: SubscriptionProduct[];
45
+ availablePurchases: Purchase[];
46
+ currentPurchase?: Purchase;
47
+ currentPurchaseError?: PurchaseError;
48
+ promotedProductIOS?: Product;
49
+ activeSubscriptions: ActiveSubscription[];
50
+ clearCurrentPurchase: () => void;
51
+ clearCurrentPurchaseError: () => void;
52
52
  finishTransaction: ({
53
53
  purchase,
54
54
  isConsumable,
55
55
  }: {
56
- purchase: Purchase
57
- isConsumable?: boolean
58
- }) => Promise<PurchaseResult | boolean>
59
- getAvailablePurchases: (skus?: string[]) => Promise<void>
56
+ purchase: Purchase;
57
+ isConsumable?: boolean;
58
+ }) => Promise<PurchaseResult | boolean>;
59
+ getAvailablePurchases: (skus?: string[]) => Promise<void>;
60
60
  fetchProducts: (params: {
61
- skus: string[]
62
- type?: 'inapp' | 'subs'
63
- }) => Promise<void>
61
+ skus: string[];
62
+ type?: 'inapp' | 'subs';
63
+ }) => Promise<void>;
64
64
  /**
65
65
  * @deprecated Use fetchProducts({ skus, type: 'inapp' }) instead. This method will be removed in version 3.0.0.
66
66
  * Note: This method internally uses fetchProducts, so no deprecation warning is shown.
67
67
  */
68
- getProducts: (skus: string[]) => Promise<void>
68
+ getProducts: (skus: string[]) => Promise<void>;
69
69
  /**
70
70
  * @deprecated Use fetchProducts({ skus, type: 'subs' }) instead. This method will be removed in version 3.0.0.
71
71
  * Note: This method internally uses fetchProducts, so no deprecation warning is shown.
72
72
  */
73
- getSubscriptions: (skus: string[]) => Promise<void>
73
+ getSubscriptions: (skus: string[]) => Promise<void>;
74
74
  requestPurchase: (params: {
75
- request: RequestPurchaseProps | RequestSubscriptionProps
76
- type?: 'inapp' | 'subs'
77
- }) => Promise<any>
75
+ request: RequestPurchaseProps | RequestSubscriptionProps;
76
+ type?: 'inapp' | 'subs';
77
+ }) => Promise<any>;
78
78
  validateReceipt: (
79
79
  sku: string,
80
80
  androidOptions?: {
81
- packageName: string
82
- productToken: string
83
- accessToken: string
84
- isSub?: boolean
85
- }
86
- ) => Promise<any>
87
- restorePurchases: () => Promise<void>
88
- getPromotedProductIOS: () => Promise<Product | null>
89
- requestPurchaseOnPromotedProductIOS: () => Promise<void>
81
+ packageName: string;
82
+ productToken: string;
83
+ accessToken: string;
84
+ isSub?: boolean;
85
+ },
86
+ ) => Promise<any>;
87
+ restorePurchases: () => Promise<void>;
88
+ getPromotedProductIOS: () => Promise<Product | null>;
89
+ requestPurchaseOnPromotedProductIOS: () => Promise<void>;
90
90
  getActiveSubscriptions: (
91
- subscriptionIds?: string[]
92
- ) => Promise<ActiveSubscription[]>
93
- hasActiveSubscriptions: (subscriptionIds?: string[]) => Promise<boolean>
94
- }
91
+ subscriptionIds?: string[],
92
+ ) => Promise<ActiveSubscription[]>;
93
+ hasActiveSubscriptions: (subscriptionIds?: string[]) => Promise<boolean>;
94
+ };
95
95
 
96
96
  export interface UseIapOptions {
97
- onPurchaseSuccess?: (purchase: Purchase) => void
98
- onPurchaseError?: (error: PurchaseError) => void
99
- onSyncError?: (error: Error) => void
100
- shouldAutoSyncPurchases?: boolean // New option to control auto-syncing
101
- onPromotedProductIOS?: (product: Product) => void
97
+ onPurchaseSuccess?: (purchase: Purchase) => void;
98
+ onPurchaseError?: (error: PurchaseError) => void;
99
+ onSyncError?: (error: Error) => void;
100
+ shouldAutoSyncPurchases?: boolean; // New option to control auto-syncing
101
+ onPromotedProductIOS?: (product: Product) => void;
102
102
  }
103
103
 
104
104
  /**
@@ -106,145 +106,145 @@ export interface UseIapOptions {
106
106
  * See documentation at https://react-native-iap.hyo.dev/docs/hooks/useIAP
107
107
  */
108
108
  export function useIAP(options?: UseIapOptions): UseIap {
109
- const [connected, setConnected] = useState<boolean>(false)
110
- const [products, setProducts] = useState<Product[]>([])
111
- const [promotedProductsIOS] = useState<Purchase[]>([])
112
- const [subscriptions, setSubscriptions] = useState<SubscriptionProduct[]>([])
113
- const [availablePurchases, setAvailablePurchases] = useState<Purchase[]>([])
114
- const [currentPurchase, setCurrentPurchase] = useState<Purchase>()
115
- const [promotedProductIOS, setPromotedProductIOS] = useState<Product>()
109
+ const [connected, setConnected] = useState<boolean>(false);
110
+ const [products, setProducts] = useState<Product[]>([]);
111
+ const [promotedProductsIOS] = useState<Purchase[]>([]);
112
+ const [subscriptions, setSubscriptions] = useState<SubscriptionProduct[]>([]);
113
+ const [availablePurchases, setAvailablePurchases] = useState<Purchase[]>([]);
114
+ const [currentPurchase, setCurrentPurchase] = useState<Purchase>();
115
+ const [promotedProductIOS, setPromotedProductIOS] = useState<Product>();
116
116
  const [currentPurchaseError, setCurrentPurchaseError] =
117
- useState<PurchaseError>()
118
- const [promotedProductIdIOS] = useState<string>()
117
+ useState<PurchaseError>();
118
+ const [promotedProductIdIOS] = useState<string>();
119
119
  const [activeSubscriptions, setActiveSubscriptions] = useState<
120
120
  ActiveSubscription[]
121
- >([])
121
+ >([]);
122
122
 
123
- const optionsRef = useRef<UseIapOptions | undefined>(options)
124
- const connectedRef = useRef<boolean>(false)
123
+ const optionsRef = useRef<UseIapOptions | undefined>(options);
124
+ const connectedRef = useRef<boolean>(false);
125
125
 
126
126
  // Helper function to merge arrays with duplicate checking
127
127
  const mergeWithDuplicateCheck = useCallback(
128
128
  <T>(
129
129
  existingItems: T[],
130
130
  newItems: T[],
131
- getKey: (item: T) => string
131
+ getKey: (item: T) => string,
132
132
  ): T[] => {
133
- const merged = [...existingItems]
133
+ const merged = [...existingItems];
134
134
  newItems.forEach((newItem) => {
135
135
  const isDuplicate = merged.some(
136
- (existingItem) => getKey(existingItem) === getKey(newItem)
137
- )
136
+ (existingItem) => getKey(existingItem) === getKey(newItem),
137
+ );
138
138
  if (!isDuplicate) {
139
- merged.push(newItem)
139
+ merged.push(newItem);
140
140
  }
141
- })
142
- return merged
141
+ });
142
+ return merged;
143
143
  },
144
- []
145
- )
144
+ [],
145
+ );
146
146
 
147
147
  useEffect(() => {
148
- optionsRef.current = options
149
- }, [options])
148
+ optionsRef.current = options;
149
+ }, [options]);
150
150
 
151
151
  useEffect(() => {
152
- connectedRef.current = connected
153
- }, [connected])
152
+ connectedRef.current = connected;
153
+ }, [connected]);
154
154
 
155
155
  const subscriptionsRef = useRef<{
156
- purchaseUpdate?: EventSubscription
157
- purchaseError?: EventSubscription
158
- promotedProductsIOS?: EventSubscription
159
- promotedProductIOS?: EventSubscription
160
- }>({})
156
+ purchaseUpdate?: EventSubscription;
157
+ purchaseError?: EventSubscription;
158
+ promotedProductsIOS?: EventSubscription;
159
+ promotedProductIOS?: EventSubscription;
160
+ }>({});
161
161
 
162
- const subscriptionsRefState = useRef<SubscriptionProduct[]>([])
162
+ const subscriptionsRefState = useRef<SubscriptionProduct[]>([]);
163
163
 
164
164
  useEffect(() => {
165
- subscriptionsRefState.current = subscriptions
166
- }, [subscriptions])
165
+ subscriptionsRefState.current = subscriptions;
166
+ }, [subscriptions]);
167
167
 
168
168
  const clearCurrentPurchase = useCallback(() => {
169
- setCurrentPurchase(undefined)
170
- }, [])
169
+ setCurrentPurchase(undefined);
170
+ }, []);
171
171
 
172
172
  const clearCurrentPurchaseError = useCallback(() => {
173
- setCurrentPurchaseError(undefined)
174
- }, [])
173
+ setCurrentPurchaseError(undefined);
174
+ }, []);
175
175
 
176
176
  const getProductsInternal = useCallback(
177
177
  async (skus: string[]): Promise<void> => {
178
178
  try {
179
- const result = await fetchProducts({ skus, type: 'inapp' })
179
+ const result = await fetchProducts({skus, type: 'inapp'});
180
180
  setProducts((prevProducts: Product[]) =>
181
181
  mergeWithDuplicateCheck(
182
182
  prevProducts,
183
183
  result as Product[],
184
- (product: Product) => product.id
185
- )
186
- )
184
+ (product: Product) => product.id,
185
+ ),
186
+ );
187
187
  } catch (error) {
188
- console.error('Error fetching products:', error)
188
+ console.error('Error fetching products:', error);
189
189
  }
190
190
  },
191
- [mergeWithDuplicateCheck]
192
- )
191
+ [mergeWithDuplicateCheck],
192
+ );
193
193
 
194
194
  const getSubscriptionsInternal = useCallback(
195
195
  async (skus: string[]): Promise<void> => {
196
196
  try {
197
- const result = await fetchProducts({ skus, type: 'subs' })
197
+ const result = await fetchProducts({skus, type: 'subs'});
198
198
  setSubscriptions((prevSubscriptions: SubscriptionProduct[]) =>
199
199
  mergeWithDuplicateCheck(
200
200
  prevSubscriptions,
201
201
  result as SubscriptionProduct[],
202
- (subscription: SubscriptionProduct) => subscription.id
203
- )
204
- )
202
+ (subscription: SubscriptionProduct) => subscription.id,
203
+ ),
204
+ );
205
205
  } catch (error) {
206
- console.error('Error fetching subscriptions:', error)
206
+ console.error('Error fetching subscriptions:', error);
207
207
  }
208
208
  },
209
- [mergeWithDuplicateCheck]
210
- )
209
+ [mergeWithDuplicateCheck],
210
+ );
211
211
 
212
212
  const fetchProductsInternal = useCallback(
213
213
  async (params: {
214
- skus: string[]
215
- type?: 'inapp' | 'subs'
214
+ skus: string[];
215
+ type?: 'inapp' | 'subs';
216
216
  }): Promise<void> => {
217
217
  if (!connectedRef.current) {
218
218
  console.warn(
219
- '[useIAP] fetchProducts called before connection; skipping'
220
- )
221
- return
219
+ '[useIAP] fetchProducts called before connection; skipping',
220
+ );
221
+ return;
222
222
  }
223
223
  try {
224
- const result = await fetchProducts(params)
224
+ const result = await fetchProducts(params);
225
225
  if (params.type === 'subs') {
226
226
  setSubscriptions((prevSubscriptions: SubscriptionProduct[]) =>
227
227
  mergeWithDuplicateCheck(
228
228
  prevSubscriptions,
229
229
  result as SubscriptionProduct[],
230
- (subscription: SubscriptionProduct) => subscription.id
231
- )
232
- )
230
+ (subscription: SubscriptionProduct) => subscription.id,
231
+ ),
232
+ );
233
233
  } else {
234
234
  setProducts((prevProducts: Product[]) =>
235
235
  mergeWithDuplicateCheck(
236
236
  prevProducts,
237
237
  result as Product[],
238
- (product: Product) => product.id
239
- )
240
- )
238
+ (product: Product) => product.id,
239
+ ),
240
+ );
241
241
  }
242
242
  } catch (error) {
243
- console.error('Error fetching products:', error)
243
+ console.error('Error fetching products:', error);
244
244
  }
245
245
  },
246
- [mergeWithDuplicateCheck]
247
- )
246
+ [mergeWithDuplicateCheck],
247
+ );
248
248
 
249
249
  const getAvailablePurchasesInternal = useCallback(
250
250
  async (_skus?: string[]): Promise<void> => {
@@ -252,64 +252,64 @@ export function useIAP(options?: UseIapOptions): UseIap {
252
252
  const result = await getAvailablePurchases({
253
253
  alsoPublishToEventListenerIOS: false,
254
254
  onlyIncludeActiveItemsIOS: true,
255
- })
256
- setAvailablePurchases(result)
255
+ });
256
+ setAvailablePurchases(result);
257
257
  } catch (error) {
258
- console.error('Error fetching available purchases:', error)
258
+ console.error('Error fetching available purchases:', error);
259
259
  }
260
260
  },
261
- []
262
- )
261
+ [],
262
+ );
263
263
 
264
264
  const getActiveSubscriptionsInternal = useCallback(
265
265
  async (subscriptionIds?: string[]): Promise<ActiveSubscription[]> => {
266
266
  try {
267
- const result = await getActiveSubscriptions(subscriptionIds)
268
- setActiveSubscriptions(result)
269
- return result
267
+ const result = await getActiveSubscriptions(subscriptionIds);
268
+ setActiveSubscriptions(result);
269
+ return result;
270
270
  } catch (error) {
271
- console.error('Error getting active subscriptions:', error)
271
+ console.error('Error getting active subscriptions:', error);
272
272
  // Don't clear existing activeSubscriptions on error - preserve current state
273
273
  // This prevents the UI from showing empty state when there are temporary network issues
274
- return []
274
+ return [];
275
275
  }
276
276
  },
277
- []
278
- )
277
+ [],
278
+ );
279
279
 
280
280
  const hasActiveSubscriptionsInternal = useCallback(
281
281
  async (subscriptionIds?: string[]): Promise<boolean> => {
282
282
  try {
283
- return await hasActiveSubscriptions(subscriptionIds)
283
+ return await hasActiveSubscriptions(subscriptionIds);
284
284
  } catch (error) {
285
- console.error('Error checking active subscriptions:', error)
286
- return false
285
+ console.error('Error checking active subscriptions:', error);
286
+ return false;
287
287
  }
288
288
  },
289
- []
290
- )
289
+ [],
290
+ );
291
291
 
292
292
  const finishTransaction = useCallback(
293
293
  async ({
294
294
  purchase,
295
295
  isConsumable,
296
296
  }: {
297
- purchase: Purchase
298
- isConsumable?: boolean
297
+ purchase: Purchase;
298
+ isConsumable?: boolean;
299
299
  }): Promise<PurchaseResult | boolean> => {
300
300
  try {
301
301
  return await finishTransactionInternal({
302
302
  purchase,
303
303
  isConsumable,
304
- })
304
+ });
305
305
  } catch (err) {
306
- throw err
306
+ throw err;
307
307
  } finally {
308
308
  if (purchase.id === currentPurchase?.id) {
309
- clearCurrentPurchase()
309
+ clearCurrentPurchase();
310
310
  }
311
311
  if (purchase.id === currentPurchaseError?.productId) {
312
- clearCurrentPurchaseError()
312
+ clearCurrentPurchaseError();
313
313
  }
314
314
  }
315
315
  },
@@ -318,22 +318,22 @@ export function useIAP(options?: UseIapOptions): UseIap {
318
318
  currentPurchaseError?.productId,
319
319
  clearCurrentPurchase,
320
320
  clearCurrentPurchaseError,
321
- ]
322
- )
321
+ ],
322
+ );
323
323
 
324
324
  const requestPurchaseWithReset = useCallback(
325
- async (requestObj: { request: any; type?: 'inapp' | 'subs' }) => {
326
- clearCurrentPurchase()
327
- clearCurrentPurchaseError()
325
+ async (requestObj: {request: any; type?: 'inapp' | 'subs'}) => {
326
+ clearCurrentPurchase();
327
+ clearCurrentPurchaseError();
328
328
 
329
329
  try {
330
- return await requestPurchaseInternal(requestObj)
330
+ return await requestPurchaseInternal(requestObj);
331
331
  } catch (error) {
332
- throw error
332
+ throw error;
333
333
  }
334
334
  },
335
- [clearCurrentPurchase, clearCurrentPurchaseError]
336
- )
335
+ [clearCurrentPurchase, clearCurrentPurchaseError],
336
+ );
337
337
 
338
338
  // No local restorePurchases; use the top-level helper via returned API
339
339
 
@@ -341,35 +341,35 @@ export function useIAP(options?: UseIapOptions): UseIap {
341
341
  async (
342
342
  sku: string,
343
343
  androidOptions?: {
344
- packageName: string
345
- productToken: string
346
- accessToken: string
347
- isSub?: boolean
348
- }
344
+ packageName: string;
345
+ productToken: string;
346
+ accessToken: string;
347
+ isSub?: boolean;
348
+ },
349
349
  ) => {
350
- return validateReceiptInternal(sku, androidOptions)
350
+ return validateReceiptInternal(sku, androidOptions);
351
351
  },
352
- []
353
- )
352
+ [],
353
+ );
354
354
 
355
355
  const initIapWithSubscriptions = useCallback(async (): Promise<void> => {
356
356
  // Register listeners BEFORE initConnection to avoid race condition
357
357
  subscriptionsRef.current.purchaseUpdate = purchaseUpdatedListener(
358
358
  async (purchase: Purchase) => {
359
- setCurrentPurchaseError(undefined)
360
- setCurrentPurchase(purchase)
359
+ setCurrentPurchaseError(undefined);
360
+ setCurrentPurchase(purchase);
361
361
  // Always refresh subscription state after a purchase event
362
362
  try {
363
- await getActiveSubscriptionsInternal()
364
- await getAvailablePurchasesInternal()
363
+ await getActiveSubscriptionsInternal();
364
+ await getAvailablePurchasesInternal();
365
365
  } catch (e) {
366
- console.warn('[useIAP] post-purchase refresh failed:', e)
366
+ console.warn('[useIAP] post-purchase refresh failed:', e);
367
367
  }
368
368
  if (optionsRef.current?.onPurchaseSuccess) {
369
- optionsRef.current.onPurchaseSuccess(purchase)
369
+ optionsRef.current.onPurchaseSuccess(purchase);
370
370
  }
371
- }
372
- )
371
+ },
372
+ );
373
373
 
374
374
  subscriptionsRef.current.purchaseError = purchaseErrorListener(
375
375
  (error: PurchaseError) => {
@@ -379,52 +379,52 @@ export function useIAP(options?: UseIapOptions): UseIap {
379
379
  (error as any).code === 'E_INIT_CONNECTION' &&
380
380
  !connectedRef.current
381
381
  ) {
382
- return
382
+ return;
383
383
  }
384
- setCurrentPurchase(undefined)
385
- setCurrentPurchaseError(error)
384
+ setCurrentPurchase(undefined);
385
+ setCurrentPurchaseError(error);
386
386
  if (optionsRef.current?.onPurchaseError) {
387
- optionsRef.current.onPurchaseError(error)
387
+ optionsRef.current.onPurchaseError(error);
388
388
  }
389
- }
390
- )
389
+ },
390
+ );
391
391
 
392
392
  if (Platform.OS === 'ios') {
393
393
  subscriptionsRef.current.promotedProductsIOS = promotedProductListenerIOS(
394
394
  (product: Product) => {
395
- setPromotedProductIOS(product)
395
+ setPromotedProductIOS(product);
396
396
  if (optionsRef.current?.onPromotedProductIOS) {
397
- optionsRef.current.onPromotedProductIOS(product)
397
+ optionsRef.current.onPromotedProductIOS(product);
398
398
  }
399
- }
400
- )
399
+ },
400
+ );
401
401
  }
402
402
 
403
- const result = await initConnection()
404
- setConnected(result)
403
+ const result = await initConnection();
404
+ setConnected(result);
405
405
  if (!result) {
406
406
  // Clean up some listeners but leave purchaseError for potential retries
407
- subscriptionsRef.current.purchaseUpdate?.remove()
408
- subscriptionsRef.current.promotedProductsIOS?.remove()
409
- subscriptionsRef.current.purchaseUpdate = undefined
410
- subscriptionsRef.current.promotedProductsIOS = undefined
411
- return
407
+ subscriptionsRef.current.purchaseUpdate?.remove();
408
+ subscriptionsRef.current.promotedProductsIOS?.remove();
409
+ subscriptionsRef.current.purchaseUpdate = undefined;
410
+ subscriptionsRef.current.promotedProductsIOS = undefined;
411
+ return;
412
412
  }
413
- }, [getActiveSubscriptionsInternal, getAvailablePurchasesInternal])
413
+ }, [getActiveSubscriptionsInternal, getAvailablePurchasesInternal]);
414
414
 
415
415
  useEffect(() => {
416
- initIapWithSubscriptions()
417
- const currentSubscriptions = subscriptionsRef.current
416
+ initIapWithSubscriptions();
417
+ const currentSubscriptions = subscriptionsRef.current;
418
418
 
419
419
  return () => {
420
- currentSubscriptions.purchaseUpdate?.remove()
421
- currentSubscriptions.purchaseError?.remove()
422
- currentSubscriptions.promotedProductsIOS?.remove()
423
- currentSubscriptions.promotedProductIOS?.remove()
420
+ currentSubscriptions.purchaseUpdate?.remove();
421
+ currentSubscriptions.purchaseError?.remove();
422
+ currentSubscriptions.promotedProductsIOS?.remove();
423
+ currentSubscriptions.promotedProductIOS?.remove();
424
424
  // Keep connection alive across screens to avoid race conditions
425
- setConnected(false)
426
- }
427
- }, [initIapWithSubscriptions])
425
+ setConnected(false);
426
+ };
427
+ }, [initIapWithSubscriptions]);
428
428
 
429
429
  return {
430
430
  connected,
@@ -449,10 +449,10 @@ export function useIAP(options?: UseIapOptions): UseIap {
449
449
  const purchases = await restorePurchasesTopLevel({
450
450
  alsoPublishToEventListenerIOS: false,
451
451
  onlyIncludeActiveItemsIOS: true,
452
- })
453
- setAvailablePurchases(purchases)
452
+ });
453
+ setAvailablePurchases(purchases);
454
454
  } catch (e) {
455
- console.warn('Failed to restore purchases:', e)
455
+ console.warn('Failed to restore purchases:', e);
456
456
  }
457
457
  },
458
458
  getProducts: getProductsInternal,
@@ -461,5 +461,5 @@ export function useIAP(options?: UseIapOptions): UseIap {
461
461
  requestPurchaseOnPromotedProductIOS,
462
462
  getActiveSubscriptions: getActiveSubscriptionsInternal,
463
463
  hasActiveSubscriptions: hasActiveSubscriptionsInternal,
464
- }
464
+ };
465
465
  }