react-native-iap 15.3.6 → 15.4.0-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/README.md +1 -1
- package/android/build.gradle +13 -5
- package/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt +19 -6
- package/ios/HybridRnIap.swift +13 -1
- package/lib/module/index.js +56 -16
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.kepler.js +170 -0
- package/lib/module/index.kepler.js.map +1 -0
- package/lib/module/types/amazon-devices-kepler/index.d.js +2 -0
- package/lib/module/types/amazon-devices-kepler/index.d.js.map +1 -0
- package/lib/module/types.js +5 -2
- package/lib/module/types.js.map +1 -1
- package/lib/module/utils/error.js +2 -2
- package/lib/module/utils/error.js.map +1 -1
- package/lib/module/utils/type-bridge.js +4 -1
- package/lib/module/utils/type-bridge.js.map +1 -1
- package/lib/module/vega-adapter.js +981 -0
- package/lib/module/vega-adapter.js.map +1 -0
- package/lib/module/vega.js +10 -0
- package/lib/module/vega.js.map +1 -0
- package/lib/module/vega.kepler.js +18 -0
- package/lib/module/vega.kepler.js.map +1 -0
- package/lib/typescript/src/index.d.ts +9 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/index.kepler.d.ts +55 -0
- package/lib/typescript/src/index.kepler.d.ts.map +1 -0
- package/lib/typescript/src/specs/RnIap.nitro.d.ts +10 -1
- package/lib/typescript/src/specs/RnIap.nitro.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +16 -3
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/utils/type-bridge.d.ts.map +1 -1
- package/lib/typescript/src/vega-adapter.d.ts +76 -0
- package/lib/typescript/src/vega-adapter.d.ts.map +1 -0
- package/lib/typescript/src/vega.d.ts +4 -0
- package/lib/typescript/src/vega.d.ts.map +1 -0
- package/lib/typescript/src/vega.kepler.d.ts +4 -0
- package/lib/typescript/src/vega.kepler.d.ts.map +1 -0
- package/nitrogen/generated/android/NitroIap+autolinking.cmake +1 -0
- package/nitrogen/generated/android/c++/JHybridRnIapSpec.cpp +5 -0
- package/nitrogen/generated/android/c++/JIapStore.hpp +3 -0
- package/nitrogen/generated/android/c++/JNitroVerifyPurchaseWithIapkitAmazonProps.hpp +71 -0
- package/nitrogen/generated/android/c++/JNitroVerifyPurchaseWithIapkitProps.hpp +9 -1
- package/nitrogen/generated/android/c++/JNitroVerifyPurchaseWithProviderProps.hpp +4 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_NitroVerifyPurchaseWithIapkitAmazonProps.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_NitroVerifyPurchaseWithIapkitAmazonProps.hpp +75 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_NitroVerifyPurchaseWithIapkitProps.hpp +4 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/IapStore.kt +2 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroVerifyPurchaseWithIapkitAmazonProps.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroVerifyPurchaseWithIapkitProps.kt +5 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/Variant_NullType_NitroVerifyPurchaseWithIapkitAmazonProps.kt +53 -0
- package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Bridge.hpp +47 -0
- package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Umbrella.hpp +3 -0
- package/nitrogen/generated/ios/c++/HybridRnIapSpecSwift.hpp +3 -0
- package/nitrogen/generated/ios/swift/IapStore.swift +4 -0
- package/nitrogen/generated/ios/swift/NitroVerifyPurchaseWithIapkitAmazonProps.swift +103 -0
- package/nitrogen/generated/ios/swift/NitroVerifyPurchaseWithIapkitProps.swift +38 -1
- package/nitrogen/generated/ios/swift/Variant_NullType_NitroVerifyPurchaseWithIapkitAmazonProps.swift +18 -0
- package/nitrogen/generated/shared/c++/IapStore.hpp +4 -0
- package/nitrogen/generated/shared/c++/NitroVerifyPurchaseWithIapkitAmazonProps.hpp +94 -0
- package/nitrogen/generated/shared/c++/NitroVerifyPurchaseWithIapkitProps.hpp +8 -1
- package/openiap-versions.json +2 -2
- package/package.json +19 -12
- package/src/index.kepler.ts +311 -0
- package/src/index.ts +65 -19
- package/src/specs/RnIap.nitro.ts +13 -2
- package/src/types/amazon-devices-kepler/index.d.ts +14 -0
- package/src/types.ts +17 -3
- package/src/utils/error.ts +2 -2
- package/src/utils/type-bridge.ts +4 -1
- package/src/vega-adapter.ts +1503 -0
- package/src/vega.kepler.ts +21 -0
- package/src/vega.ts +10 -0
- package/android/src/test/java/com/margelo/nitro/iap/ListenerThreadSafetyTest.kt +0 -154
- package/android/src/test/java/com/margelo/nitro/iap/OpenIapExceptionTest.kt +0 -93
- package/android/src/test/java/com/margelo/nitro/iap/ProductQueryHelpersTest.kt +0 -140
- package/app.plugin.js +0 -1
- package/lib/typescript/plugin/src/withIAP.d.ts +0 -48
- package/lib/typescript/plugin/src/withIAP.d.ts.map +0 -1
- package/plugin/build/withIAP.d.ts +0 -47
- package/plugin/build/withIAP.js +0 -314
- package/plugin/src/withIAP.ts +0 -500
- package/plugin/tsconfig.json +0 -18
- package/plugin/tsconfig.tsbuildinfo +0 -1
package/package.json
CHANGED
|
@@ -1,24 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-iap",
|
|
3
|
-
"version": "15.
|
|
3
|
+
"version": "15.4.0-rc.2",
|
|
4
4
|
"description": "React Native In-App Purchases module for iOS and Android using Nitro",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": {
|
|
9
9
|
"source": "./src/index.ts",
|
|
10
|
+
"react-native": "./src/index.ts",
|
|
10
11
|
"types": "./lib/typescript/src/index.d.ts",
|
|
11
|
-
"default": "./lib/module/index.js"
|
|
12
|
-
"react-native": "./src/index.ts"
|
|
12
|
+
"default": "./lib/module/index.js"
|
|
13
13
|
},
|
|
14
|
-
"./plugin": "./app.plugin.js",
|
|
15
|
-
"./app.plugin.js": "./app.plugin.js",
|
|
16
14
|
"./package.json": "./package.json"
|
|
17
15
|
},
|
|
18
16
|
"files": [
|
|
19
17
|
"src",
|
|
20
18
|
"lib",
|
|
21
|
-
"plugin",
|
|
22
19
|
"android",
|
|
23
20
|
"ios",
|
|
24
21
|
"cpp",
|
|
@@ -26,7 +23,6 @@
|
|
|
26
23
|
"nitro.json",
|
|
27
24
|
"openiap-versions.json",
|
|
28
25
|
"*.podspec",
|
|
29
|
-
"app.plugin.js",
|
|
30
26
|
"react-native.config.js",
|
|
31
27
|
"!ios/build",
|
|
32
28
|
"!android/build",
|
|
@@ -34,13 +30,15 @@
|
|
|
34
30
|
"!android/gradlew",
|
|
35
31
|
"!android/gradlew.bat",
|
|
36
32
|
"!android/local.properties",
|
|
33
|
+
"!android/src/androidTest",
|
|
34
|
+
"!android/src/test",
|
|
37
35
|
"!**/__tests__",
|
|
38
36
|
"!**/__fixtures__",
|
|
39
37
|
"!**/__mocks__",
|
|
38
|
+
"!**/*.tsbuildinfo",
|
|
40
39
|
"!**/.*"
|
|
41
40
|
],
|
|
42
41
|
"scripts": {
|
|
43
|
-
"build:plugin": "tsc --build plugin",
|
|
44
42
|
"example": "yarn workspace rn-iap-example",
|
|
45
43
|
"example:ios": "yarn workspace rn-iap-example ios",
|
|
46
44
|
"example:android": "yarn workspace rn-iap-example android",
|
|
@@ -49,21 +47,20 @@
|
|
|
49
47
|
"typecheck:lib": "yarn tsc --noEmit",
|
|
50
48
|
"clean": "rm -rf android/build node_modules/**/android/build lib nitrogen/generated",
|
|
51
49
|
"lint": "eslint --ext .ts,.tsx,.js,.jsx src",
|
|
52
|
-
"lint:eslint": "eslint --fix 'src/**/*.{ts,tsx}'
|
|
50
|
+
"lint:eslint": "eslint --fix 'src/**/*.{ts,tsx}'",
|
|
53
51
|
"lint:prettier": "prettier --write \"**/*.{md,js,jsx,ts,tsx}\"",
|
|
54
52
|
"lint:tsc": "tsc -p tsconfig.json --noEmit --skipLibCheck",
|
|
55
53
|
"lint:ci": "yarn lint:tsc && yarn lint:eslint && yarn lint:prettier",
|
|
56
|
-
"prepare": "npx tsx scripts/check-nitro-versions.ts && bob build && yarn nitrogen
|
|
54
|
+
"prepare": "npx tsx scripts/check-nitro-versions.ts && bob build && yarn nitrogen",
|
|
57
55
|
"nitrogen": "node --stack-size=65536 node_modules/nitrogen/lib/index.js",
|
|
58
56
|
"specs": "yarn nitrogen --logLevel=\"debug\"",
|
|
59
57
|
"test": "jest --coverage",
|
|
60
58
|
"test:library": "jest --coverage",
|
|
61
59
|
"test:example": "yarn workspace rn-iap-example test --coverage",
|
|
62
|
-
"test:plugin": "jest plugin --coverage",
|
|
63
60
|
"test:all": "yarn test:library && yarn test:example",
|
|
64
61
|
"test:ci": "jest --maxWorkers=2 --coverage",
|
|
65
62
|
"test:ci:example": "yarn workspace rn-iap-example test --coverage",
|
|
66
|
-
"verify:consumer-install": "node ../../scripts/verify-npm-consumer-install.mjs --package . --package-name react-native-iap --required openiap-versions.json --required lib/module/index.js --required lib/typescript/src/index.d.ts --required android/build.gradle --required NitroIap.podspec --required
|
|
63
|
+
"verify:consumer-install": "node ../../scripts/verify-npm-consumer-install.mjs --package . --package-name react-native-iap --required openiap-versions.json --required lib/module/index.js --required lib/typescript/src/index.d.ts --required android/build.gradle --required NitroIap.podspec --required nitro.json",
|
|
67
64
|
"prepare:husky": "husky install",
|
|
68
65
|
"precommit": "lint-staged",
|
|
69
66
|
"ci:check": "./scripts/ci-check.sh",
|
|
@@ -118,10 +115,20 @@
|
|
|
118
115
|
"typescript": "^5.9.2"
|
|
119
116
|
},
|
|
120
117
|
"peerDependencies": {
|
|
118
|
+
"@amazon-devices/keplerscript-appstore-iap-lib": "~2.12.13",
|
|
119
|
+
"@amazon-devices/package-manager-lib": "~1.0.1767254401",
|
|
121
120
|
"react": "*",
|
|
122
121
|
"react-native": "*",
|
|
123
122
|
"react-native-nitro-modules": "^0.35.0"
|
|
124
123
|
},
|
|
124
|
+
"peerDependenciesMeta": {
|
|
125
|
+
"@amazon-devices/keplerscript-appstore-iap-lib": {
|
|
126
|
+
"optional": true
|
|
127
|
+
},
|
|
128
|
+
"@amazon-devices/package-manager-lib": {
|
|
129
|
+
"optional": true
|
|
130
|
+
}
|
|
131
|
+
},
|
|
125
132
|
"workspaces": [
|
|
126
133
|
"example"
|
|
127
134
|
],
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import {getVegaIapModule} from './vega';
|
|
2
|
+
import type {
|
|
3
|
+
MutationField,
|
|
4
|
+
Product,
|
|
5
|
+
ProductQueryType,
|
|
6
|
+
ProductSubscription,
|
|
7
|
+
Purchase,
|
|
8
|
+
PurchaseError,
|
|
9
|
+
PurchaseUpdatedListenerOptions,
|
|
10
|
+
QueryField,
|
|
11
|
+
RequestPurchasePropsByPlatforms,
|
|
12
|
+
RequestSubscriptionPropsByPlatforms,
|
|
13
|
+
} from './types';
|
|
14
|
+
import type {
|
|
15
|
+
NitroAvailablePurchasesOptions,
|
|
16
|
+
NitroFinishTransactionParams,
|
|
17
|
+
NitroProduct,
|
|
18
|
+
NitroPurchase,
|
|
19
|
+
NitroPurchaseRequest,
|
|
20
|
+
} from './specs/RnIap.nitro';
|
|
21
|
+
import {
|
|
22
|
+
convertNitroProductToProduct,
|
|
23
|
+
convertNitroPurchaseToPurchase,
|
|
24
|
+
convertProductToProductSubscription,
|
|
25
|
+
validateNitroProduct,
|
|
26
|
+
validateNitroPurchase,
|
|
27
|
+
} from './utils/type-bridge';
|
|
28
|
+
|
|
29
|
+
export * from './types';
|
|
30
|
+
export * from './utils/error';
|
|
31
|
+
export * from './vega';
|
|
32
|
+
export {useIAP, type UseIapOptions} from './hooks/useIAP';
|
|
33
|
+
export {connectWebhookStream, parseWebhookEventData} from './webhook-client';
|
|
34
|
+
export {kitApi, KitApiError} from './kit-api';
|
|
35
|
+
|
|
36
|
+
export type ProductTypeInput = 'inapp' | 'in-app' | 'subs';
|
|
37
|
+
|
|
38
|
+
export interface EventSubscription {
|
|
39
|
+
remove(): void;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type VegaModuleExtras = {
|
|
43
|
+
acknowledgePurchaseAndroid(purchaseToken: string): Promise<boolean>;
|
|
44
|
+
consumePurchaseAndroid(purchaseToken: string): Promise<boolean>;
|
|
45
|
+
restorePurchases?: () => Promise<void>;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const unsupported = (feature: string): never => {
|
|
49
|
+
throw new Error(`${feature} is not supported on Amazon Vega.`);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const getModule = () => {
|
|
53
|
+
const module = getVegaIapModule();
|
|
54
|
+
if (!module) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
'Amazon Vega IAP module is unavailable. Install @amazon-devices/keplerscript-appstore-iap-lib in the Vega app target and build with the React Native for Vega kepler platform.',
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return module;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const getVegaModule = () =>
|
|
63
|
+
getModule() as ReturnType<typeof getModule> & VegaModuleExtras;
|
|
64
|
+
|
|
65
|
+
const normalizeProductQueryType = (
|
|
66
|
+
type?: ProductQueryType | ProductTypeInput | null,
|
|
67
|
+
): ProductTypeInput | 'all' => {
|
|
68
|
+
if (type === 'subs') return 'subs';
|
|
69
|
+
if (type === 'all') return 'all';
|
|
70
|
+
return 'inapp';
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const mapProducts = (
|
|
74
|
+
nitroProducts: NitroProduct[],
|
|
75
|
+
type: ProductTypeInput | 'all',
|
|
76
|
+
) => {
|
|
77
|
+
const converted = nitroProducts
|
|
78
|
+
.filter(validateNitroProduct)
|
|
79
|
+
.map(convertNitroProductToProduct);
|
|
80
|
+
|
|
81
|
+
if (type === 'subs') {
|
|
82
|
+
return converted.map(convertProductToProductSubscription);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return converted;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export const isNitroReady = (): boolean => false;
|
|
89
|
+
export const isTVOS = (): boolean => false;
|
|
90
|
+
export const isMacOS = (): boolean => false;
|
|
91
|
+
export const isStandardIOS = (): boolean => false;
|
|
92
|
+
|
|
93
|
+
export const initConnection: MutationField<'initConnection'> = async (
|
|
94
|
+
config,
|
|
95
|
+
) => {
|
|
96
|
+
return getModule().initConnection(config ?? null);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export const endConnection: MutationField<'endConnection'> = async () => {
|
|
100
|
+
return getModule().endConnection();
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export const fetchProducts: QueryField<'fetchProducts'> = async (request) => {
|
|
104
|
+
const {skus, type} = request;
|
|
105
|
+
const normalizedType = normalizeProductQueryType(type);
|
|
106
|
+
const nitroProducts = await getModule().fetchProducts(skus, normalizedType);
|
|
107
|
+
return mapProducts(nitroProducts, normalizedType) as
|
|
108
|
+
| Product[]
|
|
109
|
+
| ProductSubscription[];
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export const requestPurchase: MutationField<'requestPurchase'> = async (
|
|
113
|
+
request,
|
|
114
|
+
) => {
|
|
115
|
+
const perPlatformRequest = request.request as
|
|
116
|
+
| RequestPurchasePropsByPlatforms
|
|
117
|
+
| RequestSubscriptionPropsByPlatforms
|
|
118
|
+
| undefined;
|
|
119
|
+
const androidRequest =
|
|
120
|
+
perPlatformRequest?.google ?? perPlatformRequest?.android;
|
|
121
|
+
|
|
122
|
+
if (!androidRequest?.skus?.length) {
|
|
123
|
+
throw new Error(
|
|
124
|
+
'Invalid request for Amazon Vega. The `request.google.skus` or `request.android.skus` property is required and must be a non-empty array.',
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const nitroRequest: NitroPurchaseRequest = {
|
|
129
|
+
google: androidRequest,
|
|
130
|
+
android: androidRequest,
|
|
131
|
+
};
|
|
132
|
+
const result = await getModule().requestPurchase(nitroRequest);
|
|
133
|
+
if (!Array.isArray(result)) return null;
|
|
134
|
+
const purchases = result as unknown as NitroPurchase[];
|
|
135
|
+
return purchases
|
|
136
|
+
.filter(validateNitroPurchase)
|
|
137
|
+
.map((purchase) => convertNitroPurchaseToPurchase(purchase));
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
export const getAvailablePurchases: QueryField<
|
|
141
|
+
'getAvailablePurchases'
|
|
142
|
+
> = async (options) => {
|
|
143
|
+
const nitroOptions: NitroAvailablePurchasesOptions = {
|
|
144
|
+
android: {
|
|
145
|
+
includeSuspended: options?.includeSuspendedAndroid ?? false,
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
return getModule()
|
|
149
|
+
.getAvailablePurchases(nitroOptions)
|
|
150
|
+
.then((purchases) =>
|
|
151
|
+
purchases
|
|
152
|
+
.filter(validateNitroPurchase)
|
|
153
|
+
.map(convertNitroPurchaseToPurchase),
|
|
154
|
+
);
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export const finishTransaction: MutationField<'finishTransaction'> = async (
|
|
158
|
+
args,
|
|
159
|
+
) => {
|
|
160
|
+
const token = args.purchase.purchaseToken ?? undefined;
|
|
161
|
+
if (!token) {
|
|
162
|
+
throw new Error('purchaseToken required to finish Amazon Vega transaction');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const params: NitroFinishTransactionParams = {
|
|
166
|
+
android: {
|
|
167
|
+
purchaseToken: token,
|
|
168
|
+
isConsumable: args.isConsumable ?? false,
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
await getModule().finishTransaction(params);
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
export const restorePurchases: MutationField<'restorePurchases'> = async () => {
|
|
175
|
+
await getVegaModule().restorePurchases?.();
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
export const getActiveSubscriptions: QueryField<
|
|
179
|
+
'getActiveSubscriptions'
|
|
180
|
+
> = async (args) => {
|
|
181
|
+
return getModule().getActiveSubscriptions(args ?? undefined);
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
export const hasActiveSubscriptions: QueryField<
|
|
185
|
+
'hasActiveSubscriptions'
|
|
186
|
+
> = async (args) => {
|
|
187
|
+
return getModule().hasActiveSubscriptions(args ?? undefined);
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
export const purchaseUpdatedListener = (
|
|
191
|
+
listener: (purchase: Purchase) => void,
|
|
192
|
+
options?: PurchaseUpdatedListenerOptions | null,
|
|
193
|
+
): EventSubscription => {
|
|
194
|
+
const token = getModule().addPurchaseUpdatedListener((purchase) => {
|
|
195
|
+
if (validateNitroPurchase(purchase)) {
|
|
196
|
+
listener(convertNitroPurchaseToPurchase(purchase));
|
|
197
|
+
}
|
|
198
|
+
}, options ?? undefined);
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
remove: () => {
|
|
202
|
+
if (typeof token === 'number') {
|
|
203
|
+
getModule().removePurchaseUpdatedListener(token);
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
export const purchaseErrorListener = (
|
|
210
|
+
listener: (error: PurchaseError) => void,
|
|
211
|
+
): EventSubscription => {
|
|
212
|
+
const nativeListener = (error: {code?: string; message?: string}) => {
|
|
213
|
+
listener({
|
|
214
|
+
code: (error.code ?? 'service-error') as PurchaseError['code'],
|
|
215
|
+
message: error.message ?? 'Amazon Vega purchase failed',
|
|
216
|
+
});
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
getModule().addPurchaseErrorListener(nativeListener);
|
|
220
|
+
return {
|
|
221
|
+
remove: () => getModule().removePurchaseErrorListener(nativeListener),
|
|
222
|
+
};
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
export const getStorefront: QueryField<'getStorefront'> = async () => {
|
|
226
|
+
return getModule().getStorefront();
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
export const verifyPurchaseWithProvider: MutationField<
|
|
230
|
+
'verifyPurchaseWithProvider'
|
|
231
|
+
> = async (params) => {
|
|
232
|
+
return getModule().verifyPurchaseWithProvider(params) as ReturnType<
|
|
233
|
+
MutationField<'verifyPurchaseWithProvider'>
|
|
234
|
+
>;
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
export const validateReceipt: MutationField<'validateReceipt'> = async () => {
|
|
238
|
+
return unsupported('validateReceipt');
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
export const verifyPurchase: MutationField<'verifyPurchase'> = validateReceipt;
|
|
242
|
+
export const validateReceiptIOS: QueryField<'validateReceiptIOS'> = async () =>
|
|
243
|
+
unsupported('validateReceiptIOS');
|
|
244
|
+
export const syncIOS: MutationField<'syncIOS'> = async () =>
|
|
245
|
+
unsupported('syncIOS');
|
|
246
|
+
export const getAppTransactionIOS: QueryField<
|
|
247
|
+
'getAppTransactionIOS'
|
|
248
|
+
> = async () => null;
|
|
249
|
+
export const getPromotedProductIOS: QueryField<
|
|
250
|
+
'getPromotedProductIOS'
|
|
251
|
+
> = async () => null;
|
|
252
|
+
export const requestPromotedProductIOS = getPromotedProductIOS;
|
|
253
|
+
export const requestPurchaseOnPromotedProductIOS = async (): Promise<void> =>
|
|
254
|
+
unsupported('requestPurchaseOnPromotedProductIOS');
|
|
255
|
+
export const showManageSubscriptionsIOS: MutationField<
|
|
256
|
+
'showManageSubscriptionsIOS'
|
|
257
|
+
> = async () => [];
|
|
258
|
+
export const presentCodeRedemptionSheetIOS: MutationField<
|
|
259
|
+
'presentCodeRedemptionSheetIOS'
|
|
260
|
+
> = async () => false;
|
|
261
|
+
export const presentExternalPurchaseLinkIOS: MutationField<
|
|
262
|
+
'presentExternalPurchaseLinkIOS'
|
|
263
|
+
> = async () => unsupported('presentExternalPurchaseLinkIOS');
|
|
264
|
+
export const deepLinkToSubscriptions: MutationField<
|
|
265
|
+
'deepLinkToSubscriptions'
|
|
266
|
+
> = async () => unsupported('deepLinkToSubscriptions');
|
|
267
|
+
export const promotedProductListenerIOS = (): EventSubscription => ({
|
|
268
|
+
remove: () => {},
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
export const acknowledgePurchaseAndroid: MutationField<
|
|
272
|
+
'acknowledgePurchaseAndroid'
|
|
273
|
+
> = async (purchaseToken) => {
|
|
274
|
+
return getVegaModule().acknowledgePurchaseAndroid(purchaseToken);
|
|
275
|
+
};
|
|
276
|
+
export const consumePurchaseAndroid: MutationField<
|
|
277
|
+
'consumePurchaseAndroid'
|
|
278
|
+
> = async (purchaseToken) => {
|
|
279
|
+
return getVegaModule().consumePurchaseAndroid(purchaseToken);
|
|
280
|
+
};
|
|
281
|
+
export const acknowledgePurchase = acknowledgePurchaseAndroid;
|
|
282
|
+
export const consumePurchase = consumePurchaseAndroid;
|
|
283
|
+
|
|
284
|
+
export const checkAlternativeBillingAvailabilityAndroid: MutationField<
|
|
285
|
+
'checkAlternativeBillingAvailabilityAndroid'
|
|
286
|
+
> = async () => unsupported('checkAlternativeBillingAvailabilityAndroid');
|
|
287
|
+
export const showAlternativeBillingDialogAndroid: MutationField<
|
|
288
|
+
'showAlternativeBillingDialogAndroid'
|
|
289
|
+
> = async () => unsupported('showAlternativeBillingDialogAndroid');
|
|
290
|
+
export const createAlternativeBillingTokenAndroid: MutationField<
|
|
291
|
+
'createAlternativeBillingTokenAndroid'
|
|
292
|
+
> = async () => unsupported('createAlternativeBillingTokenAndroid');
|
|
293
|
+
export const isBillingProgramAvailableAndroid: MutationField<
|
|
294
|
+
'isBillingProgramAvailableAndroid'
|
|
295
|
+
> = async () => unsupported('isBillingProgramAvailableAndroid');
|
|
296
|
+
export const launchExternalLinkAndroid: MutationField<
|
|
297
|
+
'launchExternalLinkAndroid'
|
|
298
|
+
> = async () => unsupported('launchExternalLinkAndroid');
|
|
299
|
+
export const createBillingProgramReportingDetailsAndroid: MutationField<
|
|
300
|
+
'createBillingProgramReportingDetailsAndroid'
|
|
301
|
+
> = async () => unsupported('createBillingProgramReportingDetailsAndroid');
|
|
302
|
+
export const userChoiceBillingListenerAndroid = (): EventSubscription => ({
|
|
303
|
+
remove: () => {},
|
|
304
|
+
});
|
|
305
|
+
export const developerProvidedBillingListenerAndroid =
|
|
306
|
+
(): EventSubscription => ({
|
|
307
|
+
remove: () => {},
|
|
308
|
+
});
|
|
309
|
+
export const subscriptionBillingIssueListener = (): EventSubscription => ({
|
|
310
|
+
remove: () => {},
|
|
311
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -64,6 +64,7 @@ import {
|
|
|
64
64
|
import {RnIapConsole} from './utils/debug';
|
|
65
65
|
import {getSuccessFromPurchaseVariant} from './utils/purchase';
|
|
66
66
|
import {parseAppTransactionPayload} from './utils';
|
|
67
|
+
import {getVegaIapModule, isVegaOS} from './vega';
|
|
67
68
|
|
|
68
69
|
// ------------------------------
|
|
69
70
|
// Billing Programs API (Android 8.2.0+)
|
|
@@ -72,9 +73,7 @@ import {parseAppTransactionPayload} from './utils';
|
|
|
72
73
|
// Note: BillingProgramAndroid, ExternalLinkLaunchModeAndroid, and ExternalLinkTypeAndroid
|
|
73
74
|
// are exported from './types' (auto-generated from openiap-gql).
|
|
74
75
|
// Import them here for use in this file's interfaces and functions.
|
|
75
|
-
import type {
|
|
76
|
-
BillingProgramAndroid,
|
|
77
|
-
} from './types';
|
|
76
|
+
import type {BillingProgramAndroid} from './types';
|
|
78
77
|
|
|
79
78
|
// Export all types
|
|
80
79
|
export type {
|
|
@@ -85,6 +84,7 @@ export type {
|
|
|
85
84
|
} from './specs/RnIap.nitro';
|
|
86
85
|
export * from './types';
|
|
87
86
|
export * from './utils/error';
|
|
87
|
+
export * from './vega';
|
|
88
88
|
|
|
89
89
|
export type ProductTypeInput = 'inapp' | 'in-app' | 'subs';
|
|
90
90
|
|
|
@@ -178,6 +178,10 @@ let iapRef: RnIap | null = null;
|
|
|
178
178
|
*/
|
|
179
179
|
export const isNitroReady = (): boolean => {
|
|
180
180
|
if (iapRef) return true;
|
|
181
|
+
if (isVegaOS()) {
|
|
182
|
+
iapRef = getVegaIapModule();
|
|
183
|
+
return Boolean(iapRef);
|
|
184
|
+
}
|
|
181
185
|
try {
|
|
182
186
|
iapRef = NitroModules.createHybridObject<RnIap>('RnIap');
|
|
183
187
|
return true;
|
|
@@ -212,10 +216,25 @@ export const isStandardIOS = (): boolean => {
|
|
|
212
216
|
return Platform.OS === 'ios' && !isTVOS() && !isMacOS();
|
|
213
217
|
};
|
|
214
218
|
|
|
219
|
+
const isAndroidStoreRuntime = (): boolean => {
|
|
220
|
+
return Platform.OS === 'android' || isVegaOS();
|
|
221
|
+
};
|
|
222
|
+
|
|
215
223
|
const IAP = {
|
|
216
224
|
get instance(): RnIap {
|
|
217
225
|
if (iapRef) return iapRef;
|
|
218
226
|
|
|
227
|
+
if (isVegaOS()) {
|
|
228
|
+
const vegaModule = getVegaIapModule();
|
|
229
|
+
if (!vegaModule) {
|
|
230
|
+
throw new Error(
|
|
231
|
+
'Amazon Vega IAP module is unavailable. Install @amazon-devices/keplerscript-appstore-iap-lib in the Vega app target and build with the React Native for Vega kepler platform.',
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
iapRef = vegaModule;
|
|
235
|
+
return iapRef;
|
|
236
|
+
}
|
|
237
|
+
|
|
219
238
|
// Attempt to create the HybridObject and map common Nitro/JSI readiness errors
|
|
220
239
|
try {
|
|
221
240
|
iapRef = NitroModules.createHybridObject<RnIap>('RnIap');
|
|
@@ -754,7 +773,7 @@ function tryAttachSubscriptionBillingIssueNative(): void {
|
|
|
754
773
|
const msg = toErrorMessage(e);
|
|
755
774
|
if (msg.includes('Nitro runtime not installed')) {
|
|
756
775
|
RnIapConsole.warn(
|
|
757
|
-
'[subscriptionBillingIssueListener] Nitro not ready yet; will retry
|
|
776
|
+
'[subscriptionBillingIssueListener] Nitro not ready yet; will retry after initConnection()',
|
|
758
777
|
);
|
|
759
778
|
} else {
|
|
760
779
|
throw e;
|
|
@@ -863,7 +882,7 @@ export const fetchProducts: QueryField<'fetchProducts'> = async (request) => {
|
|
|
863
882
|
// item.type === 'subs' case
|
|
864
883
|
// For Android, check if subscription items have actual offers
|
|
865
884
|
if (
|
|
866
|
-
|
|
885
|
+
isAndroidStoreRuntime() &&
|
|
867
886
|
item.platform === 'android' &&
|
|
868
887
|
item.type === 'subs'
|
|
869
888
|
) {
|
|
@@ -984,11 +1003,26 @@ export const getAvailablePurchases: QueryField<
|
|
|
984
1003
|
}
|
|
985
1004
|
|
|
986
1005
|
return validPurchases.map(convertNitroPurchaseToPurchase);
|
|
987
|
-
} else if (
|
|
988
|
-
// For Android, we need to call twice for inapp and subs
|
|
1006
|
+
} else if (isAndroidStoreRuntime()) {
|
|
989
1007
|
const includeSuspended = Boolean(
|
|
990
1008
|
options?.includeSuspendedAndroid ?? false,
|
|
991
1009
|
);
|
|
1010
|
+
|
|
1011
|
+
if (isVegaOS()) {
|
|
1012
|
+
const nitroPurchases = await IAP.instance.getAvailablePurchases({
|
|
1013
|
+
android: {includeSuspended},
|
|
1014
|
+
});
|
|
1015
|
+
const validPurchases = nitroPurchases.filter(validateNitroPurchase);
|
|
1016
|
+
if (validPurchases.length !== nitroPurchases.length) {
|
|
1017
|
+
RnIapConsole.warn(
|
|
1018
|
+
`[getAvailablePurchases] Some Vega purchases failed validation: ${nitroPurchases.length - validPurchases.length} invalid`,
|
|
1019
|
+
);
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
return validPurchases.map(convertNitroPurchaseToPurchase);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
// For Android Play/Horizon/Fire OS, query in-app items and subscriptions separately.
|
|
992
1026
|
const inappNitroPurchases = await IAP.instance.getAvailablePurchases({
|
|
993
1027
|
android: {type: 'inapp', includeSuspended},
|
|
994
1028
|
});
|
|
@@ -1088,9 +1122,9 @@ export const getStorefrontIOS: QueryField<'getStorefrontIOS'> = async () => {
|
|
|
1088
1122
|
* @see {@link https://openiap.dev/docs/apis/get-storefront}
|
|
1089
1123
|
*/
|
|
1090
1124
|
export const getStorefront: QueryField<'getStorefront'> = async () => {
|
|
1091
|
-
if (Platform.OS !== 'ios' &&
|
|
1125
|
+
if (Platform.OS !== 'ios' && !isAndroidStoreRuntime()) {
|
|
1092
1126
|
RnIapConsole.warn(
|
|
1093
|
-
'[getStorefront] Storefront lookup is only supported on iOS and
|
|
1127
|
+
'[getStorefront] Storefront lookup is only supported on iOS, Android, and Vega OS.',
|
|
1094
1128
|
);
|
|
1095
1129
|
return '';
|
|
1096
1130
|
}
|
|
@@ -1598,9 +1632,13 @@ export const initConnection: MutationField<'initConnection'> = async (
|
|
|
1598
1632
|
config,
|
|
1599
1633
|
) => {
|
|
1600
1634
|
try {
|
|
1601
|
-
|
|
1635
|
+
const result = await IAP.instance.initConnection(
|
|
1602
1636
|
config as Record<string, unknown> | undefined,
|
|
1603
1637
|
);
|
|
1638
|
+
if (subscriptionBillingIssueJsListeners.size > 0) {
|
|
1639
|
+
tryAttachSubscriptionBillingIssueNative();
|
|
1640
|
+
}
|
|
1641
|
+
return result;
|
|
1604
1642
|
} catch (error) {
|
|
1605
1643
|
const parsedError = parseErrorAndLogIfNeeded(
|
|
1606
1644
|
'Failed to initialize IAP connection:',
|
|
@@ -1719,7 +1757,7 @@ export const requestPurchase: MutationField<'requestPurchase'> = async (
|
|
|
1719
1757
|
'Invalid request for iOS. The `sku` property is required.',
|
|
1720
1758
|
);
|
|
1721
1759
|
}
|
|
1722
|
-
} else if (
|
|
1760
|
+
} else if (isAndroidStoreRuntime()) {
|
|
1723
1761
|
// Support both 'google' (recommended) and 'android' (deprecated) fields
|
|
1724
1762
|
const androidRequest =
|
|
1725
1763
|
perPlatformRequest.google ?? perPlatformRequest.android;
|
|
@@ -1787,7 +1825,7 @@ export const requestPurchase: MutationField<'requestPurchase'> = async (
|
|
|
1787
1825
|
// Support both 'google' (recommended) and 'android' (deprecated) fields
|
|
1788
1826
|
const androidRequestSource =
|
|
1789
1827
|
perPlatformRequest.google ?? perPlatformRequest.android;
|
|
1790
|
-
if (
|
|
1828
|
+
if (isAndroidStoreRuntime() && androidRequestSource) {
|
|
1791
1829
|
const androidRequest = isSubs
|
|
1792
1830
|
? (androidRequestSource as RequestSubscriptionAndroidProps)
|
|
1793
1831
|
: (androidRequestSource as RequestPurchaseAndroidProps);
|
|
@@ -1896,7 +1934,7 @@ export const finishTransaction: MutationField<'finishTransaction'> = async (
|
|
|
1896
1934
|
transactionId: purchase.id,
|
|
1897
1935
|
},
|
|
1898
1936
|
};
|
|
1899
|
-
} else if (
|
|
1937
|
+
} else if (isAndroidStoreRuntime()) {
|
|
1900
1938
|
const token = purchase.purchaseToken ?? undefined;
|
|
1901
1939
|
|
|
1902
1940
|
if (!token) {
|
|
@@ -1954,9 +1992,9 @@ export const acknowledgePurchaseAndroid: MutationField<
|
|
|
1954
1992
|
'acknowledgePurchaseAndroid'
|
|
1955
1993
|
> = async (purchaseToken) => {
|
|
1956
1994
|
try {
|
|
1957
|
-
if (
|
|
1995
|
+
if (!isAndroidStoreRuntime()) {
|
|
1958
1996
|
throw new Error(
|
|
1959
|
-
'acknowledgePurchaseAndroid is only available on Android',
|
|
1997
|
+
'acknowledgePurchaseAndroid is only available on Android and Vega OS',
|
|
1960
1998
|
);
|
|
1961
1999
|
}
|
|
1962
2000
|
|
|
@@ -1997,8 +2035,10 @@ export const consumePurchaseAndroid: MutationField<
|
|
|
1997
2035
|
'consumePurchaseAndroid'
|
|
1998
2036
|
> = async (purchaseToken) => {
|
|
1999
2037
|
try {
|
|
2000
|
-
if (
|
|
2001
|
-
throw new Error(
|
|
2038
|
+
if (!isAndroidStoreRuntime()) {
|
|
2039
|
+
throw new Error(
|
|
2040
|
+
'consumePurchaseAndroid is only available on Android and Vega OS',
|
|
2041
|
+
);
|
|
2002
2042
|
}
|
|
2003
2043
|
|
|
2004
2044
|
const result = await IAP.instance.finishTransaction({
|
|
@@ -2221,8 +2261,14 @@ export const validateReceiptIOS: QueryField<'validateReceiptIOS'> = async (
|
|
|
2221
2261
|
* provider: 'iapkit',
|
|
2222
2262
|
* iapkit: {
|
|
2223
2263
|
* apiKey: 'your-api-key',
|
|
2224
|
-
*
|
|
2225
|
-
*
|
|
2264
|
+
* // Choose exactly one store payload.
|
|
2265
|
+
* // apple: { jws: purchase.purchaseToken },
|
|
2266
|
+
* // google: { purchaseToken: purchase.purchaseToken },
|
|
2267
|
+
* amazon: {
|
|
2268
|
+
* userId: amazonUserId,
|
|
2269
|
+
* receiptId: purchase.purchaseToken,
|
|
2270
|
+
* sandbox: __DEV__,
|
|
2271
|
+
* },
|
|
2226
2272
|
* },
|
|
2227
2273
|
* });
|
|
2228
2274
|
* ```
|
package/src/specs/RnIap.nitro.ts
CHANGED
|
@@ -88,7 +88,7 @@ export type IapkitPurchaseState =
|
|
|
88
88
|
|
|
89
89
|
// Store identifier for purchase origin
|
|
90
90
|
// Defined locally for Nitro codegen (not in GQL schema)
|
|
91
|
-
export type IapStore = 'unknown' | 'apple' | 'google' | 'horizon';
|
|
91
|
+
export type IapStore = 'unknown' | 'apple' | 'google' | 'horizon' | 'amazon';
|
|
92
92
|
|
|
93
93
|
// Purchase verification provider selection
|
|
94
94
|
// Defined locally for Nitro codegen (not in GQL schema)
|
|
@@ -149,7 +149,8 @@ export interface NitroReceiptValidationHorizonOptions {
|
|
|
149
149
|
userId: VerifyPurchaseHorizonOptions['userId'];
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
export type NitroPurchaseUpdatedListenerOptions =
|
|
152
|
+
export type NitroPurchaseUpdatedListenerOptions =
|
|
153
|
+
PurchaseUpdatedListenerOptions;
|
|
153
154
|
|
|
154
155
|
export interface NitroReceiptValidationParams {
|
|
155
156
|
apple?: NitroReceiptValidationAppleOptions | null;
|
|
@@ -383,8 +384,18 @@ export interface NitroVerifyPurchaseWithIapkitGoogleProps {
|
|
|
383
384
|
purchaseToken: string;
|
|
384
385
|
}
|
|
385
386
|
|
|
387
|
+
export interface NitroVerifyPurchaseWithIapkitAmazonProps {
|
|
388
|
+
/** Amazon Appstore receipt id returned by PurchaseResponse.getReceipt().getReceiptId(). */
|
|
389
|
+
receiptId: string;
|
|
390
|
+
/** Use Amazon RVS Cloud Sandbox for App Tester receipts. */
|
|
391
|
+
sandbox?: boolean | null;
|
|
392
|
+
/** Amazon Appstore user id returned by PurchaseResponse.getUserData().getUserId(). */
|
|
393
|
+
userId?: string | null;
|
|
394
|
+
}
|
|
395
|
+
|
|
386
396
|
export interface NitroVerifyPurchaseWithIapkitProps {
|
|
387
397
|
apiKey?: string | null;
|
|
398
|
+
amazon?: NitroVerifyPurchaseWithIapkitAmazonProps | null;
|
|
388
399
|
apple?: NitroVerifyPurchaseWithIapkitAppleProps | null;
|
|
389
400
|
google?: NitroVerifyPurchaseWithIapkitGoogleProps | null;
|
|
390
401
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
declare module '@amazon-devices/keplerscript-appstore-iap-lib' {
|
|
2
|
+
export const PurchasingService: {
|
|
3
|
+
getProductData(request: {skus: string[]}): Promise<unknown>;
|
|
4
|
+
getPurchaseUpdates(request: {reset: boolean}): Promise<unknown>;
|
|
5
|
+
getUserData(request: {
|
|
6
|
+
fetchUserProfileAccessConsentStatus: boolean;
|
|
7
|
+
}): Promise<unknown>;
|
|
8
|
+
notifyFulfillment(request: {
|
|
9
|
+
fulfillmentResult: number;
|
|
10
|
+
receiptId: string;
|
|
11
|
+
}): Promise<unknown>;
|
|
12
|
+
purchase(request: {sku: string}): Promise<unknown>;
|
|
13
|
+
};
|
|
14
|
+
}
|