react-native-iap 14.3.1 → 14.3.2-rc.2
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/lib/commonjs/index.js +36 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/specs/RnIap.nitro.js +6 -0
- package/lib/commonjs/specs/RnIap.nitro.js.map +1 -0
- package/lib/commonjs/types.js +118 -0
- package/lib/commonjs/types.js.map +1 -0
- package/lib/module/index.js +101 -104
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/plugin/src/withIAP.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +2 -1
- package/plugin/build/withIAP.js +68 -1
- package/plugin/src/withIAP.ts +80 -3
- package/plugin/tsconfig.tsbuildinfo +1 -1
- package/src/index.ts +119 -153
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
var _exportNames = {};
|
|
7
|
+
exports.default = void 0;
|
|
8
|
+
var _reactNativeNitroModules = require("react-native-nitro-modules");
|
|
9
|
+
var _RnIap = require("./specs/RnIap.nitro");
|
|
10
|
+
Object.keys(_RnIap).forEach(function (key) {
|
|
11
|
+
if (key === "default" || key === "__esModule") return;
|
|
12
|
+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
|
13
|
+
if (key in exports && exports[key] === _RnIap[key]) return;
|
|
14
|
+
Object.defineProperty(exports, key, {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
get: function () {
|
|
17
|
+
return _RnIap[key];
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
var _types = require("./types");
|
|
22
|
+
Object.keys(_types).forEach(function (key) {
|
|
23
|
+
if (key === "default" || key === "__esModule") return;
|
|
24
|
+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
|
25
|
+
if (key in exports && exports[key] === _types[key]) return;
|
|
26
|
+
Object.defineProperty(exports, key, {
|
|
27
|
+
enumerable: true,
|
|
28
|
+
get: function () {
|
|
29
|
+
return _types[key];
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
// Create and export the RnIap HybridObject directly
|
|
34
|
+
const RnIap = _reactNativeNitroModules.NitroModules.createHybridObject('RnIap');
|
|
35
|
+
var _default = exports.default = RnIap;
|
|
36
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_reactNativeNitroModules","require","_RnIap","Object","keys","forEach","key","prototype","hasOwnProperty","call","_exportNames","exports","defineProperty","enumerable","get","_types","RnIap","NitroModules","createHybridObject","_default","default"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;;;;;;AAAA,IAAAA,wBAAA,GAAAC,OAAA;AAGA,IAAAC,MAAA,GAAAD,OAAA;AAAAE,MAAA,CAAAC,IAAA,CAAAF,MAAA,EAAAG,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAJ,MAAA,CAAAI,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAZ,MAAA,CAAAI,GAAA;IAAA;EAAA;AAAA;AACA,IAAAS,MAAA,GAAAd,OAAA;AAAAE,MAAA,CAAAC,IAAA,CAAAW,MAAA,EAAAV,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAS,MAAA,CAAAT,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAC,MAAA,CAAAT,GAAA;IAAA;EAAA;AAAA;AAEA;AACA,MAAMU,KAAK,GAAGC,qCAAY,CAACC,kBAAkB,CAAY,OAAO,CAAC;AAAA,IAAAC,QAAA,GAAAR,OAAA,CAAAS,OAAA,GAElDJ,KAAK","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"commonjs"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sourceRoot":"../../../src","sources":["specs/RnIap.nitro.ts"],"mappings":"","ignoreList":[]}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.PurchaseAndroidState = exports.ErrorCode = void 0;
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// CORE TYPES
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// COMMON TYPES (Base types shared across all platforms)
|
|
12
|
+
// ============================================================================
|
|
13
|
+
/**
|
|
14
|
+
* Base product information shared across all platforms
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Base purchase information shared across all platforms
|
|
18
|
+
* Represents both consumables, non-consumables, and subscriptions
|
|
19
|
+
*/
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// PLATFORM TYPES
|
|
22
|
+
// ============================================================================
|
|
23
|
+
// ============================================================================
|
|
24
|
+
// IOS TYPES
|
|
25
|
+
// ============================================================================
|
|
26
|
+
// ============================================================================
|
|
27
|
+
// ANDROID TYPES
|
|
28
|
+
// ============================================================================
|
|
29
|
+
let PurchaseAndroidState = exports.PurchaseAndroidState = /*#__PURE__*/function (PurchaseAndroidState) {
|
|
30
|
+
PurchaseAndroidState[PurchaseAndroidState["UNSPECIFIED_STATE"] = 0] = "UNSPECIFIED_STATE";
|
|
31
|
+
PurchaseAndroidState[PurchaseAndroidState["PURCHASED"] = 1] = "PURCHASED";
|
|
32
|
+
PurchaseAndroidState[PurchaseAndroidState["PENDING"] = 2] = "PENDING";
|
|
33
|
+
return PurchaseAndroidState;
|
|
34
|
+
}({}); // ============================================================================
|
|
35
|
+
// TYPE ALIASES
|
|
36
|
+
// ============================================================================
|
|
37
|
+
// Legacy naming for backward compatibility
|
|
38
|
+
// Legacy naming for backward compatibility
|
|
39
|
+
// ============================================================================
|
|
40
|
+
// UNION TYPES
|
|
41
|
+
// ============================================================================
|
|
42
|
+
// Product Union Types
|
|
43
|
+
// Purchase Union Types
|
|
44
|
+
/**
|
|
45
|
+
* Regular product purchase (consumable or non-consumable)
|
|
46
|
+
* Both types appear in getAvailablePurchases until finishTransaction is called
|
|
47
|
+
*/
|
|
48
|
+
/**
|
|
49
|
+
* Active subscription purchase
|
|
50
|
+
* Appears in getAvailablePurchases while subscription is active
|
|
51
|
+
*/
|
|
52
|
+
/**
|
|
53
|
+
* Combined purchase type that includes all purchase types
|
|
54
|
+
* Used as return type for getAvailablePurchases
|
|
55
|
+
*/
|
|
56
|
+
// ============================================================================
|
|
57
|
+
// REQUEST TYPES
|
|
58
|
+
// ============================================================================
|
|
59
|
+
// iOS-specific purchase request parameters
|
|
60
|
+
// Android-specific purchase request parameters
|
|
61
|
+
// Android-specific subscription request parameters
|
|
62
|
+
// Platform-specific request structures
|
|
63
|
+
// Modern request types (v2.7.0+)
|
|
64
|
+
// ============================================================================
|
|
65
|
+
// ERROR TYPES
|
|
66
|
+
// ============================================================================
|
|
67
|
+
let ErrorCode = exports.ErrorCode = /*#__PURE__*/function (ErrorCode) {
|
|
68
|
+
ErrorCode["E_UNKNOWN"] = "E_UNKNOWN";
|
|
69
|
+
ErrorCode["E_USER_CANCELLED"] = "E_USER_CANCELLED";
|
|
70
|
+
ErrorCode["E_USER_ERROR"] = "E_USER_ERROR";
|
|
71
|
+
ErrorCode["E_ITEM_UNAVAILABLE"] = "E_ITEM_UNAVAILABLE";
|
|
72
|
+
ErrorCode["E_REMOTE_ERROR"] = "E_REMOTE_ERROR";
|
|
73
|
+
ErrorCode["E_NETWORK_ERROR"] = "E_NETWORK_ERROR";
|
|
74
|
+
ErrorCode["E_SERVICE_ERROR"] = "E_SERVICE_ERROR";
|
|
75
|
+
ErrorCode["E_RECEIPT_FAILED"] = "E_RECEIPT_FAILED";
|
|
76
|
+
ErrorCode["E_RECEIPT_FINISHED_FAILED"] = "E_RECEIPT_FINISHED_FAILED";
|
|
77
|
+
ErrorCode["E_NOT_PREPARED"] = "E_NOT_PREPARED";
|
|
78
|
+
ErrorCode["E_NOT_ENDED"] = "E_NOT_ENDED";
|
|
79
|
+
ErrorCode["E_ALREADY_OWNED"] = "E_ALREADY_OWNED";
|
|
80
|
+
ErrorCode["E_DEVELOPER_ERROR"] = "E_DEVELOPER_ERROR";
|
|
81
|
+
ErrorCode["E_BILLING_RESPONSE_JSON_PARSE_ERROR"] = "E_BILLING_RESPONSE_JSON_PARSE_ERROR";
|
|
82
|
+
ErrorCode["E_DEFERRED_PAYMENT"] = "E_DEFERRED_PAYMENT";
|
|
83
|
+
ErrorCode["E_INTERRUPTED"] = "E_INTERRUPTED";
|
|
84
|
+
ErrorCode["E_IAP_NOT_AVAILABLE"] = "E_IAP_NOT_AVAILABLE";
|
|
85
|
+
ErrorCode["E_PURCHASE_ERROR"] = "E_PURCHASE_ERROR";
|
|
86
|
+
ErrorCode["E_SYNC_ERROR"] = "E_SYNC_ERROR";
|
|
87
|
+
ErrorCode["E_TRANSACTION_VALIDATION_FAILED"] = "E_TRANSACTION_VALIDATION_FAILED";
|
|
88
|
+
ErrorCode["E_ACTIVITY_UNAVAILABLE"] = "E_ACTIVITY_UNAVAILABLE";
|
|
89
|
+
ErrorCode["E_ALREADY_PREPARED"] = "E_ALREADY_PREPARED";
|
|
90
|
+
ErrorCode["E_PENDING"] = "E_PENDING";
|
|
91
|
+
ErrorCode["E_CONNECTION_CLOSED"] = "E_CONNECTION_CLOSED";
|
|
92
|
+
return ErrorCode;
|
|
93
|
+
}({}); // Additional iOS types
|
|
94
|
+
// ============================================================================
|
|
95
|
+
// METHOD OPTIONS TYPES
|
|
96
|
+
// ============================================================================
|
|
97
|
+
/**
|
|
98
|
+
* Options for getAvailablePurchases and getPurchaseHistories methods
|
|
99
|
+
*/
|
|
100
|
+
/**
|
|
101
|
+
* Parameters for finishTransaction method
|
|
102
|
+
*/
|
|
103
|
+
// ============================================================================
|
|
104
|
+
// IAP CONTEXT INTERFACE
|
|
105
|
+
// ============================================================================
|
|
106
|
+
/**
|
|
107
|
+
* Main IAP context interface providing all in-app purchase functionality
|
|
108
|
+
*/
|
|
109
|
+
/**
|
|
110
|
+
* Purchase error type
|
|
111
|
+
*/
|
|
112
|
+
/**
|
|
113
|
+
* Validation options for receipt validation
|
|
114
|
+
*/
|
|
115
|
+
/**
|
|
116
|
+
* Validation result from receipt validation
|
|
117
|
+
*/
|
|
118
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["PurchaseAndroidState","exports","ErrorCode"],"sourceRoot":"../../src","sources":["types.ts"],"mappings":";;;;;;AAAA;AACA;AACA;AAQA;AACA;AACA;AAEA;AACA;AACA;AAwBA;AACA;AACA;AACA;AAwBA;AACA;AACA;AAKA;AACA;AACA;AAyGA;AACA;AACA;AAAA,IAsDYA,oBAAoB,GAAAC,OAAA,CAAAD,oBAAA,0BAApBA,oBAAoB;EAApBA,oBAAoB,CAApBA,oBAAoB;EAApBA,oBAAoB,CAApBA,oBAAoB;EAApBA,oBAAoB,CAApBA,oBAAoB;EAAA,OAApBA,oBAAoB;AAAA,OAuBhC;AACA;AACA;AAEA;AAIA;AAIA;AACA;AACA;AAEA;AASA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AAKA;AACA;AACA;AAEA;AASA;AAQA;AAWA;AAWA;AAIA;AACA;AACA;AAAA,IAEYE,SAAS,GAAAD,OAAA,CAAAC,SAAA,0BAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAAA,OAATA,SAAS;AAAA,OAuCrB;AAyBA;AACA;AACA;AAEA;AACA;AACA;AAQA;AACA;AACA;AAeA;AACA;AACA;AAEA;AACA;AACA;AAkFA;AACA;AACA;AAUA;AACA;AACA;AAmBA;AACA;AACA","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -38,15 +38,29 @@ export const restorePurchases = async (options = {
|
|
|
38
38
|
|
|
39
39
|
// Development utilities removed - use type bridge functions directly if needed
|
|
40
40
|
|
|
41
|
-
// Create the RnIap HybridObject instance
|
|
42
|
-
|
|
41
|
+
// Create the RnIap HybridObject instance lazily to avoid early JSI crashes
|
|
42
|
+
let iapRef = null;
|
|
43
|
+
const IAP = {
|
|
44
|
+
get instance() {
|
|
45
|
+
if (iapRef) return iapRef;
|
|
46
|
+
|
|
47
|
+
// Guard against accessing Nitro before it's installed into the JS runtime
|
|
48
|
+
const hasNitroDispatcher = typeof globalThis !== 'undefined' && globalThis?.__nitro?.dispatcher != null;
|
|
49
|
+
const isJestEnvironment = typeof globalThis.jest !== 'undefined' || typeof process !== 'undefined' && !!process.env && process.env.JEST_WORKER_ID != null;
|
|
50
|
+
if (!hasNitroDispatcher && !isJestEnvironment) {
|
|
51
|
+
throw new Error('Nitro runtime not installed yet. Ensure react-native-nitro-modules is initialized before calling IAP.');
|
|
52
|
+
}
|
|
53
|
+
iapRef = NitroModules.createHybridObject('RnIap');
|
|
54
|
+
return iapRef;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
43
57
|
|
|
44
58
|
/**
|
|
45
59
|
* Initialize connection to the store
|
|
46
60
|
*/
|
|
47
61
|
export const initConnection = async () => {
|
|
48
62
|
try {
|
|
49
|
-
return await
|
|
63
|
+
return await IAP.instance.initConnection();
|
|
50
64
|
} catch (error) {
|
|
51
65
|
console.error('Failed to initialize IAP connection:', error);
|
|
52
66
|
throw error;
|
|
@@ -58,7 +72,9 @@ export const initConnection = async () => {
|
|
|
58
72
|
*/
|
|
59
73
|
export const endConnection = async () => {
|
|
60
74
|
try {
|
|
61
|
-
|
|
75
|
+
// If never initialized, treat as ended
|
|
76
|
+
if (!iapRef) return true;
|
|
77
|
+
return await IAP.instance.endConnection();
|
|
62
78
|
} catch (error) {
|
|
63
79
|
console.error('Failed to end IAP connection:', error);
|
|
64
80
|
throw error;
|
|
@@ -90,7 +106,7 @@ export const fetchProducts = async ({
|
|
|
90
106
|
throw new Error('No SKUs provided');
|
|
91
107
|
}
|
|
92
108
|
if (type === 'all') {
|
|
93
|
-
const [inappNitro, subsNitro] = await Promise.all([
|
|
109
|
+
const [inappNitro, subsNitro] = await Promise.all([IAP.instance.fetchProducts(skus, 'inapp'), IAP.instance.fetchProducts(skus, 'subs')]);
|
|
94
110
|
const allNitro = [...inappNitro, ...subsNitro];
|
|
95
111
|
const validAll = allNitro.filter(validateNitroProduct);
|
|
96
112
|
if (validAll.length !== allNitro.length) {
|
|
@@ -98,7 +114,7 @@ export const fetchProducts = async ({
|
|
|
98
114
|
}
|
|
99
115
|
return validAll.map(convertNitroProductToProduct);
|
|
100
116
|
}
|
|
101
|
-
const nitroProducts = await
|
|
117
|
+
const nitroProducts = await IAP.instance.fetchProducts(skus, type);
|
|
102
118
|
|
|
103
119
|
// Validate and convert NitroProducts to TypeScript Products
|
|
104
120
|
const validProducts = nitroProducts.filter(validateNitroProduct);
|
|
@@ -197,7 +213,7 @@ export const requestPurchase = async ({
|
|
|
197
213
|
}
|
|
198
214
|
|
|
199
215
|
// Call unified method - returns void, listen for events instead
|
|
200
|
-
await
|
|
216
|
+
await IAP.instance.requestPurchase(unifiedRequest);
|
|
201
217
|
} catch (error) {
|
|
202
218
|
console.error('Failed to request purchase:', error);
|
|
203
219
|
throw error;
|
|
@@ -234,12 +250,12 @@ export const getAvailablePurchases = async ({
|
|
|
234
250
|
};
|
|
235
251
|
} else if (Platform.OS === 'android') {
|
|
236
252
|
// For Android, we need to call twice for inapp and subs
|
|
237
|
-
const inappNitroPurchases = await
|
|
253
|
+
const inappNitroPurchases = await IAP.instance.getAvailablePurchases({
|
|
238
254
|
android: {
|
|
239
255
|
type: 'inapp'
|
|
240
256
|
}
|
|
241
257
|
});
|
|
242
|
-
const subsNitroPurchases = await
|
|
258
|
+
const subsNitroPurchases = await IAP.instance.getAvailablePurchases({
|
|
243
259
|
android: {
|
|
244
260
|
type: 'subs'
|
|
245
261
|
}
|
|
@@ -255,7 +271,7 @@ export const getAvailablePurchases = async ({
|
|
|
255
271
|
} else {
|
|
256
272
|
throw new Error('Unsupported platform');
|
|
257
273
|
}
|
|
258
|
-
const nitroPurchases = await
|
|
274
|
+
const nitroPurchases = await IAP.instance.getAvailablePurchases(options);
|
|
259
275
|
|
|
260
276
|
// Validate and convert NitroPurchases to TypeScript Purchases
|
|
261
277
|
const validPurchases = nitroPurchases.filter(validateNitroPurchase);
|
|
@@ -310,7 +326,7 @@ export const finishTransaction = async ({
|
|
|
310
326
|
} else {
|
|
311
327
|
throw new Error('Unsupported platform');
|
|
312
328
|
}
|
|
313
|
-
const result = await
|
|
329
|
+
const result = await IAP.instance.finishTransaction(params);
|
|
314
330
|
|
|
315
331
|
// Handle variant return type
|
|
316
332
|
if (typeof result === 'boolean') {
|
|
@@ -348,7 +364,7 @@ export const acknowledgePurchaseAndroid = async purchaseToken => {
|
|
|
348
364
|
if (Platform.OS !== 'android') {
|
|
349
365
|
throw new Error('acknowledgePurchaseAndroid is only available on Android');
|
|
350
366
|
}
|
|
351
|
-
const result = await
|
|
367
|
+
const result = await IAP.instance.finishTransaction({
|
|
352
368
|
android: {
|
|
353
369
|
purchaseToken,
|
|
354
370
|
isConsumable: false
|
|
@@ -386,7 +402,7 @@ export const consumePurchaseAndroid = async purchaseToken => {
|
|
|
386
402
|
if (Platform.OS !== 'android') {
|
|
387
403
|
throw new Error('consumePurchaseAndroid is only available on Android');
|
|
388
404
|
}
|
|
389
|
-
const result = await
|
|
405
|
+
const result = await IAP.instance.finishTransaction({
|
|
390
406
|
android: {
|
|
391
407
|
purchaseToken,
|
|
392
408
|
isConsumable: true
|
|
@@ -450,12 +466,27 @@ export const purchaseUpdatedListener = listener => {
|
|
|
450
466
|
|
|
451
467
|
// Store the wrapped listener for removal
|
|
452
468
|
listenerMap.set(listener, wrappedListener);
|
|
453
|
-
|
|
469
|
+
let attached = false;
|
|
470
|
+
try {
|
|
471
|
+
IAP.instance.addPurchaseUpdatedListener(wrappedListener);
|
|
472
|
+
attached = true;
|
|
473
|
+
} catch (e) {
|
|
474
|
+
const msg = String(e ?? '');
|
|
475
|
+
if (msg.includes('Nitro runtime not installed')) {
|
|
476
|
+
console.warn('[purchaseUpdatedListener] Nitro not ready yet; listener inert until initConnection()');
|
|
477
|
+
} else {
|
|
478
|
+
throw e;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
454
481
|
return {
|
|
455
482
|
remove: () => {
|
|
456
483
|
const wrapped = listenerMap.get(listener);
|
|
457
484
|
if (wrapped) {
|
|
458
|
-
|
|
485
|
+
if (attached) {
|
|
486
|
+
try {
|
|
487
|
+
IAP.instance.removePurchaseUpdatedListener(wrapped);
|
|
488
|
+
} catch {}
|
|
489
|
+
}
|
|
459
490
|
listenerMap.delete(listener);
|
|
460
491
|
}
|
|
461
492
|
}
|
|
@@ -492,10 +523,25 @@ export const purchaseUpdatedListener = listener => {
|
|
|
492
523
|
export const purchaseErrorListener = listener => {
|
|
493
524
|
// Store the listener for removal
|
|
494
525
|
listenerMap.set(listener, listener);
|
|
495
|
-
|
|
526
|
+
let attached = false;
|
|
527
|
+
try {
|
|
528
|
+
IAP.instance.addPurchaseErrorListener(listener);
|
|
529
|
+
attached = true;
|
|
530
|
+
} catch (e) {
|
|
531
|
+
const msg = String(e ?? '');
|
|
532
|
+
if (msg.includes('Nitro runtime not installed')) {
|
|
533
|
+
console.warn('[purchaseErrorListener] Nitro not ready yet; listener inert until initConnection()');
|
|
534
|
+
} else {
|
|
535
|
+
throw e;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
496
538
|
return {
|
|
497
539
|
remove: () => {
|
|
498
|
-
|
|
540
|
+
if (attached) {
|
|
541
|
+
try {
|
|
542
|
+
IAP.instance.removePurchaseErrorListener(listener);
|
|
543
|
+
} catch {}
|
|
544
|
+
}
|
|
499
545
|
listenerMap.delete(listener);
|
|
500
546
|
}
|
|
501
547
|
};
|
|
@@ -541,12 +587,27 @@ export const promotedProductListenerIOS = listener => {
|
|
|
541
587
|
|
|
542
588
|
// Store the wrapped listener for removal
|
|
543
589
|
listenerMap.set(listener, wrappedListener);
|
|
544
|
-
|
|
590
|
+
let attached = false;
|
|
591
|
+
try {
|
|
592
|
+
IAP.instance.addPromotedProductListenerIOS(wrappedListener);
|
|
593
|
+
attached = true;
|
|
594
|
+
} catch (e) {
|
|
595
|
+
const msg = String(e ?? '');
|
|
596
|
+
if (msg.includes('Nitro runtime not installed')) {
|
|
597
|
+
console.warn('[promotedProductListenerIOS] Nitro not ready yet; listener inert until initConnection()');
|
|
598
|
+
} else {
|
|
599
|
+
throw e;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
545
602
|
return {
|
|
546
603
|
remove: () => {
|
|
547
604
|
const wrapped = listenerMap.get(listener);
|
|
548
605
|
if (wrapped) {
|
|
549
|
-
|
|
606
|
+
if (attached) {
|
|
607
|
+
try {
|
|
608
|
+
IAP.instance.removePromotedProductListenerIOS(wrapped);
|
|
609
|
+
} catch {}
|
|
610
|
+
}
|
|
550
611
|
listenerMap.delete(listener);
|
|
551
612
|
}
|
|
552
613
|
}
|
|
@@ -564,16 +625,12 @@ export const promotedProductListenerIOS = listener => {
|
|
|
564
625
|
* @returns Promise<ReceiptValidationResultIOS | ReceiptValidationResultAndroid> - Platform-specific receipt validation result
|
|
565
626
|
*/
|
|
566
627
|
export const validateReceipt = async (sku, androidOptions) => {
|
|
567
|
-
if (!iap) {
|
|
568
|
-
const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
|
|
569
|
-
throw new Error(errorJson.message);
|
|
570
|
-
}
|
|
571
628
|
try {
|
|
572
629
|
const params = {
|
|
573
630
|
sku,
|
|
574
631
|
androidOptions
|
|
575
632
|
};
|
|
576
|
-
const nitroResult = await
|
|
633
|
+
const nitroResult = await IAP.instance.validateReceipt(params);
|
|
577
634
|
|
|
578
635
|
// Convert Nitro result to public API result
|
|
579
636
|
if (Platform.OS === 'ios') {
|
|
@@ -626,12 +683,8 @@ export const syncIOS = async () => {
|
|
|
626
683
|
if (Platform.OS !== 'ios') {
|
|
627
684
|
throw new Error('syncIOS is only available on iOS');
|
|
628
685
|
}
|
|
629
|
-
if (!iap) {
|
|
630
|
-
const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
|
|
631
|
-
throw new Error(errorJson.message);
|
|
632
|
-
}
|
|
633
686
|
try {
|
|
634
|
-
return await
|
|
687
|
+
return await IAP.instance.syncIOS();
|
|
635
688
|
} catch (error) {
|
|
636
689
|
console.error('[syncIOS] Failed:', error);
|
|
637
690
|
const errorJson = parseErrorStringToJsonObj(error);
|
|
@@ -648,12 +701,8 @@ export const requestPromotedProductIOS = async () => {
|
|
|
648
701
|
if (Platform.OS !== 'ios') {
|
|
649
702
|
return null;
|
|
650
703
|
}
|
|
651
|
-
if (!iap) {
|
|
652
|
-
const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
|
|
653
|
-
throw new Error(errorJson.message);
|
|
654
|
-
}
|
|
655
704
|
try {
|
|
656
|
-
const nitroProduct = await
|
|
705
|
+
const nitroProduct = await IAP.instance.requestPromotedProductIOS();
|
|
657
706
|
if (nitroProduct) {
|
|
658
707
|
return convertNitroProductToProduct(nitroProduct);
|
|
659
708
|
}
|
|
@@ -674,12 +723,8 @@ export const presentCodeRedemptionSheetIOS = async () => {
|
|
|
674
723
|
if (Platform.OS !== 'ios') {
|
|
675
724
|
return false;
|
|
676
725
|
}
|
|
677
|
-
if (!iap) {
|
|
678
|
-
const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
|
|
679
|
-
throw new Error(errorJson.message);
|
|
680
|
-
}
|
|
681
726
|
try {
|
|
682
|
-
return await
|
|
727
|
+
return await IAP.instance.presentCodeRedemptionSheetIOS();
|
|
683
728
|
} catch (error) {
|
|
684
729
|
console.error('[presentCodeRedemptionSheetIOS] Failed:', error);
|
|
685
730
|
const errorJson = parseErrorStringToJsonObj(error);
|
|
@@ -696,12 +741,8 @@ export const buyPromotedProductIOS = async () => {
|
|
|
696
741
|
if (Platform.OS !== 'ios') {
|
|
697
742
|
throw new Error('buyPromotedProductIOS is only available on iOS');
|
|
698
743
|
}
|
|
699
|
-
if (!iap) {
|
|
700
|
-
const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
|
|
701
|
-
throw new Error(errorJson.message);
|
|
702
|
-
}
|
|
703
744
|
try {
|
|
704
|
-
await
|
|
745
|
+
await IAP.instance.buyPromotedProductIOS();
|
|
705
746
|
} catch (error) {
|
|
706
747
|
console.error('[buyPromotedProductIOS] Failed:', error);
|
|
707
748
|
const errorJson = parseErrorStringToJsonObj(error);
|
|
@@ -718,12 +759,8 @@ export const clearTransactionIOS = async () => {
|
|
|
718
759
|
if (Platform.OS !== 'ios') {
|
|
719
760
|
return;
|
|
720
761
|
}
|
|
721
|
-
if (!iap) {
|
|
722
|
-
const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
|
|
723
|
-
throw new Error(errorJson.message);
|
|
724
|
-
}
|
|
725
762
|
try {
|
|
726
|
-
await
|
|
763
|
+
await IAP.instance.clearTransactionIOS();
|
|
727
764
|
} catch (error) {
|
|
728
765
|
console.error('[clearTransactionIOS] Failed:', error);
|
|
729
766
|
const errorJson = parseErrorStringToJsonObj(error);
|
|
@@ -741,12 +778,8 @@ export const beginRefundRequestIOS = async sku => {
|
|
|
741
778
|
if (Platform.OS !== 'ios') {
|
|
742
779
|
return null;
|
|
743
780
|
}
|
|
744
|
-
if (!iap) {
|
|
745
|
-
const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
|
|
746
|
-
throw new Error(errorJson.message);
|
|
747
|
-
}
|
|
748
781
|
try {
|
|
749
|
-
return await
|
|
782
|
+
return await IAP.instance.beginRefundRequestIOS(sku);
|
|
750
783
|
} catch (error) {
|
|
751
784
|
console.error('[beginRefundRequestIOS] Failed:', error);
|
|
752
785
|
const errorJson = parseErrorStringToJsonObj(error);
|
|
@@ -765,12 +798,8 @@ export const subscriptionStatusIOS = async sku => {
|
|
|
765
798
|
if (Platform.OS !== 'ios') {
|
|
766
799
|
throw new Error('subscriptionStatusIOS is only available on iOS');
|
|
767
800
|
}
|
|
768
|
-
if (!iap) {
|
|
769
|
-
const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
|
|
770
|
-
throw new Error(errorJson.message);
|
|
771
|
-
}
|
|
772
801
|
try {
|
|
773
|
-
const statuses = await
|
|
802
|
+
const statuses = await IAP.instance.subscriptionStatusIOS(sku);
|
|
774
803
|
if (!statuses || !Array.isArray(statuses)) return [];
|
|
775
804
|
return statuses.map(s => convertNitroSubscriptionStatusToSubscriptionStatusIOS(s));
|
|
776
805
|
} catch (error) {
|
|
@@ -790,12 +819,8 @@ export const currentEntitlementIOS = async sku => {
|
|
|
790
819
|
if (Platform.OS !== 'ios') {
|
|
791
820
|
return null;
|
|
792
821
|
}
|
|
793
|
-
if (!iap) {
|
|
794
|
-
const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
|
|
795
|
-
throw new Error(errorJson.message);
|
|
796
|
-
}
|
|
797
822
|
try {
|
|
798
|
-
const nitroPurchase = await
|
|
823
|
+
const nitroPurchase = await IAP.instance.currentEntitlementIOS(sku);
|
|
799
824
|
if (nitroPurchase) {
|
|
800
825
|
return convertNitroPurchaseToPurchase(nitroPurchase);
|
|
801
826
|
}
|
|
@@ -817,12 +842,8 @@ export const latestTransactionIOS = async sku => {
|
|
|
817
842
|
if (Platform.OS !== 'ios') {
|
|
818
843
|
return null;
|
|
819
844
|
}
|
|
820
|
-
if (!iap) {
|
|
821
|
-
const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
|
|
822
|
-
throw new Error(errorJson.message);
|
|
823
|
-
}
|
|
824
845
|
try {
|
|
825
|
-
const nitroPurchase = await
|
|
846
|
+
const nitroPurchase = await IAP.instance.latestTransactionIOS(sku);
|
|
826
847
|
if (nitroPurchase) {
|
|
827
848
|
return convertNitroPurchaseToPurchase(nitroPurchase);
|
|
828
849
|
}
|
|
@@ -843,12 +864,8 @@ export const getPendingTransactionsIOS = async () => {
|
|
|
843
864
|
if (Platform.OS !== 'ios') {
|
|
844
865
|
return [];
|
|
845
866
|
}
|
|
846
|
-
if (!iap) {
|
|
847
|
-
const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
|
|
848
|
-
throw new Error(errorJson.message);
|
|
849
|
-
}
|
|
850
867
|
try {
|
|
851
|
-
const nitroPurchases = await
|
|
868
|
+
const nitroPurchases = await IAP.instance.getPendingTransactionsIOS();
|
|
852
869
|
return nitroPurchases.map(convertNitroPurchaseToPurchase);
|
|
853
870
|
} catch (error) {
|
|
854
871
|
console.error('[getPendingTransactionsIOS] Failed:', error);
|
|
@@ -866,12 +883,8 @@ export const showManageSubscriptionsIOS = async () => {
|
|
|
866
883
|
if (Platform.OS !== 'ios') {
|
|
867
884
|
return [];
|
|
868
885
|
}
|
|
869
|
-
if (!iap) {
|
|
870
|
-
const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
|
|
871
|
-
throw new Error(errorJson.message);
|
|
872
|
-
}
|
|
873
886
|
try {
|
|
874
|
-
const nitroPurchases = await
|
|
887
|
+
const nitroPurchases = await IAP.instance.showManageSubscriptionsIOS();
|
|
875
888
|
return nitroPurchases.map(convertNitroPurchaseToPurchase);
|
|
876
889
|
} catch (error) {
|
|
877
890
|
console.error('[showManageSubscriptionsIOS] Failed:', error);
|
|
@@ -890,12 +903,8 @@ export const isEligibleForIntroOfferIOS = async groupID => {
|
|
|
890
903
|
if (Platform.OS !== 'ios') {
|
|
891
904
|
return false;
|
|
892
905
|
}
|
|
893
|
-
if (!iap) {
|
|
894
|
-
const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
|
|
895
|
-
throw new Error(errorJson.message);
|
|
896
|
-
}
|
|
897
906
|
try {
|
|
898
|
-
return await
|
|
907
|
+
return await IAP.instance.isEligibleForIntroOfferIOS(groupID);
|
|
899
908
|
} catch (error) {
|
|
900
909
|
console.error('[isEligibleForIntroOfferIOS] Failed:', error);
|
|
901
910
|
const errorJson = parseErrorStringToJsonObj(error);
|
|
@@ -912,12 +921,8 @@ export const getReceiptDataIOS = async () => {
|
|
|
912
921
|
if (Platform.OS !== 'ios') {
|
|
913
922
|
throw new Error('getReceiptDataIOS is only available on iOS');
|
|
914
923
|
}
|
|
915
|
-
if (!iap) {
|
|
916
|
-
const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
|
|
917
|
-
throw new Error(errorJson.message);
|
|
918
|
-
}
|
|
919
924
|
try {
|
|
920
|
-
return await
|
|
925
|
+
return await IAP.instance.getReceiptDataIOS();
|
|
921
926
|
} catch (error) {
|
|
922
927
|
console.error('[getReceiptDataIOS] Failed:', error);
|
|
923
928
|
const errorJson = parseErrorStringToJsonObj(error);
|
|
@@ -935,12 +940,8 @@ export const isTransactionVerifiedIOS = async sku => {
|
|
|
935
940
|
if (Platform.OS !== 'ios') {
|
|
936
941
|
return false;
|
|
937
942
|
}
|
|
938
|
-
if (!iap) {
|
|
939
|
-
const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
|
|
940
|
-
throw new Error(errorJson.message);
|
|
941
|
-
}
|
|
942
943
|
try {
|
|
943
|
-
return await
|
|
944
|
+
return await IAP.instance.isTransactionVerifiedIOS(sku);
|
|
944
945
|
} catch (error) {
|
|
945
946
|
console.error('[isTransactionVerifiedIOS] Failed:', error);
|
|
946
947
|
const errorJson = parseErrorStringToJsonObj(error);
|
|
@@ -958,12 +959,8 @@ export const getTransactionJwsIOS = async sku => {
|
|
|
958
959
|
if (Platform.OS !== 'ios') {
|
|
959
960
|
return null;
|
|
960
961
|
}
|
|
961
|
-
if (!iap) {
|
|
962
|
-
const errorJson = parseErrorStringToJsonObj('RnIap: Service not initialized. Call initConnection() first.');
|
|
963
|
-
throw new Error(errorJson.message);
|
|
964
|
-
}
|
|
965
962
|
try {
|
|
966
|
-
return await
|
|
963
|
+
return await IAP.instance.getTransactionJwsIOS(sku);
|
|
967
964
|
} catch (error) {
|
|
968
965
|
console.error('[getTransactionJwsIOS] Failed:', error);
|
|
969
966
|
const errorJson = parseErrorStringToJsonObj(error);
|
|
@@ -988,7 +985,7 @@ export const getStorefrontIOS = async () => {
|
|
|
988
985
|
}
|
|
989
986
|
try {
|
|
990
987
|
// Call the native method to get storefront
|
|
991
|
-
const storefront = await
|
|
988
|
+
const storefront = await IAP.instance.getStorefrontIOS();
|
|
992
989
|
return storefront;
|
|
993
990
|
} catch (error) {
|
|
994
991
|
console.error('Failed to get storefront:', error);
|
|
@@ -1006,7 +1003,7 @@ export const getStorefront = async () => {
|
|
|
1006
1003
|
if (Platform.OS === 'android') {
|
|
1007
1004
|
try {
|
|
1008
1005
|
// Optional since older builds may not have the method
|
|
1009
|
-
const result = await
|
|
1006
|
+
const result = await IAP.instance.getStorefrontAndroid?.();
|
|
1010
1007
|
return result ?? '';
|
|
1011
1008
|
} catch {
|
|
1012
1009
|
return '';
|
|
@@ -1021,7 +1018,7 @@ export const getStorefront = async () => {
|
|
|
1021
1018
|
*/
|
|
1022
1019
|
export const deepLinkToSubscriptions = async (options = {}) => {
|
|
1023
1020
|
if (Platform.OS === 'android') {
|
|
1024
|
-
await
|
|
1021
|
+
await IAP.instance.deepLinkToSubscriptionsAndroid?.({
|
|
1025
1022
|
skuAndroid: options.skuAndroid,
|
|
1026
1023
|
packageNameAndroid: options.packageNameAndroid
|
|
1027
1024
|
});
|
|
@@ -1030,7 +1027,7 @@ export const deepLinkToSubscriptions = async (options = {}) => {
|
|
|
1030
1027
|
// iOS: Use manage subscriptions sheet (ignore returned purchases for deeplink parity)
|
|
1031
1028
|
if (Platform.OS === 'ios') {
|
|
1032
1029
|
try {
|
|
1033
|
-
await
|
|
1030
|
+
await IAP.instance.showManageSubscriptionsIOS();
|
|
1034
1031
|
} catch {
|
|
1035
1032
|
// no-op
|
|
1036
1033
|
}
|
|
@@ -1064,7 +1061,7 @@ export const getAppTransactionIOS = async () => {
|
|
|
1064
1061
|
}
|
|
1065
1062
|
try {
|
|
1066
1063
|
// Call the native method to get app transaction
|
|
1067
|
-
const appTransaction = await
|
|
1064
|
+
const appTransaction = await IAP.instance.getAppTransactionIOS();
|
|
1068
1065
|
return appTransaction;
|
|
1069
1066
|
} catch (error) {
|
|
1070
1067
|
console.error('Failed to get app transaction:', error);
|