refactor(gql): enforce generated contract SSOT - #250
Conversation
Align DiscountOffer documentation and generated API comments with the Google Play one-time offer contract. Refresh examples and search entries, and add regression audits for offer semantics and Kotlin purchase calls. Closes #249
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
PreviewActual local docs render captured for commit 5fe806a: Verified from the locally rendered documentation page; the committed JPEG is 71 KB (under the 10 MB fallback limit). The release card has since been consolidated under the correct OpenIAP Spec 2.4.2 floor ( |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis PR standardizes discount and subscription offer documentation across SDKs, GraphQL, and docs. It migrates discount examples to ChangesCanonical offer documentation
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
libraries/expo-iap/src/types.ts (1)
1109-1110: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicate
@deprecatedJSDoc tags emitted by the shared TS codegen. Bothlibraries/expo-iap/src/types.tsandlibraries/react-native-iap/src/types.tsare generated from the same GraphQL schema/TS codegen template, which emits two overlapping@deprecatedtags per deprecated field (a new detailed reason plus the old short one), unlike the Kotlin/Swift/Dart/C# outputs which only emit one.
libraries/expo-iap/src/types.ts#L1109-L1110: dedupe the@deprecatedtags foroneTimePurchaseOfferDetailsAndroid(and the same pattern recurring at lines 1124-1125, 1214-1215, 1265-1266, 1281-1282, 1344-1345) at the codegen/schema level, then regenerate.libraries/react-native-iap/src/types.ts#L1109-L1110: same dedupe, recurring at the identical relative offsets (1124-1125, 1214-1215, 1265-1266, 1281-1282, 1344-1345); fix once upstream and regenerate both packages.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@libraries/expo-iap/src/types.ts` around lines 1109 - 1110, Update the shared GraphQL/TypeScript codegen template or schema handling to emit only one `@deprecated` JSDoc tag per deprecated field, preserving the detailed deprecation reason, then regenerate all affected types. Apply the generated result across the recurring fields in libraries/expo-iap/src/types.ts at lines 1109-1110, 1124-1125, 1214-1215, 1265-1266, 1281-1282, and 1344-1345, and the corresponding ranges in libraries/react-native-iap/src/types.ts; both files require regeneration, with no duplicate tags remaining.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@libraries/godot-iap/addons/godot-iap/types.gd`:
- Line 1059: Update the `@see` reference in the DiscountOffer documentation to use
the canonical https://openiap.dev/docs/types/discount-offer URL, matching the
other bindings and ProductAndroidOneTimePurchaseOfferDetail documentation.
In `@scripts/audit-docs.ts`:
- Around line 205-237: Update findSearchEntriesByTitle to locate the enclosing
object using brace matching from the matched title position, rather than the
indentation-dependent '\n {' and '\n },' markers. Use the resulting object
boundaries to extract path and preserve the existing line-number and
null-fallback behavior across spaces, tabs, and other formatting.
---
Nitpick comments:
In `@libraries/expo-iap/src/types.ts`:
- Around line 1109-1110: Update the shared GraphQL/TypeScript codegen template
or schema handling to emit only one `@deprecated` JSDoc tag per deprecated field,
preserving the detailed deprecation reason, then regenerate all affected types.
Apply the generated result across the recurring fields in
libraries/expo-iap/src/types.ts at lines 1109-1110, 1124-1125, 1214-1215,
1265-1266, 1281-1282, and 1344-1345, and the corresponding ranges in
libraries/react-native-iap/src/types.ts; both files require regeneration, with
no duplicate tags remaining.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 1f3ee1d1-0ff9-4129-b716-2dce938216f0
⛔ Files ignored due to path filters (6)
packages/gql/src/generated/Types.csis excluded by!**/generated/**packages/gql/src/generated/Types.ktis excluded by!**/generated/**packages/gql/src/generated/Types.swiftis excluded by!**/generated/**packages/gql/src/generated/types.dartis excluded by!**/generated/**packages/gql/src/generated/types.gdis excluded by!**/generated/**packages/gql/src/generated/types.tsis excluded by!**/generated/**
📒 Files selected for processing (22)
libraries/expo-iap/src/types.tslibraries/flutter_inapp_purchase/lib/types.dartlibraries/godot-iap/addons/godot-iap/types.gdlibraries/kmp-iap/library/src/commonMain/kotlin/io/github/hyochan/kmpiap/openiap/Types.ktlibraries/maui-iap/src/OpenIap.Maui/Types.cslibraries/react-native-iap/src/types.tspackages/apple/Sources/Models/Types.swiftpackages/docs/src/lib/searchData.tspackages/docs/src/pages/docs/features/discount.tsxpackages/docs/src/pages/docs/types/android/one-time-purchase-offer-detail-android.tsxpackages/docs/src/pages/docs/types/discount-offer.tsxpackages/docs/src/pages/docs/types/index.tsxpackages/docs/src/pages/docs/types/product.tsxpackages/docs/src/pages/docs/types/request-purchase-props.tsxpackages/docs/src/pages/docs/types/subscription-offer.tsxpackages/docs/src/pages/docs/types/subscription-product.tsxpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.ktpackages/gql/src/type-android.graphqlpackages/gql/src/type-ios.graphqlpackages/gql/src/type.graphqlscripts/audit-docs.test.tsscripts/audit-docs.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/audit-docs.ts`:
- Around line 205-221: Fix the loop in findEnclosingBraceBlock so searching
stops after processing a brace at index 0; avoid calling source.lastIndexOf with
a negative search position, while preserving the existing enclosure checks and
fallback search for earlier braces.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: d4e166a9-a86e-45e3-9dbc-76431d8a02ba
⛔ Files ignored due to path filters (6)
packages/gql/src/generated/Types.csis excluded by!**/generated/**packages/gql/src/generated/Types.ktis excluded by!**/generated/**packages/gql/src/generated/Types.swiftis excluded by!**/generated/**packages/gql/src/generated/types.dartis excluded by!**/generated/**packages/gql/src/generated/types.gdis excluded by!**/generated/**packages/gql/src/generated/types.tsis excluded by!**/generated/**
📒 Files selected for processing (13)
libraries/expo-iap/src/types.tslibraries/flutter_inapp_purchase/lib/types.dartlibraries/godot-iap/addons/godot-iap/types.gdlibraries/kmp-iap/library/src/commonMain/kotlin/io/github/hyochan/kmpiap/openiap/Types.ktlibraries/maui-iap/src/OpenIap.Maui/Types.cslibraries/react-native-iap/src/types.tspackages/apple/Sources/Models/Types.swiftpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.ktpackages/gql/scripts/fix-generated-types.mjspackages/gql/src/generated-compatibility.test.tspackages/gql/src/type.graphqlscripts/audit-docs.test.tsscripts/audit-docs.ts
🚧 Files skipped from review as they are similar to previous changes (7)
- scripts/audit-docs.test.ts
- packages/gql/src/type.graphql
- packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
- libraries/godot-iap/addons/godot-iap/types.gd
- libraries/maui-iap/src/OpenIap.Maui/Types.cs
- libraries/kmp-iap/library/src/commonMain/kotlin/io/github/hyochan/kmpiap/openiap/Types.kt
- libraries/flutter_inapp_purchase/lib/types.dart
There was a problem hiding this comment.
Pull request overview
This PR clarifies and hardens the documentation and schema semantics around Google Play one-time product offers vs subscription offers, ensuring DiscountOffer is treated as the standardized one-time-offer shape (Android-only), and SubscriptionOffer remains the cross-platform subscription-discount shape.
Changes:
- Refines GraphQL SSOT descriptions and propagates consistent offer semantics + canonical doc links into all generated SDK types/comments.
- Updates the docs pages, examples, and search entries to distinguish one-time vs subscription offers, and removes legacy/incorrect mappings (e.g., WinBack or subscription-offer details on
DiscountOffer). - Adds/extends deterministic docs audits + tests to prevent regressions in canonical offer pages, search routing, enum wire values, and Kotlin/KMP example shapes.
Reviewed changes
Copilot reviewed 26 out of 32 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/audit-docs.ts | Adds canonical offer-page + search-entry audits and improves brace parsing to handle strings/comments safely. |
| scripts/audit-docs.test.ts | Adds focused tests for the new canonical offer audits and Kotlin/KMP example validation. |
| packages/gql/src/type.graphql | Clarifies DiscountOffer and SubscriptionOffer schema descriptions and canonical doc links. |
| packages/gql/src/type-ios.graphql | Updates deprecated iOS offer type @see links to canonical SubscriptionOffer docs route. |
| packages/gql/src/type-android.graphql | Clarifies Android one-time vs subscription offer fields and updates deprecation guidance. |
| packages/gql/src/generated/types.ts | Regenerates TypeScript types/comments to reflect clarified SSOT docs and deprecation wording. |
| packages/gql/src/generated/Types.swift | Regenerates Swift types/comments to reflect clarified SSOT docs and canonical links. |
| packages/gql/src/generated/Types.kt | Regenerates Kotlin types/comments to reflect clarified SSOT docs and canonical links. |
| packages/gql/src/generated/types.gd | Regenerates GDScript types/comments to reflect clarified SSOT docs and canonical links. |
| packages/gql/src/generated/types.dart | Regenerates Dart types/comments to reflect clarified SSOT docs and canonical links. |
| packages/gql/src/generated/Types.cs | Regenerates C# types/comments to reflect clarified SSOT docs and canonical links. |
| packages/gql/src/generated-doc-comments.test.mjs | Adds a Vitest unit test for the TypeScript @deprecated-dedupe helper. |
| packages/gql/src/generated-compatibility.test.ts | Adds regression coverage for canonical @see links and single @deprecated tags in TS output. |
| packages/gql/scripts/generated-doc-comments.mjs | Introduces a helper to dedupe duplicate TypeScript @deprecated JSDoc tags per block. |
| packages/gql/scripts/fix-generated-types.mjs | Integrates the new JSDoc dedupe step into the TS generated-types post-processing. |
| packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt | Syncs Android package Kotlin types/comments with updated SSOT offer semantics + canonical links. |
| packages/docs/src/pages/docs/types/subscription-product.tsx | Removes misleading discountOffers table entry for subscription products and adds compatibility explanation. |
| packages/docs/src/pages/docs/types/subscription-offer.tsx | Aligns displayed enum wire values/snippets and removes incorrect WinBack mention. |
| packages/docs/src/pages/docs/types/request-purchase-props.tsx | Corrects withOffer description to the iOS-specific promotional-offer input type. |
| packages/docs/src/pages/docs/types/product.tsx | Marks legacy one-time-offer details field as deprecated in docs and points to discountOffers + canonical page. |
| packages/docs/src/pages/docs/types/index.tsx | Updates type listing copy to describe DiscountOffer as Android one-time offer details. |
| packages/docs/src/pages/docs/types/discount-offer.tsx | Rewrites canonical DiscountOffer page to be explicitly Google Play one-time offers and enforces wire-value examples. |
| packages/docs/src/pages/docs/types/android/one-time-purchase-offer-detail-android.tsx | Updates deprecated legacy Android page language to point to standardized DiscountOffer. |
| packages/docs/src/pages/docs/features/discount.tsx | Updates the discount guide to use discountOffers (standardized) rather than legacy Android-native fields. |
| packages/docs/src/lib/searchData.ts | Adds canonical DiscountOffer/SubscriptionOffer search entries and renames legacy entries to avoid collisions. |
| packages/apple/Sources/Models/Types.swift | Syncs Apple package Swift types/comments with updated SSOT offer semantics + canonical links. |
| libraries/react-native-iap/src/types.ts | Syncs RN types/comments with updated SSOT offer semantics + canonical links. |
| libraries/maui-iap/src/OpenIap.Maui/Types.cs | Syncs MAUI types/comments with updated SSOT offer semantics + canonical links. |
| libraries/kmp-iap/library/src/commonMain/kotlin/io/github/hyochan/kmpiap/openiap/Types.kt | Syncs KMP types/comments with updated SSOT offer semantics + canonical links. |
| libraries/godot-iap/addons/godot-iap/types.gd | Syncs Godot types/comments with updated SSOT offer semantics + canonical links. |
| libraries/flutter_inapp_purchase/lib/types.dart | Syncs Flutter types/comments with updated SSOT offer semantics + canonical links. |
| libraries/expo-iap/src/types.ts | Syncs Expo types/comments with updated SSOT offer semantics + canonical links. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Parse documented TypeScript and search metadata structurally, tighten generated enum and Kotlin example guards, and run the audit fixtures in pre-commit and Docs CI.
Keep the accepted audit fixture aligned with the Kotlin and KMP requestPurchase contract so invalid named arguments cannot be mistaken for current SDK usage.
Derive schema inventories, deprecation metadata, generated sync paths, language support, and agent context inputs from canonical manifests. Fail closed on generation drift across CI and platform refreshers, remove redundant generator pipelines, and harden offer documentation audits with focused regression coverage.

Summary
Root cause
Generation policy had accumulated in parallel file lists, scripts, templates, post-processors, workflows, docs audits, and platform refreshers. Those copies could disagree while an individual pipeline still appeared green. Git hooks also leaked OpenIAP's Git-local environment into Flutter's own repository lookup, allowing Flutter to misidentify its SDK version.
SSOT and redundancy cleanup
Verification
Preview
The actual updated docs introduction was rendered locally and visually verified:
Closes #249
Summary by CodeRabbit
DiscountOfferandSubscriptionOffertype docs across platforms to match standardized semantics, updated reference links, and clarified Android formatted-discount wording and platform population behavior.discountOffersflow, including offer selection and purchase request fields.@deprecatedtags and expanded CI/pre-commit audit steps.