refactor: update verifyPurchase to support platform-specific options#53
Conversation
- Add VerifyPurchaseAppleOptions (jws) for iOS App Store verification - Add VerifyPurchaseGoogleOptions (packageName, purchaseToken, accessToken, isSub) for Play Store - Add VerifyPurchaseHorizonOptions (sku, userId, accessToken) for Meta Quest S2S API - Update VerifyPurchaseProps to accept apple, google, horizon fields - Deprecate androidOptions in favor of google field - Implement verifyPurchaseWithHorizon() for Meta S2S verification - Add platform-specific documentation comments Note: Pending version updates for release: - openiap-gql: 1.3.3 - openiap-google: 1.3.13 - openiap-apple: 1.3.1
|
Warning Rate limit exceeded@hyochan has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 22 minutes and 12 seconds before requesting another review. ⌛ 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)
WalkthroughAdds platform-specific purchase and verification types (Apple, Google, Horizon, IAPKit), updates GraphQL inputs, wires Horizon and provider-specific verification into native flows (including iOS JWS short‑circuit), and extends verification implementations and tests accordingly. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant NativeModule as Native Module
participant Verifier as Verification Service
participant Result as VerifyResult
Note over Client,Result: Platform-aware verifyPurchase (Apple/Google/Horizon/IAPKit)
Client->>NativeModule: verifyPurchase(VerifyPurchaseProps)
alt props.apple.jws present
NativeModule->>NativeModule: accept external JWS (short‑circuit)
NativeModule->>Result: return VerifyPurchaseResult (iOS JWS valid)
else props.apple present without jws
NativeModule->>Verifier: fetch StoreKit tx & validate
Verifier-->>NativeModule: verification outcome
NativeModule->>Result: return VerifyPurchaseResult
end
alt props.horizon present
NativeModule->>Verifier: verifyPurchaseWithHorizon(props.horizon, appId)
Verifier-->>Result: VerifyPurchaseResultHorizon
else props.google present
NativeModule->>Verifier: verifyPurchaseWithGooglePlay(props.google)
Verifier-->>Result: VerifyPurchaseResultAndroid/IOS
end
Result-->>Client: VerifyPurchaseResult (platform-specific union)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Suggested labels
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
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 |
- openiap-gql v1.3.3 - openiap-google v1.3.13 - openiap-apple v1.3.1 New VerifyPurchaseProps structure with apple, google, horizon fields
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
packages/apple/Sources/OpenIapModule.swift (1)
595-628: Don't setisValid = truejust because external JWS was provided — it contradicts the field's documented meaning.The
VerifyPurchaseResultIOS.isValidfield is documented as "Whether the receipt is valid". Accepting an external JWS string and immediately marking it valid (lines 607–609) is incorrect: JWS presence ≠ verification. Your own comment says "The caller should verify the JWS on their server", confirming it's unverified at this point. This is a security issue: example code (PurchaseFlowScreen, SubscriptionFlowScreen) finishes purchases based onisValid, so unverified JWS would incorrectly trigger fulfillment.Set
isValid = falsefor external JWS, matching the StoreKit path's semantics (onlytrueaftercheckVerifiedsucceeds).packages/apple/Sources/Models/Types.swift (1)
1145-1172: Stop editingpackages/apple/Sources/Models/Types.swiftdirectly; regenerate from schema instead.
This file is explicitly auto-generated, and direct edits will be overwritten and/or drift from the GraphQL schema. Per repo guidance: update the iOS/macOSgqlversion inpackages/apple/openiap-versions.json, run./scripts/generate-types.sh, then runswift test. Based on learnings / coding guidelines.#!/bin/bash set -euo pipefail # Verify what the repo considers the source of truth for generating Types.swift rg -n --hidden -S "AUTO-GENERATED TYPES|DO NOT EDIT DIRECTLY|npm run generate|generate-types\\.sh|openiap-versions\\.json|gql\"\\s*:" -C2 . # Confirm this file is produced by generation and see if there's a generator header/footer marker rg -n --hidden -S "Generated|AUTO-GENERATED|DO NOT EDIT" -n packages/apple/Sources/Models/Types.swift || trueAlso applies to: 1237-1264, 1288-1309, 1329-1439
🧹 Nitpick comments (5)
packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt (1)
2770-2813: Good direction, but ensure deprecated fields still work end-to-end (mapping/precedence).
Types look consistent, butVerifyPurchaseProps.fromJson()currently keeps bothandroidOptions(deprecated) andverifyPurchaseWithGooglePlay(...)only readsprops.google, older callers usingandroidOptionswill regress.Suggested approach (without editing this generated file): centralize compatibility in the verifier, e.g. treat
androidOptionsas a fallback whengoogle == null, and clearly define precedence when both are present. Based on learnings, keeppackages/google/openiap/src/main/java/dev/hyo/openiap/Types.ktgenerated via./scripts/generate-types.sh, not hand-edited.Also applies to: 2906-2949, 2989-3024, 3056-3082, 3084-3182, 3184-3232
packages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.kt (1)
303-322: Consider improving exception handling in test assertions.The static analysis tool flagged that the caught exception is swallowed at line 319. While the test intent is clear, you could make the assertion more explicit:
} catch (error: OpenIapError.InvalidPurchaseVerification) { - assertTrue(true) + // Expected exception type - test passes }Alternatively, use JUnit's
assertThrowsfor cleaner exception testing:@Test fun `verifyPurchaseWithHorizon throws on failure response`() = runTest { val horizonOptions = VerifyPurchaseHorizonOptions( sku = "50_gems", userId = "123456789", accessToken = "OC|app_id|app_secret" ) val props = VerifyPurchaseProps(horizon = horizonOptions, sku = "50_gems") assertThrows<OpenIapError.InvalidPurchaseVerification> { verifyPurchaseWithHorizon( props, "test-app-id", "TEST" ) { _ -> FakeHttpURLConnection(400, """{"error":"invalid_user"}""") } } }packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt (1)
288-288: Remove empty line.There's a trailing empty line that appears to be a remnant from refactoring.
} - private fun String?.orElse(fallback: String): String = this ?: fallbackpackages/apple/Sources/Models/Types.swift (2)
1151-1172: Clarify/validate “only one platform field should be set” (avoid ambiguous payloads).
RequestPurchasePropsByPlatforms/RequestSubscriptionPropsByPlatforms/VerifyPurchasePropsallow multiple optional platform fields to be set simultaneously (e.g.,android+ios+apple). If the backend expects exactly one, consider enforcing it at the schema level (preferred) or at least documenting precedence rules.Also applies to: 1243-1264, 1414-1439
1152-1160: Use real Swift deprecation annotations (not only doc comments).
If the generator supports it, prefer emitting@available(*, deprecated, message: "...")for deprecated fields/types (e.g.,androidOptions,android,ios,VerifyPurchaseAndroidOptions) so downstream users get compiler warnings. If not supported today, this is a generator/schema enhancement request.Also applies to: 1244-1252, 1329-1347, 1415-1416
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (4)
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.tsis excluded by!**/generated/**
📒 Files selected for processing (10)
packages/apple/Sources/Models/Types.swift(5 hunks)packages/apple/Sources/OpenIapModule.swift(1 hunks)packages/docs/src/pages/docs/updates/notes.tsx(1 hunks)packages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.kt(2 hunks)packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt(6 hunks)packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt(3 hunks)packages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.kt(3 hunks)packages/gql/src/type-android.graphql(1 hunks)packages/gql/src/type-ios.graphql(1 hunks)packages/gql/src/type.graphql(4 hunks)
🧰 Additional context used
📓 Path-based instructions (10)
packages/apple/**/*.swift
📄 CodeRabbit inference engine (CLAUDE.md)
packages/apple/**/*.swift: iOS-specific functions MUST haveIOSsuffix (e.g.,presentCodeRedemptionSheetIOS(),showManageSubscriptionsIOS())
Use Pascal case for acronyms at the beginning or middle of names (e.g.,IapManager,IapPurchase), but ALL CAPS only when appearing as a suffix (e.g.,ProductIAP,OpenIAP)
Files:
packages/apple/Sources/OpenIapModule.swiftpackages/apple/Sources/Models/Types.swift
packages/gql/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Run
bun run generateto regenerate types for all platforms (TypeScript, Swift, Kotlin, Dart) from the GraphQL schema
Files:
packages/gql/src/type-ios.graphqlpackages/gql/src/type-android.graphqlpackages/gql/src/type.graphql
packages/google/**/*.kt
📄 CodeRabbit inference engine (CLAUDE.md)
DO NOT add
Androidsuffix to function names in the Android-only package, even for Android-specific APIs (e.g., useacknowledgePurchase()notacknowledgePurchaseAndroid())
Files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.ktpackages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.ktpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/**/*.kt
📄 CodeRabbit inference engine (CLAUDE.md)
Place reusable Kotlin helper functions in
openiap/src/main/java/dev/hyo/openiap/utils/
Files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: iOS-specific functions must end withIOSsuffix (e.g.,clearTransactionIOS,getAppTransactionIOS)
Android-specific functions must end withAndroidsuffix (e.g.,acknowledgePurchaseAndroid,consumePurchaseAndroid)
Use action prefixes for function naming:getfor retrieval,requestfor async operations,clearfor removal,is/hasfor boolean checks,show/presentfor UI display,begin/finish/endfor process controlPrefer interface for defining object shapes in TypeScript
Files:
packages/docs/src/pages/docs/updates/notes.tsx
packages/docs/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
packages/docs/**/*.{ts,tsx}: Use kebab-case for search modal IDs (e.g.,id: 'request-products')
Modal state should be defined once at the app root level using Preact Signals (signal from '@preact/signals-react'), not instantiated multiple times
ALL components must fit within parent boundaries and never overflow outside parent containers; useoverflow-hidden,break-words, andwhitespace-nowrapas needed
Delete unused components, functions, and imports immediately; do not keep commented-out code or unused variables
ANY function that returns a Promise must be wrapped withvoidoperator when used where a void return is expected (e.g., event handlers)
Files:
packages/docs/src/pages/docs/updates/notes.tsx
packages/docs/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
packages/docs/**/*: Before committing, runnpx prettier --write,npm run lint,bun run tscornpm run typecheck, andnpm run buildto verify formatting, linting, types, and build success
Use conventional commit format with lowercase type prefix and lowercase description (e.g.,feat: add user authentication)
Files:
packages/docs/src/pages/docs/updates/notes.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (GEMINI.md)
**/*.{ts,tsx,js,jsx}: Use camelCase for variable and function names
Use PascalCase for class and component names
Always use async/await for handling promises instead of .then() chains
Add JSDoc comments for public functions and exported APIs
Use const by default, let if reassignment is needed, avoid var
Files:
packages/docs/src/pages/docs/updates/notes.tsx
packages/apple/Sources/Models/Types.swift
📄 CodeRabbit inference engine (CLAUDE.md)
DO NOT edit
Types.swiftinSources/Models/as it is auto-generated from the OpenIAP GraphQL schema; regenerate using./scripts/generate-types.sh
Files:
packages/apple/Sources/Models/Types.swift
packages/apple/Sources/Models/**/*.swift
📄 CodeRabbit inference engine (CLAUDE.md)
OpenIAP official types in
Sources/Models/must match types defined at openiap.dev/docs/types
Files:
packages/apple/Sources/Models/Types.swift
🧠 Learnings (10)
📓 Common learnings
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/openiap-versions.json : To update OpenIAP GraphQL types in the iOS/macOS library, edit the `gql` field in `openiap-versions.json`, run `./scripts/generate-types.sh`, and run `swift test` to verify compatibility
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap-versions.json : To update OpenIAP GraphQL types in the Android library, edit the `gql` field in `openiap-versions.json`, then run `./scripts/generate-types.sh` and compile to verify
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/Sources/Models/**/*.swift : OpenIAP official types in `Sources/Models/` must match types defined at [openiap.dev/docs/types](https://www.openiap.dev/docs/types)
Applied to files:
packages/apple/Sources/OpenIapModule.swiftpackages/gql/src/type-ios.graphqlpackages/gql/src/type.graphqlpackages/apple/Sources/Models/Types.swiftpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/Sources/Helpers/**/*.swift : Place internal helper classes in `Sources/Helpers/` (e.g., `ProductManager.swift` for thread-safe caching, `IapStatus.swift` for UI status); these are NOT official OpenIAP types
Applied to files:
packages/apple/Sources/OpenIapModule.swiftpackages/apple/Sources/Models/Types.swift
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/openiap-versions.json : To update OpenIAP GraphQL types in the iOS/macOS library, edit the `gql` field in `openiap-versions.json`, run `./scripts/generate-types.sh`, and run `swift test` to verify compatibility
Applied to files:
packages/apple/Sources/OpenIapModule.swiftpackages/gql/src/type-ios.graphqlpackages/gql/src/type-android.graphqlpackages/docs/src/pages/docs/updates/notes.tsxpackages/gql/src/type.graphqlpackages/apple/Sources/Models/Types.swiftpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/Sources/Models/Types.swift : DO NOT edit `Types.swift` in `Sources/Models/` as it is auto-generated from the OpenIAP GraphQL schema; regenerate using `./scripts/generate-types.sh`
Applied to files:
packages/apple/Sources/OpenIapModule.swiftpackages/gql/src/type-ios.graphqlpackages/gql/src/type.graphqlpackages/apple/Sources/Models/Types.swiftpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap-versions.json : To update OpenIAP GraphQL types in the Android library, edit the `gql` field in `openiap-versions.json`, then run `./scripts/generate-types.sh` and compile to verify
Applied to files:
packages/gql/src/type-ios.graphqlpackages/gql/src/type-android.graphqlpackages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/docs/src/pages/docs/updates/notes.tsxpackages/gql/src/type.graphqlpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap/src/main/Types.kt : DO NOT edit `openiap/src/main/Types.kt` as it is auto-generated from the GraphQL schema; regenerate it using `./scripts/generate-types.sh`
Applied to files:
packages/gql/src/type-android.graphqlpackages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.ktpackages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.ktpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/**/*.kt : DO NOT add `Android` suffix to function names in the Android-only package, even for Android-specific APIs (e.g., use `acknowledgePurchase()` not `acknowledgePurchaseAndroid()`)
Applied to files:
packages/gql/src/type-android.graphqlpackages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.ktpackages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.ktpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap/src/main/java/dev/hyo/openiap/utils/**/*.kt : Place reusable Kotlin helper functions in `openiap/src/main/java/dev/hyo/openiap/utils/`
Applied to files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.ktpackages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.ktpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/**/*.swift : Use Pascal case for acronyms at the beginning or middle of names (e.g., `IapManager`, `IapPurchase`), but ALL CAPS only when appearing as a suffix (e.g., `ProductIAP`, `OpenIAP`)
Applied to files:
packages/apple/Sources/Models/Types.swift
🧬 Code graph analysis (5)
packages/apple/Sources/OpenIapModule.swift (3)
packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt (4)
jws(2951-2968)jws(3088-3105)isValid(2073-2101)isValid(2339-2376)packages/gql/src/generated/Types.kt (4)
jws(3023-3040)jws(3160-3177)isValid(2145-2173)isValid(2411-2448)packages/apple/Sources/Helpers/StoreKitTypesBridge.swift (2)
product(6-8)purchaseIOS(103-174)
packages/docs/src/pages/docs/updates/notes.tsx (2)
packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt (2)
code(1763-1785)code(2378-2397)packages/gql/src/generated/Types.kt (2)
code(1835-1857)code(2450-2469)
packages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.kt (2)
packages/gql/src/generated/types.ts (3)
VerifyPurchaseProps(1166-1177)VerifyPurchaseGoogleOptions(1134-1143)VerifyPurchaseHorizonOptions(1150-1157)packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt (2)
verifyPurchaseWithGooglePlay(26-101)verifyPurchaseWithHorizon(107-176)
packages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.kt (2)
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt (1)
verifyPurchaseWithHorizon(107-176)packages/gql/src/generated/types.ts (1)
VerifyPurchaseResultAndroid(1181-1200)
packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt (1)
packages/gql/src/generated/types.ts (3)
VerifyPurchaseAppleOptions(1125-1128)VerifyPurchaseGoogleOptions(1134-1143)VerifyPurchaseHorizonOptions(1150-1157)
🪛 detekt (1.23.8)
packages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.kt
[warning] 319-319: The caught exception is swallowed. The original exception could be lost.
(detekt.exceptions.SwallowedException)
🔇 Additional comments (11)
packages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.kt (1)
37-37: Import addition is fine.packages/gql/src/type-ios.graphql (1)
230-239: NewVerifyPurchaseAppleOptionsinput looks correct.
Please just confirm it’s actually wired into theVerifyPurchasePropsinput in the overall schema (not only defined).packages/docs/src/pages/docs/updates/notes.tsx (1)
22-105: Documentation looks comprehensive and well-structured.The new content block clearly documents the platform-specific verification options introduced in this PR. The code example effectively demonstrates the new
VerifyPurchasePropsstructure withapple,horizonfields, along with the deprecation notice forandroidOptions.packages/gql/src/type-android.graphql (1)
373-424: New GraphQL input types are well-defined.The
VerifyPurchaseGoogleOptionsandVerifyPurchaseHorizonOptionsinput types are properly structured with clear documentation. Note thatVerifyPurchaseGoogleOptionsusespurchaseTokenwhile the deprecatedVerifyPurchaseAndroidOptionsusesproductToken- this naming improvement aligns with Google's API terminology.Per the learnings, ensure you run
./scripts/generate-types.shto regenerate types for all platforms (TypeScript, Swift, Kotlin, Dart) after modifying the GraphQL schema, then compile to verify compatibility.packages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.kt (2)
42-82: Good test coverage for the newThe test properly validates that
verifyPurchaseWithGooglePlayworks with the newVerifyPurchaseGoogleOptionstype and correctly parses the response fields.
267-301: Good Horizon verification test coverage.The tests appropriately cover:
- Missing horizon options throws
IllegalArgumentException- Successful response parsing with
successandgrantTimefields- Non-2xx responses throw
InvalidPurchaseVerificationpackages/gql/src/type.graphql (2)
190-242: Clear documentation on platform vs store semantics.The documentation blocks effectively clarify that "platforms" refers to SDK/OS level (apple, google), with google targeting Play Store by default or Horizon when built with horizon flavor. This distinction is important for developers.
245-273: Well-structured platform-specific verification options.The
VerifyPurchasePropsinput type now properly supports:
apple: App Store Server APIhorizon: Meta's S2S APIThe deprecation of
androidOptionsin favor ofpackages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt (2)
31-58: Clean backward-compatible implementation.The
whenclause correctly prioritizes the newandroidOptions, maintaining backward compatibility. The field mapping fromlegacyOptions.productTokentopurchaseTokenproperly handles the naming difference between old and new APIs.
103-176: Horizon verification implementation looks correct.The function properly:
- Validates required horizon options
- Uses URL encoding for form data parameters
- Posts to Meta's S2S API endpoint
- Parses the JSON response for
successandgrant_time- Handles errors consistently with the Google Play verification path
packages/apple/Sources/Models/Types.swift (1)
1330-1346: Verify token field mapping for Android legacy vs new Google options.
LegacyVerifyPurchaseAndroidOptionsusesproductToken, while the newVerifyPurchaseGoogleOptionsusespurchaseToken. Make sure all call sites and any bridging/serialization logic map these correctly (and that backend expects the new key name).Also applies to: 1364-1385
BREAKING CHANGE: androidOptions is removed, use google options instead - Remove androidOptions/legacyOptions from verifyPurchaseWithGooglePlay - Capture and check Horizon verification result, throw error if failed - Populate VerifyPurchaseResultAndroid with actual Horizon data
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt (1)
84-165: Horizon verification implementation looks correct.The implementation properly validates inputs, constructs the Meta S2S API request with URL-encoded form data, handles errors, and parses the response. The error handling is consistent with
verifyPurchaseWithGooglePlay.Note: A previous review comment already flagged that
VerifyPurchaseResultHorizon(lines 162-165) should be moved to the GraphQL schema rather than maintained as a local definition.
🧹 Nitpick comments (1)
packages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.kt (1)
657-689: Consider adding SKU validation between top-level and Horizon-specific fields.The previous review suggested validating that
props.skumatchesprops.horizon?.skuto prevent accidental mismatches. This validation would catch configuration errors early.Apply this diff to add the validation:
override val verifyPurchase: MutationVerifyPurchaseHandler = { props -> // Use Horizon API if horizon options provided, otherwise fallback to Google Play if (props.horizon != null) { val horizonAppId = appId ?: throw OpenIapError.DeveloperError + // Validate SKU consistency + if (props.sku != props.horizon?.sku) { + throw OpenIapError.DeveloperError + } val horizonResult = verifyPurchaseWithHorizon(props, horizonAppId, TAG) if (!horizonResult.success) { throw OpenIapError.InvalidPurchaseVerification }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.kt(2 hunks)packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt(3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
packages/google/**/*.kt
📄 CodeRabbit inference engine (CLAUDE.md)
DO NOT add
Androidsuffix to function names in the Android-only package, even for Android-specific APIs (e.g., useacknowledgePurchase()notacknowledgePurchaseAndroid())
Files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.kt
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/**/*.kt
📄 CodeRabbit inference engine (CLAUDE.md)
Place reusable Kotlin helper functions in
openiap/src/main/java/dev/hyo/openiap/utils/
Files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt
🧠 Learnings (8)
📓 Common learnings
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/openiap-versions.json : To update OpenIAP GraphQL types in the iOS/macOS library, edit the `gql` field in `openiap-versions.json`, run `./scripts/generate-types.sh`, and run `swift test` to verify compatibility
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap-versions.json : To update OpenIAP GraphQL types in the Android library, edit the `gql` field in `openiap-versions.json`, then run `./scripts/generate-types.sh` and compile to verify
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/**/*.kt : DO NOT add `Android` suffix to function names in the Android-only package, even for Android-specific APIs (e.g., use `acknowledgePurchase()` not `acknowledgePurchaseAndroid()`)
Applied to files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap/src/main/java/dev/hyo/openiap/utils/**/*.kt : Place reusable Kotlin helper functions in `openiap/src/main/java/dev/hyo/openiap/utils/`
Applied to files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap/src/main/Types.kt : DO NOT edit `openiap/src/main/Types.kt` as it is auto-generated from the GraphQL schema; regenerate it using `./scripts/generate-types.sh`
Applied to files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap-versions.json : To update OpenIAP GraphQL types in the Android library, edit the `gql` field in `openiap-versions.json`, then run `./scripts/generate-types.sh` and compile to verify
Applied to files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/openiap-versions.json : To update OpenIAP GraphQL types in the iOS/macOS library, edit the `gql` field in `openiap-versions.json`, run `./scripts/generate-types.sh`, and run `swift test` to verify compatibility
Applied to files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/Sources/Models/**/*.swift : OpenIAP official types in `Sources/Models/` must match types defined at [openiap.dev/docs/types](https://www.openiap.dev/docs/types)
Applied to files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/Sources/Models/Types.swift : DO NOT edit `Types.swift` in `Sources/Models/` as it is auto-generated from the OpenIAP GraphQL schema; regenerate using `./scripts/generate-types.sh`
Applied to files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt
🧬 Code graph analysis (1)
packages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.kt (2)
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt (2)
verifyPurchaseWithHorizon(88-157)verifyPurchaseWithGooglePlay(26-82)packages/gql/src/generated/types.ts (1)
VerifyPurchaseResultAndroid(1181-1200)
⏰ 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). (1)
- GitHub Check: Test Android
🔇 Additional comments (4)
packages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.kt (1)
37-37: LGTM!The import is correctly placed and necessary for the Horizon verification functionality.
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt (3)
26-82: LGTM!The migration from deprecated
androidOptionsto the new
174-176: LGTM!The updated comment accurately describes IAPKit support limitations for Android platforms.
254-267: LGTM!The helper function correctly builds the Google Play payload for IAPKit verification with proper validation.
…idOptions BREAKING CHANGE: VerifyPurchaseAndroidOptions is removed from schema - Add VerifyPurchaseResultHorizon type to GraphQL schema - Add VerifyPurchaseResultHorizon to VerifyPurchaseResult union - Remove deprecated VerifyPurchaseAndroidOptions from schema - Remove deprecated androidOptions from VerifyPurchaseProps - Update verifyPurchase to return VerifyPurchaseResultHorizon directly - Fix tests to use google options instead of androidOptions - Regenerate types for all platforms
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (7)
packages/apple/Sources/Models/Types.swift (1)
1154-1181: Docs are helpful, but “google targets Horizon” wording may confuse API consumers.
Consider tightening the wording to avoid implying runtime routing via thepackages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.kt (1)
37-37: Horizon verification branch looks correct (success-gated + returns Horizon result); consider SKU mismatch guard.
You nowthrow OpenIapError.InvalidPurchaseVerificationwhenhorizonResult.successis false and returnhorizonResulton success—this addresses the prior bug. Optional hardening: ifprops.horizon.skuis present and differs fromprops.sku, fail fast (likelyOpenIapError.DeveloperError) to avoid verifying/granting the wrong item.Also applies to: 657-668
packages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.kt (2)
83-147: Existing Google Play tests updated correctly; consider consolidating duplicates.
You now exercise both “works with new google field” and “parses successful response” with near-identical payloads; optional to merge to reduce duplication.
267-321: Horizon tests are solid; fix detekt “swallowed exception” by usingassertThrows.
The catch block at Line 318 triggers detekt. PreferassertThrows(OpenIapError.InvalidPurchaseVerification::class.java) { ... }(and optionally assert on message/HTTP code if exposed).packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt (3)
27-56: Google Play verification refactor looks correct; consider requiringisSub(or documenting default).
Core change (useVerifyPurchaseGoogleOptions+ Bearer token + endpoint switching) looks good. One potential footgun:isSubis nullable and currently treated as false when null, which will hit the/productsendpoint—consider requiring explicitisSubor clearly documenting that null => one-time product.
58-83: Add connect/read timeouts to avoid indefinite hangs.
Both verification paths useHttpURLConnectionwithoutconnectTimeout/readTimeout, which can blockDispatchers.IOthreads on bad networks.
85-158: Horizon S2S implementation is reasonable; keep token out of logs and consider explicit charset.
Form encoding + non-2xx mapping toInvalidPurchaseVerificationis good. Minor: write bytes as UTF-8 explicitly (toByteArray(Charsets.UTF_8)) for consistency.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (4)
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.tsis excluded by!**/generated/**
📒 Files selected for processing (7)
packages/apple/Sources/Models/Types.swift(6 hunks)packages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.kt(2 hunks)packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt(8 hunks)packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt(4 hunks)packages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.kt(4 hunks)packages/gql/src/type-android.graphql(1 hunks)packages/gql/src/type.graphql(4 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
packages/google/**/*.kt
📄 CodeRabbit inference engine (CLAUDE.md)
DO NOT add
Androidsuffix to function names in the Android-only package, even for Android-specific APIs (e.g., useacknowledgePurchase()notacknowledgePurchaseAndroid())
Files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.ktpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.ktpackages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.kt
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/**/*.kt
📄 CodeRabbit inference engine (CLAUDE.md)
Place reusable Kotlin helper functions in
openiap/src/main/java/dev/hyo/openiap/utils/
Files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt
packages/gql/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Run
bun run generateto regenerate types for all platforms (TypeScript, Swift, Kotlin, Dart) from the GraphQL schema
Files:
packages/gql/src/type-android.graphqlpackages/gql/src/type.graphql
packages/apple/**/*.swift
📄 CodeRabbit inference engine (CLAUDE.md)
packages/apple/**/*.swift: iOS-specific functions MUST haveIOSsuffix (e.g.,presentCodeRedemptionSheetIOS(),showManageSubscriptionsIOS())
Use Pascal case for acronyms at the beginning or middle of names (e.g.,IapManager,IapPurchase), but ALL CAPS only when appearing as a suffix (e.g.,ProductIAP,OpenIAP)
Files:
packages/apple/Sources/Models/Types.swift
packages/apple/Sources/Models/Types.swift
📄 CodeRabbit inference engine (CLAUDE.md)
DO NOT edit
Types.swiftinSources/Models/as it is auto-generated from the OpenIAP GraphQL schema; regenerate using./scripts/generate-types.sh
Files:
packages/apple/Sources/Models/Types.swift
packages/apple/Sources/Models/**/*.swift
📄 CodeRabbit inference engine (CLAUDE.md)
OpenIAP official types in
Sources/Models/must match types defined at openiap.dev/docs/types
Files:
packages/apple/Sources/Models/Types.swift
🧠 Learnings (10)
📓 Common learnings
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/openiap-versions.json : To update OpenIAP GraphQL types in the iOS/macOS library, edit the `gql` field in `openiap-versions.json`, run `./scripts/generate-types.sh`, and run `swift test` to verify compatibility
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap-versions.json : To update OpenIAP GraphQL types in the Android library, edit the `gql` field in `openiap-versions.json`, then run `./scripts/generate-types.sh` and compile to verify
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/**/*.kt : DO NOT add `Android` suffix to function names in the Android-only package, even for Android-specific APIs (e.g., use `acknowledgePurchase()` not `acknowledgePurchaseAndroid()`)
Applied to files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.ktpackages/gql/src/type-android.graphqlpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.ktpackages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap/src/main/java/dev/hyo/openiap/utils/**/*.kt : Place reusable Kotlin helper functions in `openiap/src/main/java/dev/hyo/openiap/utils/`
Applied to files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.ktpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.ktpackages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap/src/main/Types.kt : DO NOT edit `openiap/src/main/Types.kt` as it is auto-generated from the GraphQL schema; regenerate it using `./scripts/generate-types.sh`
Applied to files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.ktpackages/gql/src/type-android.graphqlpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.ktpackages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap-versions.json : To update OpenIAP GraphQL types in the Android library, edit the `gql` field in `openiap-versions.json`, then run `./scripts/generate-types.sh` and compile to verify
Applied to files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/gql/src/type-android.graphqlpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.ktpackages/gql/src/type.graphqlpackages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/openiap-versions.json : To update OpenIAP GraphQL types in the iOS/macOS library, edit the `gql` field in `openiap-versions.json`, run `./scripts/generate-types.sh`, and run `swift test` to verify compatibility
Applied to files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/gql/src/type-android.graphqlpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.ktpackages/gql/src/type.graphqlpackages/apple/Sources/Models/Types.swift
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/Sources/Models/**/*.swift : OpenIAP official types in `Sources/Models/` must match types defined at [openiap.dev/docs/types](https://www.openiap.dev/docs/types)
Applied to files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.ktpackages/apple/Sources/Models/Types.swift
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/Sources/Models/Types.swift : DO NOT edit `Types.swift` in `Sources/Models/` as it is auto-generated from the OpenIAP GraphQL schema; regenerate using `./scripts/generate-types.sh`
Applied to files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.ktpackages/gql/src/type.graphqlpackages/apple/Sources/Models/Types.swift
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to **/*.{ts,tsx} : Android-specific functions must end with `Android` suffix (e.g., `acknowledgePurchaseAndroid`, `consumePurchaseAndroid`)
Applied to files:
packages/gql/src/type-android.graphql
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/Sources/Helpers/**/*.swift : Place internal helper classes in `Sources/Helpers/` (e.g., `ProductManager.swift` for thread-safe caching, `IapStatus.swift` for UI status); these are NOT official OpenIAP types
Applied to files:
packages/apple/Sources/Models/Types.swift
🧬 Code graph analysis (3)
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt (2)
packages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.kt (1)
setRequestProperty(338-342)packages/gql/src/generated/types.ts (1)
VerifyPurchaseResultHorizon(1196-1201)
packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt (1)
packages/gql/src/generated/types.ts (4)
VerifyPurchaseResultHorizon(1196-1201)VerifyPurchaseAppleOptions(1117-1120)VerifyPurchaseGoogleOptions(1126-1135)VerifyPurchaseHorizonOptions(1142-1149)
packages/apple/Sources/Models/Types.swift (3)
packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt (8)
grantTime(2343-2368)apiKey(3026-3055)apple(3194-3229)jws(2982-2999)jws(3091-3108)accessToken(3114-3149)accessToken(3156-3185)purchaseToken(3001-3018)packages/gql/src/generated/Types.kt (8)
grantTime(2415-2440)apiKey(3098-3127)apple(3266-3301)jws(3054-3071)jws(3163-3180)accessToken(3186-3221)accessToken(3228-3257)purchaseToken(3073-3090)packages/google/openiap/src/main/java/dev/hyo/openiap/OpenIapError.kt (1)
sku(163-172)
🪛 detekt (1.23.8)
packages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.kt
[warning] 318-318: The caught exception is swallowed. The original exception could be lost.
(detekt.exceptions.SwallowedException)
⏰ 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: Test iOS
- GitHub Check: Test Android
🔇 Additional comments (15)
packages/gql/src/type-android.graphql (1)
373-429: Well-structured platform-specific verification types.The new Google Play and Horizon verification inputs and result types are properly documented and correctly capture the required fields for each platform's verification API.
packages/gql/src/type.graphql (4)
245-269: Clarify androidOptions removal vs. deprecation.The PR objectives state "Deprecate androidOptions" but the schema shows
VerifyPurchasePropswithout anandroidOptionsfield—indicating a removal rather than deprecation. IfandroidOptionswas completely removed, this is a breaking change that:
- Breaks clients still using the old field
- Requires clear migration guidance
- Should be marked as
@deprecatedwith replacement hints before removalPlease verify:
- Was
androidOptionsremoved entirely or deprecated with a@deprecatedmarker?- If removed, confirm this breaking change is intentional and documented in release notes.
- If deprecated, add the
@deprecated(reason: "Use google instead")marker to the schema.
190-242: Platform naming documentation is clear.The added doc comments for
RequestPurchasePropsByPlatformsand newRequestSubscriptionPropsByPlatformsclearly explain the distinction between SDK/OS "platforms" (apple, google) and stores, and properly mark deprecated aliases. This prevents confusion when the google platform targets different stores (Play Store vs. Horizon) based on build-time flavor.
270-309: Union and IAPKit types are well-structured.The addition of
VerifyPurchaseResultHorizonto the union and the newRequestVerifyPurchaseWithIapkitPropswith platform-specific sub-inputs follow the established pattern and are properly documented.
1-309: Regenerate types for all platforms after GraphQL schema changes.Per the coding guidelines, after GraphQL schema modifications, all platform-specific types (TypeScript, Swift, Kotlin, Dart) must be regenerated.
Run the following command to regenerate:
bun run generateVerify that generated types in
packages/apple/,packages/google/, and other platform packages reflect these schema changes before merging.packages/apple/Sources/Models/Types.swift (6)
847-855:VerifyPurchaseResultHorizonlooks consistent with existing cross-platform shape.
Fields (grantTime,success) align with the Kotlin types described in the context snippets, andCodableis appropriate here.
1246-1273:RequestSubscriptionPropsByPlatformsmirrors purchase props nicely.
No issues in the struct shape or init defaults.
1297-1318:RequestVerifyPurchaseWithIapkitPropsadditions are straightforward.
Clear separation of apple vs google inputs; Codable/init defaults look good.
1746-1750: Adding the Horizon case toVerifyPurchaseResultis expected for multi-provider verification.
Just ensure downstream decoding/handling is updated anywhere this enum is switched over (especially exhaustive switches in Swift).
1398-1424: This code is auto-generated from the GraphQL schema and the duplicateskufields serve different purposes:VerifyPurchaseProps.skuis the general product SKU for validation, whileVerifyPurchaseHorizonOptions.skuis the specific add-on item SKU required by Meta's API. Both fields are intentionally defined in the GraphQL schema and are not a contract footgun.Likely an incorrect or invalid review comment.
1-4: No issues found. This PR properly follows the code generation workflow: the GraphQL schema was updated withVerifyPurchaseResultHorizon, and types were regenerated across all platforms usingbun run generate. The commit message confirms "Regenerate types for all platforms," and the generated files are correctly synced. No manual edits toTypes.swiftwere made.packages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.kt (2)
5-13: Import updates align with new provider-specific types.
41-82: Good coverage for the newpackages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt (1)
247-260:buildGooglePayloadextraction is a good cleanup.packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt (1)
2339-2368: Generated types update matches the new provider-specific verification model; please confirm they were regenerated (not hand-edited) across packages.
Given this isAUTO-GENERATED, please double-check the changes came from schema updates + regeneration (per repo guidance: updatepackages/google/openiap-versions.json→ run./scripts/generate-types.sh, and similarly for Apple +swift test). Based on learnings, do not manually edit this file.Also applies to: 2801-2844, 2937-2980, 3020-3055, 3087-3229, 3324-3326
- Remove IAPKit request/response body logging to prevent token leaks - Remove responseBody from error logs - Rename test to reflect removal of androidOptions
- Add SECURITY warnings to VerifyPurchaseAppleOptions (jws) - Add SECURITY warnings to VerifyPurchaseGoogleOptions (accessToken, purchaseToken) - Add SECURITY warnings to VerifyPurchaseHorizonOptions (accessToken) - Regenerate types for all platforms with security documentation
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt (2)
52-83: SetconnectTimeout/readTimeoutonHttpURLConnectionto avoid hangs.
Both Google and Horizon requests can block indefinitely today; this is painful in client SDKs and hard to recover from.Example:
val connection = connectionFactory(url).apply { requestMethod = "GET" + connectTimeout = 10_000 + readTimeout = 10_000 setRequestProperty("Content-Type", "application/json") setRequestProperty("Authorization", "Bearer $accessToken") }(and similarly for Horizon
POST).Also applies to: 108-158
65-67: Avoid logging full verification response bodies (truncate/redact).
Even on failures, responses can include identifiers and diagnostic payloads; safer to log status + a capped snippet.Also applies to: 132-135
♻️ Duplicate comments (1)
packages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.kt (1)
28-39: PreferassertThrows(and assert message) instead of swallowing exceptions in these tests.
Detekt’s swallowed-exception warning (Line 318) is valid here;assertTrue(true)insidecatchalso hides regressions. This is the same theme as the earlier review note about preferringassertThrows.Example direction:
+import org.junit.Assert.assertThrows ... - try { - verifyPurchaseWithHorizon(...) - throw AssertionError("Expected IllegalArgumentException for missing horizon options") - } catch (expected: IllegalArgumentException) { - // Expected path - } + assertThrows(IllegalArgumentException::class.java) { + runTest { verifyPurchaseWithHorizon(...) { _ -> ... } } + }Also applies to: 127-147, 269-321
🧹 Nitpick comments (2)
packages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.kt (2)
41-82: Make this test assert the “new google field” behavior (URL + auth header), or drop it as redundant.
Right now it overlaps heavily withverifyPurchaseWithGooglePlay parses successful response, but doesn’t validate the key refactor: URL construction usingpackageName+purchaseTokenand theAuthorization: Bearer <accessToken>header.Concrete tweak:
- val result = verifyPurchaseWithGooglePlay( - props, - "TEST_TAG" - ) { _ -> FakeHttpURLConnection(200, body) } + var seenUrl: String? = null + val connection = FakeHttpURLConnection(200, body) + val result = verifyPurchaseWithGooglePlay(props, "TEST_TAG") { url -> + seenUrl = url + connection + } + assertTrue(seenUrl!!.contains("/applications/dev.hyo.app/")) + assertEquals("Bearer token", connection.headers["Authorization"])
283-321: Horizon tests: assert form-encoded body + content-type (core behavior) instead of only response parsing.
You already havewrittenBodyandheaders; use them to validate the request payload (access_token,user_id,sku) andContent-Type.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt(5 hunks)packages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.kt(4 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
packages/google/**/*.kt
📄 CodeRabbit inference engine (CLAUDE.md)
DO NOT add
Androidsuffix to function names in the Android-only package, even for Android-specific APIs (e.g., useacknowledgePurchase()notacknowledgePurchaseAndroid())
Files:
packages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.ktpackages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/**/*.kt
📄 CodeRabbit inference engine (CLAUDE.md)
Place reusable Kotlin helper functions in
openiap/src/main/java/dev/hyo/openiap/utils/
Files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/openiap-versions.json : To update OpenIAP GraphQL types in the iOS/macOS library, edit the `gql` field in `openiap-versions.json`, run `./scripts/generate-types.sh`, and run `swift test` to verify compatibility
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap-versions.json : To update OpenIAP GraphQL types in the Android library, edit the `gql` field in `openiap-versions.json`, then run `./scripts/generate-types.sh` and compile to verify
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/**/*.kt : DO NOT add `Android` suffix to function names in the Android-only package, even for Android-specific APIs (e.g., use `acknowledgePurchase()` not `acknowledgePurchaseAndroid()`)
Applied to files:
packages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.ktpackages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap/src/main/Types.kt : DO NOT edit `openiap/src/main/Types.kt` as it is auto-generated from the GraphQL schema; regenerate it using `./scripts/generate-types.sh`
Applied to files:
packages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.ktpackages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap/src/main/java/dev/hyo/openiap/utils/**/*.kt : Place reusable Kotlin helper functions in `openiap/src/main/java/dev/hyo/openiap/utils/`
Applied to files:
packages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.ktpackages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap-versions.json : To update OpenIAP GraphQL types in the Android library, edit the `gql` field in `openiap-versions.json`, then run `./scripts/generate-types.sh` and compile to verify
Applied to files:
packages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.ktpackages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/openiap-versions.json : To update OpenIAP GraphQL types in the iOS/macOS library, edit the `gql` field in `openiap-versions.json`, run `./scripts/generate-types.sh`, and run `swift test` to verify compatibility
Applied to files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/Sources/Models/**/*.swift : OpenIAP official types in `Sources/Models/` must match types defined at [openiap.dev/docs/types](https://www.openiap.dev/docs/types)
Applied to files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/Sources/Models/Types.swift : DO NOT edit `Types.swift` in `Sources/Models/` as it is auto-generated from the OpenIAP GraphQL schema; regenerate using `./scripts/generate-types.sh`
Applied to files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/**/*.swift : Use Pascal case for acronyms at the beginning or middle of names (e.g., `IapManager`, `IapPurchase`), but ALL CAPS only when appearing as a suffix (e.g., `ProductIAP`, `OpenIAP`)
Applied to files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt
🧬 Code graph analysis (1)
packages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.kt (2)
packages/gql/src/generated/types.ts (3)
VerifyPurchaseProps(1158-1167)VerifyPurchaseGoogleOptions(1126-1135)VerifyPurchaseHorizonOptions(1142-1149)packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt (2)
verifyPurchaseWithGooglePlay(27-83)verifyPurchaseWithHorizon(89-158)
🪛 detekt (1.23.8)
packages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.kt
[warning] 318-318: The caught exception is swallowed. The original exception could be lost.
(detekt.exceptions.SwallowedException)
⏰ 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). (1)
- GitHub Check: Test Android
🔇 Additional comments (1)
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt (1)
167-175:buildGooglePayload()extraction looks good.
Clearer separation and keeps the IAPKit request construction focused.Also applies to: 240-253
- Add encodePathSegment helper for URL path encoding - URL-encode packageName, sku, purchaseToken in Google Play API URL - Use explicit Charsets.UTF_8 for Horizon form data encoding
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt (1)
116-116: Include charset in Content-Type header.The
Content-Typeheader should specifycharset=UTF-8to match the byte encoding used when writing the form data.Apply this diff:
- setRequestProperty("Content-Type", "application/x-www-form-urlencoded") + setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (4)
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.tsis excluded by!**/generated/**
📒 Files selected for processing (5)
packages/apple/Sources/Models/Types.swift(6 hunks)packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt(8 hunks)packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt(6 hunks)packages/gql/src/type-android.graphql(1 hunks)packages/gql/src/type-ios.graphql(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/gql/src/type-ios.graphql
🧰 Additional context used
📓 Path-based instructions (6)
packages/gql/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Run
bun run generateto regenerate types for all platforms (TypeScript, Swift, Kotlin, Dart) from the GraphQL schema
Files:
packages/gql/src/type-android.graphql
packages/google/**/*.kt
📄 CodeRabbit inference engine (CLAUDE.md)
DO NOT add
Androidsuffix to function names in the Android-only package, even for Android-specific APIs (e.g., useacknowledgePurchase()notacknowledgePurchaseAndroid())
Files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/**/*.kt
📄 CodeRabbit inference engine (CLAUDE.md)
Place reusable Kotlin helper functions in
openiap/src/main/java/dev/hyo/openiap/utils/
Files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt
packages/apple/**/*.swift
📄 CodeRabbit inference engine (CLAUDE.md)
packages/apple/**/*.swift: iOS-specific functions MUST haveIOSsuffix (e.g.,presentCodeRedemptionSheetIOS(),showManageSubscriptionsIOS())
Use Pascal case for acronyms at the beginning or middle of names (e.g.,IapManager,IapPurchase), but ALL CAPS only when appearing as a suffix (e.g.,ProductIAP,OpenIAP)
Files:
packages/apple/Sources/Models/Types.swift
packages/apple/Sources/Models/Types.swift
📄 CodeRabbit inference engine (CLAUDE.md)
DO NOT edit
Types.swiftinSources/Models/as it is auto-generated from the OpenIAP GraphQL schema; regenerate using./scripts/generate-types.sh
Files:
packages/apple/Sources/Models/Types.swift
packages/apple/Sources/Models/**/*.swift
📄 CodeRabbit inference engine (CLAUDE.md)
OpenIAP official types in
Sources/Models/must match types defined at openiap.dev/docs/types
Files:
packages/apple/Sources/Models/Types.swift
🧠 Learnings (11)
📓 Common learnings
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/openiap-versions.json : To update OpenIAP GraphQL types in the iOS/macOS library, edit the `gql` field in `openiap-versions.json`, run `./scripts/generate-types.sh`, and run `swift test` to verify compatibility
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap-versions.json : To update OpenIAP GraphQL types in the Android library, edit the `gql` field in `openiap-versions.json`, then run `./scripts/generate-types.sh` and compile to verify
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap-versions.json : To update OpenIAP GraphQL types in the Android library, edit the `gql` field in `openiap-versions.json`, then run `./scripts/generate-types.sh` and compile to verify
Applied to files:
packages/gql/src/type-android.graphqlpackages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/openiap-versions.json : To update OpenIAP GraphQL types in the iOS/macOS library, edit the `gql` field in `openiap-versions.json`, run `./scripts/generate-types.sh`, and run `swift test` to verify compatibility
Applied to files:
packages/gql/src/type-android.graphqlpackages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/apple/Sources/Models/Types.swiftpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap/src/main/Types.kt : DO NOT edit `openiap/src/main/Types.kt` as it is auto-generated from the GraphQL schema; regenerate it using `./scripts/generate-types.sh`
Applied to files:
packages/gql/src/type-android.graphqlpackages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/**/*.kt : DO NOT add `Android` suffix to function names in the Android-only package, even for Android-specific APIs (e.g., use `acknowledgePurchase()` not `acknowledgePurchaseAndroid()`)
Applied to files:
packages/gql/src/type-android.graphqlpackages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to **/*.{ts,tsx} : Android-specific functions must end with `Android` suffix (e.g., `acknowledgePurchaseAndroid`, `consumePurchaseAndroid`)
Applied to files:
packages/gql/src/type-android.graphql
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap/src/main/java/dev/hyo/openiap/utils/**/*.kt : Place reusable Kotlin helper functions in `openiap/src/main/java/dev/hyo/openiap/utils/`
Applied to files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/Sources/Models/**/*.swift : OpenIAP official types in `Sources/Models/` must match types defined at [openiap.dev/docs/types](https://www.openiap.dev/docs/types)
Applied to files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/apple/Sources/Models/Types.swiftpackages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/Sources/Models/Types.swift : DO NOT edit `Types.swift` in `Sources/Models/` as it is auto-generated from the OpenIAP GraphQL schema; regenerate using `./scripts/generate-types.sh`
Applied to files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.ktpackages/apple/Sources/Models/Types.swift
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/**/*.swift : Use Pascal case for acronyms at the beginning or middle of names (e.g., `IapManager`, `IapPurchase`), but ALL CAPS only when appearing as a suffix (e.g., `ProductIAP`, `OpenIAP`)
Applied to files:
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/Sources/Helpers/**/*.swift : Place internal helper classes in `Sources/Helpers/` (e.g., `ProductManager.swift` for thread-safe caching, `IapStatus.swift` for UI status); these are NOT official OpenIAP types
Applied to files:
packages/apple/Sources/Models/Types.swift
🧬 Code graph analysis (2)
packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt (2)
packages/google/openiap/src/test/java/dev/hyo/openiap/PurchaseVerificationValidatorTest.kt (1)
setRequestProperty(338-342)packages/gql/src/generated/types.ts (1)
VerifyPurchaseResultHorizon(1214-1219)
packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt (1)
packages/gql/src/generated/types.ts (4)
VerifyPurchaseResultHorizon(1214-1219)VerifyPurchaseAppleOptions(1119-1125)VerifyPurchaseGoogleOptions(1133-1148)VerifyPurchaseHorizonOptions(1157-1167)
⏰ 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). (1)
- GitHub Check: Test Android
🔇 Additional comments (21)
packages/gql/src/type-android.graphql (4)
373-398: Approve the new VerifyPurchaseGoogleOptions input with security documentation, but regenerate types for all platforms.The GraphQL input type replaces the old
VerifyPurchaseAndroidOptionswith a clearer, more descriptive name that aligns with platform branding. The doc comments are excellent and prominently feature security warnings (⚠️ ) about sensitive tokens—this is a best practice for developer-facing schemas. Field definitions are correct: required fields (packageName,purchaseToken,accessToken) are properly marked with!, and the optionalisSubfield allows flexibility.However, since this is a GraphQL schema file change, the schema is self-documenting and can include descriptions with Markdown, which you've done well. The critical next step is type regeneration.
Per the coding guidelines for
packages/gql/**/*, runbun run generateto regenerate types for all platforms (TypeScript, Swift, Kotlin, Dart) from the updated GraphQL schema. Please confirm this has been completed before merge.
400-421: Approve VerifyPurchaseHorizonOptions with security documentation.The new Horizon (Meta Quest) verification input is well-designed. The doc comments include the API endpoint, security warnings about the
accessTokentoken, and clear field descriptions. All required fields are properly marked with!. The schema is correct and follows the same security-first documentation pattern as the Google options above.
423-436: Approve VerifyPurchaseResultHorizon type.The new result type for Horizon verification is correctly defined. The
successfield is required (Boolean!), andgrantTimeis properly optional (Float) to accommodate cases where the grant timestamp may not be available. Documentation is clear and concise.
373-437: Verify schema completeness and old input removal.Confirm the following to ensure the refactor is complete:
- Old input removal: Ensure
VerifyPurchaseAndroidOptionshas been fully removed from the GraphQL schema (across all schema files, if it was defined elsewhere).- Apple options: Verify that
VerifyPurchaseAppleOptions(mentioned in PR objectives withjwsfield) has been added to the appropriate iOS/Apple GraphQL schema file (e.g.,type-ios.graphql).- Root types: Check that the
VerifyPurchaseResultHorizontype is properly wired into the mutation/query root types (i.e., that there is a mutation that returns this type).- IAPKit options: The PR objectives mention
VerifyPurchaseIAPKitOptions, but it's not present in this file. Verify it has been added to the appropriate schema file if needed.packages/apple/Sources/Models/Types.swift (4)
1-4: Acknowledge: Auto-generated file - changes sourced from GraphQL schema.This file is auto-generated and should not be manually edited. Based on learnings, any corrections must be made in the GraphQL schema, then regenerated using
./scripts/generate-types.sh.
847-854: LGTM: Horizon verification result type added.The new
VerifyPurchaseResultHorizonstruct appropriately supports Meta Horizon entitlement verification, aligning with the PR objectives.
1338-1406: Security warnings properly address past concerns.The security warnings for sensitive tokens (
jws,accessToken,purchaseToken) in these Codable structs appropriately address the previous review concern about tokens potentially appearing in logs or crash reports. Higher-layer code must respect these warnings and implement proper redaction.Based on past review comments, this concern has been addressed.
1408-1434: LGTM: Verification parameters updated per PR objectives.The
VerifyPurchasePropsstructure now supports platform-specific verification (Apple, Google, Horizon) as intended. The documentation clearly explains which API each platform targets, and the structure aligns with the PR's goal to add multi-platform verification support.packages/google/openiap/src/main/java/dev/hyo/openiap/utils/PurchaseVerificationValidator.kt (6)
13-13: LGTM! Type now properly generated.The
VerifyPurchaseResultHorizontype is now correctly defined in the auto-generatedTypes.ktfile (lines 2343-2368), resolving the previous concern about local type definitions.
28-29: LGTM! Correct URL path encoding.The helper correctly encodes path segments using UTF-8 and replaces
+with%20, which is appropriate for URL paths (not query strings).
36-60: LGTM! URL encoding and security properly addressed.The refactoring to use
encodePathSegmentto all path parameters correctly addresses the previous URL encoding concerns. Sensitive tokens are not logged.
172-179: LGTM! Correct clarification about Horizon support.The comment accurately clarifies that Horizon verification is not supported through IAPKit and requires direct S2S API calls (implemented separately in
verifyPurchaseWithHorizon).
194-194: LGTM! UTF-8 encoding correctly applied.The body is now written using explicit UTF-8 encoding, addressing the previous charset concern.
245-258: LGTM! Clean payload builder for IAPKit integration.The function appropriately extracts Google payload building logic and validates required fields before constructing the minimal IAPKit payload.
packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt (7)
2339-2368: LGTM! Type definition matches GraphQL schema.The
VerifyPurchaseResultHorizondata class correctly matches the GraphQL schema with appropriate field types, nullability, and documentation.
2801-2844: LGTM! Clear documentation of platform vs. store distinction.The added documentation effectively clarifies that "platforms" refers to SDK/OS level (apple, google) rather than stores, and explains the build-time determination of Horizon support.
2937-2980: LGTM! Consistent documentation pattern.The documentation mirrors the approach in
RequestPurchasePropsByPlatforms, maintaining clarity and consistency across related types.
3020-3055: LGTM! Clear IAPKit verification documentation.The documentation effectively clarifies the verification approach for each platform (App Store JWS vs. Play Store token) supported by IAPKit.
3087-3195: LGTM! Comprehensive verification option types with security warnings.The three new verification option types (
Apple,Horizon) are well-documented with appropriate security warnings about sensitive tokens, and match the GraphQL schema.
3197-3239: LGTM! Complete verification props with all platforms.The
VerifyPurchasePropstype properly integrates Apple, Google, and Horizon verification options with clear documentation and correct serialization/deserialization.
3332-3340: LGTM! Horizon result properly integrated into union type.The
VerifyPurchaseResultHorizoncase is correctly added to theVerifyPurchaseResultsealed interface, completing the type integration.
Refactor again based on #53 - Remove sku from VerifyPurchaseProps root level - Add sku to VerifyPurchaseAppleOptions (replaces jws) - Add sku to VerifyPurchaseGoogleOptions - Update Kotlin code to use googleOptions.sku - Update tests for new schema structure - Update release notes for v1.3.4/v1.3.14/v1.3.2 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Breaking Changes * **verifyPurchase API Refactored**: SKU parameter moved from root-level options into platform-specific options. Apple and Google options now require platform-specific SKU fields. Apple verification updated to use SKU instead of legacy JWS field. Horizon platform option added. ## Documentation * Updated release notes and code examples to reflect new API structure. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
- Update VerifyPurchaseProps to use apple/google/horizon fields - Remove deprecated sku root field and androidOptions - Update native iOS/Android modules for new API structure - Update example apps with platform-specific verification - Update documentation and blog for 3.2.0 release - Bump openiap versions (gql 1.3.4, google 1.3.14, apple 1.3.2) Reflects hyodotdev/openiap#53 and hyodotdev/openiap#54 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * verifyPurchase API restructured to accept platform-specific provider options (apple, google, horizon). * Added Horizon (Meta) verification support. * **Improvements** * Stronger input validation and safer UI guards for purchase/discount handling. * Verification libraries updated to newer versions. * **Documentation** * Docs and examples updated for the new parameter shape and breaking change notes. * **Tests** * Tests updated to exercise provider-wrapped input shapes. * **Chores** * Pre-commit now re-stages linted files before running tests. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Note: Pending version updates for release:
Summary by CodeRabbit
New Features
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.