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.
Files changed (83) hide show
  1. package/README.md +1 -1
  2. package/android/build.gradle +13 -5
  3. package/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt +19 -6
  4. package/ios/HybridRnIap.swift +13 -1
  5. package/lib/module/index.js +56 -16
  6. package/lib/module/index.js.map +1 -1
  7. package/lib/module/index.kepler.js +170 -0
  8. package/lib/module/index.kepler.js.map +1 -0
  9. package/lib/module/types/amazon-devices-kepler/index.d.js +2 -0
  10. package/lib/module/types/amazon-devices-kepler/index.d.js.map +1 -0
  11. package/lib/module/types.js +5 -2
  12. package/lib/module/types.js.map +1 -1
  13. package/lib/module/utils/error.js +2 -2
  14. package/lib/module/utils/error.js.map +1 -1
  15. package/lib/module/utils/type-bridge.js +4 -1
  16. package/lib/module/utils/type-bridge.js.map +1 -1
  17. package/lib/module/vega-adapter.js +981 -0
  18. package/lib/module/vega-adapter.js.map +1 -0
  19. package/lib/module/vega.js +10 -0
  20. package/lib/module/vega.js.map +1 -0
  21. package/lib/module/vega.kepler.js +18 -0
  22. package/lib/module/vega.kepler.js.map +1 -0
  23. package/lib/typescript/src/index.d.ts +9 -2
  24. package/lib/typescript/src/index.d.ts.map +1 -1
  25. package/lib/typescript/src/index.kepler.d.ts +55 -0
  26. package/lib/typescript/src/index.kepler.d.ts.map +1 -0
  27. package/lib/typescript/src/specs/RnIap.nitro.d.ts +10 -1
  28. package/lib/typescript/src/specs/RnIap.nitro.d.ts.map +1 -1
  29. package/lib/typescript/src/types.d.ts +16 -3
  30. package/lib/typescript/src/types.d.ts.map +1 -1
  31. package/lib/typescript/src/utils/type-bridge.d.ts.map +1 -1
  32. package/lib/typescript/src/vega-adapter.d.ts +76 -0
  33. package/lib/typescript/src/vega-adapter.d.ts.map +1 -0
  34. package/lib/typescript/src/vega.d.ts +4 -0
  35. package/lib/typescript/src/vega.d.ts.map +1 -0
  36. package/lib/typescript/src/vega.kepler.d.ts +4 -0
  37. package/lib/typescript/src/vega.kepler.d.ts.map +1 -0
  38. package/nitrogen/generated/android/NitroIap+autolinking.cmake +1 -0
  39. package/nitrogen/generated/android/c++/JHybridRnIapSpec.cpp +5 -0
  40. package/nitrogen/generated/android/c++/JIapStore.hpp +3 -0
  41. package/nitrogen/generated/android/c++/JNitroVerifyPurchaseWithIapkitAmazonProps.hpp +71 -0
  42. package/nitrogen/generated/android/c++/JNitroVerifyPurchaseWithIapkitProps.hpp +9 -1
  43. package/nitrogen/generated/android/c++/JNitroVerifyPurchaseWithProviderProps.hpp +4 -0
  44. package/nitrogen/generated/android/c++/JVariant_NullType_NitroVerifyPurchaseWithIapkitAmazonProps.cpp +26 -0
  45. package/nitrogen/generated/android/c++/JVariant_NullType_NitroVerifyPurchaseWithIapkitAmazonProps.hpp +75 -0
  46. package/nitrogen/generated/android/c++/JVariant_NullType_NitroVerifyPurchaseWithIapkitProps.hpp +4 -0
  47. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/IapStore.kt +2 -1
  48. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroVerifyPurchaseWithIapkitAmazonProps.kt +44 -0
  49. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroVerifyPurchaseWithIapkitProps.kt +5 -2
  50. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/Variant_NullType_NitroVerifyPurchaseWithIapkitAmazonProps.kt +53 -0
  51. package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Bridge.hpp +47 -0
  52. package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Umbrella.hpp +3 -0
  53. package/nitrogen/generated/ios/c++/HybridRnIapSpecSwift.hpp +3 -0
  54. package/nitrogen/generated/ios/swift/IapStore.swift +4 -0
  55. package/nitrogen/generated/ios/swift/NitroVerifyPurchaseWithIapkitAmazonProps.swift +103 -0
  56. package/nitrogen/generated/ios/swift/NitroVerifyPurchaseWithIapkitProps.swift +38 -1
  57. package/nitrogen/generated/ios/swift/Variant_NullType_NitroVerifyPurchaseWithIapkitAmazonProps.swift +18 -0
  58. package/nitrogen/generated/shared/c++/IapStore.hpp +4 -0
  59. package/nitrogen/generated/shared/c++/NitroVerifyPurchaseWithIapkitAmazonProps.hpp +94 -0
  60. package/nitrogen/generated/shared/c++/NitroVerifyPurchaseWithIapkitProps.hpp +8 -1
  61. package/openiap-versions.json +2 -2
  62. package/package.json +19 -12
  63. package/src/index.kepler.ts +311 -0
  64. package/src/index.ts +65 -19
  65. package/src/specs/RnIap.nitro.ts +13 -2
  66. package/src/types/amazon-devices-kepler/index.d.ts +14 -0
  67. package/src/types.ts +17 -3
  68. package/src/utils/error.ts +2 -2
  69. package/src/utils/type-bridge.ts +4 -1
  70. package/src/vega-adapter.ts +1503 -0
  71. package/src/vega.kepler.ts +21 -0
  72. package/src/vega.ts +10 -0
  73. package/android/src/test/java/com/margelo/nitro/iap/ListenerThreadSafetyTest.kt +0 -154
  74. package/android/src/test/java/com/margelo/nitro/iap/OpenIapExceptionTest.kt +0 -93
  75. package/android/src/test/java/com/margelo/nitro/iap/ProductQueryHelpersTest.kt +0 -140
  76. package/app.plugin.js +0 -1
  77. package/lib/typescript/plugin/src/withIAP.d.ts +0 -48
  78. package/lib/typescript/plugin/src/withIAP.d.ts.map +0 -1
  79. package/plugin/build/withIAP.d.ts +0 -47
  80. package/plugin/build/withIAP.js +0 -314
  81. package/plugin/src/withIAP.ts +0 -500
  82. package/plugin/tsconfig.json +0 -18
  83. 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.6",
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}' 'plugin/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 && yarn build:plugin",
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 app.plugin.js --required nitro.json",
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 on next registration after initConnection()',
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
- Platform.OS === 'android' &&
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 (Platform.OS === 'android') {
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' && Platform.OS !== 'android') {
1125
+ if (Platform.OS !== 'ios' && !isAndroidStoreRuntime()) {
1092
1126
  RnIapConsole.warn(
1093
- '[getStorefront] Storefront lookup is only supported on iOS and Android.',
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
- return await IAP.instance.initConnection(
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 (Platform.OS === 'android') {
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 (Platform.OS === 'android' && androidRequestSource) {
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 (Platform.OS === 'android') {
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 (Platform.OS !== 'android') {
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 (Platform.OS !== 'android') {
2001
- throw new Error('consumePurchaseAndroid is only available on Android');
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
- * apple: { jws: purchase.purchaseToken },
2225
- * google: { purchaseToken: purchase.purchaseToken },
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
  * ```
@@ -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 = PurchaseUpdatedListenerOptions;
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
+ }