Conversation
- Update openiap-versions.json (gql: 1.3.12, apple: 1.3.10, google: 1.3.22) - Regenerate TypeScript types with new cross-platform offer types - New DiscountOffer and SubscriptionOffer types available - New discountOffers and subscriptionOffers fields on Product types Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds standardized cross-platform subscription and discount offer types and plumbing: native serialization on Android/iOS, NitroProduct fields for JSON-serialized offers and subscription replacement params, TypeScript types and bridge parsing, docs and example UI/tests updated to surface unified Changes
Sequence Diagram(s)sequenceDiagram
participant App as React Native App
participant Native as Native (Android / iOS)
participant Nitro as NitroProduct (native payload)
participant Bridge as JS Type Bridge
App->>Native: request products
Native->>Native: gather product data + platform offers
Native->>Nitro: serialize product including subscriptionOffers/discountOffers JSON and replacement params
Nitro->>Bridge: deliver NitroProduct payload (JSON strings fields)
Bridge->>Bridge: parse subscriptionOffers/discountOffers JSON -> arrays, map replacement params
Bridge->>App: return Product objects with parsed subscriptionOffers & discountOffers
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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. Comment |
Summary of ChangesHello @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 primarily focuses on enhancing the Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe 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
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 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
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3125 +/- ##
==========================================
+ Coverage 65.39% 65.68% +0.29%
==========================================
Files 9 9
Lines 1679 1705 +26
Branches 561 570 +9
==========================================
+ Hits 1098 1120 +22
- Misses 576 580 +4
Partials 5 5
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Code Review
This pull request primarily focuses on standardizing product and subscription offer types across iOS and Android platforms within the src/types.ts file. It introduces new interfaces like DiscountOffer for one-time product discounts and SubscriptionOffer for subscription offers, both designed for cross-platform compatibility, and adds related enumerations such as DiscountOfferType, PaymentMode, SubscriptionPeriod, and SubscriptionPeriodUnit. Consequently, several existing platform-specific interfaces and properties (e.g., DiscountIOS, DiscountOfferIOS, oneTimePurchaseOfferDetailsAndroid, subscriptionOfferDetailsAndroid, subscriptionInfoIOS, discountsIOS, SubscriptionOfferIOS) have been deprecated in favor of these new standardized types. Additionally, the openiap-versions.json file was updated to increment the version numbers for apple, google, and gql components.
- Add subscriptionOffers and discountOffers to NitroProduct interface - Update iOS RnIapHelper.swift to extract standardized offers from OpenIAP - Update Android HybridRnIap.kt with serialization for new offer types - Update type-bridge.ts to parse new JSON offer fields - Add comprehensive tests for new SubscriptionOffer and DiscountOffer types - Update documentation with new cross-platform offer types (v14.8.0+) - Update llms.txt and llms-full.txt AI reference documentation - Update example AllProducts screen to display standardized offers These new types provide a unified API for subscription and discount offers across iOS and Android, replacing the deprecated platform-specific fields subscriptionInfoIOS and subscriptionOfferDetailsAndroid. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…untOffers - Update PurchaseFlow.tsx to use discountOffers instead of deprecated oneTimePurchaseOfferDetailsAndroid - Update SubscriptionFlow.tsx to use subscriptionOffers instead of deprecated subscriptionOfferDetailsAndroid - Update subscription-offers guide documentation with cross-platform types - Remove AndroidOneTimeOfferDetails component usage (deprecated) - Update PurchaseFlow.test.tsx to test cross-platform discountOffers This aligns with expo-iap PR #302 and OpenIAP spec for unified offer handling. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@src/utils/type-bridge.ts`:
- Around line 280-303: The parsing for nitroProduct.subscriptionOffers (and
similarly for discountOffers) can produce null or non-array values but public
types (ProductSubscriptionAndroid) expect a non-null array; update the logic in
the subscriptionOffers parsing block (and the analogous blocks around lines
referenced) to JSON.parse inside a try, then validate Array.isArray(result) and
assign iosProduct.subscriptionOffers = result if true, otherwise assign []; do
the same validation/default-for-[] behavior for discountOffers and for the other
subscription-related blocks (e.g., subscriptionOfferDetailsAndroid) so all
subscription fields always resolve to arrays for subscription products.
🧹 Nitpick comments (3)
example/screens/AllProducts.tsx (1)
447-543: Gate Android-only fields withPlatform.OSfor clarity.
basePlanIdAndroid/offerTokenAndroidare platform-specific; adding explicit Android guards aligns with the project guideline and avoids accidental cross-platform UI leakage. As per coding guidelines, usePlatform.OSfor platform-specific logic.♻️ Suggested tweak
-import { - View, - Text, - StyleSheet, - TouchableOpacity, - Modal, - SectionList, - ScrollView, -} from 'react-native'; +import { + View, + Text, + StyleSheet, + TouchableOpacity, + Modal, + SectionList, + ScrollView, + Platform, +} from 'react-native'; ... - {offer.basePlanIdAndroid && ( + {Platform.OS === 'android' && + offer.basePlanIdAndroid && ( <View style={styles.offerRow}> <Text style={styles.offerLabel}> Base Plan (Android): </Text> <Text style={styles.offerValue}> {offer.basePlanIdAndroid} </Text> </View> )} - {offer.offerTokenAndroid && ( + {Platform.OS === 'android' && + offer.offerTokenAndroid && ( <> <Text style={styles.offerLabel}> Offer Token (Android): </Text> <Text style={[ styles.offerValue, styles.offerToken, ]} numberOfLines={2} > {offer.offerTokenAndroid} </Text> </> )}example/screens/PurchaseFlow.tsx (1)
387-509: Guard Android-only offer details withPlatform.OS.Several fields shown here are Android-specific (micros, time windows, preorder, rental, tags). Wrapping those details in a
Platform.OS === 'android'block keeps cross-platform UI clean and matches the project guideline. As per coding guidelines, usePlatform.OSfor platform-specific logic.♻️ Suggested tweak
- {offer.fullPriceMicrosAndroid && ( - <> - <Text style={styles.offerLabel}> - Full Price (micros): - </Text> - <Text style={styles.offerValue}> - {offer.fullPriceMicrosAndroid} - </Text> - </> - )} - {offer.percentageDiscountAndroid && ( - <Text style={styles.offerValueDiscount}> - {offer.percentageDiscountAndroid}% off - </Text> - )} - {offer.formattedDiscountAmountAndroid && ( - <> - <Text style={styles.offerLabel}>Discount:</Text> - <Text style={styles.offerValueDiscount}> - {offer.formattedDiscountAmountAndroid} - </Text> - </> - )} - {offer.validTimeWindowAndroid && ( - <> - <Text style={styles.offerLabel}> - Valid Window: - </Text> - <Text style={styles.offerValue}> - {new Date( - Number( - offer.validTimeWindowAndroid - .startTimeMillis, - ), - ).toLocaleDateString()}{' '} - -{' '} - {new Date( - Number( - offer.validTimeWindowAndroid - .endTimeMillis, - ), - ).toLocaleDateString()} - </Text> - </> - )} - {offer.limitedQuantityInfoAndroid && ( - <> - <Text style={styles.offerLabel}> - Limited Quantity: - </Text> - <Text style={styles.offerValue}> - { - offer.limitedQuantityInfoAndroid - .remainingQuantity - }{' '} - /{' '} - { - offer.limitedQuantityInfoAndroid - .maximumQuantity - }{' '} - remaining - </Text> - </> - )} - {offer.preorderDetailsAndroid && ( - <> - <Text style={styles.offerLabel}> - Pre-order Release: - </Text> - <Text style={styles.offerValue}> - {new Date( - Number( - offer.preorderDetailsAndroid - .preorderReleaseTimeMillis, - ), - ).toLocaleDateString()} - </Text> - </> - )} - {offer.rentalDetailsAndroid && ( - <> - <Text style={styles.offerLabel}>Rental:</Text> - <Text style={styles.offerValue}> - Period:{' '} - { - offer.rentalDetailsAndroid - .rentalExpirationPeriod - } - </Text> - </> - )} - {Array.isArray(offer.offerTagsAndroid) && - offer.offerTagsAndroid.length > 0 && ( - <> - <Text style={styles.offerLabel}>Tags:</Text> - <Text style={styles.offerValue}> - {offer.offerTagsAndroid.join(', ')} - </Text> - </> - )} + {Platform.OS === 'android' && ( + <> + {offer.fullPriceMicrosAndroid && ( + <> + <Text style={styles.offerLabel}> + Full Price (micros): + </Text> + <Text style={styles.offerValue}> + {offer.fullPriceMicrosAndroid} + </Text> + </> + )} + {offer.percentageDiscountAndroid && ( + <Text style={styles.offerValueDiscount}> + {offer.percentageDiscountAndroid}% off + </Text> + )} + {offer.formattedDiscountAmountAndroid && ( + <> + <Text style={styles.offerLabel}> + Discount: + </Text> + <Text style={styles.offerValueDiscount}> + {offer.formattedDiscountAmountAndroid} + </Text> + </> + )} + {offer.validTimeWindowAndroid && ( + <> + <Text style={styles.offerLabel}> + Valid Window: + </Text> + <Text style={styles.offerValue}> + {new Date( + Number( + offer.validTimeWindowAndroid + .startTimeMillis, + ), + ).toLocaleDateString()}{' '} + -{' '} + {new Date( + Number( + offer.validTimeWindowAndroid + .endTimeMillis, + ), + ).toLocaleDateString()} + </Text> + </> + )} + {offer.limitedQuantityInfoAndroid && ( + <> + <Text style={styles.offerLabel}> + Limited Quantity: + </Text> + <Text style={styles.offerValue}> + { + offer.limitedQuantityInfoAndroid + .remainingQuantity + }{' '} + /{' '} + { + offer.limitedQuantityInfoAndroid + .maximumQuantity + }{' '} + remaining + </Text> + </> + )} + {offer.preorderDetailsAndroid && ( + <> + <Text style={styles.offerLabel}> + Pre-order Release: + </Text> + <Text style={styles.offerValue}> + {new Date( + Number( + offer.preorderDetailsAndroid + .preorderReleaseTimeMillis, + ), + ).toLocaleDateString()} + </Text> + </> + )} + {offer.rentalDetailsAndroid && ( + <> + <Text style={styles.offerLabel}> + Rental: + </Text> + <Text style={styles.offerValue}> + Period:{' '} + { + offer.rentalDetailsAndroid + .rentalExpirationPeriod + } + </Text> + </> + )} + {Array.isArray(offer.offerTagsAndroid) && + offer.offerTagsAndroid.length > 0 && ( + <> + <Text style={styles.offerLabel}> + Tags: + </Text> + <Text style={styles.offerValue}> + {offer.offerTagsAndroid.join(', ')} + </Text> + </> + )} + </> + )}example/screens/SubscriptionFlow.tsx (1)
2164-2173: Consider filtering out offers with missingofferTokenAndroid.The code uses
offer.offerTokenAndroid ?? ''which will include offers with empty tokens in the request. Android requires valid offer tokens for subscription purchases.Consider filtering instead:
♻️ Suggested improvement
? ( subscription as ProductSubscriptionAndroid ).subscriptionOffers.map((offer) => ({ sku: itemId, offerToken: offer.offerTokenAndroid ?? '', })) + .filter((o) => o.offerToken !== '') : [],
…bscriptions Address coderabbit review: ProductSubscriptionAndroid.subscriptionOffers is non-nullable in the public types, so parsing failures should default to [] instead of null. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add item-level subscription replacement parameters support for Android Billing Library 8.1.0+. This allows specifying replacement mode per product instead of globally, enabling more flexible subscription upgrade/downgrade flows. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fix typo in OpenIAP enum mapping: ChargeProratedPrice (not ChargeProRatedPrice) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Summary
DiscountOfferandSubscriptionOffertypesdiscountOffersandsubscriptionOffersfields on Product typesChanges
Types (auto-generated)
DiscountOffertype with cross-platform fieldsSubscriptionOffertype with cross-platform fieldsAndroid/IOSsuffixessubscriptionOfferDetailsAndroidandoneTimePurchaseOfferDetailsAndroidstill available for compatibilityTest plan
yarn typecheckpassesyarn testpasses (172 tests)yarn buildpasses🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Tests
✏️ Tip: You can customize this high-level summary in your review settings.