react-native-iap 15.2.3 → 15.3.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.
- package/README.md +31 -51
- package/android/build.gradle +92 -22
- package/android/gradle.properties +5 -1
- package/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt +24 -8
- package/android/src/main/java/com/margelo/nitro/iap/RnIapLog.kt +3 -1
- package/ios/HybridRnIap.swift +172 -73
- package/lib/module/hooks/useIAP.js +1 -1
- package/lib/module/hooks/useIAP.js.map +1 -1
- package/lib/module/index.js +138 -165
- package/lib/module/index.js.map +1 -1
- package/lib/module/types.js.map +1 -1
- package/lib/typescript/src/hooks/useIAP.d.ts +22 -16
- package/lib/typescript/src/hooks/useIAP.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +61 -90
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/RnIap.nitro.d.ts +5 -16
- package/lib/typescript/src/specs/RnIap.nitro.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +63 -49
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/nitro.json +0 -1
- package/nitrogen/generated/android/c++/JHybridRnIapSpec.cpp +11 -6
- package/nitrogen/generated/android/c++/JHybridRnIapSpec.hpp +2 -2
- package/nitrogen/generated/android/c++/JPurchaseUpdatedListenerOptions.hpp +61 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/HybridRnIapSpec.kt +4 -9
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/PurchaseUpdatedListenerOptions.kt +38 -0
- package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Bridge.hpp +27 -0
- package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Umbrella.hpp +3 -0
- package/nitrogen/generated/ios/c++/HybridRnIapSpecSwift.hpp +9 -4
- package/nitrogen/generated/ios/swift/HybridRnIapSpec.swift +2 -2
- package/nitrogen/generated/ios/swift/HybridRnIapSpec_cxx.swift +8 -12
- package/nitrogen/generated/ios/swift/PurchaseUpdatedListenerOptions.swift +61 -0
- package/nitrogen/generated/shared/c++/HybridRnIapSpec.hpp +5 -2
- package/nitrogen/generated/shared/c++/PurchaseUpdatedListenerOptions.hpp +85 -0
- package/openiap-versions.json +3 -3
- package/package.json +4 -6
- package/src/hooks/useIAP.ts +23 -15
- package/src/index.ts +198 -215
- package/src/specs/RnIap.nitro.ts +10 -18
- package/src/types.ts +66 -49
package/src/index.ts
CHANGED
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
NitroReceiptValidationParams,
|
|
11
11
|
NitroReceiptValidationResultIOS,
|
|
12
12
|
NitroReceiptValidationResultAndroid,
|
|
13
|
+
NitroPurchaseUpdatedListenerOptions,
|
|
13
14
|
NitroSubscriptionStatus,
|
|
14
15
|
RnIap,
|
|
15
16
|
} from './specs/RnIap.nitro';
|
|
@@ -30,6 +31,7 @@ import type {
|
|
|
30
31
|
ProductSubscription,
|
|
31
32
|
Purchase,
|
|
32
33
|
PurchaseError,
|
|
34
|
+
PurchaseUpdatedListenerOptions,
|
|
33
35
|
PurchaseIOS,
|
|
34
36
|
QueryField,
|
|
35
37
|
AppTransaction,
|
|
@@ -42,6 +44,8 @@ import type {
|
|
|
42
44
|
RequestSubscriptionIosProps,
|
|
43
45
|
RequestSubscriptionPropsByPlatforms,
|
|
44
46
|
ActiveSubscription,
|
|
47
|
+
DeveloperProvidedBillingDetailsAndroid,
|
|
48
|
+
UserChoiceBillingDetails,
|
|
45
49
|
} from './types';
|
|
46
50
|
import {
|
|
47
51
|
convertNitroProductToProduct,
|
|
@@ -70,8 +74,6 @@ import {parseAppTransactionPayload} from './utils';
|
|
|
70
74
|
// Import them here for use in this file's interfaces and functions.
|
|
71
75
|
import type {
|
|
72
76
|
BillingProgramAndroid,
|
|
73
|
-
ExternalLinkLaunchModeAndroid,
|
|
74
|
-
ExternalLinkTypeAndroid,
|
|
75
77
|
} from './types';
|
|
76
78
|
|
|
77
79
|
// Export all types
|
|
@@ -87,7 +89,7 @@ export * from './utils/error';
|
|
|
87
89
|
export type ProductTypeInput = 'inapp' | 'in-app' | 'subs';
|
|
88
90
|
|
|
89
91
|
const LEGACY_INAPP_WARNING =
|
|
90
|
-
"[react-native-iap] `type: 'inapp'` is deprecated and will be removed in
|
|
92
|
+
"[react-native-iap] `type: 'inapp'` is deprecated and will be removed in a future major version. Use 'in-app' instead.";
|
|
91
93
|
|
|
92
94
|
type NitroPurchaseRequest = Parameters<RnIap['requestPurchase']>[0];
|
|
93
95
|
type NitroAvailablePurchasesOptions = NonNullable<
|
|
@@ -97,6 +99,9 @@ type NitroFinishTransactionParamsInternal = Parameters<
|
|
|
97
99
|
RnIap['finishTransaction']
|
|
98
100
|
>[0];
|
|
99
101
|
type NitroPurchaseListener = Parameters<RnIap['addPurchaseUpdatedListener']>[0];
|
|
102
|
+
type NitroPurchaseUpdatedListenerOptionsParam = NonNullable<
|
|
103
|
+
Parameters<RnIap['addPurchaseUpdatedListener']>[1]
|
|
104
|
+
>;
|
|
100
105
|
type NitroPurchaseErrorListener = Parameters<
|
|
101
106
|
RnIap['addPurchaseErrorListener']
|
|
102
107
|
>[0];
|
|
@@ -116,6 +121,9 @@ const toErrorMessage = (error: unknown): string => {
|
|
|
116
121
|
return String(error ?? '');
|
|
117
122
|
};
|
|
118
123
|
|
|
124
|
+
const unsupportedPlatformError = (): Error =>
|
|
125
|
+
new Error(`Unsupported platform: ${Platform.OS}`);
|
|
126
|
+
|
|
119
127
|
export interface EventSubscription {
|
|
120
128
|
remove(): void;
|
|
121
129
|
}
|
|
@@ -129,10 +137,7 @@ export type {
|
|
|
129
137
|
UseWebhookEventsOptions,
|
|
130
138
|
UseWebhookEventsResult,
|
|
131
139
|
} from './hooks/useWebhookEvents';
|
|
132
|
-
export {
|
|
133
|
-
connectWebhookStream,
|
|
134
|
-
parseWebhookEventData,
|
|
135
|
-
} from './webhook-client';
|
|
140
|
+
export {connectWebhookStream, parseWebhookEventData} from './webhook-client';
|
|
136
141
|
export type {
|
|
137
142
|
WebhookEventPayload,
|
|
138
143
|
WebhookEventStream,
|
|
@@ -232,11 +237,20 @@ const IAP = {
|
|
|
232
237
|
// ============================================================================
|
|
233
238
|
|
|
234
239
|
const purchaseUpdateJsListeners = new Set<(purchase: Purchase) => void>();
|
|
240
|
+
const purchaseUpdateDuplicateJsListeners = new Set<
|
|
241
|
+
(purchase: Purchase) => void
|
|
242
|
+
>();
|
|
235
243
|
let purchaseUpdateNativeAttached = false;
|
|
236
|
-
|
|
244
|
+
let purchaseUpdateDuplicateNativeAttached = false;
|
|
245
|
+
let purchaseUpdateNativeToken: number | null = null;
|
|
246
|
+
let purchaseUpdateDuplicateNativeToken: number | null = null;
|
|
247
|
+
const emitPurchaseUpdateToListeners = (
|
|
248
|
+
nitroPurchase: Parameters<NitroPurchaseListener>[0],
|
|
249
|
+
listeners: Set<(purchase: Purchase) => void>,
|
|
250
|
+
) => {
|
|
237
251
|
if (validateNitroPurchase(nitroPurchase)) {
|
|
238
252
|
const convertedPurchase = convertNitroPurchaseToPurchase(nitroPurchase);
|
|
239
|
-
for (const listener of
|
|
253
|
+
for (const listener of listeners) {
|
|
240
254
|
try {
|
|
241
255
|
listener(convertedPurchase);
|
|
242
256
|
} catch (e) {
|
|
@@ -250,6 +264,17 @@ const purchaseUpdateNativeHandler: NitroPurchaseListener = (nitroPurchase) => {
|
|
|
250
264
|
);
|
|
251
265
|
}
|
|
252
266
|
};
|
|
267
|
+
const purchaseUpdateNativeHandler: NitroPurchaseListener = (nitroPurchase) => {
|
|
268
|
+
emitPurchaseUpdateToListeners(nitroPurchase, purchaseUpdateJsListeners);
|
|
269
|
+
};
|
|
270
|
+
const purchaseUpdateDuplicateNativeHandler: NitroPurchaseListener = (
|
|
271
|
+
nitroPurchase,
|
|
272
|
+
) => {
|
|
273
|
+
emitPurchaseUpdateToListeners(
|
|
274
|
+
nitroPurchase,
|
|
275
|
+
purchaseUpdateDuplicateJsListeners,
|
|
276
|
+
);
|
|
277
|
+
};
|
|
253
278
|
|
|
254
279
|
const purchaseErrorJsListeners = new Set<(error: PurchaseError) => void>();
|
|
255
280
|
let purchaseErrorNativeAttached = false;
|
|
@@ -299,6 +324,9 @@ const promotedProductNativeHandler: NitroPromotedProductListener = (
|
|
|
299
324
|
*/
|
|
300
325
|
export const resetListenerState = (): void => {
|
|
301
326
|
purchaseUpdateNativeAttached = false;
|
|
327
|
+
purchaseUpdateDuplicateNativeAttached = false;
|
|
328
|
+
purchaseUpdateNativeToken = null;
|
|
329
|
+
purchaseUpdateDuplicateNativeToken = null;
|
|
302
330
|
purchaseErrorNativeAttached = false;
|
|
303
331
|
promotedProductNativeAttached = false;
|
|
304
332
|
userChoiceBillingNativeAttached = false;
|
|
@@ -306,6 +334,7 @@ export const resetListenerState = (): void => {
|
|
|
306
334
|
subscriptionBillingIssueNativeAttached = false;
|
|
307
335
|
// Clear all JS listeners since native side clears them in endConnection
|
|
308
336
|
purchaseUpdateJsListeners.clear();
|
|
337
|
+
purchaseUpdateDuplicateJsListeners.clear();
|
|
309
338
|
purchaseErrorJsListeners.clear();
|
|
310
339
|
promotedProductJsListeners.clear();
|
|
311
340
|
userChoiceBillingJsListeners.clear();
|
|
@@ -315,12 +344,22 @@ export const resetListenerState = (): void => {
|
|
|
315
344
|
|
|
316
345
|
export const purchaseUpdatedListener = (
|
|
317
346
|
listener: (purchase: Purchase) => void,
|
|
347
|
+
options?: PurchaseUpdatedListenerOptions | null,
|
|
318
348
|
): EventSubscription => {
|
|
319
|
-
|
|
349
|
+
const receiveDuplicateTransactionUpdatesIOS =
|
|
350
|
+
Platform.OS === 'ios' && options?.dedupeTransactionIOS === false;
|
|
351
|
+
const listeners = receiveDuplicateTransactionUpdatesIOS
|
|
352
|
+
? purchaseUpdateDuplicateJsListeners
|
|
353
|
+
: purchaseUpdateJsListeners;
|
|
354
|
+
|
|
355
|
+
listeners.add(listener);
|
|
320
356
|
|
|
321
|
-
if (!purchaseUpdateNativeAttached) {
|
|
357
|
+
if (!purchaseUpdateNativeAttached && !receiveDuplicateTransactionUpdatesIOS) {
|
|
322
358
|
try {
|
|
323
|
-
IAP.instance.addPurchaseUpdatedListener(
|
|
359
|
+
const token = IAP.instance.addPurchaseUpdatedListener(
|
|
360
|
+
purchaseUpdateNativeHandler,
|
|
361
|
+
);
|
|
362
|
+
purchaseUpdateNativeToken = typeof token === 'number' ? token : null;
|
|
324
363
|
purchaseUpdateNativeAttached = true;
|
|
325
364
|
} catch (e) {
|
|
326
365
|
const msg = toErrorMessage(e);
|
|
@@ -334,9 +373,65 @@ export const purchaseUpdatedListener = (
|
|
|
334
373
|
}
|
|
335
374
|
}
|
|
336
375
|
|
|
376
|
+
if (
|
|
377
|
+
!purchaseUpdateDuplicateNativeAttached &&
|
|
378
|
+
receiveDuplicateTransactionUpdatesIOS
|
|
379
|
+
) {
|
|
380
|
+
try {
|
|
381
|
+
const nativeOptions: NitroPurchaseUpdatedListenerOptions &
|
|
382
|
+
NitroPurchaseUpdatedListenerOptionsParam = {
|
|
383
|
+
dedupeTransactionIOS: false,
|
|
384
|
+
};
|
|
385
|
+
const token = IAP.instance.addPurchaseUpdatedListener(
|
|
386
|
+
purchaseUpdateDuplicateNativeHandler,
|
|
387
|
+
nativeOptions,
|
|
388
|
+
);
|
|
389
|
+
purchaseUpdateDuplicateNativeToken =
|
|
390
|
+
typeof token === 'number' ? token : null;
|
|
391
|
+
purchaseUpdateDuplicateNativeAttached = true;
|
|
392
|
+
} catch (e) {
|
|
393
|
+
const msg = toErrorMessage(e);
|
|
394
|
+
if (msg.includes('Nitro runtime not installed')) {
|
|
395
|
+
RnIapConsole.warn(
|
|
396
|
+
'[purchaseUpdatedListener] Nitro not ready yet; listener inert until initConnection()',
|
|
397
|
+
);
|
|
398
|
+
} else {
|
|
399
|
+
throw e;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
let removed = false;
|
|
337
405
|
return {
|
|
338
406
|
remove: () => {
|
|
339
|
-
|
|
407
|
+
if (removed) {
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
removed = true;
|
|
411
|
+
listeners.delete(listener);
|
|
412
|
+
if (listeners.size > 0) {
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const token = receiveDuplicateTransactionUpdatesIOS
|
|
417
|
+
? purchaseUpdateDuplicateNativeToken
|
|
418
|
+
: purchaseUpdateNativeToken;
|
|
419
|
+
if (token == null) {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
try {
|
|
424
|
+
IAP.instance.removePurchaseUpdatedListener(token);
|
|
425
|
+
if (receiveDuplicateTransactionUpdatesIOS) {
|
|
426
|
+
purchaseUpdateDuplicateNativeToken = null;
|
|
427
|
+
purchaseUpdateDuplicateNativeAttached = false;
|
|
428
|
+
} else {
|
|
429
|
+
purchaseUpdateNativeToken = null;
|
|
430
|
+
purchaseUpdateNativeAttached = false;
|
|
431
|
+
}
|
|
432
|
+
} catch (e) {
|
|
433
|
+
RnIapConsole.warn('[purchaseUpdatedListener] native remove failed:', e);
|
|
434
|
+
}
|
|
340
435
|
},
|
|
341
436
|
};
|
|
342
437
|
};
|
|
@@ -425,7 +520,7 @@ export const promotedProductListenerIOS = (
|
|
|
425
520
|
* const subscription = userChoiceBillingListenerAndroid((details) => {
|
|
426
521
|
* console.log('User chose alternative billing');
|
|
427
522
|
* console.log('Products:', details.products);
|
|
428
|
-
* console.log('
|
|
523
|
+
* console.log('External transaction token received; send it to your backend without logging it.');
|
|
429
524
|
*
|
|
430
525
|
* // Send token to backend for Google Play reporting
|
|
431
526
|
* await reportToGooglePlay(details.externalTransactionToken);
|
|
@@ -439,7 +534,9 @@ type NitroUserChoiceBillingListener = Parameters<
|
|
|
439
534
|
RnIap['addUserChoiceBillingListenerAndroid']
|
|
440
535
|
>[0];
|
|
441
536
|
|
|
442
|
-
const userChoiceBillingJsListeners = new Set<
|
|
537
|
+
const userChoiceBillingJsListeners = new Set<
|
|
538
|
+
(details: UserChoiceBillingDetails) => void
|
|
539
|
+
>();
|
|
443
540
|
let userChoiceBillingNativeAttached = false;
|
|
444
541
|
const userChoiceBillingNativeHandler: NitroUserChoiceBillingListener = (
|
|
445
542
|
details,
|
|
@@ -457,7 +554,7 @@ const userChoiceBillingNativeHandler: NitroUserChoiceBillingListener = (
|
|
|
457
554
|
};
|
|
458
555
|
|
|
459
556
|
export const userChoiceBillingListenerAndroid = (
|
|
460
|
-
listener: (details:
|
|
557
|
+
listener: (details: UserChoiceBillingDetails) => void,
|
|
461
558
|
): EventSubscription => {
|
|
462
559
|
if (Platform.OS !== 'android') {
|
|
463
560
|
RnIapConsole.warn(
|
|
@@ -510,7 +607,7 @@ export const userChoiceBillingListenerAndroid = (
|
|
|
510
607
|
* ```typescript
|
|
511
608
|
* const subscription = developerProvidedBillingListenerAndroid((details) => {
|
|
512
609
|
* console.log('User chose developer billing');
|
|
513
|
-
* console.log('
|
|
610
|
+
* console.log('External transaction token received; send it to your backend without logging it.');
|
|
514
611
|
*
|
|
515
612
|
* // Process payment through your external payment system
|
|
516
613
|
* await processExternalPayment();
|
|
@@ -545,15 +642,6 @@ const developerProvidedBillingNativeHandler: NitroDeveloperProvidedBillingListen
|
|
|
545
642
|
}
|
|
546
643
|
};
|
|
547
644
|
|
|
548
|
-
export interface DeveloperProvidedBillingDetailsAndroid {
|
|
549
|
-
/**
|
|
550
|
-
* External transaction token used to report transactions made through developer billing.
|
|
551
|
-
* This token must be used when reporting the external transaction to Google Play.
|
|
552
|
-
* Must be reported within 24 hours of the transaction.
|
|
553
|
-
*/
|
|
554
|
-
externalTransactionToken: string;
|
|
555
|
-
}
|
|
556
|
-
|
|
557
645
|
export const developerProvidedBillingListenerAndroid = (
|
|
558
646
|
listener: (details: DeveloperProvidedBillingDetailsAndroid) => void,
|
|
559
647
|
): EventSubscription => {
|
|
@@ -619,7 +707,9 @@ type NitroSubscriptionBillingIssueListener = Parameters<
|
|
|
619
707
|
RnIap['addSubscriptionBillingIssueListener']
|
|
620
708
|
>[0];
|
|
621
709
|
|
|
622
|
-
const subscriptionBillingIssueJsListeners = new Set<
|
|
710
|
+
const subscriptionBillingIssueJsListeners = new Set<
|
|
711
|
+
(purchase: Purchase) => void
|
|
712
|
+
>();
|
|
623
713
|
let subscriptionBillingIssueNativeAttached = false;
|
|
624
714
|
const subscriptionBillingIssueNativeHandler: NitroSubscriptionBillingIssueListener =
|
|
625
715
|
(nitroPurchase) => {
|
|
@@ -707,7 +797,7 @@ export const subscriptionBillingIssueListener = (
|
|
|
707
797
|
* @remarks This is a regular promise-based call. Don't confuse with `request*` APIs
|
|
708
798
|
* (`requestPurchase`), which are event-based.
|
|
709
799
|
*
|
|
710
|
-
* @see {@link https://
|
|
800
|
+
* @see {@link https://openiap.dev/docs/apis/fetch-products}
|
|
711
801
|
*/
|
|
712
802
|
export const fetchProducts: QueryField<'fetchProducts'> = async (request) => {
|
|
713
803
|
const {skus, type} = request;
|
|
@@ -849,7 +939,7 @@ export const fetchProducts: QueryField<'fetchProducts'> = async (request) => {
|
|
|
849
939
|
* }
|
|
850
940
|
* ```
|
|
851
941
|
*
|
|
852
|
-
* @see {@link https://
|
|
942
|
+
* @see {@link https://openiap.dev/docs/apis/get-available-purchases}
|
|
853
943
|
*/
|
|
854
944
|
export const getAvailablePurchases: QueryField<
|
|
855
945
|
'getAvailablePurchases'
|
|
@@ -904,7 +994,7 @@ export const getAvailablePurchases: QueryField<
|
|
|
904
994
|
|
|
905
995
|
return validPurchases.map(convertNitroPurchaseToPurchase);
|
|
906
996
|
} else {
|
|
907
|
-
throw
|
|
997
|
+
throw unsupportedPlatformError();
|
|
908
998
|
}
|
|
909
999
|
} catch (error) {
|
|
910
1000
|
RnIapConsole.error('Failed to get available purchases:', error);
|
|
@@ -917,7 +1007,7 @@ export const getAvailablePurchases: QueryField<
|
|
|
917
1007
|
* @returns Promise<Product | null> - The promoted product or null if none available
|
|
918
1008
|
* @platform iOS
|
|
919
1009
|
*
|
|
920
|
-
* @see {@link https://
|
|
1010
|
+
* @see {@link https://openiap.dev/docs/apis/ios/get-promoted-product-ios}
|
|
921
1011
|
*/
|
|
922
1012
|
export const getPromotedProductIOS: QueryField<
|
|
923
1013
|
'getPromotedProductIOS'
|
|
@@ -961,7 +1051,7 @@ export const requestPromotedProductIOS = getPromotedProductIOS;
|
|
|
961
1051
|
* console.log('User storefront:', storefront); // e.g., 'USA', 'GBR', 'KOR'
|
|
962
1052
|
* ```
|
|
963
1053
|
*
|
|
964
|
-
* @see {@link https://
|
|
1054
|
+
* @see {@link https://openiap.dev/docs/apis/ios/get-storefront-ios}
|
|
965
1055
|
*/
|
|
966
1056
|
export const getStorefrontIOS: QueryField<'getStorefrontIOS'> = async () => {
|
|
967
1057
|
if (Platform.OS !== 'ios') {
|
|
@@ -980,7 +1070,7 @@ export const getStorefrontIOS: QueryField<'getStorefrontIOS'> = async () => {
|
|
|
980
1070
|
/**
|
|
981
1071
|
* Return the user's storefront country code.
|
|
982
1072
|
*
|
|
983
|
-
* @see {@link https://
|
|
1073
|
+
* @see {@link https://openiap.dev/docs/apis/get-storefront}
|
|
984
1074
|
*/
|
|
985
1075
|
export const getStorefront: QueryField<'getStorefront'> = async () => {
|
|
986
1076
|
if (Platform.OS !== 'ios' && Platform.OS !== 'android') {
|
|
@@ -1034,7 +1124,7 @@ export const getStorefront: QueryField<'getStorefront'> = async () => {
|
|
|
1034
1124
|
* }
|
|
1035
1125
|
* ```
|
|
1036
1126
|
*
|
|
1037
|
-
* @see {@link https://
|
|
1127
|
+
* @see {@link https://openiap.dev/docs/apis/ios/get-app-transaction-ios}
|
|
1038
1128
|
*/
|
|
1039
1129
|
export const getAppTransactionIOS: QueryField<
|
|
1040
1130
|
'getAppTransactionIOS'
|
|
@@ -1075,7 +1165,7 @@ export const getAppTransactionIOS: QueryField<
|
|
|
1075
1165
|
* @throws Error when called on non-iOS platforms or when IAP is not initialized
|
|
1076
1166
|
* @platform iOS
|
|
1077
1167
|
*
|
|
1078
|
-
* @see {@link https://
|
|
1168
|
+
* @see {@link https://openiap.dev/docs/apis/ios/subscription-status-ios}
|
|
1079
1169
|
*/
|
|
1080
1170
|
export const subscriptionStatusIOS: QueryField<
|
|
1081
1171
|
'subscriptionStatusIOS'
|
|
@@ -1108,7 +1198,7 @@ export const subscriptionStatusIOS: QueryField<
|
|
|
1108
1198
|
* @returns Promise<Purchase | null> - Current entitlement or null
|
|
1109
1199
|
* @platform iOS
|
|
1110
1200
|
*
|
|
1111
|
-
* @see {@link https://
|
|
1201
|
+
* @see {@link https://openiap.dev/docs/apis/ios/current-entitlement-ios}
|
|
1112
1202
|
*/
|
|
1113
1203
|
export const currentEntitlementIOS: QueryField<
|
|
1114
1204
|
'currentEntitlementIOS'
|
|
@@ -1142,7 +1232,7 @@ export const currentEntitlementIOS: QueryField<
|
|
|
1142
1232
|
* @returns Promise<Purchase | null> - Latest transaction or null
|
|
1143
1233
|
* @platform iOS
|
|
1144
1234
|
*
|
|
1145
|
-
* @see {@link https://
|
|
1235
|
+
* @see {@link https://openiap.dev/docs/apis/ios/latest-transaction-ios}
|
|
1146
1236
|
*/
|
|
1147
1237
|
export const latestTransactionIOS: QueryField<'latestTransactionIOS'> = async (
|
|
1148
1238
|
sku,
|
|
@@ -1175,7 +1265,7 @@ export const latestTransactionIOS: QueryField<'latestTransactionIOS'> = async (
|
|
|
1175
1265
|
* @returns Promise<Purchase[]> - Array of pending transactions
|
|
1176
1266
|
* @platform iOS
|
|
1177
1267
|
*
|
|
1178
|
-
* @see {@link https://
|
|
1268
|
+
* @see {@link https://openiap.dev/docs/apis/ios/get-pending-transactions-ios}
|
|
1179
1269
|
*/
|
|
1180
1270
|
export const getPendingTransactionsIOS: QueryField<
|
|
1181
1271
|
'getPendingTransactionsIOS'
|
|
@@ -1206,7 +1296,7 @@ export const getPendingTransactionsIOS: QueryField<
|
|
|
1206
1296
|
/**
|
|
1207
1297
|
* List every StoreKit transaction (finished + unfinished) for the current user.
|
|
1208
1298
|
*
|
|
1209
|
-
* @see {@link https://
|
|
1299
|
+
* @see {@link https://openiap.dev/docs/apis/ios/get-all-transactions-ios}
|
|
1210
1300
|
*/
|
|
1211
1301
|
export const getAllTransactionsIOS: QueryField<
|
|
1212
1302
|
'getAllTransactionsIOS'
|
|
@@ -1239,7 +1329,7 @@ export const getAllTransactionsIOS: QueryField<
|
|
|
1239
1329
|
* @returns Promise<Purchase[]> - Subscriptions where auto-renewal status changed
|
|
1240
1330
|
* @platform iOS
|
|
1241
1331
|
*
|
|
1242
|
-
* @see {@link https://
|
|
1332
|
+
* @see {@link https://openiap.dev/docs/apis/ios/show-manage-subscriptions-ios}
|
|
1243
1333
|
*/
|
|
1244
1334
|
export const showManageSubscriptionsIOS: MutationField<
|
|
1245
1335
|
'showManageSubscriptionsIOS'
|
|
@@ -1273,7 +1363,7 @@ export const showManageSubscriptionsIOS: MutationField<
|
|
|
1273
1363
|
* @returns Promise<boolean> - Eligibility status
|
|
1274
1364
|
* @platform iOS
|
|
1275
1365
|
*
|
|
1276
|
-
* @see {@link https://
|
|
1366
|
+
* @see {@link https://openiap.dev/docs/apis/ios/is-eligible-for-intro-offer-ios}
|
|
1277
1367
|
*/
|
|
1278
1368
|
export const isEligibleForIntroOfferIOS: QueryField<
|
|
1279
1369
|
'isEligibleForIntroOfferIOS'
|
|
@@ -1301,7 +1391,7 @@ export const isEligibleForIntroOfferIOS: QueryField<
|
|
|
1301
1391
|
* @returns Promise<string> - Base64 encoded receipt data
|
|
1302
1392
|
* @platform iOS
|
|
1303
1393
|
*
|
|
1304
|
-
* @see {@link https://
|
|
1394
|
+
* @see {@link https://openiap.dev/docs/apis/ios/get-receipt-data-ios}
|
|
1305
1395
|
*/
|
|
1306
1396
|
export const getReceiptDataIOS: QueryField<'getReceiptDataIOS'> = async () => {
|
|
1307
1397
|
if (Platform.OS !== 'ios') {
|
|
@@ -1390,7 +1480,7 @@ export const requestReceiptRefreshIOS = async (): Promise<string> => {
|
|
|
1390
1480
|
* @returns Promise<boolean> - Verification status
|
|
1391
1481
|
* @platform iOS
|
|
1392
1482
|
*
|
|
1393
|
-
* @see {@link https://
|
|
1483
|
+
* @see {@link https://openiap.dev/docs/apis/ios/is-transaction-verified-ios}
|
|
1394
1484
|
*/
|
|
1395
1485
|
export const isTransactionVerifiedIOS: QueryField<
|
|
1396
1486
|
'isTransactionVerifiedIOS'
|
|
@@ -1419,7 +1509,7 @@ export const isTransactionVerifiedIOS: QueryField<
|
|
|
1419
1509
|
* @returns Promise<string | null> - JWS representation or null
|
|
1420
1510
|
* @platform iOS
|
|
1421
1511
|
*
|
|
1422
|
-
* @see {@link https://
|
|
1512
|
+
* @see {@link https://openiap.dev/docs/apis/ios/get-transaction-jws-ios}
|
|
1423
1513
|
*/
|
|
1424
1514
|
export const getTransactionJwsIOS: QueryField<'getTransactionJwsIOS'> = async (
|
|
1425
1515
|
sku,
|
|
@@ -1463,7 +1553,7 @@ export const getTransactionJwsIOS: QueryField<'getTransactionJwsIOS'> = async (
|
|
|
1463
1553
|
* @remarks When using `useIAP()`, connection is auto-managed on mount/unmount —
|
|
1464
1554
|
* pass options to the hook instead of calling this directly.
|
|
1465
1555
|
*
|
|
1466
|
-
* @see {@link https://
|
|
1556
|
+
* @see {@link https://openiap.dev/docs/apis/init-connection}
|
|
1467
1557
|
*/
|
|
1468
1558
|
export const initConnection: MutationField<'initConnection'> = async (
|
|
1469
1559
|
config,
|
|
@@ -1487,7 +1577,7 @@ export const initConnection: MutationField<'initConnection'> = async (
|
|
|
1487
1577
|
/**
|
|
1488
1578
|
* Close the store connection and release resources.
|
|
1489
1579
|
*
|
|
1490
|
-
* @see {@link https://
|
|
1580
|
+
* @see {@link https://openiap.dev/docs/apis/end-connection}
|
|
1491
1581
|
*/
|
|
1492
1582
|
export const endConnection: MutationField<'endConnection'> = async () => {
|
|
1493
1583
|
try {
|
|
@@ -1510,7 +1600,7 @@ export const endConnection: MutationField<'endConnection'> = async () => {
|
|
|
1510
1600
|
/**
|
|
1511
1601
|
* Restore non-consumable and active subscription purchases.
|
|
1512
1602
|
*
|
|
1513
|
-
* @see {@link https://
|
|
1603
|
+
* @see {@link https://openiap.dev/docs/apis/restore-purchases}
|
|
1514
1604
|
*/
|
|
1515
1605
|
export const restorePurchases: MutationField<'restorePurchases'> = async () => {
|
|
1516
1606
|
try {
|
|
@@ -1558,7 +1648,7 @@ export const restorePurchases: MutationField<'restorePurchases'> = async () => {
|
|
|
1558
1648
|
* @remarks Event-based. Listen for the result via {@link purchaseUpdatedListener} /
|
|
1559
1649
|
* {@link purchaseErrorListener}, or use `useIAP({ onPurchaseSuccess, onPurchaseError })`.
|
|
1560
1650
|
*
|
|
1561
|
-
* @see {@link https://
|
|
1651
|
+
* @see {@link https://openiap.dev/docs/apis/request-purchase}
|
|
1562
1652
|
*/
|
|
1563
1653
|
export const requestPurchase: MutationField<'requestPurchase'> = async (
|
|
1564
1654
|
request,
|
|
@@ -1594,7 +1684,7 @@ export const requestPurchase: MutationField<'requestPurchase'> = async (
|
|
|
1594
1684
|
);
|
|
1595
1685
|
}
|
|
1596
1686
|
} else {
|
|
1597
|
-
throw
|
|
1687
|
+
throw unsupportedPlatformError();
|
|
1598
1688
|
}
|
|
1599
1689
|
|
|
1600
1690
|
const unifiedRequest: NitroPurchaseRequest = {};
|
|
@@ -1629,6 +1719,22 @@ export const requestPurchase: MutationField<'requestPurchase'> = async (
|
|
|
1629
1719
|
if (iosRequest.advancedCommerceData) {
|
|
1630
1720
|
iosPayload.advancedCommerceData = iosRequest.advancedCommerceData;
|
|
1631
1721
|
}
|
|
1722
|
+
if (isSubs) {
|
|
1723
|
+
const subscriptionRequest = iosRequest as RequestSubscriptionIosProps;
|
|
1724
|
+
if (
|
|
1725
|
+
subscriptionRequest.introductoryOfferEligibility !== undefined
|
|
1726
|
+
) {
|
|
1727
|
+
iosPayload.introductoryOfferEligibility =
|
|
1728
|
+
subscriptionRequest.introductoryOfferEligibility;
|
|
1729
|
+
}
|
|
1730
|
+
if (subscriptionRequest.promotionalOfferJWS) {
|
|
1731
|
+
iosPayload.promotionalOfferJWS =
|
|
1732
|
+
subscriptionRequest.promotionalOfferJWS;
|
|
1733
|
+
}
|
|
1734
|
+
if (subscriptionRequest.winBackOffer) {
|
|
1735
|
+
iosPayload.winBackOffer = subscriptionRequest.winBackOffer;
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1632
1738
|
|
|
1633
1739
|
unifiedRequest.ios = iosPayload;
|
|
1634
1740
|
}
|
|
@@ -1726,7 +1832,7 @@ export const requestPurchase: MutationField<'requestPurchase'> = async (
|
|
|
1726
1832
|
* @remarks **Critical:** Android purchases must be finalized within 3 days or Google
|
|
1727
1833
|
* auto-refunds. iOS unfinished transactions replay on every app launch.
|
|
1728
1834
|
*
|
|
1729
|
-
* @see {@link https://
|
|
1835
|
+
* @see {@link https://openiap.dev/docs/apis/finish-transaction}
|
|
1730
1836
|
*/
|
|
1731
1837
|
export const finishTransaction: MutationField<'finishTransaction'> = async (
|
|
1732
1838
|
args,
|
|
@@ -1757,7 +1863,7 @@ export const finishTransaction: MutationField<'finishTransaction'> = async (
|
|
|
1757
1863
|
},
|
|
1758
1864
|
};
|
|
1759
1865
|
} else {
|
|
1760
|
-
throw
|
|
1866
|
+
throw unsupportedPlatformError();
|
|
1761
1867
|
}
|
|
1762
1868
|
|
|
1763
1869
|
const result = await IAP.instance.finishTransaction(params);
|
|
@@ -1795,7 +1901,7 @@ export const finishTransaction: MutationField<'finishTransaction'> = async (
|
|
|
1795
1901
|
* await acknowledgePurchaseAndroid('purchase_token_here');
|
|
1796
1902
|
* ```
|
|
1797
1903
|
*
|
|
1798
|
-
* @see {@link https://
|
|
1904
|
+
* @see {@link https://openiap.dev/docs/apis/android/acknowledge-purchase-android}
|
|
1799
1905
|
*/
|
|
1800
1906
|
export const acknowledgePurchaseAndroid: MutationField<
|
|
1801
1907
|
'acknowledgePurchaseAndroid'
|
|
@@ -1836,7 +1942,7 @@ export const acknowledgePurchaseAndroid: MutationField<
|
|
|
1836
1942
|
* await consumePurchaseAndroid('purchase_token_here');
|
|
1837
1943
|
* ```
|
|
1838
1944
|
*
|
|
1839
|
-
* @see {@link https://
|
|
1945
|
+
* @see {@link https://openiap.dev/docs/apis/android/consume-purchase-android}
|
|
1840
1946
|
*/
|
|
1841
1947
|
export const consumePurchaseAndroid: MutationField<
|
|
1842
1948
|
'consumePurchaseAndroid'
|
|
@@ -1893,7 +1999,7 @@ export const consumePurchaseAndroid: MutationField<
|
|
|
1893
1999
|
* });
|
|
1894
2000
|
* ```
|
|
1895
2001
|
*
|
|
1896
|
-
* @see {@link https://
|
|
2002
|
+
* @see {@link https://openiap.dev/docs/apis/validate-receipt}
|
|
1897
2003
|
*/
|
|
1898
2004
|
export const validateReceipt: MutationField<'validateReceipt'> = async (
|
|
1899
2005
|
options,
|
|
@@ -2024,7 +2130,7 @@ export const validateReceipt: MutationField<'validateReceipt'> = async (
|
|
|
2024
2130
|
* @param options - Receipt validation options containing the SKU
|
|
2025
2131
|
* @returns Promise resolving to receipt validation result
|
|
2026
2132
|
*
|
|
2027
|
-
* @see {@link https://
|
|
2133
|
+
* @see {@link https://openiap.dev/docs/features/validation#verify-purchase}
|
|
2028
2134
|
*/
|
|
2029
2135
|
export const verifyPurchase: MutationField<'verifyPurchase'> = validateReceipt;
|
|
2030
2136
|
|
|
@@ -2035,7 +2141,7 @@ export const verifyPurchase: MutationField<'verifyPurchase'> = validateReceipt;
|
|
|
2035
2141
|
* consumers who imported `validateReceiptIOS` — which is still declared on the
|
|
2036
2142
|
* OpenIAP Query interface — keep working. Throws on non-iOS platforms.
|
|
2037
2143
|
*
|
|
2038
|
-
* @see {@link https://
|
|
2144
|
+
* @see {@link https://openiap.dev/docs/apis/ios/validate-receipt-ios}
|
|
2039
2145
|
*/
|
|
2040
2146
|
export const validateReceiptIOS: QueryField<'validateReceiptIOS'> = async (
|
|
2041
2147
|
options,
|
|
@@ -2068,7 +2174,7 @@ export const validateReceiptIOS: QueryField<'validateReceiptIOS'> = async (
|
|
|
2068
2174
|
* });
|
|
2069
2175
|
* ```
|
|
2070
2176
|
*
|
|
2071
|
-
* @see {@link https://
|
|
2177
|
+
* @see {@link https://openiap.dev/docs/features/validation#verify-purchase-with-provider}
|
|
2072
2178
|
*/
|
|
2073
2179
|
export const verifyPurchaseWithProvider: MutationField<
|
|
2074
2180
|
'verifyPurchaseWithProvider'
|
|
@@ -2113,7 +2219,7 @@ export const verifyPurchaseWithProvider: MutationField<
|
|
|
2113
2219
|
* @returns Promise<boolean>
|
|
2114
2220
|
* @platform iOS
|
|
2115
2221
|
*
|
|
2116
|
-
* @see {@link https://
|
|
2222
|
+
* @see {@link https://openiap.dev/docs/apis/ios/sync-ios}
|
|
2117
2223
|
*/
|
|
2118
2224
|
export const syncIOS: MutationField<'syncIOS'> = async () => {
|
|
2119
2225
|
if (Platform.OS !== 'ios') {
|
|
@@ -2140,7 +2246,7 @@ export const syncIOS: MutationField<'syncIOS'> = async () => {
|
|
|
2140
2246
|
* @returns Promise<boolean> - Indicates whether the redemption sheet was presented
|
|
2141
2247
|
* @platform iOS
|
|
2142
2248
|
*
|
|
2143
|
-
* @see {@link https://
|
|
2249
|
+
* @see {@link https://openiap.dev/docs/apis/ios/present-code-redemption-sheet-ios}
|
|
2144
2250
|
*/
|
|
2145
2251
|
export const presentCodeRedemptionSheetIOS: MutationField<
|
|
2146
2252
|
'presentCodeRedemptionSheetIOS'
|
|
@@ -2184,7 +2290,7 @@ export const presentCodeRedemptionSheetIOS: MutationField<
|
|
|
2184
2290
|
* @returns Promise<boolean> - true when the request triggers successfully
|
|
2185
2291
|
* @platform iOS
|
|
2186
2292
|
*
|
|
2187
|
-
* @see {@link https://
|
|
2293
|
+
* @see {@link https://openiap.dev/docs/apis/ios/request-purchase-on-promoted-product-ios}
|
|
2188
2294
|
*/
|
|
2189
2295
|
export const requestPurchaseOnPromotedProductIOS =
|
|
2190
2296
|
async (): Promise<boolean> => {
|
|
@@ -2228,7 +2334,7 @@ export const requestPurchaseOnPromotedProductIOS =
|
|
|
2228
2334
|
* @returns Promise<boolean>
|
|
2229
2335
|
* @platform iOS
|
|
2230
2336
|
*
|
|
2231
|
-
* @see {@link https://
|
|
2337
|
+
* @see {@link https://openiap.dev/docs/apis/ios/clear-transaction-ios}
|
|
2232
2338
|
*/
|
|
2233
2339
|
export const clearTransactionIOS: MutationField<
|
|
2234
2340
|
'clearTransactionIOS'
|
|
@@ -2258,7 +2364,7 @@ export const clearTransactionIOS: MutationField<
|
|
|
2258
2364
|
* @returns Promise<string | null> - The refund status or null if not available
|
|
2259
2365
|
* @platform iOS
|
|
2260
2366
|
*
|
|
2261
|
-
* @see {@link https://
|
|
2367
|
+
* @see {@link https://openiap.dev/docs/apis/ios/begin-refund-request-ios}
|
|
2262
2368
|
*/
|
|
2263
2369
|
export const beginRefundRequestIOS: MutationField<
|
|
2264
2370
|
'beginRefundRequestIOS'
|
|
@@ -2286,7 +2392,7 @@ export const beginRefundRequestIOS: MutationField<
|
|
|
2286
2392
|
* Deeplinks to native interface that allows users to manage their subscriptions
|
|
2287
2393
|
* Cross-platform alias aligning with expo-iap
|
|
2288
2394
|
*
|
|
2289
|
-
* @see {@link https://
|
|
2395
|
+
* @see {@link https://openiap.dev/docs/apis/deep-link-to-subscriptions}
|
|
2290
2396
|
*/
|
|
2291
2397
|
export const deepLinkToSubscriptions: MutationField<
|
|
2292
2398
|
'deepLinkToSubscriptions'
|
|
@@ -2301,16 +2407,15 @@ export const deepLinkToSubscriptions: MutationField<
|
|
|
2301
2407
|
return;
|
|
2302
2408
|
}
|
|
2303
2409
|
if (Platform.OS === 'ios') {
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
await IAP.instance.showManageSubscriptionsIOS();
|
|
2309
|
-
}
|
|
2310
|
-
} catch (error) {
|
|
2311
|
-
RnIapConsole.warn('[deepLinkToSubscriptions] Failed on iOS:', error);
|
|
2410
|
+
if (typeof IAP.instance.deepLinkToSubscriptionsIOS === 'function') {
|
|
2411
|
+
await IAP.instance.deepLinkToSubscriptionsIOS();
|
|
2412
|
+
} else {
|
|
2413
|
+
await IAP.instance.showManageSubscriptionsIOS();
|
|
2312
2414
|
}
|
|
2415
|
+
return;
|
|
2313
2416
|
}
|
|
2417
|
+
|
|
2418
|
+
throw unsupportedPlatformError();
|
|
2314
2419
|
};
|
|
2315
2420
|
|
|
2316
2421
|
export const deepLinkToSubscriptionsIOS = async (): Promise<boolean> => {
|
|
@@ -2349,7 +2454,7 @@ export const deepLinkToSubscriptionsIOS = async (): Promise<boolean> => {
|
|
|
2349
2454
|
* @param subscriptionIds - Optional array of subscription IDs to filter by
|
|
2350
2455
|
* @returns Promise<ActiveSubscription[]> - Array of active subscriptions
|
|
2351
2456
|
*
|
|
2352
|
-
* @see {@link https://
|
|
2457
|
+
* @see {@link https://openiap.dev/docs/apis/get-active-subscriptions}
|
|
2353
2458
|
*/
|
|
2354
2459
|
export const getActiveSubscriptions: QueryField<
|
|
2355
2460
|
'getActiveSubscriptions'
|
|
@@ -2375,7 +2480,7 @@ export const getActiveSubscriptions: QueryField<
|
|
|
2375
2480
|
environmentIOS: sub.environmentIOS ?? null,
|
|
2376
2481
|
willExpireSoon: sub.willExpireSoon ?? null,
|
|
2377
2482
|
daysUntilExpirationIOS: sub.daysUntilExpirationIOS ?? null,
|
|
2378
|
-
//
|
|
2483
|
+
// renewalInfoIOS contains subscription lifecycle information on iOS.
|
|
2379
2484
|
renewalInfoIOS: sub.renewalInfoIOS
|
|
2380
2485
|
? {
|
|
2381
2486
|
willAutoRenew: sub.renewalInfoIOS.willAutoRenew ?? false,
|
|
@@ -2418,90 +2523,6 @@ export const getActiveSubscriptions: QueryField<
|
|
|
2418
2523
|
}
|
|
2419
2524
|
};
|
|
2420
2525
|
|
|
2421
|
-
// OLD IMPLEMENTATION - REPLACED WITH NATIVE CALL
|
|
2422
|
-
/*
|
|
2423
|
-
export const getActiveSubscriptions_OLD: QueryField<
|
|
2424
|
-
'getActiveSubscriptions'
|
|
2425
|
-
> = async (subscriptionIds) => {
|
|
2426
|
-
try {
|
|
2427
|
-
// Get all available purchases first
|
|
2428
|
-
const allPurchases = await getAvailablePurchases();
|
|
2429
|
-
|
|
2430
|
-
// For the critical bug fix: this function was previously returning ALL purchases
|
|
2431
|
-
// Now we properly filter for subscriptions only
|
|
2432
|
-
|
|
2433
|
-
// In production with real data, Android subscription filtering is done via platform-specific calls
|
|
2434
|
-
// But for backward compatibility and test support, we also check platform-specific fields
|
|
2435
|
-
|
|
2436
|
-
// Since expirationDateIOS and subscriptionGroupIdIOS are not available in NitroPurchase,
|
|
2437
|
-
// we need to rely on other indicators or assume all purchases are subscriptions
|
|
2438
|
-
// when called from getActiveSubscriptions
|
|
2439
|
-
const purchases = allPurchases;
|
|
2440
|
-
|
|
2441
|
-
// Filter for subscriptions and map to ActiveSubscription format
|
|
2442
|
-
const subscriptions = purchases
|
|
2443
|
-
.filter((purchase) => {
|
|
2444
|
-
// Filter by subscription IDs if provided
|
|
2445
|
-
if (subscriptionIds && subscriptionIds.length > 0) {
|
|
2446
|
-
return subscriptionIds.includes(purchase.productId);
|
|
2447
|
-
}
|
|
2448
|
-
return true;
|
|
2449
|
-
})
|
|
2450
|
-
.map((purchase): ActiveSubscription => {
|
|
2451
|
-
// Safe access to platform-specific fields with type guards
|
|
2452
|
-
const expirationDateIOS =
|
|
2453
|
-
'expirationDateIOS' in purchase
|
|
2454
|
-
? ((purchase as PurchaseIOS).expirationDateIOS ?? null)
|
|
2455
|
-
: null;
|
|
2456
|
-
|
|
2457
|
-
const environmentIOS =
|
|
2458
|
-
'environmentIOS' in purchase
|
|
2459
|
-
? ((purchase as PurchaseIOS).environmentIOS ?? null)
|
|
2460
|
-
: null;
|
|
2461
|
-
|
|
2462
|
-
const autoRenewingAndroid =
|
|
2463
|
-
'autoRenewingAndroid' in purchase || 'isAutoRenewing' in purchase
|
|
2464
|
-
? ((purchase as PurchaseAndroid).autoRenewingAndroid ??
|
|
2465
|
-
(purchase as PurchaseAndroid).isAutoRenewing) // deprecated - use isAutoRenewing instead
|
|
2466
|
-
: null;
|
|
2467
|
-
|
|
2468
|
-
// 🆕 Extract renewalInfoIOS if available
|
|
2469
|
-
const renewalInfoIOS =
|
|
2470
|
-
'renewalInfoIOS' in purchase
|
|
2471
|
-
? ((purchase as PurchaseIOS).renewalInfoIOS ?? null)
|
|
2472
|
-
: null;
|
|
2473
|
-
|
|
2474
|
-
return {
|
|
2475
|
-
productId: purchase.productId,
|
|
2476
|
-
isActive: true, // If it's in availablePurchases, it's active
|
|
2477
|
-
// Backend validation fields - use transactionId ?? id for proper field mapping
|
|
2478
|
-
transactionId: purchase.transactionId ?? purchase.id,
|
|
2479
|
-
purchaseToken: purchase.purchaseToken,
|
|
2480
|
-
transactionDate: purchase.transactionDate,
|
|
2481
|
-
// Platform-specific fields
|
|
2482
|
-
expirationDateIOS,
|
|
2483
|
-
autoRenewingAndroid,
|
|
2484
|
-
environmentIOS,
|
|
2485
|
-
renewalInfoIOS,
|
|
2486
|
-
// Convenience fields
|
|
2487
|
-
willExpireSoon: false, // Would need to calculate based on expiration date
|
|
2488
|
-
daysUntilExpirationIOS:
|
|
2489
|
-
expirationDateIOS != null
|
|
2490
|
-
? Math.ceil(
|
|
2491
|
-
(expirationDateIOS - Date.now()) / (1000 * 60 * 60 * 24),
|
|
2492
|
-
)
|
|
2493
|
-
: null,
|
|
2494
|
-
};
|
|
2495
|
-
});
|
|
2496
|
-
|
|
2497
|
-
return subscriptions;
|
|
2498
|
-
} catch (error) {
|
|
2499
|
-
RnIapConsole.error('Failed to get active subscriptions:', error);
|
|
2500
|
-
const errorJson = parseErrorStringToJsonObj(error);
|
|
2501
|
-
throw new Error(errorJson.message);
|
|
2502
|
-
}
|
|
2503
|
-
};
|
|
2504
|
-
|
|
2505
2526
|
/**
|
|
2506
2527
|
* Check if the user has any active subscriptions (OpenIAP compliant)
|
|
2507
2528
|
* Returns true if the user has at least one active subscription, false otherwise.
|
|
@@ -2510,7 +2531,7 @@ export const getActiveSubscriptions_OLD: QueryField<
|
|
|
2510
2531
|
* @param subscriptionIds - Optional array of subscription IDs to check
|
|
2511
2532
|
* @returns Promise<boolean> - True if there are active subscriptions
|
|
2512
2533
|
*
|
|
2513
|
-
* @see {@link https://
|
|
2534
|
+
* @see {@link https://openiap.dev/docs/apis/has-active-subscriptions}
|
|
2514
2535
|
*/
|
|
2515
2536
|
export const hasActiveSubscriptions: QueryField<
|
|
2516
2537
|
'hasActiveSubscriptions'
|
|
@@ -2639,7 +2660,7 @@ const normalizeProductQueryType = (
|
|
|
2639
2660
|
* }
|
|
2640
2661
|
* ```
|
|
2641
2662
|
*
|
|
2642
|
-
* @see {@link https://
|
|
2663
|
+
* @see {@link https://openiap.dev/docs/apis/android/check-alternative-billing-availability-android}
|
|
2643
2664
|
*/
|
|
2644
2665
|
export const checkAlternativeBillingAvailabilityAndroid: MutationField<
|
|
2645
2666
|
'checkAlternativeBillingAvailabilityAndroid'
|
|
@@ -2681,7 +2702,7 @@ export const checkAlternativeBillingAvailabilityAndroid: MutationField<
|
|
|
2681
2702
|
* }
|
|
2682
2703
|
* ```
|
|
2683
2704
|
*
|
|
2684
|
-
* @see {@link https://
|
|
2705
|
+
* @see {@link https://openiap.dev/docs/apis/android/show-alternative-billing-dialog-android}
|
|
2685
2706
|
*/
|
|
2686
2707
|
export const showAlternativeBillingDialogAndroid: MutationField<
|
|
2687
2708
|
'showAlternativeBillingDialogAndroid'
|
|
@@ -2720,7 +2741,7 @@ export const showAlternativeBillingDialogAndroid: MutationField<
|
|
|
2720
2741
|
* }
|
|
2721
2742
|
* ```
|
|
2722
2743
|
*
|
|
2723
|
-
* @see {@link https://
|
|
2744
|
+
* @see {@link https://openiap.dev/docs/apis/android/create-alternative-billing-token-android}
|
|
2724
2745
|
*/
|
|
2725
2746
|
export const createAlternativeBillingTokenAndroid: MutationField<
|
|
2726
2747
|
'createAlternativeBillingTokenAndroid'
|
|
@@ -2736,40 +2757,6 @@ export const createAlternativeBillingTokenAndroid: MutationField<
|
|
|
2736
2757
|
}
|
|
2737
2758
|
};
|
|
2738
2759
|
|
|
2739
|
-
/**
|
|
2740
|
-
* Parameters for launching an external link (Android 8.2.0+).
|
|
2741
|
-
*/
|
|
2742
|
-
export interface LaunchExternalLinkParamsAndroid {
|
|
2743
|
-
/** The billing program (external-content-link or external-offer) */
|
|
2744
|
-
billingProgram: BillingProgramAndroid;
|
|
2745
|
-
/** The external link launch mode */
|
|
2746
|
-
launchMode: ExternalLinkLaunchModeAndroid;
|
|
2747
|
-
/** The type of the external link */
|
|
2748
|
-
linkType: ExternalLinkTypeAndroid;
|
|
2749
|
-
/** The URI where the content will be accessed from */
|
|
2750
|
-
linkUri: string;
|
|
2751
|
-
}
|
|
2752
|
-
|
|
2753
|
-
/**
|
|
2754
|
-
* Result of checking billing program availability (Android 8.2.0+).
|
|
2755
|
-
*/
|
|
2756
|
-
export interface BillingProgramAvailabilityResultAndroid {
|
|
2757
|
-
/** The billing program that was checked */
|
|
2758
|
-
billingProgram: BillingProgramAndroid;
|
|
2759
|
-
/** Whether the billing program is available for the user */
|
|
2760
|
-
isAvailable: boolean;
|
|
2761
|
-
}
|
|
2762
|
-
|
|
2763
|
-
/**
|
|
2764
|
-
* Reporting details for external transactions (Android 8.2.0+).
|
|
2765
|
-
*/
|
|
2766
|
-
export interface BillingProgramReportingDetailsAndroid {
|
|
2767
|
-
/** The billing program that the reporting details are associated with */
|
|
2768
|
-
billingProgram: BillingProgramAndroid;
|
|
2769
|
-
/** External transaction token used to report transactions to Google */
|
|
2770
|
-
externalTransactionToken: string;
|
|
2771
|
-
}
|
|
2772
|
-
|
|
2773
2760
|
/**
|
|
2774
2761
|
* Enable a billing program before initConnection (Android only).
|
|
2775
2762
|
* Must be called BEFORE initConnection() to configure the BillingClient.
|
|
@@ -2795,7 +2782,7 @@ export const enableBillingProgramAndroid = (
|
|
|
2795
2782
|
return;
|
|
2796
2783
|
}
|
|
2797
2784
|
try {
|
|
2798
|
-
IAP.instance.enableBillingProgramAndroid(program
|
|
2785
|
+
IAP.instance.enableBillingProgramAndroid(program);
|
|
2799
2786
|
} catch (error) {
|
|
2800
2787
|
RnIapConsole.error('Failed to enable billing program:', error);
|
|
2801
2788
|
}
|
|
@@ -2817,7 +2804,7 @@ export const enableBillingProgramAndroid = (
|
|
|
2817
2804
|
* }
|
|
2818
2805
|
* ```
|
|
2819
2806
|
*
|
|
2820
|
-
* @see {@link https://
|
|
2807
|
+
* @see {@link https://openiap.dev/docs/apis/android/is-billing-program-available-android}
|
|
2821
2808
|
*/
|
|
2822
2809
|
export const isBillingProgramAvailableAndroid: MutationField<
|
|
2823
2810
|
'isBillingProgramAvailableAndroid'
|
|
@@ -2826,9 +2813,7 @@ export const isBillingProgramAvailableAndroid: MutationField<
|
|
|
2826
2813
|
throw new Error('Billing Programs API is only supported on Android');
|
|
2827
2814
|
}
|
|
2828
2815
|
try {
|
|
2829
|
-
const result = await IAP.instance.isBillingProgramAvailableAndroid(
|
|
2830
|
-
program as any,
|
|
2831
|
-
);
|
|
2816
|
+
const result = await IAP.instance.isBillingProgramAvailableAndroid(program);
|
|
2832
2817
|
return {
|
|
2833
2818
|
billingProgram: result.billingProgram as unknown as BillingProgramAndroid,
|
|
2834
2819
|
isAvailable: result.isAvailable,
|
|
@@ -2858,7 +2843,7 @@ export const isBillingProgramAvailableAndroid: MutationField<
|
|
|
2858
2843
|
* });
|
|
2859
2844
|
* ```
|
|
2860
2845
|
*
|
|
2861
|
-
* @see {@link https://
|
|
2846
|
+
* @see {@link https://openiap.dev/docs/apis/android/create-billing-program-reporting-details-android}
|
|
2862
2847
|
*/
|
|
2863
2848
|
export const createBillingProgramReportingDetailsAndroid: MutationField<
|
|
2864
2849
|
'createBillingProgramReportingDetailsAndroid'
|
|
@@ -2868,9 +2853,7 @@ export const createBillingProgramReportingDetailsAndroid: MutationField<
|
|
|
2868
2853
|
}
|
|
2869
2854
|
try {
|
|
2870
2855
|
const result =
|
|
2871
|
-
await IAP.instance.createBillingProgramReportingDetailsAndroid(
|
|
2872
|
-
program as any,
|
|
2873
|
-
);
|
|
2856
|
+
await IAP.instance.createBillingProgramReportingDetailsAndroid(program);
|
|
2874
2857
|
return {
|
|
2875
2858
|
billingProgram: result.billingProgram as unknown as BillingProgramAndroid,
|
|
2876
2859
|
externalTransactionToken: result.externalTransactionToken,
|
|
@@ -2905,7 +2888,7 @@ export const createBillingProgramReportingDetailsAndroid: MutationField<
|
|
|
2905
2888
|
* }
|
|
2906
2889
|
* ```
|
|
2907
2890
|
*
|
|
2908
|
-
* @see {@link https://
|
|
2891
|
+
* @see {@link https://openiap.dev/docs/apis/android/launch-external-link-android}
|
|
2909
2892
|
*/
|
|
2910
2893
|
export const launchExternalLinkAndroid: MutationField<
|
|
2911
2894
|
'launchExternalLinkAndroid'
|
|
@@ -2915,9 +2898,9 @@ export const launchExternalLinkAndroid: MutationField<
|
|
|
2915
2898
|
}
|
|
2916
2899
|
try {
|
|
2917
2900
|
return await IAP.instance.launchExternalLinkAndroid({
|
|
2918
|
-
billingProgram: params.billingProgram
|
|
2919
|
-
launchMode: params.launchMode
|
|
2920
|
-
linkType: params.linkType
|
|
2901
|
+
billingProgram: params.billingProgram,
|
|
2902
|
+
launchMode: params.launchMode,
|
|
2903
|
+
linkType: params.linkType,
|
|
2921
2904
|
linkUri: params.linkUri,
|
|
2922
2905
|
});
|
|
2923
2906
|
} catch (error) {
|
|
@@ -2949,7 +2932,7 @@ export const launchExternalLinkAndroid: MutationField<
|
|
|
2949
2932
|
* }
|
|
2950
2933
|
* ```
|
|
2951
2934
|
*
|
|
2952
|
-
* @see {@link https://
|
|
2935
|
+
* @see {@link https://openiap.dev/docs/apis/ios/can-present-external-purchase-notice-ios}
|
|
2953
2936
|
*/
|
|
2954
2937
|
export const canPresentExternalPurchaseNoticeIOS: QueryField<
|
|
2955
2938
|
'canPresentExternalPurchaseNoticeIOS'
|
|
@@ -2984,7 +2967,7 @@ export const canPresentExternalPurchaseNoticeIOS: QueryField<
|
|
|
2984
2967
|
* }
|
|
2985
2968
|
* ```
|
|
2986
2969
|
*
|
|
2987
|
-
* @see {@link https://
|
|
2970
|
+
* @see {@link https://openiap.dev/docs/apis/ios/present-external-purchase-notice-sheet-ios}
|
|
2988
2971
|
*/
|
|
2989
2972
|
export const presentExternalPurchaseNoticeSheetIOS =
|
|
2990
2973
|
async (): Promise<ExternalPurchaseNoticeResultIOS> => {
|
|
@@ -3017,7 +3000,7 @@ export const presentExternalPurchaseNoticeSheetIOS =
|
|
|
3017
3000
|
* }
|
|
3018
3001
|
* ```
|
|
3019
3002
|
*
|
|
3020
|
-
* @see {@link https://
|
|
3003
|
+
* @see {@link https://openiap.dev/docs/apis/ios/present-external-purchase-link-ios}
|
|
3021
3004
|
*/
|
|
3022
3005
|
export const presentExternalPurchaseLinkIOS: MutationField<
|
|
3023
3006
|
'presentExternalPurchaseLinkIOS'
|
|
@@ -3026,7 +3009,7 @@ export const presentExternalPurchaseLinkIOS: MutationField<
|
|
|
3026
3009
|
throw new Error('External purchase is only supported on iOS');
|
|
3027
3010
|
}
|
|
3028
3011
|
try {
|
|
3029
|
-
return
|
|
3012
|
+
return await IAP.instance.presentExternalPurchaseLinkIOS(url);
|
|
3030
3013
|
} catch (error) {
|
|
3031
3014
|
RnIapConsole.error('Failed to present external purchase link:', error);
|
|
3032
3015
|
throw error;
|
|
@@ -3053,7 +3036,7 @@ export const presentExternalPurchaseLinkIOS: MutationField<
|
|
|
3053
3036
|
* }
|
|
3054
3037
|
* ```
|
|
3055
3038
|
*
|
|
3056
|
-
* @see {@link https://
|
|
3039
|
+
* @see {@link https://openiap.dev/docs/apis/ios/is-eligible-for-external-purchase-custom-link-ios}
|
|
3057
3040
|
*/
|
|
3058
3041
|
export const isEligibleForExternalPurchaseCustomLinkIOS =
|
|
3059
3042
|
async (): Promise<boolean> => {
|
|
@@ -3090,7 +3073,7 @@ export const isEligibleForExternalPurchaseCustomLinkIOS =
|
|
|
3090
3073
|
* }
|
|
3091
3074
|
* ```
|
|
3092
3075
|
*
|
|
3093
|
-
* @see {@link https://
|
|
3076
|
+
* @see {@link https://openiap.dev/docs/apis/ios/get-external-purchase-custom-link-token-ios}
|
|
3094
3077
|
*/
|
|
3095
3078
|
export const getExternalPurchaseCustomLinkTokenIOS = async (
|
|
3096
3079
|
tokenType: ExternalPurchaseCustomLinkTokenTypeIOS,
|
|
@@ -3130,7 +3113,7 @@ export const getExternalPurchaseCustomLinkTokenIOS = async (
|
|
|
3130
3113
|
* }
|
|
3131
3114
|
* ```
|
|
3132
3115
|
*
|
|
3133
|
-
* @see {@link https://
|
|
3116
|
+
* @see {@link https://openiap.dev/docs/apis/ios/show-external-purchase-custom-link-notice-ios}
|
|
3134
3117
|
*/
|
|
3135
3118
|
export const showExternalPurchaseCustomLinkNoticeIOS = async (
|
|
3136
3119
|
noticeType: ExternalPurchaseCustomLinkNoticeTypeIOS,
|