expo-iap 3.0.7-rc.1 → 3.0.8

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 (67) hide show
  1. package/CHANGELOG.md +1 -310
  2. package/CLAUDE.md +12 -0
  3. package/android/build.gradle +1 -1
  4. package/build/index.d.ts +14 -66
  5. package/build/index.d.ts.map +1 -1
  6. package/build/index.js +149 -154
  7. package/build/index.js.map +1 -1
  8. package/build/modules/android.d.ts +7 -12
  9. package/build/modules/android.d.ts.map +1 -1
  10. package/build/modules/android.js +13 -11
  11. package/build/modules/android.js.map +1 -1
  12. package/build/modules/ios.d.ts +19 -35
  13. package/build/modules/ios.d.ts.map +1 -1
  14. package/build/modules/ios.js +86 -33
  15. package/build/modules/ios.js.map +1 -1
  16. package/build/types.d.ts +99 -76
  17. package/build/types.d.ts.map +1 -1
  18. package/build/types.js +1 -0
  19. package/build/types.js.map +1 -1
  20. package/build/useIAP.d.ts +6 -11
  21. package/build/useIAP.d.ts.map +1 -1
  22. package/build/useIAP.js +44 -15
  23. package/build/useIAP.js.map +1 -1
  24. package/build/utils/purchase.d.ts +9 -0
  25. package/build/utils/purchase.d.ts.map +1 -0
  26. package/build/utils/purchase.js +34 -0
  27. package/build/utils/purchase.js.map +1 -0
  28. package/package.json +2 -2
  29. package/plugin/build/withIAP.js +3 -3
  30. package/plugin/src/withIAP.ts +3 -3
  31. package/plugin/tsconfig.tsbuildinfo +1 -1
  32. package/src/index.ts +217 -255
  33. package/src/modules/android.ts +23 -22
  34. package/src/modules/ios.ts +123 -45
  35. package/src/types.ts +131 -85
  36. package/src/useIAP.ts +83 -42
  37. package/src/utils/purchase.ts +52 -0
  38. package/.copilot-instructions.md +0 -321
  39. package/.cursorrules +0 -321
  40. package/coverage/clover.xml +0 -440
  41. package/coverage/coverage-final.json +0 -7
  42. package/coverage/lcov-report/base.css +0 -224
  43. package/coverage/lcov-report/block-navigation.js +0 -87
  44. package/coverage/lcov-report/favicon.png +0 -0
  45. package/coverage/lcov-report/index.html +0 -161
  46. package/coverage/lcov-report/prettify.css +0 -1
  47. package/coverage/lcov-report/prettify.js +0 -2
  48. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  49. package/coverage/lcov-report/sorter.js +0 -196
  50. package/coverage/lcov-report/src/ExpoIap.types.ts.html +0 -1243
  51. package/coverage/lcov-report/src/PurchaseError.ts.html +0 -787
  52. package/coverage/lcov-report/src/helpers/index.html +0 -116
  53. package/coverage/lcov-report/src/helpers/subscription.ts.html +0 -496
  54. package/coverage/lcov-report/src/index.html +0 -131
  55. package/coverage/lcov-report/src/index.ts.html +0 -2236
  56. package/coverage/lcov-report/src/modules/android.ts.html +0 -544
  57. package/coverage/lcov-report/src/modules/index.html +0 -131
  58. package/coverage/lcov-report/src/modules/ios.ts.html +0 -952
  59. package/coverage/lcov-report/src/purchase-error.ts.html +0 -880
  60. package/coverage/lcov-report/src/types/ExpoIapAndroid.types.ts.html +0 -493
  61. package/coverage/lcov-report/src/types/index.html +0 -116
  62. package/coverage/lcov-report/src/useIap.ts.html +0 -1483
  63. package/coverage/lcov-report/src/utils/errorMapping.ts.html +0 -529
  64. package/coverage/lcov-report/src/utils/index.html +0 -116
  65. package/coverage/lcov.info +0 -852
  66. package/ios/expoiap.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
  67. package/ios/expoiap.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
@@ -12,19 +12,21 @@ export function isProductAndroid(item) {
12
12
  /**
13
13
  * Deep link to subscriptions screen on Android.
14
14
  * @param {Object} params - The parameters object
15
- * @param {string} params.sku - The product's SKU (on Android)
16
- * @param {string} params.packageName - The package name of your Android app (e.g., 'com.example.app')
15
+ * @param {string} params.skuAndroid - The product's SKU (on Android)
16
+ * @param {string} params.packageNameAndroid - The package name of your Android app (e.g., 'com.example.app')
17
17
  * @returns {Promise<void>}
18
18
  *
19
19
  * @example
20
20
  * ```typescript
21
21
  * await deepLinkToSubscriptionsAndroid({
22
- * sku: 'subscription_id',
23
- * packageName: 'com.example.app'
22
+ * skuAndroid: 'subscription_id',
23
+ * packageNameAndroid: 'com.example.app'
24
24
  * });
25
25
  * ```
26
26
  */
27
- export const deepLinkToSubscriptionsAndroid = async ({ sku, packageName, }) => {
27
+ export const deepLinkToSubscriptionsAndroid = async (options) => {
28
+ const sku = options?.skuAndroid ?? undefined;
29
+ const packageName = options?.packageNameAndroid ?? undefined;
28
30
  // Prefer native deep link implementation via OpenIAP module
29
31
  if (ExpoIapModule?.deepLinkToSubscriptionsAndroid) {
30
32
  return ExpoIapModule.deepLinkToSubscriptionsAndroid({
@@ -77,21 +79,21 @@ export const validateReceiptAndroid = async ({ packageName, productId, productTo
77
79
  * @param {string} params.token - The product's token (on Android)
78
80
  * @returns {Promise<VoidResult | void>}
79
81
  */
80
- export const acknowledgePurchaseAndroid = async ({ token, }) => {
81
- const result = await ExpoIapModule.acknowledgePurchaseAndroid(token);
82
- if (typeof result === 'boolean' || typeof result === 'undefined') {
82
+ export const acknowledgePurchaseAndroid = async (purchaseToken) => {
83
+ const result = await ExpoIapModule.acknowledgePurchaseAndroid(purchaseToken);
84
+ if (typeof result === 'boolean') {
83
85
  return result;
84
86
  }
85
87
  if (result && typeof result === 'object') {
86
88
  const record = result;
87
89
  if (typeof record.success === 'boolean') {
88
- return { success: record.success };
90
+ return record.success;
89
91
  }
90
92
  if (typeof record.responseCode === 'number') {
91
- return { success: record.responseCode === 0 };
93
+ return record.responseCode === 0;
92
94
  }
93
95
  }
94
- return { success: true };
96
+ return true;
95
97
  };
96
98
  /**
97
99
  * Open the Google Play Store to redeem offer codes (Android only).
@@ -1 +1 @@
1
- {"version":3,"file":"android.js","sourceRoot":"","sources":["../../src/modules/android.ts"],"names":[],"mappings":"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","sourcesContent":["// External dependencies\nimport {Linking} from 'react-native';\n\n// Internal modules\nimport ExpoIapModule from '../ExpoIapModule';\n\n// Types\nimport type {ReceiptValidationResultAndroid, VoidResult} from '../types';\n\n// Type guards\nexport function isProductAndroid<T extends {platform?: string}>(\n item: unknown,\n): item is T & {platform: 'android'} {\n return (\n item != null &&\n typeof item === 'object' &&\n 'platform' in item &&\n (item as any).platform === 'android'\n );\n}\n\n/**\n * Deep link to subscriptions screen on Android.\n * @param {Object} params - The parameters object\n * @param {string} params.sku - The product's SKU (on Android)\n * @param {string} params.packageName - The package name of your Android app (e.g., 'com.example.app')\n * @returns {Promise<void>}\n *\n * @example\n * ```typescript\n * await deepLinkToSubscriptionsAndroid({\n * sku: 'subscription_id',\n * packageName: 'com.example.app'\n * });\n * ```\n */\nexport const deepLinkToSubscriptionsAndroid = async ({\n sku,\n packageName,\n}: {\n sku?: string;\n packageName?: string;\n}): Promise<void> => {\n // Prefer native deep link implementation via OpenIAP module\n if (ExpoIapModule?.deepLinkToSubscriptionsAndroid) {\n return (ExpoIapModule as any).deepLinkToSubscriptionsAndroid({\n skuAndroid: sku,\n packageNameAndroid: packageName,\n });\n }\n\n // Fallback to Linking if native method unavailable\n if (!packageName) {\n throw new Error(\n 'packageName is required for deepLinkToSubscriptionsAndroid',\n );\n }\n const base = `https://play.google.com/store/account/subscriptions?package=${encodeURIComponent(\n packageName,\n )}`;\n const url = sku ? `${base}&sku=${encodeURIComponent(sku)}` : base;\n return Linking.openURL(url);\n};\n\n/**\n * Validate receipt for Android. NOTE: This method is here for debugging purposes only. Including\n * your access token in the binary you ship to users is potentially dangerous.\n * Use server side validation instead for your production builds\n * @param {Object} params - The parameters object\n * @param {string} params.packageName - package name of your app.\n * @param {string} params.productId - product id for your in app product.\n * @param {string} params.productToken - token for your purchase (called 'token' in the API documentation).\n * @param {string} params.accessToken - OAuth access token with androidpublisher scope. Required for authentication.\n * @param {boolean} params.isSub - whether this is subscription or in-app. `true` for subscription.\n * @returns {Promise<ReceiptAndroid>}\n */\nexport const validateReceiptAndroid = async ({\n packageName,\n productId,\n productToken,\n accessToken,\n isSub,\n}: {\n packageName: string;\n productId: string;\n productToken: string;\n accessToken: string;\n isSub?: boolean;\n}): Promise<ReceiptValidationResultAndroid> => {\n const type = isSub ? 'subscriptions' : 'products';\n\n const url =\n 'https://androidpublisher.googleapis.com/androidpublisher/v3/applications' +\n `/${packageName}/purchases/${type}/${productId}` +\n `/tokens/${productToken}`;\n\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${accessToken}`,\n },\n });\n\n if (!response.ok) {\n throw Object.assign(new Error(response.statusText), {\n statusCode: response.status,\n });\n }\n\n return response.json();\n};\n\n/**\n * Acknowledge a product (on Android.) No-op on iOS.\n * @param {Object} params - The parameters object\n * @param {string} params.token - The product's token (on Android)\n * @returns {Promise<VoidResult | void>}\n */\nexport const acknowledgePurchaseAndroid = async ({\n token,\n}: {\n token: string;\n}): Promise<VoidResult | boolean | void> => {\n const result = await ExpoIapModule.acknowledgePurchaseAndroid(token);\n\n if (typeof result === 'boolean' || typeof result === 'undefined') {\n return result;\n }\n\n if (result && typeof result === 'object') {\n const record = result as Record<string, unknown>;\n if (typeof record.success === 'boolean') {\n return {success: record.success};\n }\n if (typeof record.responseCode === 'number') {\n return {success: record.responseCode === 0};\n }\n }\n\n return {success: true};\n};\n\n/**\n * Open the Google Play Store to redeem offer codes (Android only).\n * Note: Google Play does not provide a direct API to redeem codes within the app.\n * This function opens the Play Store where users can manually enter their codes.\n *\n * @returns {Promise<void>}\n */\nexport const openRedeemOfferCodeAndroid = async (): Promise<void> => {\n return Linking.openURL(`https://play.google.com/redeem?code=`);\n};\n"]}
1
+ {"version":3,"file":"android.js","sourceRoot":"","sources":["../../src/modules/android.ts"],"names":[],"mappings":"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","sourcesContent":["// External dependencies\nimport {Linking} from 'react-native';\n\n// Internal modules\nimport ExpoIapModule from '../ExpoIapModule';\n\n// Types\nimport type {\n DeepLinkOptions,\n MutationField,\n ReceiptValidationResultAndroid,\n} from '../types';\n\n// Type guards\nexport function isProductAndroid<T extends {platform?: string}>(\n item: unknown,\n): item is T & {platform: 'android'} {\n return (\n item != null &&\n typeof item === 'object' &&\n 'platform' in item &&\n (item as any).platform === 'android'\n );\n}\n\n/**\n * Deep link to subscriptions screen on Android.\n * @param {Object} params - The parameters object\n * @param {string} params.skuAndroid - The product's SKU (on Android)\n * @param {string} params.packageNameAndroid - The package name of your Android app (e.g., 'com.example.app')\n * @returns {Promise<void>}\n *\n * @example\n * ```typescript\n * await deepLinkToSubscriptionsAndroid({\n * skuAndroid: 'subscription_id',\n * packageNameAndroid: 'com.example.app'\n * });\n * ```\n */\nexport const deepLinkToSubscriptionsAndroid = async (\n options?: DeepLinkOptions | null,\n): Promise<void> => {\n const sku = options?.skuAndroid ?? undefined;\n const packageName = options?.packageNameAndroid ?? undefined;\n\n // Prefer native deep link implementation via OpenIAP module\n if (ExpoIapModule?.deepLinkToSubscriptionsAndroid) {\n return (ExpoIapModule as any).deepLinkToSubscriptionsAndroid({\n skuAndroid: sku,\n packageNameAndroid: packageName,\n });\n }\n\n // Fallback to Linking if native method unavailable\n if (!packageName) {\n throw new Error(\n 'packageName is required for deepLinkToSubscriptionsAndroid',\n );\n }\n const base = `https://play.google.com/store/account/subscriptions?package=${encodeURIComponent(\n packageName,\n )}`;\n const url = sku ? `${base}&sku=${encodeURIComponent(sku)}` : base;\n return Linking.openURL(url);\n};\n\n/**\n * Validate receipt for Android. NOTE: This method is here for debugging purposes only. Including\n * your access token in the binary you ship to users is potentially dangerous.\n * Use server side validation instead for your production builds\n * @param {Object} params - The parameters object\n * @param {string} params.packageName - package name of your app.\n * @param {string} params.productId - product id for your in app product.\n * @param {string} params.productToken - token for your purchase (called 'token' in the API documentation).\n * @param {string} params.accessToken - OAuth access token with androidpublisher scope. Required for authentication.\n * @param {boolean} params.isSub - whether this is subscription or in-app. `true` for subscription.\n * @returns {Promise<ReceiptAndroid>}\n */\nexport const validateReceiptAndroid = async ({\n packageName,\n productId,\n productToken,\n accessToken,\n isSub,\n}: {\n packageName: string;\n productId: string;\n productToken: string;\n accessToken: string;\n isSub?: boolean;\n}): Promise<ReceiptValidationResultAndroid> => {\n const type = isSub ? 'subscriptions' : 'products';\n\n const url =\n 'https://androidpublisher.googleapis.com/androidpublisher/v3/applications' +\n `/${packageName}/purchases/${type}/${productId}` +\n `/tokens/${productToken}`;\n\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${accessToken}`,\n },\n });\n\n if (!response.ok) {\n throw Object.assign(new Error(response.statusText), {\n statusCode: response.status,\n });\n }\n\n return response.json();\n};\n\n/**\n * Acknowledge a product (on Android.) No-op on iOS.\n * @param {Object} params - The parameters object\n * @param {string} params.token - The product's token (on Android)\n * @returns {Promise<VoidResult | void>}\n */\nexport const acknowledgePurchaseAndroid: MutationField<\n 'acknowledgePurchaseAndroid'\n> = async (purchaseToken) => {\n const result = await ExpoIapModule.acknowledgePurchaseAndroid(purchaseToken);\n\n if (typeof result === 'boolean') {\n return result;\n }\n\n if (result && typeof result === 'object') {\n const record = result as Record<string, unknown>;\n if (typeof record.success === 'boolean') {\n return record.success;\n }\n if (typeof record.responseCode === 'number') {\n return record.responseCode === 0;\n }\n }\n\n return true;\n};\n\n/**\n * Open the Google Play Store to redeem offer codes (Android only).\n * Note: Google Play does not provide a direct API to redeem codes within the app.\n * This function opens the Play Store where users can manually enter their codes.\n *\n * @returns {Promise<void>}\n */\nexport const openRedeemOfferCodeAndroid = async (): Promise<void> => {\n return Linking.openURL(`https://play.google.com/redeem?code=`);\n};\n"]}
@@ -1,4 +1,4 @@
1
- import type { Product, Purchase, SubscriptionStatusIOS, AppTransaction, ReceiptValidationResultIOS } from '../types';
1
+ import type { MutationField, Purchase, QueryField } from '../types';
2
2
  import type { PurchaseError } from '../purchase-error';
3
3
  export type TransactionEvent = {
4
4
  transaction?: Purchase;
@@ -18,7 +18,7 @@ export declare function isProductIOS<T extends {
18
18
  *
19
19
  * @platform iOS
20
20
  */
21
- export declare const syncIOS: () => Promise<null>;
21
+ export declare const syncIOS: MutationField<'syncIOS'>;
22
22
  /**
23
23
  * Check if user is eligible for introductory offer
24
24
  *
@@ -28,7 +28,7 @@ export declare const syncIOS: () => Promise<null>;
28
28
  *
29
29
  * @platform iOS
30
30
  */
31
- export declare const isEligibleForIntroOfferIOS: (groupId: string) => Promise<boolean>;
31
+ export declare const isEligibleForIntroOfferIOS: QueryField<'isEligibleForIntroOfferIOS'>;
32
32
  /**
33
33
  * Get subscription status for a specific SKU
34
34
  *
@@ -38,7 +38,7 @@ export declare const isEligibleForIntroOfferIOS: (groupId: string) => Promise<bo
38
38
  *
39
39
  * @platform iOS
40
40
  */
41
- export declare const subscriptionStatusIOS: (sku: string) => Promise<SubscriptionStatusIOS[]>;
41
+ export declare const subscriptionStatusIOS: QueryField<'subscriptionStatusIOS'>;
42
42
  /**
43
43
  * Get current entitlement for a specific SKU
44
44
  *
@@ -48,7 +48,7 @@ export declare const subscriptionStatusIOS: (sku: string) => Promise<Subscriptio
48
48
  *
49
49
  * @platform iOS
50
50
  */
51
- export declare const currentEntitlementIOS: (sku: string) => Promise<Purchase>;
51
+ export declare const currentEntitlementIOS: QueryField<'currentEntitlementIOS'>;
52
52
  /**
53
53
  * Get latest transaction for a specific SKU
54
54
  *
@@ -58,7 +58,7 @@ export declare const currentEntitlementIOS: (sku: string) => Promise<Purchase>;
58
58
  *
59
59
  * @platform iOS
60
60
  */
61
- export declare const latestTransactionIOS: (sku: string) => Promise<Purchase>;
61
+ export declare const latestTransactionIOS: QueryField<'latestTransactionIOS'>;
62
62
  /**
63
63
  * Begin refund request for a specific SKU
64
64
  *
@@ -68,8 +68,7 @@ export declare const latestTransactionIOS: (sku: string) => Promise<Purchase>;
68
68
  *
69
69
  * @platform iOS
70
70
  */
71
- type RefundRequestStatus = 'success' | 'userCancelled';
72
- export declare const beginRefundRequestIOS: (sku: string) => Promise<RefundRequestStatus>;
71
+ export declare const beginRefundRequestIOS: MutationField<'beginRefundRequestIOS'>;
73
72
  /**
74
73
  * Shows the system UI for managing subscriptions.
75
74
  * Returns an array of subscriptions that had status changes after the UI is closed.
@@ -79,7 +78,7 @@ export declare const beginRefundRequestIOS: (sku: string) => Promise<RefundReque
79
78
  *
80
79
  * @platform iOS
81
80
  */
82
- export declare const showManageSubscriptionsIOS: () => Promise<Purchase[]>;
81
+ export declare const showManageSubscriptionsIOS: MutationField<'showManageSubscriptionsIOS'>;
83
82
  /**
84
83
  * Get the receipt data from the iOS device.
85
84
  * This returns the base64 encoded receipt data which can be sent to your server
@@ -90,7 +89,8 @@ export declare const showManageSubscriptionsIOS: () => Promise<Purchase[]>;
90
89
  *
91
90
  * @returns {Promise<string>} Base64 encoded receipt data
92
91
  */
93
- export declare const getReceiptIOS: () => Promise<string>;
92
+ export declare const getReceiptDataIOS: QueryField<'getReceiptDataIOS'>;
93
+ export declare const getReceiptIOS: () => Promise<string | null>;
94
94
  /**
95
95
  * Check if a transaction is verified through StoreKit 2.
96
96
  * StoreKit 2 performs local verification of transaction JWS signatures.
@@ -101,7 +101,7 @@ export declare const getReceiptIOS: () => Promise<string>;
101
101
  *
102
102
  * @platform iOS
103
103
  */
104
- export declare const isTransactionVerifiedIOS: (sku: string) => Promise<boolean>;
104
+ export declare const isTransactionVerifiedIOS: QueryField<'isTransactionVerifiedIOS'>;
105
105
  /**
106
106
  * Get the JWS representation of a purchase for server-side verification.
107
107
  * The JWS (JSON Web Signature) can be verified on your server using Apple's public keys.
@@ -112,23 +112,8 @@ export declare const isTransactionVerifiedIOS: (sku: string) => Promise<boolean>
112
112
  *
113
113
  * @platform iOS
114
114
  */
115
- export declare const getTransactionJwsIOS: (sku: string) => Promise<string>;
116
- /**
117
- * Validate receipt for iOS using StoreKit 2's built-in verification.
118
- * Returns receipt data and verification information to help with server-side validation.
119
- *
120
- * NOTE: For proper security, Apple recommends verifying receipts on your server using
121
- * the verifyReceipt endpoint rather than relying solely on client-side verification.
122
- *
123
- * @param {string} sku The product's SKU (on iOS)
124
- * @returns {Promise<{
125
- * isValid: boolean;
126
- * receiptData: string;
127
- * jwsRepresentation: string;
128
- * latestTransaction?: Purchase;
129
- * }>}
130
- */
131
- export declare const validateReceiptIOS: (sku: string) => Promise<ReceiptValidationResultIOS>;
115
+ export declare const getTransactionJwsIOS: QueryField<'getTransactionJwsIOS'>;
116
+ export declare const validateReceiptIOS: QueryField<"validateReceiptIOS">;
132
117
  /**
133
118
  * Present the code redemption sheet for offer codes (iOS only).
134
119
  * This allows users to redeem promotional codes for in-app purchases and subscriptions.
@@ -140,7 +125,7 @@ export declare const validateReceiptIOS: (sku: string) => Promise<ReceiptValidat
140
125
  *
141
126
  * @platform iOS
142
127
  */
143
- export declare const presentCodeRedemptionSheetIOS: () => Promise<boolean>;
128
+ export declare const presentCodeRedemptionSheetIOS: MutationField<'presentCodeRedemptionSheetIOS'>;
144
129
  /**
145
130
  * Get app transaction information (iOS 16.0+).
146
131
  * AppTransaction represents the initial purchase that unlocked the app.
@@ -155,7 +140,7 @@ export declare const presentCodeRedemptionSheetIOS: () => Promise<boolean>;
155
140
  * @platform iOS
156
141
  * @since iOS 16.0
157
142
  */
158
- export declare const getAppTransactionIOS: () => Promise<AppTransaction | null>;
143
+ export declare const getAppTransactionIOS: QueryField<'getAppTransactionIOS'>;
159
144
  /**
160
145
  * Get information about a promoted product if one is available (iOS only).
161
146
  * Promoted products are products that the App Store promotes on your behalf.
@@ -166,7 +151,7 @@ export declare const getAppTransactionIOS: () => Promise<AppTransaction | null>;
166
151
  *
167
152
  * @platform iOS
168
153
  */
169
- export declare const getPromotedProductIOS: () => Promise<Product | null>;
154
+ export declare const getPromotedProductIOS: QueryField<'getPromotedProductIOS'>;
170
155
  /**
171
156
  * Complete the purchase of a promoted product (iOS only).
172
157
  * This should be called after showing your purchase UI for a promoted product.
@@ -176,21 +161,21 @@ export declare const getPromotedProductIOS: () => Promise<Product | null>;
176
161
  *
177
162
  * @platform iOS
178
163
  */
179
- export declare const requestPurchaseOnPromotedProductIOS: () => Promise<void>;
164
+ export declare const requestPurchaseOnPromotedProductIOS: MutationField<'requestPurchaseOnPromotedProductIOS'>;
180
165
  /**
181
166
  * Get pending transactions that haven't been finished yet (iOS only).
182
167
  *
183
168
  * @returns Promise resolving to array of pending transactions
184
169
  * @platform iOS
185
170
  */
186
- export declare const getPendingTransactionsIOS: () => Promise<any[]>;
171
+ export declare const getPendingTransactionsIOS: QueryField<'getPendingTransactionsIOS'>;
187
172
  /**
188
173
  * Clear a specific transaction (iOS only).
189
174
  *
190
175
  * @returns Promise resolving when transaction is cleared
191
176
  * @platform iOS
192
177
  */
193
- export declare const clearTransactionIOS: () => Promise<void>;
178
+ export declare const clearTransactionIOS: MutationField<'clearTransactionIOS'>;
194
179
  /**
195
180
  * Deep link to subscriptions screen on iOS.
196
181
  * @returns {Promise<void>}
@@ -198,5 +183,4 @@ export declare const clearTransactionIOS: () => Promise<void>;
198
183
  * @platform iOS
199
184
  */
200
185
  export declare const deepLinkToSubscriptionsIOS: () => Promise<void>;
201
- export {};
202
186
  //# sourceMappingURL=ios.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ios.d.ts","sourceRoot":"","sources":["../../src/modules/ios.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,OAAO,EACP,QAAQ,EACR,qBAAqB,EACrB,cAAc,EACd,0BAA0B,EAC3B,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,mBAAmB,CAAC;AAGrD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,CAAC;AAKF,wBAAgB,YAAY,CAAC,CAAC,SAAS;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAC,EACxD,IAAI,EAAE,OAAO,GACZ,IAAI,IAAI,CAAC,GAAG;IAAC,QAAQ,EAAE,KAAK,CAAA;CAAC,CAO/B;AAGD;;;;;;;;GAQG;AACH,eAAO,MAAM,OAAO,QAAO,OAAO,CAAC,IAAI,CAEtC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B,GACrC,SAAS,MAAM,KACd,OAAO,CAAC,OAAO,CAEjB,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,GAChC,KAAK,MAAM,KACV,OAAO,CAAC,qBAAqB,EAAE,CAEjC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,GAAI,KAAK,MAAM,KAAG,OAAO,CAAC,QAAQ,CAEnE,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,GAAI,KAAK,MAAM,KAAG,OAAO,CAAC,QAAQ,CAElE,CAAC;AAEF;;;;;;;;GAQG;AACH,KAAK,mBAAmB,GAAG,SAAS,GAAG,eAAe,CAAC;AACvD,eAAO,MAAM,qBAAqB,GAChC,KAAK,MAAM,KACV,OAAO,CAAC,mBAAmB,CAE7B,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B,QAAO,OAAO,CAAC,QAAQ,EAAE,CAE/D,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,QAAO,OAAO,CAAC,MAAM,CAE9C,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB,GAAI,KAAK,MAAM,KAAG,OAAO,CAAC,OAAO,CAErE,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,GAAI,KAAK,MAAM,KAAG,OAAO,CAAC,MAAM,CAEhE,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,kBAAkB,GAC7B,KAAK,MAAM,KACV,OAAO,CAAC,0BAA0B,CAGpC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,6BAA6B,QAAO,OAAO,CAAC,OAAO,CAE/D,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,oBAAoB,QAAO,OAAO,CAAC,cAAc,GAAG,IAAI,CAEpE,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,QAAO,OAAO,CAAC,OAAO,GAAG,IAAI,CAE9D,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,mCAAmC,QAAO,OAAO,CAAC,IAAI,CAElE,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,QAAO,OAAO,CAAC,GAAG,EAAE,CAEzD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,QAAO,OAAO,CAAC,IAAI,CAElD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,QAAO,OAAO,CAAC,IAAI,CACO,CAAC"}
1
+ {"version":3,"file":"ios.d.ts","sourceRoot":"","sources":["../../src/modules/ios.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,aAAa,EAEb,QAAQ,EAER,UAAU,EAIX,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,mBAAmB,CAAC;AAIrD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,CAAC;AAKF,wBAAgB,YAAY,CAAC,CAAC,SAAS;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAC,EACxD,IAAI,EAAE,OAAO,GACZ,IAAI,IAAI,CAAC,GAAG;IAAC,QAAQ,EAAE,KAAK,CAAA;CAAC,CAO/B;AAGD;;;;;;;;GAQG;AACH,eAAO,MAAM,OAAO,EAAE,aAAa,CAAC,SAAS,CAE5C,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B,EAAE,UAAU,CACjD,4BAA4B,CAM7B,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,EAAE,UAAU,CAC5C,uBAAuB,CAOxB,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,EAAE,UAAU,CAC5C,uBAAuB,CAOxB,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,EAAE,UAAU,CAAC,sBAAsB,CAQnE,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,EAAE,aAAa,CAC/C,uBAAuB,CAOxB,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B,EAAE,aAAa,CACpD,4BAA4B,CAI7B,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,EAAE,UAAU,CAAC,mBAAmB,CAE7D,CAAC;AAEF,eAAO,MAAM,aAAa,8BAAoB,CAAC;AAE/C;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB,EAAE,UAAU,CAC/C,0BAA0B,CAM3B,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,EAAE,UAAU,CAAC,sBAAsB,CAQnE,CAAC;AA0CF,eAAO,MAAM,kBAAkB,EACH,UAAU,CAAC,oBAAoB,CAAC,CAAC;AAE7D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,6BAA6B,EAAE,aAAa,CACvD,+BAA+B,CAGhC,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,oBAAoB,EAAE,UAAU,CAC3C,sBAAsB,CAGvB,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,EAAE,UAAU,CAC5C,uBAAuB,CAIxB,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,mCAAmC,EAAE,aAAa,CAC7D,qCAAqC,CAItC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,EAAE,UAAU,CAChD,2BAA2B,CAI5B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,EAAE,aAAa,CAC7C,qBAAqB,CAGtB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,QAAO,OAAO,CAAC,IAAI,CACO,CAAC"}
@@ -3,6 +3,7 @@
3
3
  // import removed: use purchaseUpdatedListener directly in app code
4
4
  import ExpoIapModule from '../ExpoIapModule';
5
5
  import { Linking } from 'react-native';
6
+ import { normalizePurchaseId, normalizePurchaseList } from '../utils/purchase';
6
7
  // Listeners
7
8
  // Type guards
8
9
  export function isProductIOS(item) {
@@ -21,8 +22,8 @@ export function isProductIOS(item) {
21
22
  *
22
23
  * @platform iOS
23
24
  */
24
- export const syncIOS = () => {
25
- return ExpoIapModule.syncIOS();
25
+ export const syncIOS = async () => {
26
+ return Boolean(await ExpoIapModule.syncIOS());
26
27
  };
27
28
  /**
28
29
  * Check if user is eligible for introductory offer
@@ -33,8 +34,11 @@ export const syncIOS = () => {
33
34
  *
34
35
  * @platform iOS
35
36
  */
36
- export const isEligibleForIntroOfferIOS = (groupId) => {
37
- return ExpoIapModule.isEligibleForIntroOfferIOS(groupId);
37
+ export const isEligibleForIntroOfferIOS = async (groupID) => {
38
+ if (!groupID) {
39
+ throw new Error('isEligibleForIntroOfferIOS requires a groupID');
40
+ }
41
+ return ExpoIapModule.isEligibleForIntroOfferIOS(groupID);
38
42
  };
39
43
  /**
40
44
  * Get subscription status for a specific SKU
@@ -45,8 +49,12 @@ export const isEligibleForIntroOfferIOS = (groupId) => {
45
49
  *
46
50
  * @platform iOS
47
51
  */
48
- export const subscriptionStatusIOS = (sku) => {
49
- return ExpoIapModule.subscriptionStatusIOS(sku);
52
+ export const subscriptionStatusIOS = async (sku) => {
53
+ if (!sku) {
54
+ throw new Error('subscriptionStatusIOS requires a SKU');
55
+ }
56
+ const status = await ExpoIapModule.subscriptionStatusIOS(sku);
57
+ return (status ?? []);
50
58
  };
51
59
  /**
52
60
  * Get current entitlement for a specific SKU
@@ -57,8 +65,12 @@ export const subscriptionStatusIOS = (sku) => {
57
65
  *
58
66
  * @platform iOS
59
67
  */
60
- export const currentEntitlementIOS = (sku) => {
61
- return ExpoIapModule.currentEntitlementIOS(sku);
68
+ export const currentEntitlementIOS = async (sku) => {
69
+ if (!sku) {
70
+ throw new Error('currentEntitlementIOS requires a SKU');
71
+ }
72
+ const purchase = await ExpoIapModule.currentEntitlementIOS(sku);
73
+ return normalizePurchaseId((purchase ?? null));
62
74
  };
63
75
  /**
64
76
  * Get latest transaction for a specific SKU
@@ -69,11 +81,28 @@ export const currentEntitlementIOS = (sku) => {
69
81
  *
70
82
  * @platform iOS
71
83
  */
72
- export const latestTransactionIOS = (sku) => {
73
- return ExpoIapModule.latestTransactionIOS(sku);
84
+ export const latestTransactionIOS = async (sku) => {
85
+ if (!sku) {
86
+ throw new Error('latestTransactionIOS requires a SKU');
87
+ }
88
+ const transaction = await ExpoIapModule.latestTransactionIOS(sku);
89
+ return normalizePurchaseId((transaction ?? null));
74
90
  };
75
- export const beginRefundRequestIOS = (sku) => {
76
- return ExpoIapModule.beginRefundRequestIOS(sku);
91
+ /**
92
+ * Begin refund request for a specific SKU
93
+ *
94
+ * @param sku The product SKU
95
+ * @returns Promise resolving to refund request status
96
+ * @throws Error if called on non-iOS platform
97
+ *
98
+ * @platform iOS
99
+ */
100
+ export const beginRefundRequestIOS = async (sku) => {
101
+ if (!sku) {
102
+ throw new Error('beginRefundRequestIOS requires a SKU');
103
+ }
104
+ const status = await ExpoIapModule.beginRefundRequestIOS(sku);
105
+ return status ?? null;
77
106
  };
78
107
  /**
79
108
  * Shows the system UI for managing subscriptions.
@@ -84,8 +113,9 @@ export const beginRefundRequestIOS = (sku) => {
84
113
  *
85
114
  * @platform iOS
86
115
  */
87
- export const showManageSubscriptionsIOS = () => {
88
- return ExpoIapModule.showManageSubscriptionsIOS();
116
+ export const showManageSubscriptionsIOS = async () => {
117
+ const purchases = await ExpoIapModule.showManageSubscriptionsIOS();
118
+ return normalizePurchaseList((purchases ?? []));
89
119
  };
90
120
  /**
91
121
  * Get the receipt data from the iOS device.
@@ -97,9 +127,10 @@ export const showManageSubscriptionsIOS = () => {
97
127
  *
98
128
  * @returns {Promise<string>} Base64 encoded receipt data
99
129
  */
100
- export const getReceiptIOS = () => {
130
+ export const getReceiptDataIOS = async () => {
101
131
  return ExpoIapModule.getReceiptDataIOS();
102
132
  };
133
+ export const getReceiptIOS = getReceiptDataIOS;
103
134
  /**
104
135
  * Check if a transaction is verified through StoreKit 2.
105
136
  * StoreKit 2 performs local verification of transaction JWS signatures.
@@ -110,7 +141,10 @@ export const getReceiptIOS = () => {
110
141
  *
111
142
  * @platform iOS
112
143
  */
113
- export const isTransactionVerifiedIOS = (sku) => {
144
+ export const isTransactionVerifiedIOS = async (sku) => {
145
+ if (!sku) {
146
+ throw new Error('isTransactionVerifiedIOS requires a SKU');
147
+ }
114
148
  return ExpoIapModule.isTransactionVerifiedIOS(sku);
115
149
  };
116
150
  /**
@@ -123,8 +157,12 @@ export const isTransactionVerifiedIOS = (sku) => {
123
157
  *
124
158
  * @platform iOS
125
159
  */
126
- export const getTransactionJwsIOS = (sku) => {
127
- return ExpoIapModule.getTransactionJwsIOS(sku);
160
+ export const getTransactionJwsIOS = async (sku) => {
161
+ if (!sku) {
162
+ throw new Error('getTransactionJwsIOS requires a SKU');
163
+ }
164
+ const jws = await ExpoIapModule.getTransactionJwsIOS(sku);
165
+ return jws ?? '';
128
166
  };
129
167
  /**
130
168
  * Validate receipt for iOS using StoreKit 2's built-in verification.
@@ -141,10 +179,22 @@ export const getTransactionJwsIOS = (sku) => {
141
179
  * latestTransaction?: Purchase;
142
180
  * }>}
143
181
  */
144
- export const validateReceiptIOS = async (sku) => {
145
- const result = await ExpoIapModule.validateReceiptIOS(sku);
146
- return result;
182
+ const validateReceiptIOSImpl = async (props) => {
183
+ const sku = typeof props === 'string' ? props : props?.sku;
184
+ if (!sku) {
185
+ throw new Error('validateReceiptIOS requires a SKU');
186
+ }
187
+ const result = (await ExpoIapModule.validateReceiptIOS(sku));
188
+ const normalizedLatest = normalizePurchaseId(result.latestTransaction ?? undefined);
189
+ if (normalizedLatest === result.latestTransaction) {
190
+ return result;
191
+ }
192
+ return {
193
+ ...result,
194
+ latestTransaction: normalizedLatest ?? null,
195
+ };
147
196
  };
197
+ export const validateReceiptIOS = validateReceiptIOSImpl;
148
198
  /**
149
199
  * Present the code redemption sheet for offer codes (iOS only).
150
200
  * This allows users to redeem promotional codes for in-app purchases and subscriptions.
@@ -156,8 +206,8 @@ export const validateReceiptIOS = async (sku) => {
156
206
  *
157
207
  * @platform iOS
158
208
  */
159
- export const presentCodeRedemptionSheetIOS = () => {
160
- return ExpoIapModule.presentCodeRedemptionSheetIOS();
209
+ export const presentCodeRedemptionSheetIOS = async () => {
210
+ return Boolean(await ExpoIapModule.presentCodeRedemptionSheetIOS());
161
211
  };
162
212
  /**
163
213
  * Get app transaction information (iOS 16.0+).
@@ -173,8 +223,8 @@ export const presentCodeRedemptionSheetIOS = () => {
173
223
  * @platform iOS
174
224
  * @since iOS 16.0
175
225
  */
176
- export const getAppTransactionIOS = () => {
177
- return ExpoIapModule.getAppTransactionIOS();
226
+ export const getAppTransactionIOS = async () => {
227
+ return (await ExpoIapModule.getAppTransactionIOS()) ?? null;
178
228
  };
179
229
  /**
180
230
  * Get information about a promoted product if one is available (iOS only).
@@ -186,8 +236,9 @@ export const getAppTransactionIOS = () => {
186
236
  *
187
237
  * @platform iOS
188
238
  */
189
- export const getPromotedProductIOS = () => {
190
- return ExpoIapModule.getPromotedProductIOS();
239
+ export const getPromotedProductIOS = async () => {
240
+ const product = await ExpoIapModule.getPromotedProductIOS();
241
+ return (product ?? null);
191
242
  };
192
243
  /**
193
244
  * Complete the purchase of a promoted product (iOS only).
@@ -198,8 +249,9 @@ export const getPromotedProductIOS = () => {
198
249
  *
199
250
  * @platform iOS
200
251
  */
201
- export const requestPurchaseOnPromotedProductIOS = () => {
202
- return ExpoIapModule.requestPurchaseOnPromotedProductIOS();
252
+ export const requestPurchaseOnPromotedProductIOS = async () => {
253
+ await ExpoIapModule.requestPurchaseOnPromotedProductIOS();
254
+ return true;
203
255
  };
204
256
  /**
205
257
  * Get pending transactions that haven't been finished yet (iOS only).
@@ -207,8 +259,9 @@ export const requestPurchaseOnPromotedProductIOS = () => {
207
259
  * @returns Promise resolving to array of pending transactions
208
260
  * @platform iOS
209
261
  */
210
- export const getPendingTransactionsIOS = () => {
211
- return ExpoIapModule.getPendingTransactionsIOS();
262
+ export const getPendingTransactionsIOS = async () => {
263
+ const transactions = await ExpoIapModule.getPendingTransactionsIOS();
264
+ return normalizePurchaseList((transactions ?? []));
212
265
  };
213
266
  /**
214
267
  * Clear a specific transaction (iOS only).
@@ -216,8 +269,8 @@ export const getPendingTransactionsIOS = () => {
216
269
  * @returns Promise resolving when transaction is cleared
217
270
  * @platform iOS
218
271
  */
219
- export const clearTransactionIOS = () => {
220
- return ExpoIapModule.clearTransactionIOS();
272
+ export const clearTransactionIOS = async () => {
273
+ return Boolean(await ExpoIapModule.clearTransactionIOS());
221
274
  };
222
275
  /**
223
276
  * Deep link to subscriptions screen on iOS.
@@ -1 +1 @@
1
- {"version":3,"file":"ios.js","sourceRoot":"","sources":["../../src/modules/ios.ts"],"names":[],"mappings":"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","sourcesContent":["// External dependencies\n\n// Internal modules\n// import removed: use purchaseUpdatedListener directly in app code\nimport ExpoIapModule from '../ExpoIapModule';\n\n// Types\nimport type {\n Product,\n Purchase,\n SubscriptionStatusIOS,\n AppTransaction,\n ReceiptValidationResultIOS,\n} from '../types';\nimport type {PurchaseError} from '../purchase-error';\nimport {Linking} from 'react-native';\n\nexport type TransactionEvent = {\n transaction?: Purchase;\n error?: PurchaseError;\n};\n\n// Listeners\n\n// Type guards\nexport function isProductIOS<T extends {platform?: string}>(\n item: unknown,\n): item is T & {platform: 'ios'} {\n return (\n item != null &&\n typeof item === 'object' &&\n 'platform' in item &&\n (item as any).platform === 'ios'\n );\n}\n\n// Functions\n/**\n * Sync state with Appstore (iOS only)\n * https://developer.apple.com/documentation/storekit/appstore/3791906-sync\n *\n * @returns Promise resolving to null on success\n * @throws Error if called on non-iOS platform\n *\n * @platform iOS\n */\nexport const syncIOS = (): Promise<null> => {\n return ExpoIapModule.syncIOS();\n};\n\n/**\n * Check if user is eligible for introductory offer\n *\n * @param groupId The subscription group ID\n * @returns Promise resolving to true if eligible\n * @throws Error if called on non-iOS platform\n *\n * @platform iOS\n */\nexport const isEligibleForIntroOfferIOS = (\n groupId: string,\n): Promise<boolean> => {\n return ExpoIapModule.isEligibleForIntroOfferIOS(groupId);\n};\n\n/**\n * Get subscription status for a specific SKU\n *\n * @param sku The product SKU\n * @returns Promise resolving to array of subscription status\n * @throws Error if called on non-iOS platform\n *\n * @platform iOS\n */\nexport const subscriptionStatusIOS = (\n sku: string,\n): Promise<SubscriptionStatusIOS[]> => {\n return ExpoIapModule.subscriptionStatusIOS(sku);\n};\n\n/**\n * Get current entitlement for a specific SKU\n *\n * @param sku The product SKU\n * @returns Promise resolving to current entitlement\n * @throws Error if called on non-iOS platform\n *\n * @platform iOS\n */\nexport const currentEntitlementIOS = (sku: string): Promise<Purchase> => {\n return ExpoIapModule.currentEntitlementIOS(sku);\n};\n\n/**\n * Get latest transaction for a specific SKU\n *\n * @param sku The product SKU\n * @returns Promise resolving to latest transaction\n * @throws Error if called on non-iOS platform\n *\n * @platform iOS\n */\nexport const latestTransactionIOS = (sku: string): Promise<Purchase> => {\n return ExpoIapModule.latestTransactionIOS(sku);\n};\n\n/**\n * Begin refund request for a specific SKU\n *\n * @param sku The product SKU\n * @returns Promise resolving to refund request status\n * @throws Error if called on non-iOS platform\n *\n * @platform iOS\n */\ntype RefundRequestStatus = 'success' | 'userCancelled';\nexport const beginRefundRequestIOS = (\n sku: string,\n): Promise<RefundRequestStatus> => {\n return ExpoIapModule.beginRefundRequestIOS(sku);\n};\n\n/**\n * Shows the system UI for managing subscriptions.\n * Returns an array of subscriptions that had status changes after the UI is closed.\n *\n * @returns Promise<Purchase[]> - Array of subscriptions with status changes (e.g., auto-renewal toggled)\n * @throws Error if called on non-iOS platform\n *\n * @platform iOS\n */\nexport const showManageSubscriptionsIOS = (): Promise<Purchase[]> => {\n return ExpoIapModule.showManageSubscriptionsIOS();\n};\n\n/**\n * Get the receipt data from the iOS device.\n * This returns the base64 encoded receipt data which can be sent to your server\n * for verification with Apple's server.\n *\n * NOTE: For proper security, always verify receipts on your server using\n * Apple's verifyReceipt endpoint, not directly from the app.\n *\n * @returns {Promise<string>} Base64 encoded receipt data\n */\nexport const getReceiptIOS = (): Promise<string> => {\n return ExpoIapModule.getReceiptDataIOS();\n};\n\n/**\n * Check if a transaction is verified through StoreKit 2.\n * StoreKit 2 performs local verification of transaction JWS signatures.\n *\n * @param sku The product's SKU (on iOS)\n * @returns Promise resolving to true if the transaction is verified\n * @throws Error if called on non-iOS platform\n *\n * @platform iOS\n */\nexport const isTransactionVerifiedIOS = (sku: string): Promise<boolean> => {\n return ExpoIapModule.isTransactionVerifiedIOS(sku);\n};\n\n/**\n * Get the JWS representation of a purchase for server-side verification.\n * The JWS (JSON Web Signature) can be verified on your server using Apple's public keys.\n *\n * @param sku The product's SKU (on iOS)\n * @returns Promise resolving to JWS representation of the transaction\n * @throws Error if called on non-iOS platform\n *\n * @platform iOS\n */\nexport const getTransactionJwsIOS = (sku: string): Promise<string> => {\n return ExpoIapModule.getTransactionJwsIOS(sku);\n};\n\n/**\n * Validate receipt for iOS using StoreKit 2's built-in verification.\n * Returns receipt data and verification information to help with server-side validation.\n *\n * NOTE: For proper security, Apple recommends verifying receipts on your server using\n * the verifyReceipt endpoint rather than relying solely on client-side verification.\n *\n * @param {string} sku The product's SKU (on iOS)\n * @returns {Promise<{\n * isValid: boolean;\n * receiptData: string;\n * jwsRepresentation: string;\n * latestTransaction?: Purchase;\n * }>}\n */\nexport const validateReceiptIOS = async (\n sku: string,\n): Promise<ReceiptValidationResultIOS> => {\n const result = await ExpoIapModule.validateReceiptIOS(sku);\n return result;\n};\n\n/**\n * Present the code redemption sheet for offer codes (iOS only).\n * This allows users to redeem promotional codes for in-app purchases and subscriptions.\n *\n * Note: This only works on real devices, not simulators.\n *\n * @returns Promise resolving to true if the sheet was presented successfully\n * @throws Error if called on non-iOS platform or tvOS\n *\n * @platform iOS\n */\nexport const presentCodeRedemptionSheetIOS = (): Promise<boolean> => {\n return ExpoIapModule.presentCodeRedemptionSheetIOS();\n};\n\n/**\n * Get app transaction information (iOS 16.0+).\n * AppTransaction represents the initial purchase that unlocked the app.\n *\n * NOTE: This function requires:\n * - iOS 16.0 or later at runtime\n * - Xcode 15.0+ with iOS 16.0 SDK for compilation\n *\n * @returns Promise resolving to the app transaction information or null if not available\n * @throws Error if called on non-iOS platform, iOS version < 16.0, or compiled with older SDK\n *\n * @platform iOS\n * @since iOS 16.0\n */\nexport const getAppTransactionIOS = (): Promise<AppTransaction | null> => {\n return ExpoIapModule.getAppTransactionIOS();\n};\n\n/**\n * Get information about a promoted product if one is available (iOS only).\n * Promoted products are products that the App Store promotes on your behalf.\n * This is called after a promoted product event is received from the App Store.\n *\n * @returns Promise resolving to the promoted product information or null if none available\n * @throws Error if called on non-iOS platform\n *\n * @platform iOS\n */\nexport const getPromotedProductIOS = (): Promise<Product | null> => {\n return ExpoIapModule.getPromotedProductIOS();\n};\n\n/**\n * Complete the purchase of a promoted product (iOS only).\n * This should be called after showing your purchase UI for a promoted product.\n *\n * @returns Promise resolving when the purchase is initiated\n * @throws Error if called on non-iOS platform or no promoted product is available\n *\n * @platform iOS\n */\nexport const requestPurchaseOnPromotedProductIOS = (): Promise<void> => {\n return ExpoIapModule.requestPurchaseOnPromotedProductIOS();\n};\n\n/**\n * Get pending transactions that haven't been finished yet (iOS only).\n *\n * @returns Promise resolving to array of pending transactions\n * @platform iOS\n */\nexport const getPendingTransactionsIOS = (): Promise<any[]> => {\n return ExpoIapModule.getPendingTransactionsIOS();\n};\n\n/**\n * Clear a specific transaction (iOS only).\n *\n * @returns Promise resolving when transaction is cleared\n * @platform iOS\n */\nexport const clearTransactionIOS = (): Promise<void> => {\n return ExpoIapModule.clearTransactionIOS();\n};\n\n/**\n * Deep link to subscriptions screen on iOS.\n * @returns {Promise<void>}\n *\n * @platform iOS\n */\nexport const deepLinkToSubscriptionsIOS = (): Promise<void> =>\n Linking.openURL('https://apps.apple.com/account/subscriptions');\n\n// iOS-specific APIs only; cross-platform wrappers live in src/index.ts\n"]}
1
+ {"version":3,"file":"ios.js","sourceRoot":"","sources":["../../src/modules/ios.ts"],"names":[],"mappings":"AAAA,wBAAwB;AAExB,mBAAmB;AACnB,mEAAmE;AACnE,OAAO,aAAa,MAAM,kBAAkB,CAAC;AAc7C,OAAO,EAAC,OAAO,EAAC,MAAM,cAAc,CAAC;AACrC,OAAO,EAAC,mBAAmB,EAAE,qBAAqB,EAAC,MAAM,mBAAmB,CAAC;AAO7E,YAAY;AAEZ,cAAc;AACd,MAAM,UAAU,YAAY,CAC1B,IAAa;IAEb,OAAO,CACL,IAAI,IAAI,IAAI;QACZ,OAAO,IAAI,KAAK,QAAQ;QACxB,UAAU,IAAI,IAAI;QACjB,IAAY,CAAC,QAAQ,KAAK,KAAK,CACjC,CAAC;AACJ,CAAC;AAED,YAAY;AACZ;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,OAAO,GAA6B,KAAK,IAAI,EAAE;IAC1D,OAAO,OAAO,CAAC,MAAM,aAAa,CAAC,OAAO,EAAE,CAAC,CAAC;AAChD,CAAC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAEnC,KAAK,EAAE,OAAO,EAAE,EAAE;IACpB,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,aAAa,CAAC,0BAA0B,CAAC,OAAO,CAAC,CAAC;AAC3D,CAAC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAE9B,KAAK,EAAE,GAAG,EAAE,EAAE;IAChB,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAC9D,OAAO,CAAC,MAAM,IAAI,EAAE,CAA4B,CAAC;AACnD,CAAC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAE9B,KAAK,EAAE,GAAG,EAAE,EAAE;IAChB,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAChE,OAAO,mBAAmB,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAuB,CAAC,CAAC;AACvE,CAAC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAuC,KAAK,EAC3E,GAAG,EACH,EAAE;IACF,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACzD,CAAC;IACD,MAAM,WAAW,GAAG,MAAM,aAAa,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC;IAClE,OAAO,mBAAmB,CAAC,CAAC,WAAW,IAAI,IAAI,CAAuB,CAAC,CAAC;AAC1E,CAAC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAE9B,KAAK,EAAE,GAAG,EAAE,EAAE;IAChB,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAC9D,OAAO,MAAM,IAAI,IAAI,CAAC;AACxB,CAAC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAEnC,KAAK,IAAI,EAAE;IACb,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,0BAA0B,EAAE,CAAC;IACnE,OAAO,qBAAqB,CAAC,CAAC,SAAS,IAAI,EAAE,CAAkB,CAAC,CAAC;AACnE,CAAC,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAoC,KAAK,IAAI,EAAE;IAC3E,OAAO,aAAa,CAAC,iBAAiB,EAAE,CAAC;AAC3C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,iBAAiB,CAAC;AAE/C;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAEjC,KAAK,EAAE,GAAG,EAAE,EAAE;IAChB,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,aAAa,CAAC,wBAAwB,CAAC,GAAG,CAAC,CAAC;AACrD,CAAC,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAuC,KAAK,EAC3E,GAAG,EACH,EAAE;IACF,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACzD,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,aAAa,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC;IAC1D,OAAO,GAAG,IAAI,EAAE,CAAC;AACnB,CAAC,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,MAAM,sBAAsB,GAAG,KAAK,EAClC,KAAsC,EACtC,EAAE;IACF,MAAM,GAAG,GACP,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAE,KAAgC,EAAE,GAAG,CAAC;IAE7E,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACvD,CAAC;IAED,MAAM,MAAM,GAAG,CAAC,MAAM,aAAa,CAAC,kBAAkB,CACpD,GAAG,CACJ,CAA+B,CAAC;IACjC,MAAM,gBAAgB,GAAG,mBAAmB,CAC1C,MAAM,CAAC,iBAAiB,IAAI,SAAS,CACtC,CAAC;IACF,IAAI,gBAAgB,KAAK,MAAM,CAAC,iBAAiB,EAAE,CAAC;QAClD,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,OAAO;QACL,GAAG,MAAM;QACT,iBAAiB,EAAE,gBAAgB,IAAI,IAAI;KAC5C,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAC7B,sBAA0D,CAAC;AAE7D;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAEtC,KAAK,IAAI,EAAE;IACb,OAAO,OAAO,CAAC,MAAM,aAAa,CAAC,6BAA6B,EAAE,CAAC,CAAC;AACtE,CAAC,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAE7B,KAAK,IAAI,EAAE;IACb,OAAO,CAAC,MAAM,aAAa,CAAC,oBAAoB,EAAE,CAAC,IAAI,IAAI,CAAC;AAC9D,CAAC,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAE9B,KAAK,IAAI,EAAE;IACb,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,qBAAqB,EAAE,CAAC;IAC5D,OAAO,CAAC,OAAO,IAAI,IAAI,CAAsB,CAAC;AAChD,CAAC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,mCAAmC,GAE5C,KAAK,IAAI,EAAE;IACb,MAAM,aAAa,CAAC,mCAAmC,EAAE,CAAC;IAC1D,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAElC,KAAK,IAAI,EAAE;IACb,MAAM,YAAY,GAAG,MAAM,aAAa,CAAC,yBAAyB,EAAE,CAAC;IACrE,OAAO,qBAAqB,CAAC,CAAC,YAAY,IAAI,EAAE,CAAkB,CAAC,CAAC;AACtE,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAE5B,KAAK,IAAI,EAAE;IACb,OAAO,OAAO,CAAC,MAAM,aAAa,CAAC,mBAAmB,EAAE,CAAC,CAAC;AAC5D,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,GAAkB,EAAE,CAC5D,OAAO,CAAC,OAAO,CAAC,8CAA8C,CAAC,CAAC;AAElE,uEAAuE","sourcesContent":["// External dependencies\n\n// Internal modules\n// import removed: use purchaseUpdatedListener directly in app code\nimport ExpoIapModule from '../ExpoIapModule';\n\n// Types\nimport type {\n MutationField,\n ProductIOS,\n Purchase,\n PurchaseIOS,\n QueryField,\n ReceiptValidationProps,\n ReceiptValidationResultIOS,\n SubscriptionStatusIOS,\n} from '../types';\nimport type {PurchaseError} from '../purchase-error';\nimport {Linking} from 'react-native';\nimport {normalizePurchaseId, normalizePurchaseList} from '../utils/purchase';\n\nexport type TransactionEvent = {\n transaction?: Purchase;\n error?: PurchaseError;\n};\n\n// Listeners\n\n// Type guards\nexport function isProductIOS<T extends {platform?: string}>(\n item: unknown,\n): item is T & {platform: 'ios'} {\n return (\n item != null &&\n typeof item === 'object' &&\n 'platform' in item &&\n (item as any).platform === 'ios'\n );\n}\n\n// Functions\n/**\n * Sync state with Appstore (iOS only)\n * https://developer.apple.com/documentation/storekit/appstore/3791906-sync\n *\n * @returns Promise resolving to null on success\n * @throws Error if called on non-iOS platform\n *\n * @platform iOS\n */\nexport const syncIOS: MutationField<'syncIOS'> = async () => {\n return Boolean(await ExpoIapModule.syncIOS());\n};\n\n/**\n * Check if user is eligible for introductory offer\n *\n * @param groupId The subscription group ID\n * @returns Promise resolving to true if eligible\n * @throws Error if called on non-iOS platform\n *\n * @platform iOS\n */\nexport const isEligibleForIntroOfferIOS: QueryField<\n 'isEligibleForIntroOfferIOS'\n> = async (groupID) => {\n if (!groupID) {\n throw new Error('isEligibleForIntroOfferIOS requires a groupID');\n }\n return ExpoIapModule.isEligibleForIntroOfferIOS(groupID);\n};\n\n/**\n * Get subscription status for a specific SKU\n *\n * @param sku The product SKU\n * @returns Promise resolving to array of subscription status\n * @throws Error if called on non-iOS platform\n *\n * @platform iOS\n */\nexport const subscriptionStatusIOS: QueryField<\n 'subscriptionStatusIOS'\n> = async (sku) => {\n if (!sku) {\n throw new Error('subscriptionStatusIOS requires a SKU');\n }\n const status = await ExpoIapModule.subscriptionStatusIOS(sku);\n return (status ?? []) as SubscriptionStatusIOS[];\n};\n\n/**\n * Get current entitlement for a specific SKU\n *\n * @param sku The product SKU\n * @returns Promise resolving to current entitlement\n * @throws Error if called on non-iOS platform\n *\n * @platform iOS\n */\nexport const currentEntitlementIOS: QueryField<\n 'currentEntitlementIOS'\n> = async (sku) => {\n if (!sku) {\n throw new Error('currentEntitlementIOS requires a SKU');\n }\n const purchase = await ExpoIapModule.currentEntitlementIOS(sku);\n return normalizePurchaseId((purchase ?? null) as PurchaseIOS | null);\n};\n\n/**\n * Get latest transaction for a specific SKU\n *\n * @param sku The product SKU\n * @returns Promise resolving to latest transaction\n * @throws Error if called on non-iOS platform\n *\n * @platform iOS\n */\nexport const latestTransactionIOS: QueryField<'latestTransactionIOS'> = async (\n sku,\n) => {\n if (!sku) {\n throw new Error('latestTransactionIOS requires a SKU');\n }\n const transaction = await ExpoIapModule.latestTransactionIOS(sku);\n return normalizePurchaseId((transaction ?? null) as PurchaseIOS | null);\n};\n\n/**\n * Begin refund request for a specific SKU\n *\n * @param sku The product SKU\n * @returns Promise resolving to refund request status\n * @throws Error if called on non-iOS platform\n *\n * @platform iOS\n */\nexport const beginRefundRequestIOS: MutationField<\n 'beginRefundRequestIOS'\n> = async (sku) => {\n if (!sku) {\n throw new Error('beginRefundRequestIOS requires a SKU');\n }\n const status = await ExpoIapModule.beginRefundRequestIOS(sku);\n return status ?? null;\n};\n\n/**\n * Shows the system UI for managing subscriptions.\n * Returns an array of subscriptions that had status changes after the UI is closed.\n *\n * @returns Promise<Purchase[]> - Array of subscriptions with status changes (e.g., auto-renewal toggled)\n * @throws Error if called on non-iOS platform\n *\n * @platform iOS\n */\nexport const showManageSubscriptionsIOS: MutationField<\n 'showManageSubscriptionsIOS'\n> = async () => {\n const purchases = await ExpoIapModule.showManageSubscriptionsIOS();\n return normalizePurchaseList((purchases ?? []) as PurchaseIOS[]);\n};\n\n/**\n * Get the receipt data from the iOS device.\n * This returns the base64 encoded receipt data which can be sent to your server\n * for verification with Apple's server.\n *\n * NOTE: For proper security, always verify receipts on your server using\n * Apple's verifyReceipt endpoint, not directly from the app.\n *\n * @returns {Promise<string>} Base64 encoded receipt data\n */\nexport const getReceiptDataIOS: QueryField<'getReceiptDataIOS'> = async () => {\n return ExpoIapModule.getReceiptDataIOS();\n};\n\nexport const getReceiptIOS = getReceiptDataIOS;\n\n/**\n * Check if a transaction is verified through StoreKit 2.\n * StoreKit 2 performs local verification of transaction JWS signatures.\n *\n * @param sku The product's SKU (on iOS)\n * @returns Promise resolving to true if the transaction is verified\n * @throws Error if called on non-iOS platform\n *\n * @platform iOS\n */\nexport const isTransactionVerifiedIOS: QueryField<\n 'isTransactionVerifiedIOS'\n> = async (sku) => {\n if (!sku) {\n throw new Error('isTransactionVerifiedIOS requires a SKU');\n }\n return ExpoIapModule.isTransactionVerifiedIOS(sku);\n};\n\n/**\n * Get the JWS representation of a purchase for server-side verification.\n * The JWS (JSON Web Signature) can be verified on your server using Apple's public keys.\n *\n * @param sku The product's SKU (on iOS)\n * @returns Promise resolving to JWS representation of the transaction\n * @throws Error if called on non-iOS platform\n *\n * @platform iOS\n */\nexport const getTransactionJwsIOS: QueryField<'getTransactionJwsIOS'> = async (\n sku,\n) => {\n if (!sku) {\n throw new Error('getTransactionJwsIOS requires a SKU');\n }\n const jws = await ExpoIapModule.getTransactionJwsIOS(sku);\n return jws ?? '';\n};\n\n/**\n * Validate receipt for iOS using StoreKit 2's built-in verification.\n * Returns receipt data and verification information to help with server-side validation.\n *\n * NOTE: For proper security, Apple recommends verifying receipts on your server using\n * the verifyReceipt endpoint rather than relying solely on client-side verification.\n *\n * @param {string} sku The product's SKU (on iOS)\n * @returns {Promise<{\n * isValid: boolean;\n * receiptData: string;\n * jwsRepresentation: string;\n * latestTransaction?: Purchase;\n * }>}\n */\nconst validateReceiptIOSImpl = async (\n props: ReceiptValidationProps | string,\n) => {\n const sku =\n typeof props === 'string' ? props : (props as ReceiptValidationProps)?.sku;\n\n if (!sku) {\n throw new Error('validateReceiptIOS requires a SKU');\n }\n\n const result = (await ExpoIapModule.validateReceiptIOS(\n sku,\n )) as ReceiptValidationResultIOS;\n const normalizedLatest = normalizePurchaseId(\n result.latestTransaction ?? undefined,\n );\n if (normalizedLatest === result.latestTransaction) {\n return result;\n }\n return {\n ...result,\n latestTransaction: normalizedLatest ?? null,\n };\n};\n\nexport const validateReceiptIOS =\n validateReceiptIOSImpl as QueryField<'validateReceiptIOS'>;\n\n/**\n * Present the code redemption sheet for offer codes (iOS only).\n * This allows users to redeem promotional codes for in-app purchases and subscriptions.\n *\n * Note: This only works on real devices, not simulators.\n *\n * @returns Promise resolving to true if the sheet was presented successfully\n * @throws Error if called on non-iOS platform or tvOS\n *\n * @platform iOS\n */\nexport const presentCodeRedemptionSheetIOS: MutationField<\n 'presentCodeRedemptionSheetIOS'\n> = async () => {\n return Boolean(await ExpoIapModule.presentCodeRedemptionSheetIOS());\n};\n\n/**\n * Get app transaction information (iOS 16.0+).\n * AppTransaction represents the initial purchase that unlocked the app.\n *\n * NOTE: This function requires:\n * - iOS 16.0 or later at runtime\n * - Xcode 15.0+ with iOS 16.0 SDK for compilation\n *\n * @returns Promise resolving to the app transaction information or null if not available\n * @throws Error if called on non-iOS platform, iOS version < 16.0, or compiled with older SDK\n *\n * @platform iOS\n * @since iOS 16.0\n */\nexport const getAppTransactionIOS: QueryField<\n 'getAppTransactionIOS'\n> = async () => {\n return (await ExpoIapModule.getAppTransactionIOS()) ?? null;\n};\n\n/**\n * Get information about a promoted product if one is available (iOS only).\n * Promoted products are products that the App Store promotes on your behalf.\n * This is called after a promoted product event is received from the App Store.\n *\n * @returns Promise resolving to the promoted product information or null if none available\n * @throws Error if called on non-iOS platform\n *\n * @platform iOS\n */\nexport const getPromotedProductIOS: QueryField<\n 'getPromotedProductIOS'\n> = async () => {\n const product = await ExpoIapModule.getPromotedProductIOS();\n return (product ?? null) as ProductIOS | null;\n};\n\n/**\n * Complete the purchase of a promoted product (iOS only).\n * This should be called after showing your purchase UI for a promoted product.\n *\n * @returns Promise resolving when the purchase is initiated\n * @throws Error if called on non-iOS platform or no promoted product is available\n *\n * @platform iOS\n */\nexport const requestPurchaseOnPromotedProductIOS: MutationField<\n 'requestPurchaseOnPromotedProductIOS'\n> = async () => {\n await ExpoIapModule.requestPurchaseOnPromotedProductIOS();\n return true;\n};\n\n/**\n * Get pending transactions that haven't been finished yet (iOS only).\n *\n * @returns Promise resolving to array of pending transactions\n * @platform iOS\n */\nexport const getPendingTransactionsIOS: QueryField<\n 'getPendingTransactionsIOS'\n> = async () => {\n const transactions = await ExpoIapModule.getPendingTransactionsIOS();\n return normalizePurchaseList((transactions ?? []) as PurchaseIOS[]);\n};\n\n/**\n * Clear a specific transaction (iOS only).\n *\n * @returns Promise resolving when transaction is cleared\n * @platform iOS\n */\nexport const clearTransactionIOS: MutationField<\n 'clearTransactionIOS'\n> = async () => {\n return Boolean(await ExpoIapModule.clearTransactionIOS());\n};\n\n/**\n * Deep link to subscriptions screen on iOS.\n * @returns {Promise<void>}\n *\n * @platform iOS\n */\nexport const deepLinkToSubscriptionsIOS = (): Promise<void> =>\n Linking.openURL('https://apps.apple.com/account/subscriptions');\n\n// iOS-specific APIs only; cross-platform wrappers live in src/index.ts\n"]}