expo-iap 5.3.0 → 5.3.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/README.md +2 -2
- package/android/src/main/java/expo/modules/iap/ExpoIapHelper.kt +87 -39
- package/android/src/main/java/expo/modules/iap/ExpoIapModule.kt +35 -27
- package/build/index.d.ts.map +1 -1
- package/build/index.js +65 -30
- package/build/index.js.map +1 -1
- package/build/index.kepler.d.ts.map +1 -1
- package/build/index.kepler.js +9 -1
- package/build/index.kepler.js.map +1 -1
- package/build/kit-api.d.ts +119 -2
- package/build/kit-api.d.ts.map +1 -1
- package/build/kit-api.js +3 -1
- package/build/kit-api.js.map +1 -1
- package/build/types.d.ts +33 -9
- package/build/types.d.ts.map +1 -1
- package/build/types.js.map +1 -1
- package/build/vega-adapter.d.ts.map +1 -1
- package/build/vega-adapter.js +5 -6
- package/build/vega-adapter.js.map +1 -1
- package/ios/ExpoIapHelper.swift +80 -17
- package/ios/ExpoIapModule.swift +20 -7
- package/ios/onside/OnsideIapModule.swift +28 -56
- package/openiap-versions.json +3 -3
- package/package.json +1 -1
- package/src/index.kepler.ts +9 -1
- package/src/index.ts +54 -9
- package/src/kit-api.ts +125 -4
- package/src/types.ts +34 -9
- package/src/vega-adapter.ts +6 -11
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ Expo IAP is a powerful in-app purchase solution for Expo and React Native applic
|
|
|
9
9
|
|
|
10
10
|
If you're shipping an app with expo-iap, we’d love to hear about it—please share your product and feedback in [expo-iap Q&A Discussions](https://github.com/hyodotdev/openiap/discussions/categories/expo-iap). Community stories help us keep improving the ecosystem.
|
|
11
11
|
|
|
12
|
-
<a href="https://openiap.dev"><img src="https://raw.githubusercontent.com/hyodotdev/openiap/main/logo.
|
|
12
|
+
<a href="https://openiap.dev"><img src="https://raw.githubusercontent.com/hyodotdev/openiap/main/logo.webp" alt="Open IAP" height="40" /></a>
|
|
13
13
|
|
|
14
14
|
</div>
|
|
15
15
|
|
|
@@ -64,7 +64,7 @@ For detailed usage examples and error handling, see the [documentation](https://
|
|
|
64
64
|
|
|
65
65
|
## Powered by OpenIAP
|
|
66
66
|
|
|
67
|
-
<a href="https://openiap.dev"><img src="https://raw.githubusercontent.com/hyodotdev/openiap/main/logo.
|
|
67
|
+
<a href="https://openiap.dev"><img src="https://raw.githubusercontent.com/hyodotdev/openiap/main/logo.webp" alt="OpenIAP" height="50" /></a>
|
|
68
68
|
|
|
69
69
|
Expo IAP conforms to the **[OpenIAP specification](https://openiap.dev)** — an open, vendor-neutral interoperability standard for in-app purchases. OpenIAP provides:
|
|
70
70
|
|
|
@@ -75,6 +75,14 @@ object ExpoIapHelper {
|
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
fun parsePurchaseProductQueryType(rawType: String?): ProductQueryType {
|
|
79
|
+
val type = parseProductQueryType(rawType)
|
|
80
|
+
require(type != ProductQueryType.All) {
|
|
81
|
+
"Product type all is only supported for product queries."
|
|
82
|
+
}
|
|
83
|
+
return type
|
|
84
|
+
}
|
|
85
|
+
|
|
78
86
|
internal fun parseDeepLinkSubscriptionParams(params: Map<String, Any?>): DeepLinkSubscriptionParams {
|
|
79
87
|
return DeepLinkSubscriptionParams(
|
|
80
88
|
sku = params["skuAndroid"] as? String,
|
|
@@ -87,43 +95,93 @@ object ExpoIapHelper {
|
|
|
87
95
|
// before parsing the native request.
|
|
88
96
|
val effective: Map<String, Any?> =
|
|
89
97
|
run {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
flat
|
|
104
|
-
}
|
|
105
|
-
|
|
98
|
+
if (params.containsKey("request")) {
|
|
99
|
+
val request = params["request"]
|
|
100
|
+
require(request is Map<*, *>) { "request must be an object" }
|
|
101
|
+
val nested = request["google"]
|
|
102
|
+
require(nested is Map<*, *> && nested.keys.all { it is String }) {
|
|
103
|
+
"request.google must be an object with string keys"
|
|
104
|
+
}
|
|
105
|
+
require(!nested.containsKey("type")) {
|
|
106
|
+
"type must be provided only at the purchase envelope"
|
|
107
|
+
}
|
|
108
|
+
val flat = mutableMapOf<String, Any?>()
|
|
109
|
+
// Carry over top-level fields such as the purchase type.
|
|
110
|
+
for ((k, v) in params) {
|
|
111
|
+
if (k != "request") flat[k] = v
|
|
112
|
+
}
|
|
113
|
+
// Overlay platform-specific fields.
|
|
114
|
+
for ((k, v) in nested) {
|
|
115
|
+
flat[k as String] = v
|
|
106
116
|
}
|
|
117
|
+
flat
|
|
107
118
|
} else {
|
|
108
119
|
params
|
|
109
120
|
}
|
|
110
121
|
}
|
|
111
122
|
|
|
123
|
+
require(effective["type"] == null || effective["type"] is String) {
|
|
124
|
+
"type must be a string"
|
|
125
|
+
}
|
|
126
|
+
effective["skus"]?.let { rawSkus ->
|
|
127
|
+
require(rawSkus is List<*> && rawSkus.all { it is String && it.isNotBlank() }) {
|
|
128
|
+
"skus must contain only non-empty strings"
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
for (key in listOf(
|
|
132
|
+
"obfuscatedAccountId",
|
|
133
|
+
"obfuscatedProfileId",
|
|
134
|
+
"purchaseToken",
|
|
135
|
+
"originalExternalTransactionId",
|
|
136
|
+
"offerToken",
|
|
137
|
+
)) {
|
|
138
|
+
require(effective[key] == null || effective[key] is String) { "$key must be a string" }
|
|
139
|
+
}
|
|
140
|
+
require(effective["isOfferPersonalized"] == null || effective["isOfferPersonalized"] is Boolean) {
|
|
141
|
+
"isOfferPersonalized must be a boolean"
|
|
142
|
+
}
|
|
143
|
+
for (key in listOf("developerBillingOption", "subscriptionProductReplacementParams")) {
|
|
144
|
+
effective[key]?.let { value ->
|
|
145
|
+
require(value is Map<*, *> && value.keys.all { it is String }) {
|
|
146
|
+
"$key must be an object with string keys"
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
effective["subscriptionOffers"]?.let { rawOffers ->
|
|
151
|
+
require(rawOffers is List<*>) { "subscriptionOffers must be a list" }
|
|
152
|
+
require(rawOffers.all { rawOffer ->
|
|
153
|
+
val offer = rawOffer as? Map<*, *> ?: return@all false
|
|
154
|
+
val sku = offer["sku"] as? String
|
|
155
|
+
val token = offer["offerToken"] as? String
|
|
156
|
+
offer.keys.all { it is String } && !sku.isNullOrBlank() && !token.isNullOrBlank()
|
|
157
|
+
}) { "subscriptionOffers must contain valid sku and offerToken strings" }
|
|
158
|
+
}
|
|
159
|
+
|
|
112
160
|
val type = effective["type"] as? String
|
|
113
|
-
val
|
|
161
|
+
val purchaseType = parsePurchaseProductQueryType(type)
|
|
162
|
+
val subscriptionOnlyFields = listOf(
|
|
163
|
+
"subscriptionOffers",
|
|
164
|
+
"subscriptionProductReplacementParams",
|
|
165
|
+
"purchaseToken",
|
|
166
|
+
"originalExternalTransactionId",
|
|
167
|
+
)
|
|
168
|
+
require(
|
|
169
|
+
purchaseType != ProductQueryType.InApp ||
|
|
170
|
+
subscriptionOnlyFields.none { effective[it] != null },
|
|
171
|
+
) { "Subscription options require product type subs" }
|
|
172
|
+
require(purchaseType != ProductQueryType.Subs || effective["offerToken"] == null) {
|
|
173
|
+
"offerToken requires product type in-app"
|
|
174
|
+
}
|
|
175
|
+
val skus = (effective["skus"] as? List<*>)?.map { it as String } ?: emptyList()
|
|
114
176
|
val obfuscatedAccountId = effective["obfuscatedAccountId"] as? String
|
|
115
177
|
val obfuscatedProfileId = effective["obfuscatedProfileId"] as? String
|
|
116
178
|
val isOfferPersonalized = effective["isOfferPersonalized"] as? Boolean ?: false
|
|
117
179
|
val explicitSubscriptionOffers =
|
|
118
|
-
(effective["subscriptionOffers"] as? List<*>)?.
|
|
119
|
-
val offerMap = rawOffer as
|
|
120
|
-
val sku = offerMap["sku"] as
|
|
121
|
-
val offerToken = offerMap["offerToken"] as
|
|
122
|
-
|
|
123
|
-
null
|
|
124
|
-
} else {
|
|
125
|
-
AndroidSubscriptionOfferInput(offerToken = offerToken, sku = sku)
|
|
126
|
-
}
|
|
180
|
+
(effective["subscriptionOffers"] as? List<*>)?.map { rawOffer ->
|
|
181
|
+
val offerMap = rawOffer as Map<*, *>
|
|
182
|
+
val sku = offerMap["sku"] as String
|
|
183
|
+
val offerToken = offerMap["offerToken"] as String
|
|
184
|
+
AndroidSubscriptionOfferInput(offerToken = offerToken, sku = sku)
|
|
127
185
|
} ?: emptyList()
|
|
128
186
|
val purchaseToken = effective["purchaseToken"] as? String
|
|
129
187
|
val originalExternalTransactionId = effective["originalExternalTransactionId"] as? String
|
|
@@ -131,23 +189,13 @@ object ExpoIapHelper {
|
|
|
131
189
|
(effective["developerBillingOption"] as? Map<*, *>)?.let { optionMap ->
|
|
132
190
|
val json =
|
|
133
191
|
optionMap.entries
|
|
134
|
-
.
|
|
135
|
-
(key as? String)?.let { it to value }
|
|
136
|
-
}.toMap()
|
|
192
|
+
.associate { (key, value) -> key as String to value }
|
|
137
193
|
DeveloperBillingOptionParamsAndroid.fromJson(json)
|
|
138
194
|
}
|
|
139
195
|
val subscriptionProductReplacementParams =
|
|
140
196
|
(effective["subscriptionProductReplacementParams"] as? Map<*, *>)?.let { paramsMap ->
|
|
141
|
-
val
|
|
142
|
-
|
|
143
|
-
if (oldProductId.isNullOrEmpty() || replacementModeStr.isNullOrEmpty()) {
|
|
144
|
-
null
|
|
145
|
-
} else {
|
|
146
|
-
SubscriptionProductReplacementParamsAndroid(
|
|
147
|
-
oldProductId = oldProductId,
|
|
148
|
-
replacementMode = parseSubscriptionReplacementMode(replacementModeStr),
|
|
149
|
-
)
|
|
150
|
-
}
|
|
197
|
+
val json = paramsMap.entries.associate { (key, value) -> key as String to value }
|
|
198
|
+
SubscriptionProductReplacementParamsAndroid.fromJson(json)
|
|
151
199
|
}
|
|
152
200
|
// offerToken for one-time purchase discounts (Android 8.0+)
|
|
153
201
|
val offerToken = effective["offerToken"] as? String
|
|
@@ -20,6 +20,7 @@ import dev.hyo.openiap.RequestPurchaseResultPurchases
|
|
|
20
20
|
import dev.hyo.openiap.RequestSubscriptionAndroidProps
|
|
21
21
|
import dev.hyo.openiap.RequestSubscriptionPropsByPlatforms
|
|
22
22
|
import dev.hyo.openiap.VerifyPurchaseGoogleOptions
|
|
23
|
+
import dev.hyo.openiap.VerifyPurchaseHorizonOptions
|
|
23
24
|
import dev.hyo.openiap.VerifyPurchaseProps
|
|
24
25
|
import dev.hyo.openiap.VerifyPurchaseWithProviderProps
|
|
25
26
|
import dev.hyo.openiap.store.OpenIapStore
|
|
@@ -73,6 +74,31 @@ internal fun deliverPurchaseRequestFailure(
|
|
|
73
74
|
rejectPendingPromises(errorCode, errorEnvelope)
|
|
74
75
|
}
|
|
75
76
|
|
|
77
|
+
@Suppress("UNCHECKED_CAST")
|
|
78
|
+
internal fun verifyPurchasePropsFromMap(params: Map<String, Any?>): VerifyPurchaseProps {
|
|
79
|
+
fun requiredOption(options: Map<String, Any?>, scope: String, field: String): String =
|
|
80
|
+
(options[field] as? String)?.takeIf { it.isNotEmpty() }
|
|
81
|
+
?: throw IllegalArgumentException("Missing or empty required parameter: $scope.$field")
|
|
82
|
+
|
|
83
|
+
val googleOptions = (params["google"] as? Map<String, Any?>)?.let { options ->
|
|
84
|
+
VerifyPurchaseGoogleOptions(
|
|
85
|
+
sku = requiredOption(options, "google", "sku"),
|
|
86
|
+
accessToken = requiredOption(options, "google", "accessToken"),
|
|
87
|
+
packageName = requiredOption(options, "google", "packageName"),
|
|
88
|
+
purchaseToken = requiredOption(options, "google", "purchaseToken"),
|
|
89
|
+
isSub = options["isSub"] as? Boolean,
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
val horizonOptions = (params["horizon"] as? Map<String, Any?>)?.let { options ->
|
|
93
|
+
VerifyPurchaseHorizonOptions(
|
|
94
|
+
sku = requiredOption(options, "horizon", "sku"),
|
|
95
|
+
userId = requiredOption(options, "horizon", "userId"),
|
|
96
|
+
accessToken = requiredOption(options, "horizon", "accessToken"),
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
return VerifyPurchaseProps(google = googleOptions, horizon = horizonOptions)
|
|
100
|
+
}
|
|
101
|
+
|
|
76
102
|
class ExpoIapModule : Module() {
|
|
77
103
|
companion object {
|
|
78
104
|
const val TAG = "ExpoIapModule"
|
|
@@ -348,7 +374,7 @@ class ExpoIapModule : Module() {
|
|
|
348
374
|
val parsedParams = ExpoIapHelper.parseRequestPurchaseParams(params)
|
|
349
375
|
|
|
350
376
|
val productType =
|
|
351
|
-
when (ExpoIapHelper.
|
|
377
|
+
when (ExpoIapHelper.parsePurchaseProductQueryType(parsedParams.type)) {
|
|
352
378
|
ProductQueryType.Subs -> ProductQueryType.Subs
|
|
353
379
|
else -> ProductQueryType.InApp
|
|
354
380
|
}
|
|
@@ -497,35 +523,17 @@ class ExpoIapModule : Module() {
|
|
|
497
523
|
}
|
|
498
524
|
}
|
|
499
525
|
|
|
500
|
-
@Suppress("UNCHECKED_CAST")
|
|
501
526
|
AsyncFunction("verifyPurchase") { params: Map<String, Any?>, promise: Promise ->
|
|
502
|
-
ExpoIapLog.payload(
|
|
527
|
+
ExpoIapLog.payload(
|
|
528
|
+
"verifyPurchase",
|
|
529
|
+
mapOf(
|
|
530
|
+
"hasGoogle" to (params["google"] != null),
|
|
531
|
+
"hasHorizon" to (params["horizon"] != null),
|
|
532
|
+
),
|
|
533
|
+
)
|
|
503
534
|
scope.launch {
|
|
504
535
|
try {
|
|
505
|
-
val
|
|
506
|
-
(params["google"] as? Map<String, Any?>)?.let { opts ->
|
|
507
|
-
VerifyPurchaseGoogleOptions(
|
|
508
|
-
sku =
|
|
509
|
-
(opts["sku"] as? String)?.takeIf { it.isNotEmpty() }
|
|
510
|
-
?: throw IllegalArgumentException("Missing or empty required parameter: google.sku"),
|
|
511
|
-
accessToken =
|
|
512
|
-
(opts["accessToken"] as? String)?.takeIf { it.isNotEmpty() }
|
|
513
|
-
?: throw IllegalArgumentException("Missing or empty required parameter: google.accessToken"),
|
|
514
|
-
packageName =
|
|
515
|
-
(opts["packageName"] as? String)?.takeIf { it.isNotEmpty() }
|
|
516
|
-
?: throw IllegalArgumentException("Missing or empty required parameter: google.packageName"),
|
|
517
|
-
purchaseToken =
|
|
518
|
-
(opts["purchaseToken"] as? String)?.takeIf { it.isNotEmpty() }
|
|
519
|
-
?: throw IllegalArgumentException("Missing or empty required parameter: google.purchaseToken"),
|
|
520
|
-
isSub = opts["isSub"] as? Boolean,
|
|
521
|
-
)
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
val props =
|
|
525
|
-
VerifyPurchaseProps(
|
|
526
|
-
google = googleOptions,
|
|
527
|
-
)
|
|
528
|
-
|
|
536
|
+
val props = verifyPurchasePropsFromMap(params)
|
|
529
537
|
val result = openIap.verifyPurchase(props)
|
|
530
538
|
val resultMap = result.toJson()
|
|
531
539
|
ExpoIapLog.result("verifyPurchase", resultMap)
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/build/index.js
CHANGED
|
@@ -655,6 +655,25 @@ function normalizeRequestProps(request, platform) {
|
|
|
655
655
|
}
|
|
656
656
|
return request.google;
|
|
657
657
|
}
|
|
658
|
+
function validateAndroidPurchaseBranchOptions(request, type) {
|
|
659
|
+
if (request == null || typeof request !== 'object')
|
|
660
|
+
return;
|
|
661
|
+
const fields = request;
|
|
662
|
+
const subscriptionOnlyFields = [
|
|
663
|
+
'subscriptionOffers',
|
|
664
|
+
'subscriptionProductReplacementParams',
|
|
665
|
+
'purchaseToken',
|
|
666
|
+
'originalExternalTransactionId',
|
|
667
|
+
];
|
|
668
|
+
if ((type === 'in-app' &&
|
|
669
|
+
subscriptionOnlyFields.some((field) => fields[field] != null)) ||
|
|
670
|
+
(type === 'subs' && fields.offerToken != null)) {
|
|
671
|
+
throw createPurchaseError({
|
|
672
|
+
code: ErrorCode.DeveloperError,
|
|
673
|
+
message: 'Invalid request for Android. Purchase options must match the selected product type.',
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
}
|
|
658
677
|
/**
|
|
659
678
|
* Initiate a purchase or subscription flow. The result is delivered through
|
|
660
679
|
* `purchaseUpdatedListener` — NOT the return value.
|
|
@@ -684,20 +703,29 @@ function normalizeRequestProps(request, platform) {
|
|
|
684
703
|
export const requestPurchase = async (args) => {
|
|
685
704
|
const { request, type } = args;
|
|
686
705
|
const { canonical, native } = normalizeProductType(type);
|
|
706
|
+
if (canonical === 'all') {
|
|
707
|
+
throw createPurchaseError({
|
|
708
|
+
code: ErrorCode.DeveloperError,
|
|
709
|
+
message: 'Product type all is only supported for product queries.',
|
|
710
|
+
});
|
|
711
|
+
}
|
|
687
712
|
const isInAppPurchase = canonical === 'in-app';
|
|
688
713
|
if (Platform.OS === 'ios') {
|
|
689
714
|
const normalizedRequest = normalizeRequestProps(request, 'ios');
|
|
690
715
|
if (!normalizedRequest?.sku) {
|
|
691
|
-
throw
|
|
692
|
-
'
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
716
|
+
throw createPurchaseError({
|
|
717
|
+
message: 'Invalid request for Apple. The `sku` property is required and must be a string.\n\n' +
|
|
718
|
+
'Expected format:\n' +
|
|
719
|
+
' requestPurchase({\n' +
|
|
720
|
+
' request: {\n' +
|
|
721
|
+
' apple: { sku: "product_id" },\n' +
|
|
722
|
+
' google: { skus: ["product_id"] }\n' +
|
|
723
|
+
' },\n' +
|
|
724
|
+
' type: "in-app"\n' +
|
|
725
|
+
' })\n\n' +
|
|
726
|
+
'See: https://openiap.dev/docs/apis/request-purchase',
|
|
727
|
+
code: ErrorCode.EmptySkuList,
|
|
728
|
+
});
|
|
701
729
|
}
|
|
702
730
|
if (canonical !== 'in-app' && canonical !== 'subs') {
|
|
703
731
|
throw new Error(`Unsupported product type: ${canonical}`);
|
|
@@ -722,19 +750,23 @@ export const requestPurchase = async (args) => {
|
|
|
722
750
|
return canonical === 'subs' ? [] : null;
|
|
723
751
|
}
|
|
724
752
|
if (isAndroidStoreRuntime()) {
|
|
753
|
+
validateAndroidPurchaseBranchOptions(request?.google, canonical);
|
|
725
754
|
if (isInAppPurchase) {
|
|
726
755
|
const normalizedRequest = normalizeRequestProps(request, 'android');
|
|
727
756
|
if (!normalizedRequest?.skus?.length) {
|
|
728
|
-
throw
|
|
729
|
-
'
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
757
|
+
throw createPurchaseError({
|
|
758
|
+
message: 'Invalid request for Google. The `skus` property is required and must be a non-empty array.\n\n' +
|
|
759
|
+
'Expected format:\n' +
|
|
760
|
+
' requestPurchase({\n' +
|
|
761
|
+
' request: {\n' +
|
|
762
|
+
' apple: { sku: "product_id" },\n' +
|
|
763
|
+
' google: { skus: ["product_id"] }\n' +
|
|
764
|
+
' },\n' +
|
|
765
|
+
' type: "in-app"\n' +
|
|
766
|
+
' })\n\n' +
|
|
767
|
+
'See: https://openiap.dev/docs/apis/request-purchase',
|
|
768
|
+
code: ErrorCode.EmptySkuList,
|
|
769
|
+
});
|
|
738
770
|
}
|
|
739
771
|
const { skus, obfuscatedAccountId, obfuscatedProfileId, isOfferPersonalized, offerToken, developerBillingOption, } = normalizedRequest;
|
|
740
772
|
const result = (await invokeNativeWithPurchaseError(() => ExpoIapModule.requestPurchase({
|
|
@@ -758,16 +790,19 @@ export const requestPurchase = async (args) => {
|
|
|
758
790
|
if (canonical === 'subs') {
|
|
759
791
|
const normalizedRequest = normalizeRequestProps(request, 'android');
|
|
760
792
|
if (!normalizedRequest?.skus?.length) {
|
|
761
|
-
throw
|
|
762
|
-
'
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
793
|
+
throw createPurchaseError({
|
|
794
|
+
message: 'Invalid request for Google. The `skus` property is required and must be a non-empty array.\n\n' +
|
|
795
|
+
'Expected format:\n' +
|
|
796
|
+
' requestPurchase({\n' +
|
|
797
|
+
' request: {\n' +
|
|
798
|
+
' apple: { sku: "subscription_id" },\n' +
|
|
799
|
+
' google: { skus: ["subscription_id"] }\n' +
|
|
800
|
+
' },\n' +
|
|
801
|
+
' type: "subs"\n' +
|
|
802
|
+
' })\n\n' +
|
|
803
|
+
'See: https://openiap.dev/docs/apis/request-purchase',
|
|
804
|
+
code: ErrorCode.EmptySkuList,
|
|
805
|
+
});
|
|
771
806
|
}
|
|
772
807
|
const { skus, obfuscatedAccountId, obfuscatedProfileId, isOfferPersonalized, subscriptionOffers, purchaseToken: purchaseTokenInput, originalExternalTransactionId, developerBillingOption, subscriptionProductReplacementParams, } = normalizedRequest;
|
|
773
808
|
const normalizedOffers = subscriptionOffers ?? [];
|