react-native-iap 14.7.2 → 14.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt +32 -13
- package/ios/HybridRnIap.swift +13 -0
- package/lib/module/hooks/useIAP.js +18 -8
- package/lib/module/hooks/useIAP.js.map +1 -1
- package/lib/module/index.js +19 -8
- package/lib/module/index.js.map +1 -1
- package/lib/module/types.js +31 -0
- package/lib/module/types.js.map +1 -1
- package/lib/module/utils/type-bridge.js +3 -1
- package/lib/module/utils/type-bridge.js.map +1 -1
- package/lib/typescript/src/hooks/useIAP.d.ts +2 -0
- package/lib/typescript/src/hooks/useIAP.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/RnIap.nitro.d.ts +48 -6
- package/lib/typescript/src/specs/RnIap.nitro.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +127 -12
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/utils/type-bridge.d.ts.map +1 -1
- package/nitrogen/generated/android/c++/JHybridRnIapSpec.cpp +8 -0
- package/nitrogen/generated/android/c++/JNitroAvailablePurchasesAndroidOptions.hpp +7 -3
- package/nitrogen/generated/android/c++/JNitroAvailablePurchasesIosOptions.hpp +5 -1
- package/nitrogen/generated/android/c++/JNitroProduct.hpp +7 -3
- package/nitrogen/generated/android/c++/JNitroPurchaseRequest.hpp +4 -0
- package/nitrogen/generated/android/c++/JNitroRequestPurchaseAndroid.hpp +21 -17
- package/nitrogen/generated/android/c++/JNitroRequestPurchaseIos.hpp +19 -3
- package/nitrogen/generated/android/c++/JPromotionalOfferJwsInputIOS.hpp +61 -0
- package/nitrogen/generated/android/c++/JWinBackOfferInputIOS.hpp +57 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroAvailablePurchasesAndroidOptions.kt +6 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroAvailablePurchasesIosOptions.kt +5 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroProduct.kt +6 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroRequestPurchaseAndroid.kt +9 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroRequestPurchaseIos.kt +12 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/PromotionalOfferJwsInputIOS.kt +39 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/WinBackOfferInputIOS.kt +36 -0
- package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Bridge.hpp +36 -0
- package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Umbrella.hpp +6 -0
- package/nitrogen/generated/ios/c++/HybridRnIapSpecSwift.hpp +6 -0
- package/nitrogen/generated/ios/swift/NitroAvailablePurchasesAndroidOptions.swift +31 -1
- package/nitrogen/generated/ios/swift/NitroAvailablePurchasesIosOptions.swift +31 -1
- package/nitrogen/generated/ios/swift/NitroProduct.swift +31 -1
- package/nitrogen/generated/ios/swift/NitroRequestPurchaseAndroid.swift +50 -20
- package/nitrogen/generated/ios/swift/NitroRequestPurchaseIos.swift +77 -1
- package/nitrogen/generated/ios/swift/PromotionalOfferJwsInputIOS.swift +46 -0
- package/nitrogen/generated/ios/swift/WinBackOfferInputIOS.swift +35 -0
- package/nitrogen/generated/shared/c++/NitroAvailablePurchasesAndroidOptions.hpp +6 -2
- package/nitrogen/generated/shared/c++/NitroAvailablePurchasesIosOptions.hpp +5 -1
- package/nitrogen/generated/shared/c++/NitroProduct.hpp +6 -2
- package/nitrogen/generated/shared/c++/NitroRequestPurchaseAndroid.hpp +21 -17
- package/nitrogen/generated/shared/c++/NitroRequestPurchaseIos.hpp +20 -3
- package/nitrogen/generated/shared/c++/PromotionalOfferJwsInputIOS.hpp +79 -0
- package/nitrogen/generated/shared/c++/WinBackOfferInputIOS.hpp +75 -0
- package/openiap-versions.json +4 -4
- package/package.json +1 -1
- package/src/hooks/useIAP.ts +22 -8
- package/src/index.ts +20 -12
- package/src/specs/RnIap.nitro.ts +49 -5
- package/src/types.ts +131 -12
- package/src/utils/type-bridge.ts +2 -0
package/src/hooks/useIAP.ts
CHANGED
|
@@ -104,6 +104,8 @@ type UseIap = {
|
|
|
104
104
|
export interface UseIapOptions {
|
|
105
105
|
onPurchaseSuccess?: (purchase: Purchase) => void;
|
|
106
106
|
onPurchaseError?: (error: PurchaseError) => void;
|
|
107
|
+
/** Callback for non-purchase errors (fetchProducts, getAvailablePurchases, etc.) */
|
|
108
|
+
onError?: (error: Error) => void;
|
|
107
109
|
onPromotedProductIOS?: (product: Product) => void;
|
|
108
110
|
onUserChoiceBillingAndroid?: (details: UserChoiceBillingDetails) => void;
|
|
109
111
|
/**
|
|
@@ -180,6 +182,15 @@ export function useIAP(options?: UseIapOptions): UseIap {
|
|
|
180
182
|
subscriptionsRefState.current = subscriptions;
|
|
181
183
|
}, [subscriptions]);
|
|
182
184
|
|
|
185
|
+
// Helper function to invoke onError callback
|
|
186
|
+
const invokeOnError = useCallback((error: unknown) => {
|
|
187
|
+
if (optionsRef.current?.onError) {
|
|
188
|
+
optionsRef.current.onError(
|
|
189
|
+
error instanceof Error ? error : new Error(String(error)),
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
}, []);
|
|
193
|
+
|
|
183
194
|
const fetchProductsInternal = useCallback(
|
|
184
195
|
async (params: {
|
|
185
196
|
skus: string[];
|
|
@@ -253,9 +264,10 @@ export function useIAP(options?: UseIapOptions): UseIap {
|
|
|
253
264
|
);
|
|
254
265
|
} catch (error) {
|
|
255
266
|
RnIapConsole.error('Error fetching products:', error);
|
|
267
|
+
invokeOnError(error);
|
|
256
268
|
}
|
|
257
269
|
},
|
|
258
|
-
[mergeWithDuplicateCheck],
|
|
270
|
+
[mergeWithDuplicateCheck, invokeOnError],
|
|
259
271
|
);
|
|
260
272
|
|
|
261
273
|
const getAvailablePurchasesInternal = useCallback(
|
|
@@ -268,9 +280,10 @@ export function useIAP(options?: UseIapOptions): UseIap {
|
|
|
268
280
|
setAvailablePurchases(result);
|
|
269
281
|
} catch (error) {
|
|
270
282
|
RnIapConsole.error('Error fetching available purchases:', error);
|
|
283
|
+
invokeOnError(error);
|
|
271
284
|
}
|
|
272
285
|
},
|
|
273
|
-
[],
|
|
286
|
+
[invokeOnError],
|
|
274
287
|
);
|
|
275
288
|
|
|
276
289
|
const getActiveSubscriptionsInternal = useCallback(
|
|
@@ -281,12 +294,11 @@ export function useIAP(options?: UseIapOptions): UseIap {
|
|
|
281
294
|
return result;
|
|
282
295
|
} catch (error) {
|
|
283
296
|
RnIapConsole.error('Error getting active subscriptions:', error);
|
|
284
|
-
|
|
285
|
-
// This prevents the UI from showing empty state when there are temporary network issues
|
|
297
|
+
invokeOnError(error);
|
|
286
298
|
return [];
|
|
287
299
|
}
|
|
288
300
|
},
|
|
289
|
-
[],
|
|
301
|
+
[invokeOnError],
|
|
290
302
|
);
|
|
291
303
|
|
|
292
304
|
const hasActiveSubscriptionsInternal = useCallback(
|
|
@@ -295,10 +307,11 @@ export function useIAP(options?: UseIapOptions): UseIap {
|
|
|
295
307
|
return await hasActiveSubscriptions(subscriptionIds);
|
|
296
308
|
} catch (error) {
|
|
297
309
|
RnIapConsole.error('Error checking active subscriptions:', error);
|
|
310
|
+
invokeOnError(error);
|
|
298
311
|
return false;
|
|
299
312
|
}
|
|
300
313
|
},
|
|
301
|
-
[],
|
|
314
|
+
[invokeOnError],
|
|
302
315
|
);
|
|
303
316
|
|
|
304
317
|
const finishTransaction = useCallback(
|
|
@@ -469,8 +482,9 @@ export function useIAP(options?: UseIapOptions): UseIap {
|
|
|
469
482
|
try {
|
|
470
483
|
await restorePurchasesTopLevel();
|
|
471
484
|
await getAvailablePurchasesInternal();
|
|
472
|
-
} catch (
|
|
473
|
-
RnIapConsole.warn('Failed to restore purchases:',
|
|
485
|
+
} catch (error) {
|
|
486
|
+
RnIapConsole.warn('Failed to restore purchases:', error);
|
|
487
|
+
invokeOnError(error);
|
|
474
488
|
}
|
|
475
489
|
},
|
|
476
490
|
getPromotedProductIOS,
|
package/src/index.ts
CHANGED
|
@@ -1241,27 +1241,35 @@ export const requestPurchase: MutationField<'requestPurchase'> = async (
|
|
|
1241
1241
|
skus: androidRequest.skus,
|
|
1242
1242
|
};
|
|
1243
1243
|
|
|
1244
|
-
if (androidRequest.
|
|
1245
|
-
androidPayload.
|
|
1246
|
-
androidRequest.obfuscatedAccountIdAndroid;
|
|
1244
|
+
if (androidRequest.obfuscatedAccountId) {
|
|
1245
|
+
androidPayload.obfuscatedAccountId = androidRequest.obfuscatedAccountId;
|
|
1247
1246
|
}
|
|
1248
|
-
if (androidRequest.
|
|
1249
|
-
androidPayload.
|
|
1250
|
-
androidRequest.obfuscatedProfileIdAndroid;
|
|
1247
|
+
if (androidRequest.obfuscatedProfileId) {
|
|
1248
|
+
androidPayload.obfuscatedProfileId = androidRequest.obfuscatedProfileId;
|
|
1251
1249
|
}
|
|
1252
1250
|
if (androidRequest.isOfferPersonalized != null) {
|
|
1253
1251
|
androidPayload.isOfferPersonalized = androidRequest.isOfferPersonalized;
|
|
1254
1252
|
}
|
|
1255
1253
|
|
|
1254
|
+
// One-time purchase offerToken (Android 7.0+)
|
|
1255
|
+
if (!isSubs) {
|
|
1256
|
+
const purchaseRequest = androidRequest as RequestPurchaseAndroidProps;
|
|
1257
|
+
if (purchaseRequest.offerToken) {
|
|
1258
|
+
androidPayload.offerToken = purchaseRequest.offerToken;
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1256
1262
|
if (isSubs) {
|
|
1257
1263
|
const subsRequest = androidRequest as RequestSubscriptionAndroidProps;
|
|
1258
|
-
if (subsRequest.
|
|
1259
|
-
androidPayload.
|
|
1260
|
-
|
|
1264
|
+
if (subsRequest.purchaseToken) {
|
|
1265
|
+
androidPayload.purchaseToken = subsRequest.purchaseToken;
|
|
1266
|
+
}
|
|
1267
|
+
if (subsRequest.replacementMode != null) {
|
|
1268
|
+
androidPayload.replacementMode = subsRequest.replacementMode;
|
|
1261
1269
|
}
|
|
1262
|
-
if (subsRequest.
|
|
1263
|
-
androidPayload.
|
|
1264
|
-
subsRequest.
|
|
1270
|
+
if (subsRequest.subscriptionProductReplacementParams) {
|
|
1271
|
+
androidPayload.subscriptionProductReplacementParams =
|
|
1272
|
+
subsRequest.subscriptionProductReplacementParams;
|
|
1265
1273
|
}
|
|
1266
1274
|
androidPayload.subscriptionOffers = (
|
|
1267
1275
|
subsRequest.subscriptionOffers ?? []
|
package/src/specs/RnIap.nitro.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
ExternalPurchaseNoticeResultIOS,
|
|
13
13
|
MutationFinishTransactionArgs,
|
|
14
14
|
ProductCommon,
|
|
15
|
+
PromotionalOfferJwsInputIOS,
|
|
15
16
|
PurchaseCommon,
|
|
16
17
|
PurchaseOptions,
|
|
17
18
|
VerifyPurchaseAppleOptions,
|
|
@@ -24,6 +25,7 @@ import type {
|
|
|
24
25
|
UserChoiceBillingDetails,
|
|
25
26
|
PaymentModeIOS,
|
|
26
27
|
SubscriptionProductReplacementParamsAndroid,
|
|
28
|
+
WinBackOfferInputIOS,
|
|
27
29
|
} from '../types';
|
|
28
30
|
|
|
29
31
|
// Nitro-compatible enum types (Nitro doesn't support inline string unions from types.ts)
|
|
@@ -118,20 +120,47 @@ export interface NitroRequestPurchaseIos {
|
|
|
118
120
|
* @platform iOS
|
|
119
121
|
*/
|
|
120
122
|
advancedCommerceData?: RequestPurchaseIosProps['advancedCommerceData'];
|
|
123
|
+
/**
|
|
124
|
+
* Override introductory offer eligibility (iOS 15+, WWDC 2025).
|
|
125
|
+
* Set to true to indicate the user is eligible for introductory offer,
|
|
126
|
+
* or false to indicate they are not. When nil, the system determines eligibility.
|
|
127
|
+
* Back-deployed to iOS 15.
|
|
128
|
+
* @platform iOS
|
|
129
|
+
*/
|
|
130
|
+
introductoryOfferEligibility?: boolean | null;
|
|
131
|
+
/**
|
|
132
|
+
* JWS promotional offer (iOS 15+, WWDC 2025).
|
|
133
|
+
* New signature format using compact JWS string for promotional offers.
|
|
134
|
+
* Back-deployed to iOS 15.
|
|
135
|
+
* @platform iOS
|
|
136
|
+
*/
|
|
137
|
+
promotionalOfferJWS?: PromotionalOfferJwsInputIOS | null;
|
|
138
|
+
/**
|
|
139
|
+
* Win-back offer to apply (iOS 18+).
|
|
140
|
+
* Used to re-engage churned subscribers with a discount or free trial.
|
|
141
|
+
* @platform iOS
|
|
142
|
+
*/
|
|
143
|
+
winBackOffer?: WinBackOfferInputIOS | null;
|
|
121
144
|
}
|
|
122
145
|
|
|
123
146
|
export interface NitroRequestPurchaseAndroid {
|
|
124
147
|
skus: RequestSubscriptionAndroidProps['skus'];
|
|
125
|
-
|
|
126
|
-
|
|
148
|
+
obfuscatedAccountId?: RequestSubscriptionAndroidProps['obfuscatedAccountId'];
|
|
149
|
+
obfuscatedProfileId?: RequestSubscriptionAndroidProps['obfuscatedProfileId'];
|
|
127
150
|
isOfferPersonalized?: RequestSubscriptionAndroidProps['isOfferPersonalized'];
|
|
151
|
+
/**
|
|
152
|
+
* Offer token for one-time purchase discounts (7.0+).
|
|
153
|
+
* Pass the offerToken from oneTimePurchaseOfferDetailsAndroid or discountOffers
|
|
154
|
+
* to apply a discount offer to the purchase.
|
|
155
|
+
*/
|
|
156
|
+
offerToken?: string | null;
|
|
128
157
|
subscriptionOffers?: AndroidSubscriptionOfferInput[] | null;
|
|
129
158
|
/** @deprecated Use subscriptionProductReplacementParams instead for item-level replacement (8.1.0+) */
|
|
130
|
-
|
|
131
|
-
|
|
159
|
+
replacementMode?: RequestSubscriptionAndroidProps['replacementMode'];
|
|
160
|
+
purchaseToken?: RequestSubscriptionAndroidProps['purchaseToken'];
|
|
132
161
|
/**
|
|
133
162
|
* Product-level replacement parameters (8.1.0+)
|
|
134
|
-
* Use this instead of
|
|
163
|
+
* Use this instead of replacementMode for item-level replacement
|
|
135
164
|
*/
|
|
136
165
|
subscriptionProductReplacementParams?: SubscriptionProductReplacementParamsAndroid | null;
|
|
137
166
|
}
|
|
@@ -161,6 +190,13 @@ type NitroAvailablePurchasesAndroidType = 'inapp' | 'subs';
|
|
|
161
190
|
|
|
162
191
|
export interface NitroAvailablePurchasesAndroidOptions {
|
|
163
192
|
type?: NitroAvailablePurchasesAndroidType;
|
|
193
|
+
/**
|
|
194
|
+
* Include suspended subscriptions in the result (Android 8.1+).
|
|
195
|
+
* Suspended subscriptions have isSuspendedAndroid=true and should NOT be granted entitlements.
|
|
196
|
+
* Users should be directed to the subscription center to resolve payment issues.
|
|
197
|
+
* Default: false (only active subscriptions are returned)
|
|
198
|
+
*/
|
|
199
|
+
includeSuspended?: boolean | null;
|
|
164
200
|
}
|
|
165
201
|
|
|
166
202
|
export interface NitroAvailablePurchasesOptions {
|
|
@@ -543,6 +579,14 @@ export interface NitroProduct {
|
|
|
543
579
|
freeTrialPeriodAndroid?: string | null;
|
|
544
580
|
subscriptionOfferDetailsAndroid?: string | null;
|
|
545
581
|
oneTimePurchaseOfferDetailsAndroid?: NitroOneTimePurchaseOfferDetail[] | null;
|
|
582
|
+
/**
|
|
583
|
+
* Product-level status code indicating fetch result (Android 8.0+)
|
|
584
|
+
* OK = product fetched successfully
|
|
585
|
+
* NOT_FOUND = SKU doesn't exist
|
|
586
|
+
* NO_OFFERS_AVAILABLE = user not eligible for any offers
|
|
587
|
+
* Available in Google Play Billing Library 8.0.0+
|
|
588
|
+
*/
|
|
589
|
+
productStatusAndroid?: string | null;
|
|
546
590
|
}
|
|
547
591
|
|
|
548
592
|
// ╔══════════════════════════════════════════════════════════════════════════╗
|
package/src/types.ts
CHANGED
|
@@ -99,6 +99,22 @@ export interface BillingProgramReportingDetailsAndroid {
|
|
|
99
99
|
externalTransactionToken: string;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Extended billing result with sub-response code (Android)
|
|
104
|
+
* Available in Google Play Billing Library 8.0.0+
|
|
105
|
+
*/
|
|
106
|
+
export interface BillingResultAndroid {
|
|
107
|
+
/** Debug message from the billing library */
|
|
108
|
+
debugMessage?: (string | null);
|
|
109
|
+
/** The response code from the billing operation */
|
|
110
|
+
responseCode: number;
|
|
111
|
+
/**
|
|
112
|
+
* Sub-response code for more granular error information (8.0+).
|
|
113
|
+
* Provides additional context when responseCode indicates an error.
|
|
114
|
+
*/
|
|
115
|
+
subResponseCode?: (SubResponseCodeAndroid | null);
|
|
116
|
+
}
|
|
117
|
+
|
|
102
118
|
export interface DeepLinkOptions {
|
|
103
119
|
/** Android package name to target (required on Android) */
|
|
104
120
|
packageNameAndroid?: (string | null);
|
|
@@ -525,7 +541,7 @@ export interface Mutation {
|
|
|
525
541
|
* promoted products can be purchased directly via the standard purchase flow.
|
|
526
542
|
* @deprecated Use promotedProductListenerIOS + requestPurchase instead
|
|
527
543
|
*/
|
|
528
|
-
requestPurchaseOnPromotedProductIOS: boolean
|
|
544
|
+
requestPurchaseOnPromotedProductIOS: Promise<boolean>;
|
|
529
545
|
/** Restore completed purchases across platforms */
|
|
530
546
|
restorePurchases: Promise<void>;
|
|
531
547
|
/**
|
|
@@ -664,6 +680,14 @@ export interface ProductAndroid extends ProductCommon {
|
|
|
664
680
|
oneTimePurchaseOfferDetailsAndroid?: (ProductAndroidOneTimePurchaseOfferDetail[] | null);
|
|
665
681
|
platform: 'android';
|
|
666
682
|
price?: (number | null);
|
|
683
|
+
/**
|
|
684
|
+
* Product-level status code indicating fetch result (Android 8.0+)
|
|
685
|
+
* OK = product fetched successfully
|
|
686
|
+
* NOT_FOUND = SKU doesn't exist
|
|
687
|
+
* NO_OFFERS_AVAILABLE = user not eligible for any offers
|
|
688
|
+
* Available in Google Play Billing Library 8.0.0+
|
|
689
|
+
*/
|
|
690
|
+
productStatusAndroid?: (ProductStatusAndroid | null);
|
|
667
691
|
/**
|
|
668
692
|
* @deprecated Use subscriptionOffers instead for cross-platform compatibility.
|
|
669
693
|
* @deprecated Use subscriptionOffers instead
|
|
@@ -769,6 +793,14 @@ export interface ProductRequest {
|
|
|
769
793
|
type?: (ProductQueryType | null);
|
|
770
794
|
}
|
|
771
795
|
|
|
796
|
+
/**
|
|
797
|
+
* Status code for individual products returned from queryProductDetailsAsync (Android)
|
|
798
|
+
* Prior to 8.0, products that couldn't be fetched were simply not returned.
|
|
799
|
+
* With 8.0+, these products are returned with a status code explaining why.
|
|
800
|
+
* Available in Google Play Billing Library 8.0.0+
|
|
801
|
+
*/
|
|
802
|
+
export type ProductStatusAndroid = 'ok' | 'not-found' | 'no-offers-available' | 'unknown';
|
|
803
|
+
|
|
772
804
|
export type ProductSubscription = ProductSubscriptionAndroid | ProductSubscriptionIOS;
|
|
773
805
|
|
|
774
806
|
export interface ProductSubscriptionAndroid extends ProductCommon {
|
|
@@ -794,6 +826,14 @@ export interface ProductSubscriptionAndroid extends ProductCommon {
|
|
|
794
826
|
oneTimePurchaseOfferDetailsAndroid?: (ProductAndroidOneTimePurchaseOfferDetail[] | null);
|
|
795
827
|
platform: 'android';
|
|
796
828
|
price?: (number | null);
|
|
829
|
+
/**
|
|
830
|
+
* Product-level status code indicating fetch result (Android 8.0+)
|
|
831
|
+
* OK = product fetched successfully
|
|
832
|
+
* NOT_FOUND = SKU doesn't exist
|
|
833
|
+
* NO_OFFERS_AVAILABLE = user not eligible for any offers
|
|
834
|
+
* Available in Google Play Billing Library 8.0.0+
|
|
835
|
+
*/
|
|
836
|
+
productStatusAndroid?: (ProductStatusAndroid | null);
|
|
797
837
|
/**
|
|
798
838
|
* @deprecated Use subscriptionOffers instead for cross-platform compatibility.
|
|
799
839
|
* @deprecated Use subscriptionOffers instead
|
|
@@ -866,6 +906,23 @@ export type ProductType = 'in-app' | 'subs';
|
|
|
866
906
|
|
|
867
907
|
export type ProductTypeIOS = 'consumable' | 'non-consumable' | 'auto-renewable-subscription' | 'non-renewing-subscription';
|
|
868
908
|
|
|
909
|
+
/**
|
|
910
|
+
* JWS promotional offer input for iOS 15+ (StoreKit 2, WWDC 2025).
|
|
911
|
+
* New signature format using compact JWS string for promotional offers.
|
|
912
|
+
* This provides a simpler alternative to the legacy signature-based promotional offers.
|
|
913
|
+
* Back-deployed to iOS 15.
|
|
914
|
+
*/
|
|
915
|
+
export interface PromotionalOfferJwsInputIOS {
|
|
916
|
+
/**
|
|
917
|
+
* Compact JWS string signed by your server.
|
|
918
|
+
* The JWS should contain the promotional offer signature data.
|
|
919
|
+
* Format: header.payload.signature (base64url encoded)
|
|
920
|
+
*/
|
|
921
|
+
jws: string;
|
|
922
|
+
/** The promotional offer identifier from App Store Connect */
|
|
923
|
+
offerId: string;
|
|
924
|
+
}
|
|
925
|
+
|
|
869
926
|
export type Purchase = PurchaseAndroid | PurchaseIOS;
|
|
870
927
|
|
|
871
928
|
export interface PurchaseAndroid extends PurchaseCommon {
|
|
@@ -980,6 +1037,13 @@ export interface PurchaseOfferIOS {
|
|
|
980
1037
|
export interface PurchaseOptions {
|
|
981
1038
|
/** Also emit results through the iOS event listeners */
|
|
982
1039
|
alsoPublishToEventListenerIOS?: (boolean | null);
|
|
1040
|
+
/**
|
|
1041
|
+
* Include suspended subscriptions in the result (Android 8.1+).
|
|
1042
|
+
* Suspended subscriptions have isSuspendedAndroid=true and should NOT be granted entitlements.
|
|
1043
|
+
* Users should be directed to the subscription center to resolve payment issues.
|
|
1044
|
+
* Default: false (only active subscriptions are returned)
|
|
1045
|
+
*/
|
|
1046
|
+
includeSuspendedAndroid?: (boolean | null);
|
|
983
1047
|
/** Limit to currently active items on iOS */
|
|
984
1048
|
onlyIncludeActiveItemsIOS?: (boolean | null);
|
|
985
1049
|
}
|
|
@@ -1130,12 +1194,21 @@ export interface RequestPurchaseAndroidProps {
|
|
|
1130
1194
|
* Google Play Billing and the developer's external payment option.
|
|
1131
1195
|
*/
|
|
1132
1196
|
developerBillingOption?: (DeveloperBillingOptionParamsAndroid | null);
|
|
1133
|
-
/**
|
|
1197
|
+
/**
|
|
1198
|
+
* Personalized offer flag.
|
|
1199
|
+
* When true, indicates the price was customized for this user.
|
|
1200
|
+
*/
|
|
1134
1201
|
isOfferPersonalized?: (boolean | null);
|
|
1135
1202
|
/** Obfuscated account ID */
|
|
1136
|
-
|
|
1203
|
+
obfuscatedAccountId?: (string | null);
|
|
1137
1204
|
/** Obfuscated profile ID */
|
|
1138
|
-
|
|
1205
|
+
obfuscatedProfileId?: (string | null);
|
|
1206
|
+
/**
|
|
1207
|
+
* Offer token for one-time purchase discounts (7.0+).
|
|
1208
|
+
* Pass the offerToken from oneTimePurchaseOfferDetailsAndroid or discountOffers
|
|
1209
|
+
* to apply a discount offer to the purchase.
|
|
1210
|
+
*/
|
|
1211
|
+
offerToken?: (string | null);
|
|
1139
1212
|
/** List of product SKUs */
|
|
1140
1213
|
skus: string[];
|
|
1141
1214
|
}
|
|
@@ -1156,7 +1229,10 @@ export interface RequestPurchaseIosProps {
|
|
|
1156
1229
|
quantity?: (number | null);
|
|
1157
1230
|
/** Product SKU */
|
|
1158
1231
|
sku: string;
|
|
1159
|
-
/**
|
|
1232
|
+
/**
|
|
1233
|
+
* Promotional offer to apply (subscriptions only, ignored for one-time purchases).
|
|
1234
|
+
* iOS only supports promotional offers for auto-renewable subscriptions.
|
|
1235
|
+
*/
|
|
1160
1236
|
withOffer?: (DiscountOfferInputIOS | null);
|
|
1161
1237
|
}
|
|
1162
1238
|
|
|
@@ -1204,26 +1280,29 @@ export interface RequestSubscriptionAndroidProps {
|
|
|
1204
1280
|
* Google Play Billing and the developer's external payment option.
|
|
1205
1281
|
*/
|
|
1206
1282
|
developerBillingOption?: (DeveloperBillingOptionParamsAndroid | null);
|
|
1207
|
-
/**
|
|
1283
|
+
/**
|
|
1284
|
+
* Personalized offer flag.
|
|
1285
|
+
* When true, indicates the price was customized for this user.
|
|
1286
|
+
*/
|
|
1208
1287
|
isOfferPersonalized?: (boolean | null);
|
|
1209
1288
|
/** Obfuscated account ID */
|
|
1210
|
-
|
|
1289
|
+
obfuscatedAccountId?: (string | null);
|
|
1211
1290
|
/** Obfuscated profile ID */
|
|
1212
|
-
|
|
1291
|
+
obfuscatedProfileId?: (string | null);
|
|
1213
1292
|
/** Purchase token for upgrades/downgrades */
|
|
1214
|
-
|
|
1293
|
+
purchaseToken?: (string | null);
|
|
1215
1294
|
/**
|
|
1216
1295
|
* Replacement mode for subscription changes
|
|
1217
1296
|
* @deprecated Use subscriptionProductReplacementParams instead for item-level replacement (8.1.0+)
|
|
1218
1297
|
*/
|
|
1219
|
-
|
|
1298
|
+
replacementMode?: (number | null);
|
|
1220
1299
|
/** List of subscription SKUs */
|
|
1221
1300
|
skus: string[];
|
|
1222
1301
|
/** Subscription offers */
|
|
1223
1302
|
subscriptionOffers?: (AndroidSubscriptionOfferInput[] | null);
|
|
1224
1303
|
/**
|
|
1225
1304
|
* Product-level replacement parameters (8.1.0+)
|
|
1226
|
-
* Use this instead of
|
|
1305
|
+
* Use this instead of replacementMode for item-level replacement
|
|
1227
1306
|
*/
|
|
1228
1307
|
subscriptionProductReplacementParams?: (SubscriptionProductReplacementParamsAndroid | null);
|
|
1229
1308
|
}
|
|
@@ -1238,8 +1317,32 @@ export interface RequestSubscriptionIosProps {
|
|
|
1238
1317
|
advancedCommerceData?: (string | null);
|
|
1239
1318
|
andDangerouslyFinishTransactionAutomatically?: (boolean | null);
|
|
1240
1319
|
appAccountToken?: (string | null);
|
|
1320
|
+
/**
|
|
1321
|
+
* Override introductory offer eligibility (iOS 15+, WWDC 2025).
|
|
1322
|
+
* Set to true to indicate the user is eligible for introductory offer,
|
|
1323
|
+
* or false to indicate they are not. When nil, the system determines eligibility.
|
|
1324
|
+
* Back-deployed to iOS 15.
|
|
1325
|
+
*/
|
|
1326
|
+
introductoryOfferEligibility?: (boolean | null);
|
|
1327
|
+
/**
|
|
1328
|
+
* JWS promotional offer (iOS 15+, WWDC 2025).
|
|
1329
|
+
* New signature format using compact JWS string for promotional offers.
|
|
1330
|
+
* Back-deployed to iOS 15.
|
|
1331
|
+
*/
|
|
1332
|
+
promotionalOfferJWS?: (PromotionalOfferJwsInputIOS | null);
|
|
1241
1333
|
quantity?: (number | null);
|
|
1242
1334
|
sku: string;
|
|
1335
|
+
/**
|
|
1336
|
+
* Win-back offer to apply (iOS 18+)
|
|
1337
|
+
* Used to re-engage churned subscribers with a discount or free trial.
|
|
1338
|
+
* The offer is available when the customer is eligible and can be discovered
|
|
1339
|
+
* via StoreKit Message (automatic) or subscription offer APIs.
|
|
1340
|
+
*/
|
|
1341
|
+
winBackOffer?: (WinBackOfferInputIOS | null);
|
|
1342
|
+
/**
|
|
1343
|
+
* Promotional offer to apply for subscription purchases.
|
|
1344
|
+
* Requires server-signed offer with nonce, timestamp, keyId, and signature.
|
|
1345
|
+
*/
|
|
1243
1346
|
withOffer?: (DiscountOfferInputIOS | null);
|
|
1244
1347
|
}
|
|
1245
1348
|
|
|
@@ -1295,6 +1398,12 @@ export interface RequestVerifyPurchaseWithIapkitResult {
|
|
|
1295
1398
|
store: IapStore;
|
|
1296
1399
|
}
|
|
1297
1400
|
|
|
1401
|
+
/**
|
|
1402
|
+
* Sub-response codes for more granular purchase error information (Android)
|
|
1403
|
+
* Available in Google Play Billing Library 8.0.0+
|
|
1404
|
+
*/
|
|
1405
|
+
export type SubResponseCodeAndroid = 'no-applicable-sub-response-code' | 'payment-declined-due-to-insufficient-funds' | 'user-ineligible';
|
|
1406
|
+
|
|
1298
1407
|
export interface Subscription {
|
|
1299
1408
|
/**
|
|
1300
1409
|
* Fires when a user selects developer billing in the External Payments flow (Android only)
|
|
@@ -1415,7 +1524,7 @@ export interface SubscriptionOfferIOS {
|
|
|
1415
1524
|
type: SubscriptionOfferTypeIOS;
|
|
1416
1525
|
}
|
|
1417
1526
|
|
|
1418
|
-
export type SubscriptionOfferTypeIOS = 'introductory' | 'promotional';
|
|
1527
|
+
export type SubscriptionOfferTypeIOS = 'introductory' | 'promotional' | 'win-back';
|
|
1419
1528
|
|
|
1420
1529
|
/** Subscription period value combining unit and count. */
|
|
1421
1530
|
export interface SubscriptionPeriod {
|
|
@@ -1615,6 +1724,16 @@ export interface VerifyPurchaseWithProviderResult {
|
|
|
1615
1724
|
|
|
1616
1725
|
export type VoidResult = void;
|
|
1617
1726
|
|
|
1727
|
+
/**
|
|
1728
|
+
* Win-back offer input for iOS 18+ (StoreKit 2)
|
|
1729
|
+
* Win-back offers are used to re-engage churned subscribers.
|
|
1730
|
+
* The offer is automatically presented via StoreKit Message when eligible,
|
|
1731
|
+
* or can be applied programmatically during purchase.
|
|
1732
|
+
*/
|
|
1733
|
+
export interface WinBackOfferInputIOS {
|
|
1734
|
+
/** The win-back offer ID from App Store Connect */
|
|
1735
|
+
offerId: string;
|
|
1736
|
+
}
|
|
1618
1737
|
// -- Query helper types (auto-generated)
|
|
1619
1738
|
export type QueryArgsMap = {
|
|
1620
1739
|
canPresentExternalPurchaseNoticeIOS: never;
|
package/src/utils/type-bridge.ts
CHANGED
|
@@ -312,6 +312,8 @@ export function convertNitroProductToProduct(
|
|
|
312
312
|
subscriptionOfferDetailsAndroid: parseSubscriptionOffers(
|
|
313
313
|
nitroProduct.subscriptionOfferDetailsAndroid,
|
|
314
314
|
),
|
|
315
|
+
// Product status (Billing Library 8.0+, OpenIAP 1.3.14+)
|
|
316
|
+
productStatusAndroid: nitroProduct.productStatusAndroid ?? null,
|
|
315
317
|
};
|
|
316
318
|
|
|
317
319
|
// Parse standardized subscriptionOffers (cross-platform, OpenIAP 1.3.10+)
|