expo-iap 2.6.3 → 2.7.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.
@@ -1 +1 @@
1
- {"version":3,"file":"useIap.js","sourceRoot":"","sources":["../src/useIap.ts"],"names":[],"mappings":"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","sourcesContent":["// External dependencies\nimport {useCallback, useEffect, useState, useRef} from 'react';\nimport {Platform} from 'react-native';\nimport {EventSubscription} from 'expo-modules-core';\n\n// Internal modules\nimport {\n endConnection,\n initConnection,\n purchaseErrorListener,\n purchaseUpdatedListener,\n getProducts,\n getAvailablePurchases,\n getPurchaseHistories,\n finishTransaction as finishTransactionInternal,\n getSubscriptions,\n requestPurchase as requestPurchaseInternal,\n} from './';\nimport {syncIOS, validateReceiptIOS} from './modules/ios';\nimport {validateReceiptAndroid} from './modules/android';\n\n// Types\nimport {\n Product,\n ProductPurchase,\n Purchase,\n PurchaseError,\n PurchaseResult,\n SubscriptionProduct,\n SubscriptionPurchase,\n} from './ExpoIap.types';\n\ntype UseIap = {\n connected: boolean;\n products: Product[];\n promotedProductsIOS: ProductPurchase[];\n subscriptions: SubscriptionProduct[];\n purchaseHistories: ProductPurchase[];\n availablePurchases: ProductPurchase[];\n currentPurchase?: ProductPurchase;\n currentPurchaseError?: PurchaseError;\n clearCurrentPurchase: () => void;\n clearCurrentPurchaseError: () => void;\n finishTransaction: ({\n purchase,\n isConsumable,\n }: {\n purchase: Purchase;\n isConsumable?: boolean;\n }) => Promise<PurchaseResult | boolean>;\n getAvailablePurchases: (skus: string[]) => Promise<void>;\n getPurchaseHistories: (skus: string[]) => Promise<void>;\n getProducts: (skus: string[]) => Promise<void>;\n getSubscriptions: (skus: string[]) => Promise<void>;\n requestPurchase: (params: {\n request: any;\n type?: 'inapp' | 'subs';\n }) => Promise<any>;\n validateReceipt: (\n sku: string,\n androidOptions?: {\n packageName: string;\n productToken: string;\n accessToken: string;\n isSub?: boolean;\n },\n ) => Promise<any>;\n restorePurchases: () => Promise<void>; // 구매 복원 함수 추가\n};\n\nexport interface UseIAPOptions {\n onPurchaseSuccess?: (\n purchase: ProductPurchase | SubscriptionPurchase,\n ) => void;\n onPurchaseError?: (error: PurchaseError) => void;\n onSyncError?: (error: Error) => void;\n shouldAutoSyncPurchases?: boolean; // New option to control auto-syncing\n}\n\nexport function useIAP(options?: UseIAPOptions): UseIap {\n const [connected, setConnected] = useState<boolean>(false);\n const [products, setProducts] = useState<Product[]>([]);\n const [promotedProductsIOS, setPromotedProductsIOS] = useState<\n ProductPurchase[]\n >([]);\n const [subscriptions, setSubscriptions] = useState<SubscriptionProduct[]>([]);\n const [purchaseHistories, setPurchaseHistories] = useState<ProductPurchase[]>(\n [],\n );\n const [availablePurchases, setAvailablePurchases] = useState<\n ProductPurchase[]\n >([]);\n const [currentPurchase, setCurrentPurchase] = useState<ProductPurchase>();\n const [currentPurchaseError, setCurrentPurchaseError] =\n useState<PurchaseError>();\n\n const optionsRef = useRef<UseIAPOptions | undefined>(options);\n\n // Helper function to merge arrays with duplicate checking\n const mergeWithDuplicateCheck = useCallback(\n <T>(\n existingItems: T[],\n newItems: T[],\n getKey: (item: T) => string,\n ): T[] => {\n const merged = [...existingItems];\n newItems.forEach((newItem) => {\n const isDuplicate = merged.some(\n (existingItem) => getKey(existingItem) === getKey(newItem),\n );\n if (!isDuplicate) {\n merged.push(newItem);\n }\n });\n return merged;\n },\n [],\n );\n\n useEffect(() => {\n optionsRef.current = options;\n }, [options]);\n\n const subscriptionsRef = useRef<{\n purchaseUpdate?: EventSubscription;\n purchaseError?: EventSubscription;\n promotedProductsIos?: EventSubscription;\n }>({});\n\n const subscriptionsRefState = useRef<SubscriptionProduct[]>([]);\n\n useEffect(() => {\n subscriptionsRefState.current = subscriptions;\n }, [subscriptions]);\n\n const clearCurrentPurchase = useCallback(() => {\n setCurrentPurchase(undefined);\n }, []);\n\n const clearCurrentPurchaseError = useCallback(() => {\n setCurrentPurchaseError(undefined);\n }, []);\n\n const getProductsInternal = useCallback(\n async (skus: string[]): Promise<void> => {\n try {\n const result = await getProducts(skus);\n setProducts((prevProducts) =>\n mergeWithDuplicateCheck(\n prevProducts,\n result,\n (product) => product.id,\n ),\n );\n } catch (error) {\n console.error('Error fetching products:', error);\n }\n },\n [mergeWithDuplicateCheck],\n );\n\n const getSubscriptionsInternal = useCallback(\n async (skus: string[]): Promise<void> => {\n try {\n const result = await getSubscriptions(skus);\n setSubscriptions((prevSubscriptions) =>\n mergeWithDuplicateCheck(\n prevSubscriptions,\n result,\n (subscription) => subscription.id,\n ),\n );\n } catch (error) {\n console.error('Error fetching subscriptions:', error);\n }\n },\n [mergeWithDuplicateCheck],\n );\n\n const getAvailablePurchasesInternal = useCallback(async (): Promise<void> => {\n try {\n const result = await getAvailablePurchases();\n setAvailablePurchases(result);\n } catch (error) {\n console.error('Error fetching available purchases:', error);\n }\n }, []);\n\n const getPurchaseHistoriesInternal = useCallback(async (): Promise<void> => {\n setPurchaseHistories(await getPurchaseHistories());\n }, []);\n\n const finishTransaction = useCallback(\n async ({\n purchase,\n isConsumable,\n }: {\n purchase: ProductPurchase;\n isConsumable?: boolean;\n }): Promise<PurchaseResult | boolean> => {\n try {\n return await finishTransactionInternal({\n purchase,\n isConsumable,\n });\n } catch (err) {\n throw err;\n } finally {\n if (purchase.id === currentPurchase?.id) {\n clearCurrentPurchase();\n }\n if (purchase.id === currentPurchaseError?.productId) {\n clearCurrentPurchaseError();\n }\n }\n },\n [\n currentPurchase?.id,\n currentPurchaseError?.productId,\n clearCurrentPurchase,\n clearCurrentPurchaseError,\n ],\n );\n\n const requestPurchaseWithReset = useCallback(\n async (requestObj: {request: any; type?: 'inapp' | 'subs'}) => {\n clearCurrentPurchase();\n clearCurrentPurchaseError();\n\n try {\n return await requestPurchaseInternal(requestObj);\n } catch (error) {\n throw error;\n }\n },\n [clearCurrentPurchase, clearCurrentPurchaseError],\n );\n\n const refreshSubscriptionStatus = useCallback(\n async (productId: string) => {\n try {\n if (subscriptionsRefState.current.some((sub) => sub.id === productId)) {\n await getSubscriptionsInternal([productId]);\n await getAvailablePurchasesInternal();\n }\n } catch (error) {\n console.warn('Failed to refresh subscription status:', error);\n }\n },\n [getAvailablePurchasesInternal, getSubscriptionsInternal],\n );\n\n const restorePurchases = useCallback(async (): Promise<void> => {\n try {\n if (Platform.OS === 'ios') {\n await syncIOS().catch((error) => {\n if (optionsRef.current?.onSyncError) {\n optionsRef.current.onSyncError(error);\n } else {\n console.warn('Error restoring purchases:', error);\n }\n });\n }\n await getAvailablePurchasesInternal();\n } catch (error) {\n console.warn('Failed to restore purchases:', error);\n }\n }, [getAvailablePurchasesInternal]);\n\n const validateReceipt = useCallback(\n async (\n sku: string,\n androidOptions?: {\n packageName: string;\n productToken: string;\n accessToken: string;\n isSub?: boolean;\n },\n ) => {\n if (Platform.OS === 'ios') {\n return await validateReceiptIOS(sku);\n } else if (Platform.OS === 'android') {\n if (\n !androidOptions ||\n !androidOptions.packageName ||\n !androidOptions.productToken ||\n !androidOptions.accessToken\n ) {\n throw new Error(\n 'Android validation requires packageName, productToken, and accessToken',\n );\n }\n return await validateReceiptAndroid({\n packageName: androidOptions.packageName,\n productId: sku,\n productToken: androidOptions.productToken,\n accessToken: androidOptions.accessToken,\n isSub: androidOptions.isSub,\n });\n } else {\n throw new Error('Platform not supported');\n }\n },\n [],\n );\n\n const initIapWithSubscriptions = useCallback(async (): Promise<void> => {\n const result = await initConnection();\n setConnected(result);\n\n if (result) {\n subscriptionsRef.current.purchaseUpdate = purchaseUpdatedListener(\n async (purchase: Purchase | SubscriptionPurchase) => {\n setCurrentPurchaseError(undefined);\n setCurrentPurchase(purchase);\n\n if ('expirationDateIos' in purchase) {\n await refreshSubscriptionStatus(purchase.id);\n }\n\n if (optionsRef.current?.onPurchaseSuccess) {\n optionsRef.current.onPurchaseSuccess(purchase);\n }\n },\n );\n\n subscriptionsRef.current.purchaseError = purchaseErrorListener(\n (error: PurchaseError) => {\n setCurrentPurchase(undefined);\n setCurrentPurchaseError(error);\n\n if (optionsRef.current?.onPurchaseError) {\n optionsRef.current.onPurchaseError(error);\n }\n },\n );\n\n if (Platform.OS === 'ios') {\n // iOS promoted products are handled through regular purchase updates\n subscriptionsRef.current.promotedProductsIos = purchaseUpdatedListener(\n async (purchase: Purchase | SubscriptionPurchase) => {\n // Add to promoted products if it's a promoted transaction (avoid duplicates)\n setPromotedProductsIOS((prevProducts) =>\n mergeWithDuplicateCheck(\n prevProducts,\n [purchase as ProductPurchase],\n (product) => product.transactionId || product.id,\n ),\n );\n\n // Refresh subscription status if it's a subscription purchase\n if ('expirationDateIos' in purchase) {\n await refreshSubscriptionStatus(purchase.id);\n }\n },\n );\n }\n }\n }, [refreshSubscriptionStatus, mergeWithDuplicateCheck]);\n\n useEffect(() => {\n initIapWithSubscriptions();\n const currentSubscriptions = subscriptionsRef.current;\n\n return () => {\n currentSubscriptions.purchaseUpdate?.remove();\n currentSubscriptions.purchaseError?.remove();\n currentSubscriptions.promotedProductsIos?.remove();\n endConnection();\n setConnected(false);\n };\n }, [initIapWithSubscriptions]);\n\n return {\n connected,\n products,\n promotedProductsIOS,\n subscriptions,\n purchaseHistories,\n finishTransaction,\n availablePurchases,\n currentPurchase,\n currentPurchaseError,\n clearCurrentPurchase,\n clearCurrentPurchaseError,\n getAvailablePurchases: getAvailablePurchasesInternal,\n getPurchaseHistories: getPurchaseHistoriesInternal,\n getProducts: getProductsInternal,\n getSubscriptions: getSubscriptionsInternal,\n requestPurchase: requestPurchaseWithReset,\n validateReceipt,\n restorePurchases,\n };\n}\n"]}
1
+ {"version":3,"file":"useIap.js","sourceRoot":"","sources":["../src/useIap.ts"],"names":[],"mappings":"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","sourcesContent":["// External dependencies\nimport {useCallback, useEffect, useState, useRef} from 'react';\nimport {Platform} from 'react-native';\nimport {EventSubscription} from 'expo-modules-core';\n\n// Internal modules\nimport {\n endConnection,\n initConnection,\n purchaseErrorListener,\n purchaseUpdatedListener,\n getProducts,\n getAvailablePurchases,\n getPurchaseHistories,\n finishTransaction as finishTransactionInternal,\n getSubscriptions,\n requestPurchase as requestPurchaseInternal,\n} from './';\nimport {syncIOS, validateReceiptIOS} from './modules/ios';\nimport {validateReceiptAndroid} from './modules/android';\n\n// Types\nimport {\n Product,\n ProductPurchase,\n Purchase,\n PurchaseError,\n PurchaseResult,\n SubscriptionProduct,\n SubscriptionPurchase,\n RequestPurchaseProps,\n RequestSubscriptionProps,\n} from './ExpoIap.types';\n\ntype UseIap = {\n connected: boolean;\n products: Product[];\n promotedProductsIOS: ProductPurchase[];\n subscriptions: SubscriptionProduct[];\n purchaseHistories: ProductPurchase[];\n availablePurchases: ProductPurchase[];\n currentPurchase?: ProductPurchase;\n currentPurchaseError?: PurchaseError;\n clearCurrentPurchase: () => void;\n clearCurrentPurchaseError: () => void;\n finishTransaction: ({\n purchase,\n isConsumable,\n }: {\n purchase: Purchase;\n isConsumable?: boolean;\n }) => Promise<PurchaseResult | boolean>;\n getAvailablePurchases: (skus: string[]) => Promise<void>;\n getPurchaseHistories: (skus: string[]) => Promise<void>;\n getProducts: (skus: string[]) => Promise<void>;\n getSubscriptions: (skus: string[]) => Promise<void>;\n requestPurchase: (params: {\n request: RequestPurchaseProps | RequestSubscriptionProps;\n type?: 'inapp' | 'subs';\n }) => Promise<any>;\n validateReceipt: (\n sku: string,\n androidOptions?: {\n packageName: string;\n productToken: string;\n accessToken: string;\n isSub?: boolean;\n },\n ) => Promise<any>;\n restorePurchases: () => Promise<void>; // 구매 복원 함수 추가\n};\n\nexport interface UseIAPOptions {\n onPurchaseSuccess?: (\n purchase: ProductPurchase | SubscriptionPurchase,\n ) => void;\n onPurchaseError?: (error: PurchaseError) => void;\n onSyncError?: (error: Error) => void;\n shouldAutoSyncPurchases?: boolean; // New option to control auto-syncing\n}\n\nexport function useIAP(options?: UseIAPOptions): UseIap {\n const [connected, setConnected] = useState<boolean>(false);\n const [products, setProducts] = useState<Product[]>([]);\n const [promotedProductsIOS, setPromotedProductsIOS] = useState<\n ProductPurchase[]\n >([]);\n const [subscriptions, setSubscriptions] = useState<SubscriptionProduct[]>([]);\n const [purchaseHistories, setPurchaseHistories] = useState<ProductPurchase[]>(\n [],\n );\n const [availablePurchases, setAvailablePurchases] = useState<\n ProductPurchase[]\n >([]);\n const [currentPurchase, setCurrentPurchase] = useState<ProductPurchase>();\n const [currentPurchaseError, setCurrentPurchaseError] =\n useState<PurchaseError>();\n\n const optionsRef = useRef<UseIAPOptions | undefined>(options);\n\n // Helper function to merge arrays with duplicate checking\n const mergeWithDuplicateCheck = useCallback(\n <T>(\n existingItems: T[],\n newItems: T[],\n getKey: (item: T) => string,\n ): T[] => {\n const merged = [...existingItems];\n newItems.forEach((newItem) => {\n const isDuplicate = merged.some(\n (existingItem) => getKey(existingItem) === getKey(newItem),\n );\n if (!isDuplicate) {\n merged.push(newItem);\n }\n });\n return merged;\n },\n [],\n );\n\n useEffect(() => {\n optionsRef.current = options;\n }, [options]);\n\n const subscriptionsRef = useRef<{\n purchaseUpdate?: EventSubscription;\n purchaseError?: EventSubscription;\n promotedProductsIos?: EventSubscription;\n }>({});\n\n const subscriptionsRefState = useRef<SubscriptionProduct[]>([]);\n\n useEffect(() => {\n subscriptionsRefState.current = subscriptions;\n }, [subscriptions]);\n\n const clearCurrentPurchase = useCallback(() => {\n setCurrentPurchase(undefined);\n }, []);\n\n const clearCurrentPurchaseError = useCallback(() => {\n setCurrentPurchaseError(undefined);\n }, []);\n\n const getProductsInternal = useCallback(\n async (skus: string[]): Promise<void> => {\n try {\n const result = await getProducts(skus);\n setProducts((prevProducts) =>\n mergeWithDuplicateCheck(\n prevProducts,\n result,\n (product) => product.id,\n ),\n );\n } catch (error) {\n console.error('Error fetching products:', error);\n }\n },\n [mergeWithDuplicateCheck],\n );\n\n const getSubscriptionsInternal = useCallback(\n async (skus: string[]): Promise<void> => {\n try {\n const result = await getSubscriptions(skus);\n setSubscriptions((prevSubscriptions) =>\n mergeWithDuplicateCheck(\n prevSubscriptions,\n result,\n (subscription) => subscription.id,\n ),\n );\n } catch (error) {\n console.error('Error fetching subscriptions:', error);\n }\n },\n [mergeWithDuplicateCheck],\n );\n\n const getAvailablePurchasesInternal = useCallback(async (): Promise<void> => {\n try {\n const result = await getAvailablePurchases();\n setAvailablePurchases(result);\n } catch (error) {\n console.error('Error fetching available purchases:', error);\n }\n }, []);\n\n const getPurchaseHistoriesInternal = useCallback(async (): Promise<void> => {\n setPurchaseHistories(await getPurchaseHistories());\n }, []);\n\n const finishTransaction = useCallback(\n async ({\n purchase,\n isConsumable,\n }: {\n purchase: ProductPurchase;\n isConsumable?: boolean;\n }): Promise<PurchaseResult | boolean> => {\n try {\n return await finishTransactionInternal({\n purchase,\n isConsumable,\n });\n } catch (err) {\n throw err;\n } finally {\n if (purchase.id === currentPurchase?.id) {\n clearCurrentPurchase();\n }\n if (purchase.id === currentPurchaseError?.productId) {\n clearCurrentPurchaseError();\n }\n }\n },\n [\n currentPurchase?.id,\n currentPurchaseError?.productId,\n clearCurrentPurchase,\n clearCurrentPurchaseError,\n ],\n );\n\n const requestPurchaseWithReset = useCallback(\n async (requestObj: {request: any; type?: 'inapp' | 'subs'}) => {\n clearCurrentPurchase();\n clearCurrentPurchaseError();\n\n try {\n return await requestPurchaseInternal(requestObj);\n } catch (error) {\n throw error;\n }\n },\n [clearCurrentPurchase, clearCurrentPurchaseError],\n );\n\n const refreshSubscriptionStatus = useCallback(\n async (productId: string) => {\n try {\n if (subscriptionsRefState.current.some((sub) => sub.id === productId)) {\n await getSubscriptionsInternal([productId]);\n await getAvailablePurchasesInternal();\n }\n } catch (error) {\n console.warn('Failed to refresh subscription status:', error);\n }\n },\n [getAvailablePurchasesInternal, getSubscriptionsInternal],\n );\n\n const restorePurchases = useCallback(async (): Promise<void> => {\n try {\n if (Platform.OS === 'ios') {\n await syncIOS().catch((error) => {\n if (optionsRef.current?.onSyncError) {\n optionsRef.current.onSyncError(error);\n } else {\n console.warn('Error restoring purchases:', error);\n }\n });\n }\n await getAvailablePurchasesInternal();\n } catch (error) {\n console.warn('Failed to restore purchases:', error);\n }\n }, [getAvailablePurchasesInternal]);\n\n const validateReceipt = useCallback(\n async (\n sku: string,\n androidOptions?: {\n packageName: string;\n productToken: string;\n accessToken: string;\n isSub?: boolean;\n },\n ) => {\n if (Platform.OS === 'ios') {\n return await validateReceiptIOS(sku);\n } else if (Platform.OS === 'android') {\n if (\n !androidOptions ||\n !androidOptions.packageName ||\n !androidOptions.productToken ||\n !androidOptions.accessToken\n ) {\n throw new Error(\n 'Android validation requires packageName, productToken, and accessToken',\n );\n }\n return await validateReceiptAndroid({\n packageName: androidOptions.packageName,\n productId: sku,\n productToken: androidOptions.productToken,\n accessToken: androidOptions.accessToken,\n isSub: androidOptions.isSub,\n });\n } else {\n throw new Error('Platform not supported');\n }\n },\n [],\n );\n\n const initIapWithSubscriptions = useCallback(async (): Promise<void> => {\n const result = await initConnection();\n setConnected(result);\n\n if (result) {\n subscriptionsRef.current.purchaseUpdate = purchaseUpdatedListener(\n async (purchase: Purchase | SubscriptionPurchase) => {\n setCurrentPurchaseError(undefined);\n setCurrentPurchase(purchase);\n\n if ('expirationDateIos' in purchase) {\n await refreshSubscriptionStatus(purchase.id);\n }\n\n if (optionsRef.current?.onPurchaseSuccess) {\n optionsRef.current.onPurchaseSuccess(purchase);\n }\n },\n );\n\n subscriptionsRef.current.purchaseError = purchaseErrorListener(\n (error: PurchaseError) => {\n setCurrentPurchase(undefined);\n setCurrentPurchaseError(error);\n\n if (optionsRef.current?.onPurchaseError) {\n optionsRef.current.onPurchaseError(error);\n }\n },\n );\n\n if (Platform.OS === 'ios') {\n // iOS promoted products are handled through regular purchase updates\n subscriptionsRef.current.promotedProductsIos = purchaseUpdatedListener(\n async (purchase: Purchase | SubscriptionPurchase) => {\n // Add to promoted products if it's a promoted transaction (avoid duplicates)\n setPromotedProductsIOS((prevProducts) =>\n mergeWithDuplicateCheck(\n prevProducts,\n [purchase as ProductPurchase],\n (product) => product.transactionId || product.id,\n ),\n );\n\n // Refresh subscription status if it's a subscription purchase\n if ('expirationDateIos' in purchase) {\n await refreshSubscriptionStatus(purchase.id);\n }\n },\n );\n }\n }\n }, [refreshSubscriptionStatus, mergeWithDuplicateCheck]);\n\n useEffect(() => {\n initIapWithSubscriptions();\n const currentSubscriptions = subscriptionsRef.current;\n\n return () => {\n currentSubscriptions.purchaseUpdate?.remove();\n currentSubscriptions.purchaseError?.remove();\n currentSubscriptions.promotedProductsIos?.remove();\n endConnection();\n setConnected(false);\n };\n }, [initIapWithSubscriptions]);\n\n return {\n connected,\n products,\n promotedProductsIOS,\n subscriptions,\n purchaseHistories,\n finishTransaction,\n availablePurchases,\n currentPurchase,\n currentPurchaseError,\n clearCurrentPurchase,\n clearCurrentPurchaseError,\n getAvailablePurchases: getAvailablePurchasesInternal,\n getPurchaseHistories: getPurchaseHistoriesInternal,\n getProducts: getProductsInternal,\n getSubscriptions: getSubscriptionsInternal,\n requestPurchase: requestPurchaseWithReset,\n validateReceipt,\n restorePurchases,\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-iap",
3
- "version": "2.6.3",
3
+ "version": "2.7.0",
4
4
  "description": "In App Purchase module in Expo",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -51,12 +51,12 @@ export type SubscriptionProduct =
51
51
  | (SubscriptionProductAndroid & AndroidPlatform)
52
52
  | (SubscriptionProductIos & IosPlatform);
53
53
 
54
- // Internal platform-specific types (used for native interop only)
55
- export type RequestPurchaseProps =
54
+ // Legacy internal platform-specific types (kept for backward compatibility)
55
+ export type LegacyRequestPurchaseProps =
56
56
  | RequestPurchaseIosProps
57
57
  | RequestPurchaseAndroidProps;
58
58
 
59
- export type RequestSubscriptionProps =
59
+ export type LegacyRequestSubscriptionProps =
60
60
  | RequestSubscriptionAndroidProps
61
61
  | RequestSubscriptionIosProps;
62
62
 
@@ -338,8 +338,129 @@ export interface UnifiedRequestSubscriptionProps
338
338
  }
339
339
 
340
340
  // ============================================================================
341
+ // New Platform-Specific Request Types (v2.7.0+)
342
+ // ============================================================================
343
+
344
+ /**
345
+ * iOS-specific purchase request parameters
346
+ */
347
+ export interface IosRequestPurchaseProps {
348
+ readonly sku: string;
349
+ readonly andDangerouslyFinishTransactionAutomaticallyIOS?: boolean;
350
+ readonly appAccountToken?: string;
351
+ readonly quantity?: number;
352
+ readonly withOffer?: import('./types/ExpoIapIos.types').PaymentDiscount;
353
+ }
354
+
355
+ /**
356
+ * Android-specific purchase request parameters
357
+ */
358
+ export interface AndroidRequestPurchaseProps {
359
+ readonly skus: string[];
360
+ readonly obfuscatedAccountIdAndroid?: string;
361
+ readonly obfuscatedProfileIdAndroid?: string;
362
+ readonly isOfferPersonalized?: boolean;
363
+ }
364
+
365
+ /**
366
+ * Android-specific subscription request parameters
367
+ */
368
+ export interface AndroidRequestSubscriptionProps
369
+ extends AndroidRequestPurchaseProps {
370
+ readonly purchaseTokenAndroid?: string;
371
+ readonly replacementModeAndroid?: number;
372
+ readonly subscriptionOffers: {
373
+ sku: string;
374
+ offerToken: string;
375
+ }[];
376
+ }
377
+
378
+ /**
379
+ * Modern platform-specific request structure (v2.7.0+)
380
+ * Allows clear separation of iOS and Android parameters
381
+ */
382
+ export interface PlatformRequestPurchaseProps {
383
+ readonly ios?: IosRequestPurchaseProps;
384
+ readonly android?: AndroidRequestPurchaseProps;
385
+ }
386
+
387
+ /**
388
+ * Modern platform-specific subscription request structure (v2.7.0+)
389
+ */
390
+ export interface PlatformRequestSubscriptionProps {
391
+ readonly ios?: IosRequestPurchaseProps;
392
+ readonly android?: AndroidRequestSubscriptionProps;
393
+ }
394
+
395
+ /**
396
+ * Modern request purchase parameters (v2.7.0+)
397
+ * This is the recommended API moving forward
398
+ */
399
+ export type RequestPurchaseProps = PlatformRequestPurchaseProps;
400
+
401
+ /**
402
+ * Modern request subscription parameters (v2.7.0+)
403
+ * This is the recommended API moving forward
404
+ */
405
+ export type RequestSubscriptionProps = PlatformRequestSubscriptionProps;
406
+
407
+ /**
408
+ * Legacy request purchase parameters (deprecated)
409
+ * Includes both unified and old platform-specific formats
410
+ * @deprecated Use RequestPurchaseProps with platform-specific structure instead
411
+ */
412
+ export type LegacyRequestPurchasePropsAll =
413
+ | UnifiedRequestPurchaseProps
414
+ | LegacyRequestPurchaseProps;
415
+
416
+ /**
417
+ * Legacy request subscription parameters (deprecated)
418
+ * Includes both unified and old platform-specific formats
419
+ * @deprecated Use RequestSubscriptionProps with platform-specific structure instead
420
+ */
421
+ export type LegacyRequestSubscriptionPropsAll =
422
+ | UnifiedRequestSubscriptionProps
423
+ | LegacyRequestSubscriptionProps;
424
+
425
+ /**
426
+ * All supported request purchase parameters
427
+ * Used internally for backward compatibility
428
+ * @internal
429
+ */
430
+ export type RequestPurchasePropsWithLegacy =
431
+ | RequestPurchaseProps
432
+ | LegacyRequestPurchasePropsAll;
433
+
434
+ /**
435
+ * All supported request subscription parameters
436
+ * Used internally for backward compatibility
437
+ * @internal
438
+ */
439
+ export type RequestSubscriptionPropsWithLegacy =
440
+ | RequestSubscriptionProps
441
+ | LegacyRequestSubscriptionPropsAll;
442
+
341
443
  // ============================================================================
342
444
  // Type Guards and Utility Functions
343
445
  // ============================================================================
344
446
 
345
- // Note: Type guard functions are exported from index.ts to avoid conflicts
447
+ // Type guards to check which API style is being used
448
+ export function isPlatformRequestProps(
449
+ props: RequestPurchasePropsWithLegacy | RequestSubscriptionPropsWithLegacy,
450
+ ): props is PlatformRequestPurchaseProps | PlatformRequestSubscriptionProps {
451
+ return 'ios' in props || 'android' in props;
452
+ }
453
+
454
+ export function isUnifiedRequestProps(
455
+ props: RequestPurchasePropsWithLegacy | RequestSubscriptionPropsWithLegacy,
456
+ ): props is UnifiedRequestPurchaseProps | UnifiedRequestSubscriptionProps {
457
+ return 'sku' in props || 'skus' in props;
458
+ }
459
+
460
+ export function isLegacyRequestProps(
461
+ props: RequestPurchasePropsWithLegacy | RequestSubscriptionPropsWithLegacy,
462
+ ): props is LegacyRequestPurchaseProps | LegacyRequestSubscriptionProps {
463
+ return 'productId' in props || 'productIds' in props;
464
+ }
465
+
466
+ // Note: Other type guard functions are exported from index.ts to avoid conflicts
package/src/index.ts CHANGED
@@ -14,21 +14,17 @@ import {
14
14
  Purchase,
15
15
  PurchaseError,
16
16
  PurchaseResult,
17
- RequestSubscriptionProps,
17
+ RequestSubscriptionPropsWithLegacy,
18
+ RequestPurchasePropsWithLegacy,
18
19
  SubscriptionProduct,
19
20
  SubscriptionPurchase,
21
+ isPlatformRequestProps,
22
+ isUnifiedRequestProps,
20
23
  } from './ExpoIap.types';
21
- import {
22
- ProductPurchaseAndroid,
23
- RequestPurchaseAndroidProps,
24
- RequestSubscriptionAndroidProps,
25
- } from './types/ExpoIapAndroid.types';
26
- import {
27
- PaymentDiscount,
28
- RequestPurchaseIosProps,
29
- RequestSubscriptionIosProps,
30
- } from './types/ExpoIapIos.types';
24
+ import {ProductPurchaseAndroid} from './types/ExpoIapAndroid.types';
25
+ import {PaymentDiscount} from './types/ExpoIapIos.types';
31
26
 
27
+ // Export all types
32
28
  export * from './ExpoIap.types';
33
29
  export * from './modules/android';
34
30
  export * from './modules/ios';
@@ -186,10 +182,12 @@ export const getPurchaseHistories = ({
186
182
  );
187
183
  },
188
184
  android: async () => {
189
- const products = await ExpoIapModule.getPurchaseHistoryByType('inapp');
190
- const subscriptions =
191
- await ExpoIapModule.getPurchaseHistoryByType('subs');
192
- return products.concat(subscriptions);
185
+ // getPurchaseHistoryByType was removed in Google Play Billing Library v8
186
+ // Android doesn't provide purchase history anymore, only active purchases
187
+ console.warn(
188
+ 'getPurchaseHistories is not supported on Android with Google Play Billing Library v8. Use getAvailablePurchases instead to get active purchases.',
189
+ );
190
+ return [];
193
191
  },
194
192
  }) || (() => Promise.resolve([]))
195
193
  )();
@@ -231,22 +229,98 @@ const offerToRecordIos = (
231
229
  };
232
230
 
233
231
  // Define discriminated union with explicit type parameter
232
+ // Using legacy types internally for backward compatibility
234
233
  type PurchaseRequest =
235
234
  | {
236
- request: RequestPurchaseIosProps | RequestPurchaseAndroidProps;
235
+ request: RequestPurchasePropsWithLegacy;
237
236
  type?: 'inapp';
238
237
  }
239
238
  | {
240
- request: RequestSubscriptionAndroidProps | RequestSubscriptionIosProps;
239
+ request: RequestSubscriptionPropsWithLegacy;
241
240
  type: 'subs';
242
241
  };
243
242
 
244
- // Type guards for request objects
245
- const isIosRequest = (
246
- request: any,
247
- ): request is RequestPurchaseIosProps | RequestSubscriptionIosProps =>
248
- 'sku' in request && typeof request.sku === 'string';
243
+ /**
244
+ * Helper to normalize request props to platform-specific format
245
+ */
246
+ const normalizeRequestProps = (
247
+ request: RequestPurchasePropsWithLegacy | RequestSubscriptionPropsWithLegacy,
248
+ platform: 'ios' | 'android',
249
+ ): any => {
250
+ // If it's already platform-specific format
251
+ if (isPlatformRequestProps(request)) {
252
+ return platform === 'ios' ? request.ios : request.android;
253
+ }
254
+
255
+ // If it's unified format, convert to platform-specific
256
+ if (isUnifiedRequestProps(request)) {
257
+ if (platform === 'ios') {
258
+ return {
259
+ sku: request.sku || (request.skus?.[0] ?? ''),
260
+ andDangerouslyFinishTransactionAutomaticallyIOS:
261
+ request.andDangerouslyFinishTransactionAutomaticallyIOS,
262
+ appAccountToken: request.appAccountToken,
263
+ quantity: request.quantity,
264
+ withOffer: request.withOffer,
265
+ };
266
+ } else {
267
+ const androidRequest: any = {
268
+ skus: request.skus || (request.sku ? [request.sku] : []),
269
+ obfuscatedAccountIdAndroid: request.obfuscatedAccountIdAndroid,
270
+ obfuscatedProfileIdAndroid: request.obfuscatedProfileIdAndroid,
271
+ isOfferPersonalized: request.isOfferPersonalized,
272
+ };
273
+
274
+ // Add subscription-specific fields if present
275
+ if ('subscriptionOffers' in request && request.subscriptionOffers) {
276
+ androidRequest.subscriptionOffers = request.subscriptionOffers;
277
+ }
278
+ if ('purchaseTokenAndroid' in request) {
279
+ androidRequest.purchaseTokenAndroid = request.purchaseTokenAndroid;
280
+ }
281
+ if ('replacementModeAndroid' in request) {
282
+ androidRequest.replacementModeAndroid = request.replacementModeAndroid;
283
+ }
284
+
285
+ return androidRequest;
286
+ }
287
+ }
288
+
289
+ // Legacy format handling
290
+ return request;
291
+ };
249
292
 
293
+ /**
294
+ * Request a purchase for products or subscriptions.
295
+ *
296
+ * @param requestObj - Purchase request configuration
297
+ * @param requestObj.request - Platform-specific purchase parameters
298
+ * @param requestObj.type - Type of purchase: 'inapp' for products (default) or 'subs' for subscriptions
299
+ *
300
+ * @example
301
+ * ```typescript
302
+ * // Product purchase
303
+ * await requestPurchase({
304
+ * request: {
305
+ * ios: { sku: productId },
306
+ * android: { skus: [productId] }
307
+ * },
308
+ * type: 'inapp'
309
+ * });
310
+ *
311
+ * // Subscription purchase
312
+ * await requestPurchase({
313
+ * request: {
314
+ * ios: { sku: subscriptionId },
315
+ * android: {
316
+ * skus: [subscriptionId],
317
+ * subscriptionOffers: [{ sku: subscriptionId, offerToken: 'token' }]
318
+ * }
319
+ * },
320
+ * type: 'subs'
321
+ * });
322
+ * ```
323
+ */
250
324
  export const requestPurchase = (
251
325
  requestObj: PurchaseRequest,
252
326
  ): Promise<
@@ -259,7 +333,9 @@ export const requestPurchase = (
259
333
  const {request, type = 'inapp'} = requestObj;
260
334
 
261
335
  if (Platform.OS === 'ios') {
262
- if (!isIosRequest(request)) {
336
+ const normalizedRequest = normalizeRequestProps(request, 'ios');
337
+
338
+ if (!normalizedRequest?.sku) {
263
339
  throw new Error(
264
340
  'Invalid request for iOS. The `sku` property is required and must be a string.',
265
341
  );
@@ -271,7 +347,7 @@ export const requestPurchase = (
271
347
  appAccountToken,
272
348
  quantity,
273
349
  withOffer,
274
- } = request;
350
+ } = normalizedRequest;
275
351
 
276
352
  return (async () => {
277
353
  const offer = offerToRecordIos(withOffer);
@@ -290,13 +366,21 @@ export const requestPurchase = (
290
366
  }
291
367
 
292
368
  if (Platform.OS === 'android') {
369
+ const normalizedRequest = normalizeRequestProps(request, 'android');
370
+
371
+ if (!normalizedRequest?.skus?.length) {
372
+ throw new Error(
373
+ 'Invalid request for Android. The `skus` property is required and must be a non-empty array.',
374
+ );
375
+ }
376
+
293
377
  if (type === 'inapp') {
294
378
  const {
295
379
  skus,
296
380
  obfuscatedAccountIdAndroid,
297
381
  obfuscatedProfileIdAndroid,
298
382
  isOfferPersonalized,
299
- } = request as RequestPurchaseAndroidProps;
383
+ } = normalizedRequest;
300
384
 
301
385
  return (async () => {
302
386
  return ExpoIapModule.buyItemByType({
@@ -321,7 +405,7 @@ export const requestPurchase = (
321
405
  subscriptionOffers = [],
322
406
  replacementModeAndroid = -1,
323
407
  purchaseTokenAndroid,
324
- } = request as RequestSubscriptionAndroidProps;
408
+ } = normalizedRequest;
325
409
 
326
410
  return (async () => {
327
411
  return ExpoIapModule.buyItemByType({
@@ -331,14 +415,14 @@ export const requestPurchase = (
331
415
  replacementMode: replacementModeAndroid,
332
416
  obfuscatedAccountId: obfuscatedAccountIdAndroid,
333
417
  obfuscatedProfileId: obfuscatedProfileIdAndroid,
334
- offerTokenArr: subscriptionOffers.map((so) => so.offerToken),
418
+ offerTokenArr: subscriptionOffers.map((so: any) => so.offerToken),
335
419
  isOfferPersonalized: isOfferPersonalized ?? false,
336
420
  }) as Promise<SubscriptionPurchase[]>;
337
421
  })();
338
422
  }
339
423
 
340
424
  throw new Error(
341
- "Invalid request for Android: Expected a 'RequestPurchaseAndroidProps' object with a valid 'skus' array or a 'RequestSubscriptionAndroidProps' object with 'skus' and 'subscriptionOffers'.",
425
+ "Invalid request for Android: Expected a valid request object with 'skus' array.",
342
426
  );
343
427
  }
344
428
 
@@ -346,13 +430,35 @@ export const requestPurchase = (
346
430
  };
347
431
 
348
432
  /**
349
- * @deprecated Use `requestPurchase({ request, type: 'subs' })` instead. This method will be removed in version 3.0.0+.
433
+ * @deprecated Use `requestPurchase({ request, type: 'subs' })` instead. This method will be removed in version 3.0.0.
434
+ *
435
+ * @example
436
+ * ```typescript
437
+ * // Old way (deprecated)
438
+ * await requestSubscription({
439
+ * sku: subscriptionId,
440
+ * // or for Android
441
+ * skus: [subscriptionId],
442
+ * });
443
+ *
444
+ * // New way (recommended)
445
+ * await requestPurchase({
446
+ * request: {
447
+ * ios: { sku: subscriptionId },
448
+ * android: {
449
+ * skus: [subscriptionId],
450
+ * subscriptionOffers: [{ sku: subscriptionId, offerToken: 'token' }]
451
+ * }
452
+ * },
453
+ * type: 'subs'
454
+ * });
455
+ * ```
350
456
  */
351
457
  export const requestSubscription = async (
352
- request: RequestSubscriptionProps,
458
+ request: RequestSubscriptionPropsWithLegacy,
353
459
  ): Promise<SubscriptionPurchase | SubscriptionPurchase[] | null | void> => {
354
460
  console.warn(
355
- "`requestSubscription` is deprecated. Use `requestPurchase({ request, type: 'subs' })` instead. This method will be removed in version 3.0.0+.",
461
+ "`requestSubscription` is deprecated and will be removed in version 3.0.0. Use `requestPurchase({ request, type: 'subs' })` instead.",
356
462
  );
357
463
  return (await requestPurchase({request, type: 'subs'})) as
358
464
  | SubscriptionPurchase
@@ -1,5 +1,4 @@
1
1
  // External dependencies
2
- import {Platform} from 'react-native';
3
2
 
4
3
  // Internal modules
5
4
  import {purchaseUpdatedListener} from '..';
@@ -39,10 +38,6 @@ export type TransactionEvent = {
39
38
  export const transactionUpdatedIos = (
40
39
  listener: (event: TransactionEvent) => void,
41
40
  ) => {
42
- if (Platform.OS !== 'ios') {
43
- throw new Error('This method is only available on iOS');
44
- }
45
-
46
41
  const isProductPurchase = (item: unknown): item is ProductPurchase => {
47
42
  return (
48
43
  item != null &&
@@ -100,9 +95,6 @@ export function isProductIos<T extends {platform?: string}>(
100
95
  * @platform iOS
101
96
  */
102
97
  export const syncIOS = (): Promise<null> => {
103
- if (Platform.OS !== 'ios') {
104
- throw new Error('syncIOS: This method is only available on iOS');
105
- }
106
98
  return ExpoIapModule.sync();
107
99
  };
108
100
 
@@ -118,11 +110,6 @@ export const syncIOS = (): Promise<null> => {
118
110
  export const isEligibleForIntroOfferIOS = (
119
111
  groupID: string,
120
112
  ): Promise<boolean> => {
121
- if (Platform.OS !== 'ios') {
122
- throw new Error(
123
- 'isEligibleForIntroOfferIOS: This method is only available on iOS',
124
- );
125
- }
126
113
  return ExpoIapModule.isEligibleForIntroOffer(groupID);
127
114
  };
128
115
 
@@ -138,11 +125,6 @@ export const isEligibleForIntroOfferIOS = (
138
125
  export const subscriptionStatusIOS = (
139
126
  sku: string,
140
127
  ): Promise<ProductStatusIos[]> => {
141
- if (Platform.OS !== 'ios') {
142
- throw new Error(
143
- 'subscriptionStatusIOS: This method is only available on iOS',
144
- );
145
- }
146
128
  return ExpoIapModule.subscriptionStatus(sku);
147
129
  };
148
130
 
@@ -158,11 +140,6 @@ export const subscriptionStatusIOS = (
158
140
  export const currentEntitlementIOS = (
159
141
  sku: string,
160
142
  ): Promise<ProductPurchase> => {
161
- if (Platform.OS !== 'ios') {
162
- throw new Error(
163
- 'currentEntitlementIOS: This method is only available on iOS',
164
- );
165
- }
166
143
  return ExpoIapModule.currentEntitlement(sku);
167
144
  };
168
145
 
@@ -176,11 +153,6 @@ export const currentEntitlementIOS = (
176
153
  * @platform iOS
177
154
  */
178
155
  export const latestTransactionIOS = (sku: string): Promise<ProductPurchase> => {
179
- if (Platform.OS !== 'ios') {
180
- throw new Error(
181
- 'latestTransactionIOS: This method is only available on iOS',
182
- );
183
- }
184
156
  return ExpoIapModule.latestTransaction(sku);
185
157
  };
186
158
 
@@ -197,11 +169,6 @@ type RefundRequestStatus = 'success' | 'userCancelled';
197
169
  export const beginRefundRequestIOS = (
198
170
  sku: string,
199
171
  ): Promise<RefundRequestStatus> => {
200
- if (Platform.OS !== 'ios') {
201
- throw new Error(
202
- 'beginRefundRequestIOS: This method is only available on iOS',
203
- );
204
- }
205
172
  return ExpoIapModule.beginRefundRequest(sku);
206
173
  };
207
174
 
@@ -216,11 +183,6 @@ export const beginRefundRequestIOS = (
216
183
  * @platform iOS
217
184
  */
218
185
  export const showManageSubscriptionsIOS = (): Promise<null> => {
219
- if (Platform.OS !== 'ios') {
220
- throw new Error(
221
- 'showManageSubscriptionsIOS: This method is only available on iOS',
222
- );
223
- }
224
186
  return ExpoIapModule.showManageSubscriptions();
225
187
  };
226
188
 
@@ -235,9 +197,6 @@ export const showManageSubscriptionsIOS = (): Promise<null> => {
235
197
  * @returns {Promise<string>} Base64 encoded receipt data
236
198
  */
237
199
  export const getReceiptIOS = (): Promise<string> => {
238
- if (Platform.OS !== 'ios') {
239
- throw new Error('This method is only available on iOS');
240
- }
241
200
  return ExpoIapModule.getReceiptData();
242
201
  };
243
202
 
@@ -252,11 +211,6 @@ export const getReceiptIOS = (): Promise<string> => {
252
211
  * @platform iOS
253
212
  */
254
213
  export const isTransactionVerifiedIOS = (sku: string): Promise<boolean> => {
255
- if (Platform.OS !== 'ios') {
256
- throw new Error(
257
- 'isTransactionVerifiedIOS: This method is only available on iOS',
258
- );
259
- }
260
214
  return ExpoIapModule.isTransactionVerified(sku);
261
215
  };
262
216
 
@@ -271,11 +225,6 @@ export const isTransactionVerifiedIOS = (sku: string): Promise<boolean> => {
271
225
  * @platform iOS
272
226
  */
273
227
  export const getTransactionJwsIOS = (sku: string): Promise<string> => {
274
- if (Platform.OS !== 'ios') {
275
- throw new Error(
276
- 'getTransactionJwsIOS: This method is only available on iOS',
277
- );
278
- }
279
228
  return ExpoIapModule.getTransactionJws(sku);
280
229
  };
281
230
 
@@ -302,10 +251,6 @@ export const validateReceiptIOS = async (
302
251
  jwsRepresentation: string;
303
252
  latestTransaction?: ProductPurchase;
304
253
  }> => {
305
- if (Platform.OS !== 'ios') {
306
- throw new Error('This method is only available on iOS');
307
- }
308
-
309
254
  const result = await ExpoIapModule.validateReceiptIOS(sku);
310
255
  return result;
311
256
  };
@@ -322,11 +267,6 @@ export const validateReceiptIOS = async (
322
267
  * @platform iOS
323
268
  */
324
269
  export const presentCodeRedemptionSheetIOS = (): Promise<boolean> => {
325
- if (Platform.OS !== 'ios') {
326
- throw new Error(
327
- 'presentCodeRedemptionSheetIOS: This method is only available on iOS',
328
- );
329
- }
330
270
  return ExpoIapModule.presentCodeRedemptionSheet();
331
271
  };
332
272
 
@@ -340,11 +280,6 @@ export const presentCodeRedemptionSheetIOS = (): Promise<boolean> => {
340
280
  * @platform iOS
341
281
  */
342
282
  export const getAppTransactionIOS = (): Promise<AppTransactionIOS | null> => {
343
- if (Platform.OS !== 'ios') {
344
- throw new Error(
345
- 'getAppTransactionIOS: This method is only available on iOS',
346
- );
347
- }
348
283
  return ExpoIapModule.getAppTransaction();
349
284
  };
350
285