Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions .claude/commands/audit-code.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ Use WebSearch to get the latest platform API information:
**Google Play Billing Library:**

- Search: "Google Play Billing Library release notes site:developer.android.com"
- Check for new features in latest version (currently 8.x)
- Key areas: one-time products, subscription offers, billing programs
- Check for new features in the latest stable version (currently 9.1.0)
- Key areas: one-time products, subscription offers, billing programs, Billing Choice, in-app messages

**Apple StoreKit 2:**

Expand Down Expand Up @@ -79,9 +79,14 @@ Compare current implementation against latest platform APIs:
| -------------------------------------- | ------- | -------------------------------------- |
| One-time products with multiple offers | 8.0 | Is it in schema? |
| Product-level status codes | 8.0 | Returned in fetchProducts? |
| BillingResult sub-response codes | 8.0 | Preserved through every wrapper? |
| Suspended subscriptions (isSuspended) | 8.1 | Purchase type has it? |
| includeSuspended parameter | 8.1 | getAvailablePurchases supports it? |
| Billing Programs API | 8.2 | isBillingProgramAvailable implemented? |
| External Payments | 8.3 | Developer billing fields wired? |
| Nullable developer billing link URI | 9.0 | Null and empty URI handled safely? |
| Opt-in price increase in-app messages | 9.0 | showInAppMessagesAndroid implemented? |
| Billing Choice | 9.1 | Info, dialog, and choice type wired? |

**StoreKit 2 (check packages/gql/src/api-ios.graphql):**

Expand All @@ -98,7 +103,7 @@ Compare current implementation against latest platform APIs:

| Feature | Check |
| ------------------------------------- | ------------------------------- |
| horizon-billing-compatibility version | Is it latest? (currently 1.1.1) |
| horizon-billing-compatibility version | Is it latest? (currently 2.0.0) |
| API parity with Play flavor | Same APIs available in both? |
| Shared code compatibility | Uses only Billing 7.0 APIs? |
| getAvailableItems (Horizon-only) | Implemented? |
Expand All @@ -108,7 +113,7 @@ Compare current implementation against latest platform APIs:

| Check | Expected |
| --------------------------- | --------------------------- |
| Play flavor Billing version | 8.x |
| Play flavor Billing version | 9.1.0 |
| Horizon SDK compatible with | Billing 7.0 API |
| Shared code uses | Only 7.0-compatible APIs |
| react-native-iap requires | v14+, RN 0.79+, Kotlin 2.0+ |
Expand Down Expand Up @@ -140,15 +145,17 @@ packages/gql (GraphQL):

**Latest API Coverage:**

- [ ] Google Play Billing 8.x features implemented
- [ ] Google Play Billing 9.1.0 features implemented end-to-end
- [ ] StoreKit 2 iOS 18+ features implemented
- [ ] Meta Horizon Billing SDK up to date
- [ ] External API docs updated with new features
- [ ] New API comments lead with OpenIAP spec/package versions, then list the
upstream platform SDK requirement

**Version Compatibility:**

- [ ] horizon-billing-compatibility matches latest
- [ ] Shared code avoids Billing 8.x-only APIs
- [ ] Shared code avoids Billing 8.x/9.x-only APIs
- [ ] react-native-iap/expo-iap compatible versions documented

### 6. Fix Issues
Expand Down Expand Up @@ -312,7 +319,7 @@ For each new feature implemented:
- [ ] **Type docs** - New types documented with all fields explained
- [ ] **Example apps** - Working examples in iOS and Android example apps
- [ ] **Code examples** - Inline code examples in documentation
- [ ] **Platform notes** - Version requirements (e.g., "iOS 18+", "Billing 8.0+")
- [ ] **Platform notes** - Version requirements (e.g., "iOS 18+", "Billing 9.1+")
- [ ] **Cross-references** - Links between related functions/types
- [ ] **Search** - New items added to search index

Expand Down Expand Up @@ -386,7 +393,7 @@ Then ask Claude to:
Ask Claude Code:

> "Run /audit-code with latest API check"
> "Audit the codebase including latest Google Play Billing 8.x features"
> "Audit the codebase including latest Google Play Billing 9.1.0 features"
> "Check implementation against latest StoreKit 2 iOS 18.4 APIs"

## Output
Expand Down
69 changes: 47 additions & 22 deletions .claude/commands/e2e-tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ cd android
# Build-only regression can stop here.
: "${ANDROID_SERIAL:?Set ANDROID_SERIAL to the target Android device serial}"
adb -s "$ANDROID_SERIAL" install -r app/build/outputs/apk/debug/app-debug.apk
adb -s "$ANDROID_SERIAL" shell monkey -p dev.hyo.openiap.expo.example 1
adb -s "$ANDROID_SERIAL" shell monkey -p dev.hyo.martie 1
```

Normal iOS physical-device build and launch smoke:
Expand All @@ -290,9 +290,9 @@ cd libraries/expo-iap/example
: "${IOS_UDID:?Set IOS_UDID to the target iOS device UDID}"
: "${TEAM_ID:?Set TEAM_ID to the Apple development team ID}"
xcodebuild \
-workspace ios/expoiapexample.xcworkspace \
-workspace ios/ExpoIAPExample.xcworkspace \
-configuration Debug \
-scheme expoiapexample \
-scheme ExpoIAPExample \
-destination "id=$IOS_UDID" \
DEVELOPMENT_TEAM="$TEAM_ID" \
-derivedDataPath build/DerivedData \
Expand All @@ -301,10 +301,10 @@ xcodebuild \
# Build-only regression can stop here.
xcrun devicectl device install app \
--device "$IOS_UDID" \
build/DerivedData/Build/Products/Debug-iphoneos/expoiapexample.app
build/DerivedData/Build/Products/Debug-iphoneos/ExpoIAPExample.app
xcrun devicectl device process launch \
--device "$IOS_UDID" \
dev.hyo.openiap.expo.example
dev.hyo.martie
```

FireOS/Amazon Android path:
Expand All @@ -317,7 +317,7 @@ cd android
# Build-only regression can stop here.
: "${FIREOS_SERIAL:?Set FIREOS_SERIAL to the target FireOS device serial}"
adb -s "$FIREOS_SERIAL" install -r app/build/outputs/apk/debug/app-debug.apk
adb -s "$FIREOS_SERIAL" shell monkey -p dev.hyo.openiap.expo.example 1
adb -s "$FIREOS_SERIAL" shell monkey -p dev.hyo.martie 1
```

Horizon Android build-only path:
Expand All @@ -335,9 +335,9 @@ Onside iOS build-only path:
cd libraries/expo-iap/example
EXPO_IAP_ONSIDE=1 bunx expo prebuild --platform ios --clean
xcodebuild \
-workspace ios/expoiapexample.xcworkspace \
-workspace ios/ExpoIAPExample.xcworkspace \
-configuration Debug \
-scheme expoiapexample \
-scheme ExpoIAPExample \
-destination "generic/platform=iOS" \
CODE_SIGNING_ALLOWED=NO
```
Expand All @@ -363,6 +363,7 @@ Library:

```bash
cd libraries/react-native-iap
yarn specs
yarn lint:tsc
yarn test:library --runInBand
```
Expand Down Expand Up @@ -402,6 +403,11 @@ Normal iOS physical-device build and launch smoke:
cd libraries/react-native-iap/example
: "${IOS_UDID:?Set IOS_UDID to the target iOS device UDID}"
: "${TEAM_ID:?Set TEAM_ID to the Apple development team ID}"
# Refresh Pods after Nitro type generation so newly generated headers are
# linked into Pods/Headers before the physical-device build.
cd ios
bundle exec pod install
cd ..
xcodebuild \
-workspace ios/example.xcworkspace \
-configuration Debug \
Expand Down Expand Up @@ -577,7 +583,10 @@ cd libraries/maui-iap/android
../../../packages/google/gradlew :openiap:assembleRelease -PopenIapAndroidStore=play
cd ..
dotnet build-server shutdown || true
rm -rf src/OpenIap.Maui.Bindings.Android/bin src/OpenIap.Maui.Bindings.Android/obj
rm -rf \
src/OpenIap.Maui.Bindings.Android/bin src/OpenIap.Maui.Bindings.Android/obj \
src/OpenIap.Maui/bin src/OpenIap.Maui/obj \
example/OpenIap.Maui.Example/bin example/OpenIap.Maui.Example/obj
dotnet build src/OpenIap.Maui.Bindings.Android/OpenIap.Maui.Bindings.Android.csproj \
-p:TargetFrameworks=net9.0-android \
-p:OpenIapAndroidStore=play \
Expand All @@ -590,14 +599,14 @@ dotnet build src/OpenIap.Maui/OpenIap.Maui.csproj \
dotnet build example/OpenIap.Maui.Example/OpenIap.Maui.Example.csproj \
-f net9.0-android \
-p:OpenIapAndroidStore=play \
-p:EmbedAssembliesIntoApk=true \
--nologo
# Build-only regression can stop here.
: "${ANDROID_SERIAL:?Set ANDROID_SERIAL to the target Android device serial}"
ANDROID_SERIAL="$ANDROID_SERIAL" dotnet build example/OpenIap.Maui.Example/OpenIap.Maui.Example.csproj \
-t:Run \
-f net9.0-android \
-p:OpenIapAndroidStore=play \
--nologo
adb -s "$ANDROID_SERIAL" uninstall dev.hyo.martie || true
adb -s "$ANDROID_SERIAL" install --no-incremental -r \
example/OpenIap.Maui.Example/bin/Debug/net9.0-android/dev.hyo.martie-Signed.apk
adb -s "$ANDROID_SERIAL" shell monkey -p dev.hyo.martie 1
```

FireOS/Amazon Android build and launch smoke:
Expand All @@ -607,7 +616,10 @@ cd libraries/maui-iap/android
../../../packages/google/gradlew :openiap:assembleRelease -PopenIapAndroidStore=amazon
cd ..
dotnet build-server shutdown || true
rm -rf src/OpenIap.Maui.Bindings.Android/bin src/OpenIap.Maui.Bindings.Android/obj
rm -rf \
src/OpenIap.Maui.Bindings.Android/bin src/OpenIap.Maui.Bindings.Android/obj \
src/OpenIap.Maui/bin src/OpenIap.Maui/obj \
example/OpenIap.Maui.Example/bin example/OpenIap.Maui.Example/obj
dotnet build src/OpenIap.Maui.Bindings.Android/OpenIap.Maui.Bindings.Android.csproj \
-p:TargetFrameworks=net9.0-android \
-p:OpenIapAndroidStore=amazon \
Expand All @@ -620,14 +632,14 @@ dotnet build src/OpenIap.Maui/OpenIap.Maui.csproj \
dotnet build example/OpenIap.Maui.Example/OpenIap.Maui.Example.csproj \
-f net9.0-android \
-p:OpenIapAndroidStore=amazon \
-p:EmbedAssembliesIntoApk=true \
--nologo
# Build-only regression can stop here.
: "${FIREOS_SERIAL:?Set FIREOS_SERIAL to the target FireOS device serial}"
ANDROID_SERIAL="$FIREOS_SERIAL" dotnet build example/OpenIap.Maui.Example/OpenIap.Maui.Example.csproj \
-t:Run \
-f net9.0-android \
-p:OpenIapAndroidStore=amazon \
--nologo
adb -s "$FIREOS_SERIAL" uninstall dev.hyo.martie || true
adb -s "$FIREOS_SERIAL" install --no-incremental -r \
example/OpenIap.Maui.Example/bin/stores/amazon/Debug/net9.0-android/dev.hyo.martie-Signed.apk
adb -s "$FIREOS_SERIAL" shell monkey -p dev.hyo.martie 1
```

Horizon Android build-only path:
Expand All @@ -637,7 +649,10 @@ cd libraries/maui-iap/android
../../../packages/google/gradlew :openiap:assembleRelease -PopenIapAndroidStore=horizon
cd ..
dotnet build-server shutdown || true
rm -rf src/OpenIap.Maui.Bindings.Android/bin src/OpenIap.Maui.Bindings.Android/obj
rm -rf \
src/OpenIap.Maui.Bindings.Android/bin src/OpenIap.Maui.Bindings.Android/obj \
src/OpenIap.Maui/bin src/OpenIap.Maui/obj \
example/OpenIap.Maui.Example/bin example/OpenIap.Maui.Example/obj
dotnet build src/OpenIap.Maui.Bindings.Android/OpenIap.Maui.Bindings.Android.csproj \
-p:TargetFrameworks=net9.0-android \
-p:OpenIapAndroidStore=horizon \
Expand All @@ -658,7 +673,17 @@ iOS physical-device build and launch smoke:
```bash
cd libraries/maui-iap/example/OpenIap.Maui.Example
: "${IOS_UDID:?Set IOS_UDID to the target iOS device UDID}"
dotnet build -t:Run -f net9.0-ios -p:_DeviceName="$IOS_UDID"
dotnet build \
-f net9.0-ios \
-p:RuntimeIdentifier=ios-arm64 \
-p:ValidateXcodeVersion=false \
--nologo
xcrun devicectl device install app \
--device "$IOS_UDID" \
bin/Debug/net9.0-ios/ios-arm64/OpenIap.Maui.Example.app
xcrun devicectl device process launch \
--device "$IOS_UDID" \
dev.hyo.martie
```

## Godot Checks
Expand Down
11 changes: 7 additions & 4 deletions .claude/guides/05-google-package.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@ packages/google/

## Build Variants

| Variant | Purpose | Billing Library |
| --------- | ------------------ | ---------------- |
| `play` | Google Play Store | Play Billing 8.x |
| `horizon` | Meta Horizon Store | Horizon SDK |
| Variant | Purpose | Billing Library |
| --------- | ------------------ | ------------------------- |
| `play` | Google Play Store | Play Billing 9.1.0 |
| `horizon` | Meta Horizon Store | Horizon SDK 2.0.0 |
| `amazon` | Amazon Appstore | Amazon Appstore SDK 3.0.8 |

## Type Generation

Expand All @@ -52,10 +53,12 @@ Types.kt is auto-generated. **Never edit directly!**
# Compile library
./gradlew :openiap:compilePlayDebugKotlin
./gradlew :openiap:compileHorizonDebugKotlin
./gradlew :openiap:compileAmazonDebugKotlin

# Run tests
./gradlew :openiap:testPlayDebugUnitTest
./gradlew :openiap:testHorizonDebugUnitTest
./gradlew :openiap:testAmazonDebugUnitTest

# Build Example app
./gradlew :Example:assemblePlayDebug
Expand Down
23 changes: 22 additions & 1 deletion .codex/skills/generate-doc/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,28 @@ Follow the existing card pattern:
- Do not edit `packages/docs/src/generated/version-metadata.json` manually; it
is produced by `./scripts/sync-versions.sh`.

## Multi-package Release Trains

The consolidated release page remains the release-note SSOT, but a release that
ships several packages must still be readable package by package. This is the
project decision recorded from issue #206.

- When the user gives a starting commit, inspect that commit inclusively through
the latest target branch, then include the current PR diff. Do not derive the
release contents only from the PR title or its latest commits.
- Group notable changes under the affected platform package or framework
library (Google, Apple, IAPKit, React Native, Expo, Flutter, Godot, KMP, and
MAUI). Omit groups with no user-facing change.
- Keep each group concise. State the behavior users gain or the regression that
was fixed; do not list commit mechanics, version-bump-only commits, generated
files, or repeated cross-framework boilerplate.
- Put truly shared schema or release-process changes in one short shared group,
then describe framework-specific wiring or caveats in the relevant framework
group.
- Link the issues and PRs that explain user-visible fixes. Keep package-local
changelogs as pointers to this canonical entry unless a registry requires an
inline changelog.

## Validation

For docs-only release-note edits, run:
Expand All @@ -110,4 +132,3 @@ Before committing to `main`, pull first:
```bash
git pull --ff-only origin main
```

22 changes: 12 additions & 10 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ This document provides an overview for AI agents working across the OpenIAP mono

## Quick Reference

| Topic | File |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| Naming Conventions | [`knowledge/internal/01-naming-conventions.md`](knowledge/internal/01-naming-conventions.md) |
| Architecture | [`knowledge/internal/02-architecture.md`](knowledge/internal/02-architecture.md) |
| Coding Style | [`knowledge/internal/03-coding-style.md`](knowledge/internal/03-coding-style.md) |
| Topic | File |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Naming Conventions | [`knowledge/internal/01-naming-conventions.md`](knowledge/internal/01-naming-conventions.md) |
| Architecture | [`knowledge/internal/02-architecture.md`](knowledge/internal/02-architecture.md) |
| Coding Style | [`knowledge/internal/03-coding-style.md`](knowledge/internal/03-coding-style.md) |
| Platform Packages | [`knowledge/internal/04-platform-packages.md`](knowledge/internal/04-platform-packages.md) (run `bun audit:parity` before commits; pre-commit mirrors CI's SDK parity job) |
| Docs Patterns | [`knowledge/internal/05-docs-patterns.md`](knowledge/internal/05-docs-patterns.md) |
| Git & Deployment | [`knowledge/internal/06-git-deployment.md`](knowledge/internal/06-git-deployment.md) |
| Docs Consistency / SSOT | [`knowledge/internal/07-docs-consistency.md`](knowledge/internal/07-docs-consistency.md) (run `bun audit:docs` before pushing API/Type doc edits) |
| GV Cloud Workspaces | [`knowledge/internal/08-gv-cloud-workspaces.md`](knowledge/internal/08-gv-cloud-workspaces.md) |
| Docs Patterns | [`knowledge/internal/05-docs-patterns.md`](knowledge/internal/05-docs-patterns.md) |
| Git & Deployment | [`knowledge/internal/06-git-deployment.md`](knowledge/internal/06-git-deployment.md) |
| Docs Consistency / SSOT | [`knowledge/internal/07-docs-consistency.md`](knowledge/internal/07-docs-consistency.md) (run `bun audit:docs` before pushing API/Type doc edits) |
| GV Cloud Workspaces | [`knowledge/internal/08-gv-cloud-workspaces.md`](knowledge/internal/08-gv-cloud-workspaces.md) |

## Monorepo Structure

Expand Down Expand Up @@ -79,7 +79,9 @@ openiap/
- `libraries/flutter_inapp_purchase/lib/types.dart` - Synced from GQL
- `libraries/godot-iap/addons/godot-iap/types.gd` - Synced from GQL
- `libraries/maui-iap/src/OpenIap.Maui/Types.cs` - Synced from GQL
- `openiap-versions.json` - Managed by CI/CD workflows only; tracks only `spec`, `google`, and `apple`
- `openiap-versions.json` - Tracks only `spec`, `google`, and `apple`. Google
and Apple are CI-managed; the spec may be bumped directly in a feature PR
when explicitly requested, together with `packages/gql/package.json`.

Framework library package versions (React Native, Expo, Flutter, Godot, KMP,
MAUI) live in their own package metadata / release workflows. Do not add
Expand Down
Loading
Loading