react-native-iap 14.2.2 → 14.2.3-rc.1
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/NitroIap.podspec +4 -1
- package/app.plugin.js +1 -1
- package/ios/reactnativeiap.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/ios/reactnativeiap.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/lib/module/helpers/subscription.js.map +1 -1
- package/lib/module/utils/error.js.map +1 -1
- package/lib/typescript/src/helpers/subscription.d.ts.map +1 -1
- package/lib/typescript/src/utils/error.d.ts.map +1 -1
- package/package.json +1 -1
- package/plugin/build/src/withIAP.d.ts +3 -0
- package/plugin/build/src/withIAP.js +81 -0
- package/plugin/build/tsconfig.tsbuildinfo +1 -0
- package/plugin/tsconfig.tsbuildinfo +1 -1
- package/src/helpers/subscription.ts +30 -30
- package/src/utils/error.ts +19 -19
package/NitroIap.podspec
CHANGED
|
@@ -10,7 +10,10 @@ Pod::Spec.new do |s|
|
|
|
10
10
|
s.license = package["license"]
|
|
11
11
|
s.authors = package["author"]
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
# React Native IAP uses StoreKit 2 via OpenIAP, which requires iOS 15+.
|
|
14
|
+
# Enforce this at the podspec level so projects with a lower deployment target
|
|
15
|
+
# get a clear CocoaPods error instead of a vague SwiftCompile failure.
|
|
16
|
+
s.platforms = { :ios => '15.0', :visionos => 1.0 }
|
|
14
17
|
s.source = { :git => "https://github.com/hyochan/react-native-iap.git", :tag => "#{s.version}" }
|
|
15
18
|
|
|
16
19
|
s.source_files = [
|
package/app.plugin.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
module.exports = require('./plugin/build/withIAP.js')
|
|
1
|
+
module.exports = require('./plugin/build/withIAP.js');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["getAvailablePurchases","getActiveSubscriptions","subscriptionIds","purchases","subscriptions","filter","purchase","length","includes","productId","map","iosPurchase","androidPurchase","isActive","transactionId","id","purchaseToken","purchaseTokenAndroid","transactionDate","expirationDateIOS","Date","undefined","autoRenewingAndroid","isAutoRenewing","environmentIOS","willExpireSoon","daysUntilExpirationIOS","Math","ceil","now","error","console","hasActiveSubscriptions","activeSubscriptions"],"sourceRoot":"../../../src","sources":["helpers/subscription.ts"],"mappings":";;AAAA,
|
|
1
|
+
{"version":3,"names":["getAvailablePurchases","getActiveSubscriptions","subscriptionIds","purchases","subscriptions","filter","purchase","length","includes","productId","map","iosPurchase","androidPurchase","isActive","transactionId","id","purchaseToken","purchaseTokenAndroid","transactionDate","expirationDateIOS","Date","undefined","autoRenewingAndroid","isAutoRenewing","environmentIOS","willExpireSoon","daysUntilExpirationIOS","Math","ceil","now","error","console","hasActiveSubscriptions","activeSubscriptions"],"sourceRoot":"../../../src","sources":["helpers/subscription.ts"],"mappings":";;AAAA,SAAQA,qBAAqB,QAAO,aAAK;AAOzC;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,sBAAsB,GAAG,MACpCC,eAA0B,IACQ;EAClC,IAAI;IACF;IACA,MAAMC,SAAS,GAAG,MAAMH,qBAAqB,CAAC,CAAC;;IAE/C;IACA,MAAMI,aAAa,GAAGD,SAAS,CAC5BE,MAAM,CAAEC,QAAQ,IAAK;MACpB;MACA,IAAIJ,eAAe,IAAIA,eAAe,CAACK,MAAM,GAAG,CAAC,EAAE;QACjD,OAAOL,eAAe,CAACM,QAAQ,CAACF,QAAQ,CAACG,SAAS,CAAC;MACrD;MACA,OAAO,IAAI;IACb,CAAC,CAAC,CACDC,GAAG,CAAEJ,QAAQ,IAAyB;MACrC,MAAMK,WAAW,GAAGL,QAAuB;MAC3C,MAAMM,eAAe,GAAGN,QAA2B;MACnD,OAAO;QACLG,SAAS,EAAEH,QAAQ,CAACG,SAAS;QAC7BI,QAAQ,EAAE,IAAI;QAAE;QAChB;QACAC,aAAa,EAAER,QAAQ,CAACQ,aAAa,IAAIR,QAAQ,CAACS,EAAE;QACpDC,aAAa,EACXJ,eAAe,CAACI,aAAa,IAAIJ,eAAe,CAACK,oBAAoB,IAAIN,WAAW,CAACK,aAAa;QACpGE,eAAe,EAAEZ,QAAQ,CAACY,eAAe;QACzC;QACAC,iBAAiB,EAAER,WAAW,CAACQ,iBAAiB,GAC5C,IAAIC,IAAI,CAACT,WAAW,CAACQ,iBAAiB,CAAC,GACvCE,SAAS;QACbC,mBAAmB,EAAEV,eAAe,CAACU,mBAAmB,IAAIV,eAAe,CAACW,cAAc;QAAE;QAC5FC,cAAc,EAAEb,WAAW,CAACa,cAAc;QAC1C;QACAC,cAAc,EAAE,KAAK;QAAE;QACvBC,sBAAsB,EAAEf,WAAW,CAACQ,iBAAiB,GACjDQ,IAAI,CAACC,IAAI,CACP,CAACjB,WAAW,CAACQ,iBAAiB,GAAGC,IAAI,CAACS,GAAG,CAAC,CAAC,KAAK,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CACrE,CAAC,GACDR;MACN,CAAC;IACH,CAAC,CAAC;IAEJ,OAAOjB,aAAa;EACtB,CAAC,CAAC,OAAO0B,KAAK,EAAE;IACdC,OAAO,CAACD,KAAK,CAAC,qCAAqC,EAAEA,KAAK,CAAC;IAC3D,MAAMA,KAAK;EACb;AACF,CAAC;;AAGD;AACA;AACA;AACA;AACA;AACA,OAAO,MAAME,sBAAsB,GAAG,MACpC9B,eAA0B,IACL;EACrB,IAAI;IACF,MAAM+B,mBAAmB,GAAG,MAAMhC,sBAAsB,CAACC,eAAe,CAAC;IACzE,OAAO+B,mBAAmB,CAAC1B,MAAM,GAAG,CAAC;EACvC,CAAC,CAAC,OAAOuB,KAAK,EAAE;IACdC,OAAO,CAACD,KAAK,CAAC,uCAAuC,EAAEA,KAAK,CAAC;IAC7D,OAAO,KAAK;EACd;AACF,CAAC","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["ErrorCode","parseErrorStringToJsonObj","errorString","Error","message","code","E_UNKNOWN","parsed","JSON","parse","colonIndex","indexOf","potentialCode","substring","trim","startsWith","test","isUserCancelledError","error","errorObj","E_USER_CANCELLED","responseCode"],"sourceRoot":"../../../src","sources":["utils/error.ts"],"mappings":";;AAAA;AACA;AACA;;AAEA,
|
|
1
|
+
{"version":3,"names":["ErrorCode","parseErrorStringToJsonObj","errorString","Error","message","code","E_UNKNOWN","parsed","JSON","parse","colonIndex","indexOf","potentialCode","substring","trim","startsWith","test","isUserCancelledError","error","errorObj","E_USER_CANCELLED","responseCode"],"sourceRoot":"../../../src","sources":["utils/error.ts"],"mappings":";;AAAA;AACA;AACA;;AAEA,SAAQA,SAAS,QAAO,aAAU;AAWlC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,yBAAyBA,CACvCC,WAAqC,EAC3B;EACV;EACA,IAAIA,WAAW,YAAYC,KAAK,EAAE;IAChCD,WAAW,GAAGA,WAAW,CAACE,OAAO;EACnC;;EAEA;EACA,IAAI,OAAOF,WAAW,KAAK,QAAQ,EAAE;IACnC,OAAO;MACLG,IAAI,EAAEL,SAAS,CAACM,SAAS;MACzBF,OAAO,EAAE;IACX,CAAC;EACH;;EAEA;EACA,IAAI;IACF,MAAMG,MAAM,GAAGC,IAAI,CAACC,KAAK,CAACP,WAAW,CAAC;IACtC,IAAI,OAAOK,MAAM,KAAK,QAAQ,IAAIA,MAAM,KAAK,IAAI,EAAE;MACjD;MACA,OAAO;QACLF,IAAI,EAAEE,MAAM,CAACF,IAAI,IAAIL,SAAS,CAACM,SAAS;QACxCF,OAAO,EAAEG,MAAM,CAACH,OAAO,IAAIF,WAAW;QACtC,GAAGK;MACL,CAAC;IACH;EACF,CAAC,CAAC,MAAM;IACN;EAAA;;EAGF;EACA,MAAMG,UAAU,GAAGR,WAAW,CAACS,OAAO,CAAC,GAAG,CAAC;EAC3C,IAAID,UAAU,GAAG,CAAC,IAAIA,UAAU,GAAG,EAAE,EAAE;IACrC;IACA,MAAME,aAAa,GAAGV,WAAW,CAACW,SAAS,CAAC,CAAC,EAAEH,UAAU,CAAC,CAACI,IAAI,CAAC,CAAC;IACjE;IACA,IAAIF,aAAa,CAACG,UAAU,CAAC,IAAI,CAAC,IAAI,WAAW,CAACC,IAAI,CAACJ,aAAa,CAAC,EAAE;MACrE,OAAO;QACLP,IAAI,EAAEO,aAAa;QACnBR,OAAO,EAAEF,WAAW,CAACW,SAAS,CAACH,UAAU,GAAG,CAAC,CAAC,CAACI,IAAI,CAAC;MACtD,CAAC;IACH;EACF;;EAEA;EACA,OAAO;IACLT,IAAI,EAAEL,SAAS,CAACM,SAAS;IACzBF,OAAO,EAAEF;EACX,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASe,oBAAoBA,CAClCC,KAA0C,EACjC;EACT,MAAMC,QAAQ,GACZ,OAAOD,KAAK,KAAK,QAAQ,IAAIA,KAAK,KAAK,IAAI,IAAI,MAAM,IAAIA,KAAK,GACzDA,KAAK,GACNjB,yBAAyB,CAACiB,KAAK,CAAC;EAEtC,OACEC,QAAQ,CAACd,IAAI,KAAKL,SAAS,CAACoB,gBAAgB,IAC5CD,QAAQ,CAACd,IAAI,KAAK,iBAAiB;EAAI;EACvCc,QAAQ,CAACE,YAAY,KAAK,CAAC,CAC3B,CAAC;AACL","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subscription.d.ts","sourceRoot":"","sources":["../../../../src/helpers/subscription.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"subscription.d.ts","sourceRoot":"","sources":["../../../../src/helpers/subscription.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,kBAAkB,EAGnB,MAAM,UAAU,CAAC;AAElB;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,GACjC,kBAAkB,MAAM,EAAE,KACzB,OAAO,CAAC,kBAAkB,EAAE,CA8C9B,CAAC;AAGF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,GACjC,kBAAkB,MAAM,EAAE,KACzB,OAAO,CAAC,OAAO,CAQjB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../../../src/utils/error.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../../../src/utils/error.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,GAAG,KAAK,GAAG,OAAO,GACpC,QAAQ,CAgDV;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GACzC,OAAO,CAWT"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const config_plugins_1 = require("expo/config-plugins");
|
|
4
|
+
const pkg = require('../../package.json');
|
|
5
|
+
// Global flag to prevent duplicate logs
|
|
6
|
+
let hasLoggedPluginExecution = false;
|
|
7
|
+
const addLineToGradle = (content, anchor, lineToAdd, offset = 1) => {
|
|
8
|
+
const lines = content.split('\n');
|
|
9
|
+
const index = lines.findIndex((line) => line.match(anchor));
|
|
10
|
+
if (index === -1) {
|
|
11
|
+
console.warn(`Anchor "${anchor}" not found in build.gradle. Appending to end.`);
|
|
12
|
+
lines.push(lineToAdd);
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
lines.splice(index + offset, 0, lineToAdd);
|
|
16
|
+
}
|
|
17
|
+
return lines.join('\n');
|
|
18
|
+
};
|
|
19
|
+
const modifyAppBuildGradle = (gradle) => {
|
|
20
|
+
let modified = gradle;
|
|
21
|
+
// Add billing library dependencies to app-level build.gradle
|
|
22
|
+
const billingDep = ` implementation "com.android.billingclient:billing-ktx:8.0.0"`;
|
|
23
|
+
const gmsDep = ` implementation "com.google.android.gms:play-services-base:18.1.0"`;
|
|
24
|
+
let hasAddedDependency = false;
|
|
25
|
+
if (!modified.includes(billingDep)) {
|
|
26
|
+
modified = addLineToGradle(modified, /dependencies\s*{/, billingDep);
|
|
27
|
+
hasAddedDependency = true;
|
|
28
|
+
}
|
|
29
|
+
if (!modified.includes(gmsDep)) {
|
|
30
|
+
modified = addLineToGradle(modified, /dependencies\s*{/, gmsDep, 1);
|
|
31
|
+
hasAddedDependency = true;
|
|
32
|
+
}
|
|
33
|
+
// Log only once and only if we actually added dependencies
|
|
34
|
+
if (hasAddedDependency && !hasLoggedPluginExecution) {
|
|
35
|
+
console.log('🛠️ react-native-iap: Added billing dependencies to build.gradle');
|
|
36
|
+
}
|
|
37
|
+
return modified;
|
|
38
|
+
};
|
|
39
|
+
const withIapAndroid = (config) => {
|
|
40
|
+
// Add IAP dependencies to app build.gradle
|
|
41
|
+
config = (0, config_plugins_1.withAppBuildGradle)(config, (config) => {
|
|
42
|
+
config.modResults.contents = modifyAppBuildGradle(config.modResults.contents);
|
|
43
|
+
return config;
|
|
44
|
+
});
|
|
45
|
+
config = (0, config_plugins_1.withAndroidManifest)(config, (config) => {
|
|
46
|
+
const manifest = config.modResults;
|
|
47
|
+
if (!manifest.manifest['uses-permission']) {
|
|
48
|
+
manifest.manifest['uses-permission'] = [];
|
|
49
|
+
}
|
|
50
|
+
const permissions = manifest.manifest['uses-permission'];
|
|
51
|
+
const billingPerm = { $: { 'android:name': 'com.android.vending.BILLING' } };
|
|
52
|
+
const alreadyExists = permissions.some((p) => p.$['android:name'] === 'com.android.vending.BILLING');
|
|
53
|
+
if (!alreadyExists) {
|
|
54
|
+
permissions.push(billingPerm);
|
|
55
|
+
if (!hasLoggedPluginExecution) {
|
|
56
|
+
console.log('✅ Added com.android.vending.BILLING to AndroidManifest.xml');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
if (!hasLoggedPluginExecution) {
|
|
61
|
+
console.log('ℹ️ com.android.vending.BILLING already exists in AndroidManifest.xml');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return config;
|
|
65
|
+
});
|
|
66
|
+
return config;
|
|
67
|
+
};
|
|
68
|
+
const withIAP = (config, _props) => {
|
|
69
|
+
try {
|
|
70
|
+
const result = withIapAndroid(config);
|
|
71
|
+
// Set flag after first execution to prevent duplicate logs
|
|
72
|
+
hasLoggedPluginExecution = true;
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
config_plugins_1.WarningAggregator.addWarningAndroid('react-native-iap', `react-native-iap plugin encountered an error: ${error}`);
|
|
77
|
+
console.error('react-native-iap plugin error:', error);
|
|
78
|
+
return config;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
exports.default = (0, config_plugins_1.createRunOncePlugin)(withIAP, pkg.name, pkg.version);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"root":["../src/withiap.ts"],"version":"5.9.2"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["./src/
|
|
1
|
+
{"root":["./src/withiap.ts"],"version":"5.9.2"}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type {
|
|
1
|
+
import {getAvailablePurchases} from '../';
|
|
2
|
+
import type {
|
|
3
|
+
ActiveSubscription,
|
|
4
|
+
PurchaseIOS,
|
|
5
|
+
PurchaseAndroid,
|
|
6
|
+
} from '../types';
|
|
3
7
|
|
|
4
8
|
/**
|
|
5
9
|
* Get active subscriptions
|
|
@@ -7,59 +11,55 @@ import type { ActiveSubscription, PurchaseIOS, PurchaseAndroid } from '../types'
|
|
|
7
11
|
* @returns Promise<ActiveSubscription[]> - Array of active subscriptions
|
|
8
12
|
*/
|
|
9
13
|
export const getActiveSubscriptions = async (
|
|
10
|
-
subscriptionIds?: string[]
|
|
14
|
+
subscriptionIds?: string[],
|
|
11
15
|
): Promise<ActiveSubscription[]> => {
|
|
12
16
|
try {
|
|
13
17
|
// Get available purchases and filter for subscriptions
|
|
14
|
-
const purchases = await getAvailablePurchases()
|
|
15
|
-
|
|
18
|
+
const purchases = await getAvailablePurchases();
|
|
19
|
+
|
|
16
20
|
// Filter for subscriptions and map to ActiveSubscription format
|
|
17
21
|
const subscriptions = purchases
|
|
18
22
|
.filter((purchase) => {
|
|
19
23
|
// Filter by subscription IDs if provided
|
|
20
24
|
if (subscriptionIds && subscriptionIds.length > 0) {
|
|
21
|
-
return subscriptionIds.includes(purchase.productId)
|
|
25
|
+
return subscriptionIds.includes(purchase.productId);
|
|
22
26
|
}
|
|
23
|
-
return true
|
|
27
|
+
return true;
|
|
24
28
|
})
|
|
25
29
|
.map((purchase): ActiveSubscription => {
|
|
26
|
-
const iosPurchase = purchase as PurchaseIOS
|
|
27
|
-
const androidPurchase = purchase as PurchaseAndroid
|
|
30
|
+
const iosPurchase = purchase as PurchaseIOS;
|
|
31
|
+
const androidPurchase = purchase as PurchaseAndroid;
|
|
28
32
|
return {
|
|
29
33
|
productId: purchase.productId,
|
|
30
34
|
isActive: true, // If it's in availablePurchases, it's active
|
|
31
35
|
// Backend validation fields
|
|
32
36
|
transactionId: purchase.transactionId || purchase.id,
|
|
33
37
|
purchaseToken:
|
|
34
|
-
androidPurchase.purchaseToken ||
|
|
35
|
-
androidPurchase.purchaseTokenAndroid ||
|
|
36
|
-
iosPurchase.purchaseToken,
|
|
38
|
+
androidPurchase.purchaseToken || androidPurchase.purchaseTokenAndroid || iosPurchase.purchaseToken,
|
|
37
39
|
transactionDate: purchase.transactionDate,
|
|
38
40
|
// Platform-specific fields
|
|
39
41
|
expirationDateIOS: iosPurchase.expirationDateIOS
|
|
40
42
|
? new Date(iosPurchase.expirationDateIOS)
|
|
41
43
|
: undefined,
|
|
42
|
-
autoRenewingAndroid:
|
|
43
|
-
androidPurchase.autoRenewingAndroid ??
|
|
44
|
-
androidPurchase.isAutoRenewing, // deprecated - use isAutoRenewing instead
|
|
44
|
+
autoRenewingAndroid: androidPurchase.autoRenewingAndroid ?? androidPurchase.isAutoRenewing, // deprecated - use isAutoRenewing instead
|
|
45
45
|
environmentIOS: iosPurchase.environmentIOS,
|
|
46
46
|
// Convenience fields
|
|
47
47
|
willExpireSoon: false, // Would need to calculate based on expiration date
|
|
48
48
|
daysUntilExpirationIOS: iosPurchase.expirationDateIOS
|
|
49
49
|
? Math.ceil(
|
|
50
|
-
(iosPurchase.expirationDateIOS - Date.now()) /
|
|
51
|
-
(1000 * 60 * 60 * 24)
|
|
50
|
+
(iosPurchase.expirationDateIOS - Date.now()) / (1000 * 60 * 60 * 24),
|
|
52
51
|
)
|
|
53
52
|
: undefined,
|
|
54
|
-
}
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
return subscriptions
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return subscriptions;
|
|
58
57
|
} catch (error) {
|
|
59
|
-
console.error('Failed to get active subscriptions:', error)
|
|
60
|
-
throw error
|
|
58
|
+
console.error('Failed to get active subscriptions:', error);
|
|
59
|
+
throw error;
|
|
61
60
|
}
|
|
62
|
-
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
65
|
* Check if there are any active subscriptions
|
|
@@ -67,13 +67,13 @@ export const getActiveSubscriptions = async (
|
|
|
67
67
|
* @returns Promise<boolean> - True if there are active subscriptions
|
|
68
68
|
*/
|
|
69
69
|
export const hasActiveSubscriptions = async (
|
|
70
|
-
subscriptionIds?: string[]
|
|
70
|
+
subscriptionIds?: string[],
|
|
71
71
|
): Promise<boolean> => {
|
|
72
72
|
try {
|
|
73
|
-
const activeSubscriptions = await getActiveSubscriptions(subscriptionIds)
|
|
74
|
-
return activeSubscriptions.length > 0
|
|
73
|
+
const activeSubscriptions = await getActiveSubscriptions(subscriptionIds);
|
|
74
|
+
return activeSubscriptions.length > 0;
|
|
75
75
|
} catch (error) {
|
|
76
|
-
console.error('Failed to check active subscriptions:', error)
|
|
77
|
-
return false
|
|
76
|
+
console.error('Failed to check active subscriptions:', error);
|
|
77
|
+
return false;
|
|
78
78
|
}
|
|
79
|
-
}
|
|
79
|
+
};
|
package/src/utils/error.ts
CHANGED
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
* Error utilities for parsing platform-specific error responses
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {ErrorCode} from '../types';
|
|
6
6
|
|
|
7
7
|
export interface IapError {
|
|
8
|
-
code: string
|
|
9
|
-
message: string
|
|
10
|
-
responseCode?: number
|
|
11
|
-
debugMessage?: string
|
|
12
|
-
productId?: string
|
|
13
|
-
[key: string]: any // Allow additional platform-specific fields
|
|
8
|
+
code: string;
|
|
9
|
+
message: string;
|
|
10
|
+
responseCode?: number;
|
|
11
|
+
debugMessage?: string;
|
|
12
|
+
productId?: string;
|
|
13
|
+
[key: string]: any; // Allow additional platform-specific fields
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/**
|
|
@@ -25,11 +25,11 @@ export interface IapError {
|
|
|
25
25
|
* @returns Parsed error object with code and message
|
|
26
26
|
*/
|
|
27
27
|
export function parseErrorStringToJsonObj(
|
|
28
|
-
errorString: string | Error | unknown
|
|
28
|
+
errorString: string | Error | unknown,
|
|
29
29
|
): IapError {
|
|
30
30
|
// Handle Error objects
|
|
31
31
|
if (errorString instanceof Error) {
|
|
32
|
-
errorString = errorString.message
|
|
32
|
+
errorString = errorString.message;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
// Handle non-string inputs
|
|
@@ -37,35 +37,35 @@ export function parseErrorStringToJsonObj(
|
|
|
37
37
|
return {
|
|
38
38
|
code: ErrorCode.E_UNKNOWN,
|
|
39
39
|
message: 'Unknown error occurred',
|
|
40
|
-
}
|
|
40
|
+
};
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
// Try to parse as JSON first
|
|
44
44
|
try {
|
|
45
|
-
const parsed = JSON.parse(errorString)
|
|
45
|
+
const parsed = JSON.parse(errorString);
|
|
46
46
|
if (typeof parsed === 'object' && parsed !== null) {
|
|
47
47
|
// Ensure it has at least code and message
|
|
48
48
|
return {
|
|
49
49
|
code: parsed.code || ErrorCode.E_UNKNOWN,
|
|
50
50
|
message: parsed.message || errorString,
|
|
51
51
|
...parsed,
|
|
52
|
-
}
|
|
52
|
+
};
|
|
53
53
|
}
|
|
54
54
|
} catch {
|
|
55
55
|
// Not JSON, continue with other formats
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
// Try to parse "CODE: message" format
|
|
59
|
-
const colonIndex = errorString.indexOf(':')
|
|
59
|
+
const colonIndex = errorString.indexOf(':');
|
|
60
60
|
if (colonIndex > 0 && colonIndex < 50) {
|
|
61
61
|
// Reasonable position for error code
|
|
62
|
-
const potentialCode = errorString.substring(0, colonIndex).trim()
|
|
62
|
+
const potentialCode = errorString.substring(0, colonIndex).trim();
|
|
63
63
|
// Check if it looks like an error code (starts with E_ or contains uppercase)
|
|
64
64
|
if (potentialCode.startsWith('E_') || /^[A-Z_]+$/.test(potentialCode)) {
|
|
65
65
|
return {
|
|
66
66
|
code: potentialCode,
|
|
67
67
|
message: errorString.substring(colonIndex + 1).trim(),
|
|
68
|
-
}
|
|
68
|
+
};
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
|
|
@@ -73,7 +73,7 @@ export function parseErrorStringToJsonObj(
|
|
|
73
73
|
return {
|
|
74
74
|
code: ErrorCode.E_UNKNOWN,
|
|
75
75
|
message: errorString,
|
|
76
|
-
}
|
|
76
|
+
};
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
/**
|
|
@@ -82,16 +82,16 @@ export function parseErrorStringToJsonObj(
|
|
|
82
82
|
* @returns true if the error is a user cancellation
|
|
83
83
|
*/
|
|
84
84
|
export function isUserCancelledError(
|
|
85
|
-
error: IapError | string | Error | unknown
|
|
85
|
+
error: IapError | string | Error | unknown,
|
|
86
86
|
): boolean {
|
|
87
87
|
const errorObj =
|
|
88
88
|
typeof error === 'object' && error !== null && 'code' in error
|
|
89
89
|
? (error as IapError)
|
|
90
|
-
: parseErrorStringToJsonObj(error)
|
|
90
|
+
: parseErrorStringToJsonObj(error);
|
|
91
91
|
|
|
92
92
|
return (
|
|
93
93
|
errorObj.code === ErrorCode.E_USER_CANCELLED ||
|
|
94
94
|
errorObj.code === 'E_USER_CANCELED' || // Alternative spelling
|
|
95
95
|
errorObj.responseCode === 1
|
|
96
|
-
) // Android BillingClient.BillingResponseCode.USER_CANCELED
|
|
96
|
+
); // Android BillingClient.BillingResponseCode.USER_CANCELED
|
|
97
97
|
}
|