Skip to content
This repository was archived by the owner on Apr 26, 2026. It is now read-only.

feat: migrate to openiap 1.3.0 with IapStore and store field#3101

Merged
hyochan merged 3 commits into
mainfrom
migration/openiap-1.3
Dec 8, 2025
Merged

feat: migrate to openiap 1.3.0 with IapStore and store field#3101
hyochan merged 3 commits into
mainfrom
migration/openiap-1.3

Conversation

@hyochan

@hyochan hyochan commented Dec 8, 2025

Copy link
Copy Markdown
Owner
  • Update openiap versions: apple 1.3.0, google 1.3.10, gql 1.3.0
  • Add IapStore type ('unknown' | 'apple' | 'google' | 'horizon')
  • Add store field to Purchase (platform field deprecated)
  • Add apple/google fields to RequestPurchasePropsByPlatforms (ios/android deprecated)
  • Change verifyPurchaseWithProvider iapkit from array to object
  • Add errors field to VerifyPurchaseWithProviderResult
  • Create versioned docs for 14.4, update current to 14.5
  • Update documentation with correct types and examples

Summary by CodeRabbit

  • New Features

    • Verification results now expose a single optional iapkit object and a new errors array with codes/messages.
    • Purchases include explicit store info (apple, google, horizon, unknown).
  • Documentation

    • Complete v14.4 docs published: installation, API reference, examples (purchase/subscription flows), guides, and troubleshooting.

✏️ Tip: You can customize this high-level summary in your review settings.

@hyochan hyochan added the 🚽 migration Activities due to changes in framework label Dec 8, 2025
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Dec 8, 2025

Copy link
Copy Markdown

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

The pull request restructures purchase verification and store mapping across the native and JavaScript layers. Key changes include adding a store field to purchases, transitioning verifyPurchaseWithProvider from returning an iapkit array to a single nullable object plus an optional errors array, introducing a new IapStore type supporting apple/google/horizon/unknown, and adding comprehensive documentation for version 14.4. Platform-specific property naming is updated from ios/android to apple/google with deprecation notices.

Changes

Cohort / File(s) Summary
Native Bridge — Android
android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt
Added mapIapStore() helper and populate NitroPurchase.store. verifyPurchaseWithProvider now returns a nullable single iapkit object and an errors array instead of an array of iapkit items; logging key changed to hasIapkit.
Native Bridge — iOS
ios/HybridRnIap.swift, ios/RnIapHelper.swift
Populate purchase .store via IapStore(fromString:). verifyPurchaseWithProvider maps iapkit to a nullable single result and converts errors to an array of typed error objects; updated returned result shape.
Type Specs & Types
src/specs/RnIap.nitro.ts, src/types.ts, src/index.ts
Added IapStore type (`'unknown'
Type Bridge / Runtime conversions
src/utils/type-bridge.ts
Added normalization helper and propagate nitroPurchase.store into PurchaseIOS/PurchaseAndroid conversions.
Android OpenIAP versions
openiap-versions.json
Updated OpenIAP dependency versions (apple → 1.3.0, google → 1.3.10, gql → 1.3.0).
Tests
src/__tests__/index.test.ts, src/__tests__/hooks/useIAP.test.ts, src/__tests__/utils/type-bridge.test.ts
Updated fixtures and assertions: iapkit now a single object, added store to purchase mocks, adjusted expectations to new shapes.
Examples
example/screens/PurchaseFlow.tsx, example/screens/SubscriptionFlow.tsx
Refactored verification handling to use result.iapkit directly; added fallback that aggregates and displays result.errors when iapkit is absent.
Docs — API Methods & Types
docs/docs/api/methods/core-methods.md, docs/docs/api/types.md, docs/versioned_docs/version-14.4/api/*
Documented IapStore, updated VerifyPurchaseWithProviderResult (iapkit nullable single, added errors), expanded IapkitPurchaseState, and replaced platform keys in examples with apple/google (deprecated ios/android).
Docs — Guides, Examples, Versioning
docs/versioned_docs/version-14.4/**/*, docs/docusaurus.config.ts, docs/versions.json, docs/versioned_sidebars/version-14.4-sidebars.json
Added comprehensive v14.4 docs (installation, guides, examples, API reference), updated docs versioning (14.5 Current, added 14.4), and sidebar.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Areas requiring extra attention:

  • Native bridge conversions (android/src/.../HybridRnIap.kt, ios/HybridRnIap.swift) — ensure enum/string → IapStore mapping covers all OpenIAP values and fallbacks.
  • Verify verifyPurchaseWithProvider shape change (array → nullable single iapkit + errors) is consistently handled across JS examples, tests, and native bridges.
  • Tests and example app flows — confirm coverage for: valid iapkit, missing iapkit with errors, and mixed/edge cases.
  • Type/spec propagation — ensure generated Nitro/TS types align with native bridge outputs (deprecation comments for ios/android keys).

Possibly related PRs

Suggested labels

dependencies, ❄️ types, 💲 openiap, 📖 documentation

Poem

🐰 I hopped through code with nimble paws,

I gave each purchase a little cause,
Apple, Google, Horizon named,
Errors gathered, iapkit tamed,
Docs of fourteen point four sing — hooray for claws!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly and concisely summarizes the main change: migrating to OpenIAP 1.3.0 with the addition of IapStore type and store field.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch migration/openiap-1.3

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov

codecov Bot commented Dec 8, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 78.94737% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 63.14%. Comparing base (b36d26e) to head (53d3514).
⚠️ Report is 6 commits behind head on main.

Files with missing lines Patch % Lines
src/index.ts 50.00% 1 Missing and 1 partial ⚠️
src/utils/type-bridge.ts 86.66% 2 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #3101      +/-   ##
==========================================
+ Coverage   62.97%   63.14%   +0.16%     
==========================================
  Files           9        9              
  Lines        1564     1582      +18     
  Branches      522      531       +9     
==========================================
+ Hits          985      999      +14     
- Misses        573      576       +3     
- Partials        6        7       +1     
Flag Coverage Δ
library 63.14% <78.94%> (+0.16%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/index.ts 66.62% <50.00%> (-0.14%) ⬇️
src/utils/type-bridge.ts 73.98% <86.66%> (+0.82%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @hyochan, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces significant updates to the in-app purchase system by migrating to OpenIAP 1.3.0, enhancing type safety and clarity across the API. It refines the Purchase object with a dedicated IapStore field, standardizes platform-specific request parameters to apple and google, and improves the IAPKit verification result structure for more precise error handling. These changes are thoroughly documented with new versioned guides and examples.

Highlights

  • OpenIAP Version Upgrade: The underlying OpenIAP libraries have been updated to their latest versions: Apple (1.3.0), Google (1.3.10), and GraphQL (1.3.0).
  • New IapStore Type and Field: A new IapStore type ('unknown' | 'apple' | 'google' | 'horizon') has been introduced, and a store field has been added to the Purchase object for explicit store identification, deprecating the existing platform field.
  • API Parameter Renaming: Platform-specific parameters in RequestPurchasePropsByPlatforms and RequestSubscriptionPropsByPlatforms have been renamed from ios and android to apple and google respectively, with the old fields marked as deprecated.
  • IAPKit Verification Result Refinement: The verifyPurchaseWithProvider method's result structure has been updated to return a single iapkit object (instead of an array) and now includes an errors field for more detailed error reporting.
  • Documentation Updates: New versioned documentation for 14.4 has been created, and the current documentation has been updated to 14.5, reflecting all new types, API changes, and examples.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

- Update openiap versions: apple 1.3.0, google 1.3.10, gql 1.3.0
- Add IapStore type ('unknown' | 'apple' | 'google' | 'horizon')
- Add store field to Purchase (platform field deprecated)
- Add apple/google fields to RequestPurchasePropsByPlatforms (ios/android deprecated)
- Change verifyPurchaseWithProvider iapkit from array to object
- Add errors field to VerifyPurchaseWithProviderResult
- Create versioned docs for 14.4, update current to 14.5
- Update documentation with correct types and examples
@hyochan hyochan force-pushed the migration/openiap-1.3 branch from 345345c to 58b7bca Compare December 8, 2025 20:10

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request migrates the project to openiap v1.3.0, introducing the IapStore type and a new store field to replace the deprecated platform field. It also updates the purchase request properties to use apple/google instead of ios/android, and refactors the verifyPurchaseWithProvider result structure. The changes are extensive, covering native code, TypeScript types, tests, and documentation, including versioning for the docs.

My review has identified a few issues. There's a significant issue in the Nitro spec where IapkitStore is used instead of the new IapStore, which could lead to incorrect store type mapping. I've also found a minor code generation issue causing duplicated @deprecated tags and an inconsistency in the newly created versioned documentation. Addressing these points will improve the correctness and clarity of the library.

Comment thread src/specs/RnIap.nitro.ts Outdated
@@ -40,6 +40,9 @@ export type IapkitPurchaseState =

export type IapkitStore = 'apple' | 'google';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The IapkitStore type is now redundant with the introduction of IapStore and does not support all the new store types like 'horizon' and 'unknown'. This can lead to data loss on the native side. Please remove this type and use IapStore throughout.

Comment thread src/specs/RnIap.nitro.ts Outdated
Comment thread docs/versioned_docs/version-14.4/api/types.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 18

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
docs/docs/examples/purchase-flow.md (1)

76-90: Update verification examples to handle optional iapkit result and errors field

The VerifyPurchaseWithProviderResult type has iapkit and errors as optional fields. The current examples access result.iapkit.isValid directly, which will throw at runtime if verification fails and iapkit is null:

if (result.iapkit.isValid) {  // ❌ Will throw if iapkit is null/undefined
  // ...
}

Use optional chaining and handle errors:

if (result.iapkit?.isValid) {
  // Grant entitlement to user
  await finishTransaction({purchase, isConsumable: true});
} else if (result.errors?.length) {
  console.warn('Verification failed:', result.errors);
}

This applies to all three code examples in this section (the standalone function, the useIAP hook example, and the verification response section).

src/__tests__/index.test.ts (1)

1269-1285: Mock result should use null instead of empty array for consistency with new API.

The test should handle null iapkit param has its mock returning iapkit: [] (empty array), but the new API contract uses iapkit: null when verification data is absent. This inconsistency could mask issues if the actual implementation returns null.

     it('should handle null iapkit param', async () => {
       (Platform as any).OS = 'ios';
       const mockResult = {
         provider: 'iapkit',
-        iapkit: [],
+        iapkit: null,
       };
       mockIap.verifyPurchaseWithProvider.mockResolvedValueOnce(mockResult);
docs/docs/api/methods/core-methods.md (1)

518-528: Code example inconsistent with updated type definition.

The example iterates over result.iapkit as an array (for (const item of result.iapkit)), but the type definition below shows iapkit is now a single optional object, not an array. This will cause a runtime error.

-    for (const item of result.iapkit) {
-      console.log('Is Valid:', item.isValid);
-      console.log('State:', item.state); // 'entitled', 'expired', 'canceled', etc.
-      console.log('Store:', item.store); // 'apple' or 'google'
+    if (result.iapkit) {
+      console.log('Is Valid:', result.iapkit.isValid);
+      console.log('State:', result.iapkit.state); // 'entitled', 'expired', 'canceled', etc.
+      console.log('Store:', result.iapkit.store); // 'apple' or 'google'
+    }
+    
+    if (result.errors) {
+      for (const error of result.errors) {
+        console.error('Verification error:', error.message);
+      }
     }
🧹 Nitpick comments (18)
docs/versioned_docs/version-14.4/guides/support.md (1)

25-25: Minor: Consider tightening the closing sentence.

Line 25 uses "We appreciate your support!" which, while friendly, is somewhat verbose. Consider alternatives like "Thank you for your support!" or simply removing this sentence if earlier context suffices.

docs/versioned_docs/version-14.4/installation.md (1)

126-127: Clarify deprecation timeline for the Folly option key migration.

The migration note explains that the option key was renamed from with-folly-no-couroutines to with-folly-no-coroutines, but it doesn't specify when the old key will be removed. Add clarity on the deprecation timeline to help users plan their config updates.

   Note migration:
-  - This option key was renamed from `with-folly-no-couroutines` to `with-folly-no-coroutines`. Update your Expo config accordingly. For compatibility, the plugin temporarily accepts the old key and logs a deprecation warning.
+  - This option key was renamed from `with-folly-no-couroutines` to `with-folly-no-coroutines`. Update your Expo config accordingly. For compatibility, the plugin temporarily accepts the old key and logs a deprecation warning (to be removed in a future release).
docs/versioned_docs/version-14.4/examples/available-purchases.md (2)

27-60: Unused destructured variable reduces clarity.

activeSubscriptions is destructured from the hook but never used in the restore function. Either use it to display active subscriptions in the restore flow or remove it from the destructuring to avoid confusion about what data is being processed.


18-18: Consider more professional documentation tone.

The phrase "vibe-coded with Claude" is informal and may not be appropriate in production documentation. Consider revising to a more neutral description such as: "Note that the example code is intentionally verbose for educational purposes."

docs/versioned_docs/version-14.4/guides/alternative-billing.md (2)

52-52: Remove redundant phrase.

The phrase "outside of" is redundant; simplify to "outside" for clarity.

-allow you to use external payment systems alongside or instead of the App Store/Google Play billing.
+allow you to use external payment systems alongside or instead of App Store/Google Play billing.

1-428: Consider documenting the new store field and IapStore type in alternative billing context.

The PR introduces a new store field to Purchase and a new IapStore type ('unknown' | 'apple' | 'google' | 'horizon'). While the alternative billing guide covers purchasing workflows, it does not reference these type changes. Consider clarifying how these fields relate to alternative billing flows, or whether users need to be aware of the store field when handling purchases in alternative billing scenarios.

Do the alternative billing examples or verification workflows need to reference or check the store field to distinguish between platform sources? This would help users understand the relationship between alternative billing modes and the purchase store information.

docs/versioned_docs/version-14.4/sponsors.md (1)

5-11: Split MDX imports onto separate lines for readability

Consider formatting the imports as separate statements to match typical MDX/TS style and keep diffs cleaner:

import SponsorSection from '@site/src/components/SponsorSection';
import GreatFrontEndTopFixed from '@site/src/uis/GreatFrontEndTopFixed';
docs/versioned_docs/version-14.4/examples/alternative-billing.md (1)

23-55: Align examples with new platform keys and versioned docs behavior

Two small consistency issues plus one optional improvement:

  1. Use apple / google instead of ios / android in request payloads

Given the updated RequestPurchasePropsByPlatforms types and docs that introduce apple/google and deprecate ios/android, it would be clearer if the examples here used the new keys as the primary pattern, e.g.:

await requestPurchase({
  request: {
    apple: {
      sku: product.productId,
      quantity: 1,
    },
  },
  type: 'in-app',
  useAlternativeBilling: true,
});

and for Android user-choice:

request: {
  google: {
    skus: [product.productId],
  },
},

If you still want to show ios/android, maybe call them out explicitly as deprecated/fallback fields.

  1. Prefer versioned/relative links from versioned docs

Links like /docs/guides/alternative-billing, /docs/guides/error-handling, and /docs/examples/purchase-flow will route to the current docs version, not necessarily 14.4. If the intent is to keep users within the 14.4 snapshot, consider using relative links such as:

  • ../guides/alternative-billing
  • ../guides/error-handling
  • ../examples/purchase-flow
  1. (Optional) Showcase error helper utilities in examples

To mirror the recommended runtime usage, you might tweak the error handling samples to use helpers such as isUserCancelledError and getUserFriendlyErrorMessage instead of directly checking error.code or error.message. This would keep the docs aligned with the normalized PurchaseError surface and helper APIs. Based on learnings, this is the preferred pattern in example code.

Also applies to: 69-118, 132-169, 193-209, 235-237

docs/versioned_docs/version-14.4/getting-started/setup-horizon.md (1)

11-21: Minor wording tweak: hyphenate “react-native-iap-specific”

In “This guide focuses on react-native-iap specific configuration.” you may want to hyphenate as:

This guide focuses on react-native-iap-specific configuration.

Purely a grammar/readability polish; the rest of the guide content and structure look good.

docs/versioned_docs/version-14.4/examples/subscription-flow.md (1)

112-114: Fix markdown formatting for code block. The Markdown specification requires blank lines surrounding fenced code blocks and language specifiers for syntax highlighting.

-   ```
+   ```bash
    EXPO_PUBLIC_IAPKIT_API_KEY=your_api_key_here
-   ```
+   ```
docs/versioned_docs/version-14.4/api/methods/core-methods.md (1)

130-134: Minor style note on platform differences explanation. Consider rephrasing for clarity:

- > - **iOS**: Can only purchase one product at a time (uses `sku: string`)
+ > - **iOS**: Can purchase only one product at a time (uses `sku: string`)
docs/versioned_docs/version-14.4/guides/troubleshooting.md (1)

373-376: Fix markdown formatting for code block. Add a blank line before the fenced code block per Markdown spec:

   // android/app/src/main/AndroidManifest.xml
+
   ```xml
src/index.ts (1)

1426-1445: Update JSDoc to reflect the new return shape.

The function implementation has changed to return iapkit as a single object (or null) instead of an array, and now includes an errors field. The JSDoc should be updated to document this.

Update the JSDoc example to clarify the new return shape:

  * @example
  * ```typescript
  * const result = await verifyPurchaseWithProvider({
  *   provider: 'iapkit',
  *   iapkit: {
  *     apiKey: 'your-api-key',
  *     apple: { jws: purchase.purchaseToken },
  *     google: { purchaseToken: purchase.purchaseToken },
  *   },
  * });
+ * 
+ * // result.iapkit is a single object (or null), not an array
+ * if (result.iapkit?.isValid) {
+ *   console.log('Purchase valid, store:', result.iapkit.store);
+ * }
+ * 
+ * // Check for errors if iapkit is null
+ * if (result.errors) {
+ *   console.error('Verification errors:', result.errors);
+ * }
  * ```
docs/versioned_docs/version-14.4/api/types.md (1)

195-195: Remove stray EOF token from the rendered docs

The closing sentence currently ends with “EOF”, which looks like a leftover editor marker rather than intentional content. Consider trimming it so the page ends cleanly:

-If you need to regenerate types place new schema definitions under the GraphQL inputs and rerun the generator. EOF
+If you need to regenerate types place new schema definitions under the GraphQL inputs and rerun the generator.
src/utils/type-bridge.ts (1)

34-37: Store normalization looks correct; consider logging unexpected store values

The new IapStore plumbing and normalizeStore usage in convertNitroPurchaseToPurchase are consistent and type‑safe:

  • normalizeStore lowercases the incoming nitroPurchase.store string and maps it to 'apple' | 'google' | 'horizon' | 'unknown'.
  • The resulting store is attached to both PurchaseIOS and PurchaseAndroid, matching the updated generated types.

One optional improvement: for debugging and forward compatibility, you might want to log unexpected store strings before defaulting to 'unknown', similar to how normalizeProductTypeIOS warns on unknown product types. For example:

 function normalizeStore(value?: Nullable<string>): IapStore {
-  switch (value?.toLowerCase()) {
+  const normalized = value?.toLowerCase();
+  switch (normalized) {
     case 'apple':
       return STORE_APPLE;
     case 'google':
       return STORE_GOOGLE;
     case 'horizon':
       return STORE_HORIZON;
     default:
-      return STORE_UNKNOWN;
+      if (value) {
+        RnIapConsole.warn(
+          `[react-native-iap] Unknown store "${value}", defaulting to "unknown".`,
+        );
+      }
+      return STORE_UNKNOWN;
   }
 }

Not required for correctness, but it would make it easier to spot schema or bridge mismatches in development.

Also applies to: 65-76, 353-363, 450-458

docs/versioned_docs/version-14.4/getting-started/setup-android.md (1)

52-64: Missing dependency in useEffect dependency array.

The fetchProducts function is called inside the effect but not listed in the dependency array, which may cause stale closure issues or lint warnings.

   React.useEffect(() => {
     if (connected) {
       // Fetch products and subscriptions
       fetchProducts({
         skus: androidProductIds.filter((id) => !id.includes('subscription')),
         type: 'in-app',
       });
       fetchProducts({
         skus: androidProductIds.filter((id) => id.includes('subscription')),
         type: 'subs',
       });
     }
-  }, [connected]);
+  }, [connected, fetchProducts]);
ios/HybridRnIap.swift (1)

378-395: Remove redundant nil initializations.

SwiftLint correctly flags that initializing optional variables with nil is redundant in Swift, as optionals default to nil.

-                var nitroIapkitResult: NitroVerifyPurchaseWithIapkitResult? = nil
+                var nitroIapkitResult: NitroVerifyPurchaseWithIapkitResult?
                 if let item = result.iapkit {
                     nitroIapkitResult = NitroVerifyPurchaseWithIapkitResult(
                         isValid: item.isValid,
                         state: IapkitPurchaseState(fromString: item.state.rawValue) ?? .unknown,
                         store: IapkitStore(fromString: item.store.rawValue) ?? .apple
                     )
                 }
                 // Convert errors if present
-                var nitroErrors: [NitroVerifyPurchaseWithProviderError]? = nil
+                var nitroErrors: [NitroVerifyPurchaseWithProviderError]?
                 if let errors = result.errors {
docs/docs/api/types.md (1)

136-155: Documentation correctly reflects the property key migration.

The deprecation notices for ios/android in favor of apple/google are clear and accurate.

However, consider adding documentation for the other significant type changes in this PR:

  • The new IapStore type ('unknown' | 'apple' | 'google' | 'horizon')
  • The new store field on PurchaseCommon (and the deprecated platform field)
  • The VerifyPurchaseWithProviderResult.errors field and VerifyPurchaseWithProviderError type

These are breaking changes that API consumers would benefit from seeing documented.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 51af058 and 58b7bca.

⛔ Files ignored due to path filters (1)
  • example/ios/Podfile.lock is excluded by !**/*.lock
📒 Files selected for processing (53)
  • android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt (3 hunks)
  • docs/docs/api/methods/core-methods.md (2 hunks)
  • docs/docs/api/types.md (1 hunks)
  • docs/docs/examples/purchase-flow.md (2 hunks)
  • docs/docs/intro.md (1 hunks)
  • docs/docusaurus.config.ts (1 hunks)
  • docs/versioned_docs/version-14.4/api/error-codes.md (1 hunks)
  • docs/versioned_docs/version-14.4/api/error-handling.md (1 hunks)
  • docs/versioned_docs/version-14.4/api/index.md (1 hunks)
  • docs/versioned_docs/version-14.4/api/methods/_category_.json (1 hunks)
  • docs/versioned_docs/version-14.4/api/methods/core-methods.md (1 hunks)
  • docs/versioned_docs/version-14.4/api/methods/listeners.md (1 hunks)
  • docs/versioned_docs/version-14.4/api/types.md (1 hunks)
  • docs/versioned_docs/version-14.4/api/use-iap.md (1 hunks)
  • docs/versioned_docs/version-14.4/examples/_category_.json (1 hunks)
  • docs/versioned_docs/version-14.4/examples/alternative-billing.md (1 hunks)
  • docs/versioned_docs/version-14.4/examples/available-purchases.md (1 hunks)
  • docs/versioned_docs/version-14.4/examples/offer-code.md (1 hunks)
  • docs/versioned_docs/version-14.4/examples/purchase-flow.md (1 hunks)
  • docs/versioned_docs/version-14.4/examples/subscription-flow.md (1 hunks)
  • docs/versioned_docs/version-14.4/getting-started/installation.md (1 hunks)
  • docs/versioned_docs/version-14.4/getting-started/setup-android.md (1 hunks)
  • docs/versioned_docs/version-14.4/getting-started/setup-horizon.md (1 hunks)
  • docs/versioned_docs/version-14.4/getting-started/setup-ios.md (1 hunks)
  • docs/versioned_docs/version-14.4/guides/_category_.json (1 hunks)
  • docs/versioned_docs/version-14.4/guides/alternative-billing.md (1 hunks)
  • docs/versioned_docs/version-14.4/guides/error-handling.md (1 hunks)
  • docs/versioned_docs/version-14.4/guides/expo-plugin.md (1 hunks)
  • docs/versioned_docs/version-14.4/guides/faq.md (1 hunks)
  • docs/versioned_docs/version-14.4/guides/lifecycle.md (1 hunks)
  • docs/versioned_docs/version-14.4/guides/offer-code-redemption.md (1 hunks)
  • docs/versioned_docs/version-14.4/guides/purchases.md (1 hunks)
  • docs/versioned_docs/version-14.4/guides/subscription-offers.md (1 hunks)
  • docs/versioned_docs/version-14.4/guides/subscription-validation.md (1 hunks)
  • docs/versioned_docs/version-14.4/guides/support.md (1 hunks)
  • docs/versioned_docs/version-14.4/guides/troubleshooting.md (1 hunks)
  • docs/versioned_docs/version-14.4/installation.md (1 hunks)
  • docs/versioned_docs/version-14.4/intro.md (1 hunks)
  • docs/versioned_docs/version-14.4/sponsors.md (1 hunks)
  • docs/versioned_sidebars/version-14.4-sidebars.json (1 hunks)
  • docs/versions.json (1 hunks)
  • example/screens/PurchaseFlow.tsx (1 hunks)
  • example/screens/SubscriptionFlow.tsx (1 hunks)
  • ios/HybridRnIap.swift (1 hunks)
  • ios/RnIapHelper.swift (1 hunks)
  • openiap-versions.json (1 hunks)
  • src/__tests__/hooks/useIAP.test.ts (1 hunks)
  • src/__tests__/index.test.ts (8 hunks)
  • src/__tests__/utils/type-bridge.test.ts (2 hunks)
  • src/index.ts (1 hunks)
  • src/specs/RnIap.nitro.ts (4 hunks)
  • src/types.ts (9 hunks)
  • src/utils/type-bridge.ts (5 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

When declaring API params/results in TS modules, import canonical types from src/types.ts rather than creating ad‑hoc interfaces.

Files:

  • src/__tests__/index.test.ts
  • src/__tests__/hooks/useIAP.test.ts
  • src/__tests__/utils/type-bridge.test.ts
  • src/index.ts
  • src/types.ts
  • src/specs/RnIap.nitro.ts
  • src/utils/type-bridge.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use type-only imports when importing types (import type).

Files:

  • src/__tests__/index.test.ts
  • docs/docusaurus.config.ts
  • example/screens/PurchaseFlow.tsx
  • example/screens/SubscriptionFlow.tsx
  • src/__tests__/hooks/useIAP.test.ts
  • src/__tests__/utils/type-bridge.test.ts
  • src/index.ts
  • src/types.ts
  • src/specs/RnIap.nitro.ts
  • src/utils/type-bridge.ts
{src/**/*.{ts,tsx},example/**/*.{ts,tsx},example-expo/**/*.{ts,tsx}}

📄 CodeRabbit inference engine (CLAUDE.md)

{src/**/*.{ts,tsx},example/**/*.{ts,tsx},example-expo/**/*.{ts,tsx}}: Prefer using isUserCancelledError() and getUserFriendlyErrorMessage() with normalized ErrorCode when handling purchase errors.
Use Platform.OS checks for platform-specific logic in React Native code.

Files:

  • src/__tests__/index.test.ts
  • example/screens/PurchaseFlow.tsx
  • example/screens/SubscriptionFlow.tsx
  • src/__tests__/hooks/useIAP.test.ts
  • src/__tests__/utils/type-bridge.test.ts
  • src/index.ts
  • src/types.ts
  • src/specs/RnIap.nitro.ts
  • src/utils/type-bridge.ts
{example/**/*.{ts,tsx},example-expo/**/*.{ts,tsx}}

📄 CodeRabbit inference engine (CLAUDE.md)

{example/**/*.{ts,tsx},example-expo/**/*.{ts,tsx}}: In useIAP hook usage, do not expect returned data from methods that return Promise; consume state from the hook instead.
Do not call parseErrorStringToJsonObj() in app/user code; errors are already normalized by the library.

Files:

  • example/screens/PurchaseFlow.tsx
  • example/screens/SubscriptionFlow.tsx
{ios/**/*.swift,android/src/main/java/**/*.kt}

📄 CodeRabbit inference engine (CLAUDE.md)

Follow the native class function ordering: (1) properties/init, (2) public cross-platform methods, (3) platform-specific public methods (IOS/Android suffix), (4) event listener methods, (5) private helpers.

Files:

  • ios/HybridRnIap.swift
  • ios/RnIapHelper.swift
  • android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt
src/types.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Never edit src/types.ts manually; it is generated. Import canonical types from this file instead of defining ad‑hoc interfaces.

Files:

  • src/types.ts
**/*.nitro.ts

📄 CodeRabbit inference engine (CLAUDE.md)

After modifying any .nitro.ts interface files, regenerate Nitro bridge files (yarn specs).

Files:

  • src/specs/RnIap.nitro.ts
🧠 Learnings (8)
📓 Common learnings
Learnt from: hyochan
Repo: hyochan/react-native-iap PR: 3015
File: src/types.ts:137-166
Timestamp: 2025-09-18T16:45:10.582Z
Learning: The types in src/types.ts are auto-generated from openiap-gql1.0.6. Breaking changes in mutation return types (like acknowledgePurchaseAndroid returning Promise<boolean>, finishTransaction returning Promise<void>, etc.) originate from updates to this external GraphQL schema generator, not manual refactoring.
Learnt from: hyochan
Repo: hyochan/react-native-iap PR: 3002
File: docs/docs/getting-started/setup-ios.md:55-60
Timestamp: 2025-09-14T00:13:04.055Z
Learning: The validateReceipt function from useIAP hook in react-native-iap expects a transaction identifier as parameter, which is accessed via purchase.id (not purchase.productId). This is confirmed by the maintainer hyochan and aligns with the library's migration from purchase.transactionId to purchase.id.
📚 Learning: 2025-09-14T00:13:04.055Z
Learnt from: hyochan
Repo: hyochan/react-native-iap PR: 3002
File: docs/docs/getting-started/setup-ios.md:55-60
Timestamp: 2025-09-14T00:13:04.055Z
Learning: The validateReceipt function from useIAP hook in react-native-iap expects a transaction identifier as parameter, which is accessed via purchase.id (not purchase.productId). This is confirmed by the maintainer hyochan and aligns with the library's migration from purchase.transactionId to purchase.id.

Applied to files:

  • docs/versioned_docs/version-14.4/guides/lifecycle.md
  • docs/versioned_docs/version-14.4/getting-started/setup-ios.md
  • src/__tests__/index.test.ts
  • docs/versioned_docs/version-14.4/examples/purchase-flow.md
  • docs/versioned_docs/version-14.4/guides/troubleshooting.md
  • docs/versioned_docs/version-14.4/guides/faq.md
  • example/screens/PurchaseFlow.tsx
  • docs/versioned_docs/version-14.4/api/methods/listeners.md
  • docs/versioned_docs/version-14.4/guides/subscription-validation.md
  • docs/versioned_docs/version-14.4/api/use-iap.md
  • docs/docs/examples/purchase-flow.md
  • example/screens/SubscriptionFlow.tsx
  • src/__tests__/hooks/useIAP.test.ts
  • src/__tests__/utils/type-bridge.test.ts
  • docs/docs/intro.md
  • docs/versioned_docs/version-14.4/api/methods/core-methods.md
  • ios/HybridRnIap.swift
  • src/index.ts
  • docs/versioned_docs/version-14.4/guides/purchases.md
  • src/types.ts
  • src/specs/RnIap.nitro.ts
  • docs/docs/api/methods/core-methods.md
  • src/utils/type-bridge.ts
📚 Learning: 2025-10-02T19:35:19.667Z
Learnt from: CR
Repo: hyochan/react-native-iap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T19:35:19.667Z
Learning: Applies to {example/**/*.{ts,tsx},example-expo/**/*.{ts,tsx}} : In useIAP hook usage, do not expect returned data from methods that return Promise<void>; consume state from the hook instead.

Applied to files:

  • docs/versioned_docs/version-14.4/guides/lifecycle.md
  • docs/versioned_docs/version-14.4/api/error-codes.md
  • src/__tests__/index.test.ts
  • docs/versioned_docs/version-14.4/examples/purchase-flow.md
  • docs/versioned_docs/version-14.4/guides/troubleshooting.md
  • docs/versioned_docs/version-14.4/guides/error-handling.md
  • docs/versioned_docs/version-14.4/guides/faq.md
  • docs/versioned_docs/version-14.4/examples/available-purchases.md
  • example/screens/PurchaseFlow.tsx
  • docs/versioned_docs/version-14.4/api/methods/listeners.md
  • docs/versioned_docs/version-14.4/guides/subscription-validation.md
  • docs/versioned_docs/version-14.4/api/use-iap.md
  • docs/docs/examples/purchase-flow.md
  • example/screens/SubscriptionFlow.tsx
  • docs/docs/api/types.md
  • docs/versioned_docs/version-14.4/examples/alternative-billing.md
  • docs/versioned_docs/version-14.4/api/types.md
  • src/__tests__/hooks/useIAP.test.ts
  • docs/versioned_docs/version-14.4/api/methods/core-methods.md
  • docs/versioned_docs/version-14.4/guides/subscription-offers.md
  • docs/versioned_docs/version-14.4/api/index.md
  • docs/versioned_docs/version-14.4/examples/subscription-flow.md
  • src/index.ts
  • docs/versioned_docs/version-14.4/guides/purchases.md
  • src/types.ts
  • docs/versioned_docs/version-14.4/guides/expo-plugin.md
  • src/specs/RnIap.nitro.ts
  • docs/docs/api/methods/core-methods.md
  • src/utils/type-bridge.ts
📚 Learning: 2025-10-02T19:35:19.667Z
Learnt from: CR
Repo: hyochan/react-native-iap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T19:35:19.667Z
Learning: Applies to {src/**/*.{ts,tsx},example/**/*.{ts,tsx},example-expo/**/*.{ts,tsx}} : Prefer using isUserCancelledError() and getUserFriendlyErrorMessage() with normalized ErrorCode when handling purchase errors.

Applied to files:

  • docs/versioned_docs/version-14.4/api/error-codes.md
  • src/__tests__/index.test.ts
  • docs/versioned_docs/version-14.4/guides/troubleshooting.md
  • docs/versioned_docs/version-14.4/guides/error-handling.md
  • example/screens/PurchaseFlow.tsx
  • docs/versioned_docs/version-14.4/api/methods/listeners.md
  • docs/versioned_docs/version-14.4/api/use-iap.md
  • docs/versioned_docs/version-14.4/api/error-handling.md
  • example/screens/SubscriptionFlow.tsx
  • docs/docs/api/types.md
  • docs/versioned_docs/version-14.4/examples/alternative-billing.md
  • docs/versioned_docs/version-14.4/api/types.md
  • docs/docs/intro.md
  • docs/versioned_docs/version-14.4/api/methods/core-methods.md
  • docs/versioned_docs/version-14.4/guides/subscription-offers.md
  • src/index.ts
  • docs/versioned_docs/version-14.4/guides/purchases.md
  • src/types.ts
  • docs/docs/api/methods/core-methods.md
  • src/utils/type-bridge.ts
📚 Learning: 2025-09-18T16:45:10.582Z
Learnt from: hyochan
Repo: hyochan/react-native-iap PR: 3015
File: src/types.ts:137-166
Timestamp: 2025-09-18T16:45:10.582Z
Learning: The types in src/types.ts are auto-generated from openiap-gql1.0.6. Breaking changes in mutation return types (like acknowledgePurchaseAndroid returning Promise<boolean>, finishTransaction returning Promise<void>, etc.) originate from updates to this external GraphQL schema generator, not manual refactoring.

Applied to files:

  • src/__tests__/index.test.ts
  • openiap-versions.json
  • example/screens/PurchaseFlow.tsx
  • docs/docs/examples/purchase-flow.md
  • example/screens/SubscriptionFlow.tsx
  • docs/docs/api/types.md
  • docs/versioned_docs/version-14.4/api/types.md
  • src/__tests__/hooks/useIAP.test.ts
  • src/__tests__/utils/type-bridge.test.ts
  • docs/docs/intro.md
  • docs/versioned_docs/version-14.4/api/methods/core-methods.md
  • ios/HybridRnIap.swift
  • src/index.ts
  • src/types.ts
  • android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt
  • src/specs/RnIap.nitro.ts
  • docs/docs/api/methods/core-methods.md
  • src/utils/type-bridge.ts
📚 Learning: 2025-09-13T01:07:18.841Z
Learnt from: hyochan
Repo: hyochan/react-native-iap PR: 2999
File: android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt:644-660
Timestamp: 2025-09-13T01:07:18.841Z
Learning: In Android IAP error handling: purchaseToken and productId are distinct properties - purchaseToken identifies a completed purchase transaction (should be null in error cases), while productId is the product SKU for context

Applied to files:

  • docs/versioned_docs/version-14.4/api/use-iap.md
  • docs/versioned_docs/version-14.4/api/error-handling.md
  • src/__tests__/hooks/useIAP.test.ts
  • src/__tests__/utils/type-bridge.test.ts
  • docs/versioned_docs/version-14.4/api/methods/core-methods.md
  • docs/versioned_docs/version-14.4/guides/purchases.md
  • src/types.ts
  • android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt
  • src/specs/RnIap.nitro.ts
  • docs/docs/api/methods/core-methods.md
  • src/utils/type-bridge.ts
📚 Learning: 2025-10-02T19:35:19.667Z
Learnt from: CR
Repo: hyochan/react-native-iap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T19:35:19.667Z
Learning: Applies to src/types.ts : Never edit src/types.ts manually; it is generated. Import canonical types from this file instead of defining ad‑hoc interfaces.

Applied to files:

  • docs/versioned_docs/version-14.4/api/types.md
📚 Learning: 2025-10-02T19:35:19.667Z
Learnt from: CR
Repo: hyochan/react-native-iap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T19:35:19.667Z
Learning: Applies to src/**/*.{ts,tsx} : When declaring API params/results in TS modules, import canonical types from src/types.ts rather than creating ad‑hoc interfaces.

Applied to files:

  • docs/versioned_docs/version-14.4/api/types.md
🧬 Code graph analysis (9)
src/__tests__/index.test.ts (2)
android/src/main/java/com/margelo/nitro/iap/RnIapLog.kt (1)
  • result (14-16)
ios/RnIapLog.swift (1)
  • result (41-43)
example/screens/PurchaseFlow.tsx (2)
android/src/main/java/com/margelo/nitro/iap/RnIapLog.kt (1)
  • result (14-16)
ios/RnIapLog.swift (1)
  • result (41-43)
ios/HybridRnIap.swift (2)
src/specs/RnIap.nitro.ts (5)
  • NitroVerifyPurchaseWithIapkitResult (239-243)
  • IapkitPurchaseState (30-39)
  • IapkitStore (41-41)
  • NitroVerifyPurchaseWithProviderError (245-248)
  • NitroVerifyPurchaseWithProviderResult (250-254)
src/types.ts (1)
  • IapkitPurchaseState (186-186)
src/index.ts (2)
android/src/main/java/com/margelo/nitro/iap/RnIapLog.kt (1)
  • result (14-16)
ios/RnIapLog.swift (1)
  • result (41-43)
ios/RnIapHelper.swift (2)
src/specs/RnIap.nitro.ts (1)
  • IapStore (44-44)
src/types.ts (1)
  • IapStore (183-183)
src/types.ts (1)
src/specs/RnIap.nitro.ts (1)
  • PurchaseVerificationProvider (47-47)
android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt (1)
src/specs/RnIap.nitro.ts (3)
  • NitroVerifyPurchaseWithIapkitResult (239-243)
  • NitroVerifyPurchaseWithProviderError (245-248)
  • NitroVerifyPurchaseWithProviderResult (250-254)
src/specs/RnIap.nitro.ts (1)
src/types.ts (2)
  • IapStore (183-183)
  • IapPlatform (181-181)
src/utils/type-bridge.ts (2)
src/specs/RnIap.nitro.ts (1)
  • IapStore (44-44)
src/types.ts (2)
  • IapStore (183-183)
  • PurchaseIOS (508-548)
🪛 LanguageTool
docs/versioned_docs/version-14.4/guides/alternative-billing.md

[style] ~52-~52: This phrase is redundant. Consider using “outside”.
Context: ...les developers to offer payment options outside of the platform's standard billing systems...

(OUTSIDE_OF)

docs/versioned_docs/version-14.4/getting-started/setup-horizon.md

[grammar] ~19-~19: Use a hyphen to join words.
Context: ... This guide focuses on react-native-iap specific configuration. ::: ## Prerequ...

(QB_NEW_EN_HYPHEN)

docs/versioned_docs/version-14.4/getting-started/installation.md

[grammar] ~146-~146: Use a hyphen to join words.
Context: ...ogle Play Billing configuration ## Real world examples For detailed platform-sp...

(QB_NEW_EN_HYPHEN)

docs/versioned_docs/version-14.4/guides/faq.md

[grammar] ~47-~47: Use a hyphen to join words.
Context: ...s! react-native-iap works in both Expo managed and bare React Native projects. ...

(QB_NEW_EN_HYPHEN)


[locale-violation] ~261-~261: In American English, ‘afterward’ is the preferred variant. ‘Afterwards’ is more commonly used in British English and other dialects.
Context: ... a transient error that arrives shortly afterwards. Tip (dedupe in app logic): ```tsx im...

(AFTERWARDS_US)


[style] ~289-~289: This phrase is redundant. Consider writing “outcome”.
Context: ...on await requestPurchase(...) for the final outcome; multiple events and inter-session comp...

(FINAL_END)


[grammar] ~543-~543: Use a hyphen to join words.
Context: ...ue to 'internal' protection level(yoga related) **Root Cause:** TheappTransa...

(QB_NEW_EN_HYPHEN)

docs/versioned_docs/version-14.4/api/methods/listeners.md

[grammar] ~496-~496: Ensure spelling is correct
Context: ...our purchase listener. ## Alternative: useIAP Hook For simpler usage, consider using...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~496-~496: Ensure spelling is correct
Context: ...e listener. ## Alternative: useIAP Hook For simpler usage, consider using the `u...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

docs/versioned_docs/version-14.4/guides/support.md

[style] ~25-~25: Consider using a shorter alternative to avoid wordiness.
Context: ...he library is being used and how we can make it better. We appreciate your support! ## Become...

(MADE_IT_JJR)

docs/versioned_docs/version-14.4/guides/offer-code-redemption.md

[style] ~44-~44: This phrase is redundant (‘OS’ stands for ‘operating system’). Use simply “iOS”.
Context: ... The redemption sheet is handled by the iOS system - After successful redemption, purchase...

(ACRONYM_TAUTOLOGY)

docs/versioned_docs/version-14.4/installation.md

[grammar] ~146-~146: Use a hyphen to join words.
Context: ...ogle Play Billing configuration ## Real world examples For detailed platform-sp...

(QB_NEW_EN_HYPHEN)

docs/versioned_docs/version-14.4/api/methods/core-methods.md

[style] ~130-~130: Consider replacing ‘only’ with a different word to let your writing stand out.
Context: ...tform Differences:** > > - iOS: Can only purchase one product at a time (uses `s...

(ONLY_EXCLUSIVELY_STYLE)


[grammar] ~615-~615: Use a hyphen to join words.
Context: ...ly helpers expose StoreKit and App Store specific capabilities. Most day‑to‑day f...

(QB_NEW_EN_HYPHEN)


[style] ~918-~918: This phrase is redundant. Consider using “outside”.
Context: ...les developers to offer payment options outside of the platform's standard billing systems...

(OUTSIDE_OF)


[uncategorized] ~983-~983: Do not mix variants of the same word (‘cancelled’ and ‘canceled’) within a single text.
Context: ...-trueif user accepted,false` if cancelled Platform: Android only #### creat...

(EN_EXACT_COHERENCY_RULE)

docs/versioned_docs/version-14.4/guides/purchases.md

[grammar] ~24-~24: Ensure spelling is correct
Context: ...on()` after validation ## Recommended: useIAP Hook ```tsx const {products, requestPu...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~24-~24: Ensure spelling is correct
Context: ... validation ## Recommended: useIAP Hook tsx const {products, requestPurchase, finishTransaction} = useIAP({ onPurchaseSuccess: async (purchase) => { // Validate on your server, then finish await finishTransaction({purchase, isConsumable: true}); }, onPurchaseError: (error) => { if (error.code !== ErrorCode.UserCancelled) { Alert.alert('Error', error.message); } }, }); ## Direct Listeners ```tsx useEffect(() =>...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

docs/versioned_docs/version-14.4/guides/expo-plugin.md

[uncategorized] ~30-~30: The official name of this software platform is spelled with a capital “H”.
Context: ...on to AndroidManifest.xml. - Adds the io.github.hyochan.openiap:openiap-google depende...

(GITHUB)

🪛 markdownlint-cli2 (0.18.1)
docs/versioned_docs/version-14.4/guides/troubleshooting.md

373-373: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

docs/versioned_docs/version-14.4/examples/subscription-flow.md

112-112: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


112-112: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 SwiftLint (0.57.0)
ios/HybridRnIap.swift

[Warning] 378-378: Initializing an optional variable with nil is redundant

(redundant_optional_initialization)


[Warning] 387-387: Initializing an optional variable with nil is redundant

(redundant_optional_initialization)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build-android
  • GitHub Check: build-ios
🔇 Additional comments (45)
docs/versioned_docs/version-14.4/guides/support.md (2)

1-7: Well-structured support documentation page.

The frontmatter, component import, and overall structure are clean and follow documentation conventions. This provides clear guidance on obtaining community support.


9-26: Content is welcoming and comprehensive.

The support sections effectively guide users to GitHub Issues, Slack for real-time help, and community showcasing. Tone and messaging encourage engagement.

Please verify that the external links are accessible and accurate:

Also confirm the relative path reference ../sponsors on line 29 correctly points to the sponsors documentation page in the version-14.4 structure.

docs/versioned_docs/version-14.4/installation.md (2)

1-9: Documentation structure is clear and consistent.

The frontmatter, component imports, and section organization follow the pattern of other version-14.4 documentation pages. The GreatFrontEndTopFixed header placement and Docusaurus conventions are correct.


143-144: All referenced documentation files exist in the version-14.4 structure—no action required.

Verification confirms that all linked documentation files exist in docs/versioned_docs/version-14.4/:

  • getting-started/setup-ios.md
  • getting-started/setup-android.md
  • examples/purchase-flow.md
  • examples/subscription-flow.md
  • examples/available-purchases.md
  • examples/offer-code.md

The relative links in the installation guide are valid and functional.

docs/versioned_docs/version-14.4/guides/alternative-billing.md (2)

239-239: The AlternativeBilling.tsx file exists at the referenced path (example/screens/AlternativeBilling.tsx), so the documentation link is valid and users can access the complete working example.


423-424: Internal documentation links are valid.

The referenced pages exist: /docs/api/methods/core-methods#alternative-billing-apis (line 916) and /docs/api/types are both present in version 14.4 and properly published.

docs/versioned_docs/version-14.4/examples/_category_.json (1)

1-8: Category config for v14.4 examples looks correct

Label, position, and generated index setup are consistent with Docusaurus conventions and the surrounding docs structure.

docs/versions.json (1)

1-1: Docs versions list is consistent with config

Adding "14.4" as the newest version in the array matches the docs configuration where 14.5 is current and 14.4 is the latest versioned snapshot.

docs/docusaurus.config.ts (1)

53-60: Docs versioning update is coherent

Promoting 14.5 to the current label and adding an explicit 14.4 version entry (with matching path) lines up with the new versions.json and the added 14.4 docs.

docs/versioned_sidebars/version-14.4-sidebars.json (1)

1-75: Sidebar structure for 14.4 is well-organized

The tutorialSidebar groups getting started guides, API reference (including methods and listeners), examples (including the new alternative billing flow), and sponsors in a clear hierarchy that matches the new 14.4 docs.

openiap-versions.json (1)

2-4: Versions are correctly integrated into build system via dynamic loading; clarify gql usage

The openiap versions in the JSON file are properly utilized:

  • iOS (Podspec): Reads apple 1.3.0 from openiap-versions.json and passes it to the openiap pod dependency
  • Android (Gradle): Reads google 1.3.10 from openiap-versions.json and applies it to openiap-google and openiap-google-horizon implementations

Both build systems validate version format and existence, ensuring generation and runtime stay in sync through a single source of truth.

However, the gql 1.3.0 version is defined in the JSON but appears unused in the codebase. Clarify whether this is intentional or should be removed.

docs/versioned_docs/version-14.4/intro.md (1)

1-153: LGTM. The introduction page provides a clear overview of react-native-iap and aligns well with the version 14.4 documentation structure.

docs/versioned_docs/version-14.4/api/methods/listeners.md (1)

1-519: LGTM. The listeners documentation is comprehensive and provides clear examples for both functional and class components, with proper cleanup patterns demonstrated throughout.

docs/versioned_docs/version-14.4/examples/subscription-flow.md (1)

104-137: iapkit result structure correctly documented. The IAPKit verification example correctly shows result.iapkit.isValid (singular object), which aligns with the PR's change from array to optional object structure.

docs/docs/intro.md (1)

90-91: Platform key naming updated correctly. The changes from ios/android to apple/google properly reflect the PR migration to align with the new IapStore type and platform naming conventions.

docs/versioned_docs/version-14.4/api/methods/core-methods.md (1)

518-567: Verify iapkit result structure against implementation. The documentation shows iapkit as an Array, but the PR summary indicates it was changed from array to an optional single object with an additional errors array. The code example iterates over result.iapkit and the TypeScript interface defines it as Array<{...}>, but this may not reflect the actual post-migration API structure.

Please confirm:

  • Is iapkit now a single nullable object (not an array)?
  • Should the type be iapkit?: { isValid, state, store } | null instead of Array<...>?
  • Is there a new errors?: VerifyPurchaseWithProviderError[] field?

If confirmed, the documented examples and type definitions need updates:

-  for (const item of result.iapkit) {
-    console.log('Is Valid:', item.isValid);
-    console.log('State:', item.state);
-    console.log('Store:', item.store);
-  }
+  if (result.iapkit) {
+    console.log('Is Valid:', result.iapkit.isValid);
+    console.log('State:', result.iapkit.state);
+    console.log('Store:', result.iapkit.store);
+  } else if (result.errors) {
+    console.error('Verification errors:', result.errors);
+  }

And update the TypeScript interface:

interface VerifyPurchaseWithProviderResult {
  provider: 'iapkit';
-  iapkit: Array<{
+  iapkit?: {
    isValid: boolean;
    state: IapkitPurchaseState;
-    store: 'apple' | 'google';
-  }>;
+    store: IapkitPurchaseState;
+  } | null;
+  errors?: Array<{code?: string | null; message: string}>;
}
docs/versioned_docs/version-14.4/guides/troubleshooting.md (1)

186-220: Verify purchase identifier property name. The code example uses purchase.transactionId, but learnings indicate the library migrated to purchase.id as the transaction identifier. Please confirm whether transactionId is still valid or if this should be updated to:

const isValid = await validateReceiptOnServer({
-  transactionId: purchase.transactionId,
+  transactionId: purchase.id,
   productId: purchase.productId,
});
docs/versioned_docs/version-14.4/guides/subscription-validation.md (1)

1-196: LGTM. The subscription validation guide provides clear explanations of StoreKit 2 and Google Play Billing APIs, with practical examples showing how to use getAvailablePurchases, getActiveSubscriptions, and server-side validation patterns.

docs/versioned_docs/version-14.4/api/use-iap.md (1)

1-632: LGTM. The useIAP hook documentation clearly explains the hook's behavior, especially the critical distinction that methods like fetchProducts and requestPurchase return Promise<void> and update internal state (not returning data). The examples throughout follow best practices and the important notes section appropriately highlights the void-return pattern.

src/__tests__/hooks/useIAP.test.ts (1)

81-90: LGTM!

The addition of the store: 'apple' field correctly aligns the test fixture with the new IapStore type introduced in this PR. The value matches the platform ('ios' → 'apple').

docs/versioned_docs/version-14.4/api/methods/_category_.json (1)

1-4: LGTM!

Category configuration is properly structured for the Methods documentation section.

src/__tests__/utils/type-bridge.test.ts (2)

125-141: LGTM!

The addition of store: 'apple' correctly updates the iOS purchase fixture to include the new store field with the appropriate value.


143-161: LGTM!

The addition of store: 'google' correctly updates the Android purchase fixture to include the new store field with the appropriate value.

docs/versioned_docs/version-14.4/guides/_category_.json (1)

1-4: LGTM!

Category configuration is properly structured for the Guides documentation section.

ios/RnIapHelper.swift (1)

112-118: LGTM!

The store field initialization correctly:

  1. Reads from the dictionary using a safe optional unwrap pattern
  2. Uses the IapStore(fromString:) initializer for type-safe conversion
  3. Defaults to .apple when missing or invalid, which is appropriate for iOS platform
  4. Follows the same pattern as the platform field handling above
src/index.ts (1)

1462-1472: LGTM!

The implementation correctly transforms the verification result:

  1. Returns iapkit as a single object (with isValid, state, store) or null instead of an array
  2. Adds the new errors field with proper null handling
  3. This aligns with the PR objectives to change the iapkit parameter from array to object

This is a breaking change for consumers who previously accessed result.iapkit[0], but it's necessary and well-documented in the PR.

docs/versioned_docs/version-14.4/api/index.md (1)

1-54: LGTM!

The API reference landing page is well-structured with:

  • Clear organization of available APIs
  • Appropriate links to OpenIAP for canonical reference
  • Simple Quick Start example demonstrating useIAP hook
  • Helpful resource links

The documentation provides a good entry point for developers exploring the API.

docs/versioned_docs/version-14.4/guides/expo-plugin.md (1)

15-60: Expo plugin guide looks consistent and clear

The described plugin configuration (permissions, OpenIAP dependency, CocoaPods source, and the optional Folly workaround flag) matches the expected responsibilities of the config plugin and reads clearly. No changes needed from a code/API perspective.

docs/versioned_docs/version-14.4/examples/offer-code.md (1)

21-71: Offer code example is internally consistent and matches documented behaviour

The iOS example correctly treats presentCodeRedemptionSheetIOS as not returning a value, and the Android flow uses Linking.openURL plus getAvailablePurchases / getActiveSubscriptions without assuming return data from the hook methods. This looks good as a reference implementation.

example/screens/SubscriptionFlow.tsx (1)

1523-1538: LGTM! Verification result handling correctly updated.

The code properly handles the new verification result structure where result.iapkit is a single object (or undefined) and result.errors is an optional array. The implementation:

  • Checks for result.iapkit presence and displays verification details
  • Falls back to aggregating and displaying error messages from result.errors
  • Provides clear user feedback in both scenarios
example/screens/PurchaseFlow.tsx (1)

533-548: LGTM! Verification result handling properly updated.

The implementation correctly handles the new verification result structure:

  • Accesses result.iapkit as a single object with isValid, state, and store properties
  • Provides fallback error handling via result.errors array when iapkit is absent
  • Displays clear verification feedback to users

This is consistent with the changes in SubscriptionFlow.tsx.

src/__tests__/index.test.ts (1)

1143-1180: LGTM!

Test correctly updated to verify single-object iapkit structure with proper optional chaining for assertions (result.iapkit?.isValid, result.iapkit?.state, result.iapkit?.store).

docs/versioned_docs/version-14.4/guides/faq.md (1)

1-756: Well-structured and comprehensive FAQ documentation.

The FAQ covers essential topics including setup, testing, error handling, migration, and platform-specific issues with practical code examples and troubleshooting tips.

ios/HybridRnIap.swift (1)

352-406: LGTM!

The verifyPurchaseWithProvider implementation correctly transforms the OpenIAP result to Nitro types, handling:

  • Single optional iapkit object instead of array
  • New optional errors array mapping
  • Proper enum conversions with fallback defaults

The changes align with the updated type definitions in src/specs/RnIap.nitro.ts.

docs/docs/api/methods/core-methods.md (1)

547-575: LGTM!

The type definitions correctly document the updated API:

  • iapkit as optional single object with IapStore type for store
  • New errors array for verification error handling
  • New IapStore type including 'horizon' value
  • Expanded IapkitPurchaseState union
android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt (3)

925-925: LGTM!

The new store field is correctly populated using the mapIapStore helper, aligning with the updated NitroPurchase interface that now includes a store: IapStore field.


974-982: LGTM!

The mapIapStore helper correctly maps all OpenIAP IapStore enum values (Apple, Google, Horizon, Unknown) to their corresponding Nitro IapStore values. The function follows the established pattern of other mapping functions in this file and is placed correctly in the private helpers section.


1157-1178: LGTM! The iapkit conversion aligns with the updated API contract.

The refactoring correctly:

  1. Changes from array-based to single nullable iapkit result
  2. Adds proper errors array conversion
  3. Updates logging to use a boolean hasIapkit check

This matches the updated NitroVerifyPurchaseWithProviderResult interface where iapkit is now NitroVerifyPurchaseWithIapkitResult | null instead of an array.

src/types.ts (3)

183-184: LGTM! New IapStore type and store field additions.

The new IapStore type correctly includes all supported stores ('unknown' | 'apple' | 'google' | 'horizon'), and the store field is consistently added to PurchaseCommon, PurchaseAndroid, and PurchaseIOS with appropriate JSDoc documentation.

Also applies to: 470-471, 497-498, 540-541


911-926: LGTM! Verification result type changes align with the API migration.

The changes correctly:

  1. Add VerifyPurchaseWithProviderError interface with code (optional) and message (required)
  2. Update VerifyPurchaseWithProviderResult to have optional errors array and change iapkit from array to optional single object

This matches the PR objective of changing verifyPurchaseWithProvider iapkit parameter from an array to an object.


731-738: LGTM! Platform-specific property migration with backward compatibility.

The addition of apple/google keys alongside deprecated ios/android keys in both RequestPurchasePropsByPlatforms and RequestSubscriptionPropsByPlatforms maintains backward compatibility while guiding users toward the new naming convention.

Also applies to: 769-776

src/specs/RnIap.nitro.ts (4)

43-44: LGTM!

The IapStore type definition correctly mirrors the type in src/types.ts, ensuring consistency between the Nitro spec and the canonical types.


91-98: LGTM! NitroPurchaseRequest updated with store-based naming.

The interface correctly adds apple and google properties while retaining ios and android with deprecation notices for backward compatibility. This aligns with the broader migration from platform-based to store-based naming.


245-253: LGTM! Verification types updated to match new API contract.

The changes correctly:

  1. Add NitroVerifyPurchaseWithProviderError with optional code and required message
  2. Update NitroVerifyPurchaseWithProviderResult to have iapkit as optional single object (was array) and add optional errors array

This matches the corresponding changes in src/types.ts and the Android/iOS native implementations.


270-273: LGTM! NitroPurchase updated with store field, and Nitro bridge files have been regenerated.

The platform field is correctly marked as deprecated with guidance to use store instead. The new store: IapStore field is properly documented and the corresponding Nitro bridge files (HybridRnIap.swift and HybridRnIap.kt) have been regenerated to include the store field mappings in their conversion logic.

Comment thread docs/versioned_docs/version-14.4/api/error-handling.md
Comment thread docs/versioned_docs/version-14.4/examples/available-purchases.md
Comment thread docs/versioned_docs/version-14.4/getting-started/installation.md Outdated
Comment thread docs/versioned_docs/version-14.4/getting-started/setup-android.md
Comment thread docs/versioned_docs/version-14.4/getting-started/setup-android.md
Comment thread docs/versioned_docs/version-14.4/guides/subscription-offers.md
Comment thread docs/versioned_docs/version-14.4/guides/subscription-offers.md
Comment thread docs/versioned_docs/version-14.4/guides/subscription-offers.md
Comment thread docs/versioned_docs/version-14.4/installation.md Outdated
Comment thread src/types.ts
- Remove IapkitStore type, use IapStore instead
- Fix NitroVerifyPurchaseWithIapkitResult.store type to IapStore
- Fix 14.4 docs: use ios/android instead of apple/google
- Fix validateReceipt example to use purchase.id
- Fix getUserFriendlyMessage return type to string | null
- Fix withIAPContext HOC usage example
- Fix presentCodeRedemptionSheet to presentCodeRedemptionSheetIOS
- Add missing useEffect import in offer-code-redemption
- Fix "Real world" to "Real-world" hyphenation
- Fix handlePurchase to use event-driven pattern
- Fix confusing self-referential FAQ question

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
docs/versioned_docs/version-14.4/guides/faq.md (2)

381-383: Fix self-referential library comparison.

The text states "react-native-iap is the official successor to react-native-iap", which is self-referential and confusing. This should clarify what library is being migrated from.

-`react-native-iap` is the official successor to `react-native-iap`. The migration is straightforward with these key changes:
+`react-native-iap` is the official successor to the older `react-native-iap` package. The migration is straightforward with these key changes:

Or, if referring to a different package name, clarify the actual predecessor library name.


401-403: Fix incorrect withIAPContext usage pattern.

withIAPContext is a Higher-Order Component (HOC), not a JSX element. The syntax shown would not execute—it should wrap the component function, not render as a tag.

-const App = withIAPContext(() => {
-  return <YourApp />;
-});
+const AppWithIAP = withIAPContext(() => {
+  return <YourApp />;
+});
+
+export default AppWithIAP;

Alternatively, if the library exposes a context provider, use the provider form:

<IAPContextProvider>
  <YourApp />
</IAPContextProvider>
🧹 Nitpick comments (5)
docs/versioned_docs/version-14.4/guides/faq.md (2)

537-537: Add hyphen to compound modifier.

The phrase "yoga related" should use a hyphen to form a compound adjective: "yoga-related".

-- `Property 'unit' is inaccessible due to 'internal' protection level` (yoga related)
+- `Property 'unit' is inaccessible due to 'internal' protection level` (yoga-related)

261-261: Use American English spelling preference.

In American English, "afterward" is preferred over "afterwards".

-This can briefly happen due to StoreKit 2 event ordering and native background work. If you've already received a success and processed it, you can safely ignore a transient error that arrives shortly afterwards.
+This can briefly happen due to StoreKit 2 event ordering and native background work. If you've already received a success and processed it, you can safely ignore a transient error that arrives shortly afterward.
docs/versioned_docs/version-14.4/guides/offer-code-redemption.md (1)

82-119: Wrap the hook usage in a React component for accuracy.

The useEffect hook at lines 109-118 is shown outside of a React component, which would be invalid in actual code. Consider wrapping the complete example in a proper component function to avoid confusion.

 ```typescript
 import {useEffect} from 'react';
 import {Platform} from 'react-native';
 import {
   presentCodeRedemptionSheetIOS,
   openRedeemOfferCodeAndroid,
   purchaseUpdatedListener,
 } from 'react-native-iap';

+const RedeemCodeScreen = () => {
 const handleRedeemCode = async () => {
   try {
     if (Platform.OS === 'ios') {
       // Present native iOS redemption sheet
       const result = await presentCodeRedemptionSheetIOS();
       if (result) {
         console.log('Redemption sheet presented');
       }
     } else if (Platform.OS === 'android') {
       // Open Play Store for Android
       await openRedeemOfferCodeAndroid();
     }
   } catch (error) {
     console.error('Error redeeming code:', error);
   }
 };

 // Set up listener for purchase updates after redemption
 useEffect(() => {
   const subscription = purchaseUpdatedListener((purchase) => {
     console.log('Purchase updated after redemption:', purchase);
     // Handle the new purchase/subscription
   });

   return () => {
     subscription.remove();
   };
 }, []);
+
+  return (
+    // Your component JSX here
+  );
+};

</blockquote></details>
<details>
<summary>ios/HybridRnIap.swift (2)</summary><blockquote>

`378-378`: **Remove redundant nil initialization.**

SwiftLint reports that initializing an optional variable with `nil` is redundant since optionals default to `nil`.

```diff
-                var nitroIapkitResult: NitroVerifyPurchaseWithIapkitResult? = nil
+                var nitroIapkitResult: NitroVerifyPurchaseWithIapkitResult?

387-387: Remove redundant nil initialization.

SwiftLint reports that initializing an optional variable with nil is redundant.

-                var nitroErrors: [NitroVerifyPurchaseWithProviderError]? = nil
+                var nitroErrors: [NitroVerifyPurchaseWithProviderError]?
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 58b7bca and 53d3514.

📒 Files selected for processing (13)
  • android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt (4 hunks)
  • docs/versioned_docs/version-14.4/api/error-handling.md (1 hunks)
  • docs/versioned_docs/version-14.4/api/types.md (1 hunks)
  • docs/versioned_docs/version-14.4/examples/available-purchases.md (1 hunks)
  • docs/versioned_docs/version-14.4/getting-started/installation.md (1 hunks)
  • docs/versioned_docs/version-14.4/getting-started/setup-android.md (1 hunks)
  • docs/versioned_docs/version-14.4/getting-started/setup-ios.md (1 hunks)
  • docs/versioned_docs/version-14.4/guides/error-handling.md (1 hunks)
  • docs/versioned_docs/version-14.4/guides/faq.md (1 hunks)
  • docs/versioned_docs/version-14.4/guides/offer-code-redemption.md (1 hunks)
  • docs/versioned_docs/version-14.4/installation.md (1 hunks)
  • ios/HybridRnIap.swift (1 hunks)
  • src/specs/RnIap.nitro.ts (4 hunks)
✅ Files skipped from review due to trivial changes (1)
  • docs/versioned_docs/version-14.4/guides/error-handling.md
🚧 Files skipped from review as they are similar to previous changes (5)
  • docs/versioned_docs/version-14.4/getting-started/setup-ios.md
  • docs/versioned_docs/version-14.4/getting-started/setup-android.md
  • docs/versioned_docs/version-14.4/examples/available-purchases.md
  • docs/versioned_docs/version-14.4/api/error-handling.md
  • docs/versioned_docs/version-14.4/api/types.md
🧰 Additional context used
📓 Path-based instructions (5)
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

When declaring API params/results in TS modules, import canonical types from src/types.ts rather than creating ad‑hoc interfaces.

Files:

  • src/specs/RnIap.nitro.ts
**/*.nitro.ts

📄 CodeRabbit inference engine (CLAUDE.md)

After modifying any .nitro.ts interface files, regenerate Nitro bridge files (yarn specs).

Files:

  • src/specs/RnIap.nitro.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use type-only imports when importing types (import type).

Files:

  • src/specs/RnIap.nitro.ts
{src/**/*.{ts,tsx},example/**/*.{ts,tsx},example-expo/**/*.{ts,tsx}}

📄 CodeRabbit inference engine (CLAUDE.md)

{src/**/*.{ts,tsx},example/**/*.{ts,tsx},example-expo/**/*.{ts,tsx}}: Prefer using isUserCancelledError() and getUserFriendlyErrorMessage() with normalized ErrorCode when handling purchase errors.
Use Platform.OS checks for platform-specific logic in React Native code.

Files:

  • src/specs/RnIap.nitro.ts
{ios/**/*.swift,android/src/main/java/**/*.kt}

📄 CodeRabbit inference engine (CLAUDE.md)

Follow the native class function ordering: (1) properties/init, (2) public cross-platform methods, (3) platform-specific public methods (IOS/Android suffix), (4) event listener methods, (5) private helpers.

Files:

  • ios/HybridRnIap.swift
  • android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt
🧠 Learnings (6)
📓 Common learnings
Learnt from: hyochan
Repo: hyochan/react-native-iap PR: 3015
File: src/types.ts:137-166
Timestamp: 2025-09-18T16:45:10.582Z
Learning: The types in src/types.ts are auto-generated from openiap-gql1.0.6. Breaking changes in mutation return types (like acknowledgePurchaseAndroid returning Promise<boolean>, finishTransaction returning Promise<void>, etc.) originate from updates to this external GraphQL schema generator, not manual refactoring.
Learnt from: hyochan
Repo: hyochan/react-native-iap PR: 3002
File: docs/docs/getting-started/setup-ios.md:55-60
Timestamp: 2025-09-14T00:13:04.055Z
Learning: The validateReceipt function from useIAP hook in react-native-iap expects a transaction identifier as parameter, which is accessed via purchase.id (not purchase.productId). This is confirmed by the maintainer hyochan and aligns with the library's migration from purchase.transactionId to purchase.id.
📚 Learning: 2025-09-18T16:45:10.582Z
Learnt from: hyochan
Repo: hyochan/react-native-iap PR: 3015
File: src/types.ts:137-166
Timestamp: 2025-09-18T16:45:10.582Z
Learning: The types in src/types.ts are auto-generated from openiap-gql1.0.6. Breaking changes in mutation return types (like acknowledgePurchaseAndroid returning Promise<boolean>, finishTransaction returning Promise<void>, etc.) originate from updates to this external GraphQL schema generator, not manual refactoring.

Applied to files:

  • src/specs/RnIap.nitro.ts
  • ios/HybridRnIap.swift
📚 Learning: 2025-10-02T19:35:19.667Z
Learnt from: CR
Repo: hyochan/react-native-iap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T19:35:19.667Z
Learning: Applies to {example/**/*.{ts,tsx},example-expo/**/*.{ts,tsx}} : In useIAP hook usage, do not expect returned data from methods that return Promise<void>; consume state from the hook instead.

Applied to files:

  • src/specs/RnIap.nitro.ts
  • docs/versioned_docs/version-14.4/guides/faq.md
  • docs/versioned_docs/version-14.4/guides/offer-code-redemption.md
📚 Learning: 2025-09-14T00:13:04.055Z
Learnt from: hyochan
Repo: hyochan/react-native-iap PR: 3002
File: docs/docs/getting-started/setup-ios.md:55-60
Timestamp: 2025-09-14T00:13:04.055Z
Learning: The validateReceipt function from useIAP hook in react-native-iap expects a transaction identifier as parameter, which is accessed via purchase.id (not purchase.productId). This is confirmed by the maintainer hyochan and aligns with the library's migration from purchase.transactionId to purchase.id.

Applied to files:

  • src/specs/RnIap.nitro.ts
  • ios/HybridRnIap.swift
  • docs/versioned_docs/version-14.4/guides/faq.md
  • docs/versioned_docs/version-14.4/guides/offer-code-redemption.md
📚 Learning: 2025-09-13T01:07:18.841Z
Learnt from: hyochan
Repo: hyochan/react-native-iap PR: 2999
File: android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt:644-660
Timestamp: 2025-09-13T01:07:18.841Z
Learning: In Android IAP error handling: purchaseToken and productId are distinct properties - purchaseToken identifies a completed purchase transaction (should be null in error cases), while productId is the product SKU for context

Applied to files:

  • src/specs/RnIap.nitro.ts
  • android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt
  • docs/versioned_docs/version-14.4/guides/faq.md
📚 Learning: 2025-10-02T19:35:19.667Z
Learnt from: CR
Repo: hyochan/react-native-iap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T19:35:19.667Z
Learning: Applies to {src/**/*.{ts,tsx},example/**/*.{ts,tsx},example-expo/**/*.{ts,tsx}} : Prefer using isUserCancelledError() and getUserFriendlyErrorMessage() with normalized ErrorCode when handling purchase errors.

Applied to files:

  • docs/versioned_docs/version-14.4/guides/faq.md
  • docs/versioned_docs/version-14.4/guides/offer-code-redemption.md
🧬 Code graph analysis (3)
src/specs/RnIap.nitro.ts (1)
src/types.ts (2)
  • IapStore (183-183)
  • IapPlatform (181-181)
ios/HybridRnIap.swift (2)
src/specs/RnIap.nitro.ts (5)
  • NitroVerifyPurchaseWithIapkitResult (237-241)
  • IapkitPurchaseState (30-39)
  • IapStore (42-42)
  • NitroVerifyPurchaseWithProviderError (243-246)
  • NitroVerifyPurchaseWithProviderResult (248-252)
src/types.ts (2)
  • IapkitPurchaseState (186-186)
  • IapStore (183-183)
android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt (1)
src/specs/RnIap.nitro.ts (3)
  • NitroVerifyPurchaseWithIapkitResult (237-241)
  • NitroVerifyPurchaseWithProviderError (243-246)
  • NitroVerifyPurchaseWithProviderResult (248-252)
🪛 LanguageTool
docs/versioned_docs/version-14.4/guides/faq.md

[grammar] ~47-~47: Use a hyphen to join words.
Context: ...s! react-native-iap works in both Expo managed and bare React Native projects. ...

(QB_NEW_EN_HYPHEN)


[locale-violation] ~261-~261: In American English, ‘afterward’ is the preferred variant. ‘Afterwards’ is more commonly used in British English and other dialects.
Context: ... a transient error that arrives shortly afterwards. Tip (dedupe in app logic): ```tsx im...

(AFTERWARDS_US)


[style] ~289-~289: This phrase is redundant. Consider writing “outcome”.
Context: ...on await requestPurchase(...) for the final outcome; multiple events and inter-session comp...

(FINAL_END)


[grammar] ~537-~537: Use a hyphen to join words.
Context: ...ue to 'internal' protection level(yoga related) **Root Cause:** TheappTransa...

(QB_NEW_EN_HYPHEN)

docs/versioned_docs/version-14.4/guides/offer-code-redemption.md

[style] ~44-~44: This phrase is redundant (‘OS’ stands for ‘operating system’). Use simply “iOS”.
Context: ... The redemption sheet is handled by the iOS system - After successful redemption, purchase...

(ACRONYM_TAUTOLOGY)

🪛 SwiftLint (0.57.0)
ios/HybridRnIap.swift

[Warning] 378-378: Initializing an optional variable with nil is redundant

(redundant_optional_initialization)


[Warning] 387-387: Initializing an optional variable with nil is redundant

(redundant_optional_initialization)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build-android
  • GitHub Check: build-ios
🔇 Additional comments (14)
docs/versioned_docs/version-14.4/installation.md (4)

13-25: Compatibility section is clear and well-structured.

The Nitro compatibility warning effectively communicates version requirements, provides fallback options (pre-Nitro 13.1.0), mentions the Swift 6 C++ interop workaround, and suggests expo-iap as an alternative for constrained environments. The progression from problem statement to solutions is logical.


37-51: Package installation section is concise and accurate.

Covers npm installation, iOS Pod dependencies for React Native CLI projects, and mentions automatic native module linking. The distinction between React Native CLI and Expo workflows is appropriate for this section header.


55-137: Expo Configuration section is comprehensive.

The section properly addresses the custom development client requirement, provides the critical Kotlin 2.0+ configuration with clear context (Google Play Billing v8.0.0 requirement), includes expo-dev-client installation, prebuild instructions, and a well-documented Folly workaround with migration guidance. The note at line 126-127 about the renamed config option (with-folly-no-couroutineswith-folly-no-coroutines) with deprecation warning support is helpful for users with existing configurations.


5-5: No action needed. All referenced resources exist in the codebase: the GreatFrontEndTopFixed component is located at docs/src/uis/GreatFrontEndTopFixed.tsx, and the relative paths to setup guides correctly resolve to files in docs/versioned_docs/version-14.4/getting-started/. The imports and references are valid.

src/specs/RnIap.nitro.ts (4)

41-42: LGTM!

The IapStore type is correctly defined with all supported store values ('unknown', 'apple', 'google', 'horizon'), aligning with the openiap 1.3.0 migration.


88-97: LGTM!

The deprecation strategy for ios/android fields in favor of apple/google is well documented with JSDoc comments. This provides a clear migration path for consumers.


237-251: LGTM!

The verification result structure is updated correctly:

  • store now uses IapStore type
  • NitroVerifyPurchaseWithProviderError provides structured error information
  • iapkit changed from array to optional single object
  • errors array added for surfacing verification errors

These changes align with the openiap 1.3.0 API updates.


268-271: LGTM!

The NitroPurchase interface correctly adds the new store field with IapStore type while deprecating platform with appropriate documentation.

docs/versioned_docs/version-14.4/getting-started/installation.md (1)

1-153: LGTM!

Comprehensive installation guide covering:

  • Clear compatibility notes for Nitro 14.x vs pre-Nitro versions
  • Proper Expo configuration with Kotlin version requirements
  • Helpful migration notes for the Folly coroutine workaround key rename
  • Well-structured sections with appropriate cross-references
ios/HybridRnIap.swift (1)

376-400: LGTM on the verification result conversion logic.

The conversion from OpenIAP result to Nitro types is correct:

  • Single iapkit object with proper state and store mapping
  • Errors array populated when present
  • Provider mapping with appropriate fallback

The changes align with the new NitroVerifyPurchaseWithProviderResult structure.

android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt (4)

974-982: LGTM!

The mapIapStore helper correctly maps OpenIAP store values to Nitro IapStore enum values, handling all four cases: Apple, Google, Horizon, and Unknown.


925-925: LGTM!

The store field is correctly added to NitroPurchase using the new mapIapStore helper function.


1157-1179: LGTM!

The verification result handling is correctly updated:

  • iapkit is now a single optional object via result.iapkit?.let { ... }
  • Errors are mapped to NitroVerifyPurchaseWithProviderError array
  • Result construction passes both iapkit and errors fields

This aligns with the iOS implementation and the updated type definitions.


1441-1448: LGTM!

The mapIapkitStore function is updated to return IapStore type with correct mapping for all store values including the new HORIZON case.

Comment thread docs/versioned_docs/version-14.4/guides/faq.md
@hyochan hyochan merged commit 5c9daa0 into main Dec 8, 2025
11 checks passed
@hyochan hyochan deleted the migration/openiap-1.3 branch December 8, 2025 21:16
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

🚽 migration Activities due to changes in framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant