react-native-iap 15.5.0 → 15.5.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 (61) hide show
  1. package/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt +19 -0
  2. package/ios/HybridRnIap.swift +16 -0
  3. package/lib/module/hooks/useIAP.js +6 -2
  4. package/lib/module/hooks/useIAP.js.map +1 -1
  5. package/lib/module/index.js +6 -0
  6. package/lib/module/index.js.map +1 -1
  7. package/lib/module/index.kepler.js.map +1 -1
  8. package/lib/module/kit-api.js +27 -0
  9. package/lib/module/kit-api.js.map +1 -1
  10. package/lib/module/types.js +7 -0
  11. package/lib/module/types.js.map +1 -1
  12. package/lib/module/vega-adapter.js +10 -6
  13. package/lib/module/vega-adapter.js.map +1 -1
  14. package/lib/typescript/src/hooks/useIAP.d.ts.map +1 -1
  15. package/lib/typescript/src/index.d.ts +1 -1
  16. package/lib/typescript/src/index.d.ts.map +1 -1
  17. package/lib/typescript/src/index.kepler.d.ts +1 -0
  18. package/lib/typescript/src/index.kepler.d.ts.map +1 -1
  19. package/lib/typescript/src/kit-api.d.ts +60 -0
  20. package/lib/typescript/src/kit-api.d.ts.map +1 -1
  21. package/lib/typescript/src/specs/RnIap.nitro.d.ts +28 -12
  22. package/lib/typescript/src/specs/RnIap.nitro.d.ts.map +1 -1
  23. package/lib/typescript/src/types.d.ts +36 -1
  24. package/lib/typescript/src/types.d.ts.map +1 -1
  25. package/lib/typescript/src/vega-adapter.d.ts.map +1 -1
  26. package/nitrogen/generated/android/NitroIap+autolinking.cmake +1 -0
  27. package/nitrogen/generated/android/c++/JHybridRnIapSpec.cpp +9 -0
  28. package/nitrogen/generated/android/c++/JIapkitClientPayloadFormat.hpp +61 -0
  29. package/nitrogen/generated/android/c++/JNitroIapkitProductClientPayload.hpp +71 -0
  30. package/nitrogen/generated/android/c++/JNitroVerifyPurchaseWithIapkitProps.hpp +7 -3
  31. package/nitrogen/generated/android/c++/JNitroVerifyPurchaseWithIapkitResult.hpp +20 -1
  32. package/nitrogen/generated/android/c++/JNitroVerifyPurchaseWithProviderResult.hpp +5 -0
  33. package/nitrogen/generated/android/c++/JVariant_NullType_NitroIapkitProductClientPayload.cpp +26 -0
  34. package/nitrogen/generated/android/c++/JVariant_NullType_NitroIapkitProductClientPayload.hpp +74 -0
  35. package/nitrogen/generated/android/c++/JVariant_NullType_NitroVerifyPurchaseWithIapkitResult.hpp +8 -0
  36. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/IapkitClientPayloadFormat.kt +24 -0
  37. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroIapkitProductClientPayload.kt +66 -0
  38. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroVerifyPurchaseWithIapkitProps.kt +9 -4
  39. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroVerifyPurchaseWithIapkitResult.kt +14 -4
  40. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/Variant_NullType_NitroIapkitProductClientPayload.kt +62 -0
  41. package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Bridge.hpp +50 -0
  42. package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Umbrella.hpp +6 -0
  43. package/nitrogen/generated/ios/c++/HybridRnIapSpecSwift.hpp +6 -0
  44. package/nitrogen/generated/ios/swift/IapkitClientPayloadFormat.swift +44 -0
  45. package/nitrogen/generated/ios/swift/NitroIapkitProductClientPayload.swift +44 -0
  46. package/nitrogen/generated/ios/swift/NitroVerifyPurchaseWithIapkitProps.swift +38 -1
  47. package/nitrogen/generated/ios/swift/NitroVerifyPurchaseWithIapkitResult.swift +76 -2
  48. package/nitrogen/generated/ios/swift/Variant_NullType_NitroIapkitProductClientPayload.swift +30 -0
  49. package/nitrogen/generated/shared/c++/IapkitClientPayloadFormat.hpp +80 -0
  50. package/nitrogen/generated/shared/c++/NitroIapkitProductClientPayload.hpp +97 -0
  51. package/nitrogen/generated/shared/c++/NitroVerifyPurchaseWithIapkitProps.hpp +6 -2
  52. package/nitrogen/generated/shared/c++/NitroVerifyPurchaseWithIapkitResult.hpp +16 -1
  53. package/openiap-versions.json +3 -3
  54. package/package.json +5 -5
  55. package/src/hooks/useIAP.ts +6 -2
  56. package/src/index.kepler.ts +13 -0
  57. package/src/index.ts +13 -0
  58. package/src/kit-api.ts +107 -0
  59. package/src/specs/RnIap.nitro.ts +37 -12
  60. package/src/types.ts +38 -1
  61. package/src/vega-adapter.ts +14 -11
@@ -505,7 +505,9 @@ export function useIAP(options?: UseIapOptions): UseIap {
505
505
  onlyIncludeActiveItemsIOS: options?.onlyIncludeActiveItemsIOS ?? true,
506
506
  includeSuspendedAndroid: options?.includeSuspendedAndroid ?? false,
507
507
  });
508
- setAvailablePurchases(result);
508
+ if (isMountedRef.current) {
509
+ setAvailablePurchases(result);
510
+ }
509
511
  } catch (error) {
510
512
  RnIapConsole.error('Error fetching available purchases:', error);
511
513
  invokeOnError(error);
@@ -518,7 +520,9 @@ export function useIAP(options?: UseIapOptions): UseIap {
518
520
  async (subscriptionIds?: string[]): Promise<ActiveSubscription[]> => {
519
521
  try {
520
522
  const result = await getActiveSubscriptions(subscriptionIds);
521
- setActiveSubscriptions(result);
523
+ if (isMountedRef.current) {
524
+ setActiveSubscriptions(result);
525
+ }
522
526
  return result;
523
527
  } catch (error) {
524
528
  RnIapConsole.error('Error getting active subscriptions:', error);
@@ -32,6 +32,19 @@ export * from './vega';
32
32
  export {useIAP, type UseIapOptions} from './hooks/useIAP';
33
33
  export {connectWebhookStream, parseWebhookEventData} from './webhook-client';
34
34
  export {kitApi, KitApiError} from './kit-api';
35
+ export type {
36
+ EntitlementsResponse,
37
+ KitApiOptions,
38
+ KitClientPayloadResponse,
39
+ KitProduct,
40
+ KitProductClientPayload,
41
+ KitProductOffer,
42
+ KitProductPlatform,
43
+ KitProductsOptions,
44
+ KitProductsResponse,
45
+ KitSubscription,
46
+ StatusResponse,
47
+ } from './kit-api';
35
48
 
36
49
  export type ProductTypeInput = 'inapp' | 'in-app' | 'subs';
37
50
 
package/src/index.ts CHANGED
@@ -165,6 +165,13 @@ export type {
165
165
  export {kitApi, KitApiError} from './kit-api';
166
166
  export type {
167
167
  KitApiOptions,
168
+ KitClientPayloadResponse,
169
+ KitProduct,
170
+ KitProductClientPayload,
171
+ KitProductOffer,
172
+ KitProductPlatform,
173
+ KitProductsOptions,
174
+ KitProductsResponse,
168
175
  KitSubscription,
169
176
  EntitlementsResponse,
170
177
  StatusResponse,
@@ -2337,7 +2344,13 @@ export const verifyPurchaseWithProvider: MutationField<
2337
2344
  provider: result.provider,
2338
2345
  iapkit: result.iapkit
2339
2346
  ? {
2347
+ ...(result.iapkit.clientPayload == null
2348
+ ? {}
2349
+ : {clientPayload: result.iapkit.clientPayload}),
2340
2350
  isValid: result.iapkit.isValid,
2351
+ ...(result.iapkit.productId == null
2352
+ ? {}
2353
+ : {productId: result.iapkit.productId}),
2341
2354
  state: result.iapkit.state,
2342
2355
  store: result.iapkit.store,
2343
2356
  }
package/src/kit-api.ts CHANGED
@@ -40,6 +40,71 @@ export type StatusResponse = {
40
40
  subscription: KitSubscription | null;
41
41
  };
42
42
 
43
+ export type KitProductPlatform = "IOS" | "Android";
44
+
45
+ export type KitProductClientPayload = {
46
+ format: "toml" | "json" | "text";
47
+ body: string;
48
+ version: number;
49
+ updatedAt: number;
50
+ };
51
+
52
+ export type KitProductOffer = {
53
+ id: string;
54
+ kind:
55
+ | "FreeTrial"
56
+ | "IntroPayUpFront"
57
+ | "IntroPayAsYouGo"
58
+ | "PromotionalOffer"
59
+ | "BasePlan";
60
+ duration?: string;
61
+ numberOfPeriods?: number;
62
+ priceAmountMicros?: number;
63
+ currency?: string;
64
+ };
65
+
66
+ export type KitProduct = {
67
+ productId: string;
68
+ platform: KitProductPlatform;
69
+ type: "Subscription" | "NonConsumable" | "Consumable";
70
+ title: string;
71
+ description?: string;
72
+ priceAmountMicros?: number;
73
+ currency?: string;
74
+ state: "Draft" | "Ready" | "Active" | "Removed";
75
+ storeRef?: string;
76
+ subscriptionGroupId?: string;
77
+ subscriptionGroupName?: string;
78
+ billingPeriod?: "P1W" | "P1M" | "P2M" | "P3M" | "P6M" | "P1Y";
79
+ offers?: KitProductOffer[];
80
+ updatedAt: number;
81
+ clientPayload?: KitProductClientPayload;
82
+ };
83
+
84
+ export type KitProductsOptions = {
85
+ platform?: KitProductPlatform;
86
+ /** Include public client payload bodies in a bounded platform page. */
87
+ includeClientPayload?: boolean;
88
+ /** Page size for payload-inclusive reads (default 25, maximum 50).
89
+ * Ignored by the legacy non-payload catalog path. */
90
+ limit?: number;
91
+ /** Opaque cursor returned as `nextCursor` by the previous payload page.
92
+ * Ignored by the legacy non-payload catalog path. */
93
+ cursor?: string;
94
+ };
95
+
96
+ export type KitProductsResponse = {
97
+ products: KitProduct[];
98
+ /** Present on payload-inclusive catalog pages. */
99
+ hasMore?: boolean;
100
+ /** Present when a payload-inclusive catalog page has another page. */
101
+ nextCursor?: string;
102
+ };
103
+
104
+ export type KitClientPayloadResponse = {
105
+ clientPayload: KitProductClientPayload;
106
+ };
107
+
43
108
  const DEFAULT_BASE_URL = "https://kit.openiap.dev";
44
109
 
45
110
  // Merge caller-supplied headers with kit defaults (`accept`,
@@ -210,6 +275,48 @@ export function kitApi(options: KitApiOptions) {
210
275
  `/v1/subscriptions/entitlements/${encodeURIComponent(options.apiKey)}?userId=${encodeURIComponent(userId)}`,
211
276
  ),
212
277
 
278
+ /** GET /v1/products — read the store-synced catalog. Client payloads
279
+ * are excluded unless explicitly requested because they may add up to
280
+ * 16 KiB per product. */
281
+ products: (productOptions: KitProductsOptions = {}) => {
282
+ if (
283
+ productOptions.includeClientPayload === true &&
284
+ !productOptions.platform
285
+ ) {
286
+ throw new Error(
287
+ "kitApi.products requires platform when includeClientPayload is true",
288
+ );
289
+ }
290
+ const query = new URLSearchParams();
291
+ if (productOptions.platform) {
292
+ query.set("platform", productOptions.platform);
293
+ }
294
+ if (productOptions.includeClientPayload !== undefined) {
295
+ query.set(
296
+ "includeClientPayload",
297
+ String(productOptions.includeClientPayload),
298
+ );
299
+ }
300
+ if (productOptions.limit !== undefined) {
301
+ query.set("limit", String(productOptions.limit));
302
+ }
303
+ if (productOptions.cursor !== undefined) {
304
+ query.set("cursor", productOptions.cursor);
305
+ }
306
+ const encodedQuery = query.toString();
307
+ const suffix = encodedQuery ? `?${encodedQuery}` : "";
308
+ return call<KitProductsResponse>(
309
+ `/v1/products/${encodeURIComponent(options.apiKey)}${suffix}`,
310
+ );
311
+ },
312
+
313
+ /** GET one public client payload by its store-specific natural key.
314
+ * Payloads are app-facing data; never store secrets in them. */
315
+ clientPayload: (productId: string, platform: KitProductPlatform) =>
316
+ call<KitClientPayloadResponse>(
317
+ `/v1/products/${encodeURIComponent(options.apiKey)}/${encodeURIComponent(productId)}/client-payload?platform=${encodeURIComponent(platform)}`,
318
+ ),
319
+
213
320
  /** POST /v1/subscriptions/bind-user — call after a successful
214
321
  * verifyReceipt so kit knows which userId owns the verified
215
322
  * `purchaseToken`. Idempotent. */
@@ -17,6 +17,13 @@ import type {HybridObject} from 'react-native-nitro-modules';
17
17
  // ║ - Interface types from types.ts can be imported and used directly ║
18
18
  // ║ - Union types with 2+ values can be imported from types.ts ║
19
19
  // ║ - Single-value unions must be redefined locally with extra values ║
20
+ // ║ ║
21
+ // ║ 3. WRITE `null` FIRST IN NULLABLE UNIONS OF BOOLEANS AND ENUM ARRAYS ║
22
+ // ║ - Use `null | boolean`, not `boolean | null` (same for enum arrays) ║
23
+ // ║ - Since nitrogen 0.36 variant operands keep source order when their ║
24
+ // ║ "looseness" ties (boolean/enum-array tie with null), so null-last ║
25
+ // ║ would rename generated types (Variant_NullType_Bool → ║
26
+ // ║ Variant_Bool_NullType) and break hand-written Swift/Kotlin ║
20
27
  // ╚══════════════════════════════════════════════════════════════════════════╝
21
28
 
22
29
  // NOTE: This Nitro spec re-exports types from the generated schema (src/types.ts)
@@ -93,6 +100,8 @@ export type IapkitPurchaseState =
93
100
  | 'unknown'
94
101
  | 'inauthentic';
95
102
 
103
+ export type IapkitClientPayloadFormat = 'toml' | 'json' | 'text';
104
+
96
105
  // Store identifier for purchase origin
97
106
  // Defined locally for Nitro codegen (not in GQL schema)
98
107
  export type IapStore = 'unknown' | 'apple' | 'google' | 'horizon' | 'amazon';
@@ -278,8 +287,8 @@ export interface NitroPurchaseRequest {
278
287
  * iOS-specific options for getting available purchases
279
288
  */
280
289
  export interface NitroAvailablePurchasesIosOptions extends PurchaseOptions {
281
- alsoPublishToEventListener?: boolean | null;
282
- onlyIncludeActiveItems?: boolean | null;
290
+ alsoPublishToEventListener?: null | boolean;
291
+ onlyIncludeActiveItems?: null | boolean;
283
292
  }
284
293
 
285
294
  type NitroAvailablePurchasesAndroidType = 'inapp' | 'subs';
@@ -292,7 +301,7 @@ export interface NitroAvailablePurchasesAndroidOptions {
292
301
  * Users should be directed to the subscription center to resolve payment issues.
293
302
  * Default: false (only active subscriptions are returned)
294
303
  */
295
- includeSuspended?: boolean | null;
304
+ includeSuspended?: null | boolean;
296
305
  }
297
306
 
298
307
  export interface NitroAvailablePurchasesOptions {
@@ -358,7 +367,7 @@ export interface NitroBillingProgramInformationDialogParamsAndroid {
358
367
  }
359
368
 
360
369
  export interface NitroInAppMessageParamsAndroid {
361
- categories?: InAppMessageCategoryAndroid[] | null;
370
+ categories?: null | InAppMessageCategoryAndroid[];
362
371
  }
363
372
 
364
373
  // ╔══════════════════════════════════════════════════════════════════════════╗
@@ -450,7 +459,7 @@ export interface NitroVerifyPurchaseWithIapkitAmazonProps {
450
459
  /** Amazon Appstore receipt id returned by PurchaseResponse.getReceipt().getReceiptId(). */
451
460
  receiptId: string;
452
461
  /** Use Amazon RVS Cloud Sandbox for App Tester receipts. */
453
- sandbox?: boolean | null;
462
+ sandbox?: null | boolean;
454
463
  /** Amazon Appstore user id returned by PurchaseResponse.getUserData().getUserId(). */
455
464
  userId?: string | null;
456
465
  }
@@ -466,6 +475,11 @@ export interface NitroVerifyPurchaseWithIapkitProps {
466
475
  */
467
476
  baseUrl?: string | null;
468
477
  google?: NitroVerifyPurchaseWithIapkitGoogleProps | null;
478
+ /**
479
+ * Available in OpenIAP Spec 2.4.0 / openiap-apple 2.4.1 / openiap-google 2.4.1.
480
+ * Include the product's public IAPKit client payload when available.
481
+ */
482
+ includeClientPayload?: boolean | null;
469
483
  }
470
484
 
471
485
  export interface NitroVerifyPurchaseWithProviderProps {
@@ -474,11 +488,22 @@ export interface NitroVerifyPurchaseWithProviderProps {
474
488
  }
475
489
 
476
490
  export interface NitroVerifyPurchaseWithIapkitResult {
491
+ /** Available in OpenIAP Spec 2.4.0 / openiap-apple 2.4.1 / openiap-google 2.4.1. */
492
+ clientPayload?: NitroIapkitProductClientPayload | null;
477
493
  isValid: boolean;
494
+ /** Available in OpenIAP Spec 2.4.0 / openiap-apple 2.4.1 / openiap-google 2.4.1. */
495
+ productId?: string | null;
478
496
  state: IapkitPurchaseState;
479
497
  store: IapStore;
480
498
  }
481
499
 
500
+ export interface NitroIapkitProductClientPayload {
501
+ body: string;
502
+ format: IapkitClientPayloadFormat;
503
+ updatedAt: number;
504
+ version: number;
505
+ }
506
+
482
507
  export interface NitroVerifyPurchaseWithProviderError {
483
508
  code?: string | null;
484
509
  message: string;
@@ -501,7 +526,7 @@ export interface NitroBillingProgramAvailabilityResultAndroid {
501
526
  /** Whether the billing program is available for the user */
502
527
  isAvailable: boolean;
503
528
  /** Whether external-link payment is available for Billing Choice. */
504
- isExternalLinkAvailable?: boolean | null;
529
+ isExternalLinkAvailable?: null | boolean;
505
530
  }
506
531
 
507
532
  /**
@@ -610,7 +635,7 @@ export interface NitroPurchase {
610
635
  currencySymbolIOS?: string | null;
611
636
  environmentIOS?: string | null;
612
637
  expirationDateIOS?: number | null;
613
- isUpgradedIOS?: boolean | null;
638
+ isUpgradedIOS?: null | boolean;
614
639
  offerIOS?: string | null;
615
640
  ownershipTypeIOS?: string | null;
616
641
  reasonIOS?: string | null;
@@ -626,14 +651,14 @@ export interface NitroPurchase {
626
651
  purchaseTokenAndroid?: string | null;
627
652
  dataAndroid?: string | null;
628
653
  signatureAndroid?: string | null;
629
- autoRenewingAndroid?: boolean | null;
654
+ autoRenewingAndroid?: null | boolean;
630
655
  purchaseStateAndroid?: number | null;
631
- isAcknowledgedAndroid?: boolean | null;
656
+ isAcknowledgedAndroid?: null | boolean;
632
657
  packageNameAndroid?: string | null;
633
658
  obfuscatedAccountIdAndroid?: string | null;
634
659
  obfuscatedProfileIdAndroid?: string | null;
635
660
  developerPayloadAndroid?: string | null;
636
- isSuspendedAndroid?: boolean | null;
661
+ isSuspendedAndroid?: null | boolean;
637
662
  pendingPurchaseUpdateAndroid?: PendingPurchaseUpdateAndroid | null;
638
663
  }
639
664
 
@@ -670,7 +695,7 @@ export interface NitroRenewalInfoIOS {
670
695
  pendingUpgradeProductId?: string | null;
671
696
  renewalDate?: number | null;
672
697
  expirationReason?: string | null;
673
- isInBillingRetry?: boolean | null;
698
+ isInBillingRetry?: null | boolean;
674
699
  gracePeriodExpirationDate?: number | null;
675
700
  priceIncreaseStatus?: string | null;
676
701
  renewalBillingPlanType?: SubscriptionBillingPlanTypeIOS | null;
@@ -692,7 +717,7 @@ export interface NitroProduct {
692
717
  platform: IapPlatform;
693
718
  // iOS specific fields
694
719
  typeIOS?: string | null;
695
- isFamilyShareableIOS?: boolean | null;
720
+ isFamilyShareableIOS?: null | boolean;
696
721
  jsonRepresentationIOS?: string | null;
697
722
  pricingTermsIOS?: string | null;
698
723
  subscriptionInfoIOS?: string | null;
package/src/types.ts CHANGED
@@ -617,6 +617,20 @@ export type IapPlatform = 'ios' | 'android';
617
617
 
618
618
  export type IapStore = 'unknown' | 'apple' | 'google' | 'horizon' | 'amazon';
619
619
 
620
+ /** Serialization format of a public IAPKit product client payload. */
621
+ export type IapkitClientPayloadFormat = 'toml' | 'json' | 'text';
622
+
623
+ /**
624
+ * Public app-facing data attached to one store product in IAPKit.
625
+ * Never place credentials, signing keys, or server-authoritative rules here.
626
+ */
627
+ export interface IapkitProductClientPayload {
628
+ body: string;
629
+ format: IapkitClientPayloadFormat;
630
+ updatedAt: number;
631
+ version: number;
632
+ }
633
+
620
634
  /** Unified purchase states from IAPKit verification response. */
621
635
  export type IapkitPurchaseState = 'entitled' | 'pending-acknowledgment' | 'pending' | 'canceled' | 'expired' | 'ready-to-consume' | 'consumed' | 'unknown' | 'inauthentic';
622
636
 
@@ -1987,11 +2001,34 @@ export interface RequestVerifyPurchaseWithIapkitProps {
1987
2001
  baseUrl?: (string | null);
1988
2002
  /** Google Play Store verification parameters. */
1989
2003
  google?: (RequestVerifyPurchaseWithIapkitGoogleProps | null);
2004
+ /**
2005
+ * Available in OpenIAP Spec 2.4.0 / openiap-apple 2.4.1 / openiap-google 2.4.1.
2006
+ * Include the product's public IAPKit client payload in a valid Apple or
2007
+ * Google verification response. Defaults to false so existing response
2008
+ * shapes and bandwidth remain unchanged.
2009
+ */
2010
+ includeClientPayload?: (boolean | null);
1990
2011
  }
1991
2012
 
1992
2013
  export interface RequestVerifyPurchaseWithIapkitResult {
1993
- /** Whether the purchase is valid (not falsified). */
2014
+ /**
2015
+ * Available in OpenIAP Spec 2.4.0 / openiap-apple 2.4.1 / openiap-google 2.4.1.
2016
+ * Public product payload when includeClientPayload was requested, the
2017
+ * Apple or Google receipt is valid, and a payload exists for that product.
2018
+ */
2019
+ clientPayload?: (IapkitProductClientPayload | null);
2020
+ /**
2021
+ * True when the purchase is valid and actionable.
2022
+ * Only entitled, pending-acknowledgment, or ready-to-consume return true.
2023
+ * Callers must still match productId and use the platform plus app-owned product
2024
+ * type to choose the fulfillment path.
2025
+ */
1994
2026
  isValid: boolean;
2027
+ /**
2028
+ * Available in OpenIAP Spec 2.4.0 / openiap-apple 2.4.1 / openiap-google 2.4.1.
2029
+ * Store-verified product identifier when the provider returns one.
2030
+ */
2031
+ productId?: (string | null);
1995
2032
  /** The current state of the purchase. */
1996
2033
  state: IapkitPurchaseState;
1997
2034
  store: IapStore;
@@ -4,6 +4,7 @@ import type {
4
4
  NitroProduct,
5
5
  NitroPurchase,
6
6
  NitroPurchaseResult,
7
+ NitroVerifyPurchaseWithIapkitResult,
7
8
  NitroVerifyPurchaseWithProviderProps,
8
9
  NitroVerifyPurchaseWithProviderResult,
9
10
  RnIap,
@@ -155,8 +156,7 @@ function isValidIpv4Address(address: string): boolean {
155
156
  return (
156
157
  octets.length === 4 &&
157
158
  octets.every(
158
- (octet) =>
159
- /^(?:0|[1-9]\d{0,2})$/.test(octet) && Number(octet) <= 255,
159
+ (octet) => /^(?:0|[1-9]\d{0,2})$/.test(octet) && Number(octet) <= 255,
160
160
  )
161
161
  );
162
162
  }
@@ -1236,10 +1236,7 @@ export function createVegaIapModule(service: VegaPurchasingService): RnIap {
1236
1236
  function readIapkitResult(
1237
1237
  json: Record<string, unknown>,
1238
1238
  status: number,
1239
- ): {
1240
- isValid: boolean;
1241
- state: IapkitPurchaseState;
1242
- } {
1239
+ ): NitroVerifyPurchaseWithIapkitResult {
1243
1240
  if (
1244
1241
  typeof json.isValid !== 'boolean' ||
1245
1242
  typeof json.state !== 'string' ||
@@ -1251,9 +1248,19 @@ export function createVegaIapModule(service: VegaPurchasingService): RnIap {
1251
1248
  );
1252
1249
  }
1253
1250
 
1251
+ const productId = json.productId;
1252
+ if (productId != null && typeof productId !== 'string') {
1253
+ throw createVegaError(
1254
+ ErrorCode.ReceiptFailed,
1255
+ `IAPKit returned malformed response (HTTP ${status}).`,
1256
+ );
1257
+ }
1258
+
1254
1259
  return {
1255
1260
  isValid: json.isValid,
1261
+ ...(productId == null ? {} : {productId}),
1256
1262
  state: normalizeIapkitState(json.state),
1263
+ store: 'amazon',
1257
1264
  };
1258
1265
  }
1259
1266
 
@@ -1374,11 +1381,7 @@ export function createVegaIapModule(service: VegaPurchasingService): RnIap {
1374
1381
  const result = readIapkitResult(json, response.status);
1375
1382
  return {
1376
1383
  provider: 'iapkit',
1377
- iapkit: {
1378
- isValid: result.isValid,
1379
- state: result.state,
1380
- store: 'amazon',
1381
- },
1384
+ iapkit: result,
1382
1385
  };
1383
1386
  };
1384
1387