feat: add claude code parity and fix cross-sdk audit findings - #234
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013CLqZZbW8qCoA1nWj2SxgV
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013CLqZZbW8qCoA1nWj2SxgV
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013CLqZZbW8qCoA1nWj2SxgV
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013CLqZZbW8qCoA1nWj2SxgV
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013CLqZZbW8qCoA1nWj2SxgV
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013CLqZZbW8qCoA1nWj2SxgV
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013CLqZZbW8qCoA1nWj2SxgV
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013CLqZZbW8qCoA1nWj2SxgV
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013CLqZZbW8qCoA1nWj2SxgV
|
/gemini review |
|
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 adds Claude Code and MCP marketplace integration, expands workflow and documentation guidance, enforces Expo platform guards, enables Android Google Play verification, updates Google receipt-state mapping and Godot defaults, and adds GDScript and Google flavor parity checks. ChangesClaude Code and MCP integration
Mobile platform and purchase behavior
Code generation and SDK parity
Agent workflow governance
Convex mutation visibility
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 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.
Code Review
This pull request adds Claude Code compatibility, plugins, and documentation across the monorepo, and enforces platform guards in libraries/expo-iap to throw explicit platform errors. Additionally, it fixes a GDScript codegen regression for GraphQL enum-list defaults, converts markReceiptInvalid to an internal mutation for security, and updates the parity audit script to verify Android flavor handler wiring. The review feedback suggests adding an explicit fallback return to buildSchemaDefaultForType in the GDScript plugin to avoid implicit undefined returns, and stripping comments before matching argument names in the parity audit script to prevent false positives.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| if (type.kind === 'scalar') { | ||
| if (typeof defaultValue === 'string') { | ||
| return JSON.stringify(defaultValue); | ||
| } | ||
| if ( | ||
| typeof field.defaultValue === 'number' || | ||
| typeof field.defaultValue === 'boolean' | ||
| typeof defaultValue === 'number' || | ||
| typeof defaultValue === 'boolean' | ||
| ) { | ||
| return String(field.defaultValue); | ||
| return String(defaultValue); | ||
| } | ||
| } |
There was a problem hiding this comment.
The buildSchemaDefaultForType function lacks an explicit fallback return statement. If the type kind is not 'list', 'enum', or 'scalar', or if a scalar default value is of an unexpected type, the function implicitly returns undefined. This can cause TypeScript compilation errors (under strictNullChecks or noImplicitReturns) and lead to malformed generated GDScript (e.g., empty or invalid array elements when joined). Adding an explicit return null; at the end of the function ensures unhandled cases are safely propagated as null.
| if (type.kind === 'scalar') { | |
| if (typeof defaultValue === 'string') { | |
| return JSON.stringify(defaultValue); | |
| } | |
| if ( | |
| typeof field.defaultValue === 'number' || | |
| typeof field.defaultValue === 'boolean' | |
| typeof defaultValue === 'number' || | |
| typeof defaultValue === 'boolean' | |
| ) { | |
| return String(field.defaultValue); | |
| return String(defaultValue); | |
| } | |
| } | |
| if (type.kind === 'scalar') { | |
| if (typeof defaultValue === 'string') { | |
| return JSON.stringify(defaultValue); | |
| } | |
| if ( | |
| typeof defaultValue === 'number' || | |
| typeof defaultValue === 'boolean' | |
| ) { | |
| return String(defaultValue); | |
| } | |
| } | |
| return null; |
There was a problem hiding this comment.
The explicit return null; fallback is already present at the end of buildSchemaDefaultForType — the suggestion matches the current code verbatim (see the if (type.kind === 'scalar') block followed by return null; at HEAD). Unhandled kinds and unexpected scalar default types already propagate as null, and the GQL tsc + tests pass on this branch.
There was a problem hiding this comment.
Code Review
This pull request introduces Claude Code compatibility, including plugins, MCP server configurations, and documentation updates. It also adds platform guards to Expo-IAP wrappers, fixes a GDScript codegen regression for list defaults, changes the markReceiptInvalid Convex mutation to internal-only for security, and introduces a Google flavor handler wiring check to the non-Godot parity audit script. Feedback highlights a potential compilation error in the KMP-IAP Android implementation due to type mismatches when delegating validateReceiptHandler to verifyPurchase, as well as a parsing vulnerability in the new audit script's bracket depth parser when handling string literals or comments.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
scripts/audit-non-godot-parity.mjs (1)
870-878: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider adjusting the arguments or messages for clearer audit failures.
Since
expectSameSethardcodes the words "parity registry" in its failure messages, passing the Kotlin bundle contents as the second argument (registryValues) results in inverted error messages. If the Kotlin file is missing an operation that exists in the registry, the script will output... missing parity registry coverage: [operation], which suggests the registry needs updating rather than the Kotlin file.Consider passing a tailored label or extracting the error message generation so that wiring failures explicitly instruct developers to update the
OpenIapModule.ktbundle.🤖 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 `@scripts/audit-non-godot-parity.mjs` around lines 870 - 878, Adjust the wiring audit around androidRelevantOperations and expectSameSet so failure messages identify the Kotlin OpenIapModule.kt handler bundle as the source needing updates, rather than hardcoding “parity registry” wording. Use a tailored label or refactor the message-generation interface while preserving the existing set comparison behavior for all other parity checks.
🤖 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.
Nitpick comments:
In `@scripts/audit-non-godot-parity.mjs`:
- Around line 870-878: Adjust the wiring audit around androidRelevantOperations
and expectSameSet so failure messages identify the Kotlin OpenIapModule.kt
handler bundle as the source needing updates, rather than hardcoding “parity
registry” wording. Use a tailored label or refactor the message-generation
interface while preserving the existing set comparison behavior for all other
parity checks.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: a9d4f2f3-974f-459e-a5b4-a6617304987d
⛔ Files ignored due to path filters (2)
.github/pr-previews/claude-parity-docs-preview.mp4is excluded by!**/*.mp4packages/gql/src/generated/types.gdis excluded by!**/generated/**
📒 Files selected for processing (50)
.claude-plugin/marketplace.json.claude/commands/commit.md.claude/guides/09-kit-package.md.claude/settings.json.claude/skills/generate-doc/SKILL.md.claude/skills/iapkit-e2e-martie/SKILL.md.claude/skills/iapkit-e2e-petgu/SKILL.md.claude/skills/opencollective-steward/SKILL.md.claude/skills/openiap-workflows/SKILL.md.claude/skills/review-self/SKILL.md.codex/skills/openiap-workflows/SKILL.md.mcp.json.vscode/settings.jsonAGENTS.mdknowledge/_claude-context/context.mdknowledge/internal/02-architecture.mdknowledge/internal/04-platform-packages.mdlibraries/expo-iap/plugin/src/__tests__/tsconfig.jsonlibraries/expo-iap/src/__tests__/tsconfig.jsonlibraries/expo-iap/src/modules/__tests__/android.test.tslibraries/expo-iap/src/modules/__tests__/ios.test.tslibraries/expo-iap/src/modules/__tests__/tsconfig.jsonlibraries/expo-iap/src/modules/android.tslibraries/expo-iap/src/modules/ios.tslibraries/expo-iap/src/utils/__tests__/tsconfig.jsonlibraries/godot-iap/addons/godot-iap/types.gdlibraries/kmp-iap/library/src/androidMain/kotlin/io/github/hyochan/kmpiap/InAppPurchaseAndroid.ktpackages/docs/public/llms-full.txtpackages/docs/src/pages/docs/guides/mcp-server.tsxpackages/gql/codegen/plugins/gdscript.tspackages/gql/src/codegen-defaults.test.tspackages/kit/CONVENTION.mdpackages/kit/README.mdpackages/kit/convex/purchases/mutation.tspackages/kit/public/llms-full.txtpackages/kit/public/llms.txtpackages/kit/public/sitemap.xmlpackages/kit/server/api/v1/routes.tspackages/kit/src/pages/docs/nav.tspackages/kit/src/pages/docs/routes.tsxpackages/kit/src/pages/docs/sections/ai-assistants.tsxpackages/kit/src/pages/docs/sections/api.tsxpackages/kit/src/pages/docs/sections/claude-plugin.tsxpackages/mcp-server/README.mdpackages/mcp-server/package.jsonplugins/openiap/.claude-plugin/plugin.jsonplugins/openiap/.codex-plugin/mcp.jsonplugins/openiap/.codex-plugin/plugin.jsonplugins/openiap/skills/openiap/SKILL.mdscripts/audit-non-godot-parity.mjs
💤 Files with no reviewable changes (1)
- .claude/settings.json
Kotlin comments and string literals containing brackets or commas (e.g. `// (optional)` or `"a, b"`) inside a flavor handler bundle constructor would break the bracket-depth walk and the top-level argument split in parseHandlerBundleArgumentNames, producing spurious unbalanced-bundle or missing-wiring audit failures. Mask their contents with spaces (indices preserved) before scanning so only structural code characters count. Addresses gemini-code-assist review threads on PR #234. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
openiap-google parses Play Developer API responses with reflective Gson, which leaves declared-non-null fields null when Google omits them — and real purchases.products.get / purchases.subscriptions.get responses never contain the Amazon-RVS-shaped fields (parentProductId, productType, receiptId, term, termSku). The direct constructor copy in verifyPurchase then tripped Kotlin's parameter null checks, so every Google-verified purchase surfaced as PurchaseVerificationFailed with a misleading "Parameter specified as non-null is null" message, and validateReceipt inherited the failure through its delegation. Route the result through the JSON map boundary instead so the generated fromJson applies its schema defaults, matching how the other wrappers sanitize cross-artifact objects. Add a regression test that replicates the reflective Gson parse of a realistic response and proves the mapping absorbs the nulls. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Play Developer API cannot mark an inapp purchase as consumable, so every unconsumed Google consumable was recorded as PENDING_ACKNOWLEDGMENT at verify time — and since the standard client flow verifies before finishTransaction, the purchases view showed consumables as "Pending acknowledgment" forever while the App Store equivalent showed "Ready to consume". Consult the project's synced product catalog during Google verification and map unconsumed catalog-known consumables to READY_TO_CONSUME, mirroring the App Store mapping; unknown products keep the previous behavior. Update the response-schema and docs notes (the old "App Store only" note was already stale for Amazon) and cover the new mapping with unit tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Android verifyPurchaseWithProvider bridge passed Kotlin enum
constant names ("PendingAcknowledgment", "ReadyToConsume") into mappers
that only match separator-delimited spellings, so every multi-word
IAPKit purchase state degraded to UNKNOWN in JS while single-word states
passed through. Use rawValue ("pending-acknowledgment") like the iOS
bridge already does, for state, store, and provider alike.
Observed live: a Google consumable verify returned
state PENDING_ACKNOWLEDGMENT from the server but surfaced as
state: 'unknown' in the example app.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add the July 20 consolidated release entry for the PR #234 train, grouped per package: expo-iap 4.6.0 (platform-guard behavior change), react-native-iap 15.5.3 (android iapkit state bridge fix), kmp-iap 2.6.0 (android verifyPurchase), godot-iap 2.5.2 (in-app message default), and the IAPKit service-side verified-state/hardening changes that deploy with the dashboard. Links use the expected release tags per the assumed-published release-note convention. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Summary
plugins/openiapplugin, root marketplace (.claude-plugin/marketplace.json) + project-scoped.mcp.json, six.claude/skills/adapters, and plugin/MCP documentation.verifyPurchasein kmp-iap, and extend the CI parity audit with a google flavor handler wiring check.Changes
Claude Code parity (plugins, marketplace, skills, docs) — e51f304, 14fcdae
plugins/openiapis now dual-manifest:.codex-plugin/plugin.json(Codex, MCP config at.codex-plugin/mcp.json) +.claude-plugin/plugin.json(Claude Code, inline MCP config), with theskills/folder shared and agent-neutral..claude-plugin/marketplace.jsonpublishes the plugin as a Claude Code marketplace; root.mcp.jsonregisters the hosted IAPKit MCP endpoint (https://kit.openiap.dev/mcp) as a project-scoped server..claude/skills/adapters (generate-doc,iapkit-e2e-martie,iapkit-e2e-petgu,opencollective-steward,openiap-workflows,review-self) point at the canonical.codex/skills/bodies..github/pr-previews/(attachment upload was blocked; linked below).Security fix (packages/kit) — d3e8f93
markReceiptInvalidwas a public Convex mutation with no authentication — any caller could invalidate receipts belonging to other tenants. It is now aninternalMutation, callable only from server-side internal code.Audit fixes (gql codegen, kit docs) — 4cbae29, 6104527
Cross-SDK parity (expo, kmp, CI) — 9d09b4e, 0d2c918, bb7f9bc
getStorefrontIOS(and other*IOSwrappers) previously succeeded silently on Android; they now throw per the documented contract.verifyPurchaseimplemented via the Play Developer API.fromJsondefaults, with a regression test replicating the reflective parse.// (optional)can no longer break the audit (review feedback).IAPKit verified-state fixes (found by live Local-IAPKit E2E) — dfd8458, c7f6ddb
READY_TO_CONSUMEinstead of aPENDING_ACKNOWLEDGMENTthe standard verify-then-finish client flow can never clear (mirrors the App Store mapping; unknown products keep prior behavior). Response-schema/docs notes updated.verifyPurchaseWithProviderbridge passed Kotlin enum constant names into spelling-sensitive mappers, degrading every multi-word IAPKit state (e.g.PENDING_ACKNOWLEDGMENT) tounknownin JS; it now usesrawValuelike the iOS bridge.Release notes — ddd48ff
packages/docsfor this train:expo-iap 4.6.0,react-native-iap 15.5.3,kmp-iap 2.6.0,godot-iap 2.5.2, plus the IAPKit service-side changes. Written in the assumed-published convention — the tag links go live when/releaseships each package.Chore — 739f0a3
Preview
claude-parity-docs-preview.mp4
Test plan
bun audit:docs/bun audit:parity/bun run audit:release-statepassclaude plugin validatepassestools/listmatches the 13 documentediapkit_*tools:library:compilePlayDebugKotlinAndroid/:library:compileHorizonDebugKotlinAndroid/:library:compileAmazonDebugKotlinAndroidpass:library:build+ unit tests on all 3 flavors pass, including the newVerifyPurchaseResultMappingTestisValid: true, consume finished🤖 Generated with Claude Code
Summary by CodeRabbit